bumped fmt version to 4.0.0
This commit is contained in:
		
							parent
							
								
									268222e496
								
							
						
					
					
						commit
						fced34e3d8
					
				| @ -41,6 +41,9 @@ | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_USE_WINDOWS_H | ||||
| # if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) | ||||
| #  define WIN32_LEAN_AND_MEAN | ||||
| # endif | ||||
| # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) | ||||
| #  include <windows.h> | ||||
| # else | ||||
| @ -50,8 +53,6 @@ | ||||
| # endif | ||||
| #endif | ||||
| 
 | ||||
| using fmt::internal::Arg; | ||||
| 
 | ||||
| #if FMT_EXCEPTIONS | ||||
| # define FMT_TRY try | ||||
| # define FMT_CATCH(x) catch (x) | ||||
| @ -80,9 +81,9 @@ static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { | ||||
| 
 | ||||
| namespace fmt { | ||||
| 
 | ||||
| FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} | ||||
| FMT_FUNC FormatError::~FormatError() throw() {} | ||||
| FMT_FUNC SystemError::~SystemError() throw() {} | ||||
| FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} | ||||
| FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {} | ||||
| FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| @ -105,27 +106,6 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { | ||||
| # define FMT_SWPRINTF swprintf | ||||
| #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
 | ||||
| 
 | ||||
| // Checks if a value fits in int - used to avoid warnings about comparing
 | ||||
| // signed and unsigned integers.
 | ||||
| template <bool IsSigned> | ||||
| struct IntChecker { | ||||
|   template <typename T> | ||||
|   static bool fits_in_int(T value) { | ||||
|     unsigned max = INT_MAX; | ||||
|     return value <= max; | ||||
|   } | ||||
|   static bool fits_in_int(bool) { return true; } | ||||
| }; | ||||
| 
 | ||||
| template <> | ||||
| struct IntChecker<true> { | ||||
|   template <typename T> | ||||
|   static bool fits_in_int(T value) { | ||||
|     return value >= INT_MIN && value <= INT_MAX; | ||||
|   } | ||||
|   static bool fits_in_int(int) { return true; } | ||||
| }; | ||||
| 
 | ||||
| const char RESET_COLOR[] = "\x1b[0m"; | ||||
| 
 | ||||
| typedef void (*FormatFunc)(Writer &, int, StringRef); | ||||
| @ -191,7 +171,8 @@ int safe_strerror( | ||||
|       : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} | ||||
| 
 | ||||
|     int run() { | ||||
|       strerror_r(0, 0, "");  // Suppress a warning about unused strerror_r.
 | ||||
|       // Suppress a warning about unused strerror_r.
 | ||||
|       strerror_r(0, FMT_NULL, ""); | ||||
|       return handle(strerror_r(error_code_, buffer_, buffer_size_)); | ||||
|     } | ||||
|   }; | ||||
| @ -230,222 +211,19 @@ void report_error(FormatFunc func, int error_code, | ||||
|   std::fwrite(full_message.data(), full_message.size(), 1, stderr); | ||||
|   std::fputc('\n', stderr); | ||||
| } | ||||
| 
 | ||||
| // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
 | ||||
| class IsZeroInt : public ArgVisitor<IsZeroInt, bool> { | ||||
|  public: | ||||
|   template <typename T> | ||||
|   bool visit_any_int(T value) { return value == 0; } | ||||
| }; | ||||
| 
 | ||||
| // Checks if an argument is a valid printf width specifier and sets
 | ||||
| // left alignment if it is negative.
 | ||||
| class WidthHandler : public ArgVisitor<WidthHandler, unsigned> { | ||||
|  private: | ||||
|   FormatSpec &spec_; | ||||
| 
 | ||||
|   FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); | ||||
| 
 | ||||
|  public: | ||||
|   explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} | ||||
| 
 | ||||
