1 /*
2  Formatting library for C++
3 
4  Copyright (c) 2012 - 2015, 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 // RPCLIB is compiled with most warnings, but this file needs more turned off.
29 #ifdef __clang__
30 #pragma clang diagnostic push
31 #pragma clang diagnostic ignored "-Wmultichar"
32 #pragma clang diagnostic ignored "-Wsign-conversion"
33 #pragma clang diagnostic ignored "-Wunused-member-function"
34 #pragma clang diagnostic ignored "-Wswitch-enum"
35 #pragma clang diagnostic ignored "-Wformat-nonliteral"
36 #pragma clang diagnostic ignored "-Wmissing-noreturn"
37 #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
38 #endif
39 
40 #include "format.h"
41 
42 #include <string.h>
43 
44 #include <cctype>
45 #include <cerrno>
46 #include <climits>
47 #include <cmath>
48 #include <cstdarg>
49 #include <cstddef>  // for std::ptrdiff_t
50 
51 #if defined(_WIN32) && defined(__MINGW32__)
52 # include <cstring>
53 #endif
54 
55 #if FMT_USE_WINDOWS_H
56 # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
57 #  include <windows.h>
58 # else
59 #  define NOMINMAX
60 #  include <windows.h>
61 #  undef NOMINMAX
62 # endif
63 #endif
64 
65 using clmdep_fmt::internal::Arg;
66 
67 // Check if exceptions are disabled.
68 #if defined(__GNUC__) && !defined(__EXCEPTIONS)
69 # define FMT_EXCEPTIONS 0
70 #endif
71 #if defined(_MSC_VER) && !_HAS_EXCEPTIONS
72 # define FMT_EXCEPTIONS 0
73 #endif
74 #ifndef FMT_EXCEPTIONS
75 # define FMT_EXCEPTIONS 1
76 #endif
77 
78 #if FMT_EXCEPTIONS
79 # define FMT_TRY try
80 # define FMT_CATCH(x) catch (x)
81 #else
82 # define FMT_TRY if (true)
83 # define FMT_CATCH(x) if (false)
84 #endif
85 
86 #ifndef FMT_THROW
87 # if FMT_EXCEPTIONS
88 #  define FMT_THROW(x) throw x
89 # else
90 #  define FMT_THROW(x) assert(false)
91 # endif
92 #endif
93 
94 #ifdef FMT_HEADER_ONLY
95 # define FMT_FUNC inline
96 #else
97 # define FMT_FUNC
98 #endif
99 
100 #ifdef _MSC_VER
101 # pragma warning(push)
102 # pragma warning(disable: 4127)  // conditional expression is constant
103 # pragma warning(disable: 4702)  // unreachable code
104 // Disable deprecation warning for strerror. The latter is not called but
105 // MSVC fails to detect it.
106 # pragma warning(disable: 4996)
107 #endif
108 
109 // Dummy implementations of strerror_r and strerror_s called if corresponding
110 // system functions are not available.
strerror_r(int,char *,...)111 static inline clmdep_fmt::internal::Null<> strerror_r(int, char *, ...) {
112   return clmdep_fmt::internal::Null<>();
113 }
strerror_s(char *,std::size_t,...)114 static inline clmdep_fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
115   return clmdep_fmt::internal::Null<>();
116 }
117 
118 namespace clmdep_fmt {
119 namespace {
120 
121 #ifndef _MSC_VER
122 # define FMT_SNPRINTF snprintf
123 #else  // _MSC_VER
124 inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
125   va_list args;
126   va_start(args, format);
127   int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
128   va_end(args);
129   return result;
130 }
131 # define FMT_SNPRINTF fmt_snprintf
132 #endif  // _MSC_VER
133 
134 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
135 # define FMT_SWPRINTF snwprintf
136 #else
137 # define FMT_SWPRINTF swprintf
138 #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
139 
140 // Checks if a value fits in int - used to avoid warnings about comparing
141 // signed and unsigned integers.
142 template <bool IsSigned>
143 struct IntChecker {
144   template <typename T>
fits_in_intclmdep_fmt::__anonfa5e28470111::IntChecker145   static bool fits_in_int(T value) {
146     unsigned max = INT_MAX;
147     return value <= max;
148   }
fits_in_intclmdep_fmt::__anonfa5e28470111::IntChecker149   static bool fits_in_int(bool) { return true; }
150 };
151 
152 template <>
153 struct IntChecker<true> {
154   template <typename T>
fits_in_intclmdep_fmt::__anonfa5e28470111::IntChecker155   static bool fits_in_int(T value) {
156     return value >= INT_MIN && value <= INT_MAX;
157   }
fits_in_intclmdep_fmt::__anonfa5e28470111::IntChecker158   static bool fits_in_int(int) { return true; }
159 };
160 
161 const char RESET_COLOR[] = "\x1b[0m";
162 
163 typedef void (*FormatFunc)(clmdep_fmt::Writer &, int, clmdep_fmt::StringRef);
164 
165 // Portable thread-safe version of strerror.
166 // Sets buffer to point to a string describing the error code.
167 // This can be either a pointer to a string stored in buffer,
168 // or a pointer to some static immutable string.
169 // Returns one of the following values:
170 //   0      - success
171 //   ERANGE - buffer is not large enough to store the error message
172 //   other  - failure
173 // Buffer should be at least of size 1.
safe_strerror(int error_code,char * & buffer,std::size_t buffer_size)174 int safe_strerror(
175     int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
176   FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
177 
178   class StrError {
179    private:
180     int error_code_;
181     char *&buffer_;
182     std::size_t buffer_size_;
183 
184     // A noop assignment operator to avoid bogus warnings.
185     void operator=(const StrError &) {}
186 
187     // Handle the result of XSI-compliant version of strerror_r.
188     int handle(int result) {
189       // glibc versions before 2.13 return result in errno.
190       return result == -1 ? errno : result;
191     }
192 
193     // Handle the result of GNU-specific version of strerror_r.
194     int handle(char *message) {
195       // If the buffer is full then the message is probably truncated.
196       if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
197         return ERANGE;
198       buffer_ = message;
199       return 0;
200     }
201 
202     // Handle the case when strerror_r is not available.
203     int handle(clmdep_fmt::internal::Null<>) {
204       return fallback(strerror_s(buffer_, buffer_size_, error_code_));
205     }
206 
207     // Fallback to strerror_s when strerror_r is not available.
208     int fallback(int result) {
209       // If the buffer is full then the message is probably truncated.
210       return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
211             ERANGE : result;
212     }
213 
214     // Fallback to strerror if strerror_r and strerror_s are not available.
215     int fallback(clmdep_fmt::internal::Null<>) {
216       errno = 0;
217       buffer_ = strerror(error_code_);
218       return errno;
219     }
220 
221    public:
222     StrError(int err_code, char *&buf, std::size_t buf_size)
223       : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
224 
225     int run() {
226       strerror_r(0, 0, "");  // Suppress a warning about unused strerror_r.
227       return handle(strerror_r(error_code_, buffer_, buffer_size_));
228     }
229   };
230   return StrError(error_code, buffer, buffer_size).run();
231 }
232 
format_error_code(clmdep_fmt::Writer & out,int error_code,clmdep_fmt::StringRef message)233 void format_error_code(clmdep_fmt::Writer &out, int error_code,
234                        clmdep_fmt::StringRef message) FMT_NOEXCEPT {
235   // Report error code making sure that the output fits into
236   // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
237   // bad_alloc.
238   out.clear();
239   static const char SEP[] = ": ";
240   static const char ERROR_STR[] = "error ";
241   clmdep_fmt::internal::IntTraits<int>::MainType ec_value = error_code;
242   // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
243   std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
244   error_code_size += clmdep_fmt::internal::count_digits(ec_value);
245   if (message.size() <= clmdep_fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
246     out << message << SEP;
247   out << ERROR_STR << error_code;
248   assert(out.size() <= clmdep_fmt::internal::INLINE_BUFFER_SIZE);
249 }
250 
report_error(FormatFunc func,int error_code,clmdep_fmt::StringRef message)251 void report_error(FormatFunc func,
252     int error_code, clmdep_fmt::StringRef message) FMT_NOEXCEPT {
253   clmdep_fmt::MemoryWriter full_message;
254   func(full_message, error_code, message);
255   // Use Writer::data instead of Writer::c_str to avoid potential memory
256   // allocation.
257   std::fwrite(full_message.data(), full_message.size(), 1, stderr);
258   std::fputc('\n', stderr);
259 }
260 
261 // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
262 class IsZeroInt : public clmdep_fmt::internal::ArgVisitor<IsZeroInt, bool> {
263  public:
264   template <typename T>
visit_any_int(T value)265   bool visit_any_int(T value) { return value == 0; }
266 };
267 
268 // Parses an unsigned integer advancing s to the end of the parsed input.
269 // This function assumes that the first character of s is a digit.
270 template <typename Char>
parse_nonnegative_int(const Char * & s)271 int parse_nonnegative_int(const Char *&s) {
272   assert('0' <= *s && *s <= '9');
273   unsigned value = 0;
274   do {
275     unsigned new_value = value * 10 + (*s++ - '0');
276     // Check if value wrapped around.
277     if (new_value < value) {
278       value = UINT_MAX;
279       break;
280     }
281     value = new_value;
282   } while ('0' <= *s && *s <= '9');
283   if (value > INT_MAX)
284     FMT_THROW(clmdep_fmt::FormatError("number is too big"));
285   return value;
286 }
287 
288 template <typename Char>
is_name_start(Char c)289 inline bool is_name_start(Char c) {
290   return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
291 }
292 
require_numeric_argument(const Arg & arg,char spec)293 inline void require_numeric_argument(const Arg &arg, char spec) {
294   if (arg.type > Arg::LAST_NUMERIC_TYPE) {
295     std::string message =
296         clmdep_fmt::format("format specifier '{}' requires numeric argument", spec);
297     FMT_THROW(clmdep_fmt::FormatError(message));
298   }
299 }
300 
301 template <typename Char>
check_sign(const Char * & s,const Arg & arg)302 void check_sign(const Char *&s, const Arg &arg) {
303   char sign = static_cast<char>(*s);
304   require_numeric_argument(arg, sign);
305   if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
306     FMT_THROW(clmdep_fmt::FormatError(clmdep_fmt::format(
307       "format specifier '{}' requires signed argument", sign)));
308   }
309   ++s;
310 }
311 
312 // Checks if an argument is a valid printf width specifier and sets
313 // left alignment if it is negative.
314 class WidthHandler : public clmdep_fmt::internal::ArgVisitor<WidthHandler, unsigned> {
315  private:
316   clmdep_fmt::FormatSpec &spec_;
317 
318   FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
319 
320  public:
WidthHandler(clmdep_fmt::FormatSpec & spec)321   explicit WidthHandler(clmdep_fmt::FormatSpec &spec) : spec_(spec) {}
322 
report_unhandled_arg()323   void report_unhandled_arg() {
324     FMT_THROW(clmdep_fmt::FormatError("width is not integer"));
325   }
326 
327   template <typename T>
visit_any_int(T value)328   unsigned visit_any_int(T value) {
329     typedef typename clmdep_fmt::internal::IntTraits<T>::MainType UnsignedType;
330     UnsignedType width = value;
331     if (clmdep_fmt::internal::is_negative(value)) {
332       spec_.align_ = clmdep_fmt::ALIGN_LEFT;
333       width = 0 - width;
334     }
335     if (width > INT_MAX)
336       FMT_THROW(clmdep_fmt::FormatError("number is too big"));
337     return static_cast<unsigned>(width);
338   }
339 };
340 
341 class PrecisionHandler :
342     public clmdep_fmt::internal::ArgVisitor<PrecisionHandler, int> {
343  public:
report_unhandled_arg()344   void report_unhandled_arg() {
345     FMT_THROW(clmdep_fmt::FormatError("precision is not integer"));
346   }
347 
348   template <typename T>
visit_any_int(T value)349   int visit_any_int(T value) {
350     if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
351       FMT_THROW(clmdep_fmt::FormatError("number is too big"));
352     return static_cast<int>(value);
353   }
354 };
355 
356 // Converts an integer argument to an integral type T for printf.
357 template <typename T>
358 class ArgConverter : public clmdep_fmt::internal::ArgVisitor<ArgConverter<T>, void> {
359  private:
360   clmdep_fmt::internal::Arg &arg_;
361   wchar_t type_;
362 
363   FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
364 
365  public:
ArgConverter(clmdep_fmt::internal::Arg & arg,wchar_t type)366   ArgConverter(clmdep_fmt::internal::Arg &arg, wchar_t type)
367     : arg_(arg), type_(type) {}
368 
visit_bool(bool value)369   void visit_bool(bool value) {
370     if (type_ != 's')
371       visit_any_int(value);
372   }
373 
374   template <typename U>
visit_any_int(U value)375   void visit_any_int(U value) {
376     bool is_signed = type_ == 'd' || type_ == 'i';
377     using clmdep_fmt::internal::Arg;
378     if (sizeof(T) <= sizeof(int)) {
379       // Extra casts are used to silence warnings.
380       if (is_signed) {
381         arg_.type = Arg::INT;
382         arg_.int_value = static_cast<int>(static_cast<T>(value));
383       } else {
384         arg_.type = Arg::UINT;
385         arg_.uint_value = static_cast<unsigned>(
386             static_cast<typename clmdep_fmt::internal::MakeUnsigned<T>::Type>(value));
387       }
388     } else {
389       if (is_signed) {
390         arg_.type = Arg::LONG_LONG;
391         arg_.long_long_value =
392             static_cast<typename clmdep_fmt::internal::MakeUnsigned<U>::Type>(value);
393       } else {
394         arg_.type = Arg::ULONG_LONG;
395         arg_.ulong_long_value =
396             static_cast<typename clmdep_fmt::internal::MakeUnsigned<U>::Type>(value);
397       }
398     }
399   }
400 };
401 
402 // Converts an integer argument to char for printf.
403 class CharConverter : public clmdep_fmt::internal::ArgVisitor<CharConverter, void> {
404  private:
405   clmdep_fmt::internal::Arg &arg_;
406 
407   FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
408 
409  public:
CharConverter(clmdep_fmt::internal::Arg & arg)410   explicit CharConverter(clmdep_fmt::internal::Arg &arg) : arg_(arg) {}
411 
412   template <typename T>
visit_any_int(T value)413   void visit_any_int(T value) {
414     arg_.type = Arg::CHAR;
415     arg_.int_value = static_cast<char>(value);
416   }
417 };
418 }  // namespace
419 
420 namespace internal {
421 
422 template <typename Impl, typename Char>
423 class BasicArgFormatter : public ArgVisitor<Impl, void> {
424  private:
425   BasicWriter<Char> &writer_;
426   FormatSpec &spec_;
427 
428   FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
429 
write_pointer(const void * p)430   void write_pointer(const void *p) {
431     spec_.flags_ = HASH_FLAG;
432     spec_.type_ = 'x';
433     writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_);
434   }
435 
436  protected:
writer()437   BasicWriter<Char> &writer() { return writer_; }
spec()438   FormatSpec &spec() { return spec_; }
439 
write(bool value)440   void write(bool value) {
441     const char *str_value = value ? "true" : "false";
442     Arg::StringValue<char> str = { str_value, strlen(str_value) };
443     writer_.write_str(str, spec_);
444   }
445 
write(const char * value)446   void write(const char *value) {
447     Arg::StringValue<char> str = {value, value != 0 ? strlen(value) : 0};
448     writer_.write_str(str, spec_);
449   }
450 
451  public:
BasicArgFormatter(BasicWriter<Char> & w,FormatSpec & s)452   BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
453   : writer_(w), spec_(s) {}
454 
455   template <typename T>
visit_any_int(T value)456   void visit_any_int(T value) { writer_.write_int(value, spec_); }
457 
458   template <typename T>
visit_any_double(T value)459   void visit_any_double(T value) { writer_.write_double(value, spec_); }
460 
visit_bool(bool value)461   void visit_bool(bool value) {
462     if (spec_.type_)
463       return visit_any_int(value);
464     write(value);
465   }
466 
visit_char(int value)467   void visit_char(int value) {
468     if (spec_.type_ && spec_.type_ != 'c') {
469       spec_.flags_ |= CHAR_FLAG;
470       writer_.write_int(value, spec_);
471       return;
472     }
473     if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
474       FMT_THROW(FormatError("invalid format specifier for char"));
475     typedef typename BasicWriter<Char>::CharPtr CharPtr;
476     Char fill = internal::CharTraits<Char>::cast(spec_.fill());
477     CharPtr out = CharPtr();
478     const unsigned FMT_CHAR_WIDTH = 1;
479     if (spec_.width_ > FMT_CHAR_WIDTH) {
480       out = writer_.grow_buffer(spec_.width_);
481       if (spec_.align_ == ALIGN_RIGHT) {
482         std::fill_n(out, spec_.width_ - FMT_CHAR_WIDTH, fill);
483         out += spec_.width_ - FMT_CHAR_WIDTH;
484       } else if (spec_.align_ == ALIGN_CENTER) {
485         out = writer_.fill_padding(out, spec_.width_,
486                                    internal::check(FMT_CHAR_WIDTH), fill);
487       } else {
488         std::fill_n(out + FMT_CHAR_WIDTH, spec_.width_ - FMT_CHAR_WIDTH, fill);
489       }
490     } else {
491       out = writer_.grow_buffer(FMT_CHAR_WIDTH);
492     }
493     *out = internal::CharTraits<Char>::cast(value);
494   }
495 
visit_cstring(const char * value)496   void visit_cstring(const char *value) {
497     if (spec_.type_ == 'p')
498       return write_pointer(value);
499     write(value);
500   }
501 
visit_string(Arg::StringValue<char> value)502   void visit_string(Arg::StringValue<char> value) {
503     writer_.write_str(value, spec_);
504   }
505 
506   using ArgVisitor<Impl, void>::visit_wstring;
507 
visit_wstring(Arg::StringValue<Char> value)508   void visit_wstring(Arg::StringValue<Char> value) {
509     writer_.write_str(value, spec_);
510   }
511 
visit_pointer(const void * value)512   void visit_pointer(const void *value) {
513     if (spec_.type_ && spec_.type_ != 'p')
514       report_unknown_type(spec_.type_, "pointer");
515     write_pointer(value);
516   }
517 };
518 
519 // An argument formatter.
520 template <typename Char>
521 class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
522  private:
523   BasicFormatter<Char> &formatter_;
524   const Char *format_;
525 
526  public:
ArgFormatter(BasicFormatter<Char> & f,FormatSpec & s,const Char * fmt)527   ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
528   : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
529     formatter_(f), format_(fmt) {}
530 
visit_custom(Arg::CustomValue c)531   void visit_custom(Arg::CustomValue c) {
532     c.format(&formatter_, c.value, &format_);
533   }
534 };
535 
536 template <typename Char>
537 class PrintfArgFormatter :
538     public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
539 
write_null_pointer()540   void write_null_pointer() {
541     this->spec().type_ = 0;
542     this->write("(nil)");
543   }
544 
545   typedef BasicArgFormatter<PrintfArgFormatter<Char>, Char> Base;
546 
547  public:
PrintfArgFormatter(BasicWriter<Char> & w,FormatSpec & s)548   PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
549   : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
550 
visit_bool(bool value)551   void visit_bool(bool value) {
552     FormatSpec &fmt_spec = this->spec();
553     if (fmt_spec.type_ != 's')
554       return this->visit_any_int(value);
555     fmt_spec.type_ = 0;
556     this->write(value);
557   }
558 
visit_char(int value)559   void visit_char(int value) {
560     const FormatSpec &fmt_spec = this->spec();
561     BasicWriter<Char> &w = this->writer();
562     if (fmt_spec.type_ && fmt_spec.type_ != 'c')
563       w.write_int(value, fmt_spec);
564     typedef typename BasicWriter<Char>::CharPtr CharPtr;
565     CharPtr out = CharPtr();
566     if (fmt_spec.width_ > 1) {
567       Char fill = ' ';
568       out = w.grow_buffer(fmt_spec.width_);
569       if (fmt_spec.align_ != ALIGN_LEFT) {
570         std::fill_n(out, fmt_spec.width_ - 1, fill);
571         out += fmt_spec.width_ - 1;
572       } else {
573         std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
574       }
575     } else {
576       out = w.grow_buffer(1);
577     }
578     *out = static_cast<Char>(value);
579   }
580 
visit_cstring(const char * value)581   void visit_cstring(const char *value) {
582     if (value)
583       Base::visit_cstring(value);
584     else if (this->spec().type_ == 'p')
585       write_null_pointer();
586     else
587       this->write("(null)");
588   }
589 
visit_pointer(const void * value)590   void visit_pointer(const void *value) {
591     if (value)
592       return Base::visit_pointer(value);
593     this->spec().type_ = 0;
594     write_null_pointer();
595   }
596 
visit_custom(Arg::CustomValue c)597   void visit_custom(Arg::CustomValue c) {
598     BasicFormatter<Char> formatter(ArgList(), this->writer());
599     const Char format_str[] = {'}', 0};
600     const Char *format = format_str;
601     c.format(&formatter, c.value, &format);
602   }
603 };
604 }  // namespace internal
605 }  // namespace clmdep_fmt
606 
init(int err_code,CStringRef format_str,ArgList args)607 FMT_FUNC void clmdep_fmt::SystemError::init(
608     int err_code, CStringRef format_str, ArgList args) {
609   error_code_ = err_code;
610   MemoryWriter w;
611   internal::format_system_error(w, err_code, format(format_str, args));
612   std::runtime_error &base = *this;
613   base = std::runtime_error(w.str());
614 }
615 
616 template <typename T>
format_float(char * buffer,std::size_t size,const char * format,unsigned width,int precision,T value)617 int clmdep_fmt::internal::CharTraits<char>::format_float(
618     char *buffer, std::size_t size, const char *format,
619     unsigned width, int precision, T value) {
620   if (width == 0) {
621     return precision < 0 ?
622         FMT_SNPRINTF(buffer, size, format, value) :
623         FMT_SNPRINTF(buffer, size, format, precision, value);
624   }
625   return precision < 0 ?
626       FMT_SNPRINTF(buffer, size, format, width, value) :
627       FMT_SNPRINTF(buffer, size, format, width, precision, value);
628 }
629 
630 template <typename T>
format_float(wchar_t * buffer,std::size_t size,const wchar_t * format,unsigned width,int precision,T value)631 int clmdep_fmt::internal::CharTraits<wchar_t>::format_float(
632     wchar_t *buffer, std::size_t size, const wchar_t *format,
633     unsigned width, int precision, T value) {
634   if (width == 0) {
635     return precision < 0 ?
636         FMT_SWPRINTF(buffer, size, format, value) :
637         FMT_SWPRINTF(buffer, size, format, precision, value);
638   }
639   return precision < 0 ?
640       FMT_SWPRINTF(buffer, size, format, width, value) :
641       FMT_SWPRINTF(buffer, size, format, width, precision, value);
642 }
643 
644 template <typename T>
645 const char clmdep_fmt::internal::BasicData<T>::DIGITS[] =
646     "0001020304050607080910111213141516171819"
647     "2021222324252627282930313233343536373839"
648     "4041424344454647484950515253545556575859"
649     "6061626364656667686970717273747576777879"
650     "8081828384858687888990919293949596979899";
651 
652 #define FMT_POWERS_OF_10(factor) \
653   factor * 10, \
654   factor * 100, \
655   factor * 1000, \
656   factor * 10000, \
657   factor * 100000, \
658   factor * 1000000, \
659   factor * 10000000, \
660   factor * 100000000, \
661   factor * 1000000000
662 
663 template <typename T>
664 const uint32_t clmdep_fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
665   0, FMT_POWERS_OF_10(1)
666 };
667 
668 template <typename T>
669 const uint64_t clmdep_fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
670   0,
671   FMT_POWERS_OF_10(1),
672   FMT_POWERS_OF_10(clmdep_fmt::ULongLong(1000000000)),
673   // Multiply several constants instead of using a single long long constant
674   // to avoid warnings about C++98 not supporting long long.
675   clmdep_fmt::ULongLong(1000000000) * clmdep_fmt::ULongLong(1000000000) * 10
676 };
677 
report_unknown_type(char code,const char * type)678 FMT_FUNC void clmdep_fmt::internal::report_unknown_type(char code, const char *type) {
679   (void)type;
680   if (std::isprint(static_cast<unsigned char>(code))) {
681     FMT_THROW(clmdep_fmt::FormatError(
682         clmdep_fmt::format("unknown format code '{}' for {}", code, type)));
683   }
684   FMT_THROW(clmdep_fmt::FormatError(
685       clmdep_fmt::format("unknown format code '\\x{:02x}' for {}",
686         static_cast<unsigned>(code), type)));
687 }
688 
689 #if FMT_USE_WINDOWS_H
690 
UTF8ToUTF16(clmdep_fmt::StringRef s)691 FMT_FUNC clmdep_fmt::internal::UTF8ToUTF16::UTF8ToUTF16(clmdep_fmt::StringRef s) {
692   static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
693   if (s.size() > INT_MAX)
694     FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
695   int s_size = static_cast<int>(s.size());
696   int length = MultiByteToWideChar(
697       CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
698   if (length == 0)
699     FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
700   buffer_.resize(length + 1);
701   length = MultiByteToWideChar(
702     CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
703   if (length == 0)
704     FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
705   buffer_[length] = 0;
706 }
707 
UTF16ToUTF8(clmdep_fmt::WStringRef s)708 FMT_FUNC clmdep_fmt::internal::UTF16ToUTF8::UTF16ToUTF8(clmdep_fmt::WStringRef s) {
709   if (int error_code = convert(s)) {
710     FMT_THROW(WindowsError(error_code,
711         "cannot convert string from UTF-16 to UTF-8"));
712   }
713 }
714 
convert(clmdep_fmt::WStringRef s)715 FMT_FUNC int clmdep_fmt::internal::UTF16ToUTF8::convert(clmdep_fmt::WStringRef s) {
716   if (s.size() > INT_MAX)
717     return ERROR_INVALID_PARAMETER;
718   int s_size = static_cast<int>(s.size());
719   int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
720   if (length == 0)
721     return GetLastError();
722   buffer_.resize(length + 1);
723   length = WideCharToMultiByte(
724     CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
725   if (length == 0)
726     return GetLastError();
727   buffer_[length] = 0;
728   return 0;
729 }
730 
init(int err_code,CStringRef format_str,ArgList args)731 FMT_FUNC void clmdep_fmt::WindowsError::init(
732     int err_code, CStringRef format_str, ArgList args) {
733   error_code_ = err_code;
734   MemoryWriter w;
735   internal::format_windows_error(w, err_code, format(format_str, args));
736   std::runtime_error &base = *this;
737   base = std::runtime_error(w.str());
738 }
739 
format_windows_error(clmdep_fmt::Writer & out,int error_code,clmdep_fmt::StringRef message)740 FMT_FUNC void clmdep_fmt::internal::format_windows_error(
741     clmdep_fmt::Writer &out, int error_code,
742     clmdep_fmt::StringRef message) FMT_NOEXCEPT {
743   class String {
744    private:
745     LPWSTR str_;
746 
747    public:
748     String() : str_() {}
749     ~String() { LocalFree(str_); }
750     LPWSTR *ptr() { return &str_; }
751     LPCWSTR c_str() const { return str_; }
752   };
753   FMT_TRY {
754     String system_message;
755     if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
756         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
757         error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
758         reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
759       UTF16ToUTF8 utf8_message;
760       if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
761         out << message << ": " << utf8_message;
762         return;
763       }
764     }
765   } FMT_CATCH(...) {}
766   clmdep_fmt::format_error_code(out, error_code, message);  // 'clmdep_fmt::' is for bcc32.
767 }
768 
769 #endif  // FMT_USE_WINDOWS_H
770 
format_system_error(clmdep_fmt::Writer & out,int error_code,clmdep_fmt::StringRef message)771 FMT_FUNC void clmdep_fmt::internal::format_system_error(
772     clmdep_fmt::Writer &out, int error_code,
773     clmdep_fmt::StringRef message) FMT_NOEXCEPT {
774   FMT_TRY {
775     MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
776     buffer.resize(INLINE_BUFFER_SIZE);
777     for (;;) {
778       char *system_message = &buffer[0];
779       int result = safe_strerror(error_code, system_message, buffer.size());
780       if (result == 0) {
781         out << message << ": " << system_message;
782         return;
783       }
784       if (result != ERANGE)
785         break;  // Can't get error message, report error code instead.
786       buffer.resize(buffer.size() * 2);
787     }
788   } FMT_CATCH(...) {}
789   clmdep_fmt::format_error_code(out, error_code, message);  // 'clmdep_fmt::' is for bcc32.
790 }
791 
792 template <typename Char>
init(const ArgList & args)793 void clmdep_fmt::internal::ArgMap<Char>::init(const ArgList &args) {
794   if (!map_.empty())
795     return;
796   typedef internal::NamedArg<Char> NamedArg;
797   const NamedArg *named_arg = 0;
798   bool use_values =
799       args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
800   if (use_values) {
801     for (unsigned i = 0;/*nothing*/; ++i) {
802       internal::Arg::Type arg_type = args.type(i);
803       switch (arg_type) {
804       case internal::Arg::NONE:
805         return;
806       case internal::Arg::NAMED_ARG:
807         named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
808         map_.insert(Pair(named_arg->name, *named_arg));
809         break;
810       default:
811         /*nothing*/;
812       }
813     }
814     return;
815   }
816   for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
817     internal::Arg::Type arg_type = args.type(i);
818     if (arg_type == internal::Arg::NAMED_ARG) {
819       named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
820       map_.insert(Pair(named_arg->name, *named_arg));
821     }
822   }
823   for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
824     switch (args.args_[i].type) {
825     case internal::Arg::NONE:
826       return;
827     case internal::Arg::NAMED_ARG:
828       named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
829       map_.insert(Pair(named_arg->name, *named_arg));
830       break;
831     default:
832       /*nothing*/;
833     }
834   }
835 }
836 
837 template <typename Char>
grow(std::size_t)838 void clmdep_fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
839   FMT_THROW(std::runtime_error("buffer overflow"));
840 }
841 
842 template <typename Char>
843 template <typename StrChar>
write_str(const Arg::StringValue<StrChar> & s,const FormatSpec & spec)844 void clmdep_fmt::BasicWriter<Char>::write_str(
845     const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
846   // Check if StrChar is convertible to Char.
847   internal::CharTraits<Char>::convert(StrChar());
848   if (spec.type_ && spec.type_ != 's')
849     internal::report_unknown_type(spec.type_, "string");
850   const StrChar *str_value = s.value;
851   std::size_t str_size = s.size;
852   if (str_size == 0) {
853     if (!str_value) {
854       FMT_THROW(FormatError("string pointer is null"));
855       return;
856     }
857   }
858   std::size_t precision = spec.precision_;
859   if (spec.precision_ >= 0 && precision < str_size)
860     str_size = spec.precision_;
861   write_str(str_value, str_size, spec);
862 }
863 
864 template <typename Char>
get_arg(BasicStringRef<Char> arg_name,const char * & error)865 inline Arg clmdep_fmt::BasicFormatter<Char>::get_arg(
866   BasicStringRef<Char> arg_name, const char *&error) {
867   if (check_no_auto_index(error)) {
868     map_.init(args());
869     const Arg *arg = map_.find(arg_name);
870     if (arg)
871       return *arg;
872     error = "argument not found";
873   }
874   return Arg();
875 }
876 
877 template <typename Char>
parse_arg_index(const Char * & s)878 inline Arg clmdep_fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
879   const char *error = 0;
880   Arg arg = *s < '0' || *s > '9' ?
881         next_arg(error) : get_arg(parse_nonnegative_int(s), error);
882   if (error) {
883     FMT_THROW(FormatError(
884                 *s != '}' && *s != ':' ? "invalid format string" : error));
885   }
886   return arg;
887 }
888 
889 template <typename Char>
parse_arg_name(const Char * & s)890 inline Arg clmdep_fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
891   assert(is_name_start(*s));
892   const Char *start = s;
893   Char c;
894   do {
895     c = *++s;
896   } while (is_name_start(c) || ('0' <= c && c <= '9'));
897   const char *error = 0;
898   Arg arg = get_arg(clmdep_fmt::BasicStringRef<Char>(start, s - start), error);
899   if (error)
900     FMT_THROW(clmdep_fmt::FormatError(error));
901   return arg;
902 }
903 
do_get_arg(unsigned arg_index,const char * & error)904 FMT_FUNC Arg clmdep_fmt::internal::FormatterBase::do_get_arg(
905     unsigned arg_index, const char *&error) {
906   Arg arg = args_[arg_index];
907   switch (arg.type) {
908   case Arg::NONE:
909     error = "argument index out of range";
910     break;
911   case Arg::NAMED_ARG:
912     arg = *static_cast<const internal::Arg*>(arg.pointer);
913   default:
914     /*nothing*/;
915   }
916   return arg;
917 }
918 
next_arg(const char * & error)919 inline Arg clmdep_fmt::internal::FormatterBase::next_arg(const char *&error) {
920   if (next_arg_index_ >= 0)
921     return do_get_arg(next_arg_index_++, error);
922   error = "cannot switch from manual to automatic argument indexing";
923   return Arg();
924 }
925 
check_no_auto_index(const char * & error)926 inline bool clmdep_fmt::internal::FormatterBase::check_no_auto_index(
927     const char *&error) {
928   if (next_arg_index_ > 0) {
929     error = "cannot switch from automatic to manual argument indexing";
930     return false;
931   }
932   next_arg_index_ = -1;
933   return true;
934 }
935 
get_arg(unsigned arg_index,const char * & error)936 inline Arg clmdep_fmt::internal::FormatterBase::get_arg(
937     unsigned arg_index, const char *&error) {
938   return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
939 }
940 
941 template <typename Char>
parse_flags(FormatSpec & spec,const Char * & s)942 void clmdep_fmt::internal::PrintfFormatter<Char>::parse_flags(
943     FormatSpec &spec, const Char *&s) {
944   for (;;) {
945     switch (*s++) {
946       case '-':
947         spec.align_ = ALIGN_LEFT;
948         break;
949       case '+':
950         spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
951         break;
952       case '0':
953         spec.fill_ = '0';
954         break;
955       case ' ':
956         spec.flags_ |= SIGN_FLAG;
957         break;
958       case '#':
959         spec.flags_ |= HASH_FLAG;
960         break;
961       default:
962         --s;
963         return;
964     }
965   }
966 }
967 
968 template <typename Char>
get_arg(const Char * s,unsigned arg_index)969 Arg clmdep_fmt::internal::PrintfFormatter<Char>::get_arg(
970     const Char *s, unsigned arg_index) {
971   (void)s;
972   const char *error = 0;
973   Arg arg = arg_index == UINT_MAX ?
974     next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
975   if (error)
976     FMT_THROW(FormatError(!*s ? "invalid format string" : error));
977   return arg;
978 }
979 
980 template <typename Char>
parse_header(const Char * & s,FormatSpec & spec)981 unsigned clmdep_fmt::internal::PrintfFormatter<Char>::parse_header(
982   const Char *&s, FormatSpec &spec) {
983   unsigned arg_index = UINT_MAX;
984   Char c = *s;
985   if (c >= '0' && c <= '9') {
986     // Parse an argument index (if followed by '$') or a width possibly
987     // preceded with '0' flag(s).
988     unsigned value = parse_nonnegative_int(s);
989     if (*s == '$') {  // value is an argument index
990       ++s;
991       arg_index = value;
992     } else {
993       if (c == '0')
994         spec.fill_ = '0';
995       if (value != 0) {
996         // Nonzero value means that we parsed width and don't need to
997         // parse it or flags again, so return now.
998         spec.width_ = value;
999         return arg_index;
1000       }
1001     }
1002   }
1003   parse_flags(spec, s);
1004   // Parse width.
1005   if (*s >= '0' && *s <= '9') {
1006     spec.width_ = parse_nonnegative_int(s);
1007   } else if (*s == '*') {
1008     ++s;
1009     spec.width_ = WidthHandler(spec).visit(get_arg(s));
1010   }
1011   return arg_index;
1012 }
1013 
1014 template <typename Char>
format(BasicWriter<Char> & writer,BasicCStringRef<Char> format_str)1015 void clmdep_fmt::internal::PrintfFormatter<Char>::format(
1016     BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
1017   const Char *start = format_str.c_str();
1018   const Char *s = start;
1019   while (*s) {
1020     Char c = *s++;
1021     if (c != '%') continue;
1022     if (*s == c) {
1023       write(writer, start, s);
1024       start = ++s;
1025       continue;
1026     }
1027     write(writer, start, s - 1);
1028 
1029     FormatSpec spec;
1030     spec.align_ = ALIGN_RIGHT;
1031 
1032     // Parse argument index, flags and width.
1033     unsigned arg_index = parse_header(s, spec);
1034 
1035     // Parse precision.
1036     if (*s == '.') {
1037       ++s;
1038       if ('0' <= *s && *s <= '9') {
1039         spec.precision_ = parse_nonnegative_int(s);
1040       } else if (*s == '*') {
1041         ++s;
1042         spec.precision_ = PrecisionHandler().visit(get_arg(s));
1043       }
1044     }
1045 
1046     Arg arg = get_arg(s, arg_index);
1047     if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
1048       spec.flags_ &= ~HASH_FLAG;
1049     if (spec.fill_ == '0') {
1050       if (arg.type <= Arg::LAST_NUMERIC_TYPE)
1051         spec.align_ = ALIGN_NUMERIC;
1052       else
1053         spec.fill_ = ' ';  // Ignore '0' flag for non-numeric types.
1054     }
1055 
1056     // Parse length and convert the argument to the required type.
1057     switch (*s++) {
1058     case 'h':
1059       if (*s == 'h')
1060         ArgConverter<signed char>(arg, *++s).visit(arg);
1061       else
1062         ArgConverter<short>(arg, *s).visit(arg);
1063       break;
1064     case 'l':
1065       if (*s == 'l')
1066         ArgConverter<clmdep_fmt::LongLong>(arg, *++s).visit(arg);
1067       else
1068         ArgConverter<long>(arg, *s).visit(arg);
1069       break;
1070     case 'j':
1071       ArgConverter<intmax_t>(arg, *s).visit(arg);
1072       break;
1073     case 'z':
1074       ArgConverter<std::size_t>(arg, *s).visit(arg);
1075       break;
1076     case 't':
1077       ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
1078       break;
1079     case 'L':
1080       // printf produces garbage when 'L' is omitted for long double, no
1081       // need to do the same.
1082       break;
1083     default:
1084       --s;
1085       ArgConverter<int>(arg, *s).visit(arg);
1086     }
1087 
1088     // Parse type.
1089     if (!*s)
1090       FMT_THROW(FormatError("invalid format string"));
1091     spec.type_ = static_cast<char>(*s++);
1092     if (arg.type <= Arg::LAST_INTEGER_TYPE) {
1093       // Normalize type.
1094       switch (spec.type_) {
1095       case 'i': case 'u':
1096         spec.type_ = 'd';
1097         break;
1098       case 'c':
1099         // TODO: handle wchar_t
1100         CharConverter(arg).visit(arg);
1101         break;
1102       }
1103     }
1104 
1105     start = s;
1106 
1107     // Format argument.
1108     internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
1109   }
1110   write(writer, start, s);
1111 }
1112 
1113 template <typename Char>
format(const Char * & format_str,const Arg & arg)1114 const Char *clmdep_fmt::BasicFormatter<Char>::format(
1115     const Char *&format_str, const Arg &arg) {
1116   const Char *s = format_str;
1117   FormatSpec spec;
1118   if (*s == ':') {
1119     if (arg.type == Arg::CUSTOM) {
1120       arg.custom.format(this, arg.custom.value, &s);
1121       return s;
1122     }
1123     ++s;
1124     // Parse fill and alignment.
1125     if (Char c = *s) {
1126       const Char *p = s + 1;
1127       spec.align_ = ALIGN_DEFAULT;
1128       do {
1129         switch (*p) {
1130           case '<':
1131             spec.align_ = ALIGN_LEFT;
1132             break;
1133           case '>':
1134             spec.align_ = ALIGN_RIGHT;
1135             break;
1136           case '=':
1137             spec.align_ = ALIGN_NUMERIC;
1138             break;
1139           case '^':
1140             spec.align_ = ALIGN_CENTER;
1141             break;
1142         }
1143         if (spec.align_ != ALIGN_DEFAULT) {
1144           if (p != s) {
1145             if (c == '}') break;
1146             if (c == '{')
1147               FMT_THROW(FormatError("invalid fill character '{'"));
1148             s += 2;
1149             spec.fill_ = c;
1150           } else ++s;
1151           if (spec.align_ == ALIGN_NUMERIC)
1152             require_numeric_argument(arg, '=');
1153           break;
1154         }
1155       } while (--p >= s);
1156     }
1157 
1158     // Parse sign.
1159     switch (*s) {
1160       case '+':
1161         check_sign(s, arg);
1162         spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1163         break;
1164       case '-':
1165         check_sign(s, arg);
1166         spec.flags_ |= MINUS_FLAG;
1167         break;
1168       case ' ':
1169         check_sign(s, arg);
1170         spec.flags_ |= SIGN_FLAG;
1171         break;
1172     }
1173 
1174     if (*s == '#') {
1175       require_numeric_argument(arg, '#');
1176       spec.flags_ |= HASH_FLAG;
1177       ++s;
1178     }
1179 
1180     // Parse zero flag.
1181     if (*s == '0') {
1182       require_numeric_argument(arg, '0');
1183       spec.align_ = ALIGN_NUMERIC;
1184       spec.fill_ = '0';
1185       ++s;
1186     }
1187 
1188     // Parse width.
1189     if ('0' <= *s && *s <= '9') {
1190       spec.width_ = parse_nonnegative_int(s);
1191     } else if (*s == '{') {
1192       ++s;
1193       Arg width_arg = is_name_start(*s) ?
1194             parse_arg_name(s) : parse_arg_index(s);
1195       if (*s++ != '}')
1196         FMT_THROW(FormatError("invalid format string"));
1197       ULongLong value = 0;
1198       switch (width_arg.type) {
1199       case Arg::INT:
1200         if (width_arg.int_value < 0)
1201           FMT_THROW(FormatError("negative width"));
1202         value = width_arg.int_value;
1203         break;
1204       case Arg::UINT:
1205         value = width_arg.uint_value;
1206         break;
1207       case Arg::LONG_LONG:
1208         if (width_arg.long_long_value < 0)
1209           FMT_THROW(FormatError("negative width"));
1210         value = width_arg.long_long_value;
1211         break;
1212       case Arg::ULONG_LONG:
1213         value = width_arg.ulong_long_value;
1214         break;
1215       default:
1216         FMT_THROW(FormatError("width is not integer"));
1217       }
1218       if (value > INT_MAX)
1219         FMT_THROW(FormatError("number is too big"));
1220       spec.width_ = static_cast<int>(value);
1221     }
1222 
1223     // Parse precision.
1224     if (*s == '.') {
1225       ++s;
1226       spec.precision_ = 0;
1227       if ('0' <= *s && *s <= '9') {
1228         spec.precision_ = parse_nonnegative_int(s);
1229       } else if (*s == '{') {
1230         ++s;
1231         Arg precision_arg =
1232             is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
1233         if (*s++ != '}')
1234           FMT_THROW(FormatError("invalid format string"));
1235         ULongLong value = 0;
1236         switch (precision_arg.type) {
1237           case Arg::INT:
1238             if (precision_arg.int_value < 0)
1239               FMT_THROW(FormatError("negative precision"));
1240             value = precision_arg.int_value;
1241             break;
1242           case Arg::UINT:
1243             value = precision_arg.uint_value;
1244             break;
1245           case Arg::LONG_LONG:
1246             if (precision_arg.long_long_value < 0)
1247               FMT_THROW(FormatError("negative precision"));
1248             value = precision_arg.long_long_value;
1249             break;
1250           case Arg::ULONG_LONG:
1251             value = precision_arg.ulong_long_value;
1252             break;
1253           default:
1254             FMT_THROW(FormatError("precision is not integer"));
1255         }
1256         if (value > INT_MAX)
1257           FMT_THROW(FormatError("number is too big"));
1258         spec.precision_ = static_cast<int>(value);
1259       } else {
1260         FMT_THROW(FormatError("missing precision specifier"));
1261       }
1262       if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
1263         FMT_THROW(FormatError(
1264             clmdep_fmt::format("precision not allowed in {} format specifier",
1265             arg.type == Arg::POINTER ? "pointer" : "integer")));
1266       }
1267     }
1268 
1269     // Parse type.
1270     if (*s != '}' && *s)
1271       spec.type_ = static_cast<char>(*s++);
1272   }
1273 
1274   if (*s++ != '}')
1275     FMT_THROW(FormatError("missing '}' in format string"));
1276 
1277   // Format argument.
1278   internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
1279   return s;
1280 }
1281 
1282 template <typename Char>
format(BasicCStringRef<Char> format_str)1283 void clmdep_fmt::BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) {
1284   const Char *s = format_str.c_str();
1285   const Char *start = s;
1286   while (*s) {
1287     Char c = *s++;
1288     if (c != '{' && c != '}') continue;
1289     if (*s == c) {
1290       write(writer_, start, s);
1291       start = ++s;
1292       continue;
1293     }
1294     if (c == '}')
1295       FMT_THROW(FormatError("unmatched '}' in format string"));
1296     write(writer_, start, s - 1);
1297     Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
1298     start = s = format(s, arg);
1299   }
1300   write(writer_, start, s);
1301 }
1302 
report_system_error(int error_code,clmdep_fmt::StringRef message)1303 FMT_FUNC void clmdep_fmt::report_system_error(
1304     int error_code, clmdep_fmt::StringRef message) FMT_NOEXCEPT {
1305   // 'clmdep_fmt::' is for bcc32.
1306   clmdep_fmt::report_error(internal::format_system_error, error_code, message);
1307 }
1308 
1309 #if FMT_USE_WINDOWS_H
report_windows_error(int error_code,clmdep_fmt::StringRef message)1310 FMT_FUNC void clmdep_fmt::report_windows_error(
1311     int error_code, clmdep_fmt::StringRef message) FMT_NOEXCEPT {
1312   // 'clmdep_fmt::' is for bcc32.
1313   clmdep_fmt::report_error(internal::format_windows_error, error_code, message);
1314 }
1315 #endif
1316 
print(std::FILE * f,CStringRef format_str,ArgList args)1317 FMT_FUNC void clmdep_fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
1318   MemoryWriter w;
1319   w.write(format_str, args);
1320   std::fwrite(w.data(), 1, w.size(), f);
1321 }
1322 
print(CStringRef format_str,ArgList args)1323 FMT_FUNC void clmdep_fmt::print(CStringRef format_str, ArgList args) {
1324   print(stdout, format_str, args);
1325 }
1326 
print(std::ostream & os,CStringRef format_str,ArgList args)1327 FMT_FUNC void clmdep_fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
1328   MemoryWriter w;
1329   w.write(format_str, args);
1330   os.write(w.data(), w.size());
1331 }
1332 
print_colored(Color c,CStringRef format,ArgList args)1333 FMT_FUNC void clmdep_fmt::print_colored(Color c, CStringRef format, ArgList args) {
1334   char escape[] = "\x1b[30m";
1335   escape[3] = static_cast<char>('0' + c);
1336   std::fputs(escape, stdout);
1337   print(format, args);
1338   std::fputs(RESET_COLOR, stdout);
1339 }
1340 
fprintf(std::FILE * f,CStringRef format,ArgList args)1341 FMT_FUNC int clmdep_fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
1342   MemoryWriter w;
1343   printf(w, format, args);
1344   std::size_t size = w.size();
1345   return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
1346 }
1347 
1348 #ifndef FMT_HEADER_ONLY
1349 
1350 template struct clmdep_fmt::internal::BasicData<void>;
1351 
1352 // Explicit instantiations for char.
1353 
1354 template void clmdep_fmt::internal::FixedBuffer<char>::grow(std::size_t);
1355 
1356 template const char *clmdep_fmt::BasicFormatter<char>::format(
1357     const char *&format_str, const clmdep_fmt::internal::Arg &arg);
1358 
1359 template void clmdep_fmt::BasicFormatter<char>::format(CStringRef format);
1360 
1361 template void clmdep_fmt::internal::PrintfFormatter<char>::format(
1362   BasicWriter<char> &writer, CStringRef format);
1363 
1364 template int clmdep_fmt::internal::CharTraits<char>::format_float(
1365     char *buffer, std::size_t size, const char *format,
1366     unsigned width, int precision, double value);
1367 
1368 template int clmdep_fmt::internal::CharTraits<char>::format_float(
1369     char *buffer, std::size_t size, const char *format,
1370     unsigned width, int precision, long double value);
1371 
1372 // Explicit instantiations for wchar_t.
1373 
1374 template void clmdep_fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1375 
1376 template const wchar_t *clmdep_fmt::BasicFormatter<wchar_t>::format(
1377     const wchar_t *&format_str, const clmdep_fmt::internal::Arg &arg);
1378 
1379 template void clmdep_fmt::BasicFormatter<wchar_t>::format(
1380     BasicCStringRef<wchar_t> format);
1381 
1382 template void clmdep_fmt::internal::PrintfFormatter<wchar_t>::format(
1383     BasicWriter<wchar_t> &writer, WCStringRef format);
1384 
1385 template int clmdep_fmt::internal::CharTraits<wchar_t>::format_float(
1386     wchar_t *buffer, std::size_t size, const wchar_t *format,
1387     unsigned width, int precision, double value);
1388 
1389 template int clmdep_fmt::internal::CharTraits<wchar_t>::format_float(
1390     wchar_t *buffer, std::size_t size, const wchar_t *format,
1391     unsigned width, int precision, long double value);
1392 
1393 #endif  // FMT_HEADER_ONLY
1394 
1395 #ifdef _MSC_VER
1396 # pragma warning(pop)
1397 #endif
1398 
1399 #ifdef __clang__
1400 #pragma clang diagnostic pop
1401 #endif
1402