blob: e2083ecfb7de997b5a9995588f899748bb4366b6 [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
40namespace {
41
42#ifndef _MSC_VER
43
44inline int SignBit(double value) {
45 // When compiled in C++11 mode signbit is no longer a macro but a function
46 // defined in namespace std and the macro is undefined.
47 using namespace std;
48 return signbit(value);
49}
50
51inline int IsInf(double x) {
52#ifdef isinf
53 return isinf(x);
54#else
55 return std::isinf(x);
56#endif
57}
58
59#define FMT_SNPRINTF snprintf
60
Victor Zverovicha684d0c2013-12-27 08:00:10 -080061#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070062
63inline int SignBit(double value) {
64 if (value < 0) return 1;
65 if (value == value) return 0;
66 int dec = 0, sign = 0;
67 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
68 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
69 return sign;
70}
71
72inline int IsInf(double x) { return !_finite(x); }
73
Victor Zverovicha684d0c2013-12-27 08:00:10 -080074inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
75 va_list args;
76 va_start(args, format);
77 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
78 va_end(args);
79 return result;
80}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070081
82#endif // _MSC_VER
Victor Zverovichb605b392013-09-09 22:21:40 -070083}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070084
Victor Zverovichb605b392013-09-09 22:21:40 -070085template <typename T>
86int fmt::internal::CharTraits<char>::FormatFloat(
87 char *buffer, std::size_t size, const char *format,
88 unsigned width, int precision, T value) {
89 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -070090 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -070091 FMT_SNPRINTF(buffer, size, format, value) :
92 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -070093 }
Victor Zverovichb605b392013-09-09 22:21:40 -070094 return precision < 0 ?
95 FMT_SNPRINTF(buffer, size, format, width, value) :
96 FMT_SNPRINTF(buffer, size, format, width, precision, value);
97}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070098
Victor Zverovichb605b392013-09-09 22:21:40 -070099template <typename T>
100int fmt::internal::CharTraits<wchar_t>::FormatFloat(
101 wchar_t *buffer, std::size_t size, const wchar_t *format,
102 unsigned width, int precision, T value) {
103 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700104 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700105 swprintf(buffer, size, format, value) :
106 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700107 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700108 return precision < 0 ?
109 swprintf(buffer, size, format, width, value) :
110 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700111}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800112
Victor Zverovich65d47e52013-09-09 06:51:03 -0700113const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800114 "0001020304050607080910111213141516171819"
115 "2021222324252627282930313233343536373839"
116 "4041424344454647484950515253545556575859"
117 "6061626364656667686970717273747576777879"
118 "8081828384858687888990919293949596979899";
Victor Zverovich877abaf2013-01-08 09:56:05 -0800119
Victor Zverovich687301c2013-01-26 16:07:28 -0800120void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800121 if (std::isprint(static_cast<unsigned char>(code))) {
122 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800123 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800124 }
125 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800126 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800127 << static_cast<unsigned>(code) << type));
128}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700129
130
131// Fills the padding around the content and returns the pointer to the
132// content area.
133template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700134typename fmt::BasicWriter<Char>::CharPtr
135 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
136 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700137 std::size_t padding = total_size - content_size;
138 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700139 Char fill_char = static_cast<Char>(fill);
140 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700141 buffer += left_padding;
142 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700143 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700144 return content;
145}
146
147template <typename Char>
148void fmt::BasicWriter<Char>::FormatDecimal(
149 CharPtr buffer, uint64_t value, unsigned num_digits) {
150 --num_digits;
151 while (value >= 100) {
152 // Integer division is slow so do it for a group of two digits instead
153 // of for every digit. The idea comes from the talk by Alexandrescu
154 // "Three Optimization Tips for C++". See speed-test for a comparison.
155 unsigned index = (value % 100) * 2;
156 value /= 100;
Victor Zverovich65d47e52013-09-09 06:51:03 -0700157 buffer[num_digits] = internal::DIGITS[index + 1];
158 buffer[num_digits - 1] = internal::DIGITS[index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700159 num_digits -= 2;
160 }
161 if (value < 10) {
162 *buffer = static_cast<char>('0' + value);
163 return;
164 }
165 unsigned index = static_cast<unsigned>(value * 2);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700166 buffer[1] = internal::DIGITS[index + 1];
167 buffer[0] = internal::DIGITS[index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700168}
169
170template <typename Char>
171typename 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 void fmt::BasicWriter<char>::FormatDecimal(
679 CharPtr buffer, uint64_t value, unsigned num_digits);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700680
Victor Zverovich7cae7632013-09-06 20:23:42 -0700681template fmt::BasicWriter<char>::CharPtr
682 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800683 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700684
Victor Zverovich7cae7632013-09-06 20:23:42 -0700685template void fmt::BasicFormatter<char>::ReportError(
686 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700687
Victor Zverovich7cae7632013-09-06 20:23:42 -0700688template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700689
Victor Zverovich7cae7632013-09-06 20:23:42 -0700690template const fmt::BasicFormatter<char>::Arg
691 &fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700692
Victor Zverovich7cae7632013-09-06 20:23:42 -0700693template void fmt::BasicFormatter<char>::CheckSign(
694 const char *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700695
Victor Zverovich7cae7632013-09-06 20:23:42 -0700696template void fmt::BasicFormatter<char>::DoFormat();
697
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700698// Explicit instantiations for wchar_t.
699
Victor Zverovich7cae7632013-09-06 20:23:42 -0700700template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800701 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700702
Victor Zverovich7cae7632013-09-06 20:23:42 -0700703template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800704 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700705
Victor Zverovich7cae7632013-09-06 20:23:42 -0700706template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700707 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
708 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700709
Victor Zverovich7cae7632013-09-06 20:23:42 -0700710template void fmt::BasicWriter<wchar_t>::FormatDecimal(
711 CharPtr buffer, uint64_t value, unsigned num_digits);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700712
Victor Zverovich7cae7632013-09-06 20:23:42 -0700713template fmt::BasicWriter<wchar_t>::CharPtr
714 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800715 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700716
Victor Zverovich7cae7632013-09-06 20:23:42 -0700717template void fmt::BasicFormatter<wchar_t>::ReportError(
718 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700719
Victor Zverovich7cae7632013-09-06 20:23:42 -0700720template unsigned fmt::BasicFormatter<wchar_t>::ParseUInt(
721 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700722
Victor Zverovich7cae7632013-09-06 20:23:42 -0700723template const fmt::BasicFormatter<wchar_t>::Arg
724 &fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700725
Victor Zverovich7cae7632013-09-06 20:23:42 -0700726template void fmt::BasicFormatter<wchar_t>::CheckSign(
727 const wchar_t *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700728
Victor Zverovich7cae7632013-09-06 20:23:42 -0700729template void fmt::BasicFormatter<wchar_t>::DoFormat();