blob: 7e389de1449e8e790742ff28fdf793ca444d4d6f [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
Victor Zverovich859a4972014-04-30 06:55:21 -070045# include <windows.h>
Victor Zveroviched2bdba2014-04-30 07:41:54 -070046# undef ERROR
Victor Zverovich859a4972014-04-30 06:55:21 -070047#endif
48
Victor Zverovich447e02c2014-02-15 10:48:34 -080049using fmt::ULongLong;
50
jdale88a9862fd2014-03-11 18:56:24 +000051#if _MSC_VER
52# pragma warning(push)
53# pragma warning(disable: 4127) // conditional expression is constant
54#endif
55
Victor Zverovich9ff3b972013-09-07 10:15:08 -070056namespace {
57
58#ifndef _MSC_VER
59
60inline int SignBit(double value) {
61 // When compiled in C++11 mode signbit is no longer a macro but a function
62 // defined in namespace std and the macro is undefined.
Victor Zverovichf2e06802014-04-10 10:49:55 -070063#ifdef signbit
Victor Zverovich9ff3b972013-09-07 10:15:08 -070064 return signbit(value);
Victor Zverovichf2e06802014-04-10 10:49:55 -070065#else
66 return std::signbit(value);
67#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070068}
69
70inline int IsInf(double x) {
71#ifdef isinf
72 return isinf(x);
73#else
74 return std::isinf(x);
75#endif
76}
77
78#define FMT_SNPRINTF snprintf
79
Victor Zverovicha684d0c2013-12-27 08:00:10 -080080#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070081
82inline int SignBit(double value) {
83 if (value < 0) return 1;
84 if (value == value) return 0;
85 int dec = 0, sign = 0;
86 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
87 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
88 return sign;
89}
90
91inline int IsInf(double x) { return !_finite(x); }
92
Victor Zverovicha684d0c2013-12-27 08:00:10 -080093inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
94 va_list args;
95 va_start(args, format);
96 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
97 va_end(args);
98 return result;
99}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700100
101#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800102
103const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700104
105typedef void (*FormatFunc)(fmt::Writer &, int , fmt::StringRef);
106
107void ReportError(FormatFunc func,
108 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
109 try {
110 fmt::Writer full_message;
111 func(full_message, error_code, message); // TODO: this may throw?
112 std::fwrite(full_message.c_str(), full_message.size(), 1, stderr);
113 std::fputc('\n', stderr);
114 } catch (...) {}
Victor Zverovichb605b392013-09-09 22:21:40 -0700115}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700116} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700117
Victor Zverovichb605b392013-09-09 22:21:40 -0700118template <typename T>
119int fmt::internal::CharTraits<char>::FormatFloat(
120 char *buffer, std::size_t size, const char *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 FMT_SNPRINTF(buffer, size, format, value) :
125 FMT_SNPRINTF(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 FMT_SNPRINTF(buffer, size, format, width, value) :
129 FMT_SNPRINTF(buffer, size, format, width, precision, value);
130}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700131
Victor Zverovichb605b392013-09-09 22:21:40 -0700132template <typename T>
133int fmt::internal::CharTraits<wchar_t>::FormatFloat(
134 wchar_t *buffer, std::size_t size, const wchar_t *format,
135 unsigned width, int precision, T value) {
136 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700137 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700138 swprintf(buffer, size, format, value) :
139 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700140 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700141 return precision < 0 ?
142 swprintf(buffer, size, format, width, value) :
143 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700144}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800145
Victor Zverovich65d47e52013-09-09 06:51:03 -0700146const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800147 "0001020304050607080910111213141516171819"
148 "2021222324252627282930313233343536373839"
149 "4041424344454647484950515253545556575859"
150 "6061626364656667686970717273747576777879"
151 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800152
Victor Zverovichf1d85162014-02-19 13:02:22 -0800153#define FMT_POWERS_OF_10(factor) \
154 factor * 10, \
155 factor * 100, \
156 factor * 1000, \
157 factor * 10000, \
158 factor * 100000, \
159 factor * 1000000, \
160 factor * 10000000, \
161 factor * 100000000, \
162 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800163
Victor Zverovichf1d85162014-02-19 13:02:22 -0800164const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800165const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800166 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800167 FMT_POWERS_OF_10(1),
168 FMT_POWERS_OF_10(ULongLong(1000000000)),
169 // Multiply several constants instead of using a single long long constants
170 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800171 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800172};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800173
Victor Zverovich687301c2013-01-26 16:07:28 -0800174void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800175 if (std::isprint(static_cast<unsigned char>(code))) {
176 throw fmt::FormatError(fmt::str(
Victor Zverovich687301c2013-01-26 16:07:28 -0800177 fmt::Format("unknown format code '{}' for {}") << code << type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800178 }
179 throw fmt::FormatError(
Victor Zverovich687301c2013-01-26 16:07:28 -0800180 fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}")
Victor Zverovich877abaf2013-01-08 09:56:05 -0800181 << static_cast<unsigned>(code) << type));
182}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700183
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700184#ifdef _WIN32
185
186fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
187 int length = MultiByteToWideChar(
188 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
189 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
190 if (length == 0)
Victor Zverovich9830c522014-05-01 07:20:38 -0700191 ThrowWinError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700192 buffer_.resize(length);
193 length = MultiByteToWideChar(
194 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
195 if (length == 0)
Victor Zverovich9830c522014-05-01 07:20:38 -0700196 ThrowWinError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700197}
198
199fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
200 if (int error_code = Convert(s)) {
Victor Zverovich42764e52014-05-01 07:09:08 -0700201 ThrowWinError(GetLastError(),
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700202 "cannot convert string from UTF-16 to UTF-8");
203 }
204}
205
206int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) {
207 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
208 if (length == 0)
209 return GetLastError();
210 buffer_.resize(length);
211 length = WideCharToMultiByte(
212 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
213 if (length == 0)
214 return GetLastError();
215 return 0;
216}
217
218#endif
219
Victor Zverovich99e61122014-04-30 11:20:41 -0700220int fmt::internal::StrError(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700221 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700222 assert(buffer != 0 && buffer_size != 0);
Victor Zverovich99e61122014-04-30 11:20:41 -0700223 int result = 0;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700224#ifdef _GNU_SOURCE
225 char *message = strerror_r(error_code, buffer, buffer_size);
Victor Zverovich99e61122014-04-30 11:20:41 -0700226 // If the buffer is full then the message is probably truncated.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700227 if (message == buffer && strlen(buffer) == buffer_size - 1)
Victor Zverovich99e61122014-04-30 11:20:41 -0700228 result = ERANGE;
229 buffer = message;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700230#elif _WIN32
Victor Zverovich99e61122014-04-30 11:20:41 -0700231 result = strerror_s(buffer, buffer_size, error_code);
232 // If the buffer is full then the message is probably truncated.
233 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
234 result = ERANGE;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700235#else
Victor Zverovich99e61122014-04-30 11:20:41 -0700236 result = strerror_r(error_code, buffer, buffer_size);
237 if (result == -1)
238 result = errno; // glibc versions before 2.13 return result in errno.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700239#endif
Victor Zverovich99e61122014-04-30 11:20:41 -0700240 return result;
Victor Zverovich859a4972014-04-30 06:55:21 -0700241}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700242
Victor Zverovich53b4c312014-04-30 15:00:41 -0700243void fmt::internal::FormatSystemErrorMessage(
244 fmt::Writer &out, int error_code, fmt::StringRef message) {
245 Array<char, INLINE_BUFFER_SIZE> buffer;
246 buffer.resize(INLINE_BUFFER_SIZE);
247 char *system_message = 0;
248 for (;;) {
249 system_message = &buffer[0];
250 int result = StrError(error_code, system_message, buffer.size());
251 if (result == 0)
252 break;
253 if (result != ERANGE) {
254 // Can't get error message, report error code instead.
255 out << message << ": error code = " << error_code;
256 return;
257 }
258 buffer.resize(buffer.size() * 2);
259 }
260 out << message << ": " << system_message;
261}
262
263#ifdef _WIN32
264void fmt::internal::FormatWinErrorMessage(
265 fmt::Writer &out, int error_code, fmt::StringRef message) {
266 class String {
267 private:
268 LPWSTR str_;
269
270 public:
271 String() : str_() {}
272 ~String() { LocalFree(str_); }
273 LPWSTR *ptr() { return &str_; }
274 LPCWSTR c_str() const { return str_; }
275 };
276 String system_message;
277 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
278 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
279 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
280 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
281 UTF16ToUTF8 utf8_message;
282 if (!utf8_message.Convert(system_message.c_str())) {
283 out << message << ": " << c_str(utf8_message);
284 return;
285 }
286 }
287 // Can't get error message, report error code instead.
288 out << message << ": error code = " << error_code;
289}
290#endif
291
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700292template <typename Char>
293void fmt::internal::FormatErrorReporter<Char>::operator()(
294 const Char *s, fmt::StringRef message) const {
295 for (int n = num_open_braces; *s; ++s) {
296 if (*s == '{') {
297 ++n;
298 } else if (*s == '}') {
299 if (--n == 0)
300 throw fmt::FormatError(message);
301 }
302 }
303 throw fmt::FormatError("unmatched '{' in format");
304}
305
306// Parses an unsigned integer advancing s to the end of the parsed input.
307// This function assumes that the first character of s is a digit.
308template <typename Char>
309int fmt::internal::ParseNonnegativeInt(
310 const Char *&s, const char *&error) FMT_NOEXCEPT(true) {
311 assert('0' <= *s && *s <= '9');
312 unsigned value = 0;
313 do {
314 unsigned new_value = value * 10 + (*s++ - '0');
315 // Check if value wrapped around.
316 value = new_value >= value ? new_value : UINT_MAX;
317 } while ('0' <= *s && *s <= '9');
318 if (value > INT_MAX) {
319 if (!error)
320 error = "number is too big in format";
321 return 0;
322 }
323 return value;
324}
325
326template <typename Char>
327const typename fmt::BasicWriter<Char>::ArgInfo
328 fmt::BasicWriter<Char>::DUMMY_ARG = {fmt::BasicWriter<Char>::INT, 0};
329
Victor Zverovich7cae7632013-09-06 20:23:42 -0700330// Fills the padding around the content and returns the pointer to the
331// content area.
332template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700333typename fmt::BasicWriter<Char>::CharPtr
334 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
335 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700336 std::size_t padding = total_size - content_size;
337 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700338 Char fill_char = static_cast<Char>(fill);
339 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700340 buffer += left_padding;
341 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700342 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700343 return content;
344}
345
346template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700347typename fmt::BasicWriter<Char>::CharPtr
348 fmt::BasicWriter<Char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800349 unsigned size, const AlignSpec &spec, char sign) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700350 unsigned width = spec.width();
351 if (width <= size) {
352 CharPtr p = GrowBuffer(size);
353 *p = sign;
354 return p + size - 1;
355 }
356 CharPtr p = GrowBuffer(width);
357 CharPtr end = p + width;
358 Alignment align = spec.align();
Victor Zverovicha1bd3352014-01-08 08:17:38 -0800359 // TODO: error if fill is not convertible to Char
Victor Zverovich563a5752013-09-08 13:47:06 -0700360 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700361 if (align == ALIGN_LEFT) {
362 *p = sign;
363 p += size;
Victor Zverovich563a5752013-09-08 13:47:06 -0700364 std::fill(p, end, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700365 } else if (align == ALIGN_CENTER) {
Victor Zverovich563a5752013-09-08 13:47:06 -0700366 p = FillPadding(p, width, size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700367 *p = sign;
368 p += size;
369 } else {
370 if (align == ALIGN_NUMERIC) {
371 if (sign) {
372 *p++ = sign;
373 --size;
374 }
375 } else {
376 *(end - size) = sign;
377 }
Victor Zverovich563a5752013-09-08 13:47:06 -0700378 std::fill(p, end - size, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700379 p = end;
380 }
381 return p - 1;
382}
383
384template <typename Char>
385template <typename T>
386void fmt::BasicWriter<Char>::FormatDouble(
Victor Zverovichea5dce32014-01-28 12:47:37 -0800387 T value, const FormatSpec &spec, int precision) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700388 // Check type.
389 char type = spec.type();
390 bool upper = false;
391 switch (type) {
392 case 0:
393 type = 'g';
394 break;
395 case 'e': case 'f': case 'g':
396 break;
397 case 'F':
398#ifdef _MSC_VER
399 // MSVC's printf doesn't support 'F'.
400 type = 'f';
401#endif
402 // Fall through.
403 case 'E': case 'G':
404 upper = true;
405 break;
406 default:
407 internal::ReportUnknownType(type, "double");
408 break;
409 }
410
411 char sign = 0;
412 // Use SignBit instead of value < 0 because the latter is always
413 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000414 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700415 sign = '-';
416 value = -value;
417 } else if (spec.sign_flag()) {
418 sign = spec.plus_flag() ? '+' : ' ';
419 }
420
421 if (value != value) {
422 // Format NaN ourselves because sprintf's output is not consistent
423 // across platforms.
424 std::size_t size = 4;
425 const char *nan = upper ? " NAN" : " nan";
426 if (!sign) {
427 --size;
428 ++nan;
429 }
430 CharPtr out = FormatString(nan, size, spec);
431 if (sign)
432 *out = sign;
433 return;
434 }
435
jdale88a9862fd2014-03-11 18:56:24 +0000436 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700437 // Format infinity ourselves because sprintf's output is not consistent
438 // across platforms.
439 std::size_t size = 4;
440 const char *inf = upper ? " INF" : " inf";
441 if (!sign) {
442 --size;
443 ++inf;
444 }
445 CharPtr out = FormatString(inf, size, spec);
446 if (sign)
447 *out = sign;
448 return;
449 }
450
451 std::size_t offset = buffer_.size();
452 unsigned width = spec.width();
453 if (sign) {
454 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
455 if (width > 0)
456 --width;
457 ++offset;
458 }
459
460 // Build format string.
461 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
462 Char format[MAX_FORMAT_SIZE];
463 Char *format_ptr = format;
464 *format_ptr++ = '%';
465 unsigned width_for_sprintf = width;
466 if (spec.hash_flag())
467 *format_ptr++ = '#';
468 if (spec.align() == ALIGN_CENTER) {
469 width_for_sprintf = 0;
470 } else {
471 if (spec.align() == ALIGN_LEFT)
472 *format_ptr++ = '-';
473 if (width != 0)
474 *format_ptr++ = '*';
475 }
476 if (precision >= 0) {
477 *format_ptr++ = '.';
478 *format_ptr++ = '*';
479 }
480 if (internal::IsLongDouble<T>::VALUE)
481 *format_ptr++ = 'L';
482 *format_ptr++ = type;
483 *format_ptr = '\0';
484
485 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700486 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700487 for (;;) {
488 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700489#if _MSC_VER
490 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
491 // space for at least one extra character to make the size non-zero.
492 // Note that the buffer's capacity will increase by more than 1.
493 if (size == 0) {
494 buffer_.reserve(offset + 1);
495 size = buffer_.capacity() - offset;
496 }
497#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700498 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700499 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovich7cae7632013-09-06 20:23:42 -0700500 start, size, format, width_for_sprintf, precision, value);
501 if (n >= 0 && offset + n < buffer_.capacity()) {
502 if (sign) {
503 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
504 *start != ' ') {
505 *(start - 1) = sign;
506 sign = 0;
507 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700508 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700509 }
510 ++n;
511 }
512 if (spec.align() == ALIGN_CENTER &&
513 spec.width() > static_cast<unsigned>(n)) {
514 unsigned width = spec.width();
515 CharPtr p = GrowBuffer(width);
516 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700517 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700518 return;
519 }
520 if (spec.fill() != ' ' || sign) {
521 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700522 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700523 if (sign)
524 *(start - 1) = sign;
525 }
526 GrowBuffer(n);
527 return;
528 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700529 // If n is negative we ask to increase the capacity by at least 1,
530 // but as std::vector, the buffer grows exponentially.
531 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700532 }
533}
534
Victor Zverovich7cae7632013-09-06 20:23:42 -0700535template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700536inline const typename fmt::BasicWriter<Char>::ArgInfo
537 &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700538 unsigned arg_index = 0;
539 if (*s < '0' || *s > '9') {
540 if (*s != '}' && *s != ':')
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700541 report_error_(s, "invalid argument index in format string");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700542 if (next_arg_index_ < 0) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700543 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -0700544 "cannot switch from manual to automatic argument indexing");
545 }
546 arg_index = next_arg_index_++;
547 } else {
548 if (next_arg_index_ > 0) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700549 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -0700550 "cannot switch from automatic to manual argument indexing");
551 }
552 next_arg_index_ = -1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700553 const char *error = 0;
554 arg_index = internal::ParseNonnegativeInt(s, error);
555 if (error)
556 report_error_(s, error); // TODO
Victor Zverovich7cae7632013-09-06 20:23:42 -0700557 }
Victor Zveroviche78904b2014-04-23 08:27:50 -0700558 if (arg_index >= num_args_)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700559 report_error_(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700560 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700561}
562
563template <typename Char>
Victor Zveroviche78904b2014-04-23 08:27:50 -0700564void fmt::BasicWriter<Char>::FormatParser::CheckSign(
565 const Char *&s, const ArgInfo &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800566 char sign = static_cast<char>(*s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700567 if (arg.type > LAST_NUMERIC_TYPE) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700568 report_error_(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700569 fmt::Format("format specifier '{}' requires numeric argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700570 }
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800571 if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700572 report_error_(s,
Victor Zveroviche78904b2014-04-23 08:27:50 -0700573 fmt::Format("format specifier '{}' requires signed argument") << sign);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700574 }
575 ++s;
576}
577
578template <typename Char>
Victor Zverovichbf790d22014-06-07 07:31:25 -0700579void fmt::BasicWriter<Char>::PrintfParser::ParseFlags(
580 FormatSpec &spec, const Char *&s) {
581 // TODO: parse optional flags
582 for (;;) {
583 switch (*s) {
584 case '-':
585 ++s;
586 spec.align_ = ALIGN_LEFT;
587 break;
588 case '+':
589 // TODO
590 ++s;
591 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
592 break;
593 case '0':
594 spec.fill_ = '0';
595 case ' ':
596 case '#':
597 ++s;
598 break;
599 default:
600 return;
601 }
602 }
603}
604
605template <typename Char>
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700606void fmt::BasicWriter<Char>::PrintfParser::Format(
Victor Zveroviche78904b2014-04-23 08:27:50 -0700607 BasicWriter<Char> &writer, BasicStringRef<Char> format,
608 std::size_t num_args, const ArgInfo *args) {
609 const Char *start = format.c_str();
610 num_args_ = num_args;
611 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700612 next_arg_index_ = 0;
613 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700614 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700615 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700616 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700617 if (*s == c) {
618 writer.buffer_.append(start, s);
619 start = ++s;
620 continue;
621 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700622 writer.buffer_.append(start, s - 1);
623
Victor Zverovich80c99762014-06-07 07:11:34 -0700624 FormatSpec spec(UINT_MAX);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700625 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700626
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700627 // Reporting errors is delayed till the format specification is
628 // completely parsed. This is done to avoid potentially confusing
629 // error messages for incomplete format strings. For example, in
630 // sprintf("%2$", 42);
631 // the format specification is incomplete. In naive approach we
632 // would parse 2 as an argument index and report an error that the
633 // index is out of range which would be rather confusing if the
634 // use meant "%2d$" rather than "%2$d". If we delay an error, the
635 // user will get an error that the format string is invalid which
636 // is OK for both cases.
637 const char *error = 0;
638
639 unsigned arg_index = 0;
Victor Zverovich80c99762014-06-07 07:11:34 -0700640 bool have_arg_index = false;
Victor Zverovich9aba05b2014-06-06 07:07:57 -0700641 c = *s;
642 if (c >= '0' && c <= '9') {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700643 unsigned value = internal::ParseNonnegativeInt(s, error);
644 if (*s != '$') {
Victor Zverovich9aba05b2014-06-06 07:07:57 -0700645 if (c == '0')
646 spec.fill_ = '0';
Victor Zverovich80c99762014-06-07 07:11:34 -0700647 if (value != 0)
Victor Zverovich9aba05b2014-06-06 07:07:57 -0700648 spec.width_ = value;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700649 } else {
650 ++s;
651 if (next_arg_index_ <= 0) {
652 have_arg_index = true;
653 next_arg_index_ = -1;
654 arg_index = value - 1;
655 } else if (!error) {
656 error = "cannot switch from automatic to manual argument indexing";
657 }
658 }
659 }
660 if (!have_arg_index) {
661 if (next_arg_index_ >= 0) {
662 arg_index = next_arg_index_++;
663 } else {
664 // We don't check if error has already been set because argument
665 // index is semantically the first part of the format string, so
666 // indexing errors are reported first even though parsing width
667 // above can cause another error.
668 error = "cannot switch from manual to automatic argument indexing";
669 }
670 }
671
672 const ArgInfo *arg = 0;
673 if (arg_index < num_args) {
674 arg = &args_[arg_index];
675 } else {
676 arg = &DUMMY_ARG;
677 if (!error)
678 error = "argument index is out of range in format";
679 }
680
681 int precision = -1;
Victor Zverovich80c99762014-06-07 07:11:34 -0700682 switch (spec.width_) {
683 case UINT_MAX: {
684 spec.width_ = 0;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700685 ParseFlags(spec, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700686
687 /*
Victor Zverovich7cae7632013-09-06 20:23:42 -0700688 // Parse fill and alignment.
Victor Zverovich0fc73162013-09-07 12:52:52 -0700689 if (Char c = *s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700690 const Char *p = s + 1;
691 spec.align_ = ALIGN_DEFAULT;
692 do {
693 switch (*p) {
694 case '<':
695 spec.align_ = ALIGN_LEFT;
696 break;
697 case '>':
698 spec.align_ = ALIGN_RIGHT;
699 break;
700 case '=':
701 spec.align_ = ALIGN_NUMERIC;
702 break;
703 case '^':
704 spec.align_ = ALIGN_CENTER;
705 break;
706 }
707 if (spec.align_ != ALIGN_DEFAULT) {
708 if (p != s) {
709 if (c == '}') break;
710 if (c == '{')
711 ReportError(s, "invalid fill character '{'");
712 s += 2;
713 spec.fill_ = c;
714 } else ++s;
715 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
716 ReportError(s, "format specifier '=' requires numeric argument");
717 break;
718 }
719 } while (--p >= s);
720 }
721
722 // Parse sign.
723 switch (*s) {
724 case '+':
725 CheckSign(s, arg);
726 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
727 break;
728 case '-':
729 CheckSign(s, arg);
730 break;
731 case ' ':
732 CheckSign(s, arg);
733 spec.flags_ |= SIGN_FLAG;
734 break;
735 }
736
737 if (*s == '#') {
738 if (arg.type > LAST_NUMERIC_TYPE)
739 ReportError(s, "format specifier '#' requires numeric argument");
740 spec.flags_ |= HASH_FLAG;
741 ++s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700742 }*/
743
744 // Parse width and zero flag.
745 if (*s < '0' || *s > '9')
746 break;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700747 spec.width_ = internal::ParseNonnegativeInt(s, error);
Victor Zverovich533c8212014-06-06 08:54:37 -0700748 }
Victor Zverovich80c99762014-06-07 07:11:34 -0700749 // Fall through.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700750 default:
Victor Zverovich9aba05b2014-06-06 07:07:57 -0700751 if (spec.fill_ == '0') {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700752 if (arg->type <= LAST_NUMERIC_TYPE)
753 spec.align_ = ALIGN_NUMERIC;
754 else
755 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovich9aba05b2014-06-06 07:07:57 -0700756 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700757 break;
758 }
759
760 // Parse precision.
761 /*if (*s == '.') {
762 ++s;
763 precision = 0;
764 if ('0' <= *s && *s <= '9') {
765 unsigned value = ParseNonnegativeInt(s);
766 if (value > INT_MAX)
767 ReportError(s, "number is too big in format");
768 precision = value;
769 } else if (*s == '{') {
770 ++s;
771 ++num_open_braces_;
772 const ArgInfo &precision_arg = ParseArgIndex(s);
773 ULongLong value = 0;
774 switch (precision_arg.type) {
775 case INT:
776 if (precision_arg.int_value < 0)
777 ReportError(s, "negative precision in format");
778 value = precision_arg.int_value;
779 break;
780 case UINT:
781 value = precision_arg.uint_value;
782 break;
783 case LONG:
784 if (precision_arg.long_value < 0)
785 ReportError(s, "negative precision in format");
786 value = precision_arg.long_value;
787 break;
788 case ULONG:
789 value = precision_arg.ulong_value;
790 break;
791 case LONG_LONG:
792 if (precision_arg.long_long_value < 0)
793 ReportError(s, "negative precision in format");
794 value = precision_arg.long_long_value;
795 break;
796 case ULONG_LONG:
797 value = precision_arg.ulong_long_value;
798 break;
799 default:
800 ReportError(s, "precision is not integer");
801 }
802 if (value > INT_MAX)
803 ReportError(s, "number is too big in format");
804 precision = static_cast<int>(value);
805 if (*s++ != '}')
806 throw FormatError("unmatched '{' in format");
807 --num_open_braces_;
808 } else {
809 ReportError(s, "missing precision in format");
810 }
811 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
812 ReportError(s,
813 "precision specifier requires floating-point argument");
814 }
815 }*/
816
817 // Parse type.
818 if (!*s)
819 throw FormatError("invalid format string");
820 if (error)
821 throw FormatError(error);
822 spec.type_ = static_cast<char>(*s++);
823
824 start = s;
825
826 // Format argument.
827 switch (arg->type) {
828 case INT:
829 writer.FormatInt(arg->int_value, spec);
830 break;
831 case UINT:
832 writer.FormatInt(arg->uint_value, spec);
833 break;
834 case LONG:
835 writer.FormatInt(arg->long_value, spec);
836 break;
837 case ULONG:
838 writer.FormatInt(arg->ulong_value, spec);
839 break;
840 case LONG_LONG:
841 writer.FormatInt(arg->long_long_value, spec);
842 break;
843 case ULONG_LONG:
844 writer.FormatInt(arg->ulong_long_value, spec);
845 break;
846 case DOUBLE:
847 writer.FormatDouble(arg->double_value, spec, precision);
848 break;
849 case LONG_DOUBLE:
850 writer.FormatDouble(arg->long_double_value, spec, precision);
851 break;
852 case CHAR: {
853 if (spec.type_ && spec.type_ != 'c')
854 internal::ReportUnknownType(spec.type_, "char");
855 typedef typename BasicWriter<Char>::CharPtr CharPtr;
856 CharPtr out = CharPtr();
857 if (spec.width_ > 1) {
858 Char fill = static_cast<Char>(spec.fill());
859 out = writer.GrowBuffer(spec.width_);
860 if (spec.align_ == ALIGN_RIGHT) {
861 std::fill_n(out, spec.width_ - 1, fill);
862 out += spec.width_ - 1;
863 } else if (spec.align_ == ALIGN_CENTER) {
864 out = writer.FillPadding(out, spec.width_, 1, fill);
865 } else {
866 std::fill_n(out + 1, spec.width_ - 1, fill);
867 }
868 } else {
869 out = writer.GrowBuffer(1);
870 }
871 *out = static_cast<Char>(arg->int_value);
872 break;
873 }
874 case STRING: {
875 if (spec.type_ && spec.type_ != 's')
876 internal::ReportUnknownType(spec.type_, "string");
877 const Char *str = arg->string.value;
878 std::size_t size = arg->string.size;
879 if (size == 0) {
880 if (!str)
881 throw FormatError("string pointer is null");
882 if (*str)
883 size = std::char_traits<Char>::length(str);
884 }
885 writer.FormatString(str, size, spec);
886 break;
887 }
888 case POINTER:
889 if (spec.type_ && spec.type_ != 'p')
890 internal::ReportUnknownType(spec.type_, "pointer");
891 spec.flags_= HASH_FLAG;
892 spec.type_ = 'x';
893 writer.FormatInt(reinterpret_cast<uintptr_t>(arg->pointer_value), spec);
894 break;
895 case CUSTOM:
896 if (spec.type_)
897 internal::ReportUnknownType(spec.type_, "object");
898 arg->custom.format(writer, arg->custom.value, spec);
899 break;
900 default:
901 assert(false);
902 break;
903 }
904 }
905 writer.buffer_.append(start, s);
906}
907
908template <typename Char>
909void fmt::BasicWriter<Char>::FormatParser::Format(
910 BasicWriter<Char> &writer, BasicStringRef<Char> format,
911 std::size_t num_args, const ArgInfo *args) {
912 const char *error = 0;
913 const Char *start = format.c_str();
914 num_args_ = num_args;
915 args_ = args;
916 next_arg_index_ = 0;
917 const Char *s = start;
918 while (*s) {
919 Char c = *s++;
920 if (c != '{' && c != '}') continue;
921 if (*s == c) {
922 writer.buffer_.append(start, s);
923 start = ++s;
924 continue;
925 }
926 if (c == '}')
927 throw FormatError("unmatched '}' in format");
928 report_error_.num_open_braces = 1;
929 writer.buffer_.append(start, s - 1);
930
931 const ArgInfo &arg = ParseArgIndex(s);
932
933 FormatSpec spec;
934 int precision = -1;
935 if (*s == ':') {
936 ++s;
937
938 // Parse fill and alignment.
939 if (Char c = *s) {
940 const Char *p = s + 1;
941 spec.align_ = ALIGN_DEFAULT;
942 do {
943 switch (*p) {
944 case '<':
945 spec.align_ = ALIGN_LEFT;
946 break;
947 case '>':
948 spec.align_ = ALIGN_RIGHT;
949 break;
950 case '=':
951 spec.align_ = ALIGN_NUMERIC;
952 break;
953 case '^':
954 spec.align_ = ALIGN_CENTER;
955 break;
956 }
957 if (spec.align_ != ALIGN_DEFAULT) {
958 if (p != s) {
959 if (c == '}') break;
960 if (c == '{')
961 report_error_(s, "invalid fill character '{'");
962 s += 2;
963 spec.fill_ = c;
964 } else ++s;
965 if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE)
966 report_error_(s, "format specifier '=' requires numeric argument");
967 break;
968 }
969 } while (--p >= s);
970 }
971
972 // Parse sign.
973 switch (*s) {
974 case '+':
975 CheckSign(s, arg);
976 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
977 break;
978 case '-':
979 CheckSign(s, arg);
980 break;
981 case ' ':
982 CheckSign(s, arg);
983 spec.flags_ |= SIGN_FLAG;
984 break;
985 }
986
987 if (*s == '#') {
988 if (arg.type > LAST_NUMERIC_TYPE)
989 report_error_(s, "format specifier '#' requires numeric argument");
990 spec.flags_ |= HASH_FLAG;
991 ++s;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700992 }
993
994 // Parse width and zero flag.
995 if ('0' <= *s && *s <= '9') {
996 if (*s == '0') {
997 if (arg.type > LAST_NUMERIC_TYPE)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700998 report_error_(s, "format specifier '0' requires numeric argument");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700999 spec.align_ = ALIGN_NUMERIC;
1000 spec.fill_ = '0';
1001 }
1002 // Zero may be parsed again as a part of the width, but it is simpler
1003 // and more efficient than checking if the next char is a digit.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001004 spec.width_ = internal::ParseNonnegativeInt(s, error);
1005 if (error)
1006 report_error_(s, error);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001007 }
1008
1009 // Parse precision.
1010 if (*s == '.') {
1011 ++s;
1012 precision = 0;
1013 if ('0' <= *s && *s <= '9') {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001014 precision = internal::ParseNonnegativeInt(s, error);
1015 if (error)
1016 report_error_(s, error);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001017 } else if (*s == '{') {
1018 ++s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001019 ++report_error_.num_open_braces;
Victor Zverovich656a8372014-04-22 08:58:54 -07001020 const ArgInfo &precision_arg = ParseArgIndex(s);
Victor Zverovichf406a422013-12-06 07:12:38 -08001021 ULongLong value = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001022 switch (precision_arg.type) {
1023 case INT:
1024 if (precision_arg.int_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001025 report_error_(s, "negative precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001026 value = precision_arg.int_value;
1027 break;
1028 case UINT:
1029 value = precision_arg.uint_value;
1030 break;
1031 case LONG:
1032 if (precision_arg.long_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001033 report_error_(s, "negative precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001034 value = precision_arg.long_value;
1035 break;
1036 case ULONG:
1037 value = precision_arg.ulong_value;
1038 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -08001039 case LONG_LONG:
1040 if (precision_arg.long_long_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001041 report_error_(s, "negative precision in format");
Victor Zverovich56f12b72013-11-22 07:45:43 -08001042 value = precision_arg.long_long_value;
1043 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001044 case ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001045 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001046 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001047 default:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001048 report_error_(s, "precision is not integer");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001049 }
1050 if (value > INT_MAX)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001051 report_error_(s, "number is too big in format");
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001052 precision = static_cast<int>(value);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001053 if (*s++ != '}')
1054 throw FormatError("unmatched '{' in format");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001055 --report_error_.num_open_braces;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001056 } else {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001057 report_error_(s, "missing precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001058 }
1059 if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001060 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -07001061 "precision specifier requires floating-point argument");
1062 }
1063 }
1064
1065 // Parse type.
1066 if (*s != '}' && *s)
Victor Zverovich0fc73162013-09-07 12:52:52 -07001067 spec.type_ = static_cast<char>(*s++);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001068 }
1069
1070 if (*s++ != '}')
1071 throw FormatError("unmatched '{' in format");
1072 start = s;
1073
1074 // Format argument.
1075 switch (arg.type) {
1076 case INT:
Victor Zverovich03f68852014-04-20 08:46:09 -07001077 writer.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001078 break;
1079 case UINT:
Victor Zverovich03f68852014-04-20 08:46:09 -07001080 writer.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001081 break;
1082 case LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -07001083 writer.FormatInt(arg.long_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001084 break;
1085 case ULONG:
Victor Zverovich03f68852014-04-20 08:46:09 -07001086 writer.FormatInt(arg.ulong_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001087 break;
Victor Zverovich56f12b72013-11-22 07:45:43 -08001088 case LONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -07001089 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -08001090 break;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001091 case ULONG_LONG:
Victor Zverovich03f68852014-04-20 08:46:09 -07001092 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001093 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001094 case DOUBLE:
1095 writer.FormatDouble(arg.double_value, spec, precision);
1096 break;
1097 case LONG_DOUBLE:
1098 writer.FormatDouble(arg.long_double_value, spec, precision);
1099 break;
1100 case CHAR: {
1101 if (spec.type_ && spec.type_ != 'c')
1102 internal::ReportUnknownType(spec.type_, "char");
1103 typedef typename BasicWriter<Char>::CharPtr CharPtr;
1104 CharPtr out = CharPtr();
1105 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001106 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -07001107 out = writer.GrowBuffer(spec.width_);
1108 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001109 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001110 out += spec.width_ - 1;
1111 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001112 out = writer.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001113 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001114 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001115 }
1116 } else {
1117 out = writer.GrowBuffer(1);
1118 }
jdale884cabe162014-03-11 19:03:26 +00001119 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001120 break;
1121 }
1122 case STRING: {
1123 if (spec.type_ && spec.type_ != 's')
1124 internal::ReportUnknownType(spec.type_, "string");
1125 const Char *str = arg.string.value;
1126 std::size_t size = arg.string.size;
1127 if (size == 0) {
1128 if (!str)
1129 throw FormatError("string pointer is null");
1130 if (*str)
1131 size = std::char_traits<Char>::length(str);
1132 }
1133 writer.FormatString(str, size, spec);
1134 break;
1135 }
1136 case POINTER:
1137 if (spec.type_ && spec.type_ != 'p')
1138 internal::ReportUnknownType(spec.type_, "pointer");
1139 spec.flags_= HASH_FLAG;
1140 spec.type_ = 'x';
Victor Zverovich03f68852014-04-20 08:46:09 -07001141 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001142 break;
1143 case CUSTOM:
1144 if (spec.type_)
1145 internal::ReportUnknownType(spec.type_, "object");
1146 arg.custom.format(writer, arg.custom.value, spec);
1147 break;
1148 default:
1149 assert(false);
1150 break;
1151 }
1152 }
1153 writer.buffer_.append(start, s);
1154}
1155
Victor Zverovich859a4972014-04-30 06:55:21 -07001156void fmt::SystemErrorSink::operator()(const fmt::Writer &w) const {
1157 Writer message;
Victor Zverovich53b4c312014-04-30 15:00:41 -07001158 internal::FormatSystemErrorMessage(message, error_code_, w.c_str());
Victor Zverovich859a4972014-04-30 06:55:21 -07001159 throw SystemError(message.c_str(), error_code_);
1160}
1161
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001162void fmt::ReportSystemError(
1163 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1164 // FIXME: FormatSystemErrorMessage may throw
1165 ReportError(internal::FormatSystemErrorMessage, error_code, message);
1166}
1167
Victor Zverovich400812a2014-04-30 12:38:17 -07001168#ifdef _WIN32
1169void fmt::WinErrorSink::operator()(const Writer &w) const {
Victor Zverovichf7939862014-04-30 10:18:11 -07001170 Writer message;
Victor Zverovich53b4c312014-04-30 15:00:41 -07001171 internal::FormatWinErrorMessage(message, error_code_, w.c_str());
Victor Zverovichf7939862014-04-30 10:18:11 -07001172 throw SystemError(message.c_str(), error_code_);
1173}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001174
1175void fmt::ReportWinError(
1176 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1177 // FIXME: FormatWinErrorMessage may throw
1178 ReportError(internal::FormatWinErrorMessage, error_code, message);
1179}
Victor Zverovich400812a2014-04-30 12:38:17 -07001180#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001181
Victor Zverovichd9db8982014-04-28 08:59:29 -07001182void fmt::ANSITerminalSink::operator()(
1183 const fmt::BasicWriter<char> &w) const {
Victor Zverovich43fe1002014-02-19 14:20:26 -08001184 char escape[] = "\x1b[30m";
jdale88a9862fd2014-03-11 18:56:24 +00001185 escape[3] = '0' + static_cast<char>(color_);
Victor Zverovichd9db8982014-04-28 08:59:29 -07001186 std::fputs(escape, file_);
1187 std::fwrite(w.data(), 1, w.size(), file_);
1188 std::fputs(RESET_COLOR, file_);
Victor Zverovich43fe1002014-02-19 14:20:26 -08001189}
Victor Zverovich6968ef32014-02-19 13:51:23 -08001190
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001191// Explicit instantiations for char.
1192
Victor Zverovich93e41252013-09-08 13:07:04 -07001193template fmt::BasicWriter<char>::CharPtr
1194 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
1195 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001196
Victor Zverovich7cae7632013-09-06 20:23:42 -07001197template fmt::BasicWriter<char>::CharPtr
1198 fmt::BasicWriter<char>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -08001199 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001200
Victor Zveroviche78904b2014-04-23 08:27:50 -07001201template void fmt::BasicWriter<char>::FormatParser::Format(
1202 BasicWriter<char> &writer, BasicStringRef<char> format,
1203 std::size_t num_args, const ArgInfo *args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001204
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001205template void fmt::BasicWriter<char>::PrintfParser::Format(
1206 BasicWriter<char> &writer, BasicStringRef<char> format,
1207 std::size_t num_args, const ArgInfo *args);
1208
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001209// Explicit instantiations for wchar_t.
1210
Victor Zverovich7cae7632013-09-06 20:23:42 -07001211template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -07001212 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001213 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001214
Victor Zverovich7cae7632013-09-06 20:23:42 -07001215template fmt::BasicWriter<wchar_t>::CharPtr
1216 fmt::BasicWriter<wchar_t>::PrepareFilledBuffer(
Victor Zverovichea5dce32014-01-28 12:47:37 -08001217 unsigned size, const AlignSpec &spec, char sign);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001218
Victor Zveroviche78904b2014-04-23 08:27:50 -07001219template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001220 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
1221 std::size_t num_args, const ArgInfo *args);
1222
1223template void fmt::BasicWriter<wchar_t>::PrintfParser::Format(
1224 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
1225 std::size_t num_args, const ArgInfo *args);
jdale88a9862fd2014-03-11 18:56:24 +00001226
1227#if _MSC_VER
1228# pragma warning(pop)
1229#endif