1 /*
2 Formatting library for C++
3
4 Copyright (c) 2012 - 2016, 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 #include "mp/format.h"
29
30 #include <string.h>
31
32 #include <cctype>
33 #include <cerrno>
34 #include <climits>
35 #include <cmath>
36 #include <cstdarg>
37 #include <cstddef> // for std::ptrdiff_t
38
39 #if defined(_WIN32) && defined(__MINGW32__)
40 # include <cstring>
41 #endif
42
43 #if FMT_USE_WINDOWS_H
44 # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
45 # include <windows.h>
46 # else
47 # define NOMINMAX
48 # include <windows.h>
49 # undef NOMINMAX
50 # endif
51 #endif
52
53 using fmt::internal::Arg;
54
55 #if FMT_EXCEPTIONS
56 # define FMT_TRY try
57 # define FMT_CATCH(x) catch (x)
58 #else
59 # define FMT_TRY if (true)
60 # define FMT_CATCH(x) if (false)
61 #endif
62
63 #ifdef _MSC_VER
64 # pragma warning(push)
65 # pragma warning(disable: 4127) // conditional expression is constant
66 # pragma warning(disable: 4702) // unreachable code
67 // Disable deprecation warning for strerror. The latter is not called but
68 // MSVC fails to detect it.
69 # pragma warning(disable: 4996)
70 #endif
71
72 // Dummy implementations of strerror_r and strerror_s called if corresponding
73 // system functions are not available.
74 static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
75 return fmt::internal::Null<>();
76 }
77 static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
78 return fmt::internal::Null<>();
79 }
80
81 namespace fmt {
82
83 FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {}
84 FMT_FUNC FormatError::~FormatError() throw() {}
85 FMT_FUNC SystemError::~SystemError() throw() {}
86
87 namespace {
88
89 #ifndef _MSC_VER
90 # define FMT_SNPRINTF snprintf
91 #else // _MSC_VER
92 inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
93 va_list args;
94 va_start(args, format);
95 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
96 va_end(args);
97 return result;
98 }
99 # define FMT_SNPRINTF fmt_snprintf
100 #endif // _MSC_VER
101
102 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
103 # define FMT_SWPRINTF snwprintf
104 #else
105 # define FMT_SWPRINTF swprintf
106 #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
107
108 // Checks if a value fits in int - used to avoid warnings about comparing
109 // signed and unsigned integers.
110 template <bool IsSigned>
111 struct IntChecker {
112 template <typename T>
113 static bool fits_in_int(T value) {
114 unsigned max = INT_MAX;
115 return value <= max;
116 }
117 static bool fits_in_int(bool) { return true; }
118 };
119
120 template <>
121 struct IntChecker<true> {
122 template <typename T>
123 static bool fits_in_int(T value) {
124 return value >= INT_MIN && value <= INT_MAX;
125 }
126 static bool fits_in_int(int) { return true; }
127 };
128
129 const char RESET_COLOR[] = "\x1b[0m";
130
131 typedef void (*FormatFunc)(Writer &, int, StringRef);
132
133 // Portable thread-safe version of strerror.
134 // Sets buffer to point to a string describing the error code.
135 // This can be either a pointer to a string stored in buffer,
136 // or a pointer to some static immutable string.
137 // Returns one of the following values:
138 // 0 - success
139 // ERANGE - buffer is not large enough to store the error message
140 // other - failure
141 // Buffer should be at least of size 1.
142 int safe_strerror(
143 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
144 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
145
146 class StrError {
147 private:
148 int error_code_;
149 char *&buffer_;
150 std::size_t buffer_size_;
151
152 // A noop assignment operator to avoid bogus warnings.
153 void operator=(const StrError &) {}
154
155 // Handle the result of XSI-compliant version of strerror_r.
156 int handle(int result) {
157 // glibc versions before 2.13 return result in errno.
158 return result == -1 ? errno : result;
159 }
160
161 // Handle the result of GNU-specific version of strerror_r.
162 int handle(char *message) {
163 // If the buffer is full then the message is probably truncated.
164 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
165 return ERANGE;
166 buffer_ = message;
167 return 0;
168 }
169
170 // Handle the case when strerror_r is not available.
171 int handle(internal::Null<>) {
172 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
173 }
174
175 // Fallback to strerror_s when strerror_r is not available.
176 int fallback(int result) {
177 // If the buffer is full then the message is probably truncated.
178 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
179 ERANGE : result;
180 }
181
182 // Fallback to strerror if strerror_r and strerror_s are not available.
183 int fallback(internal::Null<>) {
184 errno = 0;
185 buffer_ = strerror(error_code_);
186 return errno;
187 }
188
189 public:
190 StrError(int err_code, char *&buf, std::size_t buf_size)
191 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
192
193 int run() {
194 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
195 return handle(strerror_r(error_code_, buffer_, buffer_size_));
196 }
197 };
198 return StrError(error_code, buffer, buffer_size).run();
199 }
200
201 void format_error_code(Writer &out, int error_code,
202 StringRef message) FMT_NOEXCEPT {
203 // Report error code making sure that the output fits into
204 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
205 // bad_alloc.
206 out.clear();
207 static const char SEP[] = ": ";
208 static const char ERROR_STR[] = "error ";
209 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
210 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
211 typedef internal::IntTraits<int>::MainType MainType;
212 MainType abs_value = static_cast<MainType>(error_code);
213 if (internal::is_negative(error_code)) {
214 abs_value = 0 - abs_value;
215 ++error_code_size;
216 }
217 error_code_size += internal::count_digits(abs_value);
218 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
219 out << message << SEP;
220 out << ERROR_STR << error_code;
221 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
222 }
223
224 void report_error(FormatFunc func, int error_code,
225 StringRef message) FMT_NOEXCEPT {
226 MemoryWriter full_message;
227 func(full_message, error_code, message);
228 // Use Writer::data instead of Writer::c_str to avoid potential memory
229 // allocation.
230 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
231 std::fputc('\n', stderr);
232 }
233
234 // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
235 class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
236 public:
237 template <typename T>
238 bool visit_any_int(T value) { return value == 0; }
239 };
240
241 // Checks if an argument is a valid printf width specifier and sets
242 // left alignment if it is negative.
243 class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
244 private:
245 FormatSpec &spec_;
246
247 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
248
249 public:
250 explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
251
252 void report_unhandled_arg() {
253 FMT_THROW(FormatError("width is not integer"));
254 }
255
256 template <typename T>
257 unsigned visit_any_int(T value) {
258 typedef typename internal::IntTraits<T>::MainType UnsignedType;
259 UnsignedType width = static_cast<UnsignedType>(value);
260 if (internal::is_negative(value)) {
261 spec_.align_ = ALIGN_LEFT;
262 width = 0 - width;
263 }
264 if (width > INT_MAX)
265 FMT_THROW(FormatError("number is too big"));
266 return static_cast<unsigned>(width);
267 }
268 };
269
270 class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
271 public:
272 void report_unhandled_arg() {
273 FMT_THROW(FormatError("precision is not integer"));
274 }
275
276 template <typename T>
277 int visit_any_int(T value) {
278 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
279 FMT_THROW(FormatError("number is too big"));
280 return static_cast<int>(value);
281 }
282 };
283
284 template <typename T, typename U>
285 struct is_same {
286 enum { value = 0 };
287 };
288
289 template <typename T>
290 struct is_same<T, T> {
291 enum { value = 1 };
292 };
293
294 // An argument visitor that converts an integer argument to T for printf,
295 // if T is an integral type. If T is void, the argument is converted to
296 // corresponding signed or unsigned type depending on the type specifier:
297 // 'd' and 'i' - signed, other - unsigned)
298 template <typename T = void>
299 class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
300 private:
301 internal::Arg &arg_;
302 wchar_t type_;
303
304 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
305
306 public:
307 ArgConverter(internal::Arg &arg, wchar_t type)
308 : arg_(arg), type_(type) {}
309
310 void visit_bool(bool value) {
311 if (type_ != 's')
312 visit_any_int(value);
313 }
314
315 template <typename U>
316 void visit_any_int(U value) {
317 bool is_signed = type_ == 'd' || type_ == 'i';
318 using internal::Arg;
319 typedef typename internal::Conditional<
320 is_same<T, void>::value, U, T>::type TargetType;
321 if (sizeof(TargetType) <= sizeof(int)) {
322 // Extra casts are used to silence warnings.
323 if (is_signed) {
324 arg_.type = Arg::INT;
325 arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
326 } else {
327 arg_.type = Arg::UINT;
328 typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
329 arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
330 }
331 } else {
332 if (is_signed) {
333 arg_.type = Arg::LONG_LONG;
334 // glibc's printf doesn't sign extend arguments of smaller types:
335 // std::printf("%lld", -42); // prints "4294967254"
336 // but we don't have to do the same because it's a UB.
337 arg_.long_long_value = static_cast<LongLong>(value);
338 } else {
339 arg_.type = Arg::ULONG_LONG;
340 arg_.ulong_long_value =
341 static_cast<typename internal::MakeUnsigned<U>::Type>(value);
342 }
343 }
344 }
345 };
346
347 // Converts an integer argument to char for printf.
348 class CharConverter : public ArgVisitor<CharConverter, void> {
349 private:
350 internal::Arg &arg_;
351
352 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
353
354 public:
355 explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
356
357 template <typename T>
358 void visit_any_int(T value) {
359 arg_.type = internal::Arg::CHAR;
360 arg_.int_value = static_cast<char>(value);
361 }
362 };
363 } // namespace
364
365 namespace internal {
366
367 template <typename Char>
368 class PrintfArgFormatter :
369 public ArgFormatterBase<PrintfArgFormatter<Char>, Char> {
370
371 void write_null_pointer() {
372 this->spec().type_ = 0;
373 this->write("(nil)");
374 }
375
376 typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base;
377
378 public:
379 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
380 : ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {}
381
382 void visit_bool(bool value) {
383 FormatSpec &fmt_spec = this->spec();
384 if (fmt_spec.type_ != 's')
385 return this->visit_any_int(value);
386 fmt_spec.type_ = 0;
387 this->write(value);
388 }
389
390 void visit_char(int value) {
391 const FormatSpec &fmt_spec = this->spec();
392 BasicWriter<Char> &w = this->writer();
393 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
394 w.write_int(value, fmt_spec);
395 typedef typename BasicWriter<Char>::CharPtr CharPtr;
396 CharPtr out = CharPtr();
397 if (fmt_spec.width_ > 1) {
398 Char fill = ' ';
399 out = w.grow_buffer(fmt_spec.width_);
400 if (fmt_spec.align_ != ALIGN_LEFT) {
401 std::fill_n(out, fmt_spec.width_ - 1, fill);
402 out += fmt_spec.width_ - 1;
403 } else {
404 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
405 }
406 } else {
407 out = w.grow_buffer(1);
408 }
409 *out = static_cast<Char>(value);
410 }
411
412 void visit_cstring(const char *value) {
413 if (value)
414 Base::visit_cstring(value);
415 else if (this->spec().type_ == 'p')
416 write_null_pointer();
417 else
418 this->write("(null)");
419 }
420
421 void visit_pointer(const void *value) {
422 if (value)
423 return Base::visit_pointer(value);
424 this->spec().type_ = 0;
425 write_null_pointer();
426 }
427
428 void visit_custom(Arg::CustomValue c) {
429 BasicFormatter<Char> formatter(ArgList(), this->writer());
430 const Char format_str[] = {'}', 0};
431 const Char *format = format_str;
432 c.format(&formatter, c.value, &format);
433 }
434 };
435 } // namespace internal
436 } // namespace fmt
437
438 FMT_FUNC void fmt::SystemError::init(
439 int err_code, CStringRef format_str, ArgList args) {
440 error_code_ = err_code;
441 MemoryWriter w;
442 internal::format_system_error(w, err_code, format(format_str, args));
443 std::runtime_error &base = *this;
444 base = std::runtime_error(w.str());
445 }
446
447 template <typename T>
448 int fmt::internal::CharTraits<char>::format_float(
449 char *buffer, std::size_t size, const char *format,
450 unsigned width, int precision, T value) {
451 if (width == 0) {
452 return precision < 0 ?
453 FMT_SNPRINTF(buffer, size, format, value) :
454 FMT_SNPRINTF(buffer, size, format, precision, value);
455 }
456 return precision < 0 ?
457 FMT_SNPRINTF(buffer, size, format, width, value) :
458 FMT_SNPRINTF(buffer, size, format, width, precision, value);
459 }
460
461 template <typename T>
462 int fmt::internal::CharTraits<wchar_t>::format_float(
463 wchar_t *buffer, std::size_t size, const wchar_t *format,
464 unsigned width, int precision, T value) {
465 if (width == 0) {
466 return precision < 0 ?
467 FMT_SWPRINTF(buffer, size, format, value) :
468 FMT_SWPRINTF(buffer, size, format, precision, value);
469 }
470 return precision < 0 ?
471 FMT_SWPRINTF(buffer, size, format, width, value) :
472 FMT_SWPRINTF(buffer, size, format, width, precision, value);
473 }
474
475 template <typename T>
476 const char fmt::internal::BasicData<T>::DIGITS[] =
477 "0001020304050607080910111213141516171819"
478 "2021222324252627282930313233343536373839"
479 "4041424344454647484950515253545556575859"
480 "6061626364656667686970717273747576777879"
481 "8081828384858687888990919293949596979899";
482
483 #define FMT_POWERS_OF_10(factor) \
484 factor * 10, \
485 factor * 100, \
486 factor * 1000, \
487 factor * 10000, \
488 factor * 100000, \
489 factor * 1000000, \
490 factor * 10000000, \
491 factor * 100000000, \
492 factor * 1000000000
493
494 template <typename T>
495 const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
496 0, FMT_POWERS_OF_10(1)
497 };
498
499 template <typename T>
500 const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
501 0,
502 FMT_POWERS_OF_10(1),
503 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
504 // Multiply several constants instead of using a single long long constant
505 // to avoid warnings about C++98 not supporting long long.
506 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
507 };
508
509 FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
510 (void)type;
511 if (std::isprint(static_cast<unsigned char>(code))) {
512 FMT_THROW(fmt::FormatError(
513 fmt::format("unknown format code '{}' for {}", code, type)));
514 }
515 FMT_THROW(fmt::FormatError(
516 fmt::format("unknown format code '\\x{:02x}' for {}",
517 static_cast<unsigned>(code), type)));
518 }
519
520 #if FMT_USE_WINDOWS_H
521
522 FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
523 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
524 if (s.size() > INT_MAX)
525 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
526 int s_size = static_cast<int>(s.size());
527 int length = MultiByteToWideChar(
528 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
529 if (length == 0)
530 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
531 buffer_.resize(length + 1);
532 length = MultiByteToWideChar(
533 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
534 if (length == 0)
535 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
536 buffer_[length] = 0;
537 }
538
539 FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
540 if (int error_code = convert(s)) {
541 FMT_THROW(WindowsError(error_code,
542 "cannot convert string from UTF-16 to UTF-8"));
543 }
544 }
545
546 FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
547 if (s.size() > INT_MAX)
548 return ERROR_INVALID_PARAMETER;
549 int s_size = static_cast<int>(s.size());
550 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
551 if (length == 0)
552 return GetLastError();
553 buffer_.resize(length + 1);
554 length = WideCharToMultiByte(
555 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
556 if (length == 0)
557 return GetLastError();
558 buffer_[length] = 0;
559 return 0;
560 }
561
562 FMT_FUNC void fmt::WindowsError::init(
563 int err_code, CStringRef format_str, ArgList args) {
564 error_code_ = err_code;
565 MemoryWriter w;
566 internal::format_windows_error(w, err_code, format(format_str, args));
567 std::runtime_error &base = *this;
568 base = std::runtime_error(w.str());
569 }
570
571 FMT_FUNC void fmt::internal::format_windows_error(
572 fmt::Writer &out, int error_code,
573 fmt::StringRef message) FMT_NOEXCEPT {
574 FMT_TRY {
575 MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
576 buffer.resize(INLINE_BUFFER_SIZE);
577 for (;;) {
578 wchar_t *system_message = &buffer[0];
579 int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
580 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
581 system_message, static_cast<uint32_t>(buffer.size()), 0);
582 if (result != 0) {
583 UTF16ToUTF8 utf8_message;
584 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
585 out << message << ": " << utf8_message;
586 return;
587 }
588 break;
589 }
590 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
591 break; // Can't get error message, report error code instead.
592 buffer.resize(buffer.size() * 2);
593 }
594 } FMT_CATCH(...) {}
595 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
596 }
597
598 #endif // FMT_USE_WINDOWS_H
599
600 FMT_FUNC void fmt::internal::format_system_error(
601 fmt::Writer &out, int error_code,
602 fmt::StringRef message) FMT_NOEXCEPT {
603 FMT_TRY {
604 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
605 buffer.resize(INLINE_BUFFER_SIZE);
606 for (;;) {
607 char *system_message = &buffer[0];
608 int result = safe_strerror(error_code, system_message, buffer.size());
609 if (result == 0) {
610 out << message << ": " << system_message;
611 return;
612 }
613 if (result != ERANGE)
614 break; // Can't get error message, report error code instead.
615 buffer.resize(buffer.size() * 2);
616 }
617 } FMT_CATCH(...) {}
618 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
619 }
620
621 template <typename Char>
622 void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
623 if (!map_.empty())
624 return;
625 typedef internal::NamedArg<Char> NamedArg;
626 const NamedArg *named_arg = 0;
627 bool use_values =
628 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
629 if (use_values) {
630 for (unsigned i = 0;/*nothing*/; ++i) {
631 internal::Arg::Type arg_type = args.type(i);
632 switch (arg_type) {
633 case internal::Arg::NONE:
634 return;
635 case internal::Arg::NAMED_ARG:
636 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
637 map_.push_back(Pair(named_arg->name, *named_arg));
638 break;
639 default:
640 /*nothing*/;
641 }
642 }
643 return;
644 }
645 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
646 internal::Arg::Type arg_type = args.type(i);
647 if (arg_type == internal::Arg::NAMED_ARG) {
648 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
649 map_.push_back(Pair(named_arg->name, *named_arg));
650 }
651 }
652 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
653 switch (args.args_[i].type) {
654 case internal::Arg::NONE:
655 return;
656 case internal::Arg::NAMED_ARG:
657 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
658 map_.push_back(Pair(named_arg->name, *named_arg));
659 break;
660 default:
661 /*nothing*/;
662 }
663 }
664 }
665
666 template <typename Char>
667 void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
668 FMT_THROW(std::runtime_error("buffer overflow"));
669 }
670
671 FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
672 unsigned arg_index, const char *&error) {
673 Arg arg = args_[arg_index];
674 switch (arg.type) {
675 case Arg::NONE:
676 error = "argument index out of range";
677 break;
678 case Arg::NAMED_ARG:
679 arg = *static_cast<const internal::Arg*>(arg.pointer);
680 break;
681 default:
682 /*nothing*/;
683 }
684 return arg;
685 }
686
687 template <typename Char>
688 void fmt::internal::PrintfFormatter<Char>::parse_flags(
689 FormatSpec &spec, const Char *&s) {
690 for (;;) {
691 switch (*s++) {
692 case '-':
693 spec.align_ = ALIGN_LEFT;
694 break;
695 case '+':
696 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
697 break;
698 case '0':
699 spec.fill_ = '0';
700 break;
701 case ' ':
702 spec.flags_ |= SIGN_FLAG;
703 break;
704 case '#':
705 spec.flags_ |= HASH_FLAG;
706 break;
707 default:
708 --s;
709 return;
710 }
711 }
712 }
713
714 template <typename Char>
715 Arg fmt::internal::PrintfFormatter<Char>::get_arg(
716 const Char *s, unsigned arg_index) {
717 (void)s;
718 const char *error = 0;
719 Arg arg = arg_index == UINT_MAX ?
720 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
721 if (error)
722 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
723 return arg;
724 }
725
726 template <typename Char>
727 unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
728 const Char *&s, FormatSpec &spec) {
729 unsigned arg_index = UINT_MAX;
730 Char c = *s;
731 if (c >= '0' && c <= '9') {
732 // Parse an argument index (if followed by '$') or a width possibly
733 // preceded with '0' flag(s).
734 unsigned value = parse_nonnegative_int(s);
735 if (*s == '$') { // value is an argument index
736 ++s;
737 arg_index = value;
738 } else {
739 if (c == '0')
740 spec.fill_ = '0';
741 if (value != 0) {
742 // Nonzero value means that we parsed width and don't need to
743 // parse it or flags again, so return now.
744 spec.width_ = value;
745 return arg_index;
746 }
747 }
748 }
749 parse_flags(spec, s);
750 // Parse width.
751 if (*s >= '0' && *s <= '9') {
752 spec.width_ = parse_nonnegative_int(s);
753 } else if (*s == '*') {
754 ++s;
755 spec.width_ = WidthHandler(spec).visit(get_arg(s));
756 }
757 return arg_index;
758 }
759
760 template <typename Char>
761 void fmt::internal::PrintfFormatter<Char>::format(
762 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
763 const Char *start = format_str.c_str();
764 const Char *s = start;
765 while (*s) {
766 Char c = *s++;
767 if (c != '%') continue;
768 if (*s == c) {
769 write(writer, start, s);
770 start = ++s;
771 continue;
772 }
773 write(writer, start, s - 1);
774
775 FormatSpec spec;
776 spec.align_ = ALIGN_RIGHT;
777
778 // Parse argument index, flags and width.
779 unsigned arg_index = parse_header(s, spec);
780
781 // Parse precision.
782 if (*s == '.') {
783 ++s;
784 if ('0' <= *s && *s <= '9') {
785 spec.precision_ = static_cast<int>(parse_nonnegative_int(s));
786 } else if (*s == '*') {
787 ++s;
788 spec.precision_ = PrecisionHandler().visit(get_arg(s));
789 }
790 }
791
792 Arg arg = get_arg(s, arg_index);
793 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
794 spec.flags_ &= ~to_unsigned<int>(HASH_FLAG);
795 if (spec.fill_ == '0') {
796 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
797 spec.align_ = ALIGN_NUMERIC;
798 else
799 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
800 }
801
802 // Parse length and convert the argument to the required type.
803 switch (*s++) {
804 case 'h':
805 if (*s == 'h')
806 ArgConverter<signed char>(arg, *++s).visit(arg);
807 else
808 ArgConverter<short>(arg, *s).visit(arg);
809 break;
810 case 'l':
811 if (*s == 'l')
812 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
813 else
814 ArgConverter<long>(arg, *s).visit(arg);
815 break;
816 case 'j':
817 ArgConverter<intmax_t>(arg, *s).visit(arg);
818 break;
819 case 'z':
820 ArgConverter<std::size_t>(arg, *s).visit(arg);
821 break;
822 case 't':
823 ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
824 break;
825 case 'L':
826 // printf produces garbage when 'L' is omitted for long double, no
827 // need to do the same.
828 break;
829 default:
830 --s;
831 ArgConverter<void>(arg, *s).visit(arg);
832 }
833
834 // Parse type.
835 if (!*s)
836 FMT_THROW(FormatError("invalid format string"));
837 spec.type_ = static_cast<char>(*s++);
838 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
839 // Normalize type.
840 switch (spec.type_) {
841 case 'i': case 'u':
842 spec.type_ = 'd';
843 break;
844 case 'c':
845 // TODO: handle wchar_t
846 CharConverter(arg).visit(arg);
847 break;
848 }
849 }
850
851 start = s;
852
853 // Format argument.
854 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
855 }
856 write(writer, start, s);
857 }
858
859 FMT_FUNC void fmt::report_system_error(
860 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
861 // 'fmt::' is for bcc32.
862 fmt::report_error(internal::format_system_error, error_code, message);
863 }
864
865 #if FMT_USE_WINDOWS_H
866 FMT_FUNC void fmt::report_windows_error(
867 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
868 // 'fmt::' is for bcc32.
869 fmt::report_error(internal::format_windows_error, error_code, message);
870 }
871 #endif
872
873 FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
874 MemoryWriter w;
875 w.write(format_str, args);
876 std::fwrite(w.data(), 1, w.size(), f);
877 }
878
879 FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
880 print(stdout, format_str, args);
881 }
882
883 FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
884 char escape[] = "\x1b[30m";
885 escape[3] = static_cast<char>('0' + c);
886 std::fputs(escape, stdout);
887 print(format, args);
888 std::fputs(RESET_COLOR, stdout);
889 }
890
891 FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
892 MemoryWriter w;
893 printf(w, format, args);
894 std::size_t size = w.size();
895 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
896 }
897
898 #ifndef FMT_HEADER_ONLY
899
900 template struct fmt::internal::BasicData<void>;
901
902 // Explicit instantiations for char.
903
904 template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
905
906 template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
907
908 template void fmt::internal::PrintfFormatter<char>::format(
909 BasicWriter<char> &writer, CStringRef format);
910
911 template int fmt::internal::CharTraits<char>::format_float(
912 char *buffer, std::size_t size, const char *format,
913 unsigned width, int precision, double value);
914
915 template int fmt::internal::CharTraits<char>::format_float(
916 char *buffer, std::size_t size, const char *format,
917 unsigned width, int precision, long double value);
918
919 // Explicit instantiations for wchar_t.
920
921 template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
922
923 template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
924
925 template void fmt::internal::PrintfFormatter<wchar_t>::format(
926 BasicWriter<wchar_t> &writer, WCStringRef format);
927
928 template int fmt::internal::CharTraits<wchar_t>::format_float(
929 wchar_t *buffer, std::size_t size, const wchar_t *format,
930 unsigned width, int precision, double value);
931
932 template int fmt::internal::CharTraits<wchar_t>::format_float(
933 wchar_t *buffer, std::size_t size, const wchar_t *format,
934 unsigned width, int precision, long double value);
935
936 #endif // FMT_HEADER_ONLY
937
938 #ifdef _MSC_VER
939 # pragma warning(pop)
940 #endif
941