blob: 30d10f77260b53d69c8df640c34f382079031167 [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
Victor Zverovich9ff3b972013-09-07 10:15:08 -070042namespace {
43
44#ifndef _MSC_VER
45
46inline int SignBit(double value) {
47 // When compiled in C++11 mode signbit is no longer a macro but a function
48 // defined in namespace std and the macro is undefined.
49 using namespace std;
50 return signbit(value);
51}
52
53inline int IsInf(double x) {
54#ifdef isinf
55 return isinf(x);
56#else
57 return std::isinf(x);
58#endif
59}
60
61#define FMT_SNPRINTF snprintf
62
Victor Zverovicha684d0c2013-12-27 08:00:10 -080063#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070064
65inline int SignBit(double value) {
66 if (value < 0) return 1;
67 if (value == value) return 0;
68 int dec = 0, sign = 0;
69 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
70 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
71 return sign;
72}
73
74inline int IsInf(double x) { return !_finite(x); }
75
Victor Zverovicha684d0c2013-12-27 08:00:10 -080076inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
77 va_list args;
78 va_start(args, format);
79 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
80 va_end(args);
81 return result;
82}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070083
84#endif // _MSC_VER
Victor Zverovichb605b392013-09-09 22:21:40 -070085}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070086
Victor Zverovichb605b392013-09-09 22:21:40 -070087template <typename T>
88int fmt::internal::CharTraits<char>::FormatFloat(
89 char *buffer, std::size_t size, const char *format,
90 unsigned width, int precision, T value) {
91 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -070092 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -070093 FMT_SNPRINTF(buffer, size, format, value) :
94 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -070095 }
Victor Zverovichb605b392013-09-09 22:21:40 -070096 return precision < 0 ?
97 FMT_SNPRINTF(buffer, size, format, width, value) :
98 FMT_SNPRINTF(buffer, size, format, width, precision, value);
99}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700100
Victor Zverovichb605b392013-09-09 22:21:40 -0700101template <typename T>
102int fmt::internal::CharTraits<wchar_t>::FormatFloat(
103 wchar_t *buffer, std::size_t size, const wchar_t *format,
104 unsigned width, int precision, T value) {
105 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700106 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700107 swprintf(buffer, size, format, value) :
108 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700109 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700110 return precision < 0 ?
111 swprintf(buffer, size, format, width, value) :
112 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700113}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800114
Victor Zverovich65d47e52013-09-09 06:51:03 -0700115const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800116 "0001020304050607080910111213141516171819"
117 "2021222324252627282930313233343536373839"
118 "4041424344454647484950515253545556575859"
119 "6061626364656667686970717273747576777879"
120 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800121
Victor Zverovichf1d85162014-02-19 13:02:22 -0800122#define FMT_POWERS_OF_10(factor) \
123 factor * 10, \
124 factor * 100, \
125 factor * 1000, \
126 factor * 10000, \
127 factor * 100000, \
128 factor * 1000000, \
129 factor * 10000000, \
130 factor * 100000000, \
131 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800132
Victor Zverovichf1d85162014-02-19 13:02:22 -0800133const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800134const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800135 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800136 FMT_POWERS_OF_10(1),
137 FMT_POWERS_OF_10(ULongLong(1000000000)),
138 // Multiply several constants instead of using a single long long constants
139 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800140 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800141};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800142
Victor Zverovich687301c2013-01-26 16:07:28 -0800143void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800144 if (std::isprint(static_cast<unsigned char>(code))) {
145 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800146 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800147 }
148 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800149 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800150 << static_cast<unsigned>(code) << type));
151}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700152
153
154// Fills the padding around the content and returns the pointer to the
155// content area.
156template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700157typename fmt::BasicWriter<Char>::CharPtr
158 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
159 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700160 std::size_t padding = total_size - content_size;
161 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700162 Char fill_char = static_cast<Char>(fill);
163 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700164 buffer += left_padding;
165 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700166 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700167 return content;
168}
169
170template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700171typename fmt::BasicWriter<Char>::CharPtr
172 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800173 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700174 unsigned width = spec.width();
175 if (width <= size) {
176 CharPtr p = GrowBuffer(size);
177 *p = sign;
178 return p + size - 1;
179 }
180 CharPtr p = GrowBuffer(width);
181 CharPtr end = p + width;
182 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800183 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700184 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700185 if (align == ALIGN_LEFT) {
186 *p = sign;
187 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700188 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700189 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700190 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700191 *p = sign;
192 p += size;
193 } else {
194 if (align == ALIGN_NUMERIC) {
195 if (sign) {
196 *p++ = sign;
197 --size;
198 }
199 } else {
200 *(end - size) = sign;
201 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700202 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700203 p = end;
204 }
205 return p - 1;
206}
207
208template <typename Char>
209template <typename T>
210void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800211 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700212 // Check type.
213 char type = spec.type();
214 bool upper = false;
215 switch (type) {
216 case 0:
217 type = 'g';
218 break;
219 case 'e': case 'f': case 'g':
220 break;
221 case 'F':
222#ifdef _MSC_VER
223 // MSVC's printf doesn't support 'F'.
224 type = 'f';
225#endif
226 // Fall through.
227 case 'E': case 'G':
228 upper = true;
229 break;
230 default:
231 internal::ReportUnknownType(type, "double");
232 break;
233 }
234
235 char sign = 0;
236 // Use SignBit instead of value < 0 because the latter is always
237 // false for NaN.
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700238 if (SignBit(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700239 sign = '-';
240 value = -value;
241 } else if (spec.sign_flag()) {
242 sign = spec.plus_flag() ? '+' : ' ';
243 }
244
245 if (value != value) {
246 // Format NaN ourselves because sprintf's output is not consistent
247 // across platforms.
248 std::size_t size = 4;
249 const char *nan = upper ? " NAN" : " nan";
250 if (!sign) {
251 --size;
252 ++nan;
253 }
254 CharPtr out = FormatString(nan, size, spec);
255 if (sign)
256 *out = sign;
257 return;
258 }
259
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700260 if (IsInf(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700261 // Format infinity ourselves because sprintf's output is not consistent
262 // across platforms.
263 std::size_t size = 4;
264 const char *inf = upper ? " INF" : " inf";
265 if (!sign) {
266 --size;
267 ++inf;
268 }
269 CharPtr out = FormatString(inf, size, spec);
270 if (sign)
271 *out = sign;
272 return;
273 }
274
275 std::size_t offset = buffer_.size();
276 unsigned width = spec.width();
277 if (sign) {
278 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
279 if (width > 0)
280 --width;
281 ++offset;
282 }
283
284 // Build format string.
285 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
286 Char format[MAX_FORMAT_SIZE];
287 Char *format_ptr = format;
288 *format_ptr++ = '%';
289 unsigned width_for_sprintf = width;
290 if (spec.hash_flag())
291 *format_ptr++ = '#';
292 if (spec.align() == ALIGN_CENTER) {
293 width_for_sprintf = 0;
294 } else {
295 if (spec.align() == ALIGN_LEFT)
296 *format_ptr++ = '-';
297 if (width != 0)
298 *format_ptr++ = '*';
299 }
300 if (precision >= 0) {
301 *format_ptr++ = '.';
302 *format_ptr++ = '*';
303 }
304 if (internal::IsLongDouble<T>::VALUE)
305 *format_ptr++ = 'L';
306 *format_ptr++ = type;
307 *format_ptr = '\0';
308
309 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700310 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700311 for (;;) {
312 std::size_t size = buffer_.capacity() - offset;
313 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700314 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700315 start, size, format, width_for_sprintf, precision, value);
316 if (n >= 0 && offset + n < buffer_.capacity()) {
317 if (sign) {
318 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
319 *start != ' ') {
320 *(start - 1) = sign;
321 sign = 0;
322 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700323 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700324 }
325 ++n;
326 }
327 if (spec.align() == ALIGN_CENTER &&
328 spec.width() > static_cast<unsigned>(n)) {
329 unsigned width = spec.width();
330 CharPtr p = GrowBuffer(width);
331 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700332 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700333 return;
334 }
335 if (spec.fill() != ' ' || sign) {
336 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700337 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700338 if (sign)
339 *(start - 1) = sign;
340 }
341 GrowBuffer(n);
342 return;
343 }
344 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
345 }
346}
347
348// Throws Exception(message) if format contains '}', otherwise throws
349// FormatError reporting unmatched '{'. The idea is that unmatched '{'
350// should override other errors.
351template <typename Char>
352void fmt::BasicFormatter<Char>::ReportError(
353 const Char *s, StringRef message) const {
354 for (int num_open_braces = num_open_braces_; *s; ++s) {
355 if (*s == '{') {
356 ++num_open_braces;
357 } else if (*s == '}') {
358 if (--num_open_braces == 0)
359 throw fmt::FormatError(message);
360 }
361 }
362 throw fmt::FormatError("unmatched '{' in format");
363}
364
365// Parses an unsigned integer advancing s to the end of the parsed input.
366// This function assumes that the first character of s is a digit.
367template <typename Char>
368unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
369 assert('0' <= *s && *s <= '9');
370 unsigned value = 0;
371 do {
372 unsigned new_value = value * 10 + (*s++ - '0');
373 if (new_value < value) // Check if value wrapped around.
374 ReportError(s, "number is too big in format");
375 value = new_value;
376 } while ('0' <= *s && *s <= '9');
377 return value;
378}
379
380template <typename Char>
381inline const typename fmt::BasicFormatter<Char>::Arg
382 &fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
383 unsigned arg_index = 0;
384 if (*s < '0' || *s > '9') {
385 if (*s != '}' && *s != ':')
386 ReportError(s, "invalid argument index in format string");
387 if (next_arg_index_ < 0) {
388 ReportError(s,
389 "cannot switch from manual to automatic argument indexing");
390 }
391 arg_index = next_arg_index_++;
392 } else {
393 if (next_arg_index_ > 0) {
394 ReportError(s,
395 "cannot switch from automatic to manual argument indexing");
396 }
397 next_arg_index_ = -1;
398 arg_index = ParseUInt(s);
399 }
400 if (arg_index >= args_.size())
401 ReportError(s, "argument index is out of range in format");
402 return *args_[arg_index];
403}
404
405template <typename Char>
406void fmt::BasicFormatter<Char>::CheckSign(const Char *&s, const Arg &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800407 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700408 if (arg.type > LAST_NUMERIC_TYPE) {
409 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800410 Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700411 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800412 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700413 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800414 Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700415 }
416 ++s;
417}
418
419template <typename Char>
420void fmt::BasicFormatter<Char>::DoFormat() {
421 const Char *start = format_;
422 format_ = 0;
423 next_arg_index_ = 0;
424 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700425 BasicWriter<Char> &writer = *writer_;
426 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700427 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700428 if (c != '{' && c != '}') continue;
429 if (*s == c) {
430 writer.buffer_.append(start, s);
431 start = ++s;
432 continue;
433 }
434 if (c == '}')
435 throw FormatError("unmatched '}' in format");
436 num_open_braces_= 1;
437 writer.buffer_.append(start, s - 1);
438
439 const Arg &arg = ParseArgIndex(s);
440
Victor Zverovichea5dce32014-01-28 12:47:37 -0800441 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700442 int precision = -1;
443 if (*s == ':') {
444 ++s;
445
446 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700447 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700448 const Char *p = s + 1;
449 spec.align_ = ALIGN_DEFAULT;
450 do {
451 switch (*p) {
452 case '<':
453 spec.align_ = ALIGN_LEFT;
454 break;
455 case '>':
456 spec.align_ = ALIGN_RIGHT;
457 break;
458 case '=':
459 spec.align_ = ALIGN_NUMERIC;
460 break;
461 case '^':
462 spec.align_ = ALIGN_CENTER;
463 break;
464 }
465 if (spec.align_ != ALIGN_DEFAULT) {
466 if (p != s) {
467 if (c == '}') break;
468 if (c == '{')
469 ReportError(s, "invalid fill character '{'");
470 s += 2;
471 spec.fill_ = c;
472 } else ++s;
473 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
474 ReportError(s, "format specifier '=' requires numeric argument");
475 break;
476 }
477 } while (--p >= s);
478 }
479
480 // Parse sign.
481 switch (*s) {
482 case '+':
483 CheckSign(s, arg);
484 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
485 break;
486 case '-':
487 CheckSign(s, arg);
488 break;
489 case ' ':
490 CheckSign(s, arg);
491 spec.flags_ |= SIGN_FLAG;
492 break;
493 }
494
495 if (*s == '#') {
496 if (arg.type > LAST_NUMERIC_TYPE)
497 ReportError(s, "format specifier '#' requires numeric argument");
498 spec.flags_ |= HASH_FLAG;
499 ++s;
500 }
501
502 // Parse width and zero flag.
503 if ('0' <= *s && *s <= '9') {
504 if (*s == '0') {
505 if (arg.type > LAST_NUMERIC_TYPE)
506 ReportError(s, "format specifier '0' requires numeric argument");
507 spec.align_ = ALIGN_NUMERIC;
508 spec.fill_ = '0';
509 }
510 // Zero may be parsed again as a part of the width, but it is simpler
511 // and more efficient than checking if the next char is a digit.
512 unsigned value = ParseUInt(s);
513 if (value > INT_MAX)
514 ReportError(s, "number is too big in format");
515 spec.width_ = value;
516 }
517
518 // Parse precision.
519 if (*s == '.') {
520 ++s;
521 precision = 0;
522 if ('0' <= *s && *s <= '9') {
523 unsigned value = ParseUInt(s);
524 if (value > INT_MAX)
525 ReportError(s, "number is too big in format");
526 precision = value;
527 } else if (*s == '{') {
528 ++s;
529 ++num_open_braces_;
530 const Arg &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800531 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700532 switch (precision_arg.type) {
533 case INT:
534 if (precision_arg.int_value < 0)
535 ReportError(s, "negative precision in format");
536 value = precision_arg.int_value;
537 break;
538 case UINT:
539 value = precision_arg.uint_value;
540 break;
541 case LONG:
542 if (precision_arg.long_value < 0)
543 ReportError(s, "negative precision in format");
544 value = precision_arg.long_value;
545 break;
546 case ULONG:
547 value = precision_arg.ulong_value;
548 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800549 case LONG_LONG:
550 if (precision_arg.long_long_value < 0)
551 ReportError(s, "negative precision in format");
552 value = precision_arg.long_long_value;
553 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800554 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800555 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800556 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700557 default:
558 ReportError(s, "precision is not integer");
559 }
560 if (value > INT_MAX)
561 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800562 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700563 if (*s++ != '}')
564 throw FormatError("unmatched '{' in format");
565 --num_open_braces_;
566 } else {
567 ReportError(s, "missing precision in format");
568 }
569 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
570 ReportError(s,
571 "precision specifier requires floating-point argument");
572 }
573 }
574
575 // Parse type.
576 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700577 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700578 }
579
580 if (*s++ != '}')
581 throw FormatError("unmatched '{' in format");
582 start = s;
583
584 // Format argument.
585 switch (arg.type) {
586 case INT:
Victor Zverovich641df952013-12-31 09:43:32 -0800587 FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700588 break;
589 case UINT:
Victor Zverovich641df952013-12-31 09:43:32 -0800590 FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700591 break;
592 case LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800593 FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700594 break;
595 case ULONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800596 FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700597 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800598 case LONG_LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800599 FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800600 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800601 case ULONG_LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800602 FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800603 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700604 case DOUBLE:
605 writer.FormatDouble(arg.double_value, spec, precision);
606 break;
607 case LONG_DOUBLE:
608 writer.FormatDouble(arg.long_double_value, spec, precision);
609 break;
610 case CHAR: {
611 if (spec.type_ && spec.type_ != 'c')
612 internal::ReportUnknownType(spec.type_, "char");
613 typedef typename BasicWriter<Char>::CharPtr CharPtr;
614 CharPtr out = CharPtr();
615 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700616 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700617 out = writer.GrowBuffer(spec.width_);
618 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700619 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700620 out += spec.width_ - 1;
621 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700622 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700623 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700624 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700625 }
626 } else {
627 out = writer.GrowBuffer(1);
628 }
629 *out = arg.int_value;
630 break;
631 }
632 case STRING: {
633 if (spec.type_ && spec.type_ != 's')
634 internal::ReportUnknownType(spec.type_, "string");
635 const Char *str = arg.string.value;
636 std::size_t size = arg.string.size;
637 if (size == 0) {
638 if (!str)
639 throw FormatError("string pointer is null");
640 if (*str)
641 size = std::char_traits<Char>::length(str);
642 }
643 writer.FormatString(str, size, spec);
644 break;
645 }
646 case POINTER:
647 if (spec.type_ && spec.type_ != 'p')
648 internal::ReportUnknownType(spec.type_, "pointer");
649 spec.flags_= HASH_FLAG;
650 spec.type_ = 'x';
Victor Zverovich641df952013-12-31 09:43:32 -0800651 FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700652 break;
653 case CUSTOM:
654 if (spec.type_)
655 internal::ReportUnknownType(spec.type_, "object");
656 arg.custom.format(writer, arg.custom.value, spec);
657 break;
658 default:
659 assert(false);
660 break;
661 }
662 }
663 writer.buffer_.append(start, s);
664}
665
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700666// Explicit instantiations for char.
667
Victor Zverovich7cae7632013-09-06 20:23:42 -0700668template void fmt::BasicWriter<char>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800669 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700670
Victor Zverovich7cae7632013-09-06 20:23:42 -0700671template void fmt::BasicWriter<char>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800672 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700673
Victor Zverovich93e41252013-09-08 13:07:04 -0700674template fmt::BasicWriter<char>::CharPtr
675 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
676 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700677
Victor Zverovich7cae7632013-09-06 20:23:42 -0700678template fmt::BasicWriter<char>::CharPtr
679 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800680 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700681
Victor Zverovich7cae7632013-09-06 20:23:42 -0700682template void fmt::BasicFormatter<char>::ReportError(
683 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700684
Victor Zverovich7cae7632013-09-06 20:23:42 -0700685template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700686
Victor Zverovich7cae7632013-09-06 20:23:42 -0700687template const fmt::BasicFormatter<char>::Arg
688 &fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700689
Victor Zverovich7cae7632013-09-06 20:23:42 -0700690template void fmt::BasicFormatter<char>::CheckSign(
691 const char *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700692
Victor Zverovich7cae7632013-09-06 20:23:42 -0700693template void fmt::BasicFormatter<char>::DoFormat();
694
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700695// Explicit instantiations for wchar_t.
696
Victor Zverovich7cae7632013-09-06 20:23:42 -0700697template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800698 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700699
Victor Zverovich7cae7632013-09-06 20:23:42 -0700700template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800701 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700702
Victor Zverovich7cae7632013-09-06 20:23:42 -0700703template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700704 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
705 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700706
Victor Zverovich7cae7632013-09-06 20:23:42 -0700707template fmt::BasicWriter<wchar_t>::CharPtr
708 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800709 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700710
Victor Zverovich7cae7632013-09-06 20:23:42 -0700711template void fmt::BasicFormatter<wchar_t>::ReportError(
712 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700713
Victor Zverovich7cae7632013-09-06 20:23:42 -0700714template unsigned fmt::BasicFormatter<wchar_t>::ParseUInt(
715 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700716
Victor Zverovich7cae7632013-09-06 20:23:42 -0700717template const fmt::BasicFormatter<wchar_t>::Arg
718 &fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700719
Victor Zverovich7cae7632013-09-06 20:23:42 -0700720template void fmt::BasicFormatter<wchar_t>::CheckSign(
721 const wchar_t *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700722
Victor Zverovich7cae7632013-09-06 20:23:42 -0700723template void fmt::BasicFormatter<wchar_t>::DoFormat();