|   void report_unhandled_arg() { | ||||
|     FMT_THROW(FormatError("width is not integer")); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T> | ||||
|   unsigned visit_any_int(T value) { | ||||
|     typedef typename internal::IntTraits<T>::MainType UnsignedType; | ||||
|     UnsignedType width = static_cast<UnsignedType>(value); | ||||
|     if (internal::is_negative(value)) { | ||||
|       spec_.align_ = ALIGN_LEFT; | ||||
|       width = 0 - width; | ||||
|     } | ||||
|     if (width > INT_MAX) | ||||
|       FMT_THROW(FormatError("number is too big")); | ||||
|     return static_cast<unsigned>(width); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> { | ||||
|  public: | ||||
|   void report_unhandled_arg() { | ||||
|     FMT_THROW(FormatError("precision is not integer")); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T> | ||||
|   int visit_any_int(T value) { | ||||
|     if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) | ||||
|       FMT_THROW(FormatError("number is too big")); | ||||
|     return static_cast<int>(value); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename U> | ||||
| struct is_same { | ||||
|   enum { value = 0 }; | ||||
| }; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct is_same<T, T> { | ||||
|   enum { value = 1 }; | ||||
| }; | ||||
| 
 | ||||
| // An argument visitor that converts an integer argument to T for printf,
 | ||||
| // if T is an integral type. If T is void, the argument is converted to
 | ||||
| // corresponding signed or unsigned type depending on the type specifier:
 | ||||
| // 'd' and 'i' - signed, other - unsigned)
 | ||||
| template <typename T = void> | ||||
| class ArgConverter : public ArgVisitor<ArgConverter<T>, void> { | ||||
|  private: | ||||
|   internal::Arg &arg_; | ||||
|   wchar_t type_; | ||||
| 
 | ||||
|   FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); | ||||
| 
 | ||||
|  public: | ||||
|   ArgConverter(internal::Arg &arg, wchar_t type) | ||||
|     : arg_(arg), type_(type) {} | ||||
| 
 | ||||
|   void visit_bool(bool value) { | ||||
|     if (type_ != 's') | ||||
|       visit_any_int(value); | ||||
|   } | ||||
| 
 | ||||
|   template <typename U> | ||||
|   void visit_any_int(U value) { | ||||
|     bool is_signed = type_ == 'd' || type_ == 'i'; | ||||
|     using internal::Arg; | ||||
|     typedef typename internal::Conditional< | ||||
|         is_same<T, void>::value, U, T>::type TargetType; | ||||
|     if (sizeof(TargetType) <= sizeof(int)) { | ||||
|       // Extra casts are used to silence warnings.
 | ||||
|       if (is_signed) { | ||||
|         arg_.type = Arg::INT; | ||||
|         arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); | ||||
|       } else { | ||||
|         arg_.type = Arg::UINT; | ||||
|         typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; | ||||
|         arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); | ||||
|       } | ||||
|     } else { | ||||
|       if (is_signed) { | ||||
|         arg_.type = Arg::LONG_LONG; | ||||
|         // glibc's printf doesn't sign extend arguments of smaller types:
 | ||||
|         //   std::printf("%lld", -42);  // prints "4294967254"
 | ||||
|         // but we don't have to do the same because it's a UB.
 | ||||
|         arg_.long_long_value = static_cast<LongLong>(value); | ||||
|       } else { | ||||
|         arg_.type = Arg::ULONG_LONG; | ||||
|         arg_.ulong_long_value = | ||||
|             static_cast<typename internal::MakeUnsigned<U>::Type>(value); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Converts an integer argument to char for printf.
 | ||||
| class CharConverter : public ArgVisitor<CharConverter, void> { | ||||
|  private: | ||||
|   internal::Arg &arg_; | ||||
| 
 | ||||
|   FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); | ||||
| 
 | ||||
|  public: | ||||
|   explicit CharConverter(internal::Arg &arg) : arg_(arg) {} | ||||
| 
 | ||||
|   template <typename T> | ||||
|   void visit_any_int(T value) { | ||||
|     arg_.type = internal::Arg::CHAR; | ||||
|     arg_.int_value = static_cast<char>(value); | ||||
|   } | ||||
| }; | ||||
| }  // namespace
 | ||||
| 
 | ||||
| namespace internal { | ||||
| 
 | ||||
| template <typename Char> | ||||
| class PrintfArgFormatter : | ||||
|     public ArgFormatterBase<PrintfArgFormatter<Char>, Char> { | ||||
| 
 | ||||
|   void write_null_pointer() { | ||||
|     this->spec().type_ = 0; | ||||
|     this->write("(nil)"); | ||||
|   } | ||||
| 
 | ||||
|   typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base; | ||||
| 
 | ||||
|  public: | ||||
|   PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) | ||||
|   : ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {} | ||||
| 
 | ||||
|   void visit_bool(bool value) { | ||||
|     FormatSpec &fmt_spec = this->spec(); | ||||
|     if (fmt_spec.type_ != 's') | ||||
|       return this->visit_any_int(value); | ||||
|     fmt_spec.type_ = 0; | ||||
|     this->write(value); | ||||
|   } | ||||
| 
 | ||||
|   void visit_char(int value) { | ||||
|     const FormatSpec &fmt_spec = this->spec(); | ||||
|     BasicWriter<Char> &w = this->writer(); | ||||
|     if (fmt_spec.type_ && fmt_spec.type_ != 'c') | ||||
|       w.write_int(value, fmt_spec); | ||||
|     typedef typename BasicWriter<Char>::CharPtr CharPtr; | ||||
|     CharPtr out = CharPtr(); | ||||
|     if (fmt_spec.width_ > 1) { | ||||
|       Char fill = ' '; | ||||
|       out = w.grow_buffer(fmt_spec.width_); | ||||
|       if (fmt_spec.align_ != ALIGN_LEFT) { | ||||
|         std::fill_n(out, fmt_spec.width_ - 1, fill); | ||||
|         out += fmt_spec.width_ - 1; | ||||
|       } else { | ||||
|         std::fill_n(out + 1, fmt_spec.width_ - 1, fill); | ||||
|       } | ||||
|     } else { | ||||
|       out = w.grow_buffer(1); | ||||
|     } | ||||
|     *out = static_cast<Char>(value); | ||||
|   } | ||||
| 
 | ||||
|   void visit_cstring(const char *value) { | ||||
|     if (value) | ||||
|       Base::visit_cstring(value); | ||||
|     else if (this->spec().type_ == 'p') | ||||
|       write_null_pointer(); | ||||
|     else | ||||
|       this->write("(null)"); | ||||
|   } | ||||
| 
 | ||||
|   void visit_pointer(const void *value) { | ||||
|     if (value) | ||||
|       return Base::visit_pointer(value); | ||||
|     this->spec().type_ = 0; | ||||
|     write_null_pointer(); | ||||
|   } | ||||
| 
 | ||||
|   void visit_custom(Arg::CustomValue c) { | ||||
|     BasicFormatter<Char> formatter(ArgList(), this->writer()); | ||||
|     const Char format_str[] = {'}', 0}; | ||||
|     const Char *format = format_str; | ||||
|     c.format(&formatter, c.value, &format); | ||||
|   } | ||||
| }; | ||||
| }  // namespace internal
 | ||||
| }  // namespace fmt
 | ||||
| 
 | ||||
| FMT_FUNC void fmt::SystemError::init( | ||||
| FMT_FUNC void SystemError::init( | ||||
|     int err_code, CStringRef format_str, ArgList args) { | ||||
|   error_code_ = err_code; | ||||
|   MemoryWriter w; | ||||
|   internal::format_system_error(w, err_code, format(format_str, args)); | ||||
|   format_system_error(w, err_code, format(format_str, args)); | ||||
|   std::runtime_error &base = *this; | ||||
|   base = std::runtime_error(w.str()); | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| int fmt::internal::CharTraits<char>::format_float( | ||||
| int internal::CharTraits<char>::format_float( | ||||
|     char *buffer, std::size_t size, const char *format, | ||||
|     unsigned width, int precision, T value) { | ||||
|   if (width == 0) { | ||||
| @ -459,7 +237,7 @@ int fmt::internal::CharTraits<char>::format_float( | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| int fmt::internal::CharTraits<wchar_t>::format_float( | ||||
| int internal::CharTraits<wchar_t>::format_float( | ||||
|     wchar_t *buffer, std::size_t size, const wchar_t *format, | ||||
|     unsigned width, int precision, T value) { | ||||
|   if (width == 0) { | ||||
| @ -473,7 +251,7 @@ int fmt::internal::CharTraits<wchar_t>::format_float( | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| const char fmt::internal::BasicData<T>::DIGITS[] = | ||||
| const char internal::BasicData<T>::DIGITS[] = | ||||
|     "0001020304050607080910111213141516171819" | ||||
|     "2021222324252627282930313233343536373839" | ||||
|     "4041424344454647484950515253545556575859" | ||||
| @ -492,40 +270,40 @@ const char fmt::internal::BasicData<T>::DIGITS[] = | ||||
|   factor * 1000000000 | ||||
| 
 | ||||
| template <typename T> | ||||
| const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = { | ||||
| const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = { | ||||
|   0, FMT_POWERS_OF_10(1) | ||||
| }; | ||||
| 
 | ||||
| template <typename T> | ||||
| const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = { | ||||
| const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = { | ||||
|   0, | ||||
|   FMT_POWERS_OF_10(1), | ||||
|   FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), | ||||
|   FMT_POWERS_OF_10(ULongLong(1000000000)), | ||||
|   // Multiply several constants instead of using a single long long constant
 | ||||
|   // to avoid warnings about C++98 not supporting long long.
 | ||||
|   fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 | ||||
|   ULongLong(1000000000) * ULongLong(1000000000) * 10 | ||||
| }; | ||||
| 
 | ||||
| FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { | ||||
| FMT_FUNC void internal::report_unknown_type(char code, const char *type) { | ||||
|   (void)type; | ||||
|   if (std::isprint(static_cast<unsigned char>(code))) { | ||||
|     FMT_THROW(fmt::FormatError( | ||||
|         fmt::format("unknown format code '{}' for {}", code, type))); | ||||
|     FMT_THROW(FormatError( | ||||
|         format("unknown format code '{}' for {}", code, type))); | ||||
|   } | ||||
|   FMT_THROW(fmt::FormatError( | ||||
|       fmt::format("unknown format code '\\x{:02x}' for {}", | ||||
|   FMT_THROW(FormatError( | ||||
|       format("unknown format code '\\x{:02x}' for {}", | ||||
|         static_cast<unsigned>(code), type))); | ||||
| } | ||||
| 
 | ||||
| #if FMT_USE_WINDOWS_H | ||||
| 
 | ||||
| FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { | ||||
| FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { | ||||
|   static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; | ||||
|   if (s.size() > INT_MAX) | ||||
|     FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); | ||||
|   int s_size = static_cast<int>(s.size()); | ||||
|   int length = MultiByteToWideChar( | ||||
|       CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); | ||||
|       CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); | ||||
|   if (length == 0) | ||||
|     FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); | ||||
|   buffer_.resize(length + 1); | ||||
| @ -536,30 +314,31 @@ FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { | ||||
|   buffer_[length] = 0; | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { | ||||
| FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { | ||||
|   if (int error_code = convert(s)) { | ||||
|     FMT_THROW(WindowsError(error_code, | ||||
|         "cannot convert string from UTF-16 to UTF-8")); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { | ||||
| FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { | ||||
|   if (s.size() > INT_MAX) | ||||
|     return ERROR_INVALID_PARAMETER; | ||||
|   int s_size = static_cast<int>(s.size()); | ||||
|   int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); | ||||
|   int length = WideCharToMultiByte( | ||||
|     CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); | ||||
|   if (length == 0) | ||||
|     return GetLastError(); | ||||
|   buffer_.resize(length + 1); | ||||
|   length = WideCharToMultiByte( | ||||
|     CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); | ||||
|     CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); | ||||
|   if (length == 0) | ||||
|     return GetLastError(); | ||||
|   buffer_[length] = 0; | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void fmt::WindowsError::init( | ||||
| FMT_FUNC void WindowsError::init( | ||||
|     int err_code, CStringRef format_str, ArgList args) { | ||||
|   error_code_ = err_code; | ||||
|   MemoryWriter w; | ||||
| @ -568,17 +347,17 @@ FMT_FUNC void fmt::WindowsError::init( | ||||
|   base = std::runtime_error(w.str()); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void fmt::internal::format_windows_error( | ||||
|     fmt::Writer &out, int error_code, | ||||
|     fmt::StringRef message) FMT_NOEXCEPT { | ||||
| FMT_FUNC void internal::format_windows_error( | ||||
|     Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { | ||||
|   FMT_TRY { | ||||
|     MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; | ||||
|     buffer.resize(INLINE_BUFFER_SIZE); | ||||
|     for (;;) { | ||||
|       wchar_t *system_message = &buffer[0]; | ||||
|       int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
|                                   0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
|                                   system_message, static_cast<uint32_t>(buffer.size()), 0); | ||||
|       int result = FormatMessageW( | ||||
|         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
|         FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
|         system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL); | ||||
|       if (result != 0) { | ||||
|         UTF16ToUTF8 utf8_message; | ||||
|         if (utf8_message.convert(system_message) == ERROR_SUCCESS) { | ||||
| @ -597,12 +376,11 @@ FMT_FUNC void fmt::internal::format_windows_error( | ||||
| 
 | ||||
| #endif  // FMT_USE_WINDOWS_H
 | ||||
| 
 | ||||
| FMT_FUNC void fmt::internal::format_system_error( | ||||
|     fmt::Writer &out, int error_code, | ||||
|     fmt::StringRef message) FMT_NOEXCEPT { | ||||
| FMT_FUNC void format_system_error( | ||||
|     Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { | ||||
|   FMT_TRY { | ||||
|     MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer; | ||||
|     buffer.resize(INLINE_BUFFER_SIZE); | ||||
|     internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer; | ||||
|     buffer.resize(internal::INLINE_BUFFER_SIZE); | ||||
|     for (;;) { | ||||
|       char *system_message = &buffer[0]; | ||||
|       int result = safe_strerror(error_code, system_message, buffer.size()); | ||||
| @ -619,11 +397,11 @@ FMT_FUNC void fmt::internal::format_system_error( | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| void fmt::internal::ArgMap<Char>::init(const ArgList &args) { | ||||
| void internal::ArgMap<Char>::init(const ArgList &args) { | ||||
|   if (!map_.empty()) | ||||
|     return; | ||||
|   typedef internal::NamedArg<Char> NamedArg; | ||||
|   const NamedArg *named_arg = 0; | ||||
|   const NamedArg *named_arg = FMT_NULL; | ||||
|   bool use_values = | ||||
|       args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; | ||||
|   if (use_values) { | ||||
| @ -664,18 +442,18 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) { | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| void fmt::internal::FixedBuffer<Char>::grow(std::size_t) { | ||||
| void internal::FixedBuffer<Char>::grow(std::size_t) { | ||||
|   FMT_THROW(std::runtime_error("buffer overflow")); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( | ||||
| FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg( | ||||
|     unsigned arg_index, const char *&error) { | ||||
|   Arg arg = args_[arg_index]; | ||||
|   internal::Arg arg = args_[arg_index]; | ||||
|   switch (arg.type) { | ||||
|   case Arg::NONE: | ||||
|   case internal::Arg::NONE: | ||||
|     error = "argument index out of range"; | ||||
|     break; | ||||
|   case Arg::NAMED_ARG: | ||||
|   case internal::Arg::NAMED_ARG: | ||||
|     arg = *static_cast<const internal::Arg*>(arg.pointer); | ||||
|     break; | ||||
|   default: | ||||
| @ -684,203 +462,31 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( | ||||
|   return arg; | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| void fmt::internal::PrintfFormatter<Char>::parse_flags( | ||||
|     FormatSpec &spec, const Char *&s) { | ||||
|   for (;;) { | ||||
|     switch (*s++) { | ||||
|       case '-': | ||||
|         spec.align_ = ALIGN_LEFT; | ||||
|         break; | ||||
|       case '+': | ||||
|         spec.flags_ |= SIGN_FLAG | PLUS_FLAG; | ||||
|         break; | ||||
|       case '0': | ||||
|         spec.fill_ = '0'; | ||||
|         break; | ||||
|       case ' ': | ||||
|         spec.flags_ |= SIGN_FLAG; | ||||
|         break; | ||||
|       case '#': | ||||
|         spec.flags_ |= HASH_FLAG; | ||||
|         break; | ||||
|       default: | ||||
|         --s; | ||||
|         return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| Arg fmt::internal::PrintfFormatter<Char>::get_arg( | ||||
|     const Char *s, unsigned arg_index) { | ||||
|   (void)s; | ||||
|   const char *error = 0; | ||||
|   Arg arg = arg_index == UINT_MAX ? | ||||
|     next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); | ||||
|   if (error) | ||||
|     FMT_THROW(FormatError(!*s ? "invalid format string" : error)); | ||||
|   return arg; | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| unsigned fmt::internal::PrintfFormatter<Char>::parse_header( | ||||
|   const Char *&s, FormatSpec &spec) { | ||||
|   unsigned arg_index = UINT_MAX; | ||||
|   Char c = *s; | ||||
|   if (c >= '0' && c <= '9') { | ||||
|     // Parse an argument index (if followed by '$') or a width possibly
 | ||||
|     // preceded with '0' flag(s).
 | ||||
|     unsigned value = parse_nonnegative_int(s); | ||||
|     if (*s == '$') {  // value is an argument index
 | ||||
|       ++s; | ||||
|       arg_index = value; | ||||
|     } else { | ||||
|       if (c == '0') | ||||
|         spec.fill_ = '0'; | ||||
|       if (value != 0) { | ||||
|         // Nonzero value means that we parsed width and don't need to
 | ||||
|         // parse it or flags again, so return now.
 | ||||
|         spec.width_ = value; | ||||
|         return arg_index; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   parse_flags(spec, s); | ||||
|   // Parse width.
 | ||||
|   if (*s >= '0' && *s <= '9') { | ||||
|     spec.width_ = parse_nonnegative_int(s); | ||||
|   } else if (*s == '*') { | ||||
|     ++s; | ||||
|     spec.width_ = WidthHandler(spec).visit(get_arg(s)); | ||||
|   } | ||||
|   return arg_index; | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| void fmt::internal::PrintfFormatter<Char>::format( | ||||
|     BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) { | ||||
|   const Char *start = format_str.c_str(); | ||||
|   const Char *s = start; | ||||
|   while (*s) { | ||||
|     Char c = *s++; | ||||
|     if (c != '%') continue; | ||||
|     if (*s == c) { | ||||
|       write(writer, start, s); | ||||
|       start = ++s; | ||||
|       continue; | ||||
|     } | ||||
|     write(writer, start, s - 1); | ||||
| 
 | ||||
|     FormatSpec spec; | ||||
|     spec.align_ = ALIGN_RIGHT; | ||||
| 
 | ||||
|     // Parse argument index, flags and width.
 | ||||
|     unsigned arg_index = parse_header(s, spec); | ||||
| 
 | ||||
|     // Parse precision.
 | ||||
|     if (*s == '.') { | ||||
|       ++s; | ||||
|       if ('0' <= *s && *s <= '9') { | ||||
|         spec.precision_ = static_cast<int>(parse_nonnegative_int(s)); | ||||
|       } else if (*s == '*') { | ||||
|         ++s; | ||||
|         spec.precision_ = PrecisionHandler().visit(get_arg(s)); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     Arg arg = get_arg(s, arg_index); | ||||
|     if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) | ||||
|       spec.flags_ &= ~to_unsigned<int>(HASH_FLAG); | ||||
|     if (spec.fill_ == '0') { | ||||
|       if (arg.type <= Arg::LAST_NUMERIC_TYPE) | ||||
|         spec.align_ = ALIGN_NUMERIC; | ||||
|       else | ||||
|         spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.
 | ||||
|     } | ||||
| 
 | ||||
|     // Parse length and convert the argument to the required type.
 | ||||
|     switch (*s++) { | ||||
|     case 'h': | ||||
|       if (*s == 'h') | ||||
|         ArgConverter<signed char>(arg, *++s).visit(arg); | ||||
|       else | ||||
|         ArgConverter<short>(arg, *s).visit(arg); | ||||
|       break; | ||||
|     case 'l': | ||||
|       if (*s == 'l') | ||||
|         ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); | ||||
|       else | ||||
|         ArgConverter<long>(arg, *s).visit(arg); | ||||
|       break; | ||||
|     case 'j': | ||||
|       ArgConverter<intmax_t>(arg, *s).visit(arg); | ||||
|       break; | ||||
|     case 'z': | ||||
|       ArgConverter<std::size_t>(arg, *s).visit(arg); | ||||
|       break; | ||||
|     case 't': | ||||
|       ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); | ||||
|       break; | ||||
|     case 'L': | ||||
|       // printf produces garbage when 'L' is omitted for long double, no
 | ||||
|       // need to do the same.
 | ||||
|       break; | ||||
|     default: | ||||
|       --s; | ||||
|       ArgConverter<void>(arg, *s).visit(arg); | ||||
|     } | ||||
| 
 | ||||
|     // Parse type.
 | ||||
|     if (!*s) | ||||
|       FMT_THROW(FormatError("invalid format string")); | ||||
|     spec.type_ = static_cast<char>(*s++); | ||||
|     if (arg.type <= Arg::LAST_INTEGER_TYPE) { | ||||
|       // Normalize type.
 | ||||
|       switch (spec.type_) { | ||||
|       case 'i': case 'u': | ||||
|         spec.type_ = 'd'; | ||||
|         break; | ||||
|       case 'c': | ||||
|         // TODO: handle wchar_t
 | ||||
|         CharConverter(arg).visit(arg); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     start = s; | ||||
| 
 | ||||
|     // Format argument.
 | ||||
|     internal::PrintfArgFormatter<Char>(writer, spec).visit(arg); | ||||
|   } | ||||
|   write(writer, start, s); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void fmt::report_system_error( | ||||
| FMT_FUNC void report_system_error( | ||||
|     int error_code, fmt::StringRef message) FMT_NOEXCEPT { | ||||
|   // 'fmt::' is for bcc32.
 | ||||
|   fmt::report_error(internal::format_system_error, error_code, message); | ||||
|   report_error(format_system_error, error_code, message); | ||||
| } | ||||
| 
 | ||||
| #if FMT_USE_WINDOWS_H | ||||
| FMT_FUNC void fmt::report_windows_error( | ||||
| FMT_FUNC void report_windows_error( | ||||
|     int error_code, fmt::StringRef message) FMT_NOEXCEPT { | ||||
|   // 'fmt::' is for bcc32.
 | ||||
|   fmt::report_error(internal::format_windows_error, error_code, message); | ||||
|   report_error(internal::format_windows_error, error_code, message); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) { | ||||
| FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { | ||||
|   MemoryWriter w; | ||||
|   w.write(format_str, args); | ||||
|   std::fwrite(w.data(), 1, w.size(), f); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { | ||||
| FMT_FUNC void print(CStringRef format_str, ArgList args) { | ||||
|   print(stdout, format_str, args); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { | ||||
| FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { | ||||
|   char escape[] = "\x1b[30m"; | ||||
|   escape[3] = static_cast<char>('0' + c); | ||||
|   std::fputs(escape, stdout); | ||||
| @ -888,53 +494,42 @@ FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { | ||||
|   std::fputs(RESET_COLOR, stdout); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { | ||||
|   MemoryWriter w; | ||||
|   printf(w, format, args); | ||||
|   std::size_t size = w.size(); | ||||
|   return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); | ||||
| } | ||||
| 
 | ||||
| #ifndef FMT_HEADER_ONLY | ||||
| 
 | ||||
| template struct fmt::internal::BasicData<void>; | ||||
| template struct internal::BasicData<void>; | ||||
| 
 | ||||
| // Explicit instantiations for char.
 | ||||
| 
 | ||||
| template void fmt::internal::FixedBuffer<char>::grow(std::size_t); | ||||
| template void internal::FixedBuffer<char>::grow(std::size_t); | ||||
| 
 | ||||
| template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args); | ||||
| template void internal::ArgMap<char>::init(const ArgList &args); | ||||
| 
 | ||||
| template void fmt::internal::PrintfFormatter<char>::format( | ||||
|   BasicWriter<char> &writer, CStringRef format); | ||||
| 
 | ||||
| template int fmt::internal::CharTraits<char>::format_float( | ||||
| template FMT_API int internal::CharTraits<char>::format_float( | ||||
|     char *buffer, std::size_t size, const char *format, | ||||
|     unsigned width, int precision, double value); | ||||
| 
 | ||||
| template int fmt::internal::CharTraits<char>::format_float( | ||||
| template FMT_API int internal::CharTraits<char>::format_float( | ||||
|     char *buffer, std::size_t size, const char *format, | ||||
|     unsigned width, int precision, long double value); | ||||
| 
 | ||||
| // Explicit instantiations for wchar_t.
 | ||||
| 
 | ||||
| template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t); | ||||
| template void internal::FixedBuffer<wchar_t>::grow(std::size_t); | ||||
| 
 | ||||
| template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args); | ||||
| template void internal::ArgMap<wchar_t>::init(const ArgList &args); | ||||
| 
 | ||||
| template void fmt::internal::PrintfFormatter<wchar_t>::format( | ||||
|     BasicWriter<wchar_t> &writer, WCStringRef format); | ||||
| 
 | ||||
| template int fmt::internal::CharTraits<wchar_t>::format_float( | ||||
| template FMT_API int internal::CharTraits<wchar_t>::format_float( | ||||
|     wchar_t *buffer, std::size_t size, const wchar_t *format, | ||||
|     unsigned width, int precision, double value); | ||||
| 
 | ||||
| template int fmt::internal::CharTraits<wchar_t>::format_float( | ||||
| template FMT_API int internal::CharTraits<wchar_t>::format_float( | ||||
|     wchar_t *buffer, std::size_t size, const wchar_t *format, | ||||
|     unsigned width, int precision, long double value); | ||||
| 
 | ||||
| #endif  // FMT_HEADER_ONLY
 | ||||
| 
 | ||||
| }  // namespace fmt
 | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
| # pragma warning(pop) | ||||
| #endif | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -11,9 +11,8 @@ | ||||
| 
 | ||||
| namespace fmt { | ||||
| 
 | ||||
| namespace { | ||||
| // Write the content of w to os.
 | ||||
| void write(std::ostream &os, Writer &w) { | ||||
| namespace internal { | ||||
| FMT_FUNC void write(std::ostream &os, Writer &w) { | ||||
|   const char *data = w.data(); | ||||
|   typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; | ||||
|   UnsignedStreamSize size = w.size(); | ||||
| @ -31,13 +30,6 @@ void write(std::ostream &os, Writer &w) { | ||||
| FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { | ||||
|   MemoryWriter w; | ||||
|   w.write(format_str, args); | ||||
|   write(os, w); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) { | ||||
|   MemoryWriter w; | ||||
|   printf(w, format, args); | ||||
|   write(os, w); | ||||
|   return static_cast<int>(w.size()); | ||||
|   internal::write(os, w); | ||||
| } | ||||
| }  // namespace fmt
 | ||||
|  | ||||
| @ -13,85 +13,76 @@ | ||||
| #include "format.h" | ||||
| #include <ostream> | ||||
| 
 | ||||
| namespace fmt | ||||
| { | ||||
| namespace fmt { | ||||
| 
 | ||||
| namespace internal | ||||
| { | ||||
| namespace internal { | ||||
| 
 | ||||
| template <class Char> | ||||
| class FormatBuf : public std::basic_streambuf<Char> | ||||
| { | ||||
| private: | ||||
|     typedef typename std::basic_streambuf<Char>::int_type int_type; | ||||
|     typedef typename std::basic_streambuf<Char>::traits_type traits_type; | ||||
| class FormatBuf : public std::basic_streambuf<Char> { | ||||
|  private: | ||||
|   typedef typename std::basic_streambuf<Char>::int_type int_type; | ||||
|   typedef typename std::basic_streambuf<Char>::traits_type traits_type; | ||||
| 
 | ||||
|     Buffer<Char> &buffer_; | ||||
|     Char *start_; | ||||
|   Buffer<Char> &buffer_; | ||||
| 
 | ||||
| public: | ||||
|     FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) | ||||
|     { | ||||
|         this->setp(start_, start_ + buffer_.capacity()); | ||||
|     } | ||||
|  public: | ||||
|   FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {} | ||||
| 
 | ||||
|     int_type overflow(int_type ch = traits_type::eof()) | ||||
|     { | ||||
|         if (!traits_type::eq_int_type(ch, traits_type::eof())) | ||||
|         { | ||||
|             size_t buf_size = size(); | ||||
|             buffer_.resize(buf_size); | ||||
|             buffer_.reserve(buf_size * 2); | ||||
|  protected: | ||||
|   // The put-area is actually always empty. This makes the implementation
 | ||||
|   // simpler and has the advantage that the streambuf and the buffer are always
 | ||||
|   // in sync and sputc never writes into uninitialized memory. The obvious
 | ||||
|   // disadvantage is that each call to sputc always results in a (virtual) call
 | ||||
|   // to overflow. There is no disadvantage here for sputn since this always
 | ||||
|   // results in a call to xsputn.
 | ||||
| 
 | ||||
|             start_ = &buffer_[0]; | ||||
|             start_[buf_size] = traits_type::to_char_type(ch); | ||||
|             this->setp(start_+ buf_size + 1, start_ + buf_size * 2); | ||||
|         } | ||||
|         return ch; | ||||
|     } | ||||
|   int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { | ||||
|     if (!traits_type::eq_int_type(ch, traits_type::eof())) | ||||
|       buffer_.push_back(static_cast<Char>(ch)); | ||||
|     return ch; | ||||
|   } | ||||
| 
 | ||||
|     size_t size() const | ||||
|     { | ||||
|         return to_unsigned(this->pptr() - start_); | ||||
|     } | ||||
|   std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { | ||||
|     buffer_.append(s, s + count); | ||||
|     return count; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| Yes &convert(std::ostream &); | ||||
| 
 | ||||
| struct DummyStream : std::ostream | ||||
| { | ||||
|     DummyStream();  // Suppress a bogus warning in MSVC.
 | ||||
|     // Hide all operator<< overloads from std::ostream.
 | ||||
|     void operator<<(Null<>); | ||||
| struct DummyStream : std::ostream { | ||||
|   DummyStream();  // Suppress a bogus warning in MSVC.
 | ||||
|   // Hide all operator<< overloads from std::ostream.
 | ||||
|   void operator<<(Null<>); | ||||
| }; | ||||
| 
 | ||||
| No &operator<<(std::ostream &, int); | ||||
| 
 | ||||
| template<typename T> | ||||
| struct ConvertToIntImpl<T, true> | ||||
| { | ||||
|     // Convert to int only if T doesn't have an overloaded operator<<.
 | ||||
|     enum | ||||
|     { | ||||
|         value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No) | ||||
|     }; | ||||
| struct ConvertToIntImpl<T, true> { | ||||
|   // Convert to int only if T doesn't have an overloaded operator<<.
 | ||||
|   enum { | ||||
|     value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No) | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| // Write the content of w to os.
 | ||||
| FMT_API void write(std::ostream &os, Writer &w); | ||||
| }  // namespace internal
 | ||||
| 
 | ||||
| // Formats a value.
 | ||||
| template <typename Char, typename ArgFormatter, typename T> | ||||
| void format(BasicFormatter<Char, ArgFormatter> &f, | ||||
|             const Char *&format_str, const T &value) | ||||
| { | ||||
|     internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; | ||||
| template <typename Char, typename ArgFormatter_, typename T> | ||||
| void format_arg(BasicFormatter<Char, ArgFormatter_> &f, | ||||
|                 const Char *&format_str, const T &value) { | ||||
|   internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; | ||||
| 
 | ||||
|     internal::FormatBuf<Char> format_buf(buffer); | ||||
|     std::basic_ostream<Char> output(&format_buf); | ||||
|     output << value; | ||||
|   internal::FormatBuf<Char> format_buf(buffer); | ||||
|   std::basic_ostream<Char> output(&format_buf); | ||||
|   output << value; | ||||
| 
 | ||||
|     BasicStringRef<Char> str(&buffer[0], format_buf.size()); | ||||
|     typedef internal::MakeArg< BasicFormatter<Char> > MakeArg; | ||||
|     format_str = f.format(format_str, MakeArg(str)); | ||||
|   BasicStringRef<Char> str(&buffer[0], buffer.size()); | ||||
|   typedef internal::MakeArg< BasicFormatter<Char> > MakeArg; | ||||
|   format_str = f.format(format_str, MakeArg(str)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| @ -105,18 +96,6 @@ void format(BasicFormatter<Char, ArgFormatter> &f, | ||||
|  */ | ||||
| FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); | ||||
| FMT_VARIADIC(void, print, std::ostream &, CStringRef) | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Prints formatted data to the stream *os*. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fprintf(cerr, "Don't %s!", "panic"); | ||||
|   \endrst | ||||
|  */ | ||||
| FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args); | ||||
| FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) | ||||
| }  // namespace fmt
 | ||||
| 
 | ||||
| #ifdef FMT_HEADER_ONLY | ||||
|  | ||||
| @ -21,6 +21,9 @@ | ||||
| #ifndef _WIN32 | ||||
| # include <unistd.h> | ||||
| #else | ||||
| # ifndef WIN32_LEAN_AND_MEAN | ||||
| #  define WIN32_LEAN_AND_MEAN | ||||
| # endif | ||||
| # include <windows.h> | ||||
| # include <io.h> | ||||
| 
 | ||||
| @ -79,7 +82,7 @@ void fmt::BufferedFile::close() { | ||||
|   if (!file_) | ||||
|     return; | ||||
|   int result = FMT_SYSTEM(fclose(file_)); | ||||
|   file_ = 0; | ||||
|   file_ = FMT_NULL; | ||||
|   if (result != 0) | ||||
|     FMT_THROW(SystemError(errno, "cannot close file")); | ||||
| } | ||||
|  | ||||
| @ -51,25 +51,6 @@ | ||||
| # endif | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_GCC_VERSION >= 407 | ||||
| # define FMT_UNUSED __attribute__((unused)) | ||||
| #else | ||||
| # define FMT_UNUSED | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FMT_USE_STATIC_ASSERT | ||||
| # define FMT_USE_STATIC_ASSERT 0 | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ | ||||
|   (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 | ||||
| # define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) | ||||
| #else | ||||
| # define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) | ||||
| # define FMT_STATIC_ASSERT(cond, message) \ | ||||
|   typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED | ||||
| #endif | ||||
| 
 | ||||
| // Retries the expression while it evaluates to error_result and errno
 | ||||
| // equals to EINTR.
 | ||||
| #ifndef _WIN32 | ||||
| @ -83,134 +64,112 @@ | ||||
| 
 | ||||
| #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) | ||||
| 
 | ||||
| namespace fmt | ||||
| { | ||||
| namespace fmt { | ||||
| 
 | ||||
| // An error code.
 | ||||
| class ErrorCode | ||||
| { | ||||
| private: | ||||
|     int value_; | ||||
| class ErrorCode { | ||||
|  private: | ||||
|   int value_; | ||||
| 
 | ||||
| public: | ||||
| explicit ErrorCode(int value = 0) FMT_NOEXCEPT : | ||||
|     value_(value) {} | ||||
|  public: | ||||
|   explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {} | ||||
| 
 | ||||
|     int get() const FMT_NOEXCEPT | ||||
|     { | ||||
|         return value_; | ||||
|     } | ||||
|   int get() const FMT_NOEXCEPT { return value_; } | ||||
| }; | ||||
| 
 | ||||
| // A buffered file.
 | ||||
| class BufferedFile | ||||
| { | ||||
| private: | ||||
|     FILE *file_; | ||||
| class BufferedFile { | ||||
|  private: | ||||
|   FILE *file_; | ||||
| 
 | ||||
|     friend class File; | ||||
|   friend class File; | ||||
| 
 | ||||
|     explicit BufferedFile(FILE *f) : file_(f) {} | ||||
|   explicit BufferedFile(FILE *f) : file_(f) {} | ||||
| 
 | ||||
| public: | ||||
|     // Constructs a BufferedFile object which doesn't represent any file.
 | ||||
| BufferedFile() FMT_NOEXCEPT : | ||||
|     file_(0) {} | ||||
|  public: | ||||
|   // Constructs a BufferedFile object which doesn't represent any file.
 | ||||
|   BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {} | ||||
| 
 | ||||
|     // Destroys the object closing the file it represents if any.
 | ||||
|     ~BufferedFile() FMT_NOEXCEPT; | ||||
|   // Destroys the object closing the file it represents if any.
 | ||||
|   FMT_API ~BufferedFile() FMT_NOEXCEPT; | ||||
| 
 | ||||
| #if !FMT_USE_RVALUE_REFERENCES | ||||
|     // Emulate a move constructor and a move assignment operator if rvalue
 | ||||
|     // references are not supported.
 | ||||
|   // Emulate a move constructor and a move assignment operator if rvalue
 | ||||
|   // references are not supported.
 | ||||
| 
 | ||||
| private: | ||||
|     // A proxy object to emulate a move constructor.
 | ||||
|     // It is private to make it impossible call operator Proxy directly.
 | ||||
|     struct Proxy | ||||
|     { | ||||
|         FILE *file; | ||||
|     }; | ||||
|  private: | ||||
|   // A proxy object to emulate a move constructor.
 | ||||
|   // It is private to make it impossible call operator Proxy directly.
 | ||||
|   struct Proxy { | ||||
|     FILE *file; | ||||
|   }; | ||||
| 
 | ||||
| public: | ||||
|     // A "move constructor" for moving from a temporary.
 | ||||
| BufferedFile(Proxy p) FMT_NOEXCEPT : | ||||
|     file_(p.file) {} | ||||
|   // A "move constructor" for moving from a temporary.
 | ||||
|   BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {} | ||||
| 
 | ||||
|     // A "move constructor" for moving from an lvalue.
 | ||||
| BufferedFile(BufferedFile &f) FMT_NOEXCEPT : | ||||
|     file_(f.file_) | ||||
|     { | ||||
|         f.file_ = 0; | ||||
|     } | ||||
|   // A "move constructor" for moving from an lvalue.
 | ||||
|   BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { | ||||
|     f.file_ = FMT_NULL; | ||||
|   } | ||||
| 
 | ||||
|     // A "move assignment operator" for moving from a temporary.
 | ||||
|     BufferedFile &operator=(Proxy p) | ||||
|     { | ||||
|         close(); | ||||
|         file_ = p.file; | ||||
|         return *this; | ||||
|     } | ||||
|   // A "move assignment operator" for moving from a temporary.
 | ||||
|   BufferedFile &operator=(Proxy p) { | ||||
|     close(); | ||||
|     file_ = p.file; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|     // A "move assignment operator" for moving from an lvalue.
 | ||||
|     BufferedFile &operator=(BufferedFile &other) | ||||
|     { | ||||
|         close(); | ||||
|         file_ = other.file_; | ||||
|         other.file_ = 0; | ||||
|         return *this; | ||||
|     } | ||||
|   // A "move assignment operator" for moving from an lvalue.
 | ||||
|   BufferedFile &operator=(BufferedFile &other) { | ||||
|     close(); | ||||
|     file_ = other.file_; | ||||
|     other.file_ = FMT_NULL; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|     // Returns a proxy object for moving from a temporary:
 | ||||
|     //   BufferedFile file = BufferedFile(...);
 | ||||
|     operator Proxy() FMT_NOEXCEPT | ||||
|     { | ||||
|         Proxy p = {file_}; | ||||
|         file_ = 0; | ||||
|         return p; | ||||
|     } | ||||
|   // Returns a proxy object for moving from a temporary:
 | ||||
|   //   BufferedFile file = BufferedFile(...);
 | ||||
|   operator Proxy() FMT_NOEXCEPT { | ||||
|     Proxy p = {file_}; | ||||
|     file_ = FMT_NULL; | ||||
|     return p; | ||||
|   } | ||||
| 
 | ||||
| #else | ||||
| private: | ||||
|     FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); | ||||
|  private: | ||||
|   FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); | ||||
| 
 | ||||
| public: | ||||
| BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : | ||||
|     file_(other.file_) | ||||
|     { | ||||
|         other.file_ = 0; | ||||
|     } | ||||
|  public: | ||||
|   BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) { | ||||
|     other.file_ = FMT_NULL; | ||||
|   } | ||||
| 
 | ||||
|     BufferedFile& operator=(BufferedFile &&other) | ||||
|     { | ||||
|         close(); | ||||
|         file_ = other.file_; | ||||
|         other.file_ = 0; | ||||
|         return *this; | ||||
|     } | ||||
|   BufferedFile& operator=(BufferedFile &&other) { | ||||
|     close(); | ||||
|     file_ = other.file_; | ||||
|     other.file_ = FMT_NULL; | ||||
|     return *this; | ||||
|   } | ||||
| #endif | ||||
| 
 | ||||
|     // Opens a file.
 | ||||
|     BufferedFile(CStringRef filename, CStringRef mode); | ||||
|   // Opens a file.
 | ||||
|   FMT_API BufferedFile(CStringRef filename, CStringRef mode); | ||||
| 
 | ||||
|     // Closes the file.
 | ||||
|     void close(); | ||||
|   // Closes the file.
 | ||||
|   FMT_API void close(); | ||||
| 
 | ||||
|     // Returns the pointer to a FILE object representing this file.
 | ||||
|     FILE *get() const FMT_NOEXCEPT | ||||
|     { | ||||
|         return file_; | ||||
|     } | ||||
|   // Returns the pointer to a FILE object representing this file.
 | ||||
|   FILE *get() const FMT_NOEXCEPT { return file_; } | ||||
| 
 | ||||
|     // We place parentheses around fileno to workaround a bug in some versions
 | ||||
|     // of MinGW that define fileno as a macro.
 | ||||
|     int (fileno)() const; | ||||
|   // We place parentheses around fileno to workaround a bug in some versions
 | ||||
|   // of MinGW that define fileno as a macro.
 | ||||
|   FMT_API int (fileno)() const; | ||||
| 
 | ||||
|     void print(CStringRef format_str, const ArgList &args) | ||||
|     { | ||||
|         fmt::print(file_, format_str, args); | ||||
|     } | ||||
|     FMT_VARIADIC(void, print, CStringRef) | ||||
|   void print(CStringRef format_str, const ArgList &args) { | ||||
|     fmt::print(file_, format_str, args); | ||||
|   } | ||||
|   FMT_VARIADIC(void, print, CStringRef) | ||||
| }; | ||||
| 
 | ||||
| // A file. Closed file is represented by a File object with descriptor -1.
 | ||||
| @ -219,141 +178,125 @@ BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : | ||||
| // closing the file multiple times will cause a crash on Windows rather
 | ||||
| // than an exception. You can get standard behavior by overriding the
 | ||||
| // invalid parameter handler with _set_invalid_parameter_handler.
 | ||||
| class File | ||||
| { | ||||
| private: | ||||
|     int fd_;  // File descriptor.
 | ||||
| class File { | ||||
|  private: | ||||
|   int fd_;  // File descriptor.
 | ||||
| 
 | ||||
|     // Constructs a File object with a given descriptor.
 | ||||
|     explicit File(int fd) : fd_(fd) {} | ||||
|   // Constructs a File object with a given descriptor.
 | ||||
|   explicit File(int fd) : fd_(fd) {} | ||||
| 
 | ||||
| public: | ||||
|     // Possible values for the oflag argument to the constructor.
 | ||||
|     enum | ||||
|     { | ||||
|         RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
 | ||||
|         WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
 | ||||
|         RDWR   = FMT_POSIX(O_RDWR)    // Open for reading and writing.
 | ||||
|     }; | ||||
|  public: | ||||
|   // Possible values for the oflag argument to the constructor.
 | ||||
|   enum { | ||||
|     RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
 | ||||
|     WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
 | ||||
|     RDWR   = FMT_POSIX(O_RDWR)    // Open for reading and writing.
 | ||||
|   }; | ||||
| 
 | ||||
|     // Constructs a File object which doesn't represent any file.
 | ||||
| File() FMT_NOEXCEPT : | ||||
|     fd_(-1) {} | ||||
|   // Constructs a File object which doesn't represent any file.
 | ||||
|   File() FMT_NOEXCEPT : fd_(-1) {} | ||||
| 
 | ||||
|     // Opens a file and constructs a File object representing this file.
 | ||||
|     File(CStringRef path, int oflag); | ||||
|   // Opens a file and constructs a File object representing this file.
 | ||||
|   FMT_API File(CStringRef path, int oflag); | ||||
| 
 | ||||
| #if !FMT_USE_RVALUE_REFERENCES | ||||
|     // Emulate a move constructor and a move assignment operator if rvalue
 | ||||
|     // references are not supported.
 | ||||
|   // Emulate a move constructor and a move assignment operator if rvalue
 | ||||
|   // references are not supported.
 | ||||
| 
 | ||||
| private: | ||||
|     // A proxy object to emulate a move constructor.
 | ||||
|     // It is private to make it impossible call operator Proxy directly.
 | ||||
|     struct Proxy | ||||
|     { | ||||
|         int fd; | ||||
|     }; | ||||
|  private: | ||||
|   // A proxy object to emulate a move constructor.
 | ||||
|   // It is private to make it impossible call operator Proxy directly.
 | ||||
|   struct Proxy { | ||||
|     int fd; | ||||
|   }; | ||||
| 
 | ||||
| public: | ||||
|     // A "move constructor" for moving from a temporary.
 | ||||
| File(Proxy p) FMT_NOEXCEPT : | ||||
|     fd_(p.fd) {} | ||||
|  public: | ||||
|   // A "move constructor" for moving from a temporary.
 | ||||
|   File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} | ||||
| 
 | ||||
|     // A "move constructor" for moving from an lvalue.
 | ||||
| File(File &other) FMT_NOEXCEPT : | ||||
|     fd_(other.fd_) | ||||
|     { | ||||
|         other.fd_ = -1; | ||||
|     } | ||||
|   // A "move constructor" for moving from an lvalue.
 | ||||
|   File(File &other) FMT_NOEXCEPT : fd_(other.fd_) { | ||||
|     other.fd_ = -1; | ||||
|   } | ||||
| 
 | ||||
|     // A "move assignment operator" for moving from a temporary.
 | ||||
|     File &operator=(Proxy p) | ||||
|     { | ||||
|         close(); | ||||
|         fd_ = p.fd; | ||||
|         return *this; | ||||
|     } | ||||
|   // A "move assignment operator" for moving from a temporary.
 | ||||
|   File &operator=(Proxy p) { | ||||
|     close(); | ||||
|     fd_ = p.fd; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|     // A "move assignment operator" for moving from an lvalue.
 | ||||
|     File &operator=(File &other) | ||||
|     { | ||||
|         close(); | ||||
|         fd_ = other.fd_; | ||||
|         other.fd_ = -1; | ||||
|         return *this; | ||||
|     } | ||||
|   // A "move assignment operator" for moving from an lvalue.
 | ||||
|   File &operator=(File &other) { | ||||
|     close(); | ||||
|     fd_ = other.fd_; | ||||
|     other.fd_ = -1; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|     // Returns a proxy object for moving from a temporary:
 | ||||
|     //   File file = File(...);
 | ||||
|     operator Proxy() FMT_NOEXCEPT | ||||
|     { | ||||
|         Proxy p = {fd_}; | ||||
|         fd_ = -1; | ||||
|         return p; | ||||
|     } | ||||
|   // Returns a proxy object for moving from a temporary:
 | ||||
|   //   File file = File(...);
 | ||||
|   operator Proxy() FMT_NOEXCEPT { | ||||
|     Proxy p = {fd_}; | ||||
|     fd_ = -1; | ||||
|     return p; | ||||
|   } | ||||
| 
 | ||||
| #else | ||||
| private: | ||||
|     FMT_DISALLOW_COPY_AND_ASSIGN(File); | ||||
|  private: | ||||
|   FMT_DISALLOW_COPY_AND_ASSIGN(File); | ||||
| 
 | ||||
| public: | ||||
| File(File &&other) FMT_NOEXCEPT : | ||||
|     fd_(other.fd_) | ||||
|     { | ||||
|         other.fd_ = -1; | ||||
|     } | ||||
|  public: | ||||
|   File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) { | ||||
|     other.fd_ = -1; | ||||
|   } | ||||
| 
 | ||||
|     File& operator=(File &&other) | ||||
|     { | ||||
|         close(); | ||||
|         fd_ = other.fd_; | ||||
|         other.fd_ = -1; | ||||
|         return *this; | ||||
|     } | ||||
|   File& operator=(File &&other) { | ||||
|     close(); | ||||
|     fd_ = other.fd_; | ||||
|     other.fd_ = -1; | ||||
|     return *this; | ||||
|   } | ||||
| #endif | ||||
| 
 | ||||
|     // Destroys the object closing the file it represents if any.
 | ||||
|     ~File() FMT_NOEXCEPT; | ||||
|   // Destroys the object closing the file it represents if any.
 | ||||
|   FMT_API ~File() FMT_NOEXCEPT; | ||||
| 
 | ||||
|     // Returns the file descriptor.
 | ||||
|     int descriptor() const FMT_NOEXCEPT | ||||
|     { | ||||
|         return fd_; | ||||
|     } | ||||
|   // Returns the file descriptor.
 | ||||
|   int descriptor() const FMT_NOEXCEPT { return fd_; } | ||||
| 
 | ||||
|     // Closes the file.
 | ||||
|     void close(); | ||||
|   // Closes the file.
 | ||||
|   FMT_API void close(); | ||||
| 
 | ||||
|     // Returns the file size. The size has signed type for consistency with
 | ||||
|     // stat::st_size.
 | ||||
|     LongLong size() const; | ||||
|   // Returns the file size. The size has signed type for consistency with
 | ||||
|   // stat::st_size.
 | ||||
|   FMT_API LongLong size() const; | ||||
| 
 | ||||
|     // Attempts to read count bytes from the file into the specified buffer.
 | ||||
|     std::size_t read(void *buffer, std::size_t count); | ||||
|   // Attempts to read count bytes from the file into the specified buffer.
 | ||||
|   FMT_API std::size_t read(void *buffer, std::size_t count); | ||||
| 
 | ||||
|     // Attempts to write count bytes from the specified buffer to the file.
 | ||||
|     std::size_t write(const void *buffer, std::size_t count); | ||||
|   // Attempts to write count bytes from the specified buffer to the file.
 | ||||
|   FMT_API std::size_t write(const void *buffer, std::size_t count); | ||||
| 
 | ||||
|     // Duplicates a file descriptor with the dup function and returns
 | ||||
|     // the duplicate as a file object.
 | ||||
|     static File dup(int fd); | ||||
|   // Duplicates a file descriptor with the dup function and returns
 | ||||
|   // the duplicate as a file object.
 | ||||
|   FMT_API static File dup(int fd); | ||||
| 
 | ||||
|     // Makes fd be the copy of this file descriptor, closing fd first if
 | ||||
|     // necessary.
 | ||||
|     void dup2(int fd); | ||||
|   // Makes fd be the copy of this file descriptor, closing fd first if
 | ||||
|   // necessary.
 | ||||
|   FMT_API void dup2(int fd); | ||||
| 
 | ||||
|     // Makes fd be the copy of this file descriptor, closing fd first if
 | ||||
|     // necessary.
 | ||||
|     void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; | ||||
|   // Makes fd be the copy of this file descriptor, closing fd first if
 | ||||
|   // necessary.
 | ||||
|   FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; | ||||
| 
 | ||||
|     // Creates a pipe setting up read_end and write_end file objects for reading
 | ||||
|     // and writing respectively.
 | ||||
|     static void pipe(File &read_end, File &write_end); | ||||
|   // Creates a pipe setting up read_end and write_end file objects for reading
 | ||||
|   // and writing respectively.
 | ||||
|   FMT_API static void pipe(File &read_end, File &write_end); | ||||
| 
 | ||||
|     // Creates a BufferedFile object associated with this file and detaches
 | ||||
|     // this File object from the file.
 | ||||
|     BufferedFile fdopen(const char *mode); | ||||
|   // Creates a BufferedFile object associated with this file and detaches
 | ||||
|   // this File object from the file.
 | ||||
|   FMT_API BufferedFile fdopen(const char *mode); | ||||
| }; | ||||
| 
 | ||||
| // Returns the memory page size.
 | ||||
| @ -366,77 +309,58 @@ long getpagesize(); | ||||
| 
 | ||||
| #ifdef FMT_LOCALE | ||||
| // A "C" numeric locale.
 | ||||
| class Locale | ||||
| { | ||||
| private: | ||||
| class Locale { | ||||
|  private: | ||||
| # ifdef _MSC_VER | ||||
|     typedef _locale_t locale_t; | ||||
|   typedef _locale_t locale_t; | ||||
| 
 | ||||
|     enum { LC_NUMERIC_MASK = LC_NUMERIC }; | ||||
|   enum { LC_NUMERIC_MASK = LC_NUMERIC }; | ||||
| 
 | ||||
|     static locale_t newlocale(int category_mask, const char *locale, locale_t) | ||||
|     { | ||||
|         return _create_locale(category_mask, locale); | ||||
|     } | ||||
|   static locale_t newlocale(int category_mask, const char *locale, locale_t) { | ||||
|     return _create_locale(category_mask, locale); | ||||
|   } | ||||
| 
 | ||||
|     static void freelocale(locale_t locale) | ||||
|     { | ||||
|         _free_locale(locale); | ||||
|     } | ||||
|   static void freelocale(locale_t locale) { | ||||
|     _free_locale(locale); | ||||
|   } | ||||
| 
 | ||||
|     static double strtod_l(const char *nptr, char **endptr, _locale_t locale) | ||||
|     { | ||||
|         return _strtod_l(nptr, endptr, locale); | ||||
|     } | ||||
|   static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { | ||||
|     return _strtod_l(nptr, endptr, locale); | ||||
|   } | ||||
| # endif | ||||
| 
 | ||||
|     locale_t locale_; | ||||
|   locale_t locale_; | ||||
| 
 | ||||
|     FMT_DISALLOW_COPY_AND_ASSIGN(Locale); | ||||
|   FMT_DISALLOW_COPY_AND_ASSIGN(Locale); | ||||
| 
 | ||||
| public: | ||||
|     typedef locale_t Type; | ||||
|  public: | ||||
|   typedef locale_t Type; | ||||
| 
 | ||||
|     Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) | ||||
|     { | ||||
|         if (!locale_) | ||||
|             FMT_THROW(fmt::SystemError(errno, "cannot create locale")); | ||||
|     } | ||||
|     ~Locale() | ||||
|     { | ||||
|         freelocale(locale_); | ||||
|     } | ||||
|   Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { | ||||
|     if (!locale_) | ||||
|       FMT_THROW(fmt::SystemError(errno, "cannot create locale")); | ||||
|   } | ||||
|   ~Locale() { freelocale(locale_); } | ||||
| 
 | ||||
|     Type get() const | ||||
|     { | ||||
|         return locale_; | ||||
|     } | ||||
|   Type get() const { return locale_; } | ||||
| 
 | ||||
|     // Converts string to floating-point number and advances str past the end
 | ||||
|     // of the parsed input.
 | ||||
|     double strtod(const char *&str) const | ||||
|     { | ||||
|         char *end = 0; | ||||
|         double result = strtod_l(str, &end, locale_); | ||||
|         str = end; | ||||
|         return result; | ||||
|     } | ||||
|   // Converts string to floating-point number and advances str past the end
 | ||||
|   // of the parsed input.
 | ||||
|   double strtod(const char *&str) const { | ||||
|     char *end = FMT_NULL; | ||||
|     double result = strtod_l(str, &end, locale_); | ||||
|     str = end; | ||||
|     return result; | ||||
|   } | ||||
| }; | ||||
| #endif  // FMT_LOCALE
 | ||||
| }  // namespace fmt
 | ||||
| 
 | ||||
| #if !FMT_USE_RVALUE_REFERENCES | ||||
| namespace std | ||||
| { | ||||
| namespace std { | ||||
| // For compatibility with C++98.
 | ||||
| inline fmt::BufferedFile &move(fmt::BufferedFile &f) | ||||
| { | ||||
|     return f; | ||||
| } | ||||
| inline fmt::File &move(fmt::File &f) | ||||
| { | ||||
|     return f; | ||||
| } | ||||
| inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; } | ||||
| inline fmt::File &move(fmt::File &f) { return f; } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  | ||||
| @ -13,46 +13,131 @@ | ||||
| #include "format.h" | ||||
| #include <ctime> | ||||
| 
 | ||||
| namespace fmt | ||||
| { | ||||
| #ifdef _MSC_VER | ||||
| # pragma warning(push) | ||||
| # pragma warning(disable: 4702)  // unreachable code
 | ||||
| # pragma warning(disable: 4996)  // "deprecated" functions
 | ||||
| #endif | ||||
| 
 | ||||
| namespace fmt { | ||||
| template <typename ArgFormatter> | ||||
| void format(BasicFormatter<char, ArgFormatter> &f, | ||||
|             const char *&format_str, const std::tm &tm) | ||||
| { | ||||
|     if (*format_str == ':') | ||||
|         ++format_str; | ||||
|     const char *end = format_str; | ||||
|     while (*end && *end != '}') | ||||
|         ++end; | ||||
|     if (*end != '}') | ||||
|         FMT_THROW(FormatError("missing '}' in format string")); | ||||
|     internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format; | ||||
|     format.append(format_str, end + 1); | ||||
|     format[format.size() - 1] = '\0'; | ||||
|     Buffer<char> &buffer = f.writer().buffer(); | ||||
|     std::size_t start = buffer.size(); | ||||
|     for (;;) | ||||
|     { | ||||
|         std::size_t size = buffer.capacity() - start; | ||||
|         std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); | ||||
|         if (count != 0) | ||||
|         { | ||||
|             buffer.resize(start + count); | ||||
|             break; | ||||
|         } | ||||
|         if (size >= format.size() * 256) | ||||
|         { | ||||
|             // If the buffer is 256 times larger than the format string, assume
 | ||||
|             // that `strftime` gives an empty result. There doesn't seem to be a
 | ||||
|             // better way to distinguish the two cases:
 | ||||
|             // https://github.com/fmtlib/fmt/issues/367
 | ||||
|             break; | ||||
|         } | ||||
|         const std::size_t MIN_GROWTH = 10; | ||||
|         buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); | ||||
| void format_arg(BasicFormatter<char, ArgFormatter> &f, | ||||
|                 const char *&format_str, const std::tm &tm) { | ||||
|   if (*format_str == ':') | ||||
|     ++format_str; | ||||
|   const char *end = format_str; | ||||
|   while (*end && *end != '}') | ||||
|     ++end; | ||||
|   if (*end != '}') | ||||
|     FMT_THROW(FormatError("missing '}' in format string")); | ||||
|   internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format; | ||||
|   format.append(format_str, end + 1); | ||||
|   format[format.size() - 1] = '\0'; | ||||
|   Buffer<char> &buffer = f.writer().buffer(); | ||||
|   std::size_t start = buffer.size(); | ||||
|   for (;;) { | ||||
|     std::size_t size = buffer.capacity() - start; | ||||
|     std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); | ||||
|     if (count != 0) { | ||||
|       buffer.resize(start + count); | ||||
|       break; | ||||
|     } | ||||
|     format_str = end + 1; | ||||
| } | ||||
|     if (size >= format.size() * 256) { | ||||
|       // If the buffer is 256 times larger than the format string, assume
 | ||||
|       // that `strftime` gives an empty result. There doesn't seem to be a
 | ||||
|       // better way to distinguish the two cases:
 | ||||
|       // https://github.com/fmtlib/fmt/issues/367
 | ||||
|       break; | ||||
|     } | ||||
|     const std::size_t MIN_GROWTH = 10; | ||||
|     buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); | ||||
|   } | ||||
|   format_str = end + 1; | ||||
| } | ||||
| 
 | ||||
| namespace internal{ | ||||
| inline Null<> localtime_r(...) { return Null<>(); } | ||||
| inline Null<> localtime_s(...) { return Null<>(); } | ||||
| inline Null<> gmtime_r(...) { return Null<>(); } | ||||
| inline Null<> gmtime_s(...) { return Null<>(); } | ||||
| } | ||||
| 
 | ||||
| // Thread-safe replacement for std::localtime
 | ||||
| inline std::tm localtime(std::time_t time) { | ||||
|   struct LocalTime { | ||||
|     std::time_t time_; | ||||
|     std::tm tm_; | ||||
| 
 | ||||
|     LocalTime(std::time_t t): time_(t) {} | ||||
| 
 | ||||
|     bool run() { | ||||
|       using namespace fmt::internal; | ||||
|       return handle(localtime_r(&time_, &tm_)); | ||||
|     } | ||||
| 
 | ||||
|     bool handle(std::tm *tm) { return tm != FMT_NULL; } | ||||
| 
 | ||||
|     bool handle(internal::Null<>) { | ||||
|       using namespace fmt::internal; | ||||
|       return fallback(localtime_s(&tm_, &time_)); | ||||
|     } | ||||
| 
 | ||||
|     bool fallback(int res) { return res == 0; } | ||||
| 
 | ||||
|     bool fallback(internal::Null<>) { | ||||
|       using namespace fmt::internal; | ||||
|       std::tm *tm = std::localtime(&time_); | ||||
|       if (tm) tm_ = *tm; | ||||
|       return tm != FMT_NULL; | ||||
|     } | ||||
|   }; | ||||
|   LocalTime lt(time); | ||||
|   if (lt.run()) | ||||
|     return lt.tm_; | ||||
|   // Too big time values may be unsupported.
 | ||||
|   FMT_THROW(fmt::FormatError("time_t value out of range")); | ||||
|   return std::tm(); | ||||
| } | ||||
| 
 | ||||
| // Thread-safe replacement for std::gmtime
 | ||||
| inline std::tm gmtime(std::time_t time) { | ||||
|   struct GMTime { | ||||
|     std::time_t time_; | ||||
|     std::tm tm_; | ||||
| 
 | ||||
|     GMTime(std::time_t t): time_(t) {} | ||||
| 
 | ||||
|     bool run() { | ||||
|       using namespace fmt::internal; | ||||
|       return handle(gmtime_r(&time_, &tm_)); | ||||
|     } | ||||
| 
 | ||||
|     bool handle(std::tm *tm) { return tm != FMT_NULL; } | ||||
| 
 | ||||
|     bool handle(internal::Null<>) { | ||||
|       using namespace fmt::internal; | ||||
|       return fallback(gmtime_s(&tm_, &time_)); | ||||
|     } | ||||
| 
 | ||||
|     bool fallback(int res) { return res == 0; } | ||||
| 
 | ||||
|     bool fallback(internal::Null<>) { | ||||
|       std::tm *tm = std::gmtime(&time_); | ||||
|       if (tm != FMT_NULL) tm_ = *tm; | ||||
|       return tm != FMT_NULL; | ||||
|     } | ||||
|   }; | ||||
|   GMTime gt(time); | ||||
|   if (gt.run()) | ||||
|     return gt.tm_; | ||||
|   // Too big time values may be unsupported.
 | ||||
|   FMT_THROW(fmt::FormatError("time_t value out of range")); | ||||
|   return std::tm(); | ||||
| } | ||||
| } //namespace fmt
 | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
| # pragma warning(pop) | ||||
| #endif | ||||
| 
 | ||||
| #endif  // FMT_TIME_H_
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user