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