blob: a5d5e1262c07b2cab0bfc1ff73a0a9c1458282f9 [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
122#define FMT_POWERS_OF_10(prefix) \
123 prefix 10, \
124 prefix 100, \
125 prefix 1000, \
126 prefix 10000, \
127 prefix 100000, \
128 prefix 1000000, \
129 prefix 10000000, \
130 prefix 100000000, \
131 prefix 1000000000
132
133const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10()};
134const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800135 0,
Victor Zveroviche9b21912014-02-19 12:43:55 -0800136 FMT_POWERS_OF_10(),
137 FMT_POWERS_OF_10(ULongLong(1000000000) *),
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800138 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800139};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800140
Victor Zverovich687301c2013-01-26 16:07:28 -0800141void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800142 if (std::isprint(static_cast<unsigned char>(code))) {
143 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800144 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800145 }
146 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800147 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800148 << static_cast<unsigned>(code) << type));
149}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700150
151
152// Fills the padding around the content and returns the pointer to the
153// content area.
154template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700155typename fmt::BasicWriter<Char>::CharPtr
156 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
157 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700158 std::size_t padding = total_size - content_size;
159 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700160 Char fill_char = static_cast<Char>(fill);
161 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700162 buffer += left_padding;
163 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700164 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700165 return content;
166}
167
168template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700169typename fmt::BasicWriter<Char>::CharPtr
170 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800171 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700172 unsigned width = spec.width();
173 if (width <= size) {
174 CharPtr p = GrowBuffer(size);
175 *p = sign;
176 return p + size - 1;
177 }
178 CharPtr p = GrowBuffer(width);
179 CharPtr end = p + width;
180 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800181 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700182 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700183 if (align == ALIGN_LEFT) {
184 *p = sign;
185 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700186 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700187 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700188 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700189 *p = sign;
190 p += size;
191 } else {
192 if (align == ALIGN_NUMERIC) {
193 if (sign) {
194 *p++ = sign;
195 --size;
196 }
197 } else {
198 *(end - size) = sign;
199 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700200 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700201 p = end;
202 }
203 return p - 1;
204}
205
206template <typename Char>
207template <typename T>
208void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800209 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700210 // Check type.
211 char type = spec.type();
212 bool upper = false;
213 switch (type) {
214 case 0:
215 type = 'g';
216 break;
217 case 'e': case 'f': case 'g':
218 break;
219 case 'F':
220#ifdef _MSC_VER
221 // MSVC's printf doesn't support 'F'.
222 type = 'f';
223#endif
224 // Fall through.
225 case 'E': case 'G':
226 upper = true;
227 break;
228 default:
229 internal::ReportUnknownType(type, "double");
230 break;
231 }
232
233 char sign = 0;
234 // Use SignBit instead of value < 0 because the latter is always
235 // false for NaN.
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700236 if (SignBit(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700237 sign = '-';
238 value = -value;
239 } else if (spec.sign_flag()) {
240 sign = spec.plus_flag() ? '+' : ' ';
241 }
242
243 if (value != value) {
244 // Format NaN ourselves because sprintf's output is not consistent
245 // across platforms.
246 std::size_t size = 4;
247 const char *nan = upper ? " NAN" : " nan";
248 if (!sign) {
249 --size;
250 ++nan;
251 }
252 CharPtr out = FormatString(nan, size, spec);
253 if (sign)
254 *out = sign;
255 return;
256 }
257
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700258 if (IsInf(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700259 // Format infinity ourselves because sprintf's output is not consistent
260 // across platforms.
261 std::size_t size = 4;
262 const char *inf = upper ? " INF" : " inf";
263 if (!sign) {
264 --size;
265 ++inf;
266 }
267 CharPtr out = FormatString(inf, size, spec);
268 if (sign)
269 *out = sign;
270 return;
271 }
272
273 std::size_t offset = buffer_.size();
274 unsigned width = spec.width();
275 if (sign) {
276 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
277 if (width > 0)
278 --width;
279 ++offset;
280 }
281
282 // Build format string.
283 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
284 Char format[MAX_FORMAT_SIZE];
285 Char *format_ptr = format;
286 *format_ptr++ = '%';
287 unsigned width_for_sprintf = width;
288 if (spec.hash_flag())
289 *format_ptr++ = '#';
290 if (spec.align() == ALIGN_CENTER) {
291 width_for_sprintf = 0;
292 } else {
293 if (spec.align() == ALIGN_LEFT)
294 *format_ptr++ = '-';
295 if (width != 0)
296 *format_ptr++ = '*';
297 }
298 if (precision >= 0) {
299 *format_ptr++ = '.';
300 *format_ptr++ = '*';
301 }
302 if (internal::IsLongDouble<T>::VALUE)
303 *format_ptr++ = 'L';
304 *format_ptr++ = type;
305 *format_ptr = '\0';
306
307 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700308 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700309 for (;;) {
310 std::size_t size = buffer_.capacity() - offset;
311 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700312 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700313 start, size, format, width_for_sprintf, precision, value);
314 if (n >= 0 && offset + n < buffer_.capacity()) {
315 if (sign) {
316 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
317 *start != ' ') {
318 *(start - 1) = sign;
319 sign = 0;
320 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700321 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700322 }
323 ++n;
324 }
325 if (spec.align() == ALIGN_CENTER &&
326 spec.width() > static_cast<unsigned>(n)) {
327 unsigned width = spec.width();
328 CharPtr p = GrowBuffer(width);
329 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700330 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700331 return;
332 }
333 if (spec.fill() != ' ' || sign) {
334 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700335 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700336 if (sign)
337 *(start - 1) = sign;
338 }
339 GrowBuffer(n);
340 return;
341 }
342 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
343 }
344}
345
346// Throws Exception(message) if format contains '}', otherwise throws
347// FormatError reporting unmatched '{'. The idea is that unmatched '{'
348// should override other errors.
349template <typename Char>
350void fmt::BasicFormatter<Char>::ReportError(
351 const Char *s, StringRef message) const {
352 for (int num_open_braces = num_open_braces_; *s; ++s) {
353 if (*s == '{') {
354 ++num_open_braces;
355 } else if (*s == '}') {
356 if (--num_open_braces == 0)
357 throw fmt::FormatError(message);
358 }
359 }
360 throw fmt::FormatError("unmatched '{' in format");
361}
362
363// Parses an unsigned integer advancing s to the end of the parsed input.
364// This function assumes that the first character of s is a digit.
365template <typename Char>
366unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
367 assert('0' <= *s && *s <= '9');
368 unsigned value = 0;
369 do {
370 unsigned new_value = value * 10 + (*s++ - '0');
371 if (new_value < value) // Check if value wrapped around.
372 ReportError(s, "number is too big in format");
373 value = new_value;
374 } while ('0' <= *s && *s <= '9');
375 return value;
376}
377
378template <typename Char>
379inline const typename fmt::BasicFormatter<Char>::Arg
380 &fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
381 unsigned arg_index = 0;
382 if (*s < '0' || *s > '9') {
383 if (*s != '}' && *s != ':')
384 ReportError(s, "invalid argument index in format string");
385 if (next_arg_index_ < 0) {
386 ReportError(s,
387 "cannot switch from manual to automatic argument indexing");
388 }
389 arg_index = next_arg_index_++;
390 } else {
391 if (next_arg_index_ > 0) {
392 ReportError(s,
393 "cannot switch from automatic to manual argument indexing");
394 }
395 next_arg_index_ = -1;
396 arg_index = ParseUInt(s);
397 }
398 if (arg_index >= args_.size())
399 ReportError(s, "argument index is out of range in format");
400 return *args_[arg_index];
401}
402
403template <typename Char>
404void fmt::BasicFormatter<Char>::CheckSign(const Char *&s, const Arg &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800405 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700406 if (arg.type > LAST_NUMERIC_TYPE) {
407 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800408 Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700409 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800410 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700411 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800412 Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700413 }
414 ++s;
415}
416
417template <typename Char>
418void fmt::BasicFormatter<Char>::DoFormat() {
419 const Char *start = format_;
420 format_ = 0;
421 next_arg_index_ = 0;
422 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700423 BasicWriter<Char> &writer = *writer_;
424 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700425 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700426 if (c != '{' && c != '}') continue;
427 if (*s == c) {
428 writer.buffer_.append(start, s);
429 start = ++s;
430 continue;
431 }
432 if (c == '}')
433 throw FormatError("unmatched '}' in format");
434 num_open_braces_= 1;
435 writer.buffer_.append(start, s - 1);
436
437 const Arg &arg = ParseArgIndex(s);
438
Victor Zverovichea5dce32014-01-28 12:47:37 -0800439 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700440 int precision = -1;
441 if (*s == ':') {
442 ++s;
443
444 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700445 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700446 const Char *p = s + 1;
447 spec.align_ = ALIGN_DEFAULT;
448 do {
449 switch (*p) {
450 case '<':
451 spec.align_ = ALIGN_LEFT;
452 break;
453 case '>':
454 spec.align_ = ALIGN_RIGHT;
455 break;
456 case '=':
457 spec.align_ = ALIGN_NUMERIC;
458 break;
459 case '^':
460 spec.align_ = ALIGN_CENTER;
461 break;
462 }
463 if (spec.align_ != ALIGN_DEFAULT) {
464 if (p != s) {
465 if (c == '}') break;
466 if (c == '{')
467 ReportError(s, "invalid fill character '{'");
468 s += 2;
469 spec.fill_ = c;
470 } else ++s;
471 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
472 ReportError(s, "format specifier '=' requires numeric argument");
473 break;
474 }
475 } while (--p >= s);
476 }
477
478 // Parse sign.
479 switch (*s) {
480 case '+':
481 CheckSign(s, arg);
482 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
483 break;
484 case '-':
485 CheckSign(s, arg);
486 break;
487 case ' ':
488 CheckSign(s, arg);
489 spec.flags_ |= SIGN_FLAG;
490 break;
491 }
492
493 if (*s == '#') {
494 if (arg.type > LAST_NUMERIC_TYPE)
495 ReportError(s, "format specifier '#' requires numeric argument");
496 spec.flags_ |= HASH_FLAG;
497 ++s;
498 }
499
500 // Parse width and zero flag.
501 if ('0' <= *s && *s <= '9') {
502 if (*s == '0') {
503 if (arg.type > LAST_NUMERIC_TYPE)
504 ReportError(s, "format specifier '0' requires numeric argument");
505 spec.align_ = ALIGN_NUMERIC;
506 spec.fill_ = '0';
507 }
508 // Zero may be parsed again as a part of the width, but it is simpler
509 // and more efficient than checking if the next char is a digit.
510 unsigned value = ParseUInt(s);
511 if (value > INT_MAX)
512 ReportError(s, "number is too big in format");
513 spec.width_ = value;
514 }
515
516 // Parse precision.
517 if (*s == '.') {
518 ++s;
519 precision = 0;
520 if ('0' <= *s && *s <= '9') {
521 unsigned value = ParseUInt(s);
522 if (value > INT_MAX)
523 ReportError(s, "number is too big in format");
524 precision = value;
525 } else if (*s == '{') {
526 ++s;
527 ++num_open_braces_;
528 const Arg &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800529 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700530 switch (precision_arg.type) {
531 case INT:
532 if (precision_arg.int_value < 0)
533 ReportError(s, "negative precision in format");
534 value = precision_arg.int_value;
535 break;
536 case UINT:
537 value = precision_arg.uint_value;
538 break;
539 case LONG:
540 if (precision_arg.long_value < 0)
541 ReportError(s, "negative precision in format");
542 value = precision_arg.long_value;
543 break;
544 case ULONG:
545 value = precision_arg.ulong_value;
546 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800547 case LONG_LONG:
548 if (precision_arg.long_long_value < 0)
549 ReportError(s, "negative precision in format");
550 value = precision_arg.long_long_value;
551 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800552 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800553 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800554 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700555 default:
556 ReportError(s, "precision is not integer");
557 }
558 if (value > INT_MAX)
559 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800560 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700561 if (*s++ != '}')
562 throw FormatError("unmatched '{' in format");
563 --num_open_braces_;
564 } else {
565 ReportError(s, "missing precision in format");
566 }
567 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
568 ReportError(s,
569 "precision specifier requires floating-point argument");
570 }
571 }
572
573 // Parse type.
574 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700575 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700576 }
577
578 if (*s++ != '}')
579 throw FormatError("unmatched '{' in format");
580 start = s;
581
582 // Format argument.
583 switch (arg.type) {
584 case INT:
Victor Zverovich641df952013-12-31 09:43:32 -0800585 FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700586 break;
587 case UINT:
Victor Zverovich641df952013-12-31 09:43:32 -0800588 FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700589 break;
590 case LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800591 FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700592 break;
593 case ULONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800594 FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700595 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800596 case LONG_LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800597 FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800598 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800599 case ULONG_LONG:
Victor Zverovich641df952013-12-31 09:43:32 -0800600 FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800601 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700602 case DOUBLE:
603 writer.FormatDouble(arg.double_value, spec, precision);
604 break;
605 case LONG_DOUBLE:
606 writer.FormatDouble(arg.long_double_value, spec, precision);
607 break;
608 case CHAR: {
609 if (spec.type_ && spec.type_ != 'c')
610 internal::ReportUnknownType(spec.type_, "char");
611 typedef typename BasicWriter<Char>::CharPtr CharPtr;
612 CharPtr out = CharPtr();
613 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700614 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700615 out = writer.GrowBuffer(spec.width_);
616 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700617 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700618 out += spec.width_ - 1;
619 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700620 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700621 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700622 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700623 }
624 } else {
625 out = writer.GrowBuffer(1);
626 }
627 *out = arg.int_value;
628 break;
629 }
630 case STRING: {
631 if (spec.type_ && spec.type_ != 's')
632 internal::ReportUnknownType(spec.type_, "string");
633 const Char *str = arg.string.value;
634 std::size_t size = arg.string.size;
635 if (size == 0) {
636 if (!str)
637 throw FormatError("string pointer is null");
638 if (*str)
639 size = std::char_traits<Char>::length(str);
640 }
641 writer.FormatString(str, size, spec);
642 break;
643 }
644 case POINTER:
645 if (spec.type_ && spec.type_ != 'p')
646 internal::ReportUnknownType(spec.type_, "pointer");
647 spec.flags_= HASH_FLAG;
648 spec.type_ = 'x';
Victor Zverovich641df952013-12-31 09:43:32 -0800649 FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700650 break;
651 case CUSTOM:
652 if (spec.type_)
653 internal::ReportUnknownType(spec.type_, "object");
654 arg.custom.format(writer, arg.custom.value, spec);
655 break;
656 default:
657 assert(false);
658 break;
659 }
660 }
661 writer.buffer_.append(start, s);
662}
663
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700664// Explicit instantiations for char.
665
Victor Zverovich7cae7632013-09-06 20:23:42 -0700666template void fmt::BasicWriter<char>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800667 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700668
Victor Zverovich7cae7632013-09-06 20:23:42 -0700669template void fmt::BasicWriter<char>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800670 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700671
Victor Zverovich93e41252013-09-08 13:07:04 -0700672template fmt::BasicWriter<char>::CharPtr
673 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
674 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700675
Victor Zverovich7cae7632013-09-06 20:23:42 -0700676template fmt::BasicWriter<char>::CharPtr
677 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800678 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700679
Victor Zverovich7cae7632013-09-06 20:23:42 -0700680template void fmt::BasicFormatter<char>::ReportError(
681 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700682
Victor Zverovich7cae7632013-09-06 20:23:42 -0700683template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700684
Victor Zverovich7cae7632013-09-06 20:23:42 -0700685template const fmt::BasicFormatter<char>::Arg
686 &fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700687
Victor Zverovich7cae7632013-09-06 20:23:42 -0700688template void fmt::BasicFormatter<char>::CheckSign(
689 const char *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700690
Victor Zverovich7cae7632013-09-06 20:23:42 -0700691template void fmt::BasicFormatter<char>::DoFormat();
692
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700693// Explicit instantiations for wchar_t.
694
Victor Zverovich7cae7632013-09-06 20:23:42 -0700695template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800696 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700697
Victor Zverovich7cae7632013-09-06 20:23:42 -0700698template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800699 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700700
Victor Zverovich7cae7632013-09-06 20:23:42 -0700701template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700702 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
703 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700704
Victor Zverovich7cae7632013-09-06 20:23:42 -0700705template fmt::BasicWriter<wchar_t>::CharPtr
706 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800707 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700708
Victor Zverovich7cae7632013-09-06 20:23:42 -0700709template void fmt::BasicFormatter<wchar_t>::ReportError(
710 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700711
Victor Zverovich7cae7632013-09-06 20:23:42 -0700712template unsigned fmt::BasicFormatter<wchar_t>::ParseUInt(
713 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700714
Victor Zverovich7cae7632013-09-06 20:23:42 -0700715template const fmt::BasicFormatter<wchar_t>::Arg
716 &fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700717
Victor Zverovich7cae7632013-09-06 20:23:42 -0700718template void fmt::BasicFormatter<wchar_t>::CheckSign(
719 const wchar_t *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700720
Victor Zverovich7cae7632013-09-06 20:23:42 -0700721template void fmt::BasicFormatter<wchar_t>::DoFormat();