| 
									
										
										
										
											2012-12-07 08:31:09 -08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2014-05-03 09:48:54 -07:00
										 |  |  |  Formatting library for C++ | 
					
						
							| 
									
										
										
										
											2012-12-12 07:44:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-09 06:56:36 -07:00
										 |  |  |  Copyright (c) 2012 - 2014, Victor Zverovich | 
					
						
							| 
									
										
										
										
											2012-12-12 07:44:41 -08:00
										 |  |  |  All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |     list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |     this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |     and/or other materials provided with the distribution. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | 
					
						
							|  |  |  |  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
					
						
							|  |  |  |  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | 
					
						
							|  |  |  |  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 
					
						
							|  |  |  |  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 
					
						
							|  |  |  |  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 
					
						
							|  |  |  |  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
					
						
							|  |  |  |  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							| 
									
										
										
										
											2012-12-07 08:31:09 -08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-16 15:06:31 -08:00
										 |  |  | // Disable useless MSVC warnings.
 | 
					
						
							| 
									
										
										
										
											2012-12-17 15:41:00 -08:00
										 |  |  | #undef _CRT_SECURE_NO_WARNINGS
 | 
					
						
							| 
									
										
										
										
											2012-12-16 15:06:31 -08:00
										 |  |  | #define _CRT_SECURE_NO_WARNINGS
 | 
					
						
							| 
									
										
										
										
											2012-12-21 15:02:25 -08:00
										 |  |  | #undef _SCL_SECURE_NO_WARNINGS
 | 
					
						
							|  |  |  | #define _SCL_SECURE_NO_WARNINGS
 | 
					
						
							| 
									
										
										
										
											2012-12-16 15:06:31 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-14 15:16:20 -08:00
										 |  |  | #include "format.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-30 06:55:21 -07:00
										 |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-12 09:17:28 -08:00
										 |  |  | #include <cctype>
 | 
					
						
							| 
									
										
										
										
											2014-07-01 16:23:50 -07:00
										 |  |  | #include <cerrno>
 | 
					
						
							| 
									
										
										
										
											2014-04-24 12:37:06 -07:00
										 |  |  | #include <climits>
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2013-12-27 08:00:10 -08:00
										 |  |  | #include <cstdarg>
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-30 06:55:21 -07:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2014-05-01 07:09:42 -07:00
										 |  |  | # define WIN32_LEAN_AND_MEAN
 | 
					
						
							| 
									
										
										
										
											2014-06-11 02:38:57 +04:00
										 |  |  | # ifdef __MINGW32__
 | 
					
						
							|  |  |  | #  include <cstring>
 | 
					
						
							|  |  |  | # endif
 | 
					
						
							| 
									
										
										
										
											2014-04-30 06:55:21 -07:00
										 |  |  | # include <windows.h>
 | 
					
						
							| 
									
										
										
										
											2014-04-30 07:41:54 -07:00
										 |  |  | # undef ERROR
 | 
					
						
							| 
									
										
										
										
											2014-04-30 06:55:21 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  | using fmt::LongLong; | 
					
						
							| 
									
										
										
										
											2014-02-15 10:48:34 -08:00
										 |  |  | using fmt::ULongLong; | 
					
						
							| 
									
										
										
										
											2014-07-02 06:33:25 -07:00
										 |  |  | using fmt::internal::Arg; | 
					
						
							| 
									
										
										
										
											2014-02-15 10:48:34 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-11 18:56:24 +00:00
										 |  |  | #if _MSC_VER
 | 
					
						
							|  |  |  | # pragma warning(push)
 | 
					
						
							|  |  |  | # pragma warning(disable: 4127) // conditional expression is constant
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef _MSC_VER
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline int SignBit(double value) { | 
					
						
							|  |  |  |   // When compiled in C++11 mode signbit is no longer a macro but a function
 | 
					
						
							|  |  |  |   // defined in namespace std and the macro is undefined.
 | 
					
						
							| 
									
										
										
										
											2014-04-10 10:49:55 -07:00
										 |  |  | #ifdef signbit
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  |   return signbit(value); | 
					
						
							| 
									
										
										
										
											2014-04-10 10:49:55 -07:00
										 |  |  | #else
 | 
					
						
							|  |  |  |   return std::signbit(value); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline int IsInf(double x) { | 
					
						
							|  |  |  | #ifdef isinf
 | 
					
						
							|  |  |  |   return isinf(x); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |   return std::isinf(x); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FMT_SNPRINTF snprintf
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-27 08:00:10 -08:00
										 |  |  | #else  // _MSC_VER
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | inline int SignBit(double value) { | 
					
						
							|  |  |  |   if (value < 0) return 1; | 
					
						
							|  |  |  |   if (value == value) return 0; | 
					
						
							|  |  |  |   int dec = 0, sign = 0; | 
					
						
							|  |  |  |   char buffer[2];  // The buffer size must be >= 2 or _ecvt_s will fail.
 | 
					
						
							|  |  |  |   _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); | 
					
						
							|  |  |  |   return sign; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline int IsInf(double x) { return !_finite(x); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-27 08:00:10 -08:00
										 |  |  | inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) { | 
					
						
							|  |  |  |   va_list args; | 
					
						
							|  |  |  |   va_start(args, format); | 
					
						
							|  |  |  |   int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); | 
					
						
							|  |  |  |   va_end(args); | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #endif  // _MSC_VER
 | 
					
						
							| 
									
										
										
										
											2014-02-19 14:20:26 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const char RESET_COLOR[] = "\x1b[0m"; | 
					
						
							| 
									
										
										
										
											2014-05-03 09:48:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef void (*FormatFunc)(fmt::Writer &, int , fmt::StringRef); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReportError(FormatFunc func, | 
					
						
							|  |  |  |     int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     fmt::Writer full_message; | 
					
						
							| 
									
										
										
										
											2014-06-21 08:32:00 -07:00
										 |  |  |     func(full_message, error_code, message); // TODO: make sure this doesn't throw
 | 
					
						
							| 
									
										
										
										
											2014-05-03 09:48:54 -07:00
										 |  |  |     std::fwrite(full_message.c_str(), full_message.size(), 1, stderr); | 
					
						
							|  |  |  |     std::fputc('\n', stderr); | 
					
						
							|  |  |  |   } catch (...) {} | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-06-30 07:12:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 06:33:25 -07:00
										 |  |  | const Arg DUMMY_ARG = {Arg::INT, 0}; | 
					
						
							| 
									
										
										
										
											2014-06-30 07:12:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-02 06:33:25 -07:00
										 |  |  | fmt::ULongLong GetIntValue(const Arg &arg) { | 
					
						
							| 
									
										
										
										
											2014-06-30 07:12:09 -07:00
										 |  |  |   switch (arg.type) { | 
					
						
							|  |  |  |     case Arg::INT: | 
					
						
							|  |  |  |       return arg.int_value; | 
					
						
							|  |  |  |     case Arg::UINT: | 
					
						
							|  |  |  |       return arg.uint_value; | 
					
						
							|  |  |  |     case Arg::LONG_LONG: | 
					
						
							|  |  |  |       return arg.long_long_value; | 
					
						
							|  |  |  |     case Arg::ULONG_LONG: | 
					
						
							|  |  |  |       return arg.ulong_long_value; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return -1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-02 06:33:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Parses an unsigned integer advancing s to the end of the parsed input.
 | 
					
						
							|  |  |  | // This function assumes that the first character of s is a digit.
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							|  |  |  | int ParseNonnegativeInt(const Char *&s, const char *&error) FMT_NOEXCEPT(true) { | 
					
						
							|  |  |  |   assert('0' <= *s && *s <= '9'); | 
					
						
							|  |  |  |   unsigned value = 0; | 
					
						
							|  |  |  |   do { | 
					
						
							|  |  |  |     unsigned new_value = value * 10 + (*s++ - '0'); | 
					
						
							|  |  |  |     // Check if value wrapped around.
 | 
					
						
							|  |  |  |     value = new_value >= value ? new_value : UINT_MAX; | 
					
						
							|  |  |  |   } while ('0' <= *s && *s <= '9'); | 
					
						
							|  |  |  |   if (value > INT_MAX) { | 
					
						
							|  |  |  |     if (!error) | 
					
						
							|  |  |  |       error = "number is too big in format"; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return value; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							|  |  |  | const Char *find_closing_brace(const Char *s, int num_open_braces = 1) { | 
					
						
							|  |  |  |   for (int n = num_open_braces; *s; ++s) { | 
					
						
							|  |  |  |     if (*s == '{') { | 
					
						
							|  |  |  |       ++n; | 
					
						
							|  |  |  |     } else if (*s == '}') { | 
					
						
							|  |  |  |       if (--n == 0) | 
					
						
							|  |  |  |         return s; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   throw fmt::FormatError("unmatched '{' in format"); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 08:04:17 -07:00
										 |  |  | // Checks if an argument is a valid printf width specifier and sets
 | 
					
						
							|  |  |  | // left alignment if it is negative.
 | 
					
						
							| 
									
										
										
										
											2014-07-16 07:27:54 -07:00
										 |  |  | struct WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> { | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  |  private: | 
					
						
							|  |  |  |   fmt::FormatSpec &spec_; | 
					
						
							| 
									
										
										
										
											2014-07-14 08:04:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  |  public: | 
					
						
							|  |  |  |   explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} | 
					
						
							| 
									
										
										
										
											2014-07-14 08:04:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 07:27:54 -07:00
										 |  |  |   unsigned visit_unhandled_arg() { | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  |     throw fmt::FormatError("width is not integer"); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-14 08:04:17 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 07:27:54 -07:00
										 |  |  |   template <typename T> | 
					
						
							|  |  |  |   unsigned visit_any_int(T value) { | 
					
						
							|  |  |  |     typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType; | 
					
						
							|  |  |  |     UnsignedType width = value; | 
					
						
							|  |  |  |     if (fmt::internal::is_negative(value)) { | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  |       spec_.align_ = fmt::ALIGN_LEFT; | 
					
						
							|  |  |  |       width = 0 - width; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-16 07:27:54 -07:00
										 |  |  |     if (width > INT_MAX) | 
					
						
							|  |  |  |       throw fmt::FormatError("number is too big in format"); | 
					
						
							|  |  |  |     return static_cast<unsigned>(width); | 
					
						
							| 
									
										
										
										
											2014-07-14 06:55:29 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // This function template is used to prevent compile errors when handling
 | 
					
						
							|  |  |  | // incompatible string arguments, e.g. handling a wide string in a narrow
 | 
					
						
							|  |  |  | // string formatter.
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							|  |  |  | Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <> | 
					
						
							|  |  |  | inline Arg::StringValue<char> ignore_incompatible_str( | 
					
						
							|  |  |  |     Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <> | 
					
						
							|  |  |  | inline Arg::StringValue<wchar_t> ignore_incompatible_str( | 
					
						
							|  |  |  |     Arg::StringValue<wchar_t> s) { return s; } | 
					
						
							| 
									
										
										
										
											2014-05-03 09:48:54 -07:00
										 |  |  | }  // namespace
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 10:46:01 -07:00
										 |  |  | int fmt::internal::SignBitNoInline(double value) { return SignBit(value); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  | void fmt::SystemError::init( | 
					
						
							|  |  |  |     int error_code, StringRef format_str, const ArgList &args) { | 
					
						
							|  |  |  |   error_code_ = error_code; | 
					
						
							|  |  |  |   Writer w; | 
					
						
							|  |  |  |   internal::FormatSystemErrorMessage(w, error_code, format(format_str, args)); | 
					
						
							|  |  |  |   std::runtime_error &base = *this; | 
					
						
							|  |  |  |   base = std::runtime_error(w.str()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  | template <typename T> | 
					
						
							| 
									
										
										
										
											2014-07-26 08:03:03 -07:00
										 |  |  | int fmt::internal::CharTraits<char>::format_float( | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  |     char *buffer, std::size_t size, const char *format, | 
					
						
							|  |  |  |     unsigned width, int precision, T value) { | 
					
						
							|  |  |  |   if (width == 0) { | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  |     return precision < 0 ? | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  |         FMT_SNPRINTF(buffer, size, format, value) : | 
					
						
							|  |  |  |         FMT_SNPRINTF(buffer, size, format, precision, value); | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  |   return precision < 0 ? | 
					
						
							|  |  |  |       FMT_SNPRINTF(buffer, size, format, width, value) : | 
					
						
							|  |  |  |       FMT_SNPRINTF(buffer, size, format, width, precision, value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename T> | 
					
						
							| 
									
										
										
										
											2014-07-26 08:03:03 -07:00
										 |  |  | int fmt::internal::CharTraits<wchar_t>::format_float( | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  |     wchar_t *buffer, std::size_t size, const wchar_t *format, | 
					
						
							|  |  |  |     unsigned width, int precision, T value) { | 
					
						
							|  |  |  |   if (width == 0) { | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  |     return precision < 0 ? | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  |         swprintf(buffer, size, format, value) : | 
					
						
							|  |  |  |         swprintf(buffer, size, format, precision, value); | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-09-09 22:21:40 -07:00
										 |  |  |   return precision < 0 ? | 
					
						
							|  |  |  |       swprintf(buffer, size, format, width, value) : | 
					
						
							|  |  |  |       swprintf(buffer, size, format, width, precision, value); | 
					
						
							| 
									
										
										
										
											2013-09-09 06:51:03 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2012-12-12 09:29:50 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-09 06:51:03 -07:00
										 |  |  | const char fmt::internal::DIGITS[] = | 
					
						
							| 
									
										
										
										
											2013-01-26 16:07:28 -08:00
										 |  |  |     "0001020304050607080910111213141516171819" | 
					
						
							|  |  |  |     "2021222324252627282930313233343536373839" | 
					
						
							|  |  |  |     "4041424344454647484950515253545556575859" | 
					
						
							|  |  |  |     "6061626364656667686970717273747576777879" | 
					
						
							|  |  |  |     "8081828384858687888990919293949596979899"; | 
					
						
							| 
									
										
										
										
											2014-02-19 12:43:55 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-19 13:02:22 -08:00
										 |  |  | #define FMT_POWERS_OF_10(factor) \
 | 
					
						
							|  |  |  |   factor * 10, \ | 
					
						
							|  |  |  |   factor * 100, \ | 
					
						
							|  |  |  |   factor * 1000, \ | 
					
						
							|  |  |  |   factor * 10000, \ | 
					
						
							|  |  |  |   factor * 100000, \ | 
					
						
							|  |  |  |   factor * 1000000, \ | 
					
						
							|  |  |  |   factor * 10000000, \ | 
					
						
							|  |  |  |   factor * 100000000, \ | 
					
						
							|  |  |  |   factor * 1000000000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)}; | 
					
						
							| 
									
										
										
										
											2014-02-19 12:43:55 -08:00
										 |  |  | const uint64_t fmt::internal::POWERS_OF_10_64[] = { | 
					
						
							| 
									
										
										
										
											2014-02-14 10:36:17 -08:00
										 |  |  |   0, | 
					
						
							| 
									
										
										
										
											2014-02-19 13:02:22 -08:00
										 |  |  |   FMT_POWERS_OF_10(1), | 
					
						
							|  |  |  |   FMT_POWERS_OF_10(ULongLong(1000000000)), | 
					
						
							|  |  |  |   // Multiply several constants instead of using a single long long constants
 | 
					
						
							|  |  |  |   // to avoid warnings about C++98 not supporting long long.
 | 
					
						
							| 
									
										
										
										
											2014-02-15 11:16:44 -08:00
										 |  |  |   ULongLong(1000000000) * ULongLong(1000000000) * 10 | 
					
						
							| 
									
										
										
										
											2014-02-14 10:36:17 -08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2013-01-08 09:56:05 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-26 08:42:19 -07:00
										 |  |  | void fmt::internal::report_unknown_type(char code, const char *type) { | 
					
						
							| 
									
										
										
										
											2013-01-08 09:56:05 -08:00
										 |  |  |   if (std::isprint(static_cast<unsigned char>(code))) { | 
					
						
							| 
									
										
										
										
											2014-06-30 06:43:53 -07:00
										 |  |  |     throw fmt::FormatError( | 
					
						
							|  |  |  |         fmt::format("unknown format code '{}' for {}", code, type)); | 
					
						
							| 
									
										
										
										
											2013-01-08 09:56:05 -08:00
										 |  |  |   } | 
					
						
							|  |  |  |   throw fmt::FormatError( | 
					
						
							| 
									
										
										
										
											2014-06-30 06:43:53 -07:00
										 |  |  |       fmt::format("unknown format code '\\x{:02x}' for {}", | 
					
						
							|  |  |  |         static_cast<unsigned>(code), type)); | 
					
						
							| 
									
										
										
										
											2013-01-08 09:56:05 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-30 07:23:43 -07:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { | 
					
						
							|  |  |  |   int length = MultiByteToWideChar( | 
					
						
							|  |  |  |       CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); | 
					
						
							|  |  |  |   static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; | 
					
						
							|  |  |  |   if (length == 0) | 
					
						
							| 
									
										
										
										
											2014-06-30 17:32:08 -07:00
										 |  |  |     throw WindowsError(GetLastError(), ERROR); | 
					
						
							| 
									
										
										
										
											2014-04-30 07:23:43 -07:00
										 |  |  |   buffer_.resize(length); | 
					
						
							|  |  |  |   length = MultiByteToWideChar( | 
					
						
							|  |  |  |     CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); | 
					
						
							|  |  |  |   if (length == 0) | 
					
						
							| 
									
										
										
										
											2014-06-30 17:32:08 -07:00
										 |  |  |     throw WindowsError(GetLastError(), ERROR); | 
					
						
							| 
									
										
										
										
											2014-04-30 07:23:43 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { | 
					
						
							|  |  |  |   if (int error_code = Convert(s)) { | 
					
						
							| 
									
										
										
										
											2014-07-09 08:39:01 -07:00
										 |  |  |     throw WindowsError(error_code, | 
					
						
							| 
									
										
										
										
											2014-04-30 07:23:43 -07:00
										 |  |  |         "cannot convert string from UTF-16 to UTF-8"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) { | 
					
						
							|  |  |  |   int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); | 
					
						
							|  |  |  |   if (length == 0) | 
					
						
							|  |  |  |     return GetLastError(); | 
					
						
							|  |  |  |   buffer_.resize(length); | 
					
						
							|  |  |  |   length = WideCharToMultiByte( | 
					
						
							|  |  |  |     CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); | 
					
						
							|  |  |  |   if (length == 0) | 
					
						
							|  |  |  |     return GetLastError(); | 
					
						
							|  |  |  |   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  | void fmt::WindowsError::init( | 
					
						
							|  |  |  |     int error_code, StringRef format_str, const ArgList &args) { | 
					
						
							|  |  |  |   error_code_ = error_code; | 
					
						
							|  |  |  |   Writer w; | 
					
						
							|  |  |  |   internal::FormatWinErrorMessage(w, error_code, format(format_str, args)); | 
					
						
							|  |  |  |   std::runtime_error &base = *this; | 
					
						
							|  |  |  |   base = std::runtime_error(w.str()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-30 07:23:43 -07:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-30 11:20:41 -07:00
										 |  |  | int fmt::internal::StrError( | 
					
						
							| 
									
										
										
										
											2014-05-03 09:48:54 -07:00
										 |  |  |     int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) { | 
					
						
							| 
									
										
										
										
											2014-04-30 09:42:48 -07:00
										 |  |  |   assert(buffer != 0 && buffer_size != 0); | 
					
						
							| 
									
										
										
										
											2014-04-30 11:20:41 -07:00
										 |  |  |   int result = 0; | 
					
						
							| 
									
										
										
										
											2014-04-30 09:42:48 -07:00
										 |  |  | #ifdef _GNU_SOURCE
 | 
					
						
							|  |  |  |   char *message = strerror_r(error_code, buffer, buffer_size); | 
					
						
							| 
									
										
										
										
											2014-04-30 11:20:41 -07:00
										 |  |  |   // If the buffer is full then the message is probably truncated.
 | 
					
						
							| 
									
										
										
										
											2014-04-30 09:42:48 -07:00
										 |  |  |   if (message == buffer && strlen(buffer) == buffer_size - 1) | 
					
						
							| 
									
										
										
										
											2014-04-30 11:20:41 -07:00
										 |  |  |     result = ERANGE; | 
					
						
							|  |  |  |   buffer = message; | 
					
						
							| 
									
										
										
										
											2014-07-09 09:45:18 -07:00
										 |  |  | #elif __MINGW32__
 | 
					
						
							|  |  |  |   errno = 0; | 
					
						
							|  |  |  |   (void)buffer_size; | 
					
						
							|  |  |  |   buffer = strerror(error_code); | 
					
						
							|  |  |  |   result = errno; | 
					
						
							|  |  |  | #elif _WIN32
 | 
					
						
							| 
									
										
										
										
											2014-04-30 11:20:41 -07:00
										 |  |  |   result = strerror_s(buffer, buffer_size, error_code); | 
					
						
							|  |  |  |   // If the buffer is full then the message is probably truncated.
 | 
					
						
							|  |  |  |   if (result == 0 && std::strlen(buffer) == buffer_size - 1) | 
					
						
							|  |  |  |     result = ERANGE; | 
					
						
							| 
									
										
										
										
											2014-04-30 09:42:48 -07:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2014-04-30 11:20:41 -07:00
										 |  |  |   result = strerror_r(error_code, buffer, buffer_size); | 
					
						
							|  |  |  |   if (result == -1) | 
					
						
							|  |  |  |     result = errno;  // glibc versions before 2.13 return result in errno.
 | 
					
						
							| 
									
										
										
										
											2014-04-30 06:55:21 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-04-30 11:20:41 -07:00
										 |  |  |   return result; | 
					
						
							| 
									
										
										
										
											2014-04-30 06:55:21 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-30 15:00:41 -07:00
										 |  |  | void fmt::internal::FormatSystemErrorMessage( | 
					
						
							|  |  |  |     fmt::Writer &out, int error_code, fmt::StringRef message) { | 
					
						
							|  |  |  |   Array<char, INLINE_BUFFER_SIZE> buffer; | 
					
						
							|  |  |  |   buffer.resize(INLINE_BUFFER_SIZE); | 
					
						
							|  |  |  |   char *system_message = 0; | 
					
						
							|  |  |  |   for (;;) { | 
					
						
							|  |  |  |     system_message = &buffer[0]; | 
					
						
							|  |  |  |     int result = StrError(error_code, system_message, buffer.size()); | 
					
						
							|  |  |  |     if (result == 0) | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     if (result != ERANGE) { | 
					
						
							|  |  |  |       // Can't get error message, report error code instead.
 | 
					
						
							|  |  |  |       out << message << ": error code = " << error_code; | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     buffer.resize(buffer.size() * 2); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   out << message << ": " << system_message; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef _WIN32
 | 
					
						
							|  |  |  | void fmt::internal::FormatWinErrorMessage( | 
					
						
							|  |  |  |     fmt::Writer &out, int error_code, fmt::StringRef message) { | 
					
						
							|  |  |  |   class String { | 
					
						
							|  |  |  |    private: | 
					
						
							|  |  |  |     LPWSTR str_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    public: | 
					
						
							|  |  |  |     String() : str_() {} | 
					
						
							|  |  |  |     ~String() { LocalFree(str_); } | 
					
						
							|  |  |  |     LPWSTR *ptr() { return &str_; } | 
					
						
							|  |  |  |     LPCWSTR c_str() const { return str_; } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   String system_message; | 
					
						
							|  |  |  |   if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | | 
					
						
							|  |  |  |       FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, | 
					
						
							|  |  |  |       error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | 
					
						
							|  |  |  |       reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) { | 
					
						
							|  |  |  |     UTF16ToUTF8 utf8_message; | 
					
						
							|  |  |  |     if (!utf8_message.Convert(system_message.c_str())) { | 
					
						
							| 
									
										
										
										
											2014-06-30 17:40:53 -07:00
										 |  |  |       out << message << ": " << utf8_message; | 
					
						
							| 
									
										
										
										
											2014-04-30 15:00:41 -07:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   // Can't get error message, report error code instead.
 | 
					
						
							|  |  |  |   out << message << ": error code = " << error_code; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  | // An argument formatter.
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							|  |  |  | class fmt::internal::ArgFormatter : | 
					
						
							|  |  |  |     public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> { | 
					
						
							|  |  |  |  private: | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |   fmt::BasicFormatter<Char> &formatter_; | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  |   fmt::BasicWriter<Char> &writer_; | 
					
						
							|  |  |  |   fmt::FormatSpec &spec_; | 
					
						
							|  |  |  |   const Char *format_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							| 
									
										
										
										
											2014-07-26 09:45:03 -07:00
										 |  |  |   ArgFormatter( | 
					
						
							|  |  |  |       fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt) | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |   : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 07:27:54 -07:00
										 |  |  |   template <typename T> | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |   void visit_any_int(T value) { writer_.write_int(value, spec_); } | 
					
						
							| 
									
										
										
										
											2014-07-16 07:27:54 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   template <typename T> | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |   void visit_any_double(T value) { writer_.write_double(value, spec_); } | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void visit_char(int value) { | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |     if (spec_.type_ && spec_.type_ != 'c') { | 
					
						
							| 
									
										
										
										
											2014-07-25 08:24:27 -07:00
										 |  |  |       spec_.flags_ |= CHAR_FLAG; | 
					
						
							|  |  |  |       writer_.write_int(value, spec_); | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) | 
					
						
							|  |  |  |       throw FormatError("invalid format specifier for char"); | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  |     typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr; | 
					
						
							|  |  |  |     CharPtr out = CharPtr(); | 
					
						
							|  |  |  |     if (spec_.width_ > 1) { | 
					
						
							|  |  |  |       Char fill = static_cast<Char>(spec_.fill()); | 
					
						
							|  |  |  |       out = writer_.GrowBuffer(spec_.width_); | 
					
						
							|  |  |  |       if (spec_.align_ == fmt::ALIGN_RIGHT) { | 
					
						
							|  |  |  |         std::fill_n(out, spec_.width_ - 1, fill); | 
					
						
							|  |  |  |         out += spec_.width_ - 1; | 
					
						
							|  |  |  |       } else if (spec_.align_ == fmt::ALIGN_CENTER) { | 
					
						
							|  |  |  |         out = writer_.FillPadding(out, spec_.width_, 1, fill); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         std::fill_n(out + 1, spec_.width_ - 1, fill); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       out = writer_.GrowBuffer(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     *out = static_cast<Char>(value); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void visit_string(Arg::StringValue<char> value) { | 
					
						
							|  |  |  |     writer_.write_str(value, spec_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   void visit_wstring(Arg::StringValue<wchar_t> value) { | 
					
						
							|  |  |  |     writer_.write_str(ignore_incompatible_str<Char>(value), spec_); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void visit_pointer(const void *value) { | 
					
						
							|  |  |  |     if (spec_.type_ && spec_.type_ != 'p') | 
					
						
							| 
									
										
										
										
											2014-07-26 08:42:19 -07:00
										 |  |  |       fmt::internal::report_unknown_type(spec_.type_, "pointer"); | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  |     spec_.flags_ = fmt::HASH_FLAG; | 
					
						
							|  |  |  |     spec_.type_ = 'x'; | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |     writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_); | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void visit_custom(Arg::CustomValue c) { | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |     c.format(&formatter_, c.value, format_); | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | template <typename Char> | 
					
						
							|  |  |  | void fmt::internal::FormatErrorReporter<Char>::operator()( | 
					
						
							|  |  |  |         const Char *s, fmt::StringRef message) const { | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |   if (find_closing_brace(s, num_open_braces)) | 
					
						
							|  |  |  |     throw fmt::FormatError(message); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | // Fills the padding around the content and returns the pointer to the
 | 
					
						
							|  |  |  | // content area.
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2013-09-08 13:07:04 -07:00
										 |  |  | typename fmt::BasicWriter<Char>::CharPtr | 
					
						
							|  |  |  |   fmt::BasicWriter<Char>::FillPadding(CharPtr buffer, | 
					
						
							|  |  |  |     unsigned total_size, std::size_t content_size, wchar_t fill) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   std::size_t padding = total_size - content_size; | 
					
						
							|  |  |  |   std::size_t left_padding = padding / 2; | 
					
						
							| 
									
										
										
										
											2013-09-08 13:47:06 -07:00
										 |  |  |   Char fill_char = static_cast<Char>(fill); | 
					
						
							|  |  |  |   std::fill_n(buffer, left_padding, fill_char); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   buffer += left_padding; | 
					
						
							|  |  |  |   CharPtr content = buffer; | 
					
						
							| 
									
										
										
										
											2013-09-08 13:47:06 -07:00
										 |  |  |   std::fill_n(buffer + content_size, padding - left_padding, fill_char); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   return content; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							|  |  |  | template <typename T> | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  | void fmt::BasicWriter<Char>::write_double(T value, const FormatSpec &spec) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   // Check type.
 | 
					
						
							|  |  |  |   char type = spec.type(); | 
					
						
							|  |  |  |   bool upper = false; | 
					
						
							|  |  |  |   switch (type) { | 
					
						
							|  |  |  |   case 0: | 
					
						
							|  |  |  |     type = 'g'; | 
					
						
							|  |  |  |     break; | 
					
						
							| 
									
										
										
										
											2014-06-10 07:03:49 -07:00
										 |  |  |   case 'e': case 'f': case 'g': case 'a': | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     break; | 
					
						
							|  |  |  |   case 'F': | 
					
						
							|  |  |  | #ifdef _MSC_VER
 | 
					
						
							|  |  |  |     // MSVC's printf doesn't support 'F'.
 | 
					
						
							|  |  |  |     type = 'f'; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     // Fall through.
 | 
					
						
							| 
									
										
										
										
											2014-06-10 07:03:49 -07:00
										 |  |  |   case 'E': case 'G': case 'A': | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     upper = true; | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   default: | 
					
						
							| 
									
										
										
										
											2014-07-26 08:42:19 -07:00
										 |  |  |     internal::report_unknown_type(type, "double"); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   char sign = 0; | 
					
						
							|  |  |  |   // Use SignBit instead of value < 0 because the latter is always
 | 
					
						
							|  |  |  |   // false for NaN.
 | 
					
						
							| 
									
										
										
										
											2014-03-11 18:56:24 +00:00
										 |  |  |   if (SignBit(static_cast<double>(value))) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     sign = '-'; | 
					
						
							|  |  |  |     value = -value; | 
					
						
							| 
									
										
										
										
											2014-07-25 08:29:06 -07:00
										 |  |  |   } else if (spec.flag(SIGN_FLAG)) { | 
					
						
							|  |  |  |     sign = spec.flag(PLUS_FLAG) ? '+' : ' '; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (value != value) { | 
					
						
							|  |  |  |     // Format NaN ourselves because sprintf's output is not consistent
 | 
					
						
							|  |  |  |     // across platforms.
 | 
					
						
							|  |  |  |     std::size_t size = 4; | 
					
						
							|  |  |  |     const char *nan = upper ? " NAN" : " nan"; | 
					
						
							|  |  |  |     if (!sign) { | 
					
						
							|  |  |  |       --size; | 
					
						
							|  |  |  |       ++nan; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     CharPtr out = write_str(nan, size, spec); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     if (sign) | 
					
						
							|  |  |  |       *out = sign; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-11 18:56:24 +00:00
										 |  |  |   if (IsInf(static_cast<double>(value))) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     // Format infinity ourselves because sprintf's output is not consistent
 | 
					
						
							|  |  |  |     // across platforms.
 | 
					
						
							|  |  |  |     std::size_t size = 4; | 
					
						
							|  |  |  |     const char *inf = upper ? " INF" : " inf"; | 
					
						
							|  |  |  |     if (!sign) { | 
					
						
							|  |  |  |       --size; | 
					
						
							|  |  |  |       ++inf; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |     CharPtr out = write_str(inf, size, spec); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     if (sign) | 
					
						
							|  |  |  |       *out = sign; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::size_t offset = buffer_.size(); | 
					
						
							|  |  |  |   unsigned width = spec.width(); | 
					
						
							|  |  |  |   if (sign) { | 
					
						
							|  |  |  |     buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); | 
					
						
							|  |  |  |     if (width > 0) | 
					
						
							|  |  |  |       --width; | 
					
						
							|  |  |  |     ++offset; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Build format string.
 | 
					
						
							|  |  |  |   enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
 | 
					
						
							|  |  |  |   Char format[MAX_FORMAT_SIZE]; | 
					
						
							|  |  |  |   Char *format_ptr = format; | 
					
						
							|  |  |  |   *format_ptr++ = '%'; | 
					
						
							|  |  |  |   unsigned width_for_sprintf = width; | 
					
						
							| 
									
										
										
										
											2014-07-25 08:29:06 -07:00
										 |  |  |   if (spec.flag(HASH_FLAG)) | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     *format_ptr++ = '#'; | 
					
						
							|  |  |  |   if (spec.align() == ALIGN_CENTER) { | 
					
						
							|  |  |  |     width_for_sprintf = 0; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     if (spec.align() == ALIGN_LEFT) | 
					
						
							|  |  |  |       *format_ptr++ = '-'; | 
					
						
							|  |  |  |     if (width != 0) | 
					
						
							|  |  |  |       *format_ptr++ = '*'; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-06-21 08:32:00 -07:00
										 |  |  |   if (spec.precision() >= 0) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     *format_ptr++ = '.'; | 
					
						
							|  |  |  |     *format_ptr++ = '*'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (internal::IsLongDouble<T>::VALUE) | 
					
						
							|  |  |  |     *format_ptr++ = 'L'; | 
					
						
							|  |  |  |   *format_ptr++ = type; | 
					
						
							|  |  |  |   *format_ptr = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Format using snprintf.
 | 
					
						
							| 
									
										
										
										
											2013-09-08 13:30:14 -07:00
										 |  |  |   Char fill = static_cast<Char>(spec.fill()); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   for (;;) { | 
					
						
							|  |  |  |     std::size_t size = buffer_.capacity() - offset; | 
					
						
							| 
									
										
										
										
											2014-04-23 18:37:08 -07:00
										 |  |  | #if _MSC_VER
 | 
					
						
							|  |  |  |     // MSVC's vsnprintf_s doesn't work with zero size, so reserve
 | 
					
						
							|  |  |  |     // space for at least one extra character to make the size non-zero.
 | 
					
						
							|  |  |  |     // Note that the buffer's capacity will increase by more than 1.
 | 
					
						
							|  |  |  |     if (size == 0) { | 
					
						
							|  |  |  |       buffer_.reserve(offset + 1); | 
					
						
							|  |  |  |       size = buffer_.capacity() - offset; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     Char *start = &buffer_[offset]; | 
					
						
							| 
									
										
										
										
											2014-07-26 08:03:03 -07:00
										 |  |  |     int n = internal::CharTraits<Char>::format_float( | 
					
						
							| 
									
										
										
										
											2014-06-21 08:32:00 -07:00
										 |  |  |         start, size, format, width_for_sprintf, spec.precision(), value); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     if (n >= 0 && offset + n < buffer_.capacity()) { | 
					
						
							|  |  |  |       if (sign) { | 
					
						
							|  |  |  |         if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || | 
					
						
							|  |  |  |             *start != ' ') { | 
					
						
							|  |  |  |           *(start - 1) = sign; | 
					
						
							|  |  |  |           sign = 0; | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2013-09-08 13:30:14 -07:00
										 |  |  |           *(start - 1) = fill; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |         ++n; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (spec.align() == ALIGN_CENTER && | 
					
						
							|  |  |  |           spec.width() > static_cast<unsigned>(n)) { | 
					
						
							|  |  |  |         unsigned width = spec.width(); | 
					
						
							|  |  |  |         CharPtr p = GrowBuffer(width); | 
					
						
							|  |  |  |         std::copy(p, p + n, p + (width - n) / 2); | 
					
						
							| 
									
										
										
										
											2013-09-08 13:30:14 -07:00
										 |  |  |         FillPadding(p, spec.width(), n, fill); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (spec.fill() != ' ' || sign) { | 
					
						
							|  |  |  |         while (*start == ' ') | 
					
						
							| 
									
										
										
										
											2013-09-08 13:30:14 -07:00
										 |  |  |           *start++ = fill; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |         if (sign) | 
					
						
							|  |  |  |           *(start - 1) = sign; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       GrowBuffer(n); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-04-23 18:37:49 -07:00
										 |  |  |     // If n is negative we ask to increase the capacity by at least 1,
 | 
					
						
							|  |  |  |     // but as std::vector, the buffer grows exponentially.
 | 
					
						
							|  |  |  |     buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-26 09:45:03 -07:00
										 |  |  | template <typename StrChar> | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  | void fmt::BasicWriter<Char>::write_str( | 
					
						
							| 
									
										
										
										
											2014-07-26 09:45:03 -07:00
										 |  |  |     const Arg::StringValue<StrChar> &str, const FormatSpec &spec) { | 
					
						
							|  |  |  |   // Check if StrChar is convertible to Char.
 | 
					
						
							|  |  |  |   internal::CharTraits<Char>::convert(StrChar()); | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |   if (spec.type_ && spec.type_ != 's') | 
					
						
							| 
									
										
										
										
											2014-07-26 08:42:19 -07:00
										 |  |  |     internal::report_unknown_type(spec.type_, "string"); | 
					
						
							| 
									
										
										
										
											2014-07-26 09:45:03 -07:00
										 |  |  |   const StrChar *s = str.value; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |   std::size_t size = str.size; | 
					
						
							|  |  |  |   if (size == 0) { | 
					
						
							|  |  |  |     if (!s) | 
					
						
							|  |  |  |       throw FormatError("string pointer is null"); | 
					
						
							|  |  |  |     if (*s) | 
					
						
							| 
									
										
										
										
											2014-07-26 09:45:03 -07:00
										 |  |  |       size = std::char_traits<StrChar>::length(s); | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |   write_str(s, size, spec); | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-02 06:33:25 -07:00
										 |  |  | inline const Arg | 
					
						
							| 
									
										
										
										
											2014-07-08 16:38:50 -07:00
										 |  |  |     &fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   unsigned arg_index = 0; | 
					
						
							|  |  |  |   if (*s < '0' || *s > '9') { | 
					
						
							|  |  |  |     if (*s != '}' && *s != ':') | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       report_error_(s, "invalid argument index in format string"); | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |     const Arg &arg = next_arg(); | 
					
						
							|  |  |  |     if (error_) | 
					
						
							|  |  |  |       report_error_(s, error_); | 
					
						
							|  |  |  |     return arg; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (next_arg_index_ > 0) { | 
					
						
							|  |  |  |     report_error_(s, | 
					
						
							|  |  |  |         "cannot switch from automatic to manual argument indexing"); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |   next_arg_index_ = -1; | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |   arg_index = ParseNonnegativeInt(s, error_); | 
					
						
							|  |  |  |   if (error_) | 
					
						
							|  |  |  |     report_error_(s, error_); // TODO: don't use report_error_
 | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |   if (arg_index >= args_.size()) | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     report_error_(s, "argument index is out of range in format"); | 
					
						
							| 
									
										
										
										
											2014-04-22 08:58:54 -07:00
										 |  |  |   return args_[arg_index]; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-08 16:38:50 -07:00
										 |  |  | void fmt::BasicFormatter<Char>::CheckSign( | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     const Char *&s, const Arg &arg) { | 
					
						
							| 
									
										
										
										
											2013-12-10 08:01:08 -08:00
										 |  |  |   char sign = static_cast<char>(*s); | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |   if (arg.type > Arg::LAST_NUMERIC_TYPE) { | 
					
						
							| 
									
										
										
										
											2014-07-26 09:45:03 -07:00
										 |  |  |     report_error_(s, fmt::format( | 
					
						
							|  |  |  |       "format specifier '{}' requires numeric argument", sign).c_str()); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |   if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { | 
					
						
							| 
									
										
										
										
											2014-07-26 09:45:03 -07:00
										 |  |  |     report_error_(s, fmt::format( | 
					
						
							|  |  |  |       "format specifier '{}' requires signed argument", sign).c_str()); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   ++s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  | const Arg &fmt::internal::FormatterBase::next_arg() { | 
					
						
							|  |  |  |   if (next_arg_index_ < 0) { | 
					
						
							|  |  |  |     if (!error_) | 
					
						
							|  |  |  |       error_ = "cannot switch from manual to automatic argument indexing"; | 
					
						
							|  |  |  |     return DUMMY_ARG; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   unsigned arg_index = next_arg_index_++; | 
					
						
							|  |  |  |   if (arg_index < args_.size()) | 
					
						
							|  |  |  |     return args_[arg_index]; | 
					
						
							|  |  |  |   if (!error_) | 
					
						
							|  |  |  |     error_ = "argument index is out of range in format"; | 
					
						
							|  |  |  |   return DUMMY_ARG; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  | const Arg &fmt::internal::FormatterBase::handle_arg_index(unsigned arg_index) { | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |   if (arg_index != UINT_MAX) { | 
					
						
							|  |  |  |     if (next_arg_index_ <= 0) { | 
					
						
							|  |  |  |       next_arg_index_ = -1; | 
					
						
							|  |  |  |       --arg_index; | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     } else if (!error_) { | 
					
						
							|  |  |  |       error_ = "cannot switch from automatic to manual argument indexing"; | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     if (arg_index < args_.size()) | 
					
						
							|  |  |  |       return args_[arg_index]; | 
					
						
							|  |  |  |     if (!error_) | 
					
						
							|  |  |  |       error_ = "argument index is out of range in format"; | 
					
						
							|  |  |  |     return DUMMY_ARG; | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |   return next_arg(); | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-07 07:31:25 -07:00
										 |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-16 07:59:45 -07:00
										 |  |  | void fmt::internal::PrintfFormatter<Char>::ParseFlags( | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |     FormatSpec &spec, const Char *&s) { | 
					
						
							| 
									
										
										
										
											2014-06-07 07:31:25 -07:00
										 |  |  |   for (;;) { | 
					
						
							| 
									
										
										
										
											2014-06-07 08:57:55 -07:00
										 |  |  |     switch (*s++) { | 
					
						
							| 
									
										
										
										
											2014-06-07 07:31:25 -07:00
										 |  |  |       case '-': | 
					
						
							|  |  |  |         spec.align_ = ALIGN_LEFT; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case '+': | 
					
						
							|  |  |  |         spec.flags_ |= SIGN_FLAG | PLUS_FLAG; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case '0': | 
					
						
							|  |  |  |         spec.fill_ = '0'; | 
					
						
							| 
									
										
										
										
											2014-06-07 08:57:55 -07:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-06-07 07:31:25 -07:00
										 |  |  |       case ' ': | 
					
						
							| 
									
										
										
										
											2014-06-07 08:57:55 -07:00
										 |  |  |         spec.flags_ |= SIGN_FLAG; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-06-07 07:31:25 -07:00
										 |  |  |       case '#': | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |         spec.flags_ |= HASH_FLAG; | 
					
						
							| 
									
										
										
										
											2014-06-07 07:31:25 -07:00
										 |  |  |         break; | 
					
						
							|  |  |  |       default: | 
					
						
							| 
									
										
										
										
											2014-06-07 08:57:55 -07:00
										 |  |  |         --s; | 
					
						
							| 
									
										
										
										
											2014-06-07 07:31:25 -07:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-16 07:59:45 -07:00
										 |  |  | unsigned fmt::internal::PrintfFormatter<Char>::ParseHeader( | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |   const Char *&s, FormatSpec &spec) { | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |   unsigned arg_index = UINT_MAX; | 
					
						
							|  |  |  |   Char c = *s; | 
					
						
							|  |  |  |   if (c >= '0' && c <= '9') { | 
					
						
							|  |  |  |     // Parse an argument index (if followed by '$') or a width possibly
 | 
					
						
							| 
									
										
										
										
											2014-06-20 07:34:02 -07:00
										 |  |  |     // preceded with '0' flag(s).
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     unsigned value = ParseNonnegativeInt(s, error_); | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |     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; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ParseFlags(spec, s); | 
					
						
							| 
									
										
										
										
											2014-06-23 08:10:50 -07:00
										 |  |  |   // Parse width.
 | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |   if (*s >= '0' && *s <= '9') { | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     spec.width_ = ParseNonnegativeInt(s, error_); | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |   } else if (*s == '*') { | 
					
						
							|  |  |  |     ++s; | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     spec.width_ = WidthHandler(spec).visit(handle_arg_index(UINT_MAX)); | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   return arg_index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-16 07:59:45 -07:00
										 |  |  | void fmt::internal::PrintfFormatter<Char>::Format( | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     BasicWriter<Char> &writer, BasicStringRef<Char> format, | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     const ArgList &args) { | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |   const Char *start = format.c_str(); | 
					
						
							|  |  |  |   args_ = args; | 
					
						
							|  |  |  |   next_arg_index_ = 0; | 
					
						
							|  |  |  |   const Char *s = start; | 
					
						
							|  |  |  |   while (*s) { | 
					
						
							|  |  |  |     Char c = *s++; | 
					
						
							|  |  |  |     if (c != '%') continue; | 
					
						
							|  |  |  |     if (*s == c) { | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       write(writer, start, s); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       start = ++s; | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |     write(writer, start, s - 1); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |     FormatSpec spec; | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     spec.align_ = ALIGN_RIGHT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Reporting errors is delayed till the format specification is
 | 
					
						
							|  |  |  |     // completely parsed. This is done to avoid potentially confusing
 | 
					
						
							|  |  |  |     // error messages for incomplete format strings. For example, in
 | 
					
						
							|  |  |  |     //   sprintf("%2$", 42);
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     // the format specification is incomplete. In a naive approach we
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     // would parse 2 as an argument index and report an error that the
 | 
					
						
							|  |  |  |     // index is out of range which would be rather confusing if the
 | 
					
						
							|  |  |  |     // use meant "%2d$" rather than "%2$d". If we delay an error, the
 | 
					
						
							|  |  |  |     // user will get an error that the format string is invalid which
 | 
					
						
							|  |  |  |     // is OK for both cases.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 07:16:46 -07:00
										 |  |  |     // Parse argument index, flags and width.
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     unsigned arg_index = ParseHeader(s, spec); | 
					
						
							| 
									
										
										
										
											2014-06-23 07:16:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Parse precision.
 | 
					
						
							|  |  |  |     if (*s == '.') { | 
					
						
							|  |  |  |       ++s; | 
					
						
							|  |  |  |       if ('0' <= *s && *s <= '9') { | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |         spec.precision_ = ParseNonnegativeInt(s, error_); | 
					
						
							| 
									
										
										
										
											2014-06-23 07:16:46 -07:00
										 |  |  |       } else if (*s == '*') { | 
					
						
							|  |  |  |         ++s; | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |         const Arg &arg = handle_arg_index(UINT_MAX); | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |         if (arg.type <= Arg::LAST_INTEGER_TYPE) | 
					
						
							| 
									
										
										
										
											2014-06-30 17:40:53 -07:00
										 |  |  |           spec.precision_ = static_cast<int>(GetIntValue(arg)); // TODO: check for overflow
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |         else if (!error_) | 
					
						
							|  |  |  |           error_ = "precision is not integer"; | 
					
						
							| 
									
										
										
										
											2014-06-23 07:16:46 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     const Arg &arg = handle_arg_index(arg_index); | 
					
						
							| 
									
										
										
										
											2014-07-25 08:29:06 -07:00
										 |  |  |     if (spec.flag(HASH_FLAG) && GetIntValue(arg) == 0) | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |       spec.flags_ &= ~HASH_FLAG; | 
					
						
							|  |  |  |     if (spec.fill_ == '0') { | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |       if (arg.type <= Arg::LAST_NUMERIC_TYPE) | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |         spec.align_ = ALIGN_NUMERIC; | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     // Parse length.
 | 
					
						
							|  |  |  |     switch (*s) { | 
					
						
							|  |  |  |     case 'h': | 
					
						
							|  |  |  |       // TODO: convert to short
 | 
					
						
							|  |  |  |     case 'l': | 
					
						
							|  |  |  |     case 'j': | 
					
						
							|  |  |  |     case 'z': | 
					
						
							|  |  |  |     case 't': | 
					
						
							|  |  |  |     case 'L': | 
					
						
							|  |  |  |       // TODO: handle length
 | 
					
						
							|  |  |  |       ++s; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Parse type.
 | 
					
						
							|  |  |  |     if (!*s) | 
					
						
							|  |  |  |       throw FormatError("invalid format string"); | 
					
						
							| 
									
										
										
										
											2014-07-16 08:49:23 -07:00
										 |  |  |     if (error_) | 
					
						
							|  |  |  |       throw FormatError(error_); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     spec.type_ = static_cast<char>(*s++); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     start = s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Format argument.
 | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |     switch (arg.type) { | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::INT: | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       writer.write_int(arg.int_value, spec); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::UINT: | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       writer.write_int(arg.uint_value, spec); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::LONG_LONG: | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       writer.write_int(arg.long_long_value, spec); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::ULONG_LONG: | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       writer.write_int(arg.ulong_long_value, spec); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::CHAR: { | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       if (spec.type_ && spec.type_ != 'c') | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |         writer.write_int(arg.int_value, spec); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       typedef typename BasicWriter<Char>::CharPtr CharPtr; | 
					
						
							|  |  |  |       CharPtr out = CharPtr(); | 
					
						
							|  |  |  |       if (spec.width_ > 1) { | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |         Char fill = ' '; | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |         out = writer.GrowBuffer(spec.width_); | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |         if (spec.align_ != ALIGN_LEFT) { | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |           std::fill_n(out, spec.width_ - 1, fill); | 
					
						
							|  |  |  |           out += spec.width_ - 1; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           std::fill_n(out + 1, spec.width_ - 1, fill); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         out = writer.GrowBuffer(1); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-06-19 07:40:35 -07:00
										 |  |  |       *out = static_cast<Char>(arg.int_value); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |     case Arg::DOUBLE: | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       writer.write_double(arg.double_value, spec); | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case Arg::LONG_DOUBLE: | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       writer.write_double(arg.long_double_value, spec); | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::STRING: | 
					
						
							| 
									
										
										
										
											2014-06-30 14:26:29 -07:00
										 |  |  |       writer.write_str(arg.string, spec); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::WSTRING: | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  |       writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec); | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case Arg::POINTER: | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       if (spec.type_ && spec.type_ != 'p') | 
					
						
							| 
									
										
										
										
											2014-07-26 08:42:19 -07:00
										 |  |  |         internal::report_unknown_type(spec.type_, "pointer"); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       spec.flags_= HASH_FLAG; | 
					
						
							|  |  |  |       spec.type_ = 'x'; | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer_value), spec); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     case Arg::CUSTOM: | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       if (spec.type_) | 
					
						
							| 
									
										
										
										
											2014-07-26 08:42:19 -07:00
										 |  |  |         internal::report_unknown_type(spec.type_, "object"); | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |       arg.custom.format(&writer, arg.custom.value, "s"); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |       break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       assert(false); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |   write(writer, start, s); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-08 16:38:50 -07:00
										 |  |  | const Char *fmt::BasicFormatter<Char>::format( | 
					
						
							| 
									
										
										
										
											2014-07-14 08:47:03 -07:00
										 |  |  |     const Char *format_str, const Arg &arg) { | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |   const Char *s = format_str; | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |   const char *error = 0; | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |   FormatSpec spec; | 
					
						
							|  |  |  |   if (*s == ':') { | 
					
						
							|  |  |  |     if (arg.type == Arg::CUSTOM) { | 
					
						
							|  |  |  |       arg.custom.format(this, arg.custom.value, s); | 
					
						
							|  |  |  |       return find_closing_brace(s) + 1; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     ++s; | 
					
						
							|  |  |  |     // Parse fill and alignment.
 | 
					
						
							|  |  |  |     if (Char c = *s) { | 
					
						
							|  |  |  |       const Char *p = s + 1; | 
					
						
							|  |  |  |       spec.align_ = ALIGN_DEFAULT; | 
					
						
							|  |  |  |       do { | 
					
						
							|  |  |  |         switch (*p) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |           case '<': | 
					
						
							|  |  |  |             spec.align_ = ALIGN_LEFT; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case '>': | 
					
						
							|  |  |  |             spec.align_ = ALIGN_RIGHT; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case '=': | 
					
						
							|  |  |  |             spec.align_ = ALIGN_NUMERIC; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |           case '^': | 
					
						
							|  |  |  |             spec.align_ = ALIGN_CENTER; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (spec.align_ != ALIGN_DEFAULT) { | 
					
						
							|  |  |  |           if (p != s) { | 
					
						
							|  |  |  |             if (c == '}') break; | 
					
						
							|  |  |  |             if (c == '{') | 
					
						
							|  |  |  |               report_error_(s, "invalid fill character '{'"); | 
					
						
							|  |  |  |             s += 2; | 
					
						
							|  |  |  |             spec.fill_ = c; | 
					
						
							|  |  |  |           } else ++s; | 
					
						
							|  |  |  |           if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE) | 
					
						
							|  |  |  |             report_error_(s, "format specifier '=' requires numeric argument"); | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } while (--p >= s); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     // Parse sign.
 | 
					
						
							|  |  |  |     switch (*s) { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |       case '+': | 
					
						
							|  |  |  |         CheckSign(s, arg); | 
					
						
							|  |  |  |         spec.flags_ |= SIGN_FLAG | PLUS_FLAG; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case '-': | 
					
						
							|  |  |  |         CheckSign(s, arg); | 
					
						
							| 
									
										
										
										
											2014-07-22 12:37:10 -07:00
										 |  |  |         spec.flags_ |= MINUS_FLAG; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |         break; | 
					
						
							|  |  |  |       case ' ': | 
					
						
							|  |  |  |         CheckSign(s, arg); | 
					
						
							|  |  |  |         spec.flags_ |= SIGN_FLAG; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (*s == '#') { | 
					
						
							|  |  |  |       if (arg.type > Arg::LAST_NUMERIC_TYPE) | 
					
						
							|  |  |  |         report_error_(s, "format specifier '#' requires numeric argument"); | 
					
						
							|  |  |  |       spec.flags_ |= HASH_FLAG; | 
					
						
							|  |  |  |       ++s; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     // Parse width and zero flag.
 | 
					
						
							|  |  |  |     if ('0' <= *s && *s <= '9') { | 
					
						
							|  |  |  |       if (*s == '0') { | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |         if (arg.type > Arg::LAST_NUMERIC_TYPE) | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |           report_error_(s, "format specifier '0' requires numeric argument"); | 
					
						
							|  |  |  |         spec.align_ = ALIGN_NUMERIC; | 
					
						
							|  |  |  |         spec.fill_ = '0'; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |       // Zero may be parsed again as a part of the width, but it is simpler
 | 
					
						
							|  |  |  |       // and more efficient than checking if the next char is a digit.
 | 
					
						
							|  |  |  |       spec.width_ = ParseNonnegativeInt(s, error); | 
					
						
							|  |  |  |       if (error) | 
					
						
							|  |  |  |         report_error_(s, error); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     // Parse precision.
 | 
					
						
							|  |  |  |     if (*s == '.') { | 
					
						
							|  |  |  |       ++s; | 
					
						
							|  |  |  |       spec.precision_ = 0; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |       if ('0' <= *s && *s <= '9') { | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |         spec.precision_ = ParseNonnegativeInt(s, error); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |         if (error) | 
					
						
							|  |  |  |           report_error_(s, error); | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |       } else if (*s == '{') { | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |         ++s; | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |         ++report_error_.num_open_braces; | 
					
						
							|  |  |  |         const Arg &precision_arg = ParseArgIndex(s); | 
					
						
							|  |  |  |         ULongLong value = 0; | 
					
						
							|  |  |  |         switch (precision_arg.type) { | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |           case Arg::INT: | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |             if (precision_arg.int_value < 0) | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |               report_error_(s, "negative precision in format"); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |             value = precision_arg.int_value; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |           case Arg::UINT: | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |             value = precision_arg.uint_value; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |           case Arg::LONG_LONG: | 
					
						
							| 
									
										
										
										
											2013-11-22 07:45:43 -08:00
										 |  |  |             if (precision_arg.long_long_value < 0) | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |               report_error_(s, "negative precision in format"); | 
					
						
							| 
									
										
										
										
											2013-11-22 07:45:43 -08:00
										 |  |  |             value = precision_arg.long_long_value; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |           case Arg::ULONG_LONG: | 
					
						
							| 
									
										
										
										
											2013-11-18 22:58:39 -08:00
										 |  |  |             value = precision_arg.ulong_long_value; | 
					
						
							| 
									
										
										
										
											2013-11-21 09:11:58 -08:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |           default: | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |             report_error_(s, "precision is not integer"); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |         if (value > INT_MAX) | 
					
						
							|  |  |  |           report_error_(s, "number is too big in format"); | 
					
						
							|  |  |  |         spec.precision_ = static_cast<int>(value); | 
					
						
							|  |  |  |         if (*s++ != '}') | 
					
						
							|  |  |  |           throw FormatError("unmatched '{' in format"); | 
					
						
							|  |  |  |         --report_error_.num_open_braces; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         report_error_(s, "missing precision in format"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) { | 
					
						
							|  |  |  |         report_error_(s, | 
					
						
							|  |  |  |             "precision specifier requires floating-point argument"); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     // Parse type.
 | 
					
						
							|  |  |  |     if (*s != '}' && *s) | 
					
						
							|  |  |  |       spec.type_ = static_cast<char>(*s++); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |   if (*s++ != '}') | 
					
						
							|  |  |  |     throw FormatError("unmatched '{' in format"); | 
					
						
							|  |  |  |   start_ = s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Format argument.
 | 
					
						
							| 
									
										
										
										
											2014-07-16 08:38:15 -07:00
										 |  |  |   internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg); | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |   return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename Char> | 
					
						
							| 
									
										
										
										
											2014-07-08 16:38:50 -07:00
										 |  |  | void fmt::BasicFormatter<Char>::Format( | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     BasicStringRef<Char> format_str, const ArgList &args) { | 
					
						
							|  |  |  |   const Char *s = start_ = format_str.c_str(); | 
					
						
							|  |  |  |   args_ = args; | 
					
						
							|  |  |  |   next_arg_index_ = 0; | 
					
						
							|  |  |  |   while (*s) { | 
					
						
							|  |  |  |     Char c = *s++; | 
					
						
							|  |  |  |     if (c != '{' && c != '}') continue; | 
					
						
							|  |  |  |     if (*s == c) { | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |       write(writer_, start_, s); | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |       start_ = ++s; | 
					
						
							|  |  |  |       continue; | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     if (c == '}') | 
					
						
							|  |  |  |       throw FormatError("unmatched '}' in format"); | 
					
						
							|  |  |  |     report_error_.num_open_braces = 1; | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |     write(writer_, start_, s - 1); | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     Arg arg = ParseArgIndex(s); | 
					
						
							|  |  |  |     s = format(s, arg); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-07-24 08:53:27 -07:00
										 |  |  |   write(writer_, start_, s); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-03 09:48:54 -07:00
										 |  |  | void fmt::ReportSystemError( | 
					
						
							|  |  |  |     int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { | 
					
						
							|  |  |  |   // FIXME: FormatSystemErrorMessage may throw
 | 
					
						
							|  |  |  |   ReportError(internal::FormatSystemErrorMessage, error_code, message); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-30 12:38:17 -07:00
										 |  |  | #ifdef _WIN32
 | 
					
						
							| 
									
										
										
										
											2014-05-03 09:48:54 -07:00
										 |  |  | void fmt::ReportWinError( | 
					
						
							|  |  |  |     int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { | 
					
						
							|  |  |  |   // FIXME: FormatWinErrorMessage may throw
 | 
					
						
							|  |  |  |   ReportError(internal::FormatWinErrorMessage, error_code, message); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-04-30 12:38:17 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-04-30 10:18:11 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-28 19:44:39 -07:00
										 |  |  | void fmt::print(StringRef format, const ArgList &args) { | 
					
						
							|  |  |  |   Writer w; | 
					
						
							| 
									
										
										
										
											2014-06-29 11:51:10 -07:00
										 |  |  |   w.write(format, args); | 
					
						
							| 
									
										
										
										
											2014-06-28 19:44:39 -07:00
										 |  |  |   std::fwrite(w.data(), 1, w.size(), stdout); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-28 21:56:40 -07:00
										 |  |  | void fmt::print(std::FILE *f, StringRef format, const ArgList &args) { | 
					
						
							|  |  |  |   Writer w; | 
					
						
							| 
									
										
										
										
											2014-06-29 11:51:10 -07:00
										 |  |  |   w.write(format, args); | 
					
						
							| 
									
										
										
										
											2014-06-28 21:56:40 -07:00
										 |  |  |   std::fwrite(w.data(), 1, w.size(), f); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-09 06:56:36 -07:00
										 |  |  | void fmt::print(std::ostream &os, StringRef format, const ArgList &args) { | 
					
						
							|  |  |  |   Writer w; | 
					
						
							|  |  |  |   w.write(format, args); | 
					
						
							|  |  |  |   os.write(w.data(), w.size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-01 09:10:43 -07:00
										 |  |  | void fmt::print_colored(Color c, StringRef format, const ArgList &args) { | 
					
						
							|  |  |  |   char escape[] = "\x1b[30m"; | 
					
						
							|  |  |  |   escape[3] = '0' + static_cast<char>(c); | 
					
						
							|  |  |  |   std::fputs(escape, stdout); | 
					
						
							|  |  |  |   print(format, args); | 
					
						
							|  |  |  |   std::fputs(RESET_COLOR, stdout); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-28 21:56:40 -07:00
										 |  |  | void fmt::printf(StringRef format, const ArgList &args) { | 
					
						
							|  |  |  |   Writer w; | 
					
						
							| 
									
										
										
										
											2014-06-29 19:52:26 -07:00
										 |  |  |   printf(w, format, args); | 
					
						
							| 
									
										
										
										
											2014-06-28 21:56:40 -07:00
										 |  |  |   std::fwrite(w.data(), 1, w.size(), stdout); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | // Explicit instantiations for char.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-08 13:07:04 -07:00
										 |  |  | template fmt::BasicWriter<char>::CharPtr | 
					
						
							|  |  |  |   fmt::BasicWriter<char>::FillPadding(CharPtr buffer, | 
					
						
							|  |  |  |     unsigned total_size, std::size_t content_size, wchar_t fill); | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:38:50 -07:00
										 |  |  | template void fmt::BasicFormatter<char>::Format( | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |   BasicStringRef<char> format, const ArgList &args); | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 07:59:45 -07:00
										 |  |  | template void fmt::internal::PrintfFormatter<char>::Format( | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |   BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args); | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | // Explicit instantiations for wchar_t.
 | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-06 20:23:42 -07:00
										 |  |  | template fmt::BasicWriter<wchar_t>::CharPtr | 
					
						
							| 
									
										
										
										
											2013-09-08 13:07:04 -07:00
										 |  |  |   fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer, | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     unsigned total_size, std::size_t content_size, wchar_t fill); | 
					
						
							| 
									
										
										
										
											2013-09-07 10:15:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 16:38:50 -07:00
										 |  |  | template void fmt::BasicFormatter<wchar_t>::Format( | 
					
						
							| 
									
										
										
										
											2014-07-08 16:20:33 -07:00
										 |  |  |     BasicStringRef<wchar_t> format, const ArgList &args); | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 07:59:45 -07:00
										 |  |  | template void fmt::internal::PrintfFormatter<wchar_t>::Format( | 
					
						
							| 
									
										
										
										
											2014-06-06 06:38:37 -07:00
										 |  |  |     BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format, | 
					
						
							| 
									
										
										
										
											2014-06-24 07:54:26 -07:00
										 |  |  |     const ArgList &args); | 
					
						
							| 
									
										
										
										
											2014-03-11 18:56:24 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if _MSC_VER
 | 
					
						
							|  |  |  | # pragma warning(pop)
 | 
					
						
							|  |  |  | #endif
 |