blob: 090e3f4d6e7151247a66038dee980eaa5d3ac439 [file] [log] [blame]
Victor Zverovichb076df42012-12-07 08:31:09 -08001/*
Victor Zverovichfaccb4c2012-12-12 07:44:41 -08002 String formatting library for C++
3
4 Copyright (c) 2012, 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.
Victor Zverovichb076df42012-12-07 08:31:09 -080026 */
27
Victor Zverovichd53f2092012-12-16 15:06:31 -080028// Disable useless MSVC warnings.
Victor Zverovichf8c91062012-12-17 15:41:00 -080029#undef _CRT_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080030#define _CRT_SECURE_NO_WARNINGS
Victor Zverovichc240a122012-12-21 15:02:25 -080031#undef _SCL_SECURE_NO_WARNINGS
32#define _SCL_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080033
Victor Zverovichfbfedcf2013-01-14 15:16:20 -080034#include "format.h"
35
Victor Zverovich72f896d2012-12-12 09:17:28 -080036#include <cctype>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070037#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080038#include <cstdarg>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070039
Victor Zverovich447e02c2014-02-15 10:48:34 -080040using fmt::ULongLong;
41
jdale88a9862fd2014-03-11 18:56:24 +000042#if _MSC_VER
43# pragma warning(push)
44# pragma warning(disable: 4127) // conditional expression is constant
45#endif
46
Victor Zverovich9ff3b972013-09-07 10:15:08 -070047namespace {
48
49#ifndef _MSC_VER
50
51inline int SignBit(double value) {
52 // When compiled in C++11 mode signbit is no longer a macro but a function
53 // defined in namespace std and the macro is undefined.
54 using namespace std;
55 return signbit(value);
56}
57
58inline int IsInf(double x) {
59#ifdef isinf
60 return isinf(x);
61#else
62 return std::isinf(x);
63#endif
64}
65
66#define FMT_SNPRINTF snprintf
67
Victor Zverovicha684d0c2013-12-27 08:00:10 -080068#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070069
70inline int SignBit(double value) {
71 if (value < 0) return 1;
72 if (value == value) return 0;
73 int dec = 0, sign = 0;
74 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
75 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
76 return sign;
77}
78
79inline int IsInf(double x) { return !_finite(x); }
80
Victor Zverovicha684d0c2013-12-27 08:00:10 -080081inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
82 va_list args;
83 va_start(args, format);
84 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
85 va_end(args);
86 return result;
87}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070088
89#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -080090
91const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovichb605b392013-09-09 22:21:40 -070092}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070093
Victor Zverovichb605b392013-09-09 22:21:40 -070094template <typename T>
95int fmt::internal::CharTraits<char>::FormatFloat(
96 char *buffer, std::size_t size, const char *format,
97 unsigned width, int precision, T value) {
98 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -070099 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700100 FMT_SNPRINTF(buffer, size, format, value) :
101 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700102 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700103 return precision < 0 ?
104 FMT_SNPRINTF(buffer, size, format, width, value) :
105 FMT_SNPRINTF(buffer, size, format, width, precision, value);
106}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700107
Victor Zverovichb605b392013-09-09 22:21:40 -0700108template <typename T>
109int fmt::internal::CharTraits<wchar_t>::FormatFloat(
110 wchar_t *buffer, std::size_t size, const wchar_t *format,
111 unsigned width, int precision, T value) {
112 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700113 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700114 swprintf(buffer, size, format, value) :
115 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700116 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700117 return precision < 0 ?
118 swprintf(buffer, size, format, width, value) :
119 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700120}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800121
Victor Zverovich65d47e52013-09-09 06:51:03 -0700122const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800123 "0001020304050607080910111213141516171819"
124 "2021222324252627282930313233343536373839"
125 "4041424344454647484950515253545556575859"
126 "6061626364656667686970717273747576777879"
127 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800128
Victor Zverovichf1d85162014-02-19 13:02:22 -0800129#define FMT_POWERS_OF_10(factor) \
130 factor * 10, \
131 factor * 100, \
132 factor * 1000, \
133 factor * 10000, \
134 factor * 100000, \
135 factor * 1000000, \
136 factor * 10000000, \
137 factor * 100000000, \
138 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800139
Victor Zverovichf1d85162014-02-19 13:02:22 -0800140const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800141const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800142 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800143 FMT_POWERS_OF_10(1),
144 FMT_POWERS_OF_10(ULongLong(1000000000)),
145 // Multiply several constants instead of using a single long long constants
146 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800147 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800148};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800149
Victor Zverovich687301c2013-01-26 16:07:28 -0800150void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800151 if (std::isprint(static_cast<unsigned char>(code))) {
152 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800153 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800154 }
155 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800156 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800157 << static_cast<unsigned>(code) << type));
158}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700159
160
161// Fills the padding around the content and returns the pointer to the
162// content area.
163template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700164typename fmt::BasicWriter<Char>::CharPtr
165 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
166 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700167 std::size_t padding = total_size - content_size;
168 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700169 Char fill_char = static_cast<Char>(fill);
170 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700171 buffer += left_padding;
172 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700173 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700174 return content;
175}
176
177template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700178typename fmt::BasicWriter<Char>::CharPtr
179 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800180 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700181 unsigned width = spec.width();
182 if (width <= size) {
183 CharPtr p = GrowBuffer(size);
184 *p = sign;
185 return p + size - 1;
186 }
187 CharPtr p = GrowBuffer(width);
188 CharPtr end = p + width;
189 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800190 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700191 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700192 if (align == ALIGN_LEFT) {
193 *p = sign;
194 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700195 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700196 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700197 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700198 *p = sign;
199 p += size;
200 } else {
201 if (align == ALIGN_NUMERIC) {
202 if (sign) {
203 *p++ = sign;
204 --size;
205 }
206 } else {
207 *(end - size) = sign;
208 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700209 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700210 p = end;
211 }
212 return p - 1;
213}
214
215template <typename Char>
216template <typename T>
217void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800218 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700219 // Check type.
220 char type = spec.type();
221 bool upper = false;
222 switch (type) {
223 case 0:
224 type = 'g';
225 break;
226 case 'e': case 'f': case 'g':
227 break;
228 case 'F':
229#ifdef _MSC_VER
230 // MSVC's printf doesn't support 'F'.
231 type = 'f';
232#endif
233 // Fall through.
234 case 'E': case 'G':
235 upper = true;
236 break;
237 default:
238 internal::ReportUnknownType(type, "double");
239 break;
240 }
241
242 char sign = 0;
243 // Use SignBit instead of value < 0 because the latter is always
244 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000245 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700246 sign = '-';
247 value = -value;
248 } else if (spec.sign_flag()) {
249 sign = spec.plus_flag() ? '+' : ' ';
250 }
251
252 if (value != value) {
253 // Format NaN ourselves because sprintf's output is not consistent
254 // across platforms.
255 std::size_t size = 4;
256 const char *nan = upper ? " NAN" : " nan";
257 if (!sign) {
258 --size;
259 ++nan;
260 }
261 CharPtr out = FormatString(nan, size, spec);
262 if (sign)
263 *out = sign;
264 return;
265 }
266
jdale88a9862fd2014-03-11 18:56:24 +0000267 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700268 // Format infinity ourselves because sprintf's output is not consistent
269 // across platforms.
270 std::size_t size = 4;
271 const char *inf = upper ? " INF" : " inf";
272 if (!sign) {
273 --size;
274 ++inf;
275 }
276 CharPtr out = FormatString(inf, size, spec);
277 if (sign)
278 *out = sign;
279 return;
280 }
281
282 std::size_t offset = buffer_.size();
283 unsigned width = spec.width();
284 if (sign) {
285 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
286 if (width > 0)
287 --width;
288 ++offset;
289 }
290
291 // Build format string.
292 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
293 Char format[MAX_FORMAT_SIZE];
294 Char *format_ptr = format;
295 *format_ptr++ = '%';
296 unsigned width_for_sprintf = width;
297 if (spec.hash_flag())
298 *format_ptr++ = '#';
299 if (spec.align() == ALIGN_CENTER) {
300 width_for_sprintf = 0;
301 } else {
302 if (spec.align() == ALIGN_LEFT)
303 *format_ptr++ = '-';
304 if (width != 0)
305 *format_ptr++ = '*';
306 }
307 if (precision >= 0) {
308 *format_ptr++ = '.';
309 *format_ptr++ = '*';
310 }
311 if (internal::IsLongDouble<T>::VALUE)
312 *format_ptr++ = 'L';
313 *format_ptr++ = type;
314 *format_ptr = '\0';
315
316 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700317 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700318 for (;;) {
319 std::size_t size = buffer_.capacity() - offset;
320 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700321 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700322 start, size, format, width_for_sprintf, precision, value);
323 if (n >= 0 && offset + n < buffer_.capacity()) {
324 if (sign) {
325 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
326 *start != ' ') {
327 *(start - 1) = sign;
328 sign = 0;
329 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700330 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700331 }
332 ++n;
333 }
334 if (spec.align() == ALIGN_CENTER &&
335 spec.width() > static_cast<unsigned>(n)) {
336 unsigned width = spec.width();
337 CharPtr p = GrowBuffer(width);
338 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700339 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700340 return;
341 }
342 if (spec.fill() != ' ' || sign) {
343 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700344 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700345 if (sign)
346 *(start - 1) = sign;
347 }
348 GrowBuffer(n);
349 return;
350 }
351 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
352 }
353}
354
355// Throws Exception(message) if format contains '}', otherwise throws
356// FormatError reporting unmatched '{'. The idea is that unmatched '{'
357// should override other errors.
358template <typename Char>
359void fmt::BasicFormatter<Char>::ReportError(
360 const Char *s, StringRef message) const {
361 for (int num_open_braces = num_open_braces_; *s; ++s) {
362 if (*s == '{') {
363 ++num_open_braces;
364 } else if (*s == '}') {
365 if (--num_open_braces == 0)
366 throw fmt::FormatError(message);
367 }
368 }
369 throw fmt::FormatError("unmatched '{' in format");
370}
371
372// Parses an unsigned integer advancing s to the end of the parsed input.
373// This function assumes that the first character of s is a digit.
374template <typename Char>
375unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
376 assert('0' <= *s && *s <= '9');
377 unsigned value = 0;
378 do {
379 unsigned new_value = value * 10 + (*s++ - '0');
380 if (new_value < value) // Check if value wrapped around.
381 ReportError(s, "number is too big in format");
382 value = new_value;
383 } while ('0' <= *s && *s <= '9');
384 return value;
385}
386
387template <typename Char>
388inline const typename fmt::BasicFormatter<Char>::Arg
389 &fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
390 unsigned arg_index = 0;
391 if (*s < '0' || *s > '9') {
392 if (*s != '}' && *s != ':')
393 ReportError(s, "invalid argument index in format string");
394 if (next_arg_index_ < 0) {
395 ReportError(s,
396 "cannot switch from manual to automatic argument indexing");
397 }
398 arg_index = next_arg_index_++;
399 } else {
400 if (next_arg_index_ > 0) {
401 ReportError(s,
402 "cannot switch from automatic to manual argument indexing");
403 }
404 next_arg_index_ = -1;
405 arg_index = ParseUInt(s);
406 }
407 if (arg_index >= args_.size())
408 ReportError(s, "argument index is out of range in format");
409 return *args_[arg_index];
410}
411
412template <typename Char>
413void fmt::BasicFormatter<Char>::CheckSign(const Char *&s, const Arg &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800414 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700415 if (arg.type > LAST_NUMERIC_TYPE) {
416 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800417 Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700418 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800419 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700420 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800421 Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700422 }
423 ++s;
424}
425
426template <typename Char>
427void fmt::BasicFormatter<Char>::DoFormat() {
428 const Char *start = format_;
429 format_ = 0;
430 next_arg_index_ = 0;
431 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700432 BasicWriter<Char> &writer = *writer_;
433 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700434 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700435 if (c != '{' && c != '}') continue;
436 if (*s == c) {
437 writer.buffer_.append(start, s);
438 start = ++s;
439 continue;
440 }
441 if (c == '}')
442 throw FormatError("unmatched '}' in format");
443 num_open_braces_= 1;
444 writer.buffer_.append(start, s - 1);
445
446 const Arg &arg = ParseArgIndex(s);
447
Victor Zverovichea5dce32014-01-28 12:47:37 -0800448 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700449 int precision = -1;
450 if (*s == ':') {
451 ++s;
452
453 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700454 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700455 const Char *p = s + 1;
456 spec.align_ = ALIGN_DEFAULT;
457 do {
458 switch (*p) {
459 case '<':
460 spec.align_ = ALIGN_LEFT;
461 break;
462 case '>':
463 spec.align_ = ALIGN_RIGHT;
464 break;
465 case '=':
466 spec.align_ = ALIGN_NUMERIC;
467 break;
468 case '^':
469 spec.align_ = ALIGN_CENTER;
470 break;
471 }
472 if (spec.align_ != ALIGN_DEFAULT) {
473 if (p != s) {
474 if (c == '}') break;
475 if (c == '{')
476 ReportError(s, "invalid fill character '{'");
477 s += 2;
478 spec.fill_ = c;
479 } else ++s;
480 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
481 ReportError(s, "format specifier '=' requires numeric argument");
482 break;
483 }
484 } while (--p >= s);
485 }
486
487 // Parse sign.
488 switch (*s) {
489 case '+':
490 CheckSign(s, arg);
491 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
492 break;
493 case '-':
494 CheckSign(s, arg);
495 break;
496 case ' ':
497 CheckSign(s, arg);
498 spec.flags_ |= SIGN_FLAG;
499 break;
500 }
501
502 if (*s == '#') {
503 if (arg.type > LAST_NUMERIC_TYPE)
504 ReportError(s, "format specifier '#' requires numeric argument");
505 spec.flags_ |= HASH_FLAG;
506 ++s;
507 }
508
509 // Parse width and zero flag.
510 if ('0' <= *s && *s <= '9') {
511 if (*s == '0') {
512 if (arg.type > LAST_NUMERIC_TYPE)
513 ReportError(s, "format specifier '0' requires numeric argument");
514 spec.align_ = ALIGN_NUMERIC;
515 spec.fill_ = '0';
516 }
517 // Zero may be parsed again as a part of the width, but it is simpler
518 // and more efficient than checking if the next char is a digit.
519 unsigned value = ParseUInt(s);
520 if (value > INT_MAX)
521 ReportError(s, "number is too big in format");
522 spec.width_ = value;
523 }
524
525 // Parse precision.
526 if (*s == '.') {
527 ++s;
528 precision = 0;
529 if ('0' <= *s && *s <= '9') {
530 unsigned value = ParseUInt(s);
531 if (value > INT_MAX)
532 ReportError(s, "number is too big in format");
533 precision = value;
534 } else if (*s == '{') {
535 ++s;
536 ++num_open_braces_;
537 const Arg &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800538 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700539 switch (precision_arg.type) {
540 case INT:
541 if (precision_arg.int_value < 0)
542 ReportError(s, "negative precision in format");
543 value = precision_arg.int_value;
544 break;
545 case UINT:
546 value = precision_arg.uint_value;
547 break;
548 case LONG:
549 if (precision_arg.long_value < 0)
550 ReportError(s, "negative precision in format");
551 value = precision_arg.long_value;
552 break;
553 case ULONG:
554 value = precision_arg.ulong_value;
555 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800556 case LONG_LONG:
557 if (precision_arg.long_long_value < 0)
558 ReportError(s, "negative precision in format");
559 value = precision_arg.long_long_value;
560 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800561 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800562 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800563 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700564 default:
565 ReportError(s, "precision is not integer");
566 }
567 if (value > INT_MAX)
568 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800569 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700570 if (*s++ != '}')
571 throw FormatError("unmatched '{' in format");
572 --num_open_braces_;
573 } else {
574 ReportError(s, "missing precision in format");
575 }
576 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
577 ReportError(s,
578 "precision specifier requires floating-point argument");
579 }
580 }
581
582 // Parse type.
583 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700584 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700585 }
586
587 if (*s++ != '}')
588 throw FormatError("unmatched '{' in format");
589 start = s;
590
591 // Format argument.
592 switch (arg.type) {
593 case INT:
Victor Zverovich641df952013-12-31 09:43:32 -0800594 FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700595 break;
596 case UINT:
Victor Zverovich641df952013-12-31 09:43:32 -0800597 FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700598 break;
599 case LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800600 FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700601 break;
602 case ULONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800603 FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700604 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800605 case LONG_LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800606 FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800607 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800608 case ULONG_LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800609 FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800610 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700611 case DOUBLE:
612 writer.FormatDouble(arg.double_value, spec, precision);
613 break;
614 case LONG_DOUBLE:
615 writer.FormatDouble(arg.long_double_value, spec, precision);
616 break;
617 case CHAR: {
618 if (spec.type_ && spec.type_ != 'c')
619 internal::ReportUnknownType(spec.type_, "char");
620 typedef typename BasicWriter<Char>::CharPtr CharPtr;
621 CharPtr out = CharPtr();
622 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700623 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700624 out = writer.GrowBuffer(spec.width_);
625 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700626 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700627 out += spec.width_ - 1;
628 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700629 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700630 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700631 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700632 }
633 } else {
634 out = writer.GrowBuffer(1);
635 }
jdale884cabe162014-03-11 19:03:26 +0000636 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700637 break;
638 }
639 case STRING: {
640 if (spec.type_ && spec.type_ != 's')
641 internal::ReportUnknownType(spec.type_, "string");
642 const Char *str = arg.string.value;
643 std::size_t size = arg.string.size;
644 if (size == 0) {
645 if (!str)
646 throw FormatError("string pointer is null");
647 if (*str)
648 size = std::char_traits<Char>::length(str);
649 }
650 writer.FormatString(str, size, spec);
651 break;
652 }
653 case POINTER:
654 if (spec.type_ && spec.type_ != 'p')
655 internal::ReportUnknownType(spec.type_, "pointer");
656 spec.flags_= HASH_FLAG;
657 spec.type_ = 'x';
Victor Zverovich641df952013-12-31 09:43:32 -0800658 FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700659 break;
660 case CUSTOM:
661 if (spec.type_)
662 internal::ReportUnknownType(spec.type_, "object");
663 arg.custom.format(writer, arg.custom.value, spec);
664 break;
665 default:
666 assert(false);
667 break;
668 }
669 }
670 writer.buffer_.append(start, s);
671}
672
Victor Zverovich43fe1002014-02-19 14:20:26 -0800673void fmt::ColorWriter::operator()(const fmt::BasicWriter<char> &w) const {
674 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +0000675 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovich43fe1002014-02-19 14:20:26 -0800676 std::fputs(escape, stdout);
677 std::fwrite(w.data(), 1, w.size(), stdout);
678 std::fputs(RESET_COLOR, stdout);
679}
Victor Zverovich6968ef32014-02-19 13:51:23 -0800680
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700681// Explicit instantiations for char.
682
Victor Zverovich7cae7632013-09-06 20:23:42 -0700683template void fmt::BasicWriter<char>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800684 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700685
Victor Zverovich7cae7632013-09-06 20:23:42 -0700686template void fmt::BasicWriter<char>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800687 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700688
Victor Zverovich93e41252013-09-08 13:07:04 -0700689template fmt::BasicWriter<char>::CharPtr
690 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
691 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700692
Victor Zverovich7cae7632013-09-06 20:23:42 -0700693template fmt::BasicWriter<char>::CharPtr
694 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800695 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700696
Victor Zverovich7cae7632013-09-06 20:23:42 -0700697template void fmt::BasicFormatter<char>::ReportError(
698 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700699
Victor Zverovich7cae7632013-09-06 20:23:42 -0700700template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700701
Victor Zverovich7cae7632013-09-06 20:23:42 -0700702template const fmt::BasicFormatter<char>::Arg
703 &fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700704
Victor Zverovich7cae7632013-09-06 20:23:42 -0700705template void fmt::BasicFormatter<char>::CheckSign(
706 const char *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700707
Victor Zverovich7cae7632013-09-06 20:23:42 -0700708template void fmt::BasicFormatter<char>::DoFormat();
709
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700710// Explicit instantiations for wchar_t.
711
Victor Zverovich7cae7632013-09-06 20:23:42 -0700712template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800713 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700714
Victor Zverovich7cae7632013-09-06 20:23:42 -0700715template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800716 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700717
Victor Zverovich7cae7632013-09-06 20:23:42 -0700718template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700719 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
720 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700721
Victor Zverovich7cae7632013-09-06 20:23:42 -0700722template fmt::BasicWriter<wchar_t>::CharPtr
723 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800724 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700725
Victor Zverovich7cae7632013-09-06 20:23:42 -0700726template void fmt::BasicFormatter<wchar_t>::ReportError(
727 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700728
Victor Zverovich7cae7632013-09-06 20:23:42 -0700729template unsigned fmt::BasicFormatter<wchar_t>::ParseUInt(
730 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700731
Victor Zverovich7cae7632013-09-06 20:23:42 -0700732template const fmt::BasicFormatter<wchar_t>::Arg
733 &fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700734
Victor Zverovich7cae7632013-09-06 20:23:42 -0700735template void fmt::BasicFormatter<wchar_t>::CheckSign(
736 const wchar_t *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700737
Victor Zverovich7cae7632013-09-06 20:23:42 -0700738template void fmt::BasicFormatter<wchar_t>::DoFormat();
jdale88a9862fd2014-03-11 18:56:24 +0000739
740#if _MSC_VER
741# pragma warning(pop)
742#endif