blob: 2790e3b6008fe3953c7c884f24802d3d05e1a8c9 [file] [log] [blame]
Victor Zverovichb076df42012-12-07 08:31:09 -08001/*
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07002 Formatting library for C++
Victor Zverovichfaccb4c2012-12-12 07:44:41 -08003
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
Victor Zverovichdcd039d2014-05-01 07:09:42 -070044# define WIN32_LEAN_AND_MEAN
Constantine Tarasenkov6aace692014-06-11 02:38:57 +040045# ifdef __MINGW32__
46# include <cstring>
47# endif
Victor Zverovich859a4972014-04-30 06:55:21 -070048# include <windows.h>
Victor Zveroviched2bdba2014-04-30 07:41:54 -070049# undef ERROR
Victor Zverovich859a4972014-04-30 06:55:21 -070050#endif
51
Victor Zverovich447e02c2014-02-15 10:48:34 -080052using fmt::ULongLong;
53
jdale88a9862fd2014-03-11 18:56:24 +000054#if _MSC_VER
55# pragma warning(push)
56# pragma warning(disable: 4127) // conditional expression is constant
57#endif
58
Victor Zverovich9ff3b972013-09-07 10:15:08 -070059namespace {
60
61#ifndef _MSC_VER
62
63inline int SignBit(double value) {
64 // When compiled in C++11 mode signbit is no longer a macro but a function
65 // defined in namespace std and the macro is undefined.
Victor Zverovichf2e06802014-04-10 10:49:55 -070066#ifdef signbit
Victor Zverovich9ff3b972013-09-07 10:15:08 -070067 return signbit(value);
Victor Zverovichf2e06802014-04-10 10:49:55 -070068#else
69 return std::signbit(value);
70#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070071}
72
73inline int IsInf(double x) {
74#ifdef isinf
75 return isinf(x);
76#else
77 return std::isinf(x);
78#endif
79}
80
81#define FMT_SNPRINTF snprintf
82
Victor Zverovicha684d0c2013-12-27 08:00:10 -080083#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070084
85inline int SignBit(double value) {
86 if (value < 0) return 1;
87 if (value == value) return 0;
88 int dec = 0, sign = 0;
89 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
90 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
91 return sign;
92}
93
94inline int IsInf(double x) { return !_finite(x); }
95
Victor Zverovicha684d0c2013-12-27 08:00:10 -080096inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
97 va_list args;
98 va_start(args, format);
99 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
100 va_end(args);
101 return result;
102}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700103
104#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800105
106const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700107
108typedef void (*FormatFunc)(fmt::Writer &, int , fmt::StringRef);
109
110void ReportError(FormatFunc func,
111 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
112 try {
113 fmt::Writer full_message;
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700114 func(full_message, error_code, message); // TODO: make sure this doesn't throw
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700115 std::fwrite(full_message.c_str(), full_message.size(), 1, stderr);
116 std::fputc('\n', stderr);
117 } catch (...) {}
Victor Zverovichb605b392013-09-09 22:21:40 -0700118}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700119} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700120
Victor Zverovichb605b392013-09-09 22:21:40 -0700121template <typename T>
122int fmt::internal::CharTraits<char>::FormatFloat(
123 char *buffer, std::size_t size, const char *format,
124 unsigned width, int precision, T value) {
125 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700126 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700127 FMT_SNPRINTF(buffer, size, format, value) :
128 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700129 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700130 return precision < 0 ?
131 FMT_SNPRINTF(buffer, size, format, width, value) :
132 FMT_SNPRINTF(buffer, size, format, width, precision, value);
133}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700134
Victor Zverovichb605b392013-09-09 22:21:40 -0700135template <typename T>
136int fmt::internal::CharTraits<wchar_t>::FormatFloat(
137 wchar_t *buffer, std::size_t size, const wchar_t *format,
138 unsigned width, int precision, T value) {
139 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700140 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700141 swprintf(buffer, size, format, value) :
142 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700143 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700144 return precision < 0 ?
145 swprintf(buffer, size, format, width, value) :
146 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700147}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800148
Victor Zverovich65d47e52013-09-09 06:51:03 -0700149const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800150 "0001020304050607080910111213141516171819"
151 "2021222324252627282930313233343536373839"
152 "4041424344454647484950515253545556575859"
153 "6061626364656667686970717273747576777879"
154 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800155
Victor Zverovichf1d85162014-02-19 13:02:22 -0800156#define FMT_POWERS_OF_10(factor) \
157 factor * 10, \
158 factor * 100, \
159 factor * 1000, \
160 factor * 10000, \
161 factor * 100000, \
162 factor * 1000000, \
163 factor * 10000000, \
164 factor * 100000000, \
165 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800166
Victor Zverovichf1d85162014-02-19 13:02:22 -0800167const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800168const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800169 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800170 FMT_POWERS_OF_10(1),
171 FMT_POWERS_OF_10(ULongLong(1000000000)),
172 // Multiply several constants instead of using a single long long constants
173 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800174 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800175};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800176
Victor Zverovich687301c2013-01-26 16:07:28 -0800177void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800178 if (std::isprint(static_cast<unsigned char>(code))) {
179 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800180 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800181 }
182 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800183 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800184 << static_cast<unsigned>(code) << type));
185}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700186
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700187#ifdef _WIN32
188
189fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
190 int length = MultiByteToWideChar(
191 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
192 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
193 if (length == 0)
Victor Zverovich9830c522014-05-01 07:20:38 -0700194 ThrowWinError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700195 buffer_.resize(length);
196 length = MultiByteToWideChar(
197 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
198 if (length == 0)
Victor Zverovich9830c522014-05-01 07:20:38 -0700199 ThrowWinError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700200}
201
202fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
203 if (int error_code = Convert(s)) {
Victor Zverovich42764e52014-05-01 07:09:08 -0700204 ThrowWinError(GetLastError(),
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700205 "cannot convert string from UTF-16 to UTF-8");
206 }
207}
208
209int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) {
210 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
211 if (length == 0)
212 return GetLastError();
213 buffer_.resize(length);
214 length = WideCharToMultiByte(
215 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
216 if (length == 0)
217 return GetLastError();
218 return 0;
219}
220
221#endif
222
Victor Zverovich99e61122014-04-30 11:20:41 -0700223int fmt::internal::StrError(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700224 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700225 assert(buffer != 0 && buffer_size != 0);
Victor Zverovich99e61122014-04-30 11:20:41 -0700226 int result = 0;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700227#ifdef _GNU_SOURCE
228 char *message = strerror_r(error_code, buffer, buffer_size);
Victor Zverovich99e61122014-04-30 11:20:41 -0700229 // If the buffer is full then the message is probably truncated.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700230 if (message == buffer && strlen(buffer) == buffer_size - 1)
Victor Zverovich99e61122014-04-30 11:20:41 -0700231 result = ERANGE;
232 buffer = message;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700233#elif _WIN32
Constantine Tarasenkov6aace692014-06-11 02:38:57 +0400234# ifdef __MINGW32__
235 strerror(result);
236# else
Victor Zverovich99e61122014-04-30 11:20:41 -0700237 result = strerror_s(buffer, buffer_size, error_code);
Constantine Tarasenkov6aace692014-06-11 02:38:57 +0400238# endif
Victor Zverovich99e61122014-04-30 11:20:41 -0700239 // If the buffer is full then the message is probably truncated.
240 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
241 result = ERANGE;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700242#else
Victor Zverovich99e61122014-04-30 11:20:41 -0700243 result = strerror_r(error_code, buffer, buffer_size);
244 if (result == -1)
245 result = errno; // glibc versions before 2.13 return result in errno.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700246#endif
Victor Zverovich99e61122014-04-30 11:20:41 -0700247 return result;
Victor Zverovich859a4972014-04-30 06:55:21 -0700248}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700249
Victor Zverovich53b4c312014-04-30 15:00:41 -0700250void fmt::internal::FormatSystemErrorMessage(
251 fmt::Writer &out, int error_code, fmt::StringRef message) {
252 Array<char, INLINE_BUFFER_SIZE> buffer;
253 buffer.resize(INLINE_BUFFER_SIZE);
254 char *system_message = 0;
255 for (;;) {
256 system_message = &buffer[0];
257 int result = StrError(error_code, system_message, buffer.size());
258 if (result == 0)
259 break;
260 if (result != ERANGE) {
261 // Can't get error message, report error code instead.
262 out << message << ": error code = " << error_code;
263 return;
264 }
265 buffer.resize(buffer.size() * 2);
266 }
267 out << message << ": " << system_message;
268}
269
270#ifdef _WIN32
271void fmt::internal::FormatWinErrorMessage(
272 fmt::Writer &out, int error_code, fmt::StringRef message) {
273 class String {
274 private:
275 LPWSTR str_;
276
277 public:
278 String() : str_() {}
279 ~String() { LocalFree(str_); }
280 LPWSTR *ptr() { return &str_; }
281 LPCWSTR c_str() const { return str_; }
282 };
283 String system_message;
284 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
285 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
286 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
287 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
288 UTF16ToUTF8 utf8_message;
289 if (!utf8_message.Convert(system_message.c_str())) {
290 out << message << ": " << c_str(utf8_message);
291 return;
292 }
293 }
294 // Can't get error message, report error code instead.
295 out << message << ": error code = " << error_code;
296}
297#endif
298
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700299template <typename Char>
300void fmt::internal::FormatErrorReporter<Char>::operator()(
301 const Char *s, fmt::StringRef message) const {
302 for (int n = num_open_braces; *s; ++s) {
303 if (*s == '{') {
304 ++n;
305 } else if (*s == '}') {
306 if (--n == 0)
307 throw fmt::FormatError(message);
308 }
309 }
310 throw fmt::FormatError("unmatched '{' in format");
311}
312
313// Parses an unsigned integer advancing s to the end of the parsed input.
314// This function assumes that the first character of s is a digit.
315template <typename Char>
316int fmt::internal::ParseNonnegativeInt(
317 const Char *&s, const char *&error) FMT_NOEXCEPT(true) {
318 assert('0' <= *s && *s <= '9');
319 unsigned value = 0;
320 do {
321 unsigned new_value = value * 10 + (*s++ - '0');
322 // Check if value wrapped around.
323 value = new_value >= value ? new_value : UINT_MAX;
324 } while ('0' <= *s && *s <= '9');
325 if (value > INT_MAX) {
326 if (!error)
327 error = "number is too big in format";
328 return 0;
329 }
330 return value;
331}
332
333template <typename Char>
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700334const typename fmt::internal::ArgInfo
335 fmt::BasicWriter<Char>::DUMMY_ARG = {fmt::internal::ArgInfo::INT, 0};
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700336
Victor Zverovich7cae7632013-09-06 20:23:42 -0700337// Fills the padding around the content and returns the pointer to the
338// content area.
339template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700340typename fmt::BasicWriter<Char>::CharPtr
341 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
342 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700343 std::size_t padding = total_size - content_size;
344 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700345 Char fill_char = static_cast<Char>(fill);
346 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700347 buffer += left_padding;
348 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700349 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700350 return content;
351}
352
353template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700354template <typename T>
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700355void fmt::BasicWriter<Char>::FormatDouble(T value, const FormatSpec &spec) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700356 // Check type.
357 char type = spec.type();
358 bool upper = false;
359 switch (type) {
360 case 0:
361 type = 'g';
362 break;
Victor Zverovich03776dd2014-06-10 07:03:49 -0700363 case 'e': case 'f': case 'g': case 'a':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700364 break;
365 case 'F':
366#ifdef _MSC_VER
367 // MSVC's printf doesn't support 'F'.
368 type = 'f';
369#endif
370 // Fall through.
Victor Zverovich03776dd2014-06-10 07:03:49 -0700371 case 'E': case 'G': case 'A':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700372 upper = true;
373 break;
374 default:
375 internal::ReportUnknownType(type, "double");
376 break;
377 }
378
379 char sign = 0;
380 // Use SignBit instead of value < 0 because the latter is always
381 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000382 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700383 sign = '-';
384 value = -value;
385 } else if (spec.sign_flag()) {
386 sign = spec.plus_flag() ? '+' : ' ';
387 }
388
389 if (value != value) {
390 // Format NaN ourselves because sprintf's output is not consistent
391 // across platforms.
392 std::size_t size = 4;
393 const char *nan = upper ? " NAN" : " nan";
394 if (!sign) {
395 --size;
396 ++nan;
397 }
398 CharPtr out = FormatString(nan, size, spec);
399 if (sign)
400 *out = sign;
401 return;
402 }
403
jdale88a9862fd2014-03-11 18:56:24 +0000404 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700405 // Format infinity ourselves because sprintf's output is not consistent
406 // across platforms.
407 std::size_t size = 4;
408 const char *inf = upper ? " INF" : " inf";
409 if (!sign) {
410 --size;
411 ++inf;
412 }
413 CharPtr out = FormatString(inf, size, spec);
414 if (sign)
415 *out = sign;
416 return;
417 }
418
419 std::size_t offset = buffer_.size();
420 unsigned width = spec.width();
421 if (sign) {
422 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
423 if (width > 0)
424 --width;
425 ++offset;
426 }
427
428 // Build format string.
429 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
430 Char format[MAX_FORMAT_SIZE];
431 Char *format_ptr = format;
432 *format_ptr++ = '%';
433 unsigned width_for_sprintf = width;
434 if (spec.hash_flag())
435 *format_ptr++ = '#';
436 if (spec.align() == ALIGN_CENTER) {
437 width_for_sprintf = 0;
438 } else {
439 if (spec.align() == ALIGN_LEFT)
440 *format_ptr++ = '-';
441 if (width != 0)
442 *format_ptr++ = '*';
443 }
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700444 if (spec.precision() >= 0) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700445 *format_ptr++ = '.';
446 *format_ptr++ = '*';
447 }
448 if (internal::IsLongDouble<T>::VALUE)
449 *format_ptr++ = 'L';
450 *format_ptr++ = type;
451 *format_ptr = '\0';
452
453 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700454 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700455 for (;;) {
456 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700457#if _MSC_VER
458 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
459 // space for at least one extra character to make the size non-zero.
460 // Note that the buffer's capacity will increase by more than 1.
461 if (size == 0) {
462 buffer_.reserve(offset + 1);
463 size = buffer_.capacity() - offset;
464 }
465#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700466 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700467 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700468 start, size, format, width_for_sprintf, spec.precision(), value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700469 if (n >= 0 && offset + n < buffer_.capacity()) {
470 if (sign) {
471 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
472 *start != ' ') {
473 *(start - 1) = sign;
474 sign = 0;
475 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700476 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700477 }
478 ++n;
479 }
480 if (spec.align() == ALIGN_CENTER &&
481 spec.width() > static_cast<unsigned>(n)) {
482 unsigned width = spec.width();
483 CharPtr p = GrowBuffer(width);
484 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700485 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700486 return;
487 }
488 if (spec.fill() != ' ' || sign) {
489 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700490 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700491 if (sign)
492 *(start - 1) = sign;
493 }
494 GrowBuffer(n);
495 return;
496 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700497 // If n is negative we ask to increase the capacity by at least 1,
498 // but as std::vector, the buffer grows exponentially.
499 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700500 }
501}
502
Victor Zverovich7cae7632013-09-06 20:23:42 -0700503template <typename Char>
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700504fmt::ULongLong fmt::BasicWriter<Char>::GetIntValue(const Arg &arg) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700505 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700506 case Arg::INT:
Victor Zverovich1b801482014-06-07 08:57:55 -0700507 return arg.int_value;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700508 case Arg::UINT:
Victor Zverovich1b801482014-06-07 08:57:55 -0700509 return arg.uint_value;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700510 case Arg::LONG_LONG:
Victor Zverovich1b801482014-06-07 08:57:55 -0700511 return arg.long_long_value;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700512 case Arg::ULONG_LONG:
Victor Zverovich1b801482014-06-07 08:57:55 -0700513 return arg.ulong_long_value;
514 default:
515 return -1;
516 }
517}
518
519template <typename Char>
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700520template <typename StringChar>
521void fmt::BasicWriter<Char>::FormatString(
522 const Arg::StringValue<StringChar> &str, const FormatSpec &spec) {
523 if (spec.type_ && spec.type_ != 's')
524 internal::ReportUnknownType(spec.type_, "string");
525 const StringChar *s = str.value;
526 std::size_t size = str.size;
527 if (size == 0) {
528 if (!s)
529 throw FormatError("string pointer is null");
530 if (*s)
531 size = std::char_traits<StringChar>::length(s);
532 }
533 FormatString(s, size, spec);
534}
535
536template <typename Char>
537inline const typename fmt::BasicWriter<Char>::Arg
Victor Zveroviche78904b2014-04-23 08:27:50 -0700538 &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700539 unsigned arg_index = 0;
540 if (*s < '0' || *s > '9') {
541 if (*s != '}' && *s != ':')
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700542 report_error_(s, "invalid argument index in format string");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700543 if (next_arg_index_ < 0) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700544 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -0700545 "cannot switch from manual to automatic argument indexing");
546 }
547 arg_index = next_arg_index_++;
548 } else {
549 if (next_arg_index_ > 0) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700550 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -0700551 "cannot switch from automatic to manual argument indexing");
552 }
553 next_arg_index_ = -1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700554 const char *error = 0;
555 arg_index = internal::ParseNonnegativeInt(s, error);
556 if (error)
557 report_error_(s, error); // TODO
Victor Zverovich7cae7632013-09-06 20:23:42 -0700558 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700559 if (arg_index >= args_.size())
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700560 report_error_(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700561 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700562}
563
564template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700565void fmt::BasicWriter<Char>::FormatParser::CheckSign(
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700566 const Char *&s, const Arg &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800567 char sign = static_cast<char>(*s);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700568 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700569 report_error_(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700570 fmt::Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700571 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700572 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700573 report_error_(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700574 fmt::Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700575 }
576 ++s;
577}
578
579template <typename Char>
Victor Zverovichbf790d22014-06-07 07:31:25 -0700580void fmt::BasicWriter<Char>::PrintfParser::ParseFlags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700581 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700582 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700583 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700584 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700585 spec.align_ = ALIGN_LEFT;
586 break;
587 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700588 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
589 break;
590 case '0':
591 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700592 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700593 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700594 spec.flags_ |= SIGN_FLAG;
595 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700596 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700597 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700598 break;
599 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700600 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700601 return;
602 }
603 }
604}
605
Victor Zverovichcb743c02014-06-19 07:40:35 -0700606template <typename Char>
607unsigned fmt::BasicWriter<Char>::PrintfParser::ParseHeader(
608 const Char *&s, FormatSpec &spec, const char *&error) {
609 unsigned arg_index = UINT_MAX;
610 Char c = *s;
611 if (c >= '0' && c <= '9') {
612 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700613 // preceded with '0' flag(s).
Victor Zverovichcb743c02014-06-19 07:40:35 -0700614 unsigned value = internal::ParseNonnegativeInt(s, error);
615 if (*s == '$') { // value is an argument index
616 ++s;
617 arg_index = value;
618 } else {
619 if (c == '0')
620 spec.fill_ = '0';
621 if (value != 0) {
622 // Nonzero value means that we parsed width and don't need to
623 // parse it or flags again, so return now.
624 spec.width_ = value;
625 return arg_index;
626 }
627 }
628 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700629 ParseFlags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700630 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700631 if (*s >= '0' && *s <= '9') {
632 spec.width_ = internal::ParseNonnegativeInt(s, error);
633 } else if (*s == '*') {
634 ++s;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700635 const Arg &arg = HandleArgIndex(UINT_MAX, error);
636 // TODO: use ArgVisitor
Victor Zverovich4099a122014-06-23 08:10:50 -0700637 ULongLong width = 0;
638 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700639 case Arg::INT:
Victor Zverovich4099a122014-06-23 08:10:50 -0700640 width = arg.int_value;
641 if (arg.int_value < 0) {
642 spec.align_ = ALIGN_LEFT;
Victor Zverovich3e53ac22014-06-23 08:48:42 -0700643 width = 0 - width;
Victor Zverovich4099a122014-06-23 08:10:50 -0700644 }
645 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700646 case Arg::UINT:
Victor Zverovich4099a122014-06-23 08:10:50 -0700647 width = arg.uint_value;
648 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700649 case Arg::LONG_LONG:
Victor Zverovich4099a122014-06-23 08:10:50 -0700650 width = arg.long_long_value;
651 if (arg.long_long_value < 0) {
652 spec.align_ = ALIGN_LEFT;
Victor Zverovich3e53ac22014-06-23 08:48:42 -0700653 width = 0 - width;
Victor Zverovich4099a122014-06-23 08:10:50 -0700654 }
655 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700656 case Arg::ULONG_LONG:
Victor Zverovich4099a122014-06-23 08:10:50 -0700657 width = arg.ulong_long_value;
658 break;
659 default:
660 if (!error)
661 error = "width is not integer";
662 }
663 if (width <= INT_MAX)
664 spec.width_ = static_cast<unsigned>(width);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700665 else if (!error)
Victor Zverovich4099a122014-06-23 08:10:50 -0700666 error = "number is too big in format";
Victor Zverovichcb743c02014-06-19 07:40:35 -0700667 }
668 return arg_index;
669}
670
Victor Zverovich879838a2014-06-20 07:34:02 -0700671// TODO: move to a base class that doesn't depend on template argument
Victor Zverovichbf790d22014-06-07 07:31:25 -0700672template <typename Char>
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700673const typename fmt::BasicWriter<Char>::Arg
Victor Zverovichcb743c02014-06-19 07:40:35 -0700674 &fmt::BasicWriter<Char>::PrintfParser::HandleArgIndex(
Victor Zverovich12759232014-06-17 06:53:48 -0700675 unsigned arg_index, const char *&error) {
676 if (arg_index != UINT_MAX) {
677 if (next_arg_index_ <= 0) {
678 next_arg_index_ = -1;
Victor Zverovichcb743c02014-06-19 07:40:35 -0700679 --arg_index;
680 } else if (!error) {
Victor Zverovich12759232014-06-17 06:53:48 -0700681 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichcb743c02014-06-19 07:40:35 -0700682 }
683 } else if (next_arg_index_ >= 0) {
684 arg_index = next_arg_index_++;
685 } else if (!error) {
686 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovich1f19b982014-06-16 07:49:30 -0700687 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700688 if (arg_index < args_.size())
Victor Zverovichcb743c02014-06-19 07:40:35 -0700689 return args_[arg_index];
690 if (!error)
691 error = "argument index is out of range in format";
692 return DUMMY_ARG;
Victor Zverovich1f19b982014-06-16 07:49:30 -0700693}
694
695template <typename Char>
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700696void fmt::BasicWriter<Char>::PrintfParser::Format(
Victor Zveroviche78904b2014-04-23 08:27:50 -0700697 BasicWriter<Char> &writer, BasicStringRef<Char> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700698 const ArgList &args) {
Victor Zveroviche78904b2014-04-23 08:27:50 -0700699 const Char *start = format.c_str();
Victor Zveroviche78904b2014-04-23 08:27:50 -0700700 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700701 next_arg_index_ = 0;
702 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700703 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700704 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700705 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700706 if (*s == c) {
707 writer.buffer_.append(start, s);
708 start = ++s;
709 continue;
710 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700711 writer.buffer_.append(start, s - 1);
712
Victor Zverovichcb743c02014-06-19 07:40:35 -0700713 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700714 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700715
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700716 // Reporting errors is delayed till the format specification is
717 // completely parsed. This is done to avoid potentially confusing
718 // error messages for incomplete format strings. For example, in
719 // sprintf("%2$", 42);
720 // the format specification is incomplete. In naive approach we
721 // would parse 2 as an argument index and report an error that the
722 // index is out of range which would be rather confusing if the
723 // use meant "%2d$" rather than "%2$d". If we delay an error, the
724 // user will get an error that the format string is invalid which
725 // is OK for both cases.
726 const char *error = 0;
727
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700728 // Parse argument index, flags and width.
729 unsigned arg_index = ParseHeader(s, spec, error);
730
731 // Parse precision.
732 if (*s == '.') {
733 ++s;
734 if ('0' <= *s && *s <= '9') {
735 spec.precision_ = internal::ParseNonnegativeInt(s, error);
736 } else if (*s == '*') {
737 ++s;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700738 const Arg &arg = HandleArgIndex(UINT_MAX, error);
739 if (arg.type <= Arg::LAST_INTEGER_TYPE)
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700740 spec.precision_ = GetIntValue(arg);
741 else if (!error)
742 error = "precision is not integer";
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700743 }
744 }
745
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700746 const Arg &arg = HandleArgIndex(arg_index, error);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700747 if (spec.hash_flag() && GetIntValue(arg) == 0)
748 spec.flags_ &= ~HASH_FLAG;
749 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700750 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700751 spec.align_ = ALIGN_NUMERIC;
752 else
753 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700754 }
755
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700756 // Parse length.
757 switch (*s) {
758 case 'h':
759 // TODO: convert to short
760 case 'l':
761 case 'j':
762 case 'z':
763 case 't':
764 case 'L':
765 // TODO: handle length
766 ++s;
767 break;
768 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700769
770 // Parse type.
771 if (!*s)
772 throw FormatError("invalid format string");
773 if (error)
774 throw FormatError(error);
775 spec.type_ = static_cast<char>(*s++);
776
777 start = s;
778
779 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700780 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700781 case Arg::INT:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700782 writer.FormatInt(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700783 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700784 case Arg::UINT:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700785 writer.FormatInt(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700786 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700787 case Arg::LONG_LONG:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700788 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700789 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700790 case Arg::ULONG_LONG:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700791 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700792 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700793 case Arg::DOUBLE:
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700794 writer.FormatDouble(arg.double_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700795 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700796 case Arg::LONG_DOUBLE:
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700797 writer.FormatDouble(arg.long_double_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700798 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700799 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700800 if (spec.type_ && spec.type_ != 'c')
801 internal::ReportUnknownType(spec.type_, "char");
802 typedef typename BasicWriter<Char>::CharPtr CharPtr;
803 CharPtr out = CharPtr();
804 if (spec.width_ > 1) {
805 Char fill = static_cast<Char>(spec.fill());
806 out = writer.GrowBuffer(spec.width_);
807 if (spec.align_ == ALIGN_RIGHT) {
808 std::fill_n(out, spec.width_ - 1, fill);
809 out += spec.width_ - 1;
810 } else if (spec.align_ == ALIGN_CENTER) {
811 out = writer.FillPadding(out, spec.width_, 1, fill);
812 } else {
813 std::fill_n(out + 1, spec.width_ - 1, fill);
814 }
815 } else {
816 out = writer.GrowBuffer(1);
817 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700818 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700819 break;
820 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700821 case Arg::STRING:
822 writer.FormatString(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700823 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700824 case Arg::WSTRING:
825 writer.FormatString(arg.wstring, spec);
826 break;
827 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700828 if (spec.type_ && spec.type_ != 'p')
829 internal::ReportUnknownType(spec.type_, "pointer");
830 spec.flags_= HASH_FLAG;
831 spec.type_ = 'x';
Victor Zverovichcb743c02014-06-19 07:40:35 -0700832 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700833 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700834 case Arg::CUSTOM:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700835 if (spec.type_)
836 internal::ReportUnknownType(spec.type_, "object");
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700837 arg.custom.format(&writer, arg.custom.value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700838 break;
839 default:
840 assert(false);
841 break;
842 }
843 }
844 writer.buffer_.append(start, s);
845}
846
847template <typename Char>
848void fmt::BasicWriter<Char>::FormatParser::Format(
849 BasicWriter<Char> &writer, BasicStringRef<Char> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700850 const ArgList &args) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700851 const char *error = 0;
852 const Char *start = format.c_str();
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700853 args_ = args;
854 next_arg_index_ = 0;
855 const Char *s = start;
856 while (*s) {
857 Char c = *s++;
858 if (c != '{' && c != '}') continue;
859 if (*s == c) {
860 writer.buffer_.append(start, s);
861 start = ++s;
862 continue;
863 }
864 if (c == '}')
865 throw FormatError("unmatched '}' in format");
866 report_error_.num_open_braces = 1;
867 writer.buffer_.append(start, s - 1);
868
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700869 const Arg &arg = ParseArgIndex(s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700870
871 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700872 if (*s == ':') {
873 ++s;
874
875 // Parse fill and alignment.
876 if (Char c = *s) {
877 const Char *p = s + 1;
878 spec.align_ = ALIGN_DEFAULT;
879 do {
880 switch (*p) {
881 case '<':
882 spec.align_ = ALIGN_LEFT;
883 break;
884 case '>':
885 spec.align_ = ALIGN_RIGHT;
886 break;
887 case '=':
888 spec.align_ = ALIGN_NUMERIC;
889 break;
890 case '^':
891 spec.align_ = ALIGN_CENTER;
892 break;
893 }
894 if (spec.align_ != ALIGN_DEFAULT) {
895 if (p != s) {
896 if (c == '}') break;
897 if (c == '{')
898 report_error_(s, "invalid fill character '{'");
899 s += 2;
900 spec.fill_ = c;
901 } else ++s;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700902 if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700903 report_error_(s, "format specifier '=' requires numeric argument");
904 break;
905 }
906 } while (--p >= s);
907 }
908
909 // Parse sign.
910 switch (*s) {
911 case '+':
912 CheckSign(s, arg);
913 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
914 break;
915 case '-':
916 CheckSign(s, arg);
917 break;
918 case ' ':
919 CheckSign(s, arg);
920 spec.flags_ |= SIGN_FLAG;
921 break;
922 }
923
924 if (*s == '#') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700925 if (arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700926 report_error_(s, "format specifier '#' requires numeric argument");
927 spec.flags_ |= HASH_FLAG;
928 ++s;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700929 }
930
931 // Parse width and zero flag.
932 if ('0' <= *s && *s <= '9') {
933 if (*s == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700934 if (arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700935 report_error_(s, "format specifier '0' requires numeric argument");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700936 spec.align_ = ALIGN_NUMERIC;
937 spec.fill_ = '0';
938 }
939 // Zero may be parsed again as a part of the width, but it is simpler
940 // and more efficient than checking if the next char is a digit.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700941 spec.width_ = internal::ParseNonnegativeInt(s, error);
942 if (error)
943 report_error_(s, error);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700944 }
945
946 // Parse precision.
947 if (*s == '.') {
948 ++s;
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700949 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700950 if ('0' <= *s && *s <= '9') {
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700951 spec.precision_ = internal::ParseNonnegativeInt(s, error);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700952 if (error)
953 report_error_(s, error);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700954 } else if (*s == '{') {
955 ++s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700956 ++report_error_.num_open_braces;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700957 const Arg &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -0800958 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700959 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700960 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700961 if (precision_arg.int_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700962 report_error_(s, "negative precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700963 value = precision_arg.int_value;
964 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700965 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700966 value = precision_arg.uint_value;
967 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700968 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -0800969 if (precision_arg.long_long_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700970 report_error_(s, "negative precision in format");
Victor Zverovich56f12b72013-11-22 07:45:43 -0800971 value = precision_arg.long_long_value;
972 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700973 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800974 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800975 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700976 default:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700977 report_error_(s, "precision is not integer");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700978 }
979 if (value > INT_MAX)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700980 report_error_(s, "number is too big in format");
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700981 spec.precision_ = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700982 if (*s++ != '}')
983 throw FormatError("unmatched '{' in format");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700984 --report_error_.num_open_braces;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700985 } else {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700986 report_error_(s, "missing precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700987 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700988 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700989 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -0700990 "precision specifier requires floating-point argument");
991 }
992 }
993
994 // Parse type.
995 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -0700996 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700997 }
998
999 if (*s++ != '}')
1000 throw FormatError("unmatched '{' in format");
1001 start = s;
1002
1003 // Format argument.
1004 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001005 case Arg::INT:
Victor Zverovich03f68852014-04-20 08:46:09 -07001006 writer.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001007 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001008 case Arg::UINT:
Victor Zverovich03f68852014-04-20 08:46:09 -07001009 writer.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001010 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001011 case Arg::LONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -07001012 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -08001013 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001014 case Arg::ULONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -07001015 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001016 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001017 case Arg::DOUBLE:
Victor Zverovichb1bbc902014-06-21 08:32:00 -07001018 writer.FormatDouble(arg.double_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001019 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001020 case Arg::LONG_DOUBLE:
Victor Zverovichb1bbc902014-06-21 08:32:00 -07001021 writer.FormatDouble(arg.long_double_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001022 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001023 case Arg::CHAR: {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001024 if (spec.type_ && spec.type_ != 'c')
1025 internal::ReportUnknownType(spec.type_, "char");
1026 typedef typename BasicWriter<Char>::CharPtr CharPtr;
1027 CharPtr out = CharPtr();
1028 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001029 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -07001030 out = writer.GrowBuffer(spec.width_);
1031 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001032 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001033 out += spec.width_ - 1;
1034 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001035 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001036 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001037 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001038 }
1039 } else {
1040 out = writer.GrowBuffer(1);
1041 }
jdale884cabe162014-03-11 19:03:26 +00001042 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001043 break;
1044 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001045 case Arg::STRING:
1046 writer.FormatString(arg.string, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001047 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001048 case Arg::WSTRING:
1049 writer.FormatString(arg.wstring, spec);
1050 break;
1051 case Arg::POINTER:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001052 if (spec.type_ && spec.type_ != 'p')
1053 internal::ReportUnknownType(spec.type_, "pointer");
1054 spec.flags_= HASH_FLAG;
1055 spec.type_ = 'x';
Victor Zverovich03f68852014-04-20 08:46:09 -07001056 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001057 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001058 case Arg::CUSTOM:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001059 if (spec.type_)
1060 internal::ReportUnknownType(spec.type_, "object");
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001061 arg.custom.format(&writer, arg.custom.value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001062 break;
1063 default:
1064 assert(false);
1065 break;
1066 }
1067 }
1068 writer.buffer_.append(start, s);
1069}
1070
Victor Zverovich859a4972014-04-30 06:55:21 -07001071void fmt::SystemErrorSink::operator()(const fmt::Writer &w) const {
1072 Writer message;
Victor Zverovich53b4c312014-04-30 15:00:41 -07001073 internal::FormatSystemErrorMessage(message, error_code_, w.c_str());
Victor Zverovich859a4972014-04-30 06:55:21 -07001074 throw SystemError(message.c_str(), error_code_);
1075}
1076
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001077void fmt::ReportSystemError(
1078 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1079 // FIXME: FormatSystemErrorMessage may throw
1080 ReportError(internal::FormatSystemErrorMessage, error_code, message);
1081}
1082
Victor Zverovich400812a2014-04-30 12:38:17 -07001083#ifdef _WIN32
1084void fmt::WinErrorSink::operator()(const Writer &w) const {
Victor Zverovichf7939862014-04-30 10:18:11 -07001085 Writer message;
Victor Zverovich53b4c312014-04-30 15:00:41 -07001086 internal::FormatWinErrorMessage(message, error_code_, w.c_str());
Victor Zverovichf7939862014-04-30 10:18:11 -07001087 throw SystemError(message.c_str(), error_code_);
1088}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001089
1090void fmt::ReportWinError(
1091 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1092 // FIXME: FormatWinErrorMessage may throw
1093 ReportError(internal::FormatWinErrorMessage, error_code, message);
1094}
Victor Zverovich400812a2014-04-30 12:38:17 -07001095#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001096
Victor Zverovichd9db8982014-04-28 08:59:29 -07001097void fmt::ANSITerminalSink::operator()(
1098 const fmt::BasicWriter<char> &w) const {
Victor Zverovich43fe1002014-02-19 14:20:26 -08001099 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +00001100 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovichd9db8982014-04-28 08:59:29 -07001101 std::fputs(escape, file_);
1102 std::fwrite(w.data(), 1, w.size(), file_);
1103 std::fputs(RESET_COLOR, file_);
Victor Zverovich43fe1002014-02-19 14:20:26 -08001104}
Victor Zverovich6968ef32014-02-19 13:51:23 -08001105
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001106// Explicit instantiations for char.
1107
Victor Zverovich93e41252013-09-08 13:07:04 -07001108template fmt::BasicWriter<char>::CharPtr
1109 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
1110 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001111
Victor Zveroviche78904b2014-04-23 08:27:50 -07001112template void fmt::BasicWriter<char>::FormatParser::Format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001113 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001114
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001115template void fmt::BasicWriter<char>::PrintfParser::Format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001116 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001117
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001118// Explicit instantiations for wchar_t.
1119
Victor Zverovich7cae7632013-09-06 20:23:42 -07001120template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -07001121 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001122 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001123
Victor Zveroviche78904b2014-04-23 08:27:50 -07001124template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001125 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001126 const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001127
1128template void fmt::BasicWriter<wchar_t>::PrintfParser::Format(
1129 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001130 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001131
1132#if _MSC_VER
1133# pragma warning(pop)
1134#endif