blob: f4c678d608db88bd57219304357fb88c8e2b55a7 [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 Zverovich591ad0a2014-07-14 06:55:29 -070053using fmt::LongLong;
Victor Zverovich447e02c2014-02-15 10:48:34 -080054using fmt::ULongLong;
Victor Zverovich6e5551e2014-07-02 06:33:25 -070055using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080056
jdale88a9862fd2014-03-11 18:56:24 +000057#if _MSC_VER
58# pragma warning(push)
59# pragma warning(disable: 4127) // conditional expression is constant
60#endif
61
Victor Zverovich9ff3b972013-09-07 10:15:08 -070062namespace {
63
64#ifndef _MSC_VER
65
Victor Zverovichbe785a82014-07-29 09:14:07 -070066// Portable version of signbit.
Victor Zverovichd8b9f412014-07-29 06:38:05 -070067// When compiled in C++11 mode signbit is no longer a macro but a function
68// defined in namespace std and the macro is undefined.
Victor Zverovichbe785a82014-07-29 09:14:07 -070069inline int getsign(double x) {
70#ifdef signbit
71 return signbit(x);
72#else
73 return std::signbit(x);
Victor Zverovichf2e06802014-04-10 10:49:55 -070074#endif
Victor Zverovichbe785a82014-07-29 09:14:07 -070075}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070076
Victor Zverovich24d6baa2014-07-29 07:49:34 -070077// Portable version of isinf.
Victor Zverovichbf5b2462014-07-29 08:22:52 -070078inline int isinfinity(double x) {
Victor Zverovich24d6baa2014-07-29 07:49:34 -070079#ifdef isinf
80 return isinf(x);
81#else
82 return std::isinf(x);
Victor Zverovich9ff3b972013-09-07 10:15:08 -070083#endif
Victor Zverovich24d6baa2014-07-29 07:49:34 -070084}
Victor Zverovich9ff3b972013-09-07 10:15:08 -070085
86#define FMT_SNPRINTF snprintf
87
Victor Zverovicha684d0c2013-12-27 08:00:10 -080088#else // _MSC_VER
Victor Zverovich9ff3b972013-09-07 10:15:08 -070089
Victor Zverovichbe785a82014-07-29 09:14:07 -070090inline int getsign(double value) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -070091 if (value < 0) return 1;
92 if (value == value) return 0;
93 int dec = 0, sign = 0;
94 char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.
95 _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
96 return sign;
97}
98
Victor Zverovichbf5b2462014-07-29 08:22:52 -070099inline int isinfinity(double x) { return !_finite(x); }
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700100
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700101inline int safe_printf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -0800102 va_list args;
103 va_start(args, format);
104 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
105 va_end(args);
106 return result;
107}
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700108#define FMT_SNPRINTF safe_printf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700109
110#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800111
112const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700113
114typedef void (*FormatFunc)(fmt::Writer &, int , fmt::StringRef);
115
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700116void report_error(FormatFunc func,
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700117 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
118 try {
119 fmt::Writer full_message;
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700120 func(full_message, error_code, message); // TODO: make sure this doesn't throw
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700121 std::fwrite(full_message.c_str(), full_message.size(), 1, stderr);
122 std::fputc('\n', stderr);
123 } catch (...) {}
Victor Zverovichb605b392013-09-09 22:21:40 -0700124}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700125
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700126const Arg DUMMY_ARG = {Arg::INT, 0};
Victor Zverovichd29e5052014-06-30 07:12:09 -0700127
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700128// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
129class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
130 public:
131 template <typename T>
132 bool visit_any_int(T value) { return value == 0; }
133};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700134
135// Parses an unsigned integer advancing s to the end of the parsed input.
136// This function assumes that the first character of s is a digit.
137template <typename Char>
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700138int parse_nonnegative_int(
139 const Char *&s, const char *&error) FMT_NOEXCEPT(true) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700140 assert('0' <= *s && *s <= '9');
141 unsigned value = 0;
142 do {
143 unsigned new_value = value * 10 + (*s++ - '0');
144 // Check if value wrapped around.
145 value = new_value >= value ? new_value : UINT_MAX;
146 } while ('0' <= *s && *s <= '9');
147 if (value > INT_MAX) {
148 if (!error)
149 error = "number is too big in format";
150 return 0;
151 }
152 return value;
153}
Victor Zveroviche8251562014-07-08 16:20:33 -0700154
155template <typename Char>
156const Char *find_closing_brace(const Char *s, int num_open_braces = 1) {
157 for (int n = num_open_braces; *s; ++s) {
158 if (*s == '{') {
159 ++n;
160 } else if (*s == '}') {
161 if (--n == 0)
162 return s;
163 }
164 }
165 throw fmt::FormatError("unmatched '{' in format");
166}
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700167
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700168// Checks if an argument is a valid printf width specifier and sets
169// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700170class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700171 private:
172 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700173
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700174 public:
175 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700176
Victor Zverovich9d74f952014-07-16 07:27:54 -0700177 unsigned visit_unhandled_arg() {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700178 throw fmt::FormatError("width is not integer");
179 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700180
Victor Zverovich9d74f952014-07-16 07:27:54 -0700181 template <typename T>
182 unsigned visit_any_int(T value) {
183 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
184 UnsignedType width = value;
185 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700186 spec_.align_ = fmt::ALIGN_LEFT;
187 width = 0 - width;
188 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700189 if (width > INT_MAX)
190 throw fmt::FormatError("number is too big in format");
191 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700192 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700193};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700194
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700195class PrecisionHandler :
196 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
197 public:
198 unsigned visit_unhandled_arg() {
199 throw fmt::FormatError("precision is not integer");
200 }
201
202 template <typename T>
203 int visit_any_int(T value) {
204 if (value < INT_MIN || value > INT_MAX)
205 throw fmt::FormatError("number is too big in format");
206 return static_cast<int>(value);
207 }
208};
209
Victor Zverovicheeca2232014-07-30 07:37:16 -0700210// Converts an integer argument to type T.
211template <typename T>
212class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
213 private:
214 fmt::internal::Arg &arg_;
215
216 public:
217 explicit ArgConverter(fmt::internal::Arg &arg) : arg_(arg) {}
218
219 template <typename U>
220 void visit_any_int(U value) {
Victor Zverovich39b09302014-07-30 08:08:08 -0700221 if (std::numeric_limits<T>::is_signed) {
Victor Zverovicheeca2232014-07-30 07:37:16 -0700222 arg_.type = fmt::internal::Arg::INT;
223 arg_.int_value = static_cast<T>(value);
224 } else {
225 arg_.type = fmt::internal::Arg::UINT;
226 arg_.uint_value = static_cast<T>(value);
227 }
228 }
229};
230
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700231// This function template is used to prevent compile errors when handling
232// incompatible string arguments, e.g. handling a wide string in a narrow
233// string formatter.
234template <typename Char>
235Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
236
237template <>
238inline Arg::StringValue<char> ignore_incompatible_str(
239 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
240
241template <>
242inline Arg::StringValue<wchar_t> ignore_incompatible_str(
243 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700244} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700245
Victor Zverovichbe785a82014-07-29 09:14:07 -0700246int fmt::internal::signbit_noinline(double value) { return getsign(value); }
Victor Zverovich302b8f42014-06-24 10:46:01 -0700247
Victor Zverovich53201032014-06-30 14:26:29 -0700248void fmt::SystemError::init(
249 int error_code, StringRef format_str, const ArgList &args) {
250 error_code_ = error_code;
251 Writer w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700252 internal::format_system_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700253 std::runtime_error &base = *this;
254 base = std::runtime_error(w.str());
255}
256
Victor Zverovichb605b392013-09-09 22:21:40 -0700257template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700258int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700259 char *buffer, std::size_t size, const char *format,
260 unsigned width, int precision, T value) {
261 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700262 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700263 FMT_SNPRINTF(buffer, size, format, value) :
264 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700265 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700266 return precision < 0 ?
267 FMT_SNPRINTF(buffer, size, format, width, value) :
268 FMT_SNPRINTF(buffer, size, format, width, precision, value);
269}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700270
Victor Zverovichb605b392013-09-09 22:21:40 -0700271template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700272int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700273 wchar_t *buffer, std::size_t size, const wchar_t *format,
274 unsigned width, int precision, T value) {
275 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700276 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700277 swprintf(buffer, size, format, value) :
278 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700279 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700280 return precision < 0 ?
281 swprintf(buffer, size, format, width, value) :
282 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700283}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800284
Victor Zverovich65d47e52013-09-09 06:51:03 -0700285const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800286 "0001020304050607080910111213141516171819"
287 "2021222324252627282930313233343536373839"
288 "4041424344454647484950515253545556575859"
289 "6061626364656667686970717273747576777879"
290 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800291
Victor Zverovichf1d85162014-02-19 13:02:22 -0800292#define FMT_POWERS_OF_10(factor) \
293 factor * 10, \
294 factor * 100, \
295 factor * 1000, \
296 factor * 10000, \
297 factor * 100000, \
298 factor * 1000000, \
299 factor * 10000000, \
300 factor * 100000000, \
301 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800302
Victor Zverovichf1d85162014-02-19 13:02:22 -0800303const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800304const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800305 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800306 FMT_POWERS_OF_10(1),
307 FMT_POWERS_OF_10(ULongLong(1000000000)),
308 // Multiply several constants instead of using a single long long constants
309 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800310 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800311};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800312
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700313void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800314 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700315 throw fmt::FormatError(
316 fmt::format("unknown format code '{}' for {}", code, type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800317 }
318 throw fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700319 fmt::format("unknown format code '\\x{:02x}' for {}",
320 static_cast<unsigned>(code), type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800321}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700322
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700323#ifdef _WIN32
324
325fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
326 int length = MultiByteToWideChar(
327 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
328 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
329 if (length == 0)
Victor Zverovichf4208772014-06-30 17:32:08 -0700330 throw WindowsError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700331 buffer_.resize(length);
332 length = MultiByteToWideChar(
333 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
334 if (length == 0)
Victor Zverovichf4208772014-06-30 17:32:08 -0700335 throw WindowsError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700336}
337
338fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700339 if (int error_code = convert(s)) {
Victor Zverovich8321d0e2014-07-09 08:39:01 -0700340 throw WindowsError(error_code,
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700341 "cannot convert string from UTF-16 to UTF-8");
342 }
343}
344
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700345int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700346 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
347 if (length == 0)
348 return GetLastError();
349 buffer_.resize(length);
350 length = WideCharToMultiByte(
351 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
352 if (length == 0)
353 return GetLastError();
354 return 0;
355}
356
Victor Zverovich53201032014-06-30 14:26:29 -0700357void fmt::WindowsError::init(
358 int error_code, StringRef format_str, const ArgList &args) {
359 error_code_ = error_code;
360 Writer w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700361 internal::format_windows_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700362 std::runtime_error &base = *this;
363 base = std::runtime_error(w.str());
364}
365
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700366#endif
367
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700368int fmt::internal::safe_strerror(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700369 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700370 assert(buffer != 0 && buffer_size != 0);
Victor Zverovich99e61122014-04-30 11:20:41 -0700371 int result = 0;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700372#ifdef _GNU_SOURCE
373 char *message = strerror_r(error_code, buffer, buffer_size);
Victor Zverovich99e61122014-04-30 11:20:41 -0700374 // If the buffer is full then the message is probably truncated.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700375 if (message == buffer && strlen(buffer) == buffer_size - 1)
Victor Zverovich99e61122014-04-30 11:20:41 -0700376 result = ERANGE;
377 buffer = message;
Victor Zverovich9c47f3e2014-07-09 09:45:18 -0700378#elif __MINGW32__
379 errno = 0;
380 (void)buffer_size;
381 buffer = strerror(error_code);
382 result = errno;
383#elif _WIN32
Victor Zverovich99e61122014-04-30 11:20:41 -0700384 result = strerror_s(buffer, buffer_size, error_code);
385 // If the buffer is full then the message is probably truncated.
386 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
387 result = ERANGE;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700388#else
Victor Zverovich99e61122014-04-30 11:20:41 -0700389 result = strerror_r(error_code, buffer, buffer_size);
390 if (result == -1)
391 result = errno; // glibc versions before 2.13 return result in errno.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700392#endif
Victor Zverovich99e61122014-04-30 11:20:41 -0700393 return result;
Victor Zverovich859a4972014-04-30 06:55:21 -0700394}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700395
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700396void fmt::internal::format_system_error(
Victor Zverovich53b4c312014-04-30 15:00:41 -0700397 fmt::Writer &out, int error_code, fmt::StringRef message) {
398 Array<char, INLINE_BUFFER_SIZE> buffer;
399 buffer.resize(INLINE_BUFFER_SIZE);
400 char *system_message = 0;
401 for (;;) {
402 system_message = &buffer[0];
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700403 int result = safe_strerror(error_code, system_message, buffer.size());
Victor Zverovich53b4c312014-04-30 15:00:41 -0700404 if (result == 0)
405 break;
406 if (result != ERANGE) {
407 // Can't get error message, report error code instead.
408 out << message << ": error code = " << error_code;
409 return;
410 }
411 buffer.resize(buffer.size() * 2);
412 }
413 out << message << ": " << system_message;
414}
415
416#ifdef _WIN32
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700417void fmt::internal::format_windows_error(
Victor Zverovich53b4c312014-04-30 15:00:41 -0700418 fmt::Writer &out, int error_code, fmt::StringRef message) {
419 class String {
420 private:
421 LPWSTR str_;
422
423 public:
424 String() : str_() {}
425 ~String() { LocalFree(str_); }
426 LPWSTR *ptr() { return &str_; }
427 LPCWSTR c_str() const { return str_; }
428 };
429 String system_message;
430 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
431 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
432 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
433 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
434 UTF16ToUTF8 utf8_message;
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700435 if (!utf8_message.convert(system_message.c_str())) {
Victor Zverovicheb034a02014-06-30 17:40:53 -0700436 out << message << ": " << utf8_message;
Victor Zverovich53b4c312014-04-30 15:00:41 -0700437 return;
438 }
439 }
440 // Can't get error message, report error code instead.
441 out << message << ": error code = " << error_code;
442}
443#endif
444
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700445// An argument formatter.
446template <typename Char>
447class fmt::internal::ArgFormatter :
448 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
449 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700450 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700451 fmt::BasicWriter<Char> &writer_;
452 fmt::FormatSpec &spec_;
453 const Char *format_;
454
455 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700456 ArgFormatter(
457 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700458 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700459
Victor Zverovich9d74f952014-07-16 07:27:54 -0700460 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700461 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700462
463 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700464 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700465
466 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700467 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700468 spec_.flags_ |= CHAR_FLAG;
469 writer_.write_int(value, spec_);
470 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700471 }
472 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
473 throw FormatError("invalid format specifier for char");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700474 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
475 CharPtr out = CharPtr();
476 if (spec_.width_ > 1) {
477 Char fill = static_cast<Char>(spec_.fill());
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700478 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700479 if (spec_.align_ == fmt::ALIGN_RIGHT) {
480 std::fill_n(out, spec_.width_ - 1, fill);
481 out += spec_.width_ - 1;
482 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700483 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700484 } else {
485 std::fill_n(out + 1, spec_.width_ - 1, fill);
486 }
487 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700488 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700489 }
490 *out = static_cast<Char>(value);
491 }
492
493 void visit_string(Arg::StringValue<char> value) {
494 writer_.write_str(value, spec_);
495 }
496 void visit_wstring(Arg::StringValue<wchar_t> value) {
497 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
498 }
499
500 void visit_pointer(const void *value) {
501 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700502 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700503 spec_.flags_ = fmt::HASH_FLAG;
504 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700505 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700506 }
507
508 void visit_custom(Arg::CustomValue c) {
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700509 c.format(&formatter_, c.value, format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700510 }
511};
512
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700513template <typename Char>
514void fmt::internal::FormatErrorReporter<Char>::operator()(
515 const Char *s, fmt::StringRef message) const {
Victor Zveroviche8251562014-07-08 16:20:33 -0700516 if (find_closing_brace(s, num_open_braces))
517 throw fmt::FormatError(message);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700518}
519
Victor Zverovich7cae7632013-09-06 20:23:42 -0700520// Fills the padding around the content and returns the pointer to the
521// content area.
522template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700523typename fmt::BasicWriter<Char>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700524 fmt::BasicWriter<Char>::fill_padding(CharPtr buffer,
Victor Zverovich93e41252013-09-08 13:07:04 -0700525 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700526 std::size_t padding = total_size - content_size;
527 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700528 Char fill_char = static_cast<Char>(fill);
529 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700530 buffer += left_padding;
531 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700532 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700533 return content;
534}
535
536template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700537template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700538void fmt::BasicWriter<Char>::write_double(T value, const FormatSpec &spec) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700539 // Check type.
540 char type = spec.type();
541 bool upper = false;
542 switch (type) {
543 case 0:
544 type = 'g';
545 break;
Victor Zverovich03776dd2014-06-10 07:03:49 -0700546 case 'e': case 'f': case 'g': case 'a':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700547 break;
548 case 'F':
549#ifdef _MSC_VER
550 // MSVC's printf doesn't support 'F'.
551 type = 'f';
552#endif
553 // Fall through.
Victor Zverovich03776dd2014-06-10 07:03:49 -0700554 case 'E': case 'G': case 'A':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700555 upper = true;
556 break;
557 default:
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700558 internal::report_unknown_type(type, "double");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700559 break;
560 }
561
562 char sign = 0;
Victor Zverovichbe785a82014-07-29 09:14:07 -0700563 // Use getsign instead of value < 0 because the latter is always
Victor Zverovich7cae7632013-09-06 20:23:42 -0700564 // false for NaN.
Victor Zverovichbe785a82014-07-29 09:14:07 -0700565 if (getsign(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700566 sign = '-';
567 value = -value;
Victor Zverovichd142e3b2014-07-25 08:29:06 -0700568 } else if (spec.flag(SIGN_FLAG)) {
569 sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700570 }
571
572 if (value != value) {
573 // Format NaN ourselves because sprintf's output is not consistent
574 // across platforms.
575 std::size_t size = 4;
576 const char *nan = upper ? " NAN" : " nan";
577 if (!sign) {
578 --size;
579 ++nan;
580 }
Victor Zverovich53201032014-06-30 14:26:29 -0700581 CharPtr out = write_str(nan, size, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700582 if (sign)
583 *out = sign;
584 return;
585 }
586
Victor Zverovichbf5b2462014-07-29 08:22:52 -0700587 if (isinfinity(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700588 // Format infinity ourselves because sprintf's output is not consistent
589 // across platforms.
590 std::size_t size = 4;
591 const char *inf = upper ? " INF" : " inf";
592 if (!sign) {
593 --size;
594 ++inf;
595 }
Victor Zverovich53201032014-06-30 14:26:29 -0700596 CharPtr out = write_str(inf, size, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700597 if (sign)
598 *out = sign;
599 return;
600 }
601
602 std::size_t offset = buffer_.size();
603 unsigned width = spec.width();
604 if (sign) {
605 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
606 if (width > 0)
607 --width;
608 ++offset;
609 }
610
611 // Build format string.
612 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
613 Char format[MAX_FORMAT_SIZE];
614 Char *format_ptr = format;
615 *format_ptr++ = '%';
616 unsigned width_for_sprintf = width;
Victor Zverovichd142e3b2014-07-25 08:29:06 -0700617 if (spec.flag(HASH_FLAG))
Victor Zverovich7cae7632013-09-06 20:23:42 -0700618 *format_ptr++ = '#';
619 if (spec.align() == ALIGN_CENTER) {
620 width_for_sprintf = 0;
621 } else {
622 if (spec.align() == ALIGN_LEFT)
623 *format_ptr++ = '-';
624 if (width != 0)
625 *format_ptr++ = '*';
626 }
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700627 if (spec.precision() >= 0) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700628 *format_ptr++ = '.';
629 *format_ptr++ = '*';
630 }
631 if (internal::IsLongDouble<T>::VALUE)
632 *format_ptr++ = 'L';
633 *format_ptr++ = type;
634 *format_ptr = '\0';
635
636 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700637 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700638 for (;;) {
639 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700640#if _MSC_VER
641 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
642 // space for at least one extra character to make the size non-zero.
643 // Note that the buffer's capacity will increase by more than 1.
644 if (size == 0) {
645 buffer_.reserve(offset + 1);
646 size = buffer_.capacity() - offset;
647 }
648#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700649 Char *start = &buffer_[offset];
Victor Zverovichb498ba02014-07-26 08:03:03 -0700650 int n = internal::CharTraits<Char>::format_float(
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700651 start, size, format, width_for_sprintf, spec.precision(), value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700652 if (n >= 0 && offset + n < buffer_.capacity()) {
653 if (sign) {
654 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
655 *start != ' ') {
656 *(start - 1) = sign;
657 sign = 0;
658 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700659 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700660 }
661 ++n;
662 }
663 if (spec.align() == ALIGN_CENTER &&
664 spec.width() > static_cast<unsigned>(n)) {
665 unsigned width = spec.width();
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700666 CharPtr p = grow_buffer(width);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700667 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700668 fill_padding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700669 return;
670 }
671 if (spec.fill() != ' ' || sign) {
672 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700673 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700674 if (sign)
675 *(start - 1) = sign;
676 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700677 grow_buffer(n);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700678 return;
679 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700680 // If n is negative we ask to increase the capacity by at least 1,
681 // but as std::vector, the buffer grows exponentially.
682 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700683 }
684}
685
Victor Zverovich7cae7632013-09-06 20:23:42 -0700686template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700687template <typename StrChar>
Victor Zverovich53201032014-06-30 14:26:29 -0700688void fmt::BasicWriter<Char>::write_str(
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700689 const Arg::StringValue<StrChar> &str, const FormatSpec &spec) {
690 // Check if StrChar is convertible to Char.
691 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700692 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700693 internal::report_unknown_type(spec.type_, "string");
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700694 const StrChar *s = str.value;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700695 std::size_t size = str.size;
696 if (size == 0) {
697 if (!s)
698 throw FormatError("string pointer is null");
699 if (*s)
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700700 size = std::char_traits<StrChar>::length(s);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700701 }
Victor Zverovich53201032014-06-30 14:26:29 -0700702 write_str(s, size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700703}
704
705template <typename Char>
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700706inline const Arg
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700707 &fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700708 unsigned arg_index = 0;
709 if (*s < '0' || *s > '9') {
710 if (*s != '}' && *s != ':')
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700711 report_error_(s, "invalid argument index in format string");
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700712 const Arg &arg = next_arg();
713 if (error_)
714 report_error_(s, error_);
715 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700716 }
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700717 if (next_arg_index_ > 0) {
718 report_error_(s,
719 "cannot switch from automatic to manual argument indexing");
720 }
721 next_arg_index_ = -1;
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700722 arg_index = parse_nonnegative_int(s, error_);
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700723 if (error_)
724 report_error_(s, error_); // TODO: don't use report_error_
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700725 if (arg_index >= args_.size())
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700726 report_error_(s, "argument index is out of range in format");
Victor Zverovich656a8372014-04-22 08:58:54 -0700727 return args_[arg_index];
Victor Zverovich7cae7632013-09-06 20:23:42 -0700728}
729
730template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700731void fmt::BasicFormatter<Char>::check_sign(
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700732 const Char *&s, const Arg &arg) {
Victor Zverovichcc6af502013-12-10 08:01:08 -0800733 char sign = static_cast<char>(*s);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700734 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700735 report_error_(s, fmt::format(
736 "format specifier '{}' requires numeric argument", sign).c_str());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700737 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700738 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700739 report_error_(s, fmt::format(
740 "format specifier '{}' requires signed argument", sign).c_str());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700741 }
742 ++s;
743}
744
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700745const Arg &fmt::internal::FormatterBase::next_arg() {
746 if (next_arg_index_ < 0) {
747 if (!error_)
748 error_ = "cannot switch from manual to automatic argument indexing";
749 return DUMMY_ARG;
750 }
751 unsigned arg_index = next_arg_index_++;
752 if (arg_index < args_.size())
753 return args_[arg_index];
754 if (!error_)
755 error_ = "argument index is out of range in format";
756 return DUMMY_ARG;
757}
758
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700759const Arg &fmt::internal::FormatterBase::handle_arg_index(unsigned arg_index) {
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700760 if (arg_index != UINT_MAX) {
761 if (next_arg_index_ <= 0) {
762 next_arg_index_ = -1;
763 --arg_index;
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700764 } else if (!error_) {
765 error_ = "cannot switch from automatic to manual argument indexing";
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700766 }
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700767 if (arg_index < args_.size())
768 return args_[arg_index];
769 if (!error_)
770 error_ = "argument index is out of range in format";
771 return DUMMY_ARG;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700772 }
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700773 return next_arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700774}
775
Victor Zverovich7cae7632013-09-06 20:23:42 -0700776template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700777void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700778 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700779 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700780 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700781 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700782 spec.align_ = ALIGN_LEFT;
783 break;
784 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700785 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
786 break;
787 case '0':
788 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700789 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700790 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700791 spec.flags_ |= SIGN_FLAG;
792 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700793 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700794 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700795 break;
796 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700797 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700798 return;
799 }
800 }
801}
802
Victor Zverovichcb743c02014-06-19 07:40:35 -0700803template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700804unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700805 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700806 unsigned arg_index = UINT_MAX;
807 Char c = *s;
808 if (c >= '0' && c <= '9') {
809 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700810 // preceded with '0' flag(s).
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700811 unsigned value = parse_nonnegative_int(s, error_);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700812 if (*s == '$') { // value is an argument index
813 ++s;
814 arg_index = value;
815 } else {
816 if (c == '0')
817 spec.fill_ = '0';
818 if (value != 0) {
819 // Nonzero value means that we parsed width and don't need to
820 // parse it or flags again, so return now.
821 spec.width_ = value;
822 return arg_index;
823 }
824 }
825 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700826 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700827 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700828 if (*s >= '0' && *s <= '9') {
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700829 spec.width_ = parse_nonnegative_int(s, error_);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700830 } else if (*s == '*') {
831 ++s;
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700832 spec.width_ = WidthHandler(spec).visit(handle_arg_index(UINT_MAX));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700833 }
834 return arg_index;
835}
836
Victor Zverovich1f19b982014-06-16 07:49:30 -0700837template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700838void fmt::internal::PrintfFormatter<Char>::format(
Victor Zveroviche78904b2014-04-23 08:27:50 -0700839 BasicWriter<Char> &writer, BasicStringRef<Char> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700840 const ArgList &args) {
Victor Zveroviche78904b2014-04-23 08:27:50 -0700841 const Char *start = format.c_str();
Victor Zveroviche78904b2014-04-23 08:27:50 -0700842 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700843 next_arg_index_ = 0;
844 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700845 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700846 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700847 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700848 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700849 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700850 start = ++s;
851 continue;
852 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700853 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700854
Victor Zverovichcb743c02014-06-19 07:40:35 -0700855 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700856 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700857
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700858 // Reporting errors is delayed till the format specification is
859 // completely parsed. This is done to avoid potentially confusing
860 // error messages for incomplete format strings. For example, in
861 // sprintf("%2$", 42);
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700862 // the format specification is incomplete. In a naive approach we
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700863 // would parse 2 as an argument index and report an error that the
864 // index is out of range which would be rather confusing if the
865 // use meant "%2d$" rather than "%2$d". If we delay an error, the
866 // user will get an error that the format string is invalid which
867 // is OK for both cases.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700868
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700869 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700870 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700871
872 // Parse precision.
873 if (*s == '.') {
874 ++s;
875 if ('0' <= *s && *s <= '9') {
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700876 spec.precision_ = parse_nonnegative_int(s, error_);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700877 } else if (*s == '*') {
878 ++s;
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700879 spec.precision_ = PrecisionHandler().visit(handle_arg_index(UINT_MAX));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700880 }
881 }
882
Victor Zverovicheeca2232014-07-30 07:37:16 -0700883 Arg arg = handle_arg_index(arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700884 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700885 spec.flags_ &= ~HASH_FLAG;
886 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700887 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700888 spec.align_ = ALIGN_NUMERIC;
889 else
890 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700891 }
892
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700893 // Parse length.
894 switch (*s) {
Victor Zverovich39b09302014-07-30 08:08:08 -0700895 case 'h': {
Victor Zverovicheeca2232014-07-30 07:37:16 -0700896 ++s;
Victor Zverovich39b09302014-07-30 08:08:08 -0700897 // TODO: handle 'hh'
898 char type = *s;
899 if (type == 'd' || type == 'i')
900 ArgConverter<short>(arg).visit(arg);
901 else
902 ArgConverter<unsigned short>(arg).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700903 break;
Victor Zverovich39b09302014-07-30 08:08:08 -0700904 }
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700905 case 'l':
906 case 'j':
907 case 'z':
908 case 't':
909 case 'L':
910 // TODO: handle length
911 ++s;
912 break;
913 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700914
915 // Parse type.
916 if (!*s)
917 throw FormatError("invalid format string");
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700918 if (error_)
919 throw FormatError(error_);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700920 spec.type_ = static_cast<char>(*s++);
Victor Zverovich39b09302014-07-30 08:08:08 -0700921 if (arg.type <= Arg::LAST_INTEGER_TYPE && spec.type_ == 'u')
922 spec.type_ = 'd';
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700923
924 start = s;
925
926 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700927 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700928 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700929 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700930 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700931 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700932 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700933 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700934 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700935 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700936 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700937 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700938 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700939 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700940 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700941 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700942 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700943 typedef typename BasicWriter<Char>::CharPtr CharPtr;
944 CharPtr out = CharPtr();
945 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700946 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700947 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700948 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700949 std::fill_n(out, spec.width_ - 1, fill);
950 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700951 } else {
952 std::fill_n(out + 1, spec.width_ - 1, fill);
953 }
954 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700955 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700956 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700957 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700958 break;
959 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700960 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700961 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700962 break;
963 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700964 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700965 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700966 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700967 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700968 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700969 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700970 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700971 break;
972 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700973 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700974 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700975 spec.flags_= HASH_FLAG;
976 spec.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700977 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700978 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700979 case Arg::CUSTOM:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700980 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700981 internal::report_unknown_type(spec.type_, "object");
Victor Zveroviche8251562014-07-08 16:20:33 -0700982 arg.custom.format(&writer, arg.custom.value, "s");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700983 break;
984 default:
985 assert(false);
986 break;
987 }
988 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700989 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700990}
991
992template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700993const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700994 const Char *format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700995 const Char *s = format_str;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700996 const char *error = 0;
Victor Zveroviche8251562014-07-08 16:20:33 -0700997 FormatSpec spec;
998 if (*s == ':') {
999 if (arg.type == Arg::CUSTOM) {
1000 arg.custom.format(this, arg.custom.value, s);
1001 return find_closing_brace(s) + 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001002 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001003 ++s;
1004 // Parse fill and alignment.
1005 if (Char c = *s) {
1006 const Char *p = s + 1;
1007 spec.align_ = ALIGN_DEFAULT;
1008 do {
1009 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001010 case '<':
1011 spec.align_ = ALIGN_LEFT;
1012 break;
1013 case '>':
1014 spec.align_ = ALIGN_RIGHT;
1015 break;
1016 case '=':
1017 spec.align_ = ALIGN_NUMERIC;
1018 break;
1019 case '^':
1020 spec.align_ = ALIGN_CENTER;
1021 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001022 }
1023 if (spec.align_ != ALIGN_DEFAULT) {
1024 if (p != s) {
1025 if (c == '}') break;
1026 if (c == '{')
1027 report_error_(s, "invalid fill character '{'");
1028 s += 2;
1029 spec.fill_ = c;
1030 } else ++s;
1031 if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE)
1032 report_error_(s, "format specifier '=' requires numeric argument");
1033 break;
1034 }
1035 } while (--p >= s);
1036 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001037
Victor Zveroviche8251562014-07-08 16:20:33 -07001038 // Parse sign.
1039 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001040 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001041 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001042 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1043 break;
1044 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001045 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001046 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001047 break;
1048 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001049 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001050 spec.flags_ |= SIGN_FLAG;
1051 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001052 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001053
Victor Zveroviche8251562014-07-08 16:20:33 -07001054 if (*s == '#') {
1055 if (arg.type > Arg::LAST_NUMERIC_TYPE)
1056 report_error_(s, "format specifier '#' requires numeric argument");
1057 spec.flags_ |= HASH_FLAG;
1058 ++s;
1059 }
1060
1061 // Parse width and zero flag.
1062 if ('0' <= *s && *s <= '9') {
1063 if (*s == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001064 if (arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zveroviche8251562014-07-08 16:20:33 -07001065 report_error_(s, "format specifier '0' requires numeric argument");
1066 spec.align_ = ALIGN_NUMERIC;
1067 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -07001068 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001069 // Zero may be parsed again as a part of the width, but it is simpler
1070 // and more efficient than checking if the next char is a digit.
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001071 spec.width_ = parse_nonnegative_int(s, error);
Victor Zveroviche8251562014-07-08 16:20:33 -07001072 if (error)
1073 report_error_(s, error);
1074 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001075
Victor Zveroviche8251562014-07-08 16:20:33 -07001076 // Parse precision.
1077 if (*s == '.') {
1078 ++s;
1079 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001080 if ('0' <= *s && *s <= '9') {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001081 spec.precision_ = parse_nonnegative_int(s, error);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001082 if (error)
1083 report_error_(s, error);
Victor Zveroviche8251562014-07-08 16:20:33 -07001084 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001085 ++s;
Victor Zveroviche8251562014-07-08 16:20:33 -07001086 ++report_error_.num_open_braces;
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001087 const Arg &precision_arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001088 ULongLong value = 0;
1089 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001090 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001091 if (precision_arg.int_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001092 report_error_(s, "negative precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001093 value = precision_arg.int_value;
1094 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001095 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001096 value = precision_arg.uint_value;
1097 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001098 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001099 if (precision_arg.long_long_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001100 report_error_(s, "negative precision in format");
Victor Zverovich56f12b72013-11-22 07:45:43 -08001101 value = precision_arg.long_long_value;
1102 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001103 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001104 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001105 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001106 default:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001107 report_error_(s, "precision is not integer");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001108 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001109 if (value > INT_MAX)
1110 report_error_(s, "number is too big in format");
1111 spec.precision_ = static_cast<int>(value);
1112 if (*s++ != '}')
1113 throw FormatError("unmatched '{' in format");
1114 --report_error_.num_open_braces;
1115 } else {
1116 report_error_(s, "missing precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001117 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001118 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
1119 report_error_(s,
1120 "precision specifier requires floating-point argument");
1121 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001122 }
1123
Victor Zveroviche8251562014-07-08 16:20:33 -07001124 // Parse type.
1125 if (*s != '}' && *s)
1126 spec.type_ = static_cast<char>(*s++);
1127 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001128
Victor Zveroviche8251562014-07-08 16:20:33 -07001129 if (*s++ != '}')
1130 throw FormatError("unmatched '{' in format");
1131 start_ = s;
1132
1133 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001134 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001135 return s;
1136}
1137
1138template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001139void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001140 BasicStringRef<Char> format_str, const ArgList &args) {
1141 const Char *s = start_ = format_str.c_str();
1142 args_ = args;
1143 next_arg_index_ = 0;
1144 while (*s) {
1145 Char c = *s++;
1146 if (c != '{' && c != '}') continue;
1147 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001148 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001149 start_ = ++s;
1150 continue;
1151 }
1152 if (c == '}')
1153 throw FormatError("unmatched '}' in format");
1154 report_error_.num_open_braces = 1;
Victor Zverovichc1db2932014-07-24 08:53:27 -07001155 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001156 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001157 s = format(s, arg);
1158 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001159 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001160}
1161
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001162void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001163 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich75b5eb42014-07-27 15:09:05 -07001164 // FIXME: format_system_error may throw
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001165 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001166}
1167
Victor Zverovich400812a2014-04-30 12:38:17 -07001168#ifdef _WIN32
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001169void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001170 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich75b5eb42014-07-27 15:09:05 -07001171 // FIXME: format_windows_error may throw
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001172 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001173}
Victor Zverovich400812a2014-04-30 12:38:17 -07001174#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001175
Victor Zverovich2e039632014-06-28 19:44:39 -07001176void fmt::print(StringRef format, const ArgList &args) {
1177 Writer w;
Victor Zverovicha1264922014-06-29 11:51:10 -07001178 w.write(format, args);
Victor Zverovich2e039632014-06-28 19:44:39 -07001179 std::fwrite(w.data(), 1, w.size(), stdout);
1180}
1181
Victor Zverovichd5b81962014-06-28 21:56:40 -07001182void fmt::print(std::FILE *f, StringRef format, const ArgList &args) {
1183 Writer w;
Victor Zverovicha1264922014-06-29 11:51:10 -07001184 w.write(format, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001185 std::fwrite(w.data(), 1, w.size(), f);
1186}
1187
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001188void fmt::print(std::ostream &os, StringRef format, const ArgList &args) {
1189 Writer w;
1190 w.write(format, args);
1191 os.write(w.data(), w.size());
1192}
1193
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001194void fmt::print_colored(Color c, StringRef format, const ArgList &args) {
1195 char escape[] = "\x1b[30m";
1196 escape[3] = '0' + static_cast<char>(c);
1197 std::fputs(escape, stdout);
1198 print(format, args);
1199 std::fputs(RESET_COLOR, stdout);
1200}
1201
Victor Zverovichd5b81962014-06-28 21:56:40 -07001202void fmt::printf(StringRef format, const ArgList &args) {
1203 Writer w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001204 printf(w, format, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001205 std::fwrite(w.data(), 1, w.size(), stdout);
1206}
1207
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001208// Explicit instantiations for char.
1209
Victor Zverovich93e41252013-09-08 13:07:04 -07001210template fmt::BasicWriter<char>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001211 fmt::BasicWriter<char>::fill_padding(CharPtr buffer,
Victor Zverovich93e41252013-09-08 13:07:04 -07001212 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001213
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001214template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001215 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001216
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001217template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001218 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001219
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001220// Explicit instantiations for wchar_t.
1221
Victor Zverovich7cae7632013-09-06 20:23:42 -07001222template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001223 fmt::BasicWriter<wchar_t>::fill_padding(CharPtr buffer,
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001224 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001225
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001226template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001227 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001228
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001229template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001230 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001231 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001232
1233#if _MSC_VER
1234# pragma warning(pop)
1235#endif