blob: 517caba6e40eef3077fbca20b4ac5b1d8a81444d [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 Zverovich859a4972014-04-30 06:55:21 -0700170void fmt::internal::FormatSystemErrorMessage(
171 fmt::Writer &out, int error_code, fmt::StringRef message) {
172#ifndef _WIN32
173 Array<char, INLINE_BUFFER_SIZE> buffer;
174 buffer.resize(INLINE_BUFFER_SIZE);
175 char *system_message = 0;
176 for (;;) {
177 errno = 0;
178# ifdef _GNU_SOURCE
179 system_message = strerror_r(error_code, &buffer[0], buffer.size());
180# else
181 strerror_r(error_code, system_message = &buffer[0], buffer.size());
182# endif
183 if (errno == 0)
184 break;
185 if (errno != ERANGE) {
186 // Can't get error message, report error code instead.
187 out << message << ": error code = " << error_code;
188 return;
189 }
190 buffer.resize(buffer.size() * 2);
191 }
192 out << message << ": " << system_message;
193#else
194 class String {
195 private:
196 LPWSTR str_;
197
198 public:
199 String() : str_() {}
200 ~String() { LocalFree(str_); }
201 LPWSTR *ptr() { return &str_; }
202 LPCWSTR c_str() const { return str_; }
203 };
204 String system_message;
205 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
206 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
207 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
208 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
209 UTF16ToUTF8 utf8_message;
210 if (!utf8_message.Convert(system_message.c_str())) {
211 out << message << ": " << utf8_message;
212 return;
213 }
214 }
215 // Can't get error message, report error code instead.
216 out << message << ": error code = " << error_code;
217#endif
218}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700219
220// Fills the padding around the content and returns the pointer to the
221// content area.
222template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700223typename fmt::BasicWriter<Char>::CharPtr
224 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
225 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700226 std::size_t padding = total_size - content_size;
227 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700228 Char fill_char = static_cast<Char>(fill);
229 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700230 buffer += left_padding;
231 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700232 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700233 return content;
234}
235
236template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700237typename fmt::BasicWriter<Char>::CharPtr
238 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800239 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700240 unsigned width = spec.width();
241 if (width <= size) {
242 CharPtr p = GrowBuffer(size);
243 *p = sign;
244 return p + size - 1;
245 }
246 CharPtr p = GrowBuffer(width);
247 CharPtr end = p + width;
248 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800249 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700250 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700251 if (align == ALIGN_LEFT) {
252 *p = sign;
253 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700254 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700255 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700256 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700257 *p = sign;
258 p += size;
259 } else {
260 if (align == ALIGN_NUMERIC) {
261 if (sign) {
262 *p++ = sign;
263 --size;
264 }
265 } else {
266 *(end - size) = sign;
267 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700268 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700269 p = end;
270 }
271 return p - 1;
272}
273
274template <typename Char>
275template <typename T>
276void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800277 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700278 // Check type.
279 char type = spec.type();
280 bool upper = false;
281 switch (type) {
282 case 0:
283 type = 'g';
284 break;
285 case 'e': case 'f': case 'g':
286 break;
287 case 'F':
288#ifdef _MSC_VER
289 // MSVC's printf doesn't support 'F'.
290 type = 'f';
291#endif
292 // Fall through.
293 case 'E': case 'G':
294 upper = true;
295 break;
296 default:
297 internal::ReportUnknownType(type, "double");
298 break;
299 }
300
301 char sign = 0;
302 // Use SignBit instead of value < 0 because the latter is always
303 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000304 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700305 sign = '-';
306 value = -value;
307 } else if (spec.sign_flag()) {
308 sign = spec.plus_flag() ? '+' : ' ';
309 }
310
311 if (value != value) {
312 // Format NaN ourselves because sprintf's output is not consistent
313 // across platforms.
314 std::size_t size = 4;
315 const char *nan = upper ? " NAN" : " nan";
316 if (!sign) {
317 --size;
318 ++nan;
319 }
320 CharPtr out = FormatString(nan, size, spec);
321 if (sign)
322 *out = sign;
323 return;
324 }
325
jdale88a9862fd2014-03-11 18:56:24 +0000326 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700327 // Format infinity ourselves because sprintf's output is not consistent
328 // across platforms.
329 std::size_t size = 4;
330 const char *inf = upper ? " INF" : " inf";
331 if (!sign) {
332 --size;
333 ++inf;
334 }
335 CharPtr out = FormatString(inf, size, spec);
336 if (sign)
337 *out = sign;
338 return;
339 }
340
341 std::size_t offset = buffer_.size();
342 unsigned width = spec.width();
343 if (sign) {
344 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
345 if (width > 0)
346 --width;
347 ++offset;
348 }
349
350 // Build format string.
351 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
352 Char format[MAX_FORMAT_SIZE];
353 Char *format_ptr = format;
354 *format_ptr++ = '%';
355 unsigned width_for_sprintf = width;
356 if (spec.hash_flag())
357 *format_ptr++ = '#';
358 if (spec.align() == ALIGN_CENTER) {
359 width_for_sprintf = 0;
360 } else {
361 if (spec.align() == ALIGN_LEFT)
362 *format_ptr++ = '-';
363 if (width != 0)
364 *format_ptr++ = '*';
365 }
366 if (precision >= 0) {
367 *format_ptr++ = '.';
368 *format_ptr++ = '*';
369 }
370 if (internal::IsLongDouble<T>::VALUE)
371 *format_ptr++ = 'L';
372 *format_ptr++ = type;
373 *format_ptr = '\0';
374
375 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700376 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700377 for (;;) {
378 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700379#if _MSC_VER
380 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
381 // space for at least one extra character to make the size non-zero.
382 // Note that the buffer's capacity will increase by more than 1.
383 if (size == 0) {
384 buffer_.reserve(offset + 1);
385 size = buffer_.capacity() - offset;
386 }
387#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700388 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700389 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700390 start, size, format, width_for_sprintf, precision, value);
391 if (n >= 0 && offset + n < buffer_.capacity()) {
392 if (sign) {
393 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
394 *start != ' ') {
395 *(start - 1) = sign;
396 sign = 0;
397 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700398 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700399 }
400 ++n;
401 }
402 if (spec.align() == ALIGN_CENTER &&
403 spec.width() > static_cast<unsigned>(n)) {
404 unsigned width = spec.width();
405 CharPtr p = GrowBuffer(width);
406 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700407 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700408 return;
409 }
410 if (spec.fill() != ' ' || sign) {
411 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700412 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700413 if (sign)
414 *(start - 1) = sign;
415 }
416 GrowBuffer(n);
417 return;
418 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700419 // If n is negative we ask to increase the capacity by at least 1,
420 // but as std::vector, the buffer grows exponentially.
421 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700422 }
423}
424
425// Throws Exception(message) if format contains '}', otherwise throws
426// FormatError reporting unmatched '{'. The idea is that unmatched '{'
427// should override other errors.
428template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700429void fmt::BasicWriter<Char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700430 const Char *s, StringRef message) const {
431 for (int num_open_braces = num_open_braces_; *s; ++s) {
432 if (*s == '{') {
433 ++num_open_braces;
434 } else if (*s == '}') {
435 if (--num_open_braces == 0)
436 throw fmt::FormatError(message);
437 }
438 }
439 throw fmt::FormatError("unmatched '{' in format");
440}
441
442// Parses an unsigned integer advancing s to the end of the parsed input.
443// This function assumes that the first character of s is a digit.
444template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700445unsigned fmt::BasicWriter<Char>::FormatParser::ParseUInt(const Char *&s) const {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700446 assert('0' <= *s && *s <= '9');
447 unsigned value = 0;
448 do {
449 unsigned new_value = value * 10 + (*s++ - '0');
450 if (new_value < value) // Check if value wrapped around.
451 ReportError(s, "number is too big in format");
452 value = new_value;
453 } while ('0' <= *s && *s <= '9');
454 return value;
455}
456
457template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700458inline const typename fmt::BasicWriter<Char>::ArgInfo
459 &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700460 unsigned arg_index = 0;
461 if (*s < '0' || *s > '9') {
462 if (*s != '}' && *s != ':')
463 ReportError(s, "invalid argument index in format string");
464 if (next_arg_index_ < 0) {
465 ReportError(s,
466 "cannot switch from manual to automatic argument indexing");
467 }
468 arg_index = next_arg_index_++;
469 } else {
470 if (next_arg_index_ > 0) {
471 ReportError(s,
472 "cannot switch from automatic to manual argument indexing");
473 }
474 next_arg_index_ = -1;
475 arg_index = ParseUInt(s);
476 }
Victor Zveroviche78904b2014-04-23 08:27:50 -0700477 if (arg_index >= num_args_)
Victor Zverovich7cae7632013-09-06 20:23:42 -0700478 ReportError(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700479 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700480}
481
482template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700483void fmt::BasicWriter<Char>::FormatParser::CheckSign(
484 const Char *&s, const ArgInfo &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800485 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700486 if (arg.type > LAST_NUMERIC_TYPE) {
487 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700488 fmt::Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700489 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800490 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700491 ReportError(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700492 fmt::Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700493 }
494 ++s;
495}
496
497template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700498void fmt::BasicWriter<Char>::FormatParser::Format(
499 BasicWriter<Char> &writer, BasicStringRef<Char> format,
500 std::size_t num_args, const ArgInfo *args) {
501 const Char *start = format.c_str();
502 num_args_ = num_args;
503 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700504 next_arg_index_ = 0;
505 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700506 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700507 Char c = *s++;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700508 if (c != '{' && c != '}') continue;
509 if (*s == c) {
510 writer.buffer_.append(start, s);
511 start = ++s;
512 continue;
513 }
514 if (c == '}')
515 throw FormatError("unmatched '}' in format");
516 num_open_braces_= 1;
517 writer.buffer_.append(start, s - 1);
518
Victor Zverovich656a8372014-04-22 08:58:54 -0700519 const ArgInfo &arg = ParseArgIndex(s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700520
Victor Zverovichea5dce32014-01-28 12:47:37 -0800521 FormatSpec spec;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700522 int precision = -1;
523 if (*s == ':') {
524 ++s;
525
526 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700527 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700528 const Char *p = s + 1;
529 spec.align_ = ALIGN_DEFAULT;
530 do {
531 switch (*p) {
532 case '<':
533 spec.align_ = ALIGN_LEFT;
534 break;
535 case '>':
536 spec.align_ = ALIGN_RIGHT;
537 break;
538 case '=':
539 spec.align_ = ALIGN_NUMERIC;
540 break;
541 case '^':
542 spec.align_ = ALIGN_CENTER;
543 break;
544 }
545 if (spec.align_ != ALIGN_DEFAULT) {
546 if (p != s) {
547 if (c == '}') break;
548 if (c == '{')
549 ReportError(s, "invalid fill character '{'");
550 s += 2;
551 spec.fill_ = c;
552 } else ++s;
553 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
554 ReportError(s, "format specifier '=' requires numeric argument");
555 break;
556 }
557 } while (--p >= s);
558 }
559
560 // Parse sign.
561 switch (*s) {
562 case '+':
563 CheckSign(s, arg);
564 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
565 break;
566 case '-':
567 CheckSign(s, arg);
568 break;
569 case ' ':
570 CheckSign(s, arg);
571 spec.flags_ |= SIGN_FLAG;
572 break;
573 }
574
575 if (*s == '#') {
576 if (arg.type > LAST_NUMERIC_TYPE)
577 ReportError(s, "format specifier '#' requires numeric argument");
578 spec.flags_ |= HASH_FLAG;
579 ++s;
580 }
581
582 // Parse width and zero flag.
583 if ('0' <= *s && *s <= '9') {
584 if (*s == '0') {
585 if (arg.type > LAST_NUMERIC_TYPE)
586 ReportError(s, "format specifier '0' requires numeric argument");
587 spec.align_ = ALIGN_NUMERIC;
588 spec.fill_ = '0';
589 }
590 // Zero may be parsed again as a part of the width, but it is simpler
591 // and more efficient than checking if the next char is a digit.
592 unsigned value = ParseUInt(s);
593 if (value > INT_MAX)
594 ReportError(s, "number is too big in format");
595 spec.width_ = value;
596 }
597
598 // Parse precision.
599 if (*s == '.') {
600 ++s;
601 precision = 0;
602 if ('0' <= *s && *s <= '9') {
603 unsigned value = ParseUInt(s);
604 if (value > INT_MAX)
605 ReportError(s, "number is too big in format");
606 precision = value;
607 } else if (*s == '{') {
608 ++s;
609 ++num_open_braces_;
Victor Zverovich656a8372014-04-22 08:58:54 -0700610 const ArgInfo &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800611 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700612 switch (precision_arg.type) {
613 case INT:
614 if (precision_arg.int_value < 0)
615 ReportError(s, "negative precision in format");
616 value = precision_arg.int_value;
617 break;
618 case UINT:
619 value = precision_arg.uint_value;
620 break;
621 case LONG:
622 if (precision_arg.long_value < 0)
623 ReportError(s, "negative precision in format");
624 value = precision_arg.long_value;
625 break;
626 case ULONG:
627 value = precision_arg.ulong_value;
628 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800629 case LONG_LONG:
630 if (precision_arg.long_long_value < 0)
631 ReportError(s, "negative precision in format");
632 value = precision_arg.long_long_value;
633 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800634 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800635 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800636 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700637 default:
638 ReportError(s, "precision is not integer");
639 }
640 if (value > INT_MAX)
641 ReportError(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800642 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700643 if (*s++ != '}')
644 throw FormatError("unmatched '{' in format");
645 --num_open_braces_;
646 } else {
647 ReportError(s, "missing precision in format");
648 }
649 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
650 ReportError(s,
651 "precision specifier requires floating-point argument");
652 }
653 }
654
655 // Parse type.
656 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700657 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700658 }
659
660 if (*s++ != '}')
661 throw FormatError("unmatched '{' in format");
662 start = s;
663
664 // Format argument.
665 switch (arg.type) {
666 case INT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700667 writer.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700668 break;
669 case UINT:
Victor Zverovich03f68852014-04-20 08:46:09 -0700670 writer.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700671 break;
672 case LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700673 writer.FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700674 break;
675 case ULONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700676 writer.FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700677 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -0800678 case LONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700679 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -0800680 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800681 case ULONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -0700682 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800683 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700684 case DOUBLE:
685 writer.FormatDouble(arg.double_value, spec, precision);
686 break;
687 case LONG_DOUBLE:
688 writer.FormatDouble(arg.long_double_value, spec, precision);
689 break;
690 case CHAR: {
691 if (spec.type_ && spec.type_ != 'c')
692 internal::ReportUnknownType(spec.type_, "char");
693 typedef typename BasicWriter<Char>::CharPtr CharPtr;
694 CharPtr out = CharPtr();
695 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700696 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700697 out = writer.GrowBuffer(spec.width_);
698 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700699 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700700 out += spec.width_ - 1;
701 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700702 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700703 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -0700704 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700705 }
706 } else {
707 out = writer.GrowBuffer(1);
708 }
jdale884cabe162014-03-11 19:03:26 +0000709 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700710 break;
711 }
712 case STRING: {
713 if (spec.type_ && spec.type_ != 's')
714 internal::ReportUnknownType(spec.type_, "string");
715 const Char *str = arg.string.value;
716 std::size_t size = arg.string.size;
717 if (size == 0) {
718 if (!str)
719 throw FormatError("string pointer is null");
720 if (*str)
721 size = std::char_traits<Char>::length(str);
722 }
723 writer.FormatString(str, size, spec);
724 break;
725 }
726 case POINTER:
727 if (spec.type_ && spec.type_ != 'p')
728 internal::ReportUnknownType(spec.type_, "pointer");
729 spec.flags_= HASH_FLAG;
730 spec.type_ = 'x';
Victor Zverovich03f68852014-04-20 08:46:09 -0700731 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700732 break;
733 case CUSTOM:
734 if (spec.type_)
735 internal::ReportUnknownType(spec.type_, "object");
736 arg.custom.format(writer, arg.custom.value, spec);
737 break;
738 default:
739 assert(false);
740 break;
741 }
742 }
743 writer.buffer_.append(start, s);
744}
745
Victor Zverovich859a4972014-04-30 06:55:21 -0700746void fmt::SystemErrorSink::operator()(const fmt::Writer &w) const {
747 Writer message;
748 internal::FormatSystemErrorMessage(message, error_code_, w.c_str());
749 throw SystemError(message.c_str(), error_code_);
750}
751
Victor Zverovichd9db8982014-04-28 08:59:29 -0700752void fmt::ANSITerminalSink::operator()(
753 const fmt::BasicWriter<char> &w) const {
Victor Zverovich43fe1002014-02-19 14:20:26 -0800754 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +0000755 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovichd9db8982014-04-28 08:59:29 -0700756 std::fputs(escape, file_);
757 std::fwrite(w.data(), 1, w.size(), file_);
758 std::fputs(RESET_COLOR, file_);
Victor Zverovich43fe1002014-02-19 14:20:26 -0800759}
Victor Zverovich6968ef32014-02-19 13:51:23 -0800760
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700761// Explicit instantiations for char.
762
Victor Zverovich7cae7632013-09-06 20:23:42 -0700763template void fmt::BasicWriter<char>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800764 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700765
Victor Zverovich7cae7632013-09-06 20:23:42 -0700766template void fmt::BasicWriter<char>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800767 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700768
Victor Zverovich93e41252013-09-08 13:07:04 -0700769template fmt::BasicWriter<char>::CharPtr
770 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
771 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700772
Victor Zverovich7cae7632013-09-06 20:23:42 -0700773template fmt::BasicWriter<char>::CharPtr
774 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800775 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700776
Victor Zveroviche78904b2014-04-23 08:27:50 -0700777template void fmt::BasicWriter<char>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700778 const char *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700779
Victor Zveroviche78904b2014-04-23 08:27:50 -0700780template unsigned fmt::BasicWriter<char>::FormatParser::ParseUInt(
781 const char *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700782
Victor Zveroviche78904b2014-04-23 08:27:50 -0700783template const fmt::BasicWriter<char>::ArgInfo
784 &fmt::BasicWriter<char>::FormatParser::ParseArgIndex(const char *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700785
Victor Zveroviche78904b2014-04-23 08:27:50 -0700786template void fmt::BasicWriter<char>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700787 const char *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700788
Victor Zveroviche78904b2014-04-23 08:27:50 -0700789template void fmt::BasicWriter<char>::FormatParser::Format(
790 BasicWriter<char> &writer, BasicStringRef<char> format,
791 std::size_t num_args, const ArgInfo *args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700792
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700793// Explicit instantiations for wchar_t.
794
Victor Zverovich7cae7632013-09-06 20:23:42 -0700795template void fmt::BasicWriter<wchar_t>::FormatDouble<double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800796 double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700797
Victor Zverovich7cae7632013-09-06 20:23:42 -0700798template void fmt::BasicWriter<wchar_t>::FormatDouble<long double>(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800799 long double value, const FormatSpec &spec, int precision);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700800
Victor Zverovich7cae7632013-09-06 20:23:42 -0700801template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -0700802 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
803 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700804
Victor Zverovich7cae7632013-09-06 20:23:42 -0700805template fmt::BasicWriter<wchar_t>::CharPtr
806 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800807 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700808
Victor Zveroviche78904b2014-04-23 08:27:50 -0700809template void fmt::BasicWriter<wchar_t>::FormatParser::ReportError(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700810 const wchar_t *s, StringRef message) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700811
Victor Zveroviche78904b2014-04-23 08:27:50 -0700812template unsigned fmt::BasicWriter<wchar_t>::FormatParser::ParseUInt(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700813 const wchar_t *&s) const;
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700814
Victor Zveroviche78904b2014-04-23 08:27:50 -0700815template const fmt::BasicWriter<wchar_t>::ArgInfo
816 &fmt::BasicWriter<wchar_t>::FormatParser::ParseArgIndex(const wchar_t *&s);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700817
Victor Zveroviche78904b2014-04-23 08:27:50 -0700818template void fmt::BasicWriter<wchar_t>::FormatParser::CheckSign(
Victor Zverovich656a8372014-04-22 08:58:54 -0700819 const wchar_t *&s, const ArgInfo &arg);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700820
Victor Zveroviche78904b2014-04-23 08:27:50 -0700821template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
822 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
823 std::size_t num_args, const ArgInfo *args);
jdale88a9862fd2014-03-11 18:56:24 +0000824
825#if _MSC_VER
826# pragma warning(pop)
827#endif