blob: 3226b17df844845b9830c8061c924301070c31c2 [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
Victor Zveroviche3a44c12014-07-09 06:56:36 -07004 Copyright (c) 2012 - 2014, Victor Zverovich
Victor Zverovichfaccb4c2012-12-12 07:44:41 -08005 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 Zverovich5d15bdd2014-07-01 16:23:50 -070039#include <cerrno>
Victor Zverovichf28645f2014-04-24 12:37:06 -070040#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070041#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080042#include <cstdarg>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070043
Victor Zverovich859a4972014-04-30 06:55:21 -070044#ifdef _WIN32
Victor Zverovichdcd039d2014-05-01 07:09:42 -070045# define WIN32_LEAN_AND_MEAN
Constantine Tarasenkov6aace692014-06-11 02:38:57 +040046# ifdef __MINGW32__
47# include <cstring>
48# endif
Victor Zverovich859a4972014-04-30 06:55:21 -070049# include <windows.h>
Victor Zveroviched2bdba2014-04-30 07:41:54 -070050# undef ERROR
Victor Zverovich859a4972014-04-30 06:55:21 -070051#endif
52
Victor Zverovich447e02c2014-02-15 10:48:34 -080053using fmt::ULongLong;
Victor Zverovich6e5551e2014-07-02 06:33:25 -070054using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080055
jdale88a9862fd2014-03-11 18:56:24 +000056#if _MSC_VER
57# pragma warning(push)
58# pragma warning(disable: 4127) // conditional expression is constant
59#endif
60
Victor Zverovich9ff3b972013-09-07 10:15:08 -070061namespace {
62
63#ifndef _MSC_VER
64
65inline int SignBit(double value) {
66 // When compiled in C++11 mode signbit is no longer a macro but a function
67 // defined in namespace std and the macro is undefined.
Victor Zverovichf2e06802014-04-10 10:49:55 -070068#ifdef signbit
Victor Zverovich9ff3b972013-09-07 10:15:08 -070069 return signbit(value);
Victor Zverovichf2e06802014-04-10 10:49:55 -070070#else
71 return std::signbit(value);
72#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070073}
74
75inline int IsInf(double x) {
76#ifdef isinf
77 return isinf(x);
78#else
79 return std::isinf(x);
80#endif
81}
82
83#define FMT_SNPRINTF snprintf
84
Victor Zverovicha684d0c2013-12-27 08:00:10 -080085#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070086
87inline int SignBit(double value) {
88 if (value < 0) return 1;
89 if (value == value) return 0;
90 int dec = 0, sign = 0;
91 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
92 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
93 return sign;
94}
95
96inline int IsInf(double x) { return !_finite(x); }
97
Victor Zverovicha684d0c2013-12-27 08:00:10 -080098inline int FMT_SNPRINTF(char *buffer, size_t size, const char *format, ...) {
99 va_list args;
100 va_start(args, format);
101 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
102 va_end(args);
103 return result;
104}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700105
106#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800107
108const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700109
110typedef void (*FormatFunc)(fmt::Writer &, int , fmt::StringRef);
111
112void ReportError(FormatFunc func,
113 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
114 try {
115 fmt::Writer full_message;
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700116 func(full_message, error_code, message); // TODO: make sure this doesn't throw
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700117 std::fwrite(full_message.c_str(), full_message.size(), 1, stderr);
118 std::fputc('\n', stderr);
119 } catch (...) {}
Victor Zverovichb605b392013-09-09 22:21:40 -0700120}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700121
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700122const Arg DUMMY_ARG = {Arg::INT, 0};
Victor Zverovichd29e5052014-06-30 07:12:09 -0700123
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700124fmt::ULongLong GetIntValue(const Arg &arg) {
Victor Zverovichd29e5052014-06-30 07:12:09 -0700125 switch (arg.type) {
126 case Arg::INT:
127 return arg.int_value;
128 case Arg::UINT:
129 return arg.uint_value;
130 case Arg::LONG_LONG:
131 return arg.long_long_value;
132 case Arg::ULONG_LONG:
133 return arg.ulong_long_value;
134 default:
135 return -1;
136 }
137}
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700138
139// Parses an unsigned integer advancing s to the end of the parsed input.
140// This function assumes that the first character of s is a digit.
141template <typename Char>
142int ParseNonnegativeInt(const Char *&s, const char *&error) FMT_NOEXCEPT(true) {
143 assert('0' <= *s && *s <= '9');
144 unsigned value = 0;
145 do {
146 unsigned new_value = value * 10 + (*s++ - '0');
147 // Check if value wrapped around.
148 value = new_value >= value ? new_value : UINT_MAX;
149 } while ('0' <= *s && *s <= '9');
150 if (value > INT_MAX) {
151 if (!error)
152 error = "number is too big in format";
153 return 0;
154 }
155 return value;
156}
Victor Zveroviche8251562014-07-08 16:20:33 -0700157
158template <typename Char>
159const Char *find_closing_brace(const Char *s, int num_open_braces = 1) {
160 for (int n = num_open_braces; *s; ++s) {
161 if (*s == '{') {
162 ++n;
163 } else if (*s == '}') {
164 if (--n == 0)
165 return s;
166 }
167 }
168 throw fmt::FormatError("unmatched '{' in format");
169}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700170} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700171
Victor Zverovich302b8f42014-06-24 10:46:01 -0700172int fmt::internal::SignBitNoInline(double value) { return SignBit(value); }
173
Victor Zverovich53201032014-06-30 14:26:29 -0700174void fmt::SystemError::init(
175 int error_code, StringRef format_str, const ArgList &args) {
176 error_code_ = error_code;
177 Writer w;
178 internal::FormatSystemErrorMessage(w, error_code, format(format_str, args));
179 std::runtime_error &base = *this;
180 base = std::runtime_error(w.str());
181}
182
Victor Zverovichb605b392013-09-09 22:21:40 -0700183template <typename T>
184int fmt::internal::CharTraits<char>::FormatFloat(
185 char *buffer, std::size_t size, const char *format,
186 unsigned width, int precision, T value) {
187 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700188 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700189 FMT_SNPRINTF(buffer, size, format, value) :
190 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700191 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700192 return precision < 0 ?
193 FMT_SNPRINTF(buffer, size, format, width, value) :
194 FMT_SNPRINTF(buffer, size, format, width, precision, value);
195}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700196
Victor Zverovichb605b392013-09-09 22:21:40 -0700197template <typename T>
198int fmt::internal::CharTraits<wchar_t>::FormatFloat(
199 wchar_t *buffer, std::size_t size, const wchar_t *format,
200 unsigned width, int precision, T value) {
201 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700202 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700203 swprintf(buffer, size, format, value) :
204 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700205 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700206 return precision < 0 ?
207 swprintf(buffer, size, format, width, value) :
208 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700209}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800210
Victor Zverovich65d47e52013-09-09 06:51:03 -0700211const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800212 "0001020304050607080910111213141516171819"
213 "2021222324252627282930313233343536373839"
214 "4041424344454647484950515253545556575859"
215 "6061626364656667686970717273747576777879"
216 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800217
Victor Zverovichf1d85162014-02-19 13:02:22 -0800218#define FMT_POWERS_OF_10(factor) \
219 factor * 10, \
220 factor * 100, \
221 factor * 1000, \
222 factor * 10000, \
223 factor * 100000, \
224 factor * 1000000, \
225 factor * 10000000, \
226 factor * 100000000, \
227 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800228
Victor Zverovichf1d85162014-02-19 13:02:22 -0800229const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800230const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800231 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800232 FMT_POWERS_OF_10(1),
233 FMT_POWERS_OF_10(ULongLong(1000000000)),
234 // Multiply several constants instead of using a single long long constants
235 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800236 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800237};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800238
Victor Zverovich687301c2013-01-26 16:07:28 -0800239void fmt::internal::ReportUnknownType(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800240 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700241 throw fmt::FormatError(
242 fmt::format("unknown format code '{}' for {}", code, type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800243 }
244 throw fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700245 fmt::format("unknown format code '\\x{:02x}' for {}",
246 static_cast<unsigned>(code), type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800247}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700248
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700249#ifdef _WIN32
250
251fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
252 int length = MultiByteToWideChar(
253 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
254 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
255 if (length == 0)
Victor Zverovichf4208772014-06-30 17:32:08 -0700256 throw WindowsError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700257 buffer_.resize(length);
258 length = MultiByteToWideChar(
259 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
260 if (length == 0)
Victor Zverovichf4208772014-06-30 17:32:08 -0700261 throw WindowsError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700262}
263
264fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
265 if (int error_code = Convert(s)) {
Victor Zverovich8321d0e2014-07-09 08:39:01 -0700266 throw WindowsError(error_code,
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700267 "cannot convert string from UTF-16 to UTF-8");
268 }
269}
270
271int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) {
272 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
273 if (length == 0)
274 return GetLastError();
275 buffer_.resize(length);
276 length = WideCharToMultiByte(
277 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
278 if (length == 0)
279 return GetLastError();
280 return 0;
281}
282
Victor Zverovich53201032014-06-30 14:26:29 -0700283void fmt::WindowsError::init(
284 int error_code, StringRef format_str, const ArgList &args) {
285 error_code_ = error_code;
286 Writer w;
287 internal::FormatWinErrorMessage(w, error_code, format(format_str, args));
288 std::runtime_error &base = *this;
289 base = std::runtime_error(w.str());
290}
291
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700292#endif
293
Victor Zverovich99e61122014-04-30 11:20:41 -0700294int fmt::internal::StrError(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700295 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700296 assert(buffer != 0 && buffer_size != 0);
Victor Zverovich99e61122014-04-30 11:20:41 -0700297 int result = 0;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700298#ifdef _GNU_SOURCE
299 char *message = strerror_r(error_code, buffer, buffer_size);
Victor Zverovich99e61122014-04-30 11:20:41 -0700300 // If the buffer is full then the message is probably truncated.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700301 if (message == buffer && strlen(buffer) == buffer_size - 1)
Victor Zverovich99e61122014-04-30 11:20:41 -0700302 result = ERANGE;
303 buffer = message;
Victor Zverovich9c47f3e2014-07-09 09:45:18 -0700304#elif __MINGW32__
305 errno = 0;
306 (void)buffer_size;
307 buffer = strerror(error_code);
308 result = errno;
309#elif _WIN32
Victor Zverovich99e61122014-04-30 11:20:41 -0700310 result = strerror_s(buffer, buffer_size, error_code);
311 // If the buffer is full then the message is probably truncated.
312 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
313 result = ERANGE;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700314#else
Victor Zverovich99e61122014-04-30 11:20:41 -0700315 result = strerror_r(error_code, buffer, buffer_size);
316 if (result == -1)
317 result = errno; // glibc versions before 2.13 return result in errno.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700318#endif
Victor Zverovich99e61122014-04-30 11:20:41 -0700319 return result;
Victor Zverovich859a4972014-04-30 06:55:21 -0700320}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700321
Victor Zverovich53b4c312014-04-30 15:00:41 -0700322void fmt::internal::FormatSystemErrorMessage(
323 fmt::Writer &out, int error_code, fmt::StringRef message) {
324 Array<char, INLINE_BUFFER_SIZE> buffer;
325 buffer.resize(INLINE_BUFFER_SIZE);
326 char *system_message = 0;
327 for (;;) {
328 system_message = &buffer[0];
329 int result = StrError(error_code, system_message, buffer.size());
330 if (result == 0)
331 break;
332 if (result != ERANGE) {
333 // Can't get error message, report error code instead.
334 out << message << ": error code = " << error_code;
335 return;
336 }
337 buffer.resize(buffer.size() * 2);
338 }
339 out << message << ": " << system_message;
340}
341
342#ifdef _WIN32
343void fmt::internal::FormatWinErrorMessage(
344 fmt::Writer &out, int error_code, fmt::StringRef message) {
345 class String {
346 private:
347 LPWSTR str_;
348
349 public:
350 String() : str_() {}
351 ~String() { LocalFree(str_); }
352 LPWSTR *ptr() { return &str_; }
353 LPCWSTR c_str() const { return str_; }
354 };
355 String system_message;
356 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
357 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
358 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
359 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
360 UTF16ToUTF8 utf8_message;
361 if (!utf8_message.Convert(system_message.c_str())) {
Victor Zverovicheb034a02014-06-30 17:40:53 -0700362 out << message << ": " << utf8_message;
Victor Zverovich53b4c312014-04-30 15:00:41 -0700363 return;
364 }
365 }
366 // Can't get error message, report error code instead.
367 out << message << ": error code = " << error_code;
368}
369#endif
370
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700371template <typename Char>
372void fmt::internal::FormatErrorReporter<Char>::operator()(
373 const Char *s, fmt::StringRef message) const {
Victor Zveroviche8251562014-07-08 16:20:33 -0700374 if (find_closing_brace(s, num_open_braces))
375 throw fmt::FormatError(message);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700376}
377
Victor Zverovich7cae7632013-09-06 20:23:42 -0700378// Fills the padding around the content and returns the pointer to the
379// content area.
380template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700381typename fmt::BasicWriter<Char>::CharPtr
382 fmt::BasicWriter<Char>::FillPadding(CharPtr buffer,
383 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700384 std::size_t padding = total_size - content_size;
385 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700386 Char fill_char = static_cast<Char>(fill);
387 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700388 buffer += left_padding;
389 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700390 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700391 return content;
392}
393
394template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700395template <typename T>
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700396void fmt::BasicWriter<Char>::FormatDouble(T value, const FormatSpec &spec) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700397 // Check type.
398 char type = spec.type();
399 bool upper = false;
400 switch (type) {
401 case 0:
402 type = 'g';
403 break;
Victor Zverovich03776dd2014-06-10 07:03:49 -0700404 case 'e': case 'f': case 'g': case 'a':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700405 break;
406 case 'F':
407#ifdef _MSC_VER
408 // MSVC's printf doesn't support 'F'.
409 type = 'f';
410#endif
411 // Fall through.
Victor Zverovich03776dd2014-06-10 07:03:49 -0700412 case 'E': case 'G': case 'A':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700413 upper = true;
414 break;
415 default:
416 internal::ReportUnknownType(type, "double");
417 break;
418 }
419
420 char sign = 0;
421 // Use SignBit instead of value < 0 because the latter is always
422 // false for NaN.
jdale88a9862fd2014-03-11 18:56:24 +0000423 if (SignBit(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700424 sign = '-';
425 value = -value;
426 } else if (spec.sign_flag()) {
427 sign = spec.plus_flag() ? '+' : ' ';
428 }
429
430 if (value != value) {
431 // Format NaN ourselves because sprintf's output is not consistent
432 // across platforms.
433 std::size_t size = 4;
434 const char *nan = upper ? " NAN" : " nan";
435 if (!sign) {
436 --size;
437 ++nan;
438 }
Victor Zverovich53201032014-06-30 14:26:29 -0700439 CharPtr out = write_str(nan, size, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700440 if (sign)
441 *out = sign;
442 return;
443 }
444
jdale88a9862fd2014-03-11 18:56:24 +0000445 if (IsInf(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700446 // Format infinity ourselves because sprintf's output is not consistent
447 // across platforms.
448 std::size_t size = 4;
449 const char *inf = upper ? " INF" : " inf";
450 if (!sign) {
451 --size;
452 ++inf;
453 }
Victor Zverovich53201032014-06-30 14:26:29 -0700454 CharPtr out = write_str(inf, size, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700455 if (sign)
456 *out = sign;
457 return;
458 }
459
460 std::size_t offset = buffer_.size();
461 unsigned width = spec.width();
462 if (sign) {
463 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
464 if (width > 0)
465 --width;
466 ++offset;
467 }
468
469 // Build format string.
470 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
471 Char format[MAX_FORMAT_SIZE];
472 Char *format_ptr = format;
473 *format_ptr++ = '%';
474 unsigned width_for_sprintf = width;
475 if (spec.hash_flag())
476 *format_ptr++ = '#';
477 if (spec.align() == ALIGN_CENTER) {
478 width_for_sprintf = 0;
479 } else {
480 if (spec.align() == ALIGN_LEFT)
481 *format_ptr++ = '-';
482 if (width != 0)
483 *format_ptr++ = '*';
484 }
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700485 if (spec.precision() >= 0) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700486 *format_ptr++ = '.';
487 *format_ptr++ = '*';
488 }
489 if (internal::IsLongDouble<T>::VALUE)
490 *format_ptr++ = 'L';
491 *format_ptr++ = type;
492 *format_ptr = '\0';
493
494 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700495 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700496 for (;;) {
497 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700498#if _MSC_VER
499 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
500 // space for at least one extra character to make the size non-zero.
501 // Note that the buffer's capacity will increase by more than 1.
502 if (size == 0) {
503 buffer_.reserve(offset + 1);
504 size = buffer_.capacity() - offset;
505 }
506#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700507 Char *start = &buffer_[offset];
Victor Zverovichb605b392013-09-09 22:21:40 -0700508 int n = internal::CharTraits<Char>::FormatFloat(
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700509 start, size, format, width_for_sprintf, spec.precision(), value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700510 if (n >= 0 && offset + n < buffer_.capacity()) {
511 if (sign) {
512 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
513 *start != ' ') {
514 *(start - 1) = sign;
515 sign = 0;
516 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700517 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700518 }
519 ++n;
520 }
521 if (spec.align() == ALIGN_CENTER &&
522 spec.width() > static_cast<unsigned>(n)) {
523 unsigned width = spec.width();
524 CharPtr p = GrowBuffer(width);
525 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich88972f42013-09-08 13:30:14 -0700526 FillPadding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700527 return;
528 }
529 if (spec.fill() != ' ' || sign) {
530 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700531 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700532 if (sign)
533 *(start - 1) = sign;
534 }
535 GrowBuffer(n);
536 return;
537 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700538 // If n is negative we ask to increase the capacity by at least 1,
539 // but as std::vector, the buffer grows exponentially.
540 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700541 }
542}
543
Victor Zverovich7cae7632013-09-06 20:23:42 -0700544template <typename Char>
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700545template <typename StringChar>
Victor Zverovich53201032014-06-30 14:26:29 -0700546void fmt::BasicWriter<Char>::write_str(
Victor Zverovich537c6c42014-07-01 06:21:51 -0700547 const internal::StringValue<StringChar> &str, const FormatSpec &spec) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700548 if (spec.type_ && spec.type_ != 's')
549 internal::ReportUnknownType(spec.type_, "string");
550 const StringChar *s = str.value;
551 std::size_t size = str.size;
552 if (size == 0) {
553 if (!s)
554 throw FormatError("string pointer is null");
555 if (*s)
556 size = std::char_traits<StringChar>::length(s);
557 }
Victor Zverovich53201032014-06-30 14:26:29 -0700558 write_str(s, size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700559}
560
561template <typename Char>
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700562inline const Arg
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700563 &fmt::BasicFormatter<Char>::ParseArgIndex(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700564 unsigned arg_index = 0;
565 if (*s < '0' || *s > '9') {
566 if (*s != '}' && *s != ':')
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700567 report_error_(s, "invalid argument index in format string");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700568 if (next_arg_index_ < 0) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700569 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -0700570 "cannot switch from manual to automatic argument indexing");
571 }
572 arg_index = next_arg_index_++;
573 } else {
574 if (next_arg_index_ > 0) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700575 report_error_(s,
Victor Zverovich7cae7632013-09-06 20:23:42 -0700576 "cannot switch from automatic to manual argument indexing");
577 }
578 next_arg_index_ = -1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700579 const char *error = 0;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700580 arg_index = ParseNonnegativeInt(s, error);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700581 if (error)
582 report_error_(s, error); // TODO
Victor Zverovich7cae7632013-09-06 20:23:42 -0700583 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700584 if (arg_index >= args_.size())
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700585 report_error_(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700586 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700587}
588
589template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700590void fmt::BasicFormatter<Char>::CheckSign(
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700591 const Char *&s, const Arg &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800592 char sign = static_cast<char>(*s);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700593 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700594 report_error_(s,
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700595 fmt::format("format specifier '{}' requires numeric argument", sign).c_str());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700596 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700597 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700598 report_error_(s,
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700599 fmt::format("format specifier '{}' requires signed argument", sign).c_str());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700600 }
601 ++s;
602}
603
604template <typename Char>
Victor Zverovichd29e5052014-06-30 07:12:09 -0700605void fmt::internal::PrintfParser<Char>::ParseFlags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700606 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700607 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700608 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700609 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700610 spec.align_ = ALIGN_LEFT;
611 break;
612 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700613 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
614 break;
615 case '0':
616 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700617 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700618 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700619 spec.flags_ |= SIGN_FLAG;
620 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700621 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700622 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700623 break;
624 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700625 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700626 return;
627 }
628 }
629}
630
Victor Zverovichcb743c02014-06-19 07:40:35 -0700631template <typename Char>
Victor Zverovichd29e5052014-06-30 07:12:09 -0700632unsigned fmt::internal::PrintfParser<Char>::ParseHeader(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700633 const Char *&s, FormatSpec &spec, const char *&error) {
634 unsigned arg_index = UINT_MAX;
635 Char c = *s;
636 if (c >= '0' && c <= '9') {
637 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700638 // preceded with '0' flag(s).
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700639 unsigned value = ParseNonnegativeInt(s, error);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700640 if (*s == '$') { // value is an argument index
641 ++s;
642 arg_index = value;
643 } else {
644 if (c == '0')
645 spec.fill_ = '0';
646 if (value != 0) {
647 // Nonzero value means that we parsed width and don't need to
648 // parse it or flags again, so return now.
649 spec.width_ = value;
650 return arg_index;
651 }
652 }
653 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700654 ParseFlags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700655 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700656 if (*s >= '0' && *s <= '9') {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700657 spec.width_ = ParseNonnegativeInt(s, error);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700658 } else if (*s == '*') {
659 ++s;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700660 const Arg &arg = HandleArgIndex(UINT_MAX, error);
661 // TODO: use ArgVisitor
Victor Zverovich4099a122014-06-23 08:10:50 -0700662 ULongLong width = 0;
663 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700664 case Arg::INT:
Victor Zverovich4099a122014-06-23 08:10:50 -0700665 width = arg.int_value;
666 if (arg.int_value < 0) {
667 spec.align_ = ALIGN_LEFT;
Victor Zverovich3e53ac22014-06-23 08:48:42 -0700668 width = 0 - width;
Victor Zverovich4099a122014-06-23 08:10:50 -0700669 }
670 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700671 case Arg::UINT:
Victor Zverovich4099a122014-06-23 08:10:50 -0700672 width = arg.uint_value;
673 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700674 case Arg::LONG_LONG:
Victor Zverovich4099a122014-06-23 08:10:50 -0700675 width = arg.long_long_value;
676 if (arg.long_long_value < 0) {
677 spec.align_ = ALIGN_LEFT;
Victor Zverovich3e53ac22014-06-23 08:48:42 -0700678 width = 0 - width;
Victor Zverovich4099a122014-06-23 08:10:50 -0700679 }
680 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700681 case Arg::ULONG_LONG:
Victor Zverovich4099a122014-06-23 08:10:50 -0700682 width = arg.ulong_long_value;
683 break;
684 default:
685 if (!error)
686 error = "width is not integer";
687 }
688 if (width <= INT_MAX)
689 spec.width_ = static_cast<unsigned>(width);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700690 else if (!error)
Victor Zverovich4099a122014-06-23 08:10:50 -0700691 error = "number is too big in format";
Victor Zverovichcb743c02014-06-19 07:40:35 -0700692 }
693 return arg_index;
694}
695
Victor Zverovich879838a2014-06-20 07:34:02 -0700696// TODO: move to a base class that doesn't depend on template argument
Victor Zverovichbf790d22014-06-07 07:31:25 -0700697template <typename Char>
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700698const Arg &fmt::internal::PrintfParser<Char>::HandleArgIndex(
Victor Zverovich12759232014-06-17 06:53:48 -0700699 unsigned arg_index, const char *&error) {
700 if (arg_index != UINT_MAX) {
701 if (next_arg_index_ <= 0) {
702 next_arg_index_ = -1;
Victor Zverovichcb743c02014-06-19 07:40:35 -0700703 --arg_index;
704 } else if (!error) {
Victor Zverovich12759232014-06-17 06:53:48 -0700705 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichcb743c02014-06-19 07:40:35 -0700706 }
707 } else if (next_arg_index_ >= 0) {
708 arg_index = next_arg_index_++;
709 } else if (!error) {
710 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovich1f19b982014-06-16 07:49:30 -0700711 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700712 if (arg_index < args_.size())
Victor Zverovichcb743c02014-06-19 07:40:35 -0700713 return args_[arg_index];
714 if (!error)
715 error = "argument index is out of range in format";
716 return DUMMY_ARG;
Victor Zverovich1f19b982014-06-16 07:49:30 -0700717}
718
719template <typename Char>
Victor Zverovichd29e5052014-06-30 07:12:09 -0700720void fmt::internal::PrintfParser<Char>::Format(
Victor Zveroviche78904b2014-04-23 08:27:50 -0700721 BasicWriter<Char> &writer, BasicStringRef<Char> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700722 const ArgList &args) {
Victor Zveroviche78904b2014-04-23 08:27:50 -0700723 const Char *start = format.c_str();
Victor Zveroviche78904b2014-04-23 08:27:50 -0700724 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700725 next_arg_index_ = 0;
726 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700727 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700728 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700729 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700730 if (*s == c) {
731 writer.buffer_.append(start, s);
732 start = ++s;
733 continue;
734 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700735 writer.buffer_.append(start, s - 1);
736
Victor Zverovichcb743c02014-06-19 07:40:35 -0700737 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700738 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700739
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700740 // Reporting errors is delayed till the format specification is
741 // completely parsed. This is done to avoid potentially confusing
742 // error messages for incomplete format strings. For example, in
743 // sprintf("%2$", 42);
744 // the format specification is incomplete. In naive approach we
745 // would parse 2 as an argument index and report an error that the
746 // index is out of range which would be rather confusing if the
747 // use meant "%2d$" rather than "%2$d". If we delay an error, the
748 // user will get an error that the format string is invalid which
749 // is OK for both cases.
750 const char *error = 0;
751
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700752 // Parse argument index, flags and width.
753 unsigned arg_index = ParseHeader(s, spec, error);
754
755 // Parse precision.
756 if (*s == '.') {
757 ++s;
758 if ('0' <= *s && *s <= '9') {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700759 spec.precision_ = ParseNonnegativeInt(s, error);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700760 } else if (*s == '*') {
761 ++s;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700762 const Arg &arg = HandleArgIndex(UINT_MAX, error);
763 if (arg.type <= Arg::LAST_INTEGER_TYPE)
Victor Zverovicheb034a02014-06-30 17:40:53 -0700764 spec.precision_ = static_cast<int>(GetIntValue(arg)); // TODO: check for overflow
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700765 else if (!error)
766 error = "precision is not integer";
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700767 }
768 }
769
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700770 const Arg &arg = HandleArgIndex(arg_index, error);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700771 if (spec.hash_flag() && GetIntValue(arg) == 0)
772 spec.flags_ &= ~HASH_FLAG;
773 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700774 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700775 spec.align_ = ALIGN_NUMERIC;
776 else
777 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700778 }
779
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700780 // Parse length.
781 switch (*s) {
782 case 'h':
783 // TODO: convert to short
784 case 'l':
785 case 'j':
786 case 'z':
787 case 't':
788 case 'L':
789 // TODO: handle length
790 ++s;
791 break;
792 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700793
794 // Parse type.
795 if (!*s)
796 throw FormatError("invalid format string");
797 if (error)
798 throw FormatError(error);
799 spec.type_ = static_cast<char>(*s++);
800
801 start = s;
802
803 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700804 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700805 case Arg::INT:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700806 writer.FormatInt(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700807 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700808 case Arg::UINT:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700809 writer.FormatInt(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700810 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700811 case Arg::LONG_LONG:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700812 writer.FormatInt(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700813 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700814 case Arg::ULONG_LONG:
Victor Zverovichcb743c02014-06-19 07:40:35 -0700815 writer.FormatInt(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700816 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700817 case Arg::DOUBLE:
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700818 writer.FormatDouble(arg.double_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700819 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700820 case Arg::LONG_DOUBLE:
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700821 writer.FormatDouble(arg.long_double_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700822 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700823 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700824 if (spec.type_ && spec.type_ != 'c')
825 internal::ReportUnknownType(spec.type_, "char");
826 typedef typename BasicWriter<Char>::CharPtr CharPtr;
827 CharPtr out = CharPtr();
828 if (spec.width_ > 1) {
829 Char fill = static_cast<Char>(spec.fill());
830 out = writer.GrowBuffer(spec.width_);
831 if (spec.align_ == ALIGN_RIGHT) {
832 std::fill_n(out, spec.width_ - 1, fill);
833 out += spec.width_ - 1;
834 } else if (spec.align_ == ALIGN_CENTER) {
835 out = writer.FillPadding(out, spec.width_, 1, fill);
836 } else {
837 std::fill_n(out + 1, spec.width_ - 1, fill);
838 }
839 } else {
840 out = writer.GrowBuffer(1);
841 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700842 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700843 break;
844 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700845 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700846 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700847 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700848 case Arg::WSTRING:
Victor Zverovichcff1c792014-07-01 06:27:15 -0700849 writer.write_str(internal::CharTraits<Char>::convert(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700850 break;
851 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700852 if (spec.type_ && spec.type_ != 'p')
853 internal::ReportUnknownType(spec.type_, "pointer");
854 spec.flags_= HASH_FLAG;
855 spec.type_ = 'x';
Victor Zverovichcb743c02014-06-19 07:40:35 -0700856 writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700857 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700858 case Arg::CUSTOM:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700859 if (spec.type_)
860 internal::ReportUnknownType(spec.type_, "object");
Victor Zveroviche8251562014-07-08 16:20:33 -0700861 arg.custom.format(&writer, arg.custom.value, "s");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700862 break;
863 default:
864 assert(false);
865 break;
866 }
867 }
868 writer.buffer_.append(start, s);
869}
870
871template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700872const Char *fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -0700873 const Char *format_str, const internal::Arg &arg) {
874 const Char *s = format_str;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700875 const char *error = 0;
Victor Zveroviche8251562014-07-08 16:20:33 -0700876 FormatSpec spec;
877 if (*s == ':') {
878 if (arg.type == Arg::CUSTOM) {
879 arg.custom.format(this, arg.custom.value, s);
880 return find_closing_brace(s) + 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700881 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700882 ++s;
883 // Parse fill and alignment.
884 if (Char c = *s) {
885 const Char *p = s + 1;
886 spec.align_ = ALIGN_DEFAULT;
887 do {
888 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700889 case '<':
890 spec.align_ = ALIGN_LEFT;
891 break;
892 case '>':
893 spec.align_ = ALIGN_RIGHT;
894 break;
895 case '=':
896 spec.align_ = ALIGN_NUMERIC;
897 break;
898 case '^':
899 spec.align_ = ALIGN_CENTER;
900 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700901 }
902 if (spec.align_ != ALIGN_DEFAULT) {
903 if (p != s) {
904 if (c == '}') break;
905 if (c == '{')
906 report_error_(s, "invalid fill character '{'");
907 s += 2;
908 spec.fill_ = c;
909 } else ++s;
910 if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE)
911 report_error_(s, "format specifier '=' requires numeric argument");
912 break;
913 }
914 } while (--p >= s);
915 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700916
Victor Zveroviche8251562014-07-08 16:20:33 -0700917 // Parse sign.
918 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700919 case '+':
920 CheckSign(s, arg);
921 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
922 break;
923 case '-':
924 CheckSign(s, arg);
925 break;
926 case ' ':
927 CheckSign(s, arg);
928 spec.flags_ |= SIGN_FLAG;
929 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700930 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700931
Victor Zveroviche8251562014-07-08 16:20:33 -0700932 if (*s == '#') {
933 if (arg.type > Arg::LAST_NUMERIC_TYPE)
934 report_error_(s, "format specifier '#' requires numeric argument");
935 spec.flags_ |= HASH_FLAG;
936 ++s;
937 }
938
939 // Parse width and zero flag.
940 if ('0' <= *s && *s <= '9') {
941 if (*s == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700942 if (arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zveroviche8251562014-07-08 16:20:33 -0700943 report_error_(s, "format specifier '0' requires numeric argument");
944 spec.align_ = ALIGN_NUMERIC;
945 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700946 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700947 // Zero may be parsed again as a part of the width, but it is simpler
948 // and more efficient than checking if the next char is a digit.
949 spec.width_ = ParseNonnegativeInt(s, error);
950 if (error)
951 report_error_(s, error);
952 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700953
Victor Zveroviche8251562014-07-08 16:20:33 -0700954 // Parse precision.
955 if (*s == '.') {
956 ++s;
957 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700958 if ('0' <= *s && *s <= '9') {
Victor Zveroviche8251562014-07-08 16:20:33 -0700959 spec.precision_ = ParseNonnegativeInt(s, error);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700960 if (error)
961 report_error_(s, error);
Victor Zveroviche8251562014-07-08 16:20:33 -0700962 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700963 ++s;
Victor Zveroviche8251562014-07-08 16:20:33 -0700964 ++report_error_.num_open_braces;
965 const Arg &precision_arg = ParseArgIndex(s);
966 ULongLong value = 0;
967 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700968 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700969 if (precision_arg.int_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700970 report_error_(s, "negative precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700971 value = precision_arg.int_value;
972 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700973 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700974 value = precision_arg.uint_value;
975 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700976 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -0800977 if (precision_arg.long_long_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700978 report_error_(s, "negative precision in format");
Victor Zverovich56f12b72013-11-22 07:45:43 -0800979 value = precision_arg.long_long_value;
980 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700981 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800982 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800983 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700984 default:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700985 report_error_(s, "precision is not integer");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700986 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700987 if (value > INT_MAX)
988 report_error_(s, "number is too big in format");
989 spec.precision_ = static_cast<int>(value);
990 if (*s++ != '}')
991 throw FormatError("unmatched '{' in format");
992 --report_error_.num_open_braces;
993 } else {
994 report_error_(s, "missing precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700995 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700996 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
997 report_error_(s,
998 "precision specifier requires floating-point argument");
999 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001000 }
1001
Victor Zveroviche8251562014-07-08 16:20:33 -07001002 // Parse type.
1003 if (*s != '}' && *s)
1004 spec.type_ = static_cast<char>(*s++);
1005 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001006
Victor Zveroviche8251562014-07-08 16:20:33 -07001007 if (*s++ != '}')
1008 throw FormatError("unmatched '{' in format");
1009 start_ = s;
1010
1011 // Format argument.
1012 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001013 case Arg::INT:
Victor Zveroviche8251562014-07-08 16:20:33 -07001014 writer_.FormatInt(arg.int_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001015 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001016 case Arg::UINT:
Victor Zveroviche8251562014-07-08 16:20:33 -07001017 writer_.FormatInt(arg.uint_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001018 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001019 case Arg::LONG_LONG:
Victor Zveroviche8251562014-07-08 16:20:33 -07001020 writer_.FormatInt(arg.long_long_value, spec);
Victor Zverovich56f12b72013-11-22 07:45:43 -08001021 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001022 case Arg::ULONG_LONG:
Victor Zveroviche8251562014-07-08 16:20:33 -07001023 writer_.FormatInt(arg.ulong_long_value, spec);
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001024 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001025 case Arg::DOUBLE:
Victor Zveroviche8251562014-07-08 16:20:33 -07001026 writer_.FormatDouble(arg.double_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001027 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001028 case Arg::LONG_DOUBLE:
Victor Zveroviche8251562014-07-08 16:20:33 -07001029 writer_.FormatDouble(arg.long_double_value, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001030 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001031 case Arg::CHAR: {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001032 if (spec.type_ && spec.type_ != 'c')
1033 internal::ReportUnknownType(spec.type_, "char");
1034 typedef typename BasicWriter<Char>::CharPtr CharPtr;
1035 CharPtr out = CharPtr();
1036 if (spec.width_ > 1) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001037 Char fill = static_cast<Char>(spec.fill());
Victor Zveroviche8251562014-07-08 16:20:33 -07001038 out = writer_.GrowBuffer(spec.width_);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001039 if (spec.align_ == ALIGN_RIGHT) {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001040 std::fill_n(out, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001041 out += spec.width_ - 1;
1042 } else if (spec.align_ == ALIGN_CENTER) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001043 out = writer_.FillPadding(out, spec.width_, 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001044 } else {
Victor Zverovichc62c4752013-09-08 14:25:22 -07001045 std::fill_n(out + 1, spec.width_ - 1, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001046 }
1047 } else {
Victor Zveroviche8251562014-07-08 16:20:33 -07001048 out = writer_.GrowBuffer(1);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001049 }
jdale884cabe162014-03-11 19:03:26 +00001050 *out = static_cast<Char>(arg.int_value);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001051 break;
1052 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001053 case Arg::STRING:
Victor Zveroviche8251562014-07-08 16:20:33 -07001054 writer_.write_str(arg.string, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001055 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001056 case Arg::WSTRING:
Victor Zveroviche8251562014-07-08 16:20:33 -07001057 writer_.write_str(internal::CharTraits<Char>::convert(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001058 break;
1059 case Arg::POINTER:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001060 if (spec.type_ && spec.type_ != 'p')
1061 internal::ReportUnknownType(spec.type_, "pointer");
1062 spec.flags_= HASH_FLAG;
1063 spec.type_ = 'x';
Victor Zveroviche8251562014-07-08 16:20:33 -07001064 writer_.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001065 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001066 case Arg::CUSTOM:
Victor Zveroviche8251562014-07-08 16:20:33 -07001067 arg.custom.format(this, arg.custom.value, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001068 break;
1069 default:
1070 assert(false);
1071 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001072 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001073 return s;
1074}
1075
1076template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001077void fmt::BasicFormatter<Char>::Format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001078 BasicStringRef<Char> format_str, const ArgList &args) {
1079 const Char *s = start_ = format_str.c_str();
1080 args_ = args;
1081 next_arg_index_ = 0;
1082 while (*s) {
1083 Char c = *s++;
1084 if (c != '{' && c != '}') continue;
1085 if (*s == c) {
1086 writer_.buffer_.append(start_, s);
1087 start_ = ++s;
1088 continue;
1089 }
1090 if (c == '}')
1091 throw FormatError("unmatched '}' in format");
1092 report_error_.num_open_braces = 1;
1093 writer_.buffer_.append(start_, s - 1);
1094 Arg arg = ParseArgIndex(s);
1095 s = format(s, arg);
1096 }
1097 writer_.buffer_.append(start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001098}
1099
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001100void fmt::ReportSystemError(
1101 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1102 // FIXME: FormatSystemErrorMessage may throw
1103 ReportError(internal::FormatSystemErrorMessage, error_code, message);
1104}
1105
Victor Zverovich400812a2014-04-30 12:38:17 -07001106#ifdef _WIN32
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001107void fmt::ReportWinError(
1108 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
1109 // FIXME: FormatWinErrorMessage may throw
1110 ReportError(internal::FormatWinErrorMessage, error_code, message);
1111}
Victor Zverovich400812a2014-04-30 12:38:17 -07001112#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001113
Victor Zverovich2e039632014-06-28 19:44:39 -07001114void fmt::print(StringRef format, const ArgList &args) {
1115 Writer w;
Victor Zverovicha1264922014-06-29 11:51:10 -07001116 w.write(format, args);
Victor Zverovich2e039632014-06-28 19:44:39 -07001117 std::fwrite(w.data(), 1, w.size(), stdout);
1118}
1119
Victor Zverovichd5b81962014-06-28 21:56:40 -07001120void fmt::print(std::FILE *f, StringRef format, const ArgList &args) {
1121 Writer w;
Victor Zverovicha1264922014-06-29 11:51:10 -07001122 w.write(format, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001123 std::fwrite(w.data(), 1, w.size(), f);
1124}
1125
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001126void fmt::print(std::ostream &os, StringRef format, const ArgList &args) {
1127 Writer w;
1128 w.write(format, args);
1129 os.write(w.data(), w.size());
1130}
1131
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001132void fmt::print_colored(Color c, StringRef format, const ArgList &args) {
1133 char escape[] = "\x1b[30m";
1134 escape[3] = '0' + static_cast<char>(c);
1135 std::fputs(escape, stdout);
1136 print(format, args);
1137 std::fputs(RESET_COLOR, stdout);
1138}
1139
Victor Zverovichd5b81962014-06-28 21:56:40 -07001140void fmt::printf(StringRef format, const ArgList &args) {
1141 Writer w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001142 printf(w, format, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001143 std::fwrite(w.data(), 1, w.size(), stdout);
1144}
1145
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001146// Explicit instantiations for char.
1147
Victor Zverovich93e41252013-09-08 13:07:04 -07001148template fmt::BasicWriter<char>::CharPtr
1149 fmt::BasicWriter<char>::FillPadding(CharPtr buffer,
1150 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001151
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001152template void fmt::BasicFormatter<char>::Format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001153 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001154
Victor Zverovichd29e5052014-06-30 07:12:09 -07001155template void fmt::internal::PrintfParser<char>::Format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001156 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001157
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001158// Explicit instantiations for wchar_t.
1159
Victor Zverovich7cae7632013-09-06 20:23:42 -07001160template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich93e41252013-09-08 13:07:04 -07001161 fmt::BasicWriter<wchar_t>::FillPadding(CharPtr buffer,
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001162 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001163
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001164template void fmt::BasicFormatter<wchar_t>::Format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001165 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001166
Victor Zverovichd29e5052014-06-30 07:12:09 -07001167template void fmt::internal::PrintfParser<wchar_t>::Format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001168 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001169 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001170
1171#if _MSC_VER
1172# pragma warning(pop)
1173#endif