// Formatting library for C++ // // Copyright (c) 2012 - 2016, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "fmt/format-inl.h" FMT_BEGIN_NAMESPACE namespace internal { template int format_float(char* buf, std::size_t size, const char* format, int precision, T value) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (precision > 100000) throw std::runtime_error( "fuzz mode - avoid large allocation inside snprintf"); #endif // Suppress the warning about nonliteral format string. int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF; return precision < 0 ? snprintf_ptr(buf, size, format, value) : snprintf_ptr(buf, size, format, precision, value); } struct sprintf_specs { int precision; char type; bool alt : 1; template constexpr sprintf_specs(basic_format_specs specs) : precision(specs.precision), type(specs.type), alt(specs.alt) {} constexpr bool has_precision() const { return precision >= 0; } }; // This is deprecated and is kept only to preserve ABI compatibility. template char* sprintf_format(Double value, internal::buffer& buf, sprintf_specs specs) { // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. FMT_ASSERT(buf.capacity() != 0, "empty buffer"); // Build format string. enum { max_format_size = 10 }; // longest format: %#-*.*Lg char format[max_format_size]; char* format_ptr = format; *format_ptr++ = '%'; if (specs.alt || !specs.type) *format_ptr++ = '#'; if (specs.precision >= 0) { *format_ptr++ = '.'; *format_ptr++ = '*'; } if (std::is_same::value) *format_ptr++ = 'L'; char type = specs.type; if (type == '%') type = 'f'; else if (type == 0 || type == 'n') type = 'g'; #if FMT_MSC_VER if (type == 'F') { // MSVC's printf doesn't support 'F'. type = 'f'; } #endif *format_ptr++ = type; *format_ptr = '\0'; // Format using snprintf. char* start = nullptr; char* decimal_point_pos = nullptr; for (;;) { std::size_t buffer_size = buf.capacity(); start = &buf[0]; int result = format_float(start, buffer_size, format, specs.precision, value); if (result >= 0) { unsigned n = internal::to_unsigned(result); if (n < buf.capacity()) { // Find the decimal point. auto p = buf.data(), end = p + n; if (*p == '+' || *p == '-') ++p; if (specs.type != 'a' && specs.type != 'A') { while (p < end && *p >= '0' && *p <= '9') ++p; if (p < end && *p != 'e' && *p != 'E') { decimal_point_pos = p; if (!specs.type) { // Keep only one trailing zero after the decimal point. ++p; if (*p == '0') ++p; while (p != end && *p >= '1' && *p <= '9') ++p; char* where = p; while (p != end && *p == '0') ++p; if (p == end || *p < '0' || *p > '9') { if (p != end) std::memmove(where, p, to_unsigned(end - p)); n -= static_cast(p - where); } } } } buf.resize(n); break; // The buffer is large enough - continue with formatting. } buf.reserve(n + 1); } else { // If result is negative we ask to increase the capacity by at least 1, // but as std::vector, the buffer grows exponentially. buf.reserve(buf.capacity() + 1); } } return decimal_point_pos; } } // namespace internal template FMT_API char* internal::sprintf_format(double, internal::buffer&, sprintf_specs); template FMT_API char* internal::sprintf_format(long double, internal::buffer&, sprintf_specs); template struct FMT_INSTANTIATION_DEF_API internal::basic_data; // Workaround a bug in MSVC2013 that prevents instantiation of format_float. int (*instantiate_format_float)(double, int, internal::float_specs, internal::buffer&) = internal::format_float; #ifndef FMT_STATIC_THOUSANDS_SEPARATOR template FMT_API internal::locale_ref::locale_ref(const std::locale& loc); template FMT_API std::locale internal::locale_ref::get() const; #endif // Explicit instantiations for char. template FMT_API std::string internal::grouping_impl(locale_ref); template FMT_API char internal::thousands_sep_impl(locale_ref); template FMT_API char internal::decimal_point_impl(locale_ref); template FMT_API void internal::buffer::append(const char*, const char*); template FMT_API void internal::arg_map::init( const basic_format_args& args); template FMT_API std::string internal::vformat( string_view, basic_format_args); template FMT_API format_context::iterator internal::vformat_to( internal::buffer&, string_view, basic_format_args); template FMT_API int internal::snprintf_float(double, int, internal::float_specs, internal::buffer&); template FMT_API int internal::snprintf_float(long double, int, internal::float_specs, internal::buffer&); template FMT_API int internal::format_float(double, int, internal::float_specs, internal::buffer&); template FMT_API int internal::format_float(long double, int, internal::float_specs, internal::buffer&); // Explicit instantiations for wchar_t. template FMT_API std::string internal::grouping_impl(locale_ref); template FMT_API wchar_t internal::thousands_sep_impl(locale_ref); template FMT_API wchar_t internal::decimal_point_impl(locale_ref); template FMT_API void internal::buffer::append(const wchar_t*, const wchar_t*); template FMT_API std::wstring internal::vformat( wstring_view, basic_format_args); FMT_END_NAMESPACE