comparison extern/cppformat/format.cc @ 104:be4b9ed19a17

Irccd: import cppformat, #483
author David Demelier <markand@malikania.fr>
date Tue, 26 Apr 2016 22:09:02 +0200
parents
children
comparison
equal deleted inserted replaced
103:04d672ab41a4 104:be4b9ed19a17
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 // Check if exceptions are disabled.
56 #if defined(__GNUC__) && !defined(__EXCEPTIONS)
57 # define FMT_EXCEPTIONS 0
58 #endif
59 #if defined(_MSC_VER) && !_HAS_EXCEPTIONS
60 # define FMT_EXCEPTIONS 0
61 #endif
62 #ifndef FMT_EXCEPTIONS
63 # define FMT_EXCEPTIONS 1
64 #endif
65
66 #if FMT_EXCEPTIONS
67 # define FMT_TRY try
68 # define FMT_CATCH(x) catch (x)
69 #else
70 # define FMT_TRY if (true)
71 # define FMT_CATCH(x) if (false)
72 #endif
73
74 #ifndef FMT_THROW
75 # if FMT_EXCEPTIONS
76 # define FMT_THROW(x) throw x
77 # else
78 # define FMT_THROW(x) assert(false)
79 # endif
80 #endif
81
82 #ifdef FMT_HEADER_ONLY
83 # define FMT_FUNC inline
84 #else
85 # define FMT_FUNC
86 #endif
87
88 #ifdef _MSC_VER
89 # pragma warning(push)
90 # pragma warning(disable: 4127) // conditional expression is constant
91 # pragma warning(disable: 4702) // unreachable code
92 // Disable deprecation warning for strerror. The latter is not called but
93 // MSVC fails to detect it.
94 # pragma warning(disable: 4996)
95 #endif
96
97 // Dummy implementations of strerror_r and strerror_s called if corresponding
98 // system functions are not available.
99 static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
100 return fmt::internal::Null<>();
101 }
102 static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
103 return fmt::internal::Null<>();
104 }
105
106 namespace fmt {
107 namespace {
108
109 #ifndef _MSC_VER
110 # define FMT_SNPRINTF snprintf
111 #else // _MSC_VER
112 inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
113 va_list args;
114 va_start(args, format);
115 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
116 va_end(args);
117 return result;
118 }
119 # define FMT_SNPRINTF fmt_snprintf
120 #endif // _MSC_VER
121
122 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
123 # define FMT_SWPRINTF snwprintf
124 #else
125 # define FMT_SWPRINTF swprintf
126 #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
127
128 // Checks if a value fits in int - used to avoid warnings about comparing
129 // signed and unsigned integers.
130 template <bool IsSigned>
131 struct IntChecker {
132 template <typename T>
133 static bool fits_in_int(T value) {
134 unsigned max = INT_MAX;
135 return value <= max;
136 }
137 static bool fits_in_int(bool) { return true; }
138 };
139
140 template <>
141 struct IntChecker<true> {
142 template <typename T>
143 static bool fits_in_int(T value) {
144 return value >= INT_MIN && value <= INT_MAX;
145 }
146 static bool fits_in_int(int) { return true; }
147 };
148
149 const char RESET_COLOR[] = "\x1b[0m";
150
151 typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
152
153 // Portable thread-safe version of strerror.
154 // Sets buffer to point to a string describing the error code.
155 // This can be either a pointer to a string stored in buffer,
156 // or a pointer to some static immutable string.
157 // Returns one of the following values:
158 // 0 - success
159 // ERANGE - buffer is not large enough to store the error message
160 // other - failure
161 // Buffer should be at least of size 1.
162 int safe_strerror(
163 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
164 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
165
166 class StrError {
167 private:
168 int error_code_;
169 char *&buffer_;
170 std::size_t buffer_size_;
171
172 // A noop assignment operator to avoid bogus warnings.
173 void operator=(const StrError &) {}
174
175 // Handle the result of XSI-compliant version of strerror_r.
176 int handle(int result) {
177 // glibc versions before 2.13 return result in errno.
178 return result == -1 ? errno : result;
179 }
180
181 // Handle the result of GNU-specific version of strerror_r.
182 int handle(char *message) {
183 // If the buffer is full then the message is probably truncated.
184 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
185 return ERANGE;
186 buffer_ = message;
187 return 0;
188 }
189
190 // Handle the case when strerror_r is not available.
191 int handle(fmt::internal::Null<>) {
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 // If the buffer is full then the message is probably truncated.
198 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
199 ERANGE : result;
200 }
201
202 // Fallback to strerror if strerror_r and strerror_s are not available.
203 int fallback(fmt::internal::Null<>) {
204 errno = 0;
205 buffer_ = strerror(error_code_);
206 return errno;
207 }
208
209 public:
210 StrError(int err_code, char *&buf, std::size_t buf_size)
211 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
212
213 int run() {
214 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
215 return handle(strerror_r(error_code_, buffer_, buffer_size_));
216 }
217 };
218 return StrError(error_code, buffer, buffer_size).run();
219 }
220
221 void format_error_code(fmt::Writer &out, int error_code,
222 fmt::StringRef message) FMT_NOEXCEPT {
223 // Report error code making sure that the output fits into
224 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
225 // bad_alloc.
226 out.clear();
227 static const char SEP[] = ": ";
228 static const char ERROR_STR[] = "error ";
229 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
230 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
231 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
232 error_code_size += fmt::internal::count_digits(ec_value);
233 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
234 out << message << SEP;
235 out << ERROR_STR << error_code;
236 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
237 }
238
239 void report_error(FormatFunc func,
240 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
241 fmt::MemoryWriter full_message;
242 func(full_message, error_code, message);
243 // Use Writer::data instead of Writer::c_str to avoid potential memory
244 // allocation.
245 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
246 std::fputc('\n', stderr);
247 }
248
249 // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
250 class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
251 public:
252 template <typename T>
253 bool visit_any_int(T value) { return value == 0; }
254 };
255
256 // Parses an unsigned integer advancing s to the end of the parsed input.
257 // This function assumes that the first character of s is a digit.
258 template <typename Char>
259 int parse_nonnegative_int(const Char *&s) {
260 assert('0' <= *s && *s <= '9');
261 unsigned value = 0;
262 do {
263 unsigned new_value = value * 10 + (*s++ - '0');
264 // Check if value wrapped around.
265 if (new_value < value) {
266 value = UINT_MAX;
267 break;
268 }
269 value = new_value;
270 } while ('0' <= *s && *s <= '9');
271 if (value > INT_MAX)
272 FMT_THROW(fmt::FormatError("number is too big"));
273 return value;
274 }
275
276 template <typename Char>
277 inline bool is_name_start(Char c) {
278 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
279 }
280
281 inline void require_numeric_argument(const Arg &arg, char spec) {
282 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
283 std::string message =
284 fmt::format("format specifier '{}' requires numeric argument", spec);
285 FMT_THROW(fmt::FormatError(message));
286 }
287 }
288
289 template <typename Char>
290 void check_sign(const Char *&s, const Arg &arg) {
291 char sign = static_cast<char>(*s);
292 require_numeric_argument(arg, sign);
293 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
294 FMT_THROW(fmt::FormatError(fmt::format(
295 "format specifier '{}' requires signed argument", sign)));
296 }
297 ++s;
298 }
299
300 // Checks if an argument is a valid printf width specifier and sets
301 // left alignment if it is negative.
302 class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
303 private:
304 fmt::FormatSpec &spec_;
305
306 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
307
308 public:
309 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
310
311 void report_unhandled_arg() {
312 FMT_THROW(fmt::FormatError("width is not integer"));
313 }
314
315 template <typename T>
316 unsigned visit_any_int(T value) {
317 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
318 UnsignedType width = value;
319 if (fmt::internal::is_negative(value)) {
320 spec_.align_ = fmt::ALIGN_LEFT;
321 width = 0 - width;
322 }
323 if (width > INT_MAX)
324 FMT_THROW(fmt::FormatError("number is too big"));
325 return static_cast<unsigned>(width);
326 }
327 };
328
329 class PrecisionHandler :
330 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
331 public:
332 void report_unhandled_arg() {
333 FMT_THROW(fmt::FormatError("precision is not integer"));
334 }
335
336 template <typename T>
337 int visit_any_int(T value) {
338 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
339 FMT_THROW(fmt::FormatError("number is too big"));
340 return static_cast<int>(value);
341 }
342 };
343
344 // Converts an integer argument to an integral type T for printf.
345 template <typename T>
346 class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
347 private:
348 fmt::internal::Arg &arg_;
349 wchar_t type_;
350
351 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
352
353 public:
354 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
355 : arg_(arg), type_(type) {}
356
357 void visit_bool(bool value) {
358 if (type_ != 's')
359 visit_any_int(value);
360 }
361
362 template <typename U>
363 void visit_any_int(U value) {
364 bool is_signed = type_ == 'd' || type_ == 'i';
365 using fmt::internal::Arg;
366 if (sizeof(T) <= sizeof(int)) {
367 // Extra casts are used to silence warnings.
368 if (is_signed) {
369 arg_.type = Arg::INT;
370 arg_.int_value = static_cast<int>(static_cast<T>(value));
371 } else {
372 arg_.type = Arg::UINT;
373 arg_.uint_value = static_cast<unsigned>(
374 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
375 }
376 } else {
377 if (is_signed) {
378 arg_.type = Arg::LONG_LONG;
379 arg_.long_long_value =
380 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
381 } else {
382 arg_.type = Arg::ULONG_LONG;
383 arg_.ulong_long_value =
384 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
385 }
386 }
387 }
388 };
389
390 // Converts an integer argument to char for printf.
391 class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
392 private:
393 fmt::internal::Arg &arg_;
394
395 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
396
397 public:
398 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
399
400 template <typename T>
401 void visit_any_int(T value) {
402 arg_.type = Arg::CHAR;
403 arg_.int_value = static_cast<char>(value);
404 }
405 };
406 } // namespace
407
408 namespace internal {
409
410 template <typename Impl, typename Char>
411 class BasicArgFormatter : public ArgVisitor<Impl, void> {
412 private:
413 BasicWriter<Char> &writer_;
414 FormatSpec &spec_;
415
416 FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
417
418 void write_pointer(const void *p) {
419 spec_.flags_ = HASH_FLAG;
420 spec_.type_ = 'x';
421 writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_);
422 }
423
424 protected:
425 BasicWriter<Char> &writer() { return writer_; }
426 FormatSpec &spec() { return spec_; }
427
428 void write(bool value) {
429 const char *str_value = value ? "true" : "false";
430 Arg::StringValue<char> str = { str_value, strlen(str_value) };
431 writer_.write_str(str, spec_);
432 }
433
434 void write(const char *value) {
435 Arg::StringValue<char> str = {value, value != 0 ? strlen(value) : 0};
436 writer_.write_str(str, spec_);
437 }
438
439 public:
440 BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
441 : writer_(w), spec_(s) {}
442
443 template <typename T>
444 void visit_any_int(T value) { writer_.write_int(value, spec_); }
445
446 template <typename T>
447 void visit_any_double(T value) { writer_.write_double(value, spec_); }
448
449 void visit_bool(bool value) {
450 if (spec_.type_)
451 return visit_any_int(value);
452 write(value);
453 }
454
455 void visit_char(int value) {
456 if (spec_.type_ && spec_.type_ != 'c') {
457 spec_.flags_ |= CHAR_FLAG;
458 writer_.write_int(value, spec_);
459 return;
460 }
461 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
462 FMT_THROW(FormatError("invalid format specifier for char"));
463 typedef typename BasicWriter<Char>::CharPtr CharPtr;
464 Char fill = internal::CharTraits<Char>::cast(spec_.fill());
465 CharPtr out = CharPtr();
466 const unsigned CHAR_WIDTH = 1;
467 if (spec_.width_ > CHAR_WIDTH) {
468 out = writer_.grow_buffer(spec_.width_);
469 if (spec_.align_ == ALIGN_RIGHT) {
470 std::fill_n(out, spec_.width_ - CHAR_WIDTH, fill);
471 out += spec_.width_ - CHAR_WIDTH;
472 } else if (spec_.align_ == ALIGN_CENTER) {
473 out = writer_.fill_padding(out, spec_.width_,
474 internal::check(CHAR_WIDTH), fill);
475 } else {
476 std::fill_n(out + CHAR_WIDTH, spec_.width_ - CHAR_WIDTH, fill);
477 }
478 } else {
479 out = writer_.grow_buffer(CHAR_WIDTH);
480 }
481 *out = internal::CharTraits<Char>::cast(value);
482 }
483
484 void visit_cstring(const char *value) {
485 if (spec_.type_ == 'p')
486 return write_pointer(value);
487 write(value);
488 }
489
490 void visit_string(Arg::StringValue<char> value) {
491 writer_.write_str(value, spec_);
492 }
493
494 using ArgVisitor<Impl, void>::visit_wstring;
495
496 void visit_wstring(Arg::StringValue<Char> value) {
497 writer_.write_str(value, spec_);
498 }
499
500 void visit_pointer(const void *value) {
501 if (spec_.type_ && spec_.type_ != 'p')
502 report_unknown_type(spec_.type_, "pointer");
503 write_pointer(value);
504 }
505 };
506
507 // An argument formatter.
508 template <typename Char>
509 class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
510 private:
511 BasicFormatter<Char> &formatter_;
512 const Char *format_;
513
514 public:
515 ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
516 : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
517 formatter_(f), format_(fmt) {}
518
519 void visit_custom(Arg::CustomValue c) {
520 c.format(&formatter_, c.value, &format_);
521 }
522 };
523
524 template <typename Char>
525 class PrintfArgFormatter :
526 public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
527
528 void write_null_pointer() {
529 this->spec().type_ = 0;
530 this->write("(nil)");
531 }
532
533 typedef BasicArgFormatter<PrintfArgFormatter<Char>, Char> Base;
534
535 public:
536 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
537 : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
538
539 void visit_bool(bool value) {
540 FormatSpec &fmt_spec = this->spec();
541 if (fmt_spec.type_ != 's')
542 return this->visit_any_int(value);
543 fmt_spec.type_ = 0;
544 this->write(value);
545 }
546
547 void visit_char(int value) {
548 const FormatSpec &fmt_spec = this->spec();
549 BasicWriter<Char> &w = this->writer();
550 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
551 w.write_int(value, fmt_spec);
552 typedef typename BasicWriter<Char>::CharPtr CharPtr;
553 CharPtr out = CharPtr();
554 if (fmt_spec.width_ > 1) {
555 Char fill = ' ';
556 out = w.grow_buffer(fmt_spec.width_);
557 if (fmt_spec.align_ != ALIGN_LEFT) {
558 std::fill_n(out, fmt_spec.width_ - 1, fill);
559 out += fmt_spec.width_ - 1;
560 } else {
561 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
562 }
563 } else {
564 out = w.grow_buffer(1);
565 }
566 *out = static_cast<Char>(value);
567 }
568
569 void visit_cstring(const char *value) {
570 if (value)
571 Base::visit_cstring(value);
572 else if (this->spec().type_ == 'p')
573 write_null_pointer();
574 else
575 this->write("(null)");
576 }
577
578 void visit_pointer(const void *value) {
579 if (value)
580 return Base::visit_pointer(value);
581 this->spec().type_ = 0;
582 write_null_pointer();
583 }
584
585 void visit_custom(Arg::CustomValue c) {
586 BasicFormatter<Char> formatter(ArgList(), this->writer());
587 const Char format_str[] = {'}', 0};
588 const Char *format = format_str;
589 c.format(&formatter, c.value, &format);
590 }
591 };
592 } // namespace internal
593 } // namespace fmt
594
595 FMT_FUNC void fmt::SystemError::init(
596 int err_code, CStringRef format_str, ArgList args) {
597 error_code_ = err_code;
598 MemoryWriter w;
599 internal::format_system_error(w, err_code, format(format_str, args));
600 std::runtime_error &base = *this;
601 base = std::runtime_error(w.str());
602 }
603
604 template <typename T>
605 int fmt::internal::CharTraits<char>::format_float(
606 char *buffer, std::size_t size, const char *format,
607 unsigned width, int precision, T value) {
608 if (width == 0) {
609 return precision < 0 ?
610 FMT_SNPRINTF(buffer, size, format, value) :
611 FMT_SNPRINTF(buffer, size, format, precision, value);
612 }
613 return precision < 0 ?
614 FMT_SNPRINTF(buffer, size, format, width, value) :
615 FMT_SNPRINTF(buffer, size, format, width, precision, value);
616 }
617
618 template <typename T>
619 int fmt::internal::CharTraits<wchar_t>::format_float(
620 wchar_t *buffer, std::size_t size, const wchar_t *format,
621 unsigned width, int precision, T value) {
622 if (width == 0) {
623 return precision < 0 ?
624 FMT_SWPRINTF(buffer, size, format, value) :
625 FMT_SWPRINTF(buffer, size, format, precision, value);
626 }
627 return precision < 0 ?
628 FMT_SWPRINTF(buffer, size, format, width, value) :
629 FMT_SWPRINTF(buffer, size, format, width, precision, value);
630 }
631
632 template <typename T>
633 const char fmt::internal::BasicData<T>::DIGITS[] =
634 "0001020304050607080910111213141516171819"
635 "2021222324252627282930313233343536373839"
636 "4041424344454647484950515253545556575859"
637 "6061626364656667686970717273747576777879"
638 "8081828384858687888990919293949596979899";
639
640 #define FMT_POWERS_OF_10(factor) \
641 factor * 10, \
642 factor * 100, \
643 factor * 1000, \
644 factor * 10000, \
645 factor * 100000, \
646 factor * 1000000, \
647 factor * 10000000, \
648 factor * 100000000, \
649 factor * 1000000000
650
651 template <typename T>
652 const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
653 0, FMT_POWERS_OF_10(1)
654 };
655
656 template <typename T>
657 const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
658 0,
659 FMT_POWERS_OF_10(1),
660 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
661 // Multiply several constants instead of using a single long long constant
662 // to avoid warnings about C++98 not supporting long long.
663 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
664 };
665
666 FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
667 (void)type;
668 if (std::isprint(static_cast<unsigned char>(code))) {
669 FMT_THROW(fmt::FormatError(
670 fmt::format("unknown format code '{}' for {}", code, type)));
671 }
672 FMT_THROW(fmt::FormatError(
673 fmt::format("unknown format code '\\x{:02x}' for {}",
674 static_cast<unsigned>(code), type)));
675 }
676
677 #if FMT_USE_WINDOWS_H
678
679 FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
680 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
681 if (s.size() > INT_MAX)
682 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
683 int s_size = static_cast<int>(s.size());
684 int length = MultiByteToWideChar(
685 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
686 if (length == 0)
687 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
688 buffer_.resize(length + 1);
689 length = MultiByteToWideChar(
690 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
691 if (length == 0)
692 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
693 buffer_[length] = 0;
694 }
695
696 FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
697 if (int error_code = convert(s)) {
698 FMT_THROW(WindowsError(error_code,
699 "cannot convert string from UTF-16 to UTF-8"));
700 }
701 }
702
703 FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
704 if (s.size() > INT_MAX)
705 return ERROR_INVALID_PARAMETER;
706 int s_size = static_cast<int>(s.size());
707 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
708 if (length == 0)
709 return GetLastError();
710 buffer_.resize(length + 1);
711 length = WideCharToMultiByte(
712 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
713 if (length == 0)
714 return GetLastError();
715 buffer_[length] = 0;
716 return 0;
717 }
718
719 FMT_FUNC void fmt::WindowsError::init(
720 int err_code, CStringRef format_str, ArgList args) {
721 error_code_ = err_code;
722 MemoryWriter w;
723 internal::format_windows_error(w, err_code, format(format_str, args));
724 std::runtime_error &base = *this;
725 base = std::runtime_error(w.str());
726 }
727
728 FMT_FUNC void fmt::internal::format_windows_error(
729 fmt::Writer &out, int error_code,
730 fmt::StringRef message) FMT_NOEXCEPT {
731 class String {
732 private:
733 LPWSTR str_;
734
735 public:
736 String() : str_() {}
737 ~String() { LocalFree(str_); }
738 LPWSTR *ptr() { return &str_; }
739 LPCWSTR c_str() const { return str_; }
740 };
741 FMT_TRY {
742 String system_message;
743 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
744 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
745 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
746 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
747 UTF16ToUTF8 utf8_message;
748 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
749 out << message << ": " << utf8_message;
750 return;
751 }
752 }
753 } FMT_CATCH(...) {}
754 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
755 }
756
757 #endif // FMT_USE_WINDOWS_H
758
759 FMT_FUNC void fmt::internal::format_system_error(
760 fmt::Writer &out, int error_code,
761 fmt::StringRef message) FMT_NOEXCEPT {
762 FMT_TRY {
763 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
764 buffer.resize(INLINE_BUFFER_SIZE);
765 for (;;) {
766 char *system_message = &buffer[0];
767 int result = safe_strerror(error_code, system_message, buffer.size());
768 if (result == 0) {
769 out << message << ": " << system_message;
770 return;
771 }
772 if (result != ERANGE)
773 break; // Can't get error message, report error code instead.
774 buffer.resize(buffer.size() * 2);
775 }
776 } FMT_CATCH(...) {}
777 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
778 }
779
780 template <typename Char>
781 void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
782 if (!map_.empty())
783 return;
784 typedef internal::NamedArg<Char> NamedArg;
785 const NamedArg *named_arg = 0;
786 bool use_values =
787 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
788 if (use_values) {
789 for (unsigned i = 0;/*nothing*/; ++i) {
790 internal::Arg::Type arg_type = args.type(i);
791 switch (arg_type) {
792 case internal::Arg::NONE:
793 return;
794 case internal::Arg::NAMED_ARG:
795 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
796 map_.insert(Pair(named_arg->name, *named_arg));
797 break;
798 default:
799 /*nothing*/;
800 }
801 }
802 return;
803 }
804 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
805 internal::Arg::Type arg_type = args.type(i);
806 if (arg_type == internal::Arg::NAMED_ARG) {
807 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
808 map_.insert(Pair(named_arg->name, *named_arg));
809 }
810 }
811 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
812 switch (args.args_[i].type) {
813 case internal::Arg::NONE:
814 return;
815 case internal::Arg::NAMED_ARG:
816 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
817 map_.insert(Pair(named_arg->name, *named_arg));
818 break;
819 default:
820 /*nothing*/;
821 }
822 }
823 }
824
825 template <typename Char>
826 void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
827 FMT_THROW(std::runtime_error("buffer overflow"));
828 }
829
830 template <typename Char>
831 template <typename StrChar>
832 void fmt::BasicWriter<Char>::write_str(
833 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
834 // Check if StrChar is convertible to Char.
835 internal::CharTraits<Char>::convert(StrChar());
836 if (spec.type_ && spec.type_ != 's')
837 internal::report_unknown_type(spec.type_, "string");
838 const StrChar *str_value = s.value;
839 std::size_t str_size = s.size;
840 if (str_size == 0) {
841 if (!str_value) {
842 FMT_THROW(FormatError("string pointer is null"));
843 return;
844 }
845 }
846 std::size_t precision = spec.precision_;
847 if (spec.precision_ >= 0 && precision < str_size)
848 str_size = spec.precision_;
849 write_str(str_value, str_size, spec);
850 }
851
852 template <typename Char>
853 inline Arg fmt::BasicFormatter<Char>::get_arg(
854 BasicStringRef<Char> arg_name, const char *&error) {
855 if (check_no_auto_index(error)) {
856 map_.init(args());
857 const Arg *arg = map_.find(arg_name);
858 if (arg)
859 return *arg;
860 error = "argument not found";
861 }
862 return Arg();
863 }
864
865 template <typename Char>
866 inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
867 const char *error = 0;
868 Arg arg = *s < '0' || *s > '9' ?
869 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
870 if (error) {
871 FMT_THROW(FormatError(
872 *s != '}' && *s != ':' ? "invalid format string" : error));
873 }
874 return arg;
875 }
876
877 template <typename Char>
878 inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
879 assert(is_name_start(*s));
880 const Char *start = s;
881 Char c;
882 do {
883 c = *++s;
884 } while (is_name_start(c) || ('0' <= c && c <= '9'));
885 const char *error = 0;
886 Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
887 if (error)
888 FMT_THROW(fmt::FormatError(error));
889 return arg;
890 }
891
892 FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
893 unsigned arg_index, const char *&error) {
894 Arg arg = args_[arg_index];
895 switch (arg.type) {
896 case Arg::NONE:
897 error = "argument index out of range";
898 break;
899 case Arg::NAMED_ARG:
900 arg = *static_cast<const internal::Arg*>(arg.pointer);
901 default:
902 /*nothing*/;
903 }
904 return arg;
905 }
906
907 inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
908 if (next_arg_index_ >= 0)
909 return do_get_arg(next_arg_index_++, error);
910 error = "cannot switch from manual to automatic argument indexing";
911 return Arg();
912 }
913
914 inline bool fmt::internal::FormatterBase::check_no_auto_index(
915 const char *&error) {
916 if (next_arg_index_ > 0) {
917 error = "cannot switch from automatic to manual argument indexing";
918 return false;
919 }
920 next_arg_index_ = -1;
921 return true;
922 }
923
924 inline Arg fmt::internal::FormatterBase::get_arg(
925 unsigned arg_index, const char *&error) {
926 return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
927 }
928
929 template <typename Char>
930 void fmt::internal::PrintfFormatter<Char>::parse_flags(
931 FormatSpec &spec, const Char *&s) {
932 for (;;) {
933 switch (*s++) {
934 case '-':
935 spec.align_ = ALIGN_LEFT;
936 break;
937 case '+':
938 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
939 break;
940 case '0':
941 spec.fill_ = '0';
942 break;
943 case ' ':
944 spec.flags_ |= SIGN_FLAG;
945 break;
946 case '#':
947 spec.flags_ |= HASH_FLAG;
948 break;
949 default:
950 --s;
951 return;
952 }
953 }
954 }
955
956 template <typename Char>
957 Arg fmt::internal::PrintfFormatter<Char>::get_arg(
958 const Char *s, unsigned arg_index) {
959 (void)s;
960 const char *error = 0;
961 Arg arg = arg_index == UINT_MAX ?
962 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
963 if (error)
964 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
965 return arg;
966 }
967
968 template <typename Char>
969 unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
970 const Char *&s, FormatSpec &spec) {
971 unsigned arg_index = UINT_MAX;
972 Char c = *s;
973 if (c >= '0' && c <= '9') {
974 // Parse an argument index (if followed by '$') or a width possibly
975 // preceded with '0' flag(s).
976 unsigned value = parse_nonnegative_int(s);
977 if (*s == '$') { // value is an argument index
978 ++s;
979 arg_index = value;
980 } else {
981 if (c == '0')
982 spec.fill_ = '0';
983 if (value != 0) {
984 // Nonzero value means that we parsed width and don't need to
985 // parse it or flags again, so return now.
986 spec.width_ = value;
987 return arg_index;
988 }
989 }
990 }
991 parse_flags(spec, s);
992 // Parse width.
993 if (*s >= '0' && *s <= '9') {
994 spec.width_ = parse_nonnegative_int(s);
995 } else if (*s == '*') {
996 ++s;
997 spec.width_ = WidthHandler(spec).visit(get_arg(s));
998 }
999 return arg_index;
1000 }
1001
1002 template <typename Char>
1003 void fmt::internal::PrintfFormatter<Char>::format(
1004 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
1005 const Char *start = format_str.c_str();
1006 const Char *s = start;
1007 while (*s) {
1008 Char c = *s++;
1009 if (c != '%') continue;
1010 if (*s == c) {
1011 write(writer, start, s);
1012 start = ++s;
1013 continue;
1014 }
1015 write(writer, start, s - 1);
1016
1017 FormatSpec spec;
1018 spec.align_ = ALIGN_RIGHT;
1019
1020 // Parse argument index, flags and width.
1021 unsigned arg_index = parse_header(s, spec);
1022
1023 // Parse precision.
1024 if (*s == '.') {
1025 ++s;
1026 if ('0' <= *s && *s <= '9') {
1027 spec.precision_ = parse_nonnegative_int(s);
1028 } else if (*s == '*') {
1029 ++s;
1030 spec.precision_ = PrecisionHandler().visit(get_arg(s));
1031 }
1032 }
1033
1034 Arg arg = get_arg(s, arg_index);
1035 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
1036 spec.flags_ &= ~HASH_FLAG;
1037 if (spec.fill_ == '0') {
1038 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
1039 spec.align_ = ALIGN_NUMERIC;
1040 else
1041 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
1042 }
1043
1044 // Parse length and convert the argument to the required type.
1045 switch (*s++) {
1046 case 'h':
1047 if (*s == 'h')
1048 ArgConverter<signed char>(arg, *++s).visit(arg);
1049 else
1050 ArgConverter<short>(arg, *s).visit(arg);
1051 break;
1052 case 'l':
1053 if (*s == 'l')
1054 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
1055 else
1056 ArgConverter<long>(arg, *s).visit(arg);
1057 break;
1058 case 'j':
1059 ArgConverter<intmax_t>(arg, *s).visit(arg);
1060 break;
1061 case 'z':
1062 ArgConverter<std::size_t>(arg, *s).visit(arg);
1063 break;
1064 case 't':
1065 ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
1066 break;
1067 case 'L':
1068 // printf produces garbage when 'L' is omitted for long double, no
1069 // need to do the same.
1070 break;
1071 default:
1072 --s;
1073 ArgConverter<int>(arg, *s).visit(arg);
1074 }
1075
1076 // Parse type.
1077 if (!*s)
1078 FMT_THROW(FormatError("invalid format string"));
1079 spec.type_ = static_cast<char>(*s++);
1080 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
1081 // Normalize type.
1082 switch (spec.type_) {
1083 case 'i': case 'u':
1084 spec.type_ = 'd';
1085 break;
1086 case 'c':
1087 // TODO: handle wchar_t
1088 CharConverter(arg).visit(arg);
1089 break;
1090 }
1091 }
1092
1093 start = s;
1094
1095 // Format argument.
1096 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
1097 }
1098 write(writer, start, s);
1099 }
1100
1101 template <typename Char>
1102 const Char *fmt::BasicFormatter<Char>::format(
1103 const Char *&format_str, const Arg &arg) {
1104 const Char *s = format_str;
1105 FormatSpec spec;
1106 if (*s == ':') {
1107 if (arg.type == Arg::CUSTOM) {
1108 arg.custom.format(this, arg.custom.value, &s);
1109 return s;
1110 }
1111 ++s;
1112 // Parse fill and alignment.
1113 if (Char c = *s) {
1114 const Char *p = s + 1;
1115 spec.align_ = ALIGN_DEFAULT;
1116 do {
1117 switch (*p) {
1118 case '<':
1119 spec.align_ = ALIGN_LEFT;
1120 break;
1121 case '>':
1122 spec.align_ = ALIGN_RIGHT;
1123 break;
1124 case '=':
1125 spec.align_ = ALIGN_NUMERIC;
1126 break;
1127 case '^':
1128 spec.align_ = ALIGN_CENTER;
1129 break;
1130 }
1131 if (spec.align_ != ALIGN_DEFAULT) {
1132 if (p != s) {
1133 if (c == '}') break;
1134 if (c == '{')
1135 FMT_THROW(FormatError("invalid fill character '{'"));
1136 s += 2;
1137 spec.fill_ = c;
1138 } else ++s;
1139 if (spec.align_ == ALIGN_NUMERIC)
1140 require_numeric_argument(arg, '=');
1141 break;
1142 }
1143 } while (--p >= s);
1144 }
1145
1146 // Parse sign.
1147 switch (*s) {
1148 case '+':
1149 check_sign(s, arg);
1150 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1151 break;
1152 case '-':
1153 check_sign(s, arg);
1154 spec.flags_ |= MINUS_FLAG;
1155 break;
1156 case ' ':
1157 check_sign(s, arg);
1158 spec.flags_ |= SIGN_FLAG;
1159 break;
1160 }
1161
1162 if (*s == '#') {
1163 require_numeric_argument(arg, '#');
1164 spec.flags_ |= HASH_FLAG;
1165 ++s;
1166 }
1167
1168 // Parse zero flag.
1169 if (*s == '0') {
1170 require_numeric_argument(arg, '0');
1171 spec.align_ = ALIGN_NUMERIC;
1172 spec.fill_ = '0';
1173 ++s;
1174 }
1175
1176 // Parse width.
1177 if ('0' <= *s && *s <= '9') {
1178 spec.width_ = parse_nonnegative_int(s);
1179 } else if (*s == '{') {
1180 ++s;
1181 Arg width_arg = is_name_start(*s) ?
1182 parse_arg_name(s) : parse_arg_index(s);
1183 if (*s++ != '}')
1184 FMT_THROW(FormatError("invalid format string"));
1185 ULongLong value = 0;
1186 switch (width_arg.type) {
1187 case Arg::INT:
1188 if (width_arg.int_value < 0)
1189 FMT_THROW(FormatError("negative width"));
1190 value = width_arg.int_value;
1191 break;
1192 case Arg::UINT:
1193 value = width_arg.uint_value;
1194 break;
1195 case Arg::LONG_LONG:
1196 if (width_arg.long_long_value < 0)
1197 FMT_THROW(FormatError("negative width"));
1198 value = width_arg.long_long_value;
1199 break;
1200 case Arg::ULONG_LONG:
1201 value = width_arg.ulong_long_value;
1202 break;
1203 default:
1204 FMT_THROW(FormatError("width is not integer"));
1205 }
1206 if (value > INT_MAX)
1207 FMT_THROW(FormatError("number is too big"));
1208 spec.width_ = static_cast<int>(value);
1209 }
1210
1211 // Parse precision.
1212 if (*s == '.') {
1213 ++s;
1214 spec.precision_ = 0;
1215 if ('0' <= *s && *s <= '9') {
1216 spec.precision_ = parse_nonnegative_int(s);
1217 } else if (*s == '{') {
1218 ++s;
1219 Arg precision_arg =
1220 is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
1221 if (*s++ != '}')
1222 FMT_THROW(FormatError("invalid format string"));
1223 ULongLong value = 0;
1224 switch (precision_arg.type) {
1225 case Arg::INT:
1226 if (precision_arg.int_value < 0)
1227 FMT_THROW(FormatError("negative precision"));
1228 value = precision_arg.int_value;
1229 break;
1230 case Arg::UINT:
1231 value = precision_arg.uint_value;
1232 break;
1233 case Arg::LONG_LONG:
1234 if (precision_arg.long_long_value < 0)
1235 FMT_THROW(FormatError("negative precision"));
1236 value = precision_arg.long_long_value;
1237 break;
1238 case Arg::ULONG_LONG:
1239 value = precision_arg.ulong_long_value;
1240 break;
1241 default:
1242 FMT_THROW(FormatError("precision is not integer"));
1243 }
1244 if (value > INT_MAX)
1245 FMT_THROW(FormatError("number is too big"));
1246 spec.precision_ = static_cast<int>(value);
1247 } else {
1248 FMT_THROW(FormatError("missing precision specifier"));
1249 }
1250 if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
1251 FMT_THROW(FormatError(
1252 fmt::format("precision not allowed in {} format specifier",
1253 arg.type == Arg::POINTER ? "pointer" : "integer")));
1254 }
1255 }
1256
1257 // Parse type.
1258 if (*s != '}' && *s)
1259 spec.type_ = static_cast<char>(*s++);
1260 }
1261
1262 if (*s++ != '}')
1263 FMT_THROW(FormatError("missing '}' in format string"));
1264
1265 // Format argument.
1266 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
1267 return s;
1268 }
1269
1270 template <typename Char>
1271 void fmt::BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) {
1272 const Char *s = format_str.c_str();
1273 const Char *start = s;
1274 while (*s) {
1275 Char c = *s++;
1276 if (c != '{' && c != '}') continue;
1277 if (*s == c) {
1278 write(writer_, start, s);
1279 start = ++s;
1280 continue;
1281 }
1282 if (c == '}')
1283 FMT_THROW(FormatError("unmatched '}' in format string"));
1284 write(writer_, start, s - 1);
1285 Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
1286 start = s = format(s, arg);
1287 }
1288 write(writer_, start, s);
1289 }
1290
1291 FMT_FUNC void fmt::report_system_error(
1292 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
1293 // 'fmt::' is for bcc32.
1294 fmt::report_error(internal::format_system_error, error_code, message);
1295 }
1296
1297 #if FMT_USE_WINDOWS_H
1298 FMT_FUNC void fmt::report_windows_error(
1299 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
1300 // 'fmt::' is for bcc32.
1301 fmt::report_error(internal::format_windows_error, error_code, message);
1302 }
1303 #endif
1304
1305 FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
1306 MemoryWriter w;
1307 w.write(format_str, args);
1308 std::fwrite(w.data(), 1, w.size(), f);
1309 }
1310
1311 FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
1312 print(stdout, format_str, args);
1313 }
1314
1315 FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
1316 MemoryWriter w;
1317 w.write(format_str, args);
1318 os.write(w.data(), w.size());
1319 }
1320
1321 FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
1322 char escape[] = "\x1b[30m";
1323 escape[3] = static_cast<char>('0' + c);
1324 std::fputs(escape, stdout);
1325 print(format, args);
1326 std::fputs(RESET_COLOR, stdout);
1327 }
1328
1329 FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
1330 MemoryWriter w;
1331 printf(w, format, args);
1332 std::size_t size = w.size();
1333 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
1334 }
1335
1336 #ifndef FMT_HEADER_ONLY
1337
1338 template struct fmt::internal::BasicData<void>;
1339
1340 // Explicit instantiations for char.
1341
1342 template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
1343
1344 template const char *fmt::BasicFormatter<char>::format(
1345 const char *&format_str, const fmt::internal::Arg &arg);
1346
1347 template void fmt::BasicFormatter<char>::format(CStringRef format);
1348
1349 template void fmt::internal::PrintfFormatter<char>::format(
1350 BasicWriter<char> &writer, CStringRef format);
1351
1352 template int fmt::internal::CharTraits<char>::format_float(
1353 char *buffer, std::size_t size, const char *format,
1354 unsigned width, int precision, double value);
1355
1356 template int fmt::internal::CharTraits<char>::format_float(
1357 char *buffer, std::size_t size, const char *format,
1358 unsigned width, int precision, long double value);
1359
1360 // Explicit instantiations for wchar_t.
1361
1362 template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1363
1364 template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1365 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1366
1367 template void fmt::BasicFormatter<wchar_t>::format(
1368 BasicCStringRef<wchar_t> format);
1369
1370 template void fmt::internal::PrintfFormatter<wchar_t>::format(
1371 BasicWriter<wchar_t> &writer, WCStringRef format);
1372
1373 template int fmt::internal::CharTraits<wchar_t>::format_float(
1374 wchar_t *buffer, std::size_t size, const wchar_t *format,
1375 unsigned width, int precision, double value);
1376
1377 template int fmt::internal::CharTraits<wchar_t>::format_float(
1378 wchar_t *buffer, std::size_t size, const wchar_t *format,
1379 unsigned width, int precision, long double value);
1380
1381 #endif // FMT_HEADER_ONLY
1382
1383 #ifdef _MSC_VER
1384 # pragma warning(pop)
1385 #endif