1 /*
2  Formatting library for C++
3 
4  Copyright (c) 2012 - 2014, Victor Zverovich
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions are met:
9 
10  1. Redistributions of source code must retain the above copyright notice, this
11     list of conditions and the following disclaimer.
12  2. Redistributions in binary form must reproduce the above copyright notice,
13     this list of conditions and the following disclaimer in the documentation
14     and/or other materials provided with the distribution.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 // Disable useless MSVC warnings.
29 #undef _CRT_SECURE_NO_WARNINGS
30 #define _CRT_SECURE_NO_WARNINGS
31 #undef _SCL_SECURE_NO_WARNINGS
32 #define _SCL_SECURE_NO_WARNINGS
33 
34 #include "format.hpp"
35 
36 #include <string.h>
37 
38 #include <cctype>
39 #include <cerrno>
40 #include <climits>
41 #include <cmath>
42 #include <cstdarg>
43 
44 
45 namespace A_LIB_NAMESPACE {
46 
47 #ifdef _WIN32
48 # define WIN32_LEAN_AND_MEAN
49 # ifdef __MINGW32__
50 #  include <cstring>
51 # endif
52 # include <windows.h>
53 # undef ERROR
54 #endif
55 
56 using fmt::LongLong;
57 using fmt::ULongLong;
58 using fmt::internal::Arg;
59 
60 // Check if exceptions are disabled.
61 #if __GNUC__ && !__EXCEPTIONS
62 # define FMT_EXCEPTIONS 0
63 #endif
64 #if _MSC_VER && !_HAS_EXCEPTIONS
65 # define FMT_EXCEPTIONS 0
66 #endif
67 #ifndef FMT_EXCEPTIONS
68 # define FMT_EXCEPTIONS 1
69 #endif
70 
71 #if FMT_EXCEPTIONS
72 # define FMT_TRY try
73 # define FMT_CATCH(x) catch (x)
74 #else
75 # define FMT_TRY if (true)
76 # define FMT_CATCH(x) if (false)
77 #endif
78 
79 #ifndef FMT_THROW
80 # if FMT_EXCEPTIONS
81 #  define FMT_THROW(x) throw x
82 # else
83 #  define FMT_THROW(x) assert(false)
84 # endif
85 #endif
86 
87 #if _MSC_VER
88 # pragma warning(push)
89 # pragma warning(disable: 4127)  // conditional expression is constant
90 #endif
91 
92 namespace {
93 
94 #ifndef _MSC_VER
95 # define FMT_SNPRINTF snprintf
96 #else  // _MSC_VER
97 inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
98   va_list args;
99   va_start(args, format);
100   int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
101   va_end(args);
102   return result;
103 }
104 # define FMT_SNPRINTF fmt_snprintf
105 #endif  // _MSC_VER
106 
107 // Checks if a value fits in int - used to avoid warnings about comparing
108 // signed and unsigned integers.
109 template <bool IsSigned>
110 struct IntChecker {
111   template <typename T>
fits_in_intA_LIB_NAMESPACE::__anon870aaaa30111::IntChecker112   static bool fits_in_int(T value) {
113     unsigned max = INT_MAX;
114     return value <= max;
115   }
116 };
117 
118 template <>
119 struct IntChecker<true> {
120   template <typename T>
fits_in_intA_LIB_NAMESPACE::__anon870aaaa30111::IntChecker121   static bool fits_in_int(T value) {
122     return value >= INT_MIN && value <= INT_MAX;
123   }
124 };
125 
126 const char RESET_COLOR[] = "\x1b[0m";
127 
128 typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
129 
130 // Portable thread-safe version of strerror.
131 // Sets buffer to point to a string describing the error code.
132 // This can be either a pointer to a string stored in buffer,
133 // or a pointer to some static immutable string.
134 // Returns one of the following values:
135 //   0      - success
136 //   ERANGE - buffer is not large enough to store the error message
137 //   other  - failure
138 // Buffer should be at least of size 1.
safe_strerror(int error_code,char * & buffer,std::size_t buffer_size)139 int safe_strerror(
140     int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
141   assert(buffer != 0 && buffer_size != 0);
142   int result = 0;
143 #if  (defined _GNU_SOURCE) && (defined __USE_GNU)
144   char *message = strerror_r(error_code, buffer, buffer_size);
145   // If the buffer is full then the message is probably truncated.
146   if (message == buffer && strlen(buffer) == buffer_size - 1)
147     result = ERANGE;
148   buffer = message;
149 #elif (defined __MINGW32__)
150   errno = 0;
151   (void)buffer_size;
152   buffer = strerror(error_code);
153   result = errno;
154 #elif (defined _WIN32)
155   result = strerror_s(buffer, buffer_size, error_code);
156   // If the buffer is full then the message is probably truncated.
157   if (result == 0 && std::strlen(buffer) == buffer_size - 1)
158     result = ERANGE;
159 #else
160   result = strerror_r(error_code, buffer, buffer_size);
161   if (result == -1)
162     result = errno;  // glibc versions before 2.13 return result in errno.
163 #endif
164   return result;
165 }
166 
format_error_code(fmt::Writer & out,int error_code,fmt::StringRef message)167 void format_error_code(fmt::Writer &out, int error_code,
168                        fmt::StringRef message) FMT_NOEXCEPT(true) {
169   // Report error code making sure that the output fits into
170   // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
171   // bad_alloc.
172   out.clear();
173   static const char SEP[] = ": ";
174   static const char ERROR[] = "error ";
175   fmt::internal::IntTraits<int>::MainType ec_value = error_code;
176   // Subtract 2 to account for terminating null characters in SEP and ERROR.
177   std::size_t error_code_size =
178       sizeof(SEP) + sizeof(ERROR) + fmt::internal::count_digits(ec_value) - 2;
179   if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
180     out << message << SEP;
181   out << ERROR << error_code;
182   assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
183 }
184 
report_error(FormatFunc func,int error_code,fmt::StringRef message)185 void report_error(FormatFunc func,
186     int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
187   fmt::MemoryWriter full_message;
188   func(full_message, error_code, message);
189   // Use Writer::data instead of Writer::c_str to avoid potential memory
190   // allocation.
191   std::fwrite(full_message.data(), full_message.size(), 1, stderr);
192   std::fputc('\n', stderr);
193 }
194 
195 // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
196 class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
197  public:
198   template <typename T>
visit_any_int(T value)199   bool visit_any_int(T value) { return value == 0; }
200 };
201 
202 // Parses an unsigned integer advancing s to the end of the parsed input.
203 // This function assumes that the first character of s is a digit.
204 template <typename Char>
parse_nonnegative_int(const Char * & s)205 int parse_nonnegative_int(const Char *&s) {
206   assert('0' <= *s && *s <= '9');
207   unsigned value = 0;
208   do {
209     unsigned new_value = value * 10 + (*s++ - '0');
210     // Check if value wrapped around.
211     if (new_value < value) {
212       value = UINT_MAX;
213       break;
214     }
215     value = new_value;
216   } while ('0' <= *s && *s <= '9');
217   if (value > INT_MAX)
218     FMT_THROW(fmt::FormatError("number is too big"));
219   return value;
220 }
221 
require_numeric_argument(const Arg & arg,char spec)222 inline void require_numeric_argument(const Arg &arg, char spec) {
223   if (arg.type > Arg::LAST_NUMERIC_TYPE) {
224     std::string message =
225         fmt::format("format specifier '{}' requires numeric argument", spec);
226     FMT_THROW(fmt::FormatError(message));
227   }
228 }
229 
230 template <typename Char>
check_sign(const Char * & s,const Arg & arg)231 void check_sign(const Char *&s, const Arg &arg) {
232   char sign = static_cast<char>(*s);
233   require_numeric_argument(arg, sign);
234   if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
235     FMT_THROW(fmt::FormatError(fmt::format(
236       "format specifier '{}' requires signed argument", sign)));
237   }
238   ++s;
239 }
240 
241 // Checks if an argument is a valid printf width specifier and sets
242 // left alignment if it is negative.
243 class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
244  private:
245   fmt::FormatSpec &spec_;
246 
247  public:
WidthHandler(fmt::FormatSpec & spec)248   explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
249 
visit_unhandled_arg()250   unsigned visit_unhandled_arg() {
251     FMT_THROW(fmt::FormatError("width is not integer"));
252     return 0;
253   }
254 
255   template <typename T>
visit_any_int(T value)256   unsigned visit_any_int(T value) {
257     typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
258     UnsignedType width = value;
259     if (fmt::internal::is_negative(value)) {
260       spec_.align_ = fmt::ALIGN_LEFT;
261       width = 0 - width;
262     }
263     if (width > INT_MAX)
264       FMT_THROW(fmt::FormatError("number is too big"));
265     return static_cast<unsigned>(width);
266   }
267 };
268 
269 class PrecisionHandler :
270     public fmt::internal::ArgVisitor<PrecisionHandler, int> {
271  public:
visit_unhandled_arg()272   unsigned visit_unhandled_arg() {
273     FMT_THROW(fmt::FormatError("precision is not integer"));
274     return 0;
275   }
276 
277   template <typename T>
visit_any_int(T value)278   int visit_any_int(T value) {
279     if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
280       FMT_THROW(fmt::FormatError("number is too big"));
281     return static_cast<int>(value);
282   }
283 };
284 
285 // Converts an integer argument to an integral type T for printf.
286 template <typename T>
287 class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
288  private:
289   fmt::internal::Arg &arg_;
290   wchar_t type_;
291 
292  public:
ArgConverter(fmt::internal::Arg & arg,wchar_t type)293   ArgConverter(fmt::internal::Arg &arg, wchar_t type)
294     : arg_(arg), type_(type) {}
295 
296   template <typename U>
visit_any_int(U value)297   void visit_any_int(U value) {
298     bool is_signed = type_ == 'd' || type_ == 'i';
299     using fmt::internal::Arg;
300     if (sizeof(T) <= sizeof(int)) {
301       // Extra casts are used to silence warnings.
302       if (is_signed) {
303         arg_.type = Arg::INT;
304         arg_.int_value = static_cast<int>(static_cast<T>(value));
305       } else {
306         arg_.type = Arg::UINT;
307         arg_.uint_value = static_cast<unsigned>(
308             static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
309       }
310     } else {
311       if (is_signed) {
312         arg_.type = Arg::LONG_LONG;
313         arg_.long_long_value =
314             static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
315       } else {
316         arg_.type = Arg::ULONG_LONG;
317         arg_.ulong_long_value =
318             static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
319       }
320     }
321   }
322 };
323 
324 // Converts an integer argument to char for printf.
325 class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
326  private:
327   fmt::internal::Arg &arg_;
328 
329  public:
CharConverter(fmt::internal::Arg & arg)330   explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
331 
332   template <typename T>
visit_any_int(T value)333   void visit_any_int(T value) {
334     arg_.type = Arg::CHAR;
335     arg_.int_value = static_cast<char>(value);
336   }
337 };
338 
339 // This function template is used to prevent compile errors when handling
340 // incompatible string arguments, e.g. handling a wide string in a narrow
341 // string formatter.
342 template <typename Char>
343 Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
344 
345 template <>
ignore_incompatible_str(Arg::StringValue<wchar_t>)346 inline Arg::StringValue<char> ignore_incompatible_str(
347     Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
348 
349 template <>
ignore_incompatible_str(Arg::StringValue<wchar_t> s)350 inline Arg::StringValue<wchar_t> ignore_incompatible_str(
351     Arg::StringValue<wchar_t> s) { return s; }
352 }  // namespace
353 
init(int error_code,StringRef format_str,ArgList args)354 void fmt::SystemError::init(
355     int error_code, StringRef format_str, ArgList args) {
356   error_code_ = error_code;
357   MemoryWriter w;
358   internal::format_system_error(w, error_code, format(format_str, args));
359   std::runtime_error &base = *this;
360   base = std::runtime_error(w.str());
361 }
362 
363 template <typename T>
format_float(char * buffer,std::size_t size,const char * format,unsigned width,int precision,T value)364 int fmt::internal::CharTraits<char>::format_float(
365     char *buffer, std::size_t size, const char *format,
366     unsigned width, int precision, T value) {
367   if (width == 0) {
368     return precision < 0 ?
369         FMT_SNPRINTF(buffer, size, format, value) :
370         FMT_SNPRINTF(buffer, size, format, precision, value);
371   }
372   return precision < 0 ?
373       FMT_SNPRINTF(buffer, size, format, width, value) :
374       FMT_SNPRINTF(buffer, size, format, width, precision, value);
375 }
376 
377 template <typename T>
format_float(wchar_t * buffer,std::size_t size,const wchar_t * format,unsigned width,int precision,T value)378 int fmt::internal::CharTraits<wchar_t>::format_float(
379     wchar_t *buffer, std::size_t size, const wchar_t *format,
380     unsigned width, int precision, T value) {
381   if (width == 0) {
382     return precision < 0 ?
383         swprintf(buffer, size, format, value) :
384         swprintf(buffer, size, format, precision, value);
385   }
386   return precision < 0 ?
387       swprintf(buffer, size, format, width, value) :
388       swprintf(buffer, size, format, width, precision, value);
389 }
390 
391 const char fmt::internal::DIGITS[] =
392     "0001020304050607080910111213141516171819"
393     "2021222324252627282930313233343536373839"
394     "4041424344454647484950515253545556575859"
395     "6061626364656667686970717273747576777879"
396     "8081828384858687888990919293949596979899";
397 
398 #define FMT_POWERS_OF_10(factor) \
399   factor * 10, \
400   factor * 100, \
401   factor * 1000, \
402   factor * 10000, \
403   factor * 100000, \
404   factor * 1000000, \
405   factor * 10000000, \
406   factor * 100000000, \
407   factor * 1000000000
408 
409 const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
410 const uint64_t fmt::internal::POWERS_OF_10_64[] = {
411   0,
412   FMT_POWERS_OF_10(1),
413   FMT_POWERS_OF_10(ULongLong(1000000000)),
414   // Multiply several constants instead of using a single long long constant
415   // to avoid warnings about C++98 not supporting long long.
416   ULongLong(1000000000) * ULongLong(1000000000) * 10
417 };
418 
report_unknown_type(char code,const char * type)419 void fmt::internal::report_unknown_type(char code, const char *type) {
420   if (std::isprint(static_cast<unsigned char>(code))) {
421     FMT_THROW(fmt::FormatError(
422         fmt::format("unknown format code '{}' for {}", code, type)));
423   }
424   FMT_THROW(fmt::FormatError(
425       fmt::format("unknown format code '\\x{:02x}' for {}",
426         static_cast<unsigned>(code), type)));
427 }
428 
429 #ifdef _WIN32
430 
UTF8ToUTF16(fmt::StringRef s)431 fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
432   int length = MultiByteToWideChar(
433       CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
434   static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
435   if (length == 0)
436     FMT_THROW(WindowsError(GetLastError(), ERROR));
437   buffer_.resize(length);
438   length = MultiByteToWideChar(
439     CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
440   if (length == 0)
441     FMT_THROW(WindowsError(GetLastError(), ERROR));
442 }
443 
UTF16ToUTF8(fmt::WStringRef s)444 fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
445   if (int error_code = convert(s)) {
446     FMT_THROW(WindowsError(error_code,
447         "cannot convert string from UTF-16 to UTF-8"));
448   }
449 }
450 
convert(fmt::WStringRef s)451 int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
452   int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
453   if (length == 0)
454     return GetLastError();
455   buffer_.resize(length);
456   length = WideCharToMultiByte(
457     CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
458   if (length == 0)
459     return GetLastError();
460   return 0;
461 }
462 
init(int error_code,StringRef format_str,ArgList args)463 void fmt::WindowsError::init(
464     int error_code, StringRef format_str, ArgList args) {
465   error_code_ = error_code;
466   MemoryWriter w;
467   internal::format_windows_error(w, error_code, format(format_str, args));
468   std::runtime_error &base = *this;
469   base = std::runtime_error(w.str());
470 }
471 
472 #endif
473 
format_system_error(fmt::Writer & out,int error_code,fmt::StringRef message)474 void fmt::internal::format_system_error(
475     fmt::Writer &out, int error_code,
476     fmt::StringRef message) FMT_NOEXCEPT(true) {
477   FMT_TRY {
478     MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
479     buffer.resize(INLINE_BUFFER_SIZE);
480     for (;;) {
481       char *system_message = &buffer[0];
482       int result = safe_strerror(error_code, system_message, buffer.size());
483       if (result == 0) {
484         out << message << ": " << system_message;
485         return;
486       }
487       if (result != ERANGE)
488         break;  // Can't get error message, report error code instead.
489       buffer.resize(buffer.size() * 2);
490     }
491   } FMT_CATCH(...) {}
492   format_error_code(out, error_code, message);
493 }
494 
495 #ifdef _WIN32
format_windows_error(fmt::Writer & out,int error_code,fmt::StringRef message)496 void fmt::internal::format_windows_error(
497     fmt::Writer &out, int error_code,
498     fmt::StringRef message) FMT_NOEXCEPT(true) {
499   class String {
500    private:
501     LPWSTR str_;
502 
503    public:
504     String() : str_() {}
505     ~String() { LocalFree(str_); }
506     LPWSTR *ptr() { return &str_; }
507     LPCWSTR c_str() const { return str_; }
508   };
509   FMT_TRY {
510     String system_message;
511     if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
512         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
513         error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
514         reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
515       UTF16ToUTF8 utf8_message;
516       if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
517         out << message << ": " << utf8_message;
518         return;
519       }
520     }
521   } FMT_CATCH(...) {}
522   format_error_code(out, error_code, message);
523 }
524 #endif
525 
526 // An argument formatter.
527 template <typename Char>
528 class fmt::internal::ArgFormatter :
529     public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
530  private:
531   fmt::BasicFormatter<Char> &formatter_;
532   fmt::BasicWriter<Char> &writer_;
533   fmt::FormatSpec &spec_;
534   const Char *format_;
535 
536  public:
ArgFormatter(fmt::BasicFormatter<Char> & f,fmt::FormatSpec & s,const Char * fmt)537   ArgFormatter(
538       fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
539   : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
540 
541   template <typename T>
visit_any_int(T value)542   void visit_any_int(T value) { writer_.write_int(value, spec_); }
543 
544   template <typename T>
visit_any_double(T value)545   void visit_any_double(T value) { writer_.write_double(value, spec_); }
546 
visit_char(int value)547   void visit_char(int value) {
548     if (spec_.type_ && spec_.type_ != 'c') {
549       spec_.flags_ |= CHAR_FLAG;
550       writer_.write_int(value, spec_);
551       return;
552     }
553     if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
554       FMT_THROW(FormatError("invalid format specifier for char"));
555     typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
556     CharPtr out = CharPtr();
557     if (spec_.width_ > 1) {
558       Char fill = static_cast<Char>(spec_.fill());
559       out = writer_.grow_buffer(spec_.width_);
560       if (spec_.align_ == fmt::ALIGN_RIGHT) {
561         std::fill_n(out, spec_.width_ - 1, fill);
562         out += spec_.width_ - 1;
563       } else if (spec_.align_ == fmt::ALIGN_CENTER) {
564         out = writer_.fill_padding(out, spec_.width_, 1, fill);
565       } else {
566         std::fill_n(out + 1, spec_.width_ - 1, fill);
567       }
568     } else {
569       out = writer_.grow_buffer(1);
570     }
571     *out = static_cast<Char>(value);
572   }
573 
visit_string(Arg::StringValue<char> value)574   void visit_string(Arg::StringValue<char> value) {
575     writer_.write_str(value, spec_);
576   }
visit_wstring(Arg::StringValue<wchar_t> value)577   void visit_wstring(Arg::StringValue<wchar_t> value) {
578     writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
579   }
580 
visit_pointer(const void * value)581   void visit_pointer(const void *value) {
582     if (spec_.type_ && spec_.type_ != 'p')
583       fmt::internal::report_unknown_type(spec_.type_, "pointer");
584     spec_.flags_ = fmt::HASH_FLAG;
585     spec_.type_ = 'x';
586     writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
587   }
588 
visit_custom(Arg::CustomValue c)589   void visit_custom(Arg::CustomValue c) {
590     c.format(&formatter_, c.value, &format_);
591   }
592 };
593 
594 template <typename Char>
595 template <typename StrChar>
write_str(const Arg::StringValue<StrChar> & str,const FormatSpec & spec)596 void fmt::BasicWriter<Char>::write_str(
597     const Arg::StringValue<StrChar> &str, const FormatSpec &spec) {
598   // Check if StrChar is convertible to Char.
599   internal::CharTraits<Char>::convert(StrChar());
600   if (spec.type_ && spec.type_ != 's')
601     internal::report_unknown_type(spec.type_, "string");
602   const StrChar *s = str.value;
603   std::size_t size = str.size;
604   if (size == 0) {
605     if (!s)
606       FMT_THROW(FormatError("string pointer is null"));
607     if (*s)
608       size = std::char_traits<StrChar>::length(s);
609   }
610   write_str(s, size, spec);
611 }
612 
613 template <typename Char>
parse_arg_index(const Char * & s)614 inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
615   const char *error = 0;
616   Arg arg = *s < '0' || *s > '9' ?
617         next_arg(error) : get_arg(parse_nonnegative_int(s), error);
618   if (error) {
619     FMT_THROW(FormatError(
620                 *s != '}' && *s != ':' ? "invalid format string" : error));
621   }
622   return arg;
623 }
624 
do_get_arg(unsigned arg_index,const char * & error)625 Arg fmt::internal::FormatterBase::do_get_arg(
626     unsigned arg_index, const char *&error) {
627   Arg arg = args_[arg_index];
628   if (arg.type == Arg::NONE)
629     error = "argument index out of range";
630   return arg;
631 }
632 
next_arg(const char * & error)633 inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
634   if (next_arg_index_ >= 0)
635     return do_get_arg(next_arg_index_++, error);
636   error = "cannot switch from manual to automatic argument indexing";
637   return Arg();
638 }
639 
get_arg(unsigned arg_index,const char * & error)640 inline Arg fmt::internal::FormatterBase::get_arg(
641     unsigned arg_index, const char *&error) {
642   if (next_arg_index_ <= 0) {
643     next_arg_index_ = -1;
644     return do_get_arg(arg_index, error);
645   }
646   error = "cannot switch from automatic to manual argument indexing";
647   return Arg();
648 }
649 
650 template <typename Char>
parse_flags(FormatSpec & spec,const Char * & s)651 void fmt::internal::PrintfFormatter<Char>::parse_flags(
652     FormatSpec &spec, const Char *&s) {
653   for (;;) {
654     switch (*s++) {
655       case '-':
656         spec.align_ = ALIGN_LEFT;
657         break;
658       case '+':
659         spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
660         break;
661       case '0':
662         spec.fill_ = '0';
663         break;
664       case ' ':
665         spec.flags_ |= SIGN_FLAG;
666         break;
667       case '#':
668         spec.flags_ |= HASH_FLAG;
669         break;
670       default:
671         --s;
672         return;
673     }
674   }
675 }
676 
677 template <typename Char>
get_arg(const Char * s,unsigned arg_index)678 Arg fmt::internal::PrintfFormatter<Char>::get_arg(
679     const Char *s, unsigned arg_index) {
680   const char *error = 0;
681   Arg arg = arg_index == UINT_MAX ?
682     next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
683   if (error)
684     FMT_THROW(FormatError(!*s ? "invalid format string" : error));
685   return arg;
686 }
687 
688 template <typename Char>
parse_header(const Char * & s,FormatSpec & spec)689 unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
690   const Char *&s, FormatSpec &spec) {
691   unsigned arg_index = UINT_MAX;
692   Char c = *s;
693   if (c >= '0' && c <= '9') {
694     // Parse an argument index (if followed by '$') or a width possibly
695     // preceded with '0' flag(s).
696     unsigned value = parse_nonnegative_int(s);
697     if (*s == '$') {  // value is an argument index
698       ++s;
699       arg_index = value;
700     } else {
701       if (c == '0')
702         spec.fill_ = '0';
703       if (value != 0) {
704         // Nonzero value means that we parsed width and don't need to
705         // parse it or flags again, so return now.
706         spec.width_ = value;
707         return arg_index;
708       }
709     }
710   }
711   parse_flags(spec, s);
712   // Parse width.
713   if (*s >= '0' && *s <= '9') {
714     spec.width_ = parse_nonnegative_int(s);
715   } else if (*s == '*') {
716     ++s;
717     spec.width_ = WidthHandler(spec).visit(get_arg(s));
718   }
719   return arg_index;
720 }
721 
722 template <typename Char>
format(BasicWriter<Char> & writer,BasicStringRef<Char> format,const ArgList & args)723 void fmt::internal::PrintfFormatter<Char>::format(
724     BasicWriter<Char> &writer, BasicStringRef<Char> format,
725     const ArgList &args) {
726   const Char *start = format.c_str();
727   set_args(args);
728   const Char *s = start;
729   while (*s) {
730     Char c = *s++;
731     if (c != '%') continue;
732     if (*s == c) {
733       write(writer, start, s);
734       start = ++s;
735       continue;
736     }
737     write(writer, start, s - 1);
738 
739     FormatSpec spec;
740     spec.align_ = ALIGN_RIGHT;
741 
742     // Parse argument index, flags and width.
743     unsigned arg_index = parse_header(s, spec);
744 
745     // Parse precision.
746     if (*s == '.') {
747       ++s;
748       if ('0' <= *s && *s <= '9') {
749         spec.precision_ = parse_nonnegative_int(s);
750       } else if (*s == '*') {
751         ++s;
752         spec.precision_ = PrecisionHandler().visit(get_arg(s));
753       }
754     }
755 
756     Arg arg = get_arg(s, arg_index);
757     if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
758       spec.flags_ &= ~HASH_FLAG;
759     if (spec.fill_ == '0') {
760       if (arg.type <= Arg::LAST_NUMERIC_TYPE)
761         spec.align_ = ALIGN_NUMERIC;
762       else
763         spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.
764     }
765 
766     // Parse length and convert the argument to the required type.
767     switch (*s++) {
768     case 'h':
769       if (*s == 'h')
770         ArgConverter<signed char>(arg, *++s).visit(arg);
771       else
772         ArgConverter<short>(arg, *s).visit(arg);
773       break;
774     case 'l':
775       if (*s == 'l')
776         ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
777       else
778         ArgConverter<long>(arg, *s).visit(arg);
779       break;
780     case 'j':
781       ArgConverter<intmax_t>(arg, *s).visit(arg);
782       break;
783     case 'z':
784       ArgConverter<size_t>(arg, *s).visit(arg);
785       break;
786     case 't':
787       ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
788       break;
789     case 'L':
790       // printf produces garbage when 'L' is omitted for long double, no
791       // need to do the same.
792       break;
793     default:
794       --s;
795       ArgConverter<int>(arg, *s).visit(arg);
796     }
797 
798     // Parse type.
799     if (!*s)
800       FMT_THROW(FormatError("invalid format string"));
801     spec.type_ = static_cast<char>(*s++);
802     if (arg.type <= Arg::LAST_INTEGER_TYPE) {
803       // Normalize type.
804       switch (spec.type_) {
805       case 'i': case 'u':
806         spec.type_ = 'd';
807         break;
808       case 'c':
809         // TODO: handle wchar_t
810         CharConverter(arg).visit(arg);
811         break;
812       }
813     }
814 
815     start = s;
816 
817     // Format argument.
818     switch (arg.type) {
819     case Arg::INT:
820       writer.write_int(arg.int_value, spec);
821       break;
822     case Arg::UINT:
823       writer.write_int(arg.uint_value, spec);
824       break;
825     case Arg::LONG_LONG:
826       writer.write_int(arg.long_long_value, spec);
827       break;
828     case Arg::ULONG_LONG:
829       writer.write_int(arg.ulong_long_value, spec);
830       break;
831     case Arg::CHAR: {
832       if (spec.type_ && spec.type_ != 'c')
833         writer.write_int(arg.int_value, spec);
834       typedef typename BasicWriter<Char>::CharPtr CharPtr;
835       CharPtr out = CharPtr();
836       if (spec.width_ > 1) {
837         Char fill = ' ';
838         out = writer.grow_buffer(spec.width_);
839         if (spec.align_ != ALIGN_LEFT) {
840           std::fill_n(out, spec.width_ - 1, fill);
841           out += spec.width_ - 1;
842         } else {
843           std::fill_n(out + 1, spec.width_ - 1, fill);
844         }
845       } else {
846         out = writer.grow_buffer(1);
847       }
848       *out = static_cast<Char>(arg.int_value);
849       break;
850     }
851     case Arg::DOUBLE:
852       writer.write_double(arg.double_value, spec);
853       break;
854     case Arg::LONG_DOUBLE:
855       writer.write_double(arg.long_double_value, spec);
856       break;
857     case Arg::CSTRING:
858       arg.string.size = 0;
859       writer.write_str(arg.string, spec);
860       break;
861     case Arg::STRING:
862       writer.write_str(arg.string, spec);
863       break;
864     case Arg::WSTRING:
865       writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
866       break;
867     case Arg::POINTER:
868       if (spec.type_ && spec.type_ != 'p')
869         internal::report_unknown_type(spec.type_, "pointer");
870       spec.flags_= HASH_FLAG;
871       spec.type_ = 'x';
872       writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
873       break;
874     case Arg::CUSTOM: {
875       if (spec.type_)
876         internal::report_unknown_type(spec.type_, "object");
877       const void *s = "s";
878       arg.custom.format(&writer, arg.custom.value, &s);
879       break;
880     }
881     default:
882       assert(false);
883       break;
884     }
885   }
886   write(writer, start, s);
887 }
888 
889 template <typename Char>
format(const Char * & format_str,const Arg & arg)890 const Char *fmt::BasicFormatter<Char>::format(
891     const Char *&format_str, const Arg &arg) {
892   const Char *s = format_str;
893   FormatSpec spec;
894   if (*s == ':') {
895     if (arg.type == Arg::CUSTOM) {
896       arg.custom.format(this, arg.custom.value, &s);
897       return s;
898     }
899     ++s;
900     // Parse fill and alignment.
901     if (Char c = *s) {
902       const Char *p = s + 1;
903       spec.align_ = ALIGN_DEFAULT;
904       do {
905         switch (*p) {
906           case '<':
907             spec.align_ = ALIGN_LEFT;
908             break;
909           case '>':
910             spec.align_ = ALIGN_RIGHT;
911             break;
912           case '=':
913             spec.align_ = ALIGN_NUMERIC;
914             break;
915           case '^':
916             spec.align_ = ALIGN_CENTER;
917             break;
918         }
919         if (spec.align_ != ALIGN_DEFAULT) {
920           if (p != s) {
921             if (c == '}') break;
922             if (c == '{')
923               FMT_THROW(FormatError("invalid fill character '{'"));
924             s += 2;
925             spec.fill_ = c;
926           } else ++s;
927           if (spec.align_ == ALIGN_NUMERIC)
928             require_numeric_argument(arg, '=');
929           break;
930         }
931       } while (--p >= s);
932     }
933 
934     // Parse sign.
935     switch (*s) {
936       case '+':
937         check_sign(s, arg);
938         spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
939         break;
940       case '-':
941         check_sign(s, arg);
942         spec.flags_ |= MINUS_FLAG;
943         break;
944       case ' ':
945         check_sign(s, arg);
946         spec.flags_ |= SIGN_FLAG;
947         break;
948     }
949 
950     if (*s == '#') {
951       require_numeric_argument(arg, '#');
952       spec.flags_ |= HASH_FLAG;
953       ++s;
954     }
955 
956     // Parse width and zero flag.
957     if ('0' <= *s && *s <= '9') {
958       if (*s == '0') {
959         require_numeric_argument(arg, '0');
960         spec.align_ = ALIGN_NUMERIC;
961         spec.fill_ = '0';
962       }
963       // Zero may be parsed again as a part of the width, but it is simpler
964       // and more efficient than checking if the next char is a digit.
965       spec.width_ = parse_nonnegative_int(s);
966     }
967 
968     // Parse precision.
969     if (*s == '.') {
970       ++s;
971       spec.precision_ = 0;
972       if ('0' <= *s && *s <= '9') {
973         spec.precision_ = parse_nonnegative_int(s);
974       } else if (*s == '{') {
975         ++s;
976         const Arg &precision_arg = parse_arg_index(s);
977         if (*s++ != '}')
978           FMT_THROW(FormatError("invalid format string"));
979         ULongLong value = 0;
980         switch (precision_arg.type) {
981           case Arg::INT:
982             if (precision_arg.int_value < 0)
983               FMT_THROW(FormatError("negative precision"));
984             value = precision_arg.int_value;
985             break;
986           case Arg::UINT:
987             value = precision_arg.uint_value;
988             break;
989           case Arg::LONG_LONG:
990             if (precision_arg.long_long_value < 0)
991               FMT_THROW(FormatError("negative precision"));
992             value = precision_arg.long_long_value;
993             break;
994           case Arg::ULONG_LONG:
995             value = precision_arg.ulong_long_value;
996             break;
997           default:
998             FMT_THROW(FormatError("precision is not integer"));
999         }
1000         if (value > INT_MAX)
1001           FMT_THROW(FormatError("number is too big"));
1002         spec.precision_ = static_cast<int>(value);
1003       } else {
1004         FMT_THROW(FormatError("missing precision specifier"));
1005       }
1006       if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
1007         FMT_THROW(FormatError(
1008             "precision specifier requires floating-point argument"));
1009       }
1010     }
1011 
1012     // Parse type.
1013     if (*s != '}' && *s)
1014       spec.type_ = static_cast<char>(*s++);
1015   }
1016 
1017   if (*s++ != '}')
1018     FMT_THROW(FormatError("missing '}' in format string"));
1019   start_ = s;
1020 
1021   // Format argument.
1022   internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
1023   return s;
1024 }
1025 
1026 template <typename Char>
format(BasicStringRef<Char> format_str,const ArgList & args)1027 void fmt::BasicFormatter<Char>::format(
1028     BasicStringRef<Char> format_str, const ArgList &args) {
1029   const Char *s = start_ = format_str.c_str();
1030   set_args(args);
1031   while (*s) {
1032     Char c = *s++;
1033     if (c != '{' && c != '}') continue;
1034     if (*s == c) {
1035       write(writer_, start_, s);
1036       start_ = ++s;
1037       continue;
1038     }
1039     if (c == '}')
1040       FMT_THROW(FormatError("unmatched '}' in format string"));
1041     write(writer_, start_, s - 1);
1042     Arg arg = parse_arg_index(s);
1043     s = format(s, arg);
1044   }
1045   write(writer_, start_, s);
1046 }
1047 
report_system_error(int error_code,fmt::StringRef message)1048 void fmt::report_system_error(
1049     int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1050   report_error(internal::format_system_error, error_code, message);
1051 }
1052 
1053 #ifdef _WIN32
report_windows_error(int error_code,fmt::StringRef message)1054 void fmt::report_windows_error(
1055     int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1056   report_error(internal::format_windows_error, error_code, message);
1057 }
1058 #endif
1059 
print(std::FILE * f,StringRef format_str,ArgList args)1060 void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
1061   MemoryWriter w;
1062   w.write(format_str, args);
1063   std::fwrite(w.data(), 1, w.size(), f);
1064 }
1065 
print(StringRef format_str,ArgList args)1066 void fmt::print(StringRef format_str, ArgList args) {
1067   print(stdout, format_str, args);
1068 }
1069 
print(std::ostream & os,StringRef format_str,ArgList args)1070 void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
1071   MemoryWriter w;
1072   w.write(format_str, args);
1073   os.write(w.data(), w.size());
1074 }
1075 
print_colored(Color c,StringRef format,ArgList args)1076 void fmt::print_colored(Color c, StringRef format, ArgList args) {
1077   char escape[] = "\x1b[30m";
1078   escape[3] = '0' + static_cast<char>(c);
1079   std::fputs(escape, stdout);
1080   print(format, args);
1081   std::fputs(RESET_COLOR, stdout);
1082 }
1083 
fprintf(std::FILE * f,StringRef format,ArgList args)1084 int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
1085   MemoryWriter w;
1086   printf(w, format, args);
1087   std::size_t size = w.size();
1088   return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
1089 }
1090 
1091 // Explicit instantiations for char.
1092 
1093 template const char *fmt::BasicFormatter<char>::format(
1094     const char *&format_str, const fmt::internal::Arg &arg);
1095 
1096 template void fmt::BasicFormatter<char>::format(
1097   BasicStringRef<char> format, const ArgList &args);
1098 
1099 template void fmt::internal::PrintfFormatter<char>::format(
1100   BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
1101 
1102 template int fmt::internal::CharTraits<char>::format_float(
1103     char *buffer, std::size_t size, const char *format,
1104     unsigned width, int precision, double value);
1105 
1106 template int fmt::internal::CharTraits<char>::format_float(
1107     char *buffer, std::size_t size, const char *format,
1108     unsigned width, int precision, long double value);
1109 
1110 // Explicit instantiations for wchar_t.
1111 
1112 template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1113     const wchar_t *&format_str, const fmt::internal::Arg &arg);
1114 
1115 template void fmt::BasicFormatter<wchar_t>::format(
1116     BasicStringRef<wchar_t> format, const ArgList &args);
1117 
1118 template void fmt::internal::PrintfFormatter<wchar_t>::format(
1119     BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
1120     const ArgList &args);
1121 
1122 template int fmt::internal::CharTraits<wchar_t>::format_float(
1123     wchar_t *buffer, std::size_t size, const wchar_t *format,
1124     unsigned width, int precision, double value);
1125 
1126 template int fmt::internal::CharTraits<wchar_t>::format_float(
1127     wchar_t *buffer, std::size_t size, const wchar_t *format,
1128     unsigned width, int precision, long double value);
1129 
1130 #if _MSC_VER
1131 # pragma warning(pop)
1132 #endif
1133 
1134 
1135 } // end generic namespace
1136