blob: 07c619d2ce74b30a33a2f70e902f644fb85df197 [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) {
221 if (std::numeric_limits<U>::is_signed) {
222 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) {
895 case 'h':
Victor Zverovicheeca2232014-07-30 07:37:16 -0700896 ++s;
897 ArgConverter<short>(arg).visit(arg);
898 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700899 case 'l':
900 case 'j':
901 case 'z':
902 case 't':
903 case 'L':
904 // TODO: handle length
905 ++s;
906 break;
907 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700908
909 // Parse type.
910 if (!*s)
911 throw FormatError("invalid format string");
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700912 if (error_)
913 throw FormatError(error_);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700914 spec.type_ = static_cast<char>(*s++);
915
916 start = s;
917
918 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700919 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700920 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700921 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700922 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700923 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700924 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700925 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700926 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700927 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700928 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700929 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700930 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700931 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700932 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700933 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700934 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700935 typedef typename BasicWriter<Char>::CharPtr CharPtr;
936 CharPtr out = CharPtr();
937 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700938 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700939 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700940 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700941 std::fill_n(out, spec.width_ - 1, fill);
942 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700943 } else {
944 std::fill_n(out + 1, spec.width_ - 1, fill);
945 }
946 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700947 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700948 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700949 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700950 break;
951 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700952 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700953 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700954 break;
955 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700956 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700957 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700958 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700959 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700960 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700961 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700962 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700963 break;
964 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700965 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700966 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700967 spec.flags_= HASH_FLAG;
968 spec.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700969 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700970 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700971 case Arg::CUSTOM:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700972 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700973 internal::report_unknown_type(spec.type_, "object");
Victor Zveroviche8251562014-07-08 16:20:33 -0700974 arg.custom.format(&writer, arg.custom.value, "s");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700975 break;
976 default:
977 assert(false);
978 break;
979 }
980 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700981 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700982}
983
984template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700985const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700986 const Char *format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700987 const Char *s = format_str;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700988 const char *error = 0;
Victor Zveroviche8251562014-07-08 16:20:33 -0700989 FormatSpec spec;
990 if (*s == ':') {
991 if (arg.type == Arg::CUSTOM) {
992 arg.custom.format(this, arg.custom.value, s);
993 return find_closing_brace(s) + 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700994 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700995 ++s;
996 // Parse fill and alignment.
997 if (Char c = *s) {
998 const Char *p = s + 1;
999 spec.align_ = ALIGN_DEFAULT;
1000 do {
1001 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001002 case '<':
1003 spec.align_ = ALIGN_LEFT;
1004 break;
1005 case '>':
1006 spec.align_ = ALIGN_RIGHT;
1007 break;
1008 case '=':
1009 spec.align_ = ALIGN_NUMERIC;
1010 break;
1011 case '^':
1012 spec.align_ = ALIGN_CENTER;
1013 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001014 }
1015 if (spec.align_ != ALIGN_DEFAULT) {
1016 if (p != s) {
1017 if (c == '}') break;
1018 if (c == '{')
1019 report_error_(s, "invalid fill character '{'");
1020 s += 2;
1021 spec.fill_ = c;
1022 } else ++s;
1023 if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE)
1024 report_error_(s, "format specifier '=' requires numeric argument");
1025 break;
1026 }
1027 } while (--p >= s);
1028 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001029
Victor Zveroviche8251562014-07-08 16:20:33 -07001030 // Parse sign.
1031 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001032 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001033 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001034 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1035 break;
1036 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001037 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001038 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001039 break;
1040 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;
1043 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001044 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001045
Victor Zveroviche8251562014-07-08 16:20:33 -07001046 if (*s == '#') {
1047 if (arg.type > Arg::LAST_NUMERIC_TYPE)
1048 report_error_(s, "format specifier '#' requires numeric argument");
1049 spec.flags_ |= HASH_FLAG;
1050 ++s;
1051 }
1052
1053 // Parse width and zero flag.
1054 if ('0' <= *s && *s <= '9') {
1055 if (*s == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001056 if (arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zveroviche8251562014-07-08 16:20:33 -07001057 report_error_(s, "format specifier '0' requires numeric argument");
1058 spec.align_ = ALIGN_NUMERIC;
1059 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -07001060 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001061 // Zero may be parsed again as a part of the width, but it is simpler
1062 // and more efficient than checking if the next char is a digit.
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001063 spec.width_ = parse_nonnegative_int(s, error);
Victor Zveroviche8251562014-07-08 16:20:33 -07001064 if (error)
1065 report_error_(s, error);
1066 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001067
Victor Zveroviche8251562014-07-08 16:20:33 -07001068 // Parse precision.
1069 if (*s == '.') {
1070 ++s;
1071 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001072 if ('0' <= *s && *s <= '9') {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001073 spec.precision_ = parse_nonnegative_int(s, error);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001074 if (error)
1075 report_error_(s, error);
Victor Zveroviche8251562014-07-08 16:20:33 -07001076 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001077 ++s;
Victor Zveroviche8251562014-07-08 16:20:33 -07001078 ++report_error_.num_open_braces;
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001079 const Arg &precision_arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001080 ULongLong value = 0;
1081 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001082 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001083 if (precision_arg.int_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001084 report_error_(s, "negative precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001085 value = precision_arg.int_value;
1086 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001087 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001088 value = precision_arg.uint_value;
1089 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001090 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001091 if (precision_arg.long_long_value < 0)
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001092 report_error_(s, "negative precision in format");
Victor Zverovich56f12b72013-11-22 07:45:43 -08001093 value = precision_arg.long_long_value;
1094 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001095 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001096 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001097 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001098 default:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001099 report_error_(s, "precision is not integer");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001100 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001101 if (value > INT_MAX)
1102 report_error_(s, "number is too big in format");
1103 spec.precision_ = static_cast<int>(value);
1104 if (*s++ != '}')
1105 throw FormatError("unmatched '{' in format");
1106 --report_error_.num_open_braces;
1107 } else {
1108 report_error_(s, "missing precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001109 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001110 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
1111 report_error_(s,
1112 "precision specifier requires floating-point argument");
1113 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001114 }
1115
Victor Zveroviche8251562014-07-08 16:20:33 -07001116 // Parse type.
1117 if (*s != '}' && *s)
1118 spec.type_ = static_cast<char>(*s++);
1119 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001120
Victor Zveroviche8251562014-07-08 16:20:33 -07001121 if (*s++ != '}')
1122 throw FormatError("unmatched '{' in format");
1123 start_ = s;
1124
1125 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001126 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001127 return s;
1128}
1129
1130template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001131void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001132 BasicStringRef<Char> format_str, const ArgList &args) {
1133 const Char *s = start_ = format_str.c_str();
1134 args_ = args;
1135 next_arg_index_ = 0;
1136 while (*s) {
1137 Char c = *s++;
1138 if (c != '{' && c != '}') continue;
1139 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001140 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001141 start_ = ++s;
1142 continue;
1143 }
1144 if (c == '}')
1145 throw FormatError("unmatched '}' in format");
1146 report_error_.num_open_braces = 1;
Victor Zverovichc1db2932014-07-24 08:53:27 -07001147 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001148 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001149 s = format(s, arg);
1150 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001151 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001152}
1153
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001154void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001155 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich75b5eb42014-07-27 15:09:05 -07001156 // FIXME: format_system_error may throw
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001157 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001158}
1159
Victor Zverovich400812a2014-04-30 12:38:17 -07001160#ifdef _WIN32
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001161void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001162 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich75b5eb42014-07-27 15:09:05 -07001163 // FIXME: format_windows_error may throw
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001164 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001165}
Victor Zverovich400812a2014-04-30 12:38:17 -07001166#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001167
Victor Zverovich2e039632014-06-28 19:44:39 -07001168void fmt::print(StringRef format, const ArgList &args) {
1169 Writer w;
Victor Zverovicha1264922014-06-29 11:51:10 -07001170 w.write(format, args);
Victor Zverovich2e039632014-06-28 19:44:39 -07001171 std::fwrite(w.data(), 1, w.size(), stdout);
1172}
1173
Victor Zverovichd5b81962014-06-28 21:56:40 -07001174void fmt::print(std::FILE *f, StringRef format, const ArgList &args) {
1175 Writer w;
Victor Zverovicha1264922014-06-29 11:51:10 -07001176 w.write(format, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001177 std::fwrite(w.data(), 1, w.size(), f);
1178}
1179
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001180void fmt::print(std::ostream &os, StringRef format, const ArgList &args) {
1181 Writer w;
1182 w.write(format, args);
1183 os.write(w.data(), w.size());
1184}
1185
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001186void fmt::print_colored(Color c, StringRef format, const ArgList &args) {
1187 char escape[] = "\x1b[30m";
1188 escape[3] = '0' + static_cast<char>(c);
1189 std::fputs(escape, stdout);
1190 print(format, args);
1191 std::fputs(RESET_COLOR, stdout);
1192}
1193
Victor Zverovichd5b81962014-06-28 21:56:40 -07001194void fmt::printf(StringRef format, const ArgList &args) {
1195 Writer w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001196 printf(w, format, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001197 std::fwrite(w.data(), 1, w.size(), stdout);
1198}
1199
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001200// Explicit instantiations for char.
1201
Victor Zverovich93e41252013-09-08 13:07:04 -07001202template fmt::BasicWriter<char>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001203 fmt::BasicWriter<char>::fill_padding(CharPtr buffer,
Victor Zverovich93e41252013-09-08 13:07:04 -07001204 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001205
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001206template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001207 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001208
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001209template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001210 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001211
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001212// Explicit instantiations for wchar_t.
1213
Victor Zverovich7cae7632013-09-06 20:23:42 -07001214template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001215 fmt::BasicWriter<wchar_t>::fill_padding(CharPtr buffer,
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001216 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001217
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001218template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001219 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001220
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001221template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001222 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001223 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001224
1225#if _MSC_VER
1226# pragma warning(pop)
1227#endif