blob: 671cc0176411d31505a4b898585a4acbdf2111f3 [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 }
363 buffer_.reserve(n >= 0 ? offset + n + 1 : 2 * buffer_.capacity());
364 }
365}
366
367// Throws Exception(message) if format contains '}', otherwise throws
368// FormatError reporting unmatched '{'. The idea is that unmatched '{'
369// should override other errors.
370template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700371void fmt::BasicWriter<Char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700372 const Char *s, StringRef message) const {
373 for (int num_open_braces = num_open_braces_; *s; ++s) {
374 if (*s == '{') {
375 ++num_open_braces;
376 } else if (*s == '}') {
377 if (--num_open_braces == 0)
378 throw fmt::FormatError(message);
379 }
380 }
381 throw fmt::FormatError("unmatched '{' in format");
382}
383
384// Parses an unsigned integer advancing s to the end of the parsed input.
385// This function assumes that the first character of s is a digit.
386template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700387unsigned fmt::BasicWriter<Char>::FormatParser::ParseUInt(const Char *&s) const {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700388 assert('0' <= *s && *s <= '9');
389 unsigned value = 0;
390 do {
391 unsigned new_value = value * 10 + (*s++ - '0');
392 if (new_value < value) // Check if value wrapped around.
393 ReportError(s, "number is too big in format");
394 value = new_value;
395 } while ('0' <= *s && *s <= '9');
396 return value;
397}
398
399template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700400inline const typename fmt::BasicWriter<Char>::ArgInfo
401 &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700402 unsigned arg_index = 0;
403 if (*s < '0' || *s > '9') {
404 if (*s != '}' && *s != ':')
405 ReportError(s, "invalid argument index in format string");
406 if (next_arg_index_ < 0) {
407 ReportError(s,
408 "cannot switch from manual to automatic argument indexing");
409 }
410 arg_index = next_arg_index_++;
411 } else {
412 if (next_arg_index_ > 0) {
413 ReportError(s,
414 "cannot switch from automatic to manual argument indexing");
415 }
416 next_arg_index_ = -1;
417 arg_index = ParseUInt(s);
418 }
Victor Zveroviche78904b2014-04-23 08:27:50 -0700419 if (arg_index >= num_args_)
Victor Zverovich7cae7632013-09-06 20:23:42 -0700420 ReportError(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700421 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700422}
423
424template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700425void fmt::BasicWriter<Char>::FormatParser::CheckSign(
426 const Char *&s, const ArgInfo &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800427 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700428 if (arg.type > LAST_NUMERIC_TYPE) {
429 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700430 fmt::Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700431 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800432 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700433 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700434 fmt::Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700435 }
436 ++s;
437}
438
439template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700440void fmt::BasicWriter<Char>::FormatParser::Format(
441 BasicWriter<Char> &writer, BasicStringRef<Char> format,
442 std::size_t num_args, const ArgInfo *args) {
443 const Char *start = format.c_str();
444 num_args_ = num_args;
445 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700446 next_arg_index_ = 0;
447 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700448 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700449 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700450 if (c != '{' && c != '}') continue;
451 if (*s == c) {
452 writer.buffer_.append(start, s);
453 start = ++s;
454 continue;
455 }
456 if (c == '}')
457 throw FormatError("unmatched '}' in format");
458 num_open_braces_= 1;
459 writer.buffer_.append(start, s - 1);
460
Victor Zverovich656a8372014-04-22 08:58:54 -0700461 const ArgInfo &arg = ParseArgIndex(s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700462
Victor Zverovichea5dce32014-01-28 12:47:37 -0800463 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700464 int precision = -1;
465 if (*s == ':') {
466 ++s;
467
468 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700469 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700470 const Char *p = s + 1;
471 spec.align_ = ALIGN_DEFAULT;
472 do {
473 switch (*p) {
474 case '<':
475 spec.align_ = ALIGN_LEFT;
476 break;
477 case '>':
478 spec.align_ = ALIGN_RIGHT;
479 break;
480 case '=':
481 spec.align_ = ALIGN_NUMERIC;
482 break;
483 case '^':
484 spec.align_ = ALIGN_CENTER;
485 break;
486 }
487 if (spec.align_ != ALIGN_DEFAULT) {
488 if (p != s) {
489 if (c == '}') break;
490 if (c == '{')
491 ReportError(s, "invalid fill character '{'");
492 s += 2;
493 spec.fill_ = c;
494 } else ++s;
495 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
496 ReportError(s, "format specifier '=' requires numeric argument");
497 break;
498 }
499 } while (--p >= s);
500 }
501
502 // Parse sign.
503 switch (*s) {
504 case '+':
505 CheckSign(s, arg);
506 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
507 break;
508 case '-':
509 CheckSign(s, arg);
510 break;
511 case ' ':
512 CheckSign(s, arg);
513 spec.flags_ |= SIGN_FLAG;
514 break;
515 }
516
517 if (*s == '#') {
518 if (arg.type > LAST_NUMERIC_TYPE)
519 ReportError(s, "format specifier '#' requires numeric argument");
520 spec.flags_ |= HASH_FLAG;
521 ++s;
522 }
523
524 // Parse width and zero flag.
525 if ('0' <= *s && *s <= '9') {
526 if (*s == '0') {
527 if (arg.type > LAST_NUMERIC_TYPE)
528 ReportError(s, "format specifier '0' requires numeric argument");
529 spec.align_ = ALIGN_NUMERIC;
530 spec.fill_ = '0';
531 }
532 // Zero may be parsed again as a part of the width, but it is simpler
533 // and more efficient than checking if the next char is a digit.
534 unsigned value = ParseUInt(s);
535 if (value > INT_MAX)
536 ReportError(s, "number is too big in format");
537 spec.width_ = value;
538 }
539
540 // Parse precision.
541 if (*s == '.') {
542 ++s;
543 precision = 0;
544 if ('0' <= *s && *s <= '9') {
545 unsigned value = ParseUInt(s);
546 if (value > INT_MAX)
547 ReportError(s, "number is too big in format");
548 precision = value;
549 } else if (*s == '{') {
550 ++s;
551 ++num_open_braces_;
Victor Zverovich656a8372014-04-22 08:58:54 -0700552 const ArgInfo &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800553 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700554 switch (precision_arg.type) {
555 case INT:
556 if (precision_arg.int_value < 0)
557 ReportError(s, "negative precision in format");
558 value = precision_arg.int_value;
559 break;
560 case UINT:
561 value = precision_arg.uint_value;
562 break;
563 case LONG:
564 if (precision_arg.long_value < 0)
565 ReportError(s, "negative precision in format");
566 value = precision_arg.long_value;
567 break;
568 case ULONG:
569 value = precision_arg.ulong_value;
570 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800571 case LONG_LONG:
572 if (precision_arg.long_long_value < 0)
573 ReportError(s, "negative precision in format");
574 value = precision_arg.long_long_value;
575 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800576 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800577 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800578 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700579 default:
580 ReportError(s, "precision is not integer");
581 }
582 if (value > INT_MAX)
583 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800584 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700585 if (*s++ != '}')
586 throw FormatError("unmatched '{' in format");
587 --num_open_braces_;
588 } else {
589 ReportError(s, "missing precision in format");
590 }
591 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
592 ReportError(s,
593 "precision specifier requires floating-point argument");
594 }
595 }
596
597 // Parse type.
598 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700599 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700600 }
601
602 if (*s++ != '}')
603 throw FormatError("unmatched '{' in format");
604 start = s;
605
606 // Format argument.
607 switch (arg.type) {
608 case INT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700609 writer.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700610 break;
611 case UINT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700612 writer.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700613 break;
614 case LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700615 writer.FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700616 break;
617 case ULONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700618 writer.FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700619 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800620 case LONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700621 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800622 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800623 case ULONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700624 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800625 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700626 case DOUBLE:
627 writer.FormatDouble(arg.double_value, spec, precision);
628 break;
629 case LONG_DOUBLE:
630 writer.FormatDouble(arg.long_double_value, spec, precision);
631 break;
632 case CHAR: {
633 if (spec.type_ && spec.type_ != 'c')
634 internal::ReportUnknownType(spec.type_, "char");
635 typedef typename BasicWriter<Char>::CharPtr CharPtr;
636 CharPtr out = CharPtr();
637 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700638 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700639 out = writer.GrowBuffer(spec.width_);
640 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700641 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700642 out += spec.width_ - 1;
643 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700644 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700645 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700646 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700647 }
648 } else {
649 out = writer.GrowBuffer(1);
650 }
jdale884cabe162014-03-11 19:03:26 +0000651 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700652 break;
653 }
654 case STRING: {
655 if (spec.type_ && spec.type_ != 's')
656 internal::ReportUnknownType(spec.type_, "string");
657 const Char *str = arg.string.value;
658 std::size_t size = arg.string.size;
659 if (size == 0) {
660 if (!str)
661 throw FormatError("string pointer is null");
662 if (*str)
663 size = std::char_traits<Char>::length(str);
664 }
665 writer.FormatString(str, size, spec);
666 break;
667 }
668 case POINTER:
669 if (spec.type_ && spec.type_ != 'p')
670 internal::ReportUnknownType(spec.type_, "pointer");
671 spec.flags_= HASH_FLAG;
672 spec.type_ = 'x';
Victor Zverovich03f68852014-04-20 08:46:09 -0700673 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700674 break;
675 case CUSTOM:
676 if (spec.type_)
677 internal::ReportUnknownType(spec.type_, "object");
678 arg.custom.format(writer, arg.custom.value, spec);
679 break;
680 default:
681 assert(false);
682 break;
683 }
684 }
685 writer.buffer_.append(start, s);
686}
687
Victor Zverovich43fe1002014-02-19 14:20:26 -0800688void fmt::ColorWriter::operator()(const fmt::BasicWriter<char> &w) const {
689 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +0000690 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovich43fe1002014-02-19 14:20:26 -0800691 std::fputs(escape, stdout);
692 std::fwrite(w.data(), 1, w.size(), stdout);
693 std::fputs(RESET_COLOR, stdout);
694}
Victor Zverovich6968ef32014-02-19 13:51:23 -0800695
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700696// Explicit instantiations for char.
697
Victor Zverovich7cae7632013-09-06 20:23:42 -0700698template void fmt::BasicWriter<char>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800699 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700700
Victor Zverovich7cae7632013-09-06 20:23:42 -0700701template void fmt::BasicWriter<char>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800702 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700703
Victor Zverovich93e41252013-09-08 13:07:04 -0700704template fmt::BasicWriter<char>::CharPtr
705 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
706 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700707
Victor Zverovich7cae7632013-09-06 20:23:42 -0700708template fmt::BasicWriter<char>::CharPtr
709 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800710 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700711
Victor Zveroviche78904b2014-04-23 08:27:50 -0700712template void fmt::BasicWriter<char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700713 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700714
Victor Zveroviche78904b2014-04-23 08:27:50 -0700715template unsigned fmt::BasicWriter<char>::FormatParser::ParseUInt(
716 const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700717
Victor Zveroviche78904b2014-04-23 08:27:50 -0700718template const fmt::BasicWriter<char>::ArgInfo
719 &fmt::BasicWriter<char>::FormatParser::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700720
Victor Zveroviche78904b2014-04-23 08:27:50 -0700721template void fmt::BasicWriter<char>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700722 const char *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700723
Victor Zveroviche78904b2014-04-23 08:27:50 -0700724template void fmt::BasicWriter<char>::FormatParser::Format(
725 BasicWriter<char> &writer, BasicStringRef<char> format,
726 std::size_t num_args, const ArgInfo *args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700727
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700728// Explicit instantiations for wchar_t.
729
Victor Zverovich7cae7632013-09-06 20:23:42 -0700730template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800731 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700732
Victor Zverovich7cae7632013-09-06 20:23:42 -0700733template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800734 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700735
Victor Zverovich7cae7632013-09-06 20:23:42 -0700736template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700737 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
738 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700739
Victor Zverovich7cae7632013-09-06 20:23:42 -0700740template fmt::BasicWriter<wchar_t>::CharPtr
741 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800742 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700743
Victor Zveroviche78904b2014-04-23 08:27:50 -0700744template void fmt::BasicWriter<wchar_t>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700745 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700746
Victor Zveroviche78904b2014-04-23 08:27:50 -0700747template unsigned fmt::BasicWriter<wchar_t>::FormatParser::ParseUInt(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700748 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700749
Victor Zveroviche78904b2014-04-23 08:27:50 -0700750template const fmt::BasicWriter<wchar_t>::ArgInfo
751 &fmt::BasicWriter<wchar_t>::FormatParser::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700752
Victor Zveroviche78904b2014-04-23 08:27:50 -0700753template void fmt::BasicWriter<wchar_t>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700754 const wchar_t *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700755
Victor Zveroviche78904b2014-04-23 08:27:50 -0700756template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
757 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
758 std::size_t num_args, const ArgInfo *args);
jdale88a9862fd2014-03-11 18:56:24 +0000759
760#if _MSC_VER
761# pragma warning(pop)
762#endif