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