blob: d62820b730fea6a480170a425d2913a8e81f0ac4 [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) {
399 if (arg.type > LAST_NUMERIC_TYPE) {
400 ReportError(s,
401 Format("format specifier '{0}' requires numeric argument") << *s);
402 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800403 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700404 ReportError(s,
405 Format("format specifier '{0}' requires signed argument") << *s);
406 }
407 ++s;
408}
409
410template <typename Char>
411void fmt::BasicFormatter<Char>::DoFormat() {
412 const Char *start = format_;
413 format_ = 0;
414 next_arg_index_ = 0;
415 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700416 BasicWriter<Char> &writer = *writer_;
417 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700418 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700419 if (c != '{' && c != '}') continue;
420 if (*s == c) {
421 writer.buffer_.append(start, s);
422 start = ++s;
423 continue;
424 }
425 if (c == '}')
426 throw FormatError("unmatched '}' in format");
427 num_open_braces_= 1;
428 writer.buffer_.append(start, s - 1);
429
430 const Arg &arg = ParseArgIndex(s);
431
432 FormatSpec spec;
433 int precision = -1;
434 if (*s == ':') {
435 ++s;
436
437 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700438 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700439 const Char *p = s + 1;
440 spec.align_ = ALIGN_DEFAULT;
441 do {
442 switch (*p) {
443 case '<':
444 spec.align_ = ALIGN_LEFT;
445 break;
446 case '>':
447 spec.align_ = ALIGN_RIGHT;
448 break;
449 case '=':
450 spec.align_ = ALIGN_NUMERIC;
451 break;
452 case '^':
453 spec.align_ = ALIGN_CENTER;
454 break;
455 }
456 if (spec.align_ != ALIGN_DEFAULT) {
457 if (p != s) {
458 if (c == '}') break;
459 if (c == '{')
460 ReportError(s, "invalid fill character '{'");
461 s += 2;
462 spec.fill_ = c;
463 } else ++s;
464 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
465 ReportError(s, "format specifier '=' requires numeric argument");
466 break;
467 }
468 } while (--p >= s);
469 }
470
471 // Parse sign.
472 switch (*s) {
473 case '+':
474 CheckSign(s, arg);
475 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
476 break;
477 case '-':
478 CheckSign(s, arg);
479 break;
480 case ' ':
481 CheckSign(s, arg);
482 spec.flags_ |= SIGN_FLAG;
483 break;
484 }
485
486 if (*s == '#') {
487 if (arg.type > LAST_NUMERIC_TYPE)
488 ReportError(s, "format specifier '#' requires numeric argument");
489 spec.flags_ |= HASH_FLAG;
490 ++s;
491 }
492
493 // Parse width and zero flag.
494 if ('0' <= *s && *s <= '9') {
495 if (*s == '0') {
496 if (arg.type > LAST_NUMERIC_TYPE)
497 ReportError(s, "format specifier '0' requires numeric argument");
498 spec.align_ = ALIGN_NUMERIC;
499 spec.fill_ = '0';
500 }
501 // Zero may be parsed again as a part of the width, but it is simpler
502 // and more efficient than checking if the next char is a digit.
503 unsigned value = ParseUInt(s);
504 if (value > INT_MAX)
505 ReportError(s, "number is too big in format");
506 spec.width_ = value;
507 }
508
509 // Parse precision.
510 if (*s == '.') {
511 ++s;
512 precision = 0;
513 if ('0' <= *s && *s <= '9') {
514 unsigned value = ParseUInt(s);
515 if (value > INT_MAX)
516 ReportError(s, "number is too big in format");
517 precision = value;
518 } else if (*s == '{') {
519 ++s;
520 ++num_open_braces_;
521 const Arg &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800522 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700523 switch (precision_arg.type) {
524 case INT:
525 if (precision_arg.int_value < 0)
526 ReportError(s, "negative precision in format");
527 value = precision_arg.int_value;
528 break;
529 case UINT:
530 value = precision_arg.uint_value;
531 break;
532 case LONG:
533 if (precision_arg.long_value < 0)
534 ReportError(s, "negative precision in format");
535 value = precision_arg.long_value;
536 break;
537 case ULONG:
538 value = precision_arg.ulong_value;
539 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800540 case LONG_LONG:
541 if (precision_arg.long_long_value < 0)
542 ReportError(s, "negative precision in format");
543 value = precision_arg.long_long_value;
544 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800545 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800546 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800547 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700548 default:
549 ReportError(s, "precision is not integer");
550 }
551 if (value > INT_MAX)
552 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800553 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700554 if (*s++ != '}')
555 throw FormatError("unmatched '{' in format");
556 --num_open_braces_;
557 } else {
558 ReportError(s, "missing precision in format");
559 }
560 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
561 ReportError(s,
562 "precision specifier requires floating-point argument");
563 }
564 }
565
566 // Parse type.
567 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700568 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700569 }
570
571 if (*s++ != '}')
572 throw FormatError("unmatched '{' in format");
573 start = s;
574
575 // Format argument.
576 switch (arg.type) {
577 case INT:
578 writer.FormatInt(arg.int_value, spec);
579 break;
580 case UINT:
581 writer.FormatInt(arg.uint_value, spec);
582 break;
583 case LONG:
584 writer.FormatInt(arg.long_value, spec);
585 break;
586 case ULONG:
587 writer.FormatInt(arg.ulong_value, spec);
588 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800589 case LONG_LONG:
590 writer.FormatInt(arg.long_long_value, spec);
591 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800592 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800593 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800594 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700595 case DOUBLE:
596 writer.FormatDouble(arg.double_value, spec, precision);
597 break;
598 case LONG_DOUBLE:
599 writer.FormatDouble(arg.long_double_value, spec, precision);
600 break;
601 case CHAR: {
602 if (spec.type_ && spec.type_ != 'c')
603 internal::ReportUnknownType(spec.type_, "char");
604 typedef typename BasicWriter<Char>::CharPtr CharPtr;
605 CharPtr out = CharPtr();
606 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700607 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700608 out = writer.GrowBuffer(spec.width_);
609 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700610 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700611 out += spec.width_ - 1;
612 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700613 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700614 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700615 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700616 }
617 } else {
618 out = writer.GrowBuffer(1);
619 }
620 *out = arg.int_value;
621 break;
622 }
623 case STRING: {
624 if (spec.type_ && spec.type_ != 's')
625 internal::ReportUnknownType(spec.type_, "string");
626 const Char *str = arg.string.value;
627 std::size_t size = arg.string.size;
628 if (size == 0) {
629 if (!str)
630 throw FormatError("string pointer is null");
631 if (*str)
632 size = std::char_traits<Char>::length(str);
633 }
634 writer.FormatString(str, size, spec);
635 break;
636 }
637 case POINTER:
638 if (spec.type_ && spec.type_ != 'p')
639 internal::ReportUnknownType(spec.type_, "pointer");
640 spec.flags_= HASH_FLAG;
641 spec.type_ = 'x';
642 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
643 break;
644 case CUSTOM:
645 if (spec.type_)
646 internal::ReportUnknownType(spec.type_, "object");
647 arg.custom.format(writer, arg.custom.value, spec);
648 break;
649 default:
650 assert(false);
651 break;
652 }
653 }
654 writer.buffer_.append(start, s);
655}
656
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700657// Explicit instantiations for char.
658
Victor Zverovich7cae7632013-09-06 20:23:42 -0700659template void fmt::BasicWriter<char>::FormatDouble<double>(
660 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700661
Victor Zverovich7cae7632013-09-06 20:23:42 -0700662template void fmt::BasicWriter<char>::FormatDouble<long double>(
663 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700664
Victor Zverovich93e41252013-09-08 13:07:04 -0700665template fmt::BasicWriter<char>::CharPtr
666 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
667 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700668
Victor Zverovich7cae7632013-09-06 20:23:42 -0700669template void fmt::BasicWriter<char>::FormatDecimal(
670 CharPtr buffer, uint64_t value, unsigned num_digits);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700671
Victor Zverovich7cae7632013-09-06 20:23:42 -0700672template fmt::BasicWriter<char>::CharPtr
673 fmt::BasicWriter<char>::PrepareFilledBuffer(
674 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700675
Victor Zverovich7cae7632013-09-06 20:23:42 -0700676template void fmt::BasicFormatter<char>::ReportError(
677 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700678
Victor Zverovich7cae7632013-09-06 20:23:42 -0700679template unsigned fmt::BasicFormatter<char>::ParseUInt(const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700680
Victor Zverovich7cae7632013-09-06 20:23:42 -0700681template const fmt::BasicFormatter<char>::Arg
682 &fmt::BasicFormatter<char>::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700683
Victor Zverovich7cae7632013-09-06 20:23:42 -0700684template void fmt::BasicFormatter<char>::CheckSign(
685 const char *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700686
Victor Zverovich7cae7632013-09-06 20:23:42 -0700687template void fmt::BasicFormatter<char>::DoFormat();
688
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700689// Explicit instantiations for wchar_t.
690
Victor Zverovich7cae7632013-09-06 20:23:42 -0700691template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
692 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700693
Victor Zverovich7cae7632013-09-06 20:23:42 -0700694template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
695 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700696
Victor Zverovich7cae7632013-09-06 20:23:42 -0700697template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700698 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
699 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700700
Victor Zverovich7cae7632013-09-06 20:23:42 -0700701template void fmt::BasicWriter<wchar_t>::FormatDecimal(
702 CharPtr buffer, uint64_t value, unsigned num_digits);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700703
Victor Zverovich7cae7632013-09-06 20:23:42 -0700704template fmt::BasicWriter<wchar_t>::CharPtr
705 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
706 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700707
Victor Zverovich7cae7632013-09-06 20:23:42 -0700708template void fmt::BasicFormatter<wchar_t>::ReportError(
709 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700710
Victor Zverovich7cae7632013-09-06 20:23:42 -0700711template unsigned fmt::BasicFormatter<wchar_t>::ParseUInt(
712 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700713
Victor Zverovich7cae7632013-09-06 20:23:42 -0700714template const fmt::BasicFormatter<wchar_t>::Arg
715 &fmt::BasicFormatter<wchar_t>::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700716
Victor Zverovich7cae7632013-09-06 20:23:42 -0700717template void fmt::BasicFormatter<wchar_t>::CheckSign(
718 const wchar_t *&s, const Arg &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700719
Victor Zverovich7cae7632013-09-06 20:23:42 -0700720template void fmt::BasicFormatter<wchar_t>::DoFormat();