blob: b29be0074141b07701d80925cf8be2ec27d2635c [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>
38
39namespace {
40
41#ifndef _MSC_VER
42
43inline int SignBit(double value) {
44 // When compiled in C++11 mode signbit is no longer a macro but a function
45 // defined in namespace std and the macro is undefined.
46 using namespace std;
47 return signbit(value);
48}
49
50inline int IsInf(double x) {
51#ifdef isinf
52 return isinf(x);
53#else
54 return std::isinf(x);
55#endif
56}
57
58#define FMT_SNPRINTF snprintf
59
60#else
61
62inline int SignBit(double value) {
63 if (value < 0) return 1;
64 if (value == value) return 0;
65 int dec = 0, sign = 0;
66 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
67 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
68 return sign;
69}
70
71inline int IsInf(double x) { return !_finite(x); }
72
73#define FMT_SNPRINTF sprintf_s
74
75#endif // _MSC_VER
Victor Zverovichb605b392013-09-09 22:21:40 -070076}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070077
Victor Zverovichb605b392013-09-09 22:21:40 -070078template <typename T>
79int fmt::internal::CharTraits<char>::FormatFloat(
80 char *buffer, std::size_t size, const char *format,
81 unsigned width, int precision, T value) {
82 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -070083 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -070084 FMT_SNPRINTF(buffer, size, format, value) :
85 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -070086 }
Victor Zverovichb605b392013-09-09 22:21:40 -070087 return precision < 0 ?
88 FMT_SNPRINTF(buffer, size, format, width, value) :
89 FMT_SNPRINTF(buffer, size, format, width, precision, value);
90}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070091
Victor Zverovichb605b392013-09-09 22:21:40 -070092template <typename T>
93int fmt::internal::CharTraits<wchar_t>::FormatFloat(
94 wchar_t *buffer, std::size_t size, const wchar_t *format,
95 unsigned width, int precision, T value) {
96 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -070097 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -070098 swprintf(buffer, size, format, value) :
99 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700100 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700101 return precision < 0 ?
102 swprintf(buffer, size, format, width, value) :
103 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700104}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800105
Victor Zverovich65d47e52013-09-09 06:51:03 -0700106const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800107 "0001020304050607080910111213141516171819"
108 "2021222324252627282930313233343536373839"
109 "4041424344454647484950515253545556575859"
110 "6061626364656667686970717273747576777879"
111 "8081828384858687888990919293949596979899";
Victor Zverovich877abaf2013-01-08 09:56:05 -0800112
Victor Zverovich687301c2013-01-26 16:07:28 -0800113void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800114 if (std::isprint(static_cast<unsigned char>(code))) {
115 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800116 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800117 }
118 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800119 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800120 << static_cast<unsigned>(code) << type));
121}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700122
123
124// Fills the padding around the content and returns the pointer to the
125// content area.
126template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700127typename fmt::BasicWriter<Char>::CharPtr
128 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
129 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700130 std::size_t padding = total_size - content_size;
131 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700132 Char fill_char = static_cast<Char>(fill);
133 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700134 buffer += left_padding;
135 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700136 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700137 return content;
138}
139
140template <typename Char>
141void fmt::BasicWriter<Char>::FormatDecimal(
142 CharPtr buffer, uint64_t value, unsigned num_digits) {
143 --num_digits;
144 while (value >= 100) {
145 // Integer division is slow so do it for a group of two digits instead
146 // of for every digit. The idea comes from the talk by Alexandrescu
147 // "Three Optimization Tips for C++". See speed-test for a comparison.
148 unsigned index = (value % 100) * 2;
149 value /= 100;
Victor Zverovich65d47e52013-09-09 06:51:03 -0700150 buffer[num_digits] = internal::DIGITS[index + 1];
151 buffer[num_digits - 1] = internal::DIGITS[index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700152 num_digits -= 2;
153 }
154 if (value < 10) {
155 *buffer = static_cast<char>('0' + value);
156 return;
157 }
158 unsigned index = static_cast<unsigned>(value * 2);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700159 buffer[1] = internal::DIGITS[index + 1];
160 buffer[0] = internal::DIGITS[index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700161}
162
163template <typename Char>
164typename fmt::BasicWriter<Char>::CharPtr
165 fmt::BasicWriter<Char>::PrepareFilledBuffer(
166 unsigned size, const AlignSpec &spec, char sign) {
167 unsigned width = spec.width();
168 if (width <= size) {
169 CharPtr p = GrowBuffer(size);
170 *p = sign;
171 return p + size - 1;
172 }
173 CharPtr p = GrowBuffer(width);
174 CharPtr end = p + width;
175 Alignment align = spec.align();
Victor Zverovich563a5752013-09-08 13:47:06 -0700176 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700177 if (align == ALIGN_LEFT) {
178 *p = sign;
179 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700180 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700181 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700182 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700183 *p = sign;
184 p += size;
185 } else {
186 if (align == ALIGN_NUMERIC) {
187 if (sign) {
188 *p++ = sign;
189 --size;
190 }
191 } else {
192 *(end - size) = sign;
193 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700194 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700195 p = end;
196 }
197 return p - 1;
198}
199
200template <typename Char>
201template <typename T>
202void fmt::BasicWriter<Char>::FormatDouble(
203 T value, const FormatSpec &spec, int precision) {
204 // Check type.
205 char type = spec.type();
206 bool upper = false;
207 switch (type) {
208 case 0:
209 type = 'g';
210 break;
211 case 'e': case 'f': case 'g':
212 break;
213 case 'F':
214#ifdef _MSC_VER
215 // MSVC's printf doesn't support 'F'.
216 type = 'f';
217#endif
218 // Fall through.
219 case 'E': case 'G':
220 upper = true;
221 break;
222 default:
223 internal::ReportUnknownType(type, "double");
224 break;
225 }
226
227 char sign = 0;
228 // Use SignBit instead of value < 0 because the latter is always
229 // false for NaN.
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700230 if (SignBit(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700231 sign = '-';
232 value = -value;
233 } else if (spec.sign_flag()) {
234 sign = spec.plus_flag() ? '+' : ' ';
235 }
236
237 if (value != value) {
238 // Format NaN ourselves because sprintf's output is not consistent
239 // across platforms.
240 std::size_t size = 4;
241 const char *nan = upper ? " NAN" : " nan";
242 if (!sign) {
243 --size;
244 ++nan;
245 }
246 CharPtr out = FormatString(nan, size, spec);
247 if (sign)
248 *out = sign;
249 return;
250 }
251
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700252 if (IsInf(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700253 // Format infinity ourselves because sprintf's output is not consistent
254 // across platforms.
255 std::size_t size = 4;
256 const char *inf = upper ? " INF" : " inf";
257 if (!sign) {
258 --size;
259 ++inf;
260 }
261 CharPtr out = FormatString(inf, size, spec);
262 if (sign)
263 *out = sign;
264 return;
265 }
266
267 std::size_t offset = buffer_.size();
268 unsigned width = spec.width();
269 if (sign) {
270 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
271 if (width > 0)
272 --width;
273 ++offset;
274 }
275
276 // Build format string.
277 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
278 Char format[MAX_FORMAT_SIZE];
279 Char *format_ptr = format;
280 *format_ptr++ = '%';
281 unsigned width_for_sprintf = width;
282 if (spec.hash_flag())
283 *format_ptr++ = '#';
284 if (spec.align() == ALIGN_CENTER) {
285 width_for_sprintf = 0;
286 } else {
287 if (spec.align() == ALIGN_LEFT)
288 *format_ptr++ = '-';
289 if (width != 0)
290 *format_ptr++ = '*';
291 }
292 if (precision >= 0) {
293 *format_ptr++ = '.';
294 *format_ptr++ = '*';
295 }
296 if (internal::IsLongDouble<T>::VALUE)
297 *format_ptr++ = 'L';
298 *format_ptr++ = type;
299 *format_ptr = '\0';
300
301 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700302 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700303 for (;;) {
304 std::size_t size = buffer_.capacity() - offset;
305 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700306 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700307 start, size, format, width_for_sprintf, precision, value);
308 if (n >= 0 && offset + n < buffer_.capacity()) {
309 if (sign) {
310 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
311 *start != ' ') {
312 *(start - 1) = sign;
313 sign = 0;
314 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700315 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700316 }
317 ++n;
318 }
319 if (spec.align() == ALIGN_CENTER &&
320 spec.width() > static_cast<unsigned>(n)) {
321 unsigned width = spec.width();
322 CharPtr p = GrowBuffer(width);
323 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700324 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700325 return;
326 }
327 if (spec.fill() != ' ' || sign) {
328 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700329 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700330 if (sign)
331 *(start - 1) = sign;
332 }
333 GrowBuffer(n);
334 return;
335 }
336 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
337 }
338}
339
340// Throws Exception(message) if format contains '}', otherwise throws
341// FormatError reporting unmatched '{'. The idea is that unmatched '{'
342// should override other errors.
343template <typename Char>
344void fmt::BasicFormatter<Char>::ReportError(
345 const Char *s, StringRef message) const {
346 for (int num_open_braces = num_open_braces_; *s; ++s) {
347 if (*s == '{') {
348 ++num_open_braces;
349 } else if (*s == '}') {
350 if (--num_open_braces == 0)
351 throw fmt::FormatError(message);
352 }
353 }
354 throw fmt::FormatError("unmatched '{' in format");
355}
356
357// Parses an unsigned integer advancing s to the end of the parsed input.
358// This function assumes that the first character of s is a digit.
359template <typename Char>
360unsigned fmt::BasicFormatter<Char>::ParseUInt(const Char *&s) const {
361 assert('0' <= *s && *s <= '9');
362 unsigned value = 0;
363 do {
364 unsigned new_value = value * 10 + (*s++ - '0');
365 if (new_value < value) // Check if value wrapped around.
366 ReportError(s, "number is too big in format");
367 value = new_value;
368 } while ('0' <= *s && *s <= '9');
369 return value;
370}
371
372template <typename Char>
373inline const typename fmt::BasicFormatter<Char>::Arg
374 &fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
375 unsigned arg_index = 0;
376 if (*s < '0' || *s > '9') {
377 if (*s != '}' && *s != ':')
378 ReportError(s, "invalid argument index in format string");
379 if (next_arg_index_ < 0) {
380 ReportError(s,
381 "cannot switch from manual to automatic argument indexing");
382 }
383 arg_index = next_arg_index_++;
384 } else {
385 if (next_arg_index_ > 0) {
386 ReportError(s,
387 "cannot switch from automatic to manual argument indexing");
388 }
389 next_arg_index_ = -1;
390 arg_index = ParseUInt(s);
391 }
392 if (arg_index >= args_.size())
393 ReportError(s, "argument index is out of range in format");
394 return *args_[arg_index];
395}
396
397template <typename Char>
398void fmt::BasicFormatter<Char>::CheckSign(const Char *&s, const Arg &arg) {
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800399 char sign = *s;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700400 if (arg.type > LAST_NUMERIC_TYPE) {
401 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800402 Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700403 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800404 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700405 ReportError(s,
Victor Zveroviche3b4a3f2013-12-07 08:12:03 -0800406 Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700407 }
408 ++s;
409}
410
411template <typename Char>
412void fmt::BasicFormatter<Char>::DoFormat() {
413 const Char *start = format_;
414 format_ = 0;
415 next_arg_index_ = 0;
416 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700417 BasicWriter<Char> &writer = *writer_;
418 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700419 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700420 if (c != '{' && c != '}') continue;
421 if (*s == c) {
422 writer.buffer_.append(start, s);
423 start = ++s;
424 continue;
425 }
426 if (c == '}')
427 throw FormatError("unmatched '}' in format");
428 num_open_braces_= 1;
429 writer.buffer_.append(start, s - 1);
430
431 const Arg &arg = ParseArgIndex(s);
432
433 FormatSpec spec;
434 int precision = -1;
435 if (*s == ':') {
436 ++s;
437
438 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700439 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700440 const Char *p = s + 1;
441 spec.align_ = ALIGN_DEFAULT;
442 do {
443 switch (*p) {
444 case '<':
445 spec.align_ = ALIGN_LEFT;
446 break;
447 case '>':
448 spec.align_ = ALIGN_RIGHT;
449 break;
450 case '=':
451 spec.align_ = ALIGN_NUMERIC;
452 break;
453 case '^':
454 spec.align_ = ALIGN_CENTER;
455 break;
456 }
457 if (spec.align_ != ALIGN_DEFAULT) {
458 if (p != s) {
459 if (c == '}') break;
460 if (c == '{')
461 ReportError(s, "invalid fill character '{'");
462 s += 2;
463 spec.fill_ = c;
464 } else ++s;
465 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
466 ReportError(s, "format specifier '=' requires numeric argument");
467 break;
468 }
469 } while (--p >= s);
470 }
471
472 // Parse sign.
473 switch (*s) {
474 case '+':
475 CheckSign(s, arg);
476 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
477 break;
478 case '-':
479 CheckSign(s, arg);
480 break;
481 case ' ':
482 CheckSign(s, arg);
483 spec.flags_ |= SIGN_FLAG;
484 break;
485 }
486
487 if (*s == '#') {
488 if (arg.type > LAST_NUMERIC_TYPE)
489 ReportError(s, "format specifier '#' requires numeric argument");
490 spec.flags_ |= HASH_FLAG;
491 ++s;
492 }
493
494 // Parse width and zero flag.
495 if ('0' <= *s && *s <= '9') {
496 if (*s == '0') {
497 if (arg.type > LAST_NUMERIC_TYPE)
498 ReportError(s, "format specifier '0' requires numeric argument");
499 spec.align_ = ALIGN_NUMERIC;
500 spec.fill_ = '0';
501 }
502 // Zero may be parsed again as a part of the width, but it is simpler
503 // and more efficient than checking if the next char is a digit.
504 unsigned value = ParseUInt(s);
505 if (value > INT_MAX)
506 ReportError(s, "number is too big in format");
507 spec.width_ = value;
508 }
509
510 // Parse precision.
511 if (*s == '.') {
512 ++s;
513 precision = 0;
514 if ('0' <= *s && *s <= '9') {
515 unsigned value = ParseUInt(s);
516 if (value > INT_MAX)
517 ReportError(s, "number is too big in format");
518 precision = value;
519 } else if (*s == '{') {
520 ++s;
521 ++num_open_braces_;
522 const Arg &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800523 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700524 switch (precision_arg.type) {
525 case INT:
526 if (precision_arg.int_value < 0)
527 ReportError(s, "negative precision in format");
528 value = precision_arg.int_value;
529 break;
530 case UINT:
531 value = precision_arg.uint_value;
532 break;
533 case LONG:
534 if (precision_arg.long_value < 0)
535 ReportError(s, "negative precision in format");
536 value = precision_arg.long_value;
537 break;
538 case ULONG:
539 value = precision_arg.ulong_value;
540 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800541 case LONG_LONG:
542 if (precision_arg.long_long_value < 0)
543 ReportError(s, "negative precision in format");
544 value = precision_arg.long_long_value;
545 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800546 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800547 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800548 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700549 default:
550 ReportError(s, "precision is not integer");
551 }
552 if (value > INT_MAX)
553 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800554 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700555 if (*s++ != '}')
556 throw FormatError("unmatched '{' in format");
557 --num_open_braces_;
558 } else {
559 ReportError(s, "missing precision in format");
560 }
561 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
562 ReportError(s,
563 "precision specifier requires floating-point argument");
564 }
565 }
566
567 // Parse type.
568 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700569 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700570 }
571
572 if (*s++ != '}')
573 throw FormatError("unmatched '{' in format");
574 start = s;
575
576 // Format argument.
577 switch (arg.type) {
578 case INT:
579 writer.FormatInt(arg.int_value, spec);
580 break;
581 case UINT:
582 writer.FormatInt(arg.uint_value, spec);
583 break;
584 case LONG:
585 writer.FormatInt(arg.long_value, spec);
586 break;
587 case ULONG:
588 writer.FormatInt(arg.ulong_value, spec);
589 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800590 case LONG_LONG:
591 writer.FormatInt(arg.long_long_value, spec);
592 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800593 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800594 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800595 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700596 case DOUBLE:
597 writer.FormatDouble(arg.double_value, spec, precision);
598 break;
599 case LONG_DOUBLE:
600 writer.FormatDouble(arg.long_double_value, spec, precision);
601 break;
602 case CHAR: {
603 if (spec.type_ && spec.type_ != 'c')
604 internal::ReportUnknownType(spec.type_, "char");
605 typedef typename BasicWriter<Char>::CharPtr CharPtr;
606 CharPtr out = CharPtr();
607 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700608 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700609 out = writer.GrowBuffer(spec.width_);
610 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700611 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700612 out += spec.width_ - 1;
613 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700614 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700615 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700616 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700617 }
618 } else {
619 out = writer.GrowBuffer(1);
620 }
621 *out = arg.int_value;
622 break;
623 }
624 case STRING: {
625 if (spec.type_ && spec.type_ != 's')
626 internal::ReportUnknownType(spec.type_, "string");
627 const Char *str = arg.string.value;
628 std::size_t size = arg.string.size;
629 if (size == 0) {
630 if (!str)
631 throw FormatError("string pointer is null");
632 if (*str)
633 size = std::char_traits<Char>::length(str);
634 }
635 writer.FormatString(str, size, spec);
636 break;
637 }
638 case POINTER:
639 if (spec.type_ && spec.type_ != 'p')
640 internal::ReportUnknownType(spec.type_, "pointer");
641 spec.flags_= HASH_FLAG;
642 spec.type_ = 'x';
643 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
644 break;
645 case CUSTOM:
646 if (spec.type_)
647 internal::ReportUnknownType(spec.type_, "object");
648 arg.custom.format(writer, arg.custom.value, spec);
649 break;
650 default:
651 assert(false);
652 break;
653 }
654 }
655 writer.buffer_.append(start, s);
656}
657
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700658// Explicit instantiations for char.
659
Victor Zverovich7cae7632013-09-06 20:23:42 -0700660template void fmt::BasicWriter<char>::FormatDouble<double>(
661 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700662
Victor Zverovich7cae7632013-09-06 20:23:42 -0700663template void fmt::BasicWriter<char>::FormatDouble<long double>(
664 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700665
Victor Zverovich93e41252013-09-08 13:07:04 -0700666template fmt::BasicWriter<char>::CharPtr
667 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
668 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700669
Victor Zverovich7cae7632013-09-06 20:23:42 -0700670template void fmt::BasicWriter<char>::FormatDecimal(
671 CharPtr buffer, uint64_t value, unsigned num_digits);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700672
Victor Zverovich7cae7632013-09-06 20:23:42 -0700673template fmt::BasicWriter<char>::CharPtr
674 fmt::BasicWriter<char>::PrepareFilledBuffer(
675 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700676
Victor Zverovich7cae7632013-09-06 20:23:42 -0700677template void fmt::BasicFormatter<char>::ReportError(
678 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700679
Victor Zverovich7cae7632013-09-06 20:23:42 -0700680template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700681
Victor Zverovich7cae7632013-09-06 20:23:42 -0700682template const fmt::BasicFormatter<char>::Arg
683 &fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700684
Victor Zverovich7cae7632013-09-06 20:23:42 -0700685template void fmt::BasicFormatter<char>::CheckSign(
686 const char *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700687
Victor Zverovich7cae7632013-09-06 20:23:42 -0700688template void fmt::BasicFormatter<char>::DoFormat();
689
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700690// Explicit instantiations for wchar_t.
691
Victor Zverovich7cae7632013-09-06 20:23:42 -0700692template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
693 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700694
Victor Zverovich7cae7632013-09-06 20:23:42 -0700695template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
696 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700697
Victor Zverovich7cae7632013-09-06 20:23:42 -0700698template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700699 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
700 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700701
Victor Zverovich7cae7632013-09-06 20:23:42 -0700702template void fmt::BasicWriter<wchar_t>::FormatDecimal(
703 CharPtr buffer, uint64_t value, unsigned num_digits);
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(
707 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();