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