blob: 007f235c2599a5408a2dd381abfa840d9dfb892d [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>
45#endif
46
Victor Zverovich447e02c2014-02-15 10:48:34 -080047using fmt::ULongLong;
48
jdale88a9862fd2014-03-11 18:56:24 +000049#if _MSC_VER
50# pragma warning(push)
51# pragma warning(disable: 4127) // conditional expression is constant
52#endif
53
Victor Zverovich9ff3b972013-09-07 10:15:08 -070054namespace {
55
56#ifndef _MSC_VER
57
58inline int SignBit(double value) {
59 // When compiled in C++11 mode signbit is no longer a macro but a function
60 // defined in namespace std and the macro is undefined.
Victor Zverovichf2e06802014-04-10 10:49:55 -070061#ifdef signbit
Victor Zverovich9ff3b972013-09-07 10:15:08 -070062 return signbit(value);
Victor Zverovichf2e06802014-04-10 10:49:55 -070063#else
64 return std::signbit(value);
65#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070066}
67
68inline int IsInf(double x) {
69#ifdef isinf
70 return isinf(x);
71#else
72 return std::isinf(x);
73#endif
74}
75
76#define FMT_SNPRINTF snprintf
77
Victor Zverovicha684d0c2013-12-27 08:00:10 -080078#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070079
80inline int SignBit(double value) {
81 if (value < 0) return 1;
82 if (value == value) return 0;
83 int dec = 0, sign = 0;
84 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
85 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
86 return sign;
87}
88
89inline int IsInf(double x) { return !_finite(x); }
90
Victor Zverovicha684d0c2013-12-27 08:00:10 -080091inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
92 va_list args;
93 va_start(args, format);
94 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
95 va_end(args);
96 return result;
97}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070098
99#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800100
101const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovichb605b392013-09-09 22:21:40 -0700102}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700103
Victor Zverovichb605b392013-09-09 22:21:40 -0700104template <typename T>
105int fmt::internal::CharTraits<char>::FormatFloat(
106 char *buffer, std::size_t size, const char *format,
107 unsigned width, int precision, T value) {
108 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700109 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700110 FMT_SNPRINTF(buffer, size, format, value) :
111 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700112 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700113 return precision < 0 ?
114 FMT_SNPRINTF(buffer, size, format, width, value) :
115 FMT_SNPRINTF(buffer, size, format, width, precision, value);
116}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700117
Victor Zverovichb605b392013-09-09 22:21:40 -0700118template <typename T>
119int fmt::internal::CharTraits<wchar_t>::FormatFloat(
120 wchar_t *buffer, std::size_t size, const wchar_t *format,
121 unsigned width, int precision, T value) {
122 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700123 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700124 swprintf(buffer, size, format, value) :
125 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700126 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700127 return precision < 0 ?
128 swprintf(buffer, size, format, width, value) :
129 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700130}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800131
Victor Zverovich65d47e52013-09-09 06:51:03 -0700132const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800133 "0001020304050607080910111213141516171819"
134 "2021222324252627282930313233343536373839"
135 "4041424344454647484950515253545556575859"
136 "6061626364656667686970717273747576777879"
137 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800138
Victor Zverovichf1d85162014-02-19 13:02:22 -0800139#define FMT_POWERS_OF_10(factor) \
140 factor * 10, \
141 factor * 100, \
142 factor * 1000, \
143 factor * 10000, \
144 factor * 100000, \
145 factor * 1000000, \
146 factor * 10000000, \
147 factor * 100000000, \
148 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800149
Victor Zverovichf1d85162014-02-19 13:02:22 -0800150const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800151const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800152 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800153 FMT_POWERS_OF_10(1),
154 FMT_POWERS_OF_10(ULongLong(1000000000)),
155 // Multiply several constants instead of using a single long long constants
156 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800157 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800158};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800159
Victor Zverovich687301c2013-01-26 16:07:28 -0800160void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800161 if (std::isprint(static_cast<unsigned char>(code))) {
162 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800163 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800164 }
165 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800166 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800167 << static_cast<unsigned>(code) << type));
168}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700169
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700170#ifdef _WIN32
171
172fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
173 int length = MultiByteToWideChar(
174 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
175 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
176 if (length == 0)
177 ThrowSystemError(GetLastError(), ERROR);
178 buffer_.resize(length);
179 length = MultiByteToWideChar(
180 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
181 if (length == 0)
182 ThrowSystemError(GetLastError(), ERROR);
183}
184
185fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
186 if (int error_code = Convert(s)) {
187 ThrowSystemError(GetLastError(),
188 "cannot convert string from UTF-16 to UTF-8");
189 }
190}
191
192int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) {
193 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
194 if (length == 0)
195 return GetLastError();
196 buffer_.resize(length);
197 length = WideCharToMultiByte(
198 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
199 if (length == 0)
200 return GetLastError();
201 return 0;
202}
203
204#endif
205
Victor Zverovich859a4972014-04-30 06:55:21 -0700206void fmt::internal::FormatSystemErrorMessage(
207 fmt::Writer &out, int error_code, fmt::StringRef message) {
208#ifndef _WIN32
209 Array<char, INLINE_BUFFER_SIZE> buffer;
210 buffer.resize(INLINE_BUFFER_SIZE);
211 char *system_message = 0;
212 for (;;) {
213 errno = 0;
214# ifdef _GNU_SOURCE
215 system_message = strerror_r(error_code, &buffer[0], buffer.size());
216# else
217 strerror_r(error_code, system_message = &buffer[0], buffer.size());
218# endif
219 if (errno == 0)
220 break;
221 if (errno != ERANGE) {
222 // Can't get error message, report error code instead.
223 out << message << ": error code = " << error_code;
224 return;
225 }
226 buffer.resize(buffer.size() * 2);
227 }
228 out << message << ": " << system_message;
229#else
230 class String {
231 private:
232 LPWSTR str_;
233
234 public:
235 String() : str_() {}
236 ~String() { LocalFree(str_); }
237 LPWSTR *ptr() { return &str_; }
238 LPCWSTR c_str() const { return str_; }
239 };
240 String system_message;
241 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
242 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
243 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
244 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
245 UTF16ToUTF8 utf8_message;
246 if (!utf8_message.Convert(system_message.c_str())) {
Victor Zverovichc16217b2014-04-30 07:38:43 -0700247 out << message << ": " << c_str(utf8_message);
Victor Zverovich859a4972014-04-30 06:55:21 -0700248 return;
249 }
250 }
251 // Can't get error message, report error code instead.
252 out << message << ": error code = " << error_code;
253#endif
254}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700255
256// Fills the padding around the content and returns the pointer to the
257// content area.
258template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700259typename fmt::BasicWriter<Char>::CharPtr
260 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
261 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700262 std::size_t padding = total_size - content_size;
263 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700264 Char fill_char = static_cast<Char>(fill);
265 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700266 buffer += left_padding;
267 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700268 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700269 return content;
270}
271
272template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700273typename fmt::BasicWriter<Char>::CharPtr
274 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800275 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700276 unsigned width = spec.width();
277 if (width <= size) {
278 CharPtr p = GrowBuffer(size);
279 *p = sign;
280 return p + size - 1;
281 }
282 CharPtr p = GrowBuffer(width);
283 CharPtr end = p + width;
284 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800285 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700286 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700287 if (align == ALIGN_LEFT) {
288 *p = sign;
289 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700290 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700291 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700292 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700293 *p = sign;
294 p += size;
295 } else {
296 if (align == ALIGN_NUMERIC) {
297 if (sign) {
298 *p++ = sign;
299 --size;
300 }
301 } else {
302 *(end - size) = sign;
303 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700304 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700305 p = end;
306 }
307 return p - 1;
308}
309
310template <typename Char>
311template <typename T>
312void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800313 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700314 // Check type.
315 char type = spec.type();
316 bool upper = false;
317 switch (type) {
318 case 0:
319 type = 'g';
320 break;
321 case 'e': case 'f': case 'g':
322 break;
323 case 'F':
324#ifdef _MSC_VER
325 // MSVC's printf doesn't support 'F'.
326 type = 'f';
327#endif
328 // Fall through.
329 case 'E': case 'G':
330 upper = true;
331 break;
332 default:
333 internal::ReportUnknownType(type, "double");
334 break;
335 }
336
337 char sign = 0;
338 // Use SignBit instead of value < 0 because the latter is always
339 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000340 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700341 sign = '-';
342 value = -value;
343 } else if (spec.sign_flag()) {
344 sign = spec.plus_flag() ? '+' : ' ';
345 }
346
347 if (value != value) {
348 // Format NaN ourselves because sprintf's output is not consistent
349 // across platforms.
350 std::size_t size = 4;
351 const char *nan = upper ? " NAN" : " nan";
352 if (!sign) {
353 --size;
354 ++nan;
355 }
356 CharPtr out = FormatString(nan, size, spec);
357 if (sign)
358 *out = sign;
359 return;
360 }
361
jdale88a9862fd2014-03-11 18:56:24 +0000362 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700363 // Format infinity ourselves because sprintf's output is not consistent
364 // across platforms.
365 std::size_t size = 4;
366 const char *inf = upper ? " INF" : " inf";
367 if (!sign) {
368 --size;
369 ++inf;
370 }
371 CharPtr out = FormatString(inf, size, spec);
372 if (sign)
373 *out = sign;
374 return;
375 }
376
377 std::size_t offset = buffer_.size();
378 unsigned width = spec.width();
379 if (sign) {
380 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
381 if (width > 0)
382 --width;
383 ++offset;
384 }
385
386 // Build format string.
387 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
388 Char format[MAX_FORMAT_SIZE];
389 Char *format_ptr = format;
390 *format_ptr++ = '%';
391 unsigned width_for_sprintf = width;
392 if (spec.hash_flag())
393 *format_ptr++ = '#';
394 if (spec.align() == ALIGN_CENTER) {
395 width_for_sprintf = 0;
396 } else {
397 if (spec.align() == ALIGN_LEFT)
398 *format_ptr++ = '-';
399 if (width != 0)
400 *format_ptr++ = '*';
401 }
402 if (precision >= 0) {
403 *format_ptr++ = '.';
404 *format_ptr++ = '*';
405 }
406 if (internal::IsLongDouble<T>::VALUE)
407 *format_ptr++ = 'L';
408 *format_ptr++ = type;
409 *format_ptr = '\0';
410
411 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700412 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700413 for (;;) {
414 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700415#if _MSC_VER
416 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
417 // space for at least one extra character to make the size non-zero.
418 // Note that the buffer's capacity will increase by more than 1.
419 if (size == 0) {
420 buffer_.reserve(offset + 1);
421 size = buffer_.capacity() - offset;
422 }
423#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700424 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700425 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700426 start, size, format, width_for_sprintf, precision, value);
427 if (n >= 0 && offset + n < buffer_.capacity()) {
428 if (sign) {
429 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
430 *start != ' ') {
431 *(start - 1) = sign;
432 sign = 0;
433 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700434 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700435 }
436 ++n;
437 }
438 if (spec.align() == ALIGN_CENTER &&
439 spec.width() > static_cast<unsigned>(n)) {
440 unsigned width = spec.width();
441 CharPtr p = GrowBuffer(width);
442 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700443 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700444 return;
445 }
446 if (spec.fill() != ' ' || sign) {
447 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700448 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700449 if (sign)
450 *(start - 1) = sign;
451 }
452 GrowBuffer(n);
453 return;
454 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700455 // If n is negative we ask to increase the capacity by at least 1,
456 // but as std::vector, the buffer grows exponentially.
457 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700458 }
459}
460
461// Throws Exception(message) if format contains '}', otherwise throws
462// FormatError reporting unmatched '{'. The idea is that unmatched '{'
463// should override other errors.
464template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700465void fmt::BasicWriter<Char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700466 const Char *s, StringRef message) const {
467 for (int num_open_braces = num_open_braces_; *s; ++s) {
468 if (*s == '{') {
469 ++num_open_braces;
470 } else if (*s == '}') {
471 if (--num_open_braces == 0)
472 throw fmt::FormatError(message);
473 }
474 }
475 throw fmt::FormatError("unmatched '{' in format");
476}
477
478// Parses an unsigned integer advancing s to the end of the parsed input.
479// This function assumes that the first character of s is a digit.
480template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700481unsigned fmt::BasicWriter<Char>::FormatParser::ParseUInt(const Char *&s) const {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700482 assert('0' <= *s && *s <= '9');
483 unsigned value = 0;
484 do {
485 unsigned new_value = value * 10 + (*s++ - '0');
486 if (new_value < value) // Check if value wrapped around.
487 ReportError(s, "number is too big in format");
488 value = new_value;
489 } while ('0' <= *s && *s <= '9');
490 return value;
491}
492
493template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700494inline const typename fmt::BasicWriter<Char>::ArgInfo
495 &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700496 unsigned arg_index = 0;
497 if (*s < '0' || *s > '9') {
498 if (*s != '}' && *s != ':')
499 ReportError(s, "invalid argument index in format string");
500 if (next_arg_index_ < 0) {
501 ReportError(s,
502 "cannot switch from manual to automatic argument indexing");
503 }
504 arg_index = next_arg_index_++;
505 } else {
506 if (next_arg_index_ > 0) {
507 ReportError(s,
508 "cannot switch from automatic to manual argument indexing");
509 }
510 next_arg_index_ = -1;
511 arg_index = ParseUInt(s);
512 }
Victor Zveroviche78904b2014-04-23 08:27:50 -0700513 if (arg_index >= num_args_)
Victor Zverovich7cae7632013-09-06 20:23:42 -0700514 ReportError(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700515 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700516}
517
518template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700519void fmt::BasicWriter<Char>::FormatParser::CheckSign(
520 const Char *&s, const ArgInfo &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800521 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700522 if (arg.type > LAST_NUMERIC_TYPE) {
523 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700524 fmt::Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700525 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800526 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700527 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700528 fmt::Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700529 }
530 ++s;
531}
532
533template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700534void fmt::BasicWriter<Char>::FormatParser::Format(
535 BasicWriter<Char> &writer, BasicStringRef<Char> format,
536 std::size_t num_args, const ArgInfo *args) {
537 const Char *start = format.c_str();
538 num_args_ = num_args;
539 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700540 next_arg_index_ = 0;
541 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700542 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700543 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700544 if (c != '{' && c != '}') continue;
545 if (*s == c) {
546 writer.buffer_.append(start, s);
547 start = ++s;
548 continue;
549 }
550 if (c == '}')
551 throw FormatError("unmatched '}' in format");
552 num_open_braces_= 1;
553 writer.buffer_.append(start, s - 1);
554
Victor Zverovich656a8372014-04-22 08:58:54 -0700555 const ArgInfo &arg = ParseArgIndex(s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700556
Victor Zverovichea5dce32014-01-28 12:47:37 -0800557 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700558 int precision = -1;
559 if (*s == ':') {
560 ++s;
561
562 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700563 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700564 const Char *p = s + 1;
565 spec.align_ = ALIGN_DEFAULT;
566 do {
567 switch (*p) {
568 case '<':
569 spec.align_ = ALIGN_LEFT;
570 break;
571 case '>':
572 spec.align_ = ALIGN_RIGHT;
573 break;
574 case '=':
575 spec.align_ = ALIGN_NUMERIC;
576 break;
577 case '^':
578 spec.align_ = ALIGN_CENTER;
579 break;
580 }
581 if (spec.align_ != ALIGN_DEFAULT) {
582 if (p != s) {
583 if (c == '}') break;
584 if (c == '{')
585 ReportError(s, "invalid fill character '{'");
586 s += 2;
587 spec.fill_ = c;
588 } else ++s;
589 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
590 ReportError(s, "format specifier '=' requires numeric argument");
591 break;
592 }
593 } while (--p >= s);
594 }
595
596 // Parse sign.
597 switch (*s) {
598 case '+':
599 CheckSign(s, arg);
600 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
601 break;
602 case '-':
603 CheckSign(s, arg);
604 break;
605 case ' ':
606 CheckSign(s, arg);
607 spec.flags_ |= SIGN_FLAG;
608 break;
609 }
610
611 if (*s == '#') {
612 if (arg.type > LAST_NUMERIC_TYPE)
613 ReportError(s, "format specifier '#' requires numeric argument");
614 spec.flags_ |= HASH_FLAG;
615 ++s;
616 }
617
618 // Parse width and zero flag.
619 if ('0' <= *s && *s <= '9') {
620 if (*s == '0') {
621 if (arg.type > LAST_NUMERIC_TYPE)
622 ReportError(s, "format specifier '0' requires numeric argument");
623 spec.align_ = ALIGN_NUMERIC;
624 spec.fill_ = '0';
625 }
626 // Zero may be parsed again as a part of the width, but it is simpler
627 // and more efficient than checking if the next char is a digit.
628 unsigned value = ParseUInt(s);
629 if (value > INT_MAX)
630 ReportError(s, "number is too big in format");
631 spec.width_ = value;
632 }
633
634 // Parse precision.
635 if (*s == '.') {
636 ++s;
637 precision = 0;
638 if ('0' <= *s && *s <= '9') {
639 unsigned value = ParseUInt(s);
640 if (value > INT_MAX)
641 ReportError(s, "number is too big in format");
642 precision = value;
643 } else if (*s == '{') {
644 ++s;
645 ++num_open_braces_;
Victor Zverovich656a8372014-04-22 08:58:54 -0700646 const ArgInfo &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800647 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700648 switch (precision_arg.type) {
649 case INT:
650 if (precision_arg.int_value < 0)
651 ReportError(s, "negative precision in format");
652 value = precision_arg.int_value;
653 break;
654 case UINT:
655 value = precision_arg.uint_value;
656 break;
657 case LONG:
658 if (precision_arg.long_value < 0)
659 ReportError(s, "negative precision in format");
660 value = precision_arg.long_value;
661 break;
662 case ULONG:
663 value = precision_arg.ulong_value;
664 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800665 case LONG_LONG:
666 if (precision_arg.long_long_value < 0)
667 ReportError(s, "negative precision in format");
668 value = precision_arg.long_long_value;
669 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800670 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800671 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800672 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700673 default:
674 ReportError(s, "precision is not integer");
675 }
676 if (value > INT_MAX)
677 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800678 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700679 if (*s++ != '}')
680 throw FormatError("unmatched '{' in format");
681 --num_open_braces_;
682 } else {
683 ReportError(s, "missing precision in format");
684 }
685 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
686 ReportError(s,
687 "precision specifier requires floating-point argument");
688 }
689 }
690
691 // Parse type.
692 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700693 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700694 }
695
696 if (*s++ != '}')
697 throw FormatError("unmatched '{' in format");
698 start = s;
699
700 // Format argument.
701 switch (arg.type) {
702 case INT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700703 writer.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700704 break;
705 case UINT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700706 writer.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700707 break;
708 case LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700709 writer.FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700710 break;
711 case ULONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700712 writer.FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700713 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800714 case LONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700715 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800716 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800717 case ULONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700718 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800719 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700720 case DOUBLE:
721 writer.FormatDouble(arg.double_value, spec, precision);
722 break;
723 case LONG_DOUBLE:
724 writer.FormatDouble(arg.long_double_value, spec, precision);
725 break;
726 case CHAR: {
727 if (spec.type_ && spec.type_ != 'c')
728 internal::ReportUnknownType(spec.type_, "char");
729 typedef typename BasicWriter<Char>::CharPtr CharPtr;
730 CharPtr out = CharPtr();
731 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700732 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700733 out = writer.GrowBuffer(spec.width_);
734 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700735 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700736 out += spec.width_ - 1;
737 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700738 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700739 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700740 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700741 }
742 } else {
743 out = writer.GrowBuffer(1);
744 }
jdale884cabe162014-03-11 19:03:26 +0000745 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700746 break;
747 }
748 case STRING: {
749 if (spec.type_ && spec.type_ != 's')
750 internal::ReportUnknownType(spec.type_, "string");
751 const Char *str = arg.string.value;
752 std::size_t size = arg.string.size;
753 if (size == 0) {
754 if (!str)
755 throw FormatError("string pointer is null");
756 if (*str)
757 size = std::char_traits<Char>::length(str);
758 }
759 writer.FormatString(str, size, spec);
760 break;
761 }
762 case POINTER:
763 if (spec.type_ && spec.type_ != 'p')
764 internal::ReportUnknownType(spec.type_, "pointer");
765 spec.flags_= HASH_FLAG;
766 spec.type_ = 'x';
Victor Zverovich03f68852014-04-20 08:46:09 -0700767 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700768 break;
769 case CUSTOM:
770 if (spec.type_)
771 internal::ReportUnknownType(spec.type_, "object");
772 arg.custom.format(writer, arg.custom.value, spec);
773 break;
774 default:
775 assert(false);
776 break;
777 }
778 }
779 writer.buffer_.append(start, s);
780}
781
Victor Zverovich859a4972014-04-30 06:55:21 -0700782void fmt::SystemErrorSink::operator()(const fmt::Writer &w) const {
783 Writer message;
784 internal::FormatSystemErrorMessage(message, error_code_, w.c_str());
785 throw SystemError(message.c_str(), error_code_);
786}
787
Victor Zverovichd9db8982014-04-28 08:59:29 -0700788void fmt::ANSITerminalSink::operator()(
789 const fmt::BasicWriter<char> &w) const {
Victor Zverovich43fe1002014-02-19 14:20:26 -0800790 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +0000791 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovichd9db8982014-04-28 08:59:29 -0700792 std::fputs(escape, file_);
793 std::fwrite(w.data(), 1, w.size(), file_);
794 std::fputs(RESET_COLOR, file_);
Victor Zverovich43fe1002014-02-19 14:20:26 -0800795}
Victor Zverovich6968ef32014-02-19 13:51:23 -0800796
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700797// Explicit instantiations for char.
798
Victor Zverovich7cae7632013-09-06 20:23:42 -0700799template void fmt::BasicWriter<char>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800800 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700801
Victor Zverovich7cae7632013-09-06 20:23:42 -0700802template void fmt::BasicWriter<char>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800803 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700804
Victor Zverovich93e41252013-09-08 13:07:04 -0700805template fmt::BasicWriter<char>::CharPtr
806 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
807 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700808
Victor Zverovich7cae7632013-09-06 20:23:42 -0700809template fmt::BasicWriter<char>::CharPtr
810 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800811 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700812
Victor Zveroviche78904b2014-04-23 08:27:50 -0700813template void fmt::BasicWriter<char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700814 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700815
Victor Zveroviche78904b2014-04-23 08:27:50 -0700816template unsigned fmt::BasicWriter<char>::FormatParser::ParseUInt(
817 const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700818
Victor Zveroviche78904b2014-04-23 08:27:50 -0700819template const fmt::BasicWriter<char>::ArgInfo
820 &fmt::BasicWriter<char>::FormatParser::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700821
Victor Zveroviche78904b2014-04-23 08:27:50 -0700822template void fmt::BasicWriter<char>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700823 const char *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700824
Victor Zveroviche78904b2014-04-23 08:27:50 -0700825template void fmt::BasicWriter<char>::FormatParser::Format(
826 BasicWriter<char> &writer, BasicStringRef<char> format,
827 std::size_t num_args, const ArgInfo *args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700828
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700829// Explicit instantiations for wchar_t.
830
Victor Zverovich7cae7632013-09-06 20:23:42 -0700831template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800832 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700833
Victor Zverovich7cae7632013-09-06 20:23:42 -0700834template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800835 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700836
Victor Zverovich7cae7632013-09-06 20:23:42 -0700837template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700838 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
839 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700840
Victor Zverovich7cae7632013-09-06 20:23:42 -0700841template fmt::BasicWriter<wchar_t>::CharPtr
842 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800843 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700844
Victor Zveroviche78904b2014-04-23 08:27:50 -0700845template void fmt::BasicWriter<wchar_t>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700846 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700847
Victor Zveroviche78904b2014-04-23 08:27:50 -0700848template unsigned fmt::BasicWriter<wchar_t>::FormatParser::ParseUInt(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700849 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700850
Victor Zveroviche78904b2014-04-23 08:27:50 -0700851template const fmt::BasicWriter<wchar_t>::ArgInfo
852 &fmt::BasicWriter<wchar_t>::FormatParser::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700853
Victor Zveroviche78904b2014-04-23 08:27:50 -0700854template void fmt::BasicWriter<wchar_t>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700855 const wchar_t *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700856
Victor Zveroviche78904b2014-04-23 08:27:50 -0700857template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
858 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
859 std::size_t num_args, const ArgInfo *args);
jdale88a9862fd2014-03-11 18:56:24 +0000860
861#if _MSC_VER
862# pragma warning(pop)
863#endif