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