blob: 197796962ae05c1483df3b07bdc25a12da322cee [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 Zverovich859a4972014-04-30 06:55:21 -070036#include <string.h>
37
Victor Zverovich72f896d2012-12-12 09:17:28 -080038#include <cctype>
Victor Zverovichf28645f2014-04-24 12:37:06 -070039#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070040#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080041#include <cstdarg>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070042
Victor Zverovich859a4972014-04-30 06:55:21 -070043#ifdef _WIN32
44# include <windows.h>
Victor Zveroviched2bdba2014-04-30 07:41:54 -070045# undef ERROR
Victor Zverovich859a4972014-04-30 06:55:21 -070046#endif
47
Victor Zverovich447e02c2014-02-15 10:48:34 -080048using fmt::ULongLong;
49
jdale88a9862fd2014-03-11 18:56:24 +000050#if _MSC_VER
51# pragma warning(push)
52# pragma warning(disable: 4127) // conditional expression is constant
53#endif
54
Victor Zverovich9ff3b972013-09-07 10:15:08 -070055namespace {
56
57#ifndef _MSC_VER
58
59inline int SignBit(double value) {
60 // When compiled in C++11 mode signbit is no longer a macro but a function
61 // defined in namespace std and the macro is undefined.
Victor Zverovichf2e06802014-04-10 10:49:55 -070062#ifdef signbit
Victor Zverovich9ff3b972013-09-07 10:15:08 -070063 return signbit(value);
Victor Zverovichf2e06802014-04-10 10:49:55 -070064#else
65 return std::signbit(value);
66#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070067}
68
69inline int IsInf(double x) {
70#ifdef isinf
71 return isinf(x);
72#else
73 return std::isinf(x);
74#endif
75}
76
77#define FMT_SNPRINTF snprintf
78
Victor Zverovicha684d0c2013-12-27 08:00:10 -080079#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070080
81inline int SignBit(double value) {
82 if (value < 0) return 1;
83 if (value == value) return 0;
84 int dec = 0, sign = 0;
85 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
86 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
87 return sign;
88}
89
90inline int IsInf(double x) { return !_finite(x); }
91
Victor Zverovicha684d0c2013-12-27 08:00:10 -080092inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
93 va_list args;
94 va_start(args, format);
95 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
96 va_end(args);
97 return result;
98}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070099
100#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800101
102const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovichb605b392013-09-09 22:21:40 -0700103}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700104
Victor Zverovichb605b392013-09-09 22:21:40 -0700105template <typename T>
106int fmt::internal::CharTraits<char>::FormatFloat(
107 char *buffer, std::size_t size, const char *format,
108 unsigned width, int precision, T value) {
109 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700110 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700111 FMT_SNPRINTF(buffer, size, format, value) :
112 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700113 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700114 return precision < 0 ?
115 FMT_SNPRINTF(buffer, size, format, width, value) :
116 FMT_SNPRINTF(buffer, size, format, width, precision, value);
117}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700118
Victor Zverovichb605b392013-09-09 22:21:40 -0700119template <typename T>
120int fmt::internal::CharTraits<wchar_t>::FormatFloat(
121 wchar_t *buffer, std::size_t size, const wchar_t *format,
122 unsigned width, int precision, T value) {
123 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700124 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700125 swprintf(buffer, size, format, value) :
126 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700127 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700128 return precision < 0 ?
129 swprintf(buffer, size, format, width, value) :
130 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700131}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800132
Victor Zverovich65d47e52013-09-09 06:51:03 -0700133const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800134 "0001020304050607080910111213141516171819"
135 "2021222324252627282930313233343536373839"
136 "4041424344454647484950515253545556575859"
137 "6061626364656667686970717273747576777879"
138 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800139
Victor Zverovichf1d85162014-02-19 13:02:22 -0800140#define FMT_POWERS_OF_10(factor) \
141 factor * 10, \
142 factor * 100, \
143 factor * 1000, \
144 factor * 10000, \
145 factor * 100000, \
146 factor * 1000000, \
147 factor * 10000000, \
148 factor * 100000000, \
149 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800150
Victor Zverovichf1d85162014-02-19 13:02:22 -0800151const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800152const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800153 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800154 FMT_POWERS_OF_10(1),
155 FMT_POWERS_OF_10(ULongLong(1000000000)),
156 // Multiply several constants instead of using a single long long constants
157 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800158 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800159};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800160
Victor Zverovich687301c2013-01-26 16:07:28 -0800161void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800162 if (std::isprint(static_cast<unsigned char>(code))) {
163 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800164 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800165 }
166 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800167 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800168 << static_cast<unsigned>(code) << type));
169}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700170
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700171#ifdef _WIN32
172
173fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
174 int length = MultiByteToWideChar(
175 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
176 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
177 if (length == 0)
178 ThrowSystemError(GetLastError(), ERROR);
179 buffer_.resize(length);
180 length = MultiByteToWideChar(
181 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
182 if (length == 0)
183 ThrowSystemError(GetLastError(), ERROR);
184}
185
186fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
187 if (int error_code = Convert(s)) {
188 ThrowSystemError(GetLastError(),
189 "cannot convert string from UTF-16 to UTF-8");
190 }
191}
192
193int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) {
194 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
195 if (length == 0)
196 return GetLastError();
197 buffer_.resize(length);
198 length = WideCharToMultiByte(
199 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
200 if (length == 0)
201 return GetLastError();
202 return 0;
203}
204
205#endif
206
Victor Zverovich859a4972014-04-30 06:55:21 -0700207void fmt::internal::FormatSystemErrorMessage(
208 fmt::Writer &out, int error_code, fmt::StringRef message) {
209#ifndef _WIN32
210 Array<char, INLINE_BUFFER_SIZE> buffer;
211 buffer.resize(INLINE_BUFFER_SIZE);
212 char *system_message = 0;
213 for (;;) {
214 errno = 0;
215# ifdef _GNU_SOURCE
216 system_message = strerror_r(error_code, &buffer[0], buffer.size());
217# else
218 strerror_r(error_code, system_message = &buffer[0], buffer.size());
219# endif
220 if (errno == 0)
221 break;
222 if (errno != ERANGE) {
223 // Can't get error message, report error code instead.
224 out << message << ": error code = " << error_code;
225 return;
226 }
227 buffer.resize(buffer.size() * 2);
228 }
229 out << message << ": " << system_message;
230#else
231 class String {
232 private:
233 LPWSTR str_;
234
235 public:
236 String() : str_() {}
237 ~String() { LocalFree(str_); }
238 LPWSTR *ptr() { return &str_; }
239 LPCWSTR c_str() const { return str_; }
240 };
241 String system_message;
242 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
243 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
244 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
245 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
246 UTF16ToUTF8 utf8_message;
247 if (!utf8_message.Convert(system_message.c_str())) {
Victor Zverovichc16217b2014-04-30 07:38:43 -0700248 out << message << ": " << c_str(utf8_message);
Victor Zverovich859a4972014-04-30 06:55:21 -0700249 return;
250 }
251 }
252 // Can't get error message, report error code instead.
253 out << message << ": error code = " << error_code;
254#endif
255}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700256
257// Fills the padding around the content and returns the pointer to the
258// content area.
259template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700260typename fmt::BasicWriter<Char>::CharPtr
261 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
262 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700263 std::size_t padding = total_size - content_size;
264 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700265 Char fill_char = static_cast<Char>(fill);
266 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700267 buffer += left_padding;
268 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700269 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700270 return content;
271}
272
273template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700274typename fmt::BasicWriter<Char>::CharPtr
275 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800276 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700277 unsigned width = spec.width();
278 if (width <= size) {
279 CharPtr p = GrowBuffer(size);
280 *p = sign;
281 return p + size - 1;
282 }
283 CharPtr p = GrowBuffer(width);
284 CharPtr end = p + width;
285 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800286 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700287 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700288 if (align == ALIGN_LEFT) {
289 *p = sign;
290 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700291 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700292 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700293 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700294 *p = sign;
295 p += size;
296 } else {
297 if (align == ALIGN_NUMERIC) {
298 if (sign) {
299 *p++ = sign;
300 --size;
301 }
302 } else {
303 *(end - size) = sign;
304 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700305 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700306 p = end;
307 }
308 return p - 1;
309}
310
311template <typename Char>
312template <typename T>
313void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800314 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700315 // Check type.
316 char type = spec.type();
317 bool upper = false;
318 switch (type) {
319 case 0:
320 type = 'g';
321 break;
322 case 'e': case 'f': case 'g':
323 break;
324 case 'F':
325#ifdef _MSC_VER
326 // MSVC's printf doesn't support 'F'.
327 type = 'f';
328#endif
329 // Fall through.
330 case 'E': case 'G':
331 upper = true;
332 break;
333 default:
334 internal::ReportUnknownType(type, "double");
335 break;
336 }
337
338 char sign = 0;
339 // Use SignBit instead of value < 0 because the latter is always
340 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000341 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700342 sign = '-';
343 value = -value;
344 } else if (spec.sign_flag()) {
345 sign = spec.plus_flag() ? '+' : ' ';
346 }
347
348 if (value != value) {
349 // Format NaN ourselves because sprintf's output is not consistent
350 // across platforms.
351 std::size_t size = 4;
352 const char *nan = upper ? " NAN" : " nan";
353 if (!sign) {
354 --size;
355 ++nan;
356 }
357 CharPtr out = FormatString(nan, size, spec);
358 if (sign)
359 *out = sign;
360 return;
361 }
362
jdale88a9862fd2014-03-11 18:56:24 +0000363 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700364 // Format infinity ourselves because sprintf's output is not consistent
365 // across platforms.
366 std::size_t size = 4;
367 const char *inf = upper ? " INF" : " inf";
368 if (!sign) {
369 --size;
370 ++inf;
371 }
372 CharPtr out = FormatString(inf, size, spec);
373 if (sign)
374 *out = sign;
375 return;
376 }
377
378 std::size_t offset = buffer_.size();
379 unsigned width = spec.width();
380 if (sign) {
381 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
382 if (width > 0)
383 --width;
384 ++offset;
385 }
386
387 // Build format string.
388 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
389 Char format[MAX_FORMAT_SIZE];
390 Char *format_ptr = format;
391 *format_ptr++ = '%';
392 unsigned width_for_sprintf = width;
393 if (spec.hash_flag())
394 *format_ptr++ = '#';
395 if (spec.align() == ALIGN_CENTER) {
396 width_for_sprintf = 0;
397 } else {
398 if (spec.align() == ALIGN_LEFT)
399 *format_ptr++ = '-';
400 if (width != 0)
401 *format_ptr++ = '*';
402 }
403 if (precision >= 0) {
404 *format_ptr++ = '.';
405 *format_ptr++ = '*';
406 }
407 if (internal::IsLongDouble<T>::VALUE)
408 *format_ptr++ = 'L';
409 *format_ptr++ = type;
410 *format_ptr = '\0';
411
412 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700413 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700414 for (;;) {
415 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700416#if _MSC_VER
417 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
418 // space for at least one extra character to make the size non-zero.
419 // Note that the buffer's capacity will increase by more than 1.
420 if (size == 0) {
421 buffer_.reserve(offset + 1);
422 size = buffer_.capacity() - offset;
423 }
424#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700425 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700426 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700427 start, size, format, width_for_sprintf, precision, value);
428 if (n >= 0 && offset + n < buffer_.capacity()) {
429 if (sign) {
430 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
431 *start != ' ') {
432 *(start - 1) = sign;
433 sign = 0;
434 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700435 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700436 }
437 ++n;
438 }
439 if (spec.align() == ALIGN_CENTER &&
440 spec.width() > static_cast<unsigned>(n)) {
441 unsigned width = spec.width();
442 CharPtr p = GrowBuffer(width);
443 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700444 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700445 return;
446 }
447 if (spec.fill() != ' ' || sign) {
448 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700449 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700450 if (sign)
451 *(start - 1) = sign;
452 }
453 GrowBuffer(n);
454 return;
455 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700456 // If n is negative we ask to increase the capacity by at least 1,
457 // but as std::vector, the buffer grows exponentially.
458 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700459 }
460}
461
462// Throws Exception(message) if format contains '}', otherwise throws
463// FormatError reporting unmatched '{'. The idea is that unmatched '{'
464// should override other errors.
465template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700466void fmt::BasicWriter<Char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700467 const Char *s, StringRef message) const {
468 for (int num_open_braces = num_open_braces_; *s; ++s) {
469 if (*s == '{') {
470 ++num_open_braces;
471 } else if (*s == '}') {
472 if (--num_open_braces == 0)
473 throw fmt::FormatError(message);
474 }
475 }
476 throw fmt::FormatError("unmatched '{' in format");
477}
478
479// Parses an unsigned integer advancing s to the end of the parsed input.
480// This function assumes that the first character of s is a digit.
481template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700482unsigned fmt::BasicWriter<Char>::FormatParser::ParseUInt(const Char *&s) const {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700483 assert('0' <= *s && *s <= '9');
484 unsigned value = 0;
485 do {
486 unsigned new_value = value * 10 + (*s++ - '0');
487 if (new_value < value) // Check if value wrapped around.
488 ReportError(s, "number is too big in format");
489 value = new_value;
490 } while ('0' <= *s && *s <= '9');
491 return value;
492}
493
494template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700495inline const typename fmt::BasicWriter<Char>::ArgInfo
496 &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700497 unsigned arg_index = 0;
498 if (*s < '0' || *s > '9') {
499 if (*s != '}' && *s != ':')
500 ReportError(s, "invalid argument index in format string");
501 if (next_arg_index_ < 0) {
502 ReportError(s,
503 "cannot switch from manual to automatic argument indexing");
504 }
505 arg_index = next_arg_index_++;
506 } else {
507 if (next_arg_index_ > 0) {
508 ReportError(s,
509 "cannot switch from automatic to manual argument indexing");
510 }
511 next_arg_index_ = -1;
512 arg_index = ParseUInt(s);
513 }
Victor Zveroviche78904b2014-04-23 08:27:50 -0700514 if (arg_index >= num_args_)
Victor Zverovich7cae7632013-09-06 20:23:42 -0700515 ReportError(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700516 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700517}
518
519template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700520void fmt::BasicWriter<Char>::FormatParser::CheckSign(
521 const Char *&s, const ArgInfo &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800522 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700523 if (arg.type > LAST_NUMERIC_TYPE) {
524 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700525 fmt::Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700526 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800527 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700528 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700529 fmt::Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700530 }
531 ++s;
532}
533
534template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700535void fmt::BasicWriter<Char>::FormatParser::Format(
536 BasicWriter<Char> &writer, BasicStringRef<Char> format,
537 std::size_t num_args, const ArgInfo *args) {
538 const Char *start = format.c_str();
539 num_args_ = num_args;
540 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700541 next_arg_index_ = 0;
542 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700543 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700544 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700545 if (c != '{' && c != '}') continue;
546 if (*s == c) {
547 writer.buffer_.append(start, s);
548 start = ++s;
549 continue;
550 }
551 if (c == '}')
552 throw FormatError("unmatched '}' in format");
553 num_open_braces_= 1;
554 writer.buffer_.append(start, s - 1);
555
Victor Zverovich656a8372014-04-22 08:58:54 -0700556 const ArgInfo &arg = ParseArgIndex(s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700557
Victor Zverovichea5dce32014-01-28 12:47:37 -0800558 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700559 int precision = -1;
560 if (*s == ':') {
561 ++s;
562
563 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700564 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700565 const Char *p = s + 1;
566 spec.align_ = ALIGN_DEFAULT;
567 do {
568 switch (*p) {
569 case '<':
570 spec.align_ = ALIGN_LEFT;
571 break;
572 case '>':
573 spec.align_ = ALIGN_RIGHT;
574 break;
575 case '=':
576 spec.align_ = ALIGN_NUMERIC;
577 break;
578 case '^':
579 spec.align_ = ALIGN_CENTER;
580 break;
581 }
582 if (spec.align_ != ALIGN_DEFAULT) {
583 if (p != s) {
584 if (c == '}') break;
585 if (c == '{')
586 ReportError(s, "invalid fill character '{'");
587 s += 2;
588 spec.fill_ = c;
589 } else ++s;
590 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
591 ReportError(s, "format specifier '=' requires numeric argument");
592 break;
593 }
594 } while (--p >= s);
595 }
596
597 // Parse sign.
598 switch (*s) {
599 case '+':
600 CheckSign(s, arg);
601 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
602 break;
603 case '-':
604 CheckSign(s, arg);
605 break;
606 case ' ':
607 CheckSign(s, arg);
608 spec.flags_ |= SIGN_FLAG;
609 break;
610 }
611
612 if (*s == '#') {
613 if (arg.type > LAST_NUMERIC_TYPE)
614 ReportError(s, "format specifier '#' requires numeric argument");
615 spec.flags_ |= HASH_FLAG;
616 ++s;
617 }
618
619 // Parse width and zero flag.
620 if ('0' <= *s && *s <= '9') {
621 if (*s == '0') {
622 if (arg.type > LAST_NUMERIC_TYPE)
623 ReportError(s, "format specifier '0' requires numeric argument");
624 spec.align_ = ALIGN_NUMERIC;
625 spec.fill_ = '0';
626 }
627 // Zero may be parsed again as a part of the width, but it is simpler
628 // and more efficient than checking if the next char is a digit.
629 unsigned value = ParseUInt(s);
630 if (value > INT_MAX)
631 ReportError(s, "number is too big in format");
632 spec.width_ = value;
633 }
634
635 // Parse precision.
636 if (*s == '.') {
637 ++s;
638 precision = 0;
639 if ('0' <= *s && *s <= '9') {
640 unsigned value = ParseUInt(s);
641 if (value > INT_MAX)
642 ReportError(s, "number is too big in format");
643 precision = value;
644 } else if (*s == '{') {
645 ++s;
646 ++num_open_braces_;
Victor Zverovich656a8372014-04-22 08:58:54 -0700647 const ArgInfo &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800648 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700649 switch (precision_arg.type) {
650 case INT:
651 if (precision_arg.int_value < 0)
652 ReportError(s, "negative precision in format");
653 value = precision_arg.int_value;
654 break;
655 case UINT:
656 value = precision_arg.uint_value;
657 break;
658 case LONG:
659 if (precision_arg.long_value < 0)
660 ReportError(s, "negative precision in format");
661 value = precision_arg.long_value;
662 break;
663 case ULONG:
664 value = precision_arg.ulong_value;
665 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800666 case LONG_LONG:
667 if (precision_arg.long_long_value < 0)
668 ReportError(s, "negative precision in format");
669 value = precision_arg.long_long_value;
670 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800671 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800672 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800673 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700674 default:
675 ReportError(s, "precision is not integer");
676 }
677 if (value > INT_MAX)
678 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800679 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700680 if (*s++ != '}')
681 throw FormatError("unmatched '{' in format");
682 --num_open_braces_;
683 } else {
684 ReportError(s, "missing precision in format");
685 }
686 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
687 ReportError(s,
688 "precision specifier requires floating-point argument");
689 }
690 }
691
692 // Parse type.
693 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700694 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700695 }
696
697 if (*s++ != '}')
698 throw FormatError("unmatched '{' in format");
699 start = s;
700
701 // Format argument.
702 switch (arg.type) {
703 case INT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700704 writer.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700705 break;
706 case UINT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700707 writer.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700708 break;
709 case LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700710 writer.FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700711 break;
712 case ULONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700713 writer.FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700714 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800715 case LONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700716 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800717 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800718 case ULONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700719 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800720 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700721 case DOUBLE:
722 writer.FormatDouble(arg.double_value, spec, precision);
723 break;
724 case LONG_DOUBLE:
725 writer.FormatDouble(arg.long_double_value, spec, precision);
726 break;
727 case CHAR: {
728 if (spec.type_ && spec.type_ != 'c')
729 internal::ReportUnknownType(spec.type_, "char");
730 typedef typename BasicWriter<Char>::CharPtr CharPtr;
731 CharPtr out = CharPtr();
732 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700733 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700734 out = writer.GrowBuffer(spec.width_);
735 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700736 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700737 out += spec.width_ - 1;
738 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700739 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700740 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700741 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700742 }
743 } else {
744 out = writer.GrowBuffer(1);
745 }
jdale884cabe162014-03-11 19:03:26 +0000746 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700747 break;
748 }
749 case STRING: {
750 if (spec.type_ && spec.type_ != 's')
751 internal::ReportUnknownType(spec.type_, "string");
752 const Char *str = arg.string.value;
753 std::size_t size = arg.string.size;
754 if (size == 0) {
755 if (!str)
756 throw FormatError("string pointer is null");
757 if (*str)
758 size = std::char_traits<Char>::length(str);
759 }
760 writer.FormatString(str, size, spec);
761 break;
762 }
763 case POINTER:
764 if (spec.type_ && spec.type_ != 'p')
765 internal::ReportUnknownType(spec.type_, "pointer");
766 spec.flags_= HASH_FLAG;
767 spec.type_ = 'x';
Victor Zverovich03f68852014-04-20 08:46:09 -0700768 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700769 break;
770 case CUSTOM:
771 if (spec.type_)
772 internal::ReportUnknownType(spec.type_, "object");
773 arg.custom.format(writer, arg.custom.value, spec);
774 break;
775 default:
776 assert(false);
777 break;
778 }
779 }
780 writer.buffer_.append(start, s);
781}
782
Victor Zverovich859a4972014-04-30 06:55:21 -0700783void fmt::SystemErrorSink::operator()(const fmt::Writer &w) const {
784 Writer message;
785 internal::FormatSystemErrorMessage(message, error_code_, w.c_str());
786 throw SystemError(message.c_str(), error_code_);
787}
788
Victor Zverovichd9db8982014-04-28 08:59:29 -0700789void fmt::ANSITerminalSink::operator()(
790 const fmt::BasicWriter<char> &w) const {
Victor Zverovich43fe1002014-02-19 14:20:26 -0800791 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +0000792 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovichd9db8982014-04-28 08:59:29 -0700793 std::fputs(escape, file_);
794 std::fwrite(w.data(), 1, w.size(), file_);
795 std::fputs(RESET_COLOR, file_);
Victor Zverovich43fe1002014-02-19 14:20:26 -0800796}
Victor Zverovich6968ef32014-02-19 13:51:23 -0800797
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700798// Explicit instantiations for char.
799
Victor Zverovich7cae7632013-09-06 20:23:42 -0700800template void fmt::BasicWriter<char>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800801 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700802
Victor Zverovich7cae7632013-09-06 20:23:42 -0700803template void fmt::BasicWriter<char>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800804 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700805
Victor Zverovich93e41252013-09-08 13:07:04 -0700806template fmt::BasicWriter<char>::CharPtr
807 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
808 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700809
Victor Zverovich7cae7632013-09-06 20:23:42 -0700810template fmt::BasicWriter<char>::CharPtr
811 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800812 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700813
Victor Zveroviche78904b2014-04-23 08:27:50 -0700814template void fmt::BasicWriter<char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700815 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700816
Victor Zveroviche78904b2014-04-23 08:27:50 -0700817template unsigned fmt::BasicWriter<char>::FormatParser::ParseUInt(
818 const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700819
Victor Zveroviche78904b2014-04-23 08:27:50 -0700820template const fmt::BasicWriter<char>::ArgInfo
821 &fmt::BasicWriter<char>::FormatParser::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700822
Victor Zveroviche78904b2014-04-23 08:27:50 -0700823template void fmt::BasicWriter<char>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700824 const char *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700825
Victor Zveroviche78904b2014-04-23 08:27:50 -0700826template void fmt::BasicWriter<char>::FormatParser::Format(
827 BasicWriter<char> &writer, BasicStringRef<char> format,
828 std::size_t num_args, const ArgInfo *args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700829
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700830// Explicit instantiations for wchar_t.
831
Victor Zverovich7cae7632013-09-06 20:23:42 -0700832template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800833 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700834
Victor Zverovich7cae7632013-09-06 20:23:42 -0700835template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800836 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700837
Victor Zverovich7cae7632013-09-06 20:23:42 -0700838template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700839 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
840 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700841
Victor Zverovich7cae7632013-09-06 20:23:42 -0700842template fmt::BasicWriter<wchar_t>::CharPtr
843 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800844 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700845
Victor Zveroviche78904b2014-04-23 08:27:50 -0700846template void fmt::BasicWriter<wchar_t>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700847 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700848
Victor Zveroviche78904b2014-04-23 08:27:50 -0700849template unsigned fmt::BasicWriter<wchar_t>::FormatParser::ParseUInt(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700850 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700851
Victor Zveroviche78904b2014-04-23 08:27:50 -0700852template const fmt::BasicWriter<wchar_t>::ArgInfo
853 &fmt::BasicWriter<wchar_t>::FormatParser::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700854
Victor Zveroviche78904b2014-04-23 08:27:50 -0700855template void fmt::BasicWriter<wchar_t>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700856 const wchar_t *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700857
Victor Zveroviche78904b2014-04-23 08:27:50 -0700858template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
859 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
860 std::size_t num_args, const ArgInfo *args);
jdale88a9862fd2014-03-11 18:56:24 +0000861
862#if _MSC_VER
863# pragma warning(pop)
864#endif