blob: ab2a0ea3c4fc6e0ce5e328ee155857df6bfd5c61 [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
jdale88a9862fd2014-03-11 18:56:24 +000042#if _MSC_VER
43# pragma warning(push)
44# pragma warning(disable: 4127) // conditional expression is constant
45#endif
46
Victor Zverovich9ff3b972013-09-07 10:15:08 -070047namespace {
48
49#ifndef _MSC_VER
50
51inline int SignBit(double value) {
52 // When compiled in C++11 mode signbit is no longer a macro but a function
53 // defined in namespace std and the macro is undefined.
Victor Zverovichf2e06802014-04-10 10:49:55 -070054#ifdef signbit
Victor Zverovich9ff3b972013-09-07 10:15:08 -070055 return signbit(value);
Victor Zverovichf2e06802014-04-10 10:49:55 -070056#else
57 return std::signbit(value);
58#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070059}
60
61inline int IsInf(double x) {
62#ifdef isinf
63 return isinf(x);
64#else
65 return std::isinf(x);
66#endif
67}
68
69#define FMT_SNPRINTF snprintf
70
Victor Zverovicha684d0c2013-12-27 08:00:10 -080071#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070072
73inline int SignBit(double value) {
74 if (value < 0) return 1;
75 if (value == value) return 0;
76 int dec = 0, sign = 0;
77 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
78 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
79 return sign;
80}
81
82inline int IsInf(double x) { return !_finite(x); }
83
Victor Zverovicha684d0c2013-12-27 08:00:10 -080084inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
85 va_list args;
86 va_start(args, format);
87 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
88 va_end(args);
89 return result;
90}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070091
92#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -080093
94const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovichb605b392013-09-09 22:21:40 -070095}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070096
Victor Zverovichb605b392013-09-09 22:21:40 -070097template <typename T>
98int fmt::internal::CharTraits<char>::FormatFloat(
99 char *buffer, std::size_t size, const char *format,
100 unsigned width, int precision, T value) {
101 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700102 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700103 FMT_SNPRINTF(buffer, size, format, value) :
104 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700105 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700106 return precision < 0 ?
107 FMT_SNPRINTF(buffer, size, format, width, value) :
108 FMT_SNPRINTF(buffer, size, format, width, precision, value);
109}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700110
Victor Zverovichb605b392013-09-09 22:21:40 -0700111template <typename T>
112int fmt::internal::CharTraits<wchar_t>::FormatFloat(
113 wchar_t *buffer, std::size_t size, const wchar_t *format,
114 unsigned width, int precision, T value) {
115 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700116 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700117 swprintf(buffer, size, format, value) :
118 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700119 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700120 return precision < 0 ?
121 swprintf(buffer, size, format, width, value) :
122 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700123}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800124
Victor Zverovich65d47e52013-09-09 06:51:03 -0700125const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800126 "0001020304050607080910111213141516171819"
127 "2021222324252627282930313233343536373839"
128 "4041424344454647484950515253545556575859"
129 "6061626364656667686970717273747576777879"
130 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800131
Victor Zverovichf1d85162014-02-19 13:02:22 -0800132#define FMT_POWERS_OF_10(factor) \
133 factor * 10, \
134 factor * 100, \
135 factor * 1000, \
136 factor * 10000, \
137 factor * 100000, \
138 factor * 1000000, \
139 factor * 10000000, \
140 factor * 100000000, \
141 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800142
Victor Zverovichf1d85162014-02-19 13:02:22 -0800143const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800144const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800145 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800146 FMT_POWERS_OF_10(1),
147 FMT_POWERS_OF_10(ULongLong(1000000000)),
148 // Multiply several constants instead of using a single long long constants
149 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800150 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800151};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800152
Victor Zverovich687301c2013-01-26 16:07:28 -0800153void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800154 if (std::isprint(static_cast<unsigned char>(code))) {
155 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800156 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800157 }
158 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800159 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800160 << static_cast<unsigned>(code) << type));
161}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700162
163
164// Fills the padding around the content and returns the pointer to the
165// content area.
166template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700167typename fmt::BasicWriter<Char>::CharPtr
168 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
169 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700170 std::size_t padding = total_size - content_size;
171 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700172 Char fill_char = static_cast<Char>(fill);
173 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700174 buffer += left_padding;
175 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700176 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700177 return content;
178}
179
180template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700181typename fmt::BasicWriter<Char>::CharPtr
182 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800183 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700184 unsigned width = spec.width();
185 if (width <= size) {
186 CharPtr p = GrowBuffer(size);
187 *p = sign;
188 return p + size - 1;
189 }
190 CharPtr p = GrowBuffer(width);
191 CharPtr end = p + width;
192 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800193 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700194 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700195 if (align == ALIGN_LEFT) {
196 *p = sign;
197 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700198 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700199 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700200 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700201 *p = sign;
202 p += size;
203 } else {
204 if (align == ALIGN_NUMERIC) {
205 if (sign) {
206 *p++ = sign;
207 --size;
208 }
209 } else {
210 *(end - size) = sign;
211 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700212 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700213 p = end;
214 }
215 return p - 1;
216}
217
218template <typename Char>
219template <typename T>
220void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800221 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700222 // Check type.
223 char type = spec.type();
224 bool upper = false;
225 switch (type) {
226 case 0:
227 type = 'g';
228 break;
229 case 'e': case 'f': case 'g':
230 break;
231 case 'F':
232#ifdef _MSC_VER
233 // MSVC's printf doesn't support 'F'.
234 type = 'f';
235#endif
236 // Fall through.
237 case 'E': case 'G':
238 upper = true;
239 break;
240 default:
241 internal::ReportUnknownType(type, "double");
242 break;
243 }
244
245 char sign = 0;
246 // Use SignBit instead of value < 0 because the latter is always
247 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000248 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700249 sign = '-';
250 value = -value;
251 } else if (spec.sign_flag()) {
252 sign = spec.plus_flag() ? '+' : ' ';
253 }
254
255 if (value != value) {
256 // Format NaN ourselves because sprintf's output is not consistent
257 // across platforms.
258 std::size_t size = 4;
259 const char *nan = upper ? " NAN" : " nan";
260 if (!sign) {
261 --size;
262 ++nan;
263 }
264 CharPtr out = FormatString(nan, size, spec);
265 if (sign)
266 *out = sign;
267 return;
268 }
269
jdale88a9862fd2014-03-11 18:56:24 +0000270 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700271 // Format infinity ourselves because sprintf's output is not consistent
272 // across platforms.
273 std::size_t size = 4;
274 const char *inf = upper ? " INF" : " inf";
275 if (!sign) {
276 --size;
277 ++inf;
278 }
279 CharPtr out = FormatString(inf, size, spec);
280 if (sign)
281 *out = sign;
282 return;
283 }
284
285 std::size_t offset = buffer_.size();
286 unsigned width = spec.width();
287 if (sign) {
288 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
289 if (width > 0)
290 --width;
291 ++offset;
292 }
293
294 // Build format string.
295 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
296 Char format[MAX_FORMAT_SIZE];
297 Char *format_ptr = format;
298 *format_ptr++ = '%';
299 unsigned width_for_sprintf = width;
300 if (spec.hash_flag())
301 *format_ptr++ = '#';
302 if (spec.align() == ALIGN_CENTER) {
303 width_for_sprintf = 0;
304 } else {
305 if (spec.align() == ALIGN_LEFT)
306 *format_ptr++ = '-';
307 if (width != 0)
308 *format_ptr++ = '*';
309 }
310 if (precision >= 0) {
311 *format_ptr++ = '.';
312 *format_ptr++ = '*';
313 }
314 if (internal::IsLongDouble<T>::VALUE)
315 *format_ptr++ = 'L';
316 *format_ptr++ = type;
317 *format_ptr = '\0';
318
319 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700320 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700321 for (;;) {
322 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700323#if _MSC_VER
324 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
325 // space for at least one extra character to make the size non-zero.
326 // Note that the buffer's capacity will increase by more than 1.
327 if (size == 0) {
328 buffer_.reserve(offset + 1);
329 size = buffer_.capacity() - offset;
330 }
331#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700332 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700333 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700334 start, size, format, width_for_sprintf, precision, value);
335 if (n >= 0 && offset + n < buffer_.capacity()) {
336 if (sign) {
337 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
338 *start != ' ') {
339 *(start - 1) = sign;
340 sign = 0;
341 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700342 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700343 }
344 ++n;
345 }
346 if (spec.align() == ALIGN_CENTER &&
347 spec.width() > static_cast<unsigned>(n)) {
348 unsigned width = spec.width();
349 CharPtr p = GrowBuffer(width);
350 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700351 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700352 return;
353 }
354 if (spec.fill() != ' ' || sign) {
355 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700356 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700357 if (sign)
358 *(start - 1) = sign;
359 }
360 GrowBuffer(n);
361 return;
362 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700363 // If n is negative we ask to increase the capacity by at least 1,
364 // but as std::vector, the buffer grows exponentially.
365 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700366 }
367}
368
369// Throws Exception(message) if format contains '}', otherwise throws
370// FormatError reporting unmatched '{'. The idea is that unmatched '{'
371// should override other errors.
372template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700373void fmt::BasicWriter<Char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700374 const Char *s, StringRef message) const {
375 for (int num_open_braces = num_open_braces_; *s; ++s) {
376 if (*s == '{') {
377 ++num_open_braces;
378 } else if (*s == '}') {
379 if (--num_open_braces == 0)
380 throw fmt::FormatError(message);
381 }
382 }
383 throw fmt::FormatError("unmatched '{' in format");
384}
385
386// Parses an unsigned integer advancing s to the end of the parsed input.
387// This function assumes that the first character of s is a digit.
388template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700389unsigned fmt::BasicWriter<Char>::FormatParser::ParseUInt(const Char *&s) const {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700390 assert('0' <= *s && *s <= '9');
391 unsigned value = 0;
392 do {
393 unsigned new_value = value * 10 + (*s++ - '0');
394 if (new_value < value) // Check if value wrapped around.
395 ReportError(s, "number is too big in format");
396 value = new_value;
397 } while ('0' <= *s && *s <= '9');
398 return value;
399}
400
401template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700402inline const typename fmt::BasicWriter<Char>::ArgInfo
403 &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700404 unsigned arg_index = 0;
405 if (*s < '0' || *s > '9') {
406 if (*s != '}' && *s != ':')
407 ReportError(s, "invalid argument index in format string");
408 if (next_arg_index_ < 0) {
409 ReportError(s,
410 "cannot switch from manual to automatic argument indexing");
411 }
412 arg_index = next_arg_index_++;
413 } else {
414 if (next_arg_index_ > 0) {
415 ReportError(s,
416 "cannot switch from automatic to manual argument indexing");
417 }
418 next_arg_index_ = -1;
419 arg_index = ParseUInt(s);
420 }
Victor Zveroviche78904b2014-04-23 08:27:50 -0700421 if (arg_index >= num_args_)
Victor Zverovich7cae7632013-09-06 20:23:42 -0700422 ReportError(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700423 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700424}
425
426template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700427void fmt::BasicWriter<Char>::FormatParser::CheckSign(
428 const Char *&s, const ArgInfo &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800429 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700430 if (arg.type > LAST_NUMERIC_TYPE) {
431 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700432 fmt::Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700433 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800434 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700435 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700436 fmt::Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700437 }
438 ++s;
439}
440
441template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700442void fmt::BasicWriter<Char>::FormatParser::Format(
443 BasicWriter<Char> &writer, BasicStringRef<Char> format,
444 std::size_t num_args, const ArgInfo *args) {
445 const Char *start = format.c_str();
446 num_args_ = num_args;
447 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700448 next_arg_index_ = 0;
449 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700450 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700451 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700452 if (c != '{' && c != '}') continue;
453 if (*s == c) {
454 writer.buffer_.append(start, s);
455 start = ++s;
456 continue;
457 }
458 if (c == '}')
459 throw FormatError("unmatched '}' in format");
460 num_open_braces_= 1;
461 writer.buffer_.append(start, s - 1);
462
Victor Zverovich656a8372014-04-22 08:58:54 -0700463 const ArgInfo &arg = ParseArgIndex(s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700464
Victor Zverovichea5dce32014-01-28 12:47:37 -0800465 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700466 int precision = -1;
467 if (*s == ':') {
468 ++s;
469
470 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700471 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700472 const Char *p = s + 1;
473 spec.align_ = ALIGN_DEFAULT;
474 do {
475 switch (*p) {
476 case '<':
477 spec.align_ = ALIGN_LEFT;
478 break;
479 case '>':
480 spec.align_ = ALIGN_RIGHT;
481 break;
482 case '=':
483 spec.align_ = ALIGN_NUMERIC;
484 break;
485 case '^':
486 spec.align_ = ALIGN_CENTER;
487 break;
488 }
489 if (spec.align_ != ALIGN_DEFAULT) {
490 if (p != s) {
491 if (c == '}') break;
492 if (c == '{')
493 ReportError(s, "invalid fill character '{'");
494 s += 2;
495 spec.fill_ = c;
496 } else ++s;
497 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
498 ReportError(s, "format specifier '=' requires numeric argument");
499 break;
500 }
501 } while (--p >= s);
502 }
503
504 // Parse sign.
505 switch (*s) {
506 case '+':
507 CheckSign(s, arg);
508 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
509 break;
510 case '-':
511 CheckSign(s, arg);
512 break;
513 case ' ':
514 CheckSign(s, arg);
515 spec.flags_ |= SIGN_FLAG;
516 break;
517 }
518
519 if (*s == '#') {
520 if (arg.type > LAST_NUMERIC_TYPE)
521 ReportError(s, "format specifier '#' requires numeric argument");
522 spec.flags_ |= HASH_FLAG;
523 ++s;
524 }
525
526 // Parse width and zero flag.
527 if ('0' <= *s && *s <= '9') {
528 if (*s == '0') {
529 if (arg.type > LAST_NUMERIC_TYPE)
530 ReportError(s, "format specifier '0' requires numeric argument");
531 spec.align_ = ALIGN_NUMERIC;
532 spec.fill_ = '0';
533 }
534 // Zero may be parsed again as a part of the width, but it is simpler
535 // and more efficient than checking if the next char is a digit.
536 unsigned value = ParseUInt(s);
537 if (value > INT_MAX)
538 ReportError(s, "number is too big in format");
539 spec.width_ = value;
540 }
541
542 // Parse precision.
543 if (*s == '.') {
544 ++s;
545 precision = 0;
546 if ('0' <= *s && *s <= '9') {
547 unsigned value = ParseUInt(s);
548 if (value > INT_MAX)
549 ReportError(s, "number is too big in format");
550 precision = value;
551 } else if (*s == '{') {
552 ++s;
553 ++num_open_braces_;
Victor Zverovich656a8372014-04-22 08:58:54 -0700554 const ArgInfo &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800555 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700556 switch (precision_arg.type) {
557 case INT:
558 if (precision_arg.int_value < 0)
559 ReportError(s, "negative precision in format");
560 value = precision_arg.int_value;
561 break;
562 case UINT:
563 value = precision_arg.uint_value;
564 break;
565 case LONG:
566 if (precision_arg.long_value < 0)
567 ReportError(s, "negative precision in format");
568 value = precision_arg.long_value;
569 break;
570 case ULONG:
571 value = precision_arg.ulong_value;
572 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800573 case LONG_LONG:
574 if (precision_arg.long_long_value < 0)
575 ReportError(s, "negative precision in format");
576 value = precision_arg.long_long_value;
577 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800578 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800579 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800580 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700581 default:
582 ReportError(s, "precision is not integer");
583 }
584 if (value > INT_MAX)
585 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800586 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700587 if (*s++ != '}')
588 throw FormatError("unmatched '{' in format");
589 --num_open_braces_;
590 } else {
591 ReportError(s, "missing precision in format");
592 }
593 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
594 ReportError(s,
595 "precision specifier requires floating-point argument");
596 }
597 }
598
599 // Parse type.
600 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700601 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700602 }
603
604 if (*s++ != '}')
605 throw FormatError("unmatched '{' in format");
606 start = s;
607
608 // Format argument.
609 switch (arg.type) {
610 case INT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700611 writer.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700612 break;
613 case UINT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700614 writer.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700615 break;
616 case LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700617 writer.FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700618 break;
619 case ULONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700620 writer.FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700621 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800622 case LONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700623 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800624 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800625 case ULONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700626 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800627 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700628 case DOUBLE:
629 writer.FormatDouble(arg.double_value, spec, precision);
630 break;
631 case LONG_DOUBLE:
632 writer.FormatDouble(arg.long_double_value, spec, precision);
633 break;
634 case CHAR: {
635 if (spec.type_ && spec.type_ != 'c')
636 internal::ReportUnknownType(spec.type_, "char");
637 typedef typename BasicWriter<Char>::CharPtr CharPtr;
638 CharPtr out = CharPtr();
639 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700640 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700641 out = writer.GrowBuffer(spec.width_);
642 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700643 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700644 out += spec.width_ - 1;
645 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700646 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700647 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700648 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700649 }
650 } else {
651 out = writer.GrowBuffer(1);
652 }
jdale884cabe162014-03-11 19:03:26 +0000653 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700654 break;
655 }
656 case STRING: {
657 if (spec.type_ && spec.type_ != 's')
658 internal::ReportUnknownType(spec.type_, "string");
659 const Char *str = arg.string.value;
660 std::size_t size = arg.string.size;
661 if (size == 0) {
662 if (!str)
663 throw FormatError("string pointer is null");
664 if (*str)
665 size = std::char_traits<Char>::length(str);
666 }
667 writer.FormatString(str, size, spec);
668 break;
669 }
670 case POINTER:
671 if (spec.type_ && spec.type_ != 'p')
672 internal::ReportUnknownType(spec.type_, "pointer");
673 spec.flags_= HASH_FLAG;
674 spec.type_ = 'x';
Victor Zverovich03f68852014-04-20 08:46:09 -0700675 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700676 break;
677 case CUSTOM:
678 if (spec.type_)
679 internal::ReportUnknownType(spec.type_, "object");
680 arg.custom.format(writer, arg.custom.value, spec);
681 break;
682 default:
683 assert(false);
684 break;
685 }
686 }
687 writer.buffer_.append(start, s);
688}
689
Victor Zverovich43fe1002014-02-19 14:20:26 -0800690void fmt::ColorWriter::operator()(const fmt::BasicWriter<char> &w) const {
691 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +0000692 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovich43fe1002014-02-19 14:20:26 -0800693 std::fputs(escape, stdout);
694 std::fwrite(w.data(), 1, w.size(), stdout);
695 std::fputs(RESET_COLOR, stdout);
696}
Victor Zverovich6968ef32014-02-19 13:51:23 -0800697
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700698// Explicit instantiations for char.
699
Victor Zverovich7cae7632013-09-06 20:23:42 -0700700template void fmt::BasicWriter<char>::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<char>::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 Zverovich93e41252013-09-08 13:07:04 -0700706template fmt::BasicWriter<char>::CharPtr
707 fmt::BasicWriter<char>::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 fmt::BasicWriter<char>::CharPtr
711 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800712 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700713
Victor Zveroviche78904b2014-04-23 08:27:50 -0700714template void fmt::BasicWriter<char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700715 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700716
Victor Zveroviche78904b2014-04-23 08:27:50 -0700717template unsigned fmt::BasicWriter<char>::FormatParser::ParseUInt(
718 const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700719
Victor Zveroviche78904b2014-04-23 08:27:50 -0700720template const fmt::BasicWriter<char>::ArgInfo
721 &fmt::BasicWriter<char>::FormatParser::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700722
Victor Zveroviche78904b2014-04-23 08:27:50 -0700723template void fmt::BasicWriter<char>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700724 const char *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700725
Victor Zveroviche78904b2014-04-23 08:27:50 -0700726template void fmt::BasicWriter<char>::FormatParser::Format(
727 BasicWriter<char> &writer, BasicStringRef<char> format,
728 std::size_t num_args, const ArgInfo *args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700729
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700730// Explicit instantiations for wchar_t.
731
Victor Zverovich7cae7632013-09-06 20:23:42 -0700732template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800733 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700734
Victor Zverovich7cae7632013-09-06 20:23:42 -0700735template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800736 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700737
Victor Zverovich7cae7632013-09-06 20:23:42 -0700738template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700739 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
740 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700741
Victor Zverovich7cae7632013-09-06 20:23:42 -0700742template fmt::BasicWriter<wchar_t>::CharPtr
743 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800744 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700745
Victor Zveroviche78904b2014-04-23 08:27:50 -0700746template void fmt::BasicWriter<wchar_t>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700747 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700748
Victor Zveroviche78904b2014-04-23 08:27:50 -0700749template unsigned fmt::BasicWriter<wchar_t>::FormatParser::ParseUInt(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700750 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700751
Victor Zveroviche78904b2014-04-23 08:27:50 -0700752template const fmt::BasicWriter<wchar_t>::ArgInfo
753 &fmt::BasicWriter<wchar_t>::FormatParser::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700754
Victor Zveroviche78904b2014-04-23 08:27:50 -0700755template void fmt::BasicWriter<wchar_t>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700756 const wchar_t *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700757
Victor Zveroviche78904b2014-04-23 08:27:50 -0700758template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
759 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
760 std::size_t num_args, const ArgInfo *args);
jdale88a9862fd2014-03-11 18:56:24 +0000761
762#if _MSC_VER
763# pragma warning(pop)
764#endif