blob: bf355910de9c543d7c7fa7fa7f75e4ef682b9d07 [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 Zverovich24d6baa2014-07-29 07:49:34 -070078#ifdef isinf
Victor Zverovichd4412a02014-08-13 08:01:51 -070079inline int isinfinity(double x) { return isinf(x); }
80inline int isinfinity(long double x) { return isinf(x); }
Victor Zverovich24d6baa2014-07-29 07:49:34 -070081#else
Victor Zverovichd4412a02014-08-13 08:01:51 -070082inline int isinfinity(double x) { return std::isinf(x); }
83inline int isinfinity(long double x) { return std::isinf(x); }
Victor Zverovich9ff3b972013-09-07 10:15:08 -070084#endif
Victor Zverovich1a0c76a2014-08-13 07:51:02 -070085
Victor Zverovich9ff3b972013-09-07 10:15:08 -070086#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 Zverovich406c6122014-08-19 08:47:38 -0700101inline int fmt_snprintf(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 Zverovich406c6122014-08-19 08:47:38 -0700108#define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700109
110#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800111
Victor Zverovichfb321612014-08-15 08:40:03 -0700112template <typename T>
113struct IsLongDouble { enum {VALUE = 0}; };
114
115template <>
116struct IsLongDouble<long double> { enum {VALUE = 1}; };
117
Victor Zverovichadce0242014-08-17 07:53:55 -0700118// Checks if a value fits in int - used to avoid warnings about comparing
119// signed and unsigned integers.
120template <bool IsSigned>
121struct IntChecker {
122 template <typename T>
123 static bool fits_in_int(T value) {
124 unsigned max = INT_MAX;
125 return value <= max;
126 }
127};
128
129template <>
130struct IntChecker<true> {
131 template <typename T>
132 static bool fits_in_int(T value) {
133 return value >= INT_MIN && value <= INT_MAX;
134 }
135};
136
Victor Zverovich43fe1002014-02-19 14:20:26 -0800137const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700138
139typedef void (*FormatFunc)(fmt::Writer &, int , fmt::StringRef);
140
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700141void report_error(FormatFunc func,
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700142 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
143 try {
144 fmt::Writer full_message;
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700145 func(full_message, error_code, message); // TODO: make sure this doesn't throw
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700146 std::fwrite(full_message.c_str(), full_message.size(), 1, stderr);
147 std::fputc('\n', stderr);
148 } catch (...) {}
Victor Zverovichb605b392013-09-09 22:21:40 -0700149}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700150
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700151// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
152class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
153 public:
154 template <typename T>
155 bool visit_any_int(T value) { return value == 0; }
156};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700157
158// Parses an unsigned integer advancing s to the end of the parsed input.
159// This function assumes that the first character of s is a digit.
160template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700161int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700162 assert('0' <= *s && *s <= '9');
163 unsigned value = 0;
164 do {
165 unsigned new_value = value * 10 + (*s++ - '0');
166 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700167 if (new_value < value) {
168 value = UINT_MAX;
169 break;
170 }
171 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700172 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700173 if (value > INT_MAX)
Victor Zverovich279c7a62014-08-28 06:50:52 -0700174 throw fmt::FormatError("number is too big");
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700175 return value;
176}
Victor Zveroviche8251562014-07-08 16:20:33 -0700177
178template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700179void check_sign(const Char *&s, const Arg &arg) {
180 char sign = static_cast<char>(*s);
181 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
182 throw fmt::FormatError(fmt::format(
183 "format specifier '{}' requires numeric argument", sign));
184 }
185 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
186 throw fmt::FormatError(fmt::format(
187 "format specifier '{}' requires signed argument", sign));
188 }
189 ++s;
190}
191
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700192// Checks if an argument is a valid printf width specifier and sets
193// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700194class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700195 private:
196 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700197
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700198 public:
199 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700200
Victor Zverovich9d74f952014-07-16 07:27:54 -0700201 unsigned visit_unhandled_arg() {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700202 throw fmt::FormatError("width is not integer");
203 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700204
Victor Zverovich9d74f952014-07-16 07:27:54 -0700205 template <typename T>
206 unsigned visit_any_int(T value) {
207 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
208 UnsignedType width = value;
209 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700210 spec_.align_ = fmt::ALIGN_LEFT;
211 width = 0 - width;
212 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700213 if (width > INT_MAX)
Victor Zverovich279c7a62014-08-28 06:50:52 -0700214 throw fmt::FormatError("number is too big");
Victor Zverovich9d74f952014-07-16 07:27:54 -0700215 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700216 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700217};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700218
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700219class PrecisionHandler :
220 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
221 public:
222 unsigned visit_unhandled_arg() {
223 throw fmt::FormatError("precision is not integer");
224 }
225
226 template <typename T>
227 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700228 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich279c7a62014-08-28 06:50:52 -0700229 throw fmt::FormatError("number is too big");
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700230 return static_cast<int>(value);
231 }
232};
233
Victor Zverovich32344d92014-08-28 08:11:21 -0700234// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700235template <typename T>
236class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
237 private:
238 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700239 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700240
241 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700242 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
243 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700244
245 template <typename U>
246 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700247 bool is_signed = type_ == 'd' || type_ == 'i';
248 using fmt::internal::Arg;
249 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700250 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700251 if (is_signed) {
252 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700253 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700254 } else {
255 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700256 arg_.uint_value = static_cast<unsigned>(
257 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700258 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700259 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700260 if (is_signed) {
261 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700262 arg_.long_long_value =
263 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700264 } else {
265 arg_.type = Arg::ULONG_LONG;
266 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700267 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700268 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700269 }
270 }
271};
272
Victor Zverovich32344d92014-08-28 08:11:21 -0700273// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700274class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
275 private:
276 fmt::internal::Arg &arg_;
277
278 public:
279 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
280
281 template <typename T>
282 void visit_any_int(T value) {
283 arg_.type = Arg::CHAR;
284 arg_.int_value = static_cast<char>(value);
285 }
286};
287
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700288// This function template is used to prevent compile errors when handling
289// incompatible string arguments, e.g. handling a wide string in a narrow
290// string formatter.
291template <typename Char>
292Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
293
294template <>
295inline Arg::StringValue<char> ignore_incompatible_str(
296 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
297
298template <>
299inline Arg::StringValue<wchar_t> ignore_incompatible_str(
300 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700301} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700302
Victor Zverovich53201032014-06-30 14:26:29 -0700303void fmt::SystemError::init(
304 int error_code, StringRef format_str, const ArgList &args) {
305 error_code_ = error_code;
306 Writer w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700307 internal::format_system_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700308 std::runtime_error &base = *this;
309 base = std::runtime_error(w.str());
310}
311
Victor Zverovichb605b392013-09-09 22:21:40 -0700312template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700313int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700314 char *buffer, std::size_t size, const char *format,
315 unsigned width, int precision, T value) {
316 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700317 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700318 FMT_SNPRINTF(buffer, size, format, value) :
319 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700320 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700321 return precision < 0 ?
322 FMT_SNPRINTF(buffer, size, format, width, value) :
323 FMT_SNPRINTF(buffer, size, format, width, precision, value);
324}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700325
Victor Zverovichb605b392013-09-09 22:21:40 -0700326template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700327int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700328 wchar_t *buffer, std::size_t size, const wchar_t *format,
329 unsigned width, int precision, T value) {
330 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700331 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700332 swprintf(buffer, size, format, value) :
333 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700334 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700335 return precision < 0 ?
336 swprintf(buffer, size, format, width, value) :
337 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700338}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800339
Victor Zverovich65d47e52013-09-09 06:51:03 -0700340const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800341 "0001020304050607080910111213141516171819"
342 "2021222324252627282930313233343536373839"
343 "4041424344454647484950515253545556575859"
344 "6061626364656667686970717273747576777879"
345 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800346
Victor Zverovichf1d85162014-02-19 13:02:22 -0800347#define FMT_POWERS_OF_10(factor) \
348 factor * 10, \
349 factor * 100, \
350 factor * 1000, \
351 factor * 10000, \
352 factor * 100000, \
353 factor * 1000000, \
354 factor * 10000000, \
355 factor * 100000000, \
356 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800357
Victor Zverovichf1d85162014-02-19 13:02:22 -0800358const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800359const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800360 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800361 FMT_POWERS_OF_10(1),
362 FMT_POWERS_OF_10(ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700363 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800364 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800365 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800366};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800367
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700368void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800369 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700370 throw fmt::FormatError(
371 fmt::format("unknown format code '{}' for {}", code, type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800372 }
373 throw fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700374 fmt::format("unknown format code '\\x{:02x}' for {}",
375 static_cast<unsigned>(code), type));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800376}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700377
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700378#ifdef _WIN32
379
380fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
381 int length = MultiByteToWideChar(
382 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
383 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
384 if (length == 0)
Victor Zverovichf4208772014-06-30 17:32:08 -0700385 throw WindowsError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700386 buffer_.resize(length);
387 length = MultiByteToWideChar(
388 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
389 if (length == 0)
Victor Zverovichf4208772014-06-30 17:32:08 -0700390 throw WindowsError(GetLastError(), ERROR);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700391}
392
393fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700394 if (int error_code = convert(s)) {
Victor Zverovich8321d0e2014-07-09 08:39:01 -0700395 throw WindowsError(error_code,
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700396 "cannot convert string from UTF-16 to UTF-8");
397 }
398}
399
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700400int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700401 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
402 if (length == 0)
403 return GetLastError();
404 buffer_.resize(length);
405 length = WideCharToMultiByte(
406 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
407 if (length == 0)
408 return GetLastError();
409 return 0;
410}
411
Victor Zverovich53201032014-06-30 14:26:29 -0700412void fmt::WindowsError::init(
413 int error_code, StringRef format_str, const ArgList &args) {
414 error_code_ = error_code;
415 Writer w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700416 internal::format_windows_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700417 std::runtime_error &base = *this;
418 base = std::runtime_error(w.str());
419}
420
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700421#endif
422
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700423int fmt::internal::safe_strerror(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700424 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700425 assert(buffer != 0 && buffer_size != 0);
Victor Zverovich99e61122014-04-30 11:20:41 -0700426 int result = 0;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700427#ifdef _GNU_SOURCE
428 char *message = strerror_r(error_code, buffer, buffer_size);
Victor Zverovich99e61122014-04-30 11:20:41 -0700429 // If the buffer is full then the message is probably truncated.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700430 if (message == buffer && strlen(buffer) == buffer_size - 1)
Victor Zverovich99e61122014-04-30 11:20:41 -0700431 result = ERANGE;
432 buffer = message;
Victor Zverovich9c47f3e2014-07-09 09:45:18 -0700433#elif __MINGW32__
434 errno = 0;
435 (void)buffer_size;
436 buffer = strerror(error_code);
437 result = errno;
438#elif _WIN32
Victor Zverovich99e61122014-04-30 11:20:41 -0700439 result = strerror_s(buffer, buffer_size, error_code);
440 // If the buffer is full then the message is probably truncated.
441 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
442 result = ERANGE;
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700443#else
Victor Zverovich99e61122014-04-30 11:20:41 -0700444 result = strerror_r(error_code, buffer, buffer_size);
445 if (result == -1)
446 result = errno; // glibc versions before 2.13 return result in errno.
Victor Zverovich2c6372d2014-04-30 09:42:48 -0700447#endif
Victor Zverovich99e61122014-04-30 11:20:41 -0700448 return result;
Victor Zverovich859a4972014-04-30 06:55:21 -0700449}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700450
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700451void fmt::internal::format_system_error(
Victor Zverovich53b4c312014-04-30 15:00:41 -0700452 fmt::Writer &out, int error_code, fmt::StringRef message) {
453 Array<char, INLINE_BUFFER_SIZE> buffer;
454 buffer.resize(INLINE_BUFFER_SIZE);
455 char *system_message = 0;
456 for (;;) {
457 system_message = &buffer[0];
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700458 int result = safe_strerror(error_code, system_message, buffer.size());
Victor Zverovich53b4c312014-04-30 15:00:41 -0700459 if (result == 0)
460 break;
461 if (result != ERANGE) {
462 // Can't get error message, report error code instead.
463 out << message << ": error code = " << error_code;
464 return;
465 }
466 buffer.resize(buffer.size() * 2);
467 }
468 out << message << ": " << system_message;
469}
470
471#ifdef _WIN32
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700472void fmt::internal::format_windows_error(
Victor Zverovich53b4c312014-04-30 15:00:41 -0700473 fmt::Writer &out, int error_code, fmt::StringRef message) {
474 class String {
475 private:
476 LPWSTR str_;
477
478 public:
479 String() : str_() {}
480 ~String() { LocalFree(str_); }
481 LPWSTR *ptr() { return &str_; }
482 LPCWSTR c_str() const { return str_; }
483 };
484 String system_message;
485 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
486 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
487 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
488 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
489 UTF16ToUTF8 utf8_message;
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700490 if (!utf8_message.convert(system_message.c_str())) {
Victor Zverovicheb034a02014-06-30 17:40:53 -0700491 out << message << ": " << utf8_message;
Victor Zverovich53b4c312014-04-30 15:00:41 -0700492 return;
493 }
494 }
495 // Can't get error message, report error code instead.
496 out << message << ": error code = " << error_code;
497}
498#endif
499
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700500// An argument formatter.
501template <typename Char>
502class fmt::internal::ArgFormatter :
503 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
504 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700505 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700506 fmt::BasicWriter<Char> &writer_;
507 fmt::FormatSpec &spec_;
508 const Char *format_;
509
510 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700511 ArgFormatter(
512 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700513 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700514
Victor Zverovich9d74f952014-07-16 07:27:54 -0700515 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700516 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700517
518 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700519 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700520
521 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700522 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700523 spec_.flags_ |= CHAR_FLAG;
524 writer_.write_int(value, spec_);
525 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700526 }
527 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
528 throw FormatError("invalid format specifier for char");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700529 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
530 CharPtr out = CharPtr();
531 if (spec_.width_ > 1) {
532 Char fill = static_cast<Char>(spec_.fill());
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700533 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700534 if (spec_.align_ == fmt::ALIGN_RIGHT) {
535 std::fill_n(out, spec_.width_ - 1, fill);
536 out += spec_.width_ - 1;
537 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700538 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700539 } else {
540 std::fill_n(out + 1, spec_.width_ - 1, fill);
541 }
542 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700543 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700544 }
545 *out = static_cast<Char>(value);
546 }
547
548 void visit_string(Arg::StringValue<char> value) {
549 writer_.write_str(value, spec_);
550 }
551 void visit_wstring(Arg::StringValue<wchar_t> value) {
552 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
553 }
554
555 void visit_pointer(const void *value) {
556 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700557 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700558 spec_.flags_ = fmt::HASH_FLAG;
559 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700560 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700561 }
562
563 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700564 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700565 }
566};
567
Victor Zverovich7cae7632013-09-06 20:23:42 -0700568// Fills the padding around the content and returns the pointer to the
569// content area.
570template <typename Char>
Victor Zverovich93e41252013-09-08 13:07:04 -0700571typename fmt::BasicWriter<Char>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700572 fmt::BasicWriter<Char>::fill_padding(CharPtr buffer,
Victor Zverovich93e41252013-09-08 13:07:04 -0700573 unsigned total_size, std::size_t content_size, wchar_t fill) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700574 std::size_t padding = total_size - content_size;
575 std::size_t left_padding = padding / 2;
Victor Zverovich563a5752013-09-08 13:47:06 -0700576 Char fill_char = static_cast<Char>(fill);
577 std::fill_n(buffer, left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700578 buffer += left_padding;
579 CharPtr content = buffer;
Victor Zverovich563a5752013-09-08 13:47:06 -0700580 std::fill_n(buffer + content_size, padding - left_padding, fill_char);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700581 return content;
582}
583
584template <typename Char>
Victor Zverovich7cae7632013-09-06 20:23:42 -0700585template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700586void fmt::BasicWriter<Char>::write_double(T value, const FormatSpec &spec) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700587 // Check type.
588 char type = spec.type();
589 bool upper = false;
590 switch (type) {
591 case 0:
592 type = 'g';
593 break;
Victor Zverovich03776dd2014-06-10 07:03:49 -0700594 case 'e': case 'f': case 'g': case 'a':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700595 break;
596 case 'F':
597#ifdef _MSC_VER
598 // MSVC's printf doesn't support 'F'.
599 type = 'f';
600#endif
601 // Fall through.
Victor Zverovich03776dd2014-06-10 07:03:49 -0700602 case 'E': case 'G': case 'A':
Victor Zverovich7cae7632013-09-06 20:23:42 -0700603 upper = true;
604 break;
605 default:
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700606 internal::report_unknown_type(type, "double");
Victor Zverovich7cae7632013-09-06 20:23:42 -0700607 break;
608 }
609
610 char sign = 0;
Victor Zverovichbe785a82014-07-29 09:14:07 -0700611 // Use getsign instead of value < 0 because the latter is always
Victor Zverovich7cae7632013-09-06 20:23:42 -0700612 // false for NaN.
Victor Zverovichbe785a82014-07-29 09:14:07 -0700613 if (getsign(static_cast<double>(value))) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700614 sign = '-';
615 value = -value;
Victor Zverovichd142e3b2014-07-25 08:29:06 -0700616 } else if (spec.flag(SIGN_FLAG)) {
617 sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700618 }
619
620 if (value != value) {
621 // Format NaN ourselves because sprintf's output is not consistent
622 // across platforms.
623 std::size_t size = 4;
624 const char *nan = upper ? " NAN" : " nan";
625 if (!sign) {
626 --size;
627 ++nan;
628 }
Victor Zverovich53201032014-06-30 14:26:29 -0700629 CharPtr out = write_str(nan, size, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700630 if (sign)
631 *out = sign;
632 return;
633 }
634
Victor Zverovich1a0c76a2014-08-13 07:51:02 -0700635 if (isinfinity(value)) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700636 // Format infinity ourselves because sprintf's output is not consistent
637 // across platforms.
638 std::size_t size = 4;
639 const char *inf = upper ? " INF" : " inf";
640 if (!sign) {
641 --size;
642 ++inf;
643 }
Victor Zverovich53201032014-06-30 14:26:29 -0700644 CharPtr out = write_str(inf, size, spec);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700645 if (sign)
646 *out = sign;
647 return;
648 }
649
650 std::size_t offset = buffer_.size();
651 unsigned width = spec.width();
652 if (sign) {
653 buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
654 if (width > 0)
655 --width;
656 ++offset;
657 }
658
659 // Build format string.
660 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
661 Char format[MAX_FORMAT_SIZE];
662 Char *format_ptr = format;
663 *format_ptr++ = '%';
664 unsigned width_for_sprintf = width;
Victor Zverovichd142e3b2014-07-25 08:29:06 -0700665 if (spec.flag(HASH_FLAG))
Victor Zverovich7cae7632013-09-06 20:23:42 -0700666 *format_ptr++ = '#';
667 if (spec.align() == ALIGN_CENTER) {
668 width_for_sprintf = 0;
669 } else {
670 if (spec.align() == ALIGN_LEFT)
671 *format_ptr++ = '-';
672 if (width != 0)
673 *format_ptr++ = '*';
674 }
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700675 if (spec.precision() >= 0) {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700676 *format_ptr++ = '.';
677 *format_ptr++ = '*';
678 }
Victor Zverovichfb321612014-08-15 08:40:03 -0700679 if (IsLongDouble<T>::VALUE)
Victor Zverovich7cae7632013-09-06 20:23:42 -0700680 *format_ptr++ = 'L';
681 *format_ptr++ = type;
682 *format_ptr = '\0';
683
684 // Format using snprintf.
Victor Zverovich88972f42013-09-08 13:30:14 -0700685 Char fill = static_cast<Char>(spec.fill());
Victor Zverovich7cae7632013-09-06 20:23:42 -0700686 for (;;) {
687 std::size_t size = buffer_.capacity() - offset;
Victor Zverovich33baa8f2014-04-23 18:37:08 -0700688#if _MSC_VER
689 // MSVC's vsnprintf_s doesn't work with zero size, so reserve
690 // space for at least one extra character to make the size non-zero.
691 // Note that the buffer's capacity will increase by more than 1.
692 if (size == 0) {
693 buffer_.reserve(offset + 1);
694 size = buffer_.capacity() - offset;
695 }
696#endif
Victor Zverovich7cae7632013-09-06 20:23:42 -0700697 Char *start = &buffer_[offset];
Victor Zverovichb498ba02014-07-26 08:03:03 -0700698 int n = internal::CharTraits<Char>::format_float(
Victor Zverovichb1bbc902014-06-21 08:32:00 -0700699 start, size, format, width_for_sprintf, spec.precision(), value);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700700 if (n >= 0 && offset + n < buffer_.capacity()) {
701 if (sign) {
702 if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
703 *start != ' ') {
704 *(start - 1) = sign;
705 sign = 0;
706 } else {
Victor Zverovich88972f42013-09-08 13:30:14 -0700707 *(start - 1) = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700708 }
709 ++n;
710 }
711 if (spec.align() == ALIGN_CENTER &&
712 spec.width() > static_cast<unsigned>(n)) {
713 unsigned width = spec.width();
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700714 CharPtr p = grow_buffer(width);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700715 std::copy(p, p + n, p + (width - n) / 2);
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700716 fill_padding(p, spec.width(), n, fill);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700717 return;
718 }
719 if (spec.fill() != ' ' || sign) {
720 while (*start == ' ')
Victor Zverovich88972f42013-09-08 13:30:14 -0700721 *start++ = fill;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700722 if (sign)
723 *(start - 1) = sign;
724 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700725 grow_buffer(n);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700726 return;
727 }
Victor Zverovichcfeba452014-04-23 18:37:49 -0700728 // If n is negative we ask to increase the capacity by at least 1,
729 // but as std::vector, the buffer grows exponentially.
730 buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700731 }
732}
733
Victor Zverovich7cae7632013-09-06 20:23:42 -0700734template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700735template <typename StrChar>
Victor Zverovich53201032014-06-30 14:26:29 -0700736void fmt::BasicWriter<Char>::write_str(
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700737 const Arg::StringValue<StrChar> &str, const FormatSpec &spec) {
738 // Check if StrChar is convertible to Char.
739 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700740 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700741 internal::report_unknown_type(spec.type_, "string");
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700742 const StrChar *s = str.value;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700743 std::size_t size = str.size;
744 if (size == 0) {
745 if (!s)
746 throw FormatError("string pointer is null");
747 if (*s)
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700748 size = std::char_traits<StrChar>::length(s);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700749 }
Victor Zverovich53201032014-06-30 14:26:29 -0700750 write_str(s, size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700751}
752
753template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700754inline const Arg &fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700755 const char *error = 0;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700756 const Arg *arg = *s < '0' || *s > '9' ?
757 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich9646e382014-08-27 09:13:42 -0700758 if (error)
759 throw FormatError(*s != '}' && *s != ':' ? "invalid format string" : error);
Victor Zverovichda0f7c02014-08-27 09:04:51 -0700760 return *arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700761}
762
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700763const Arg *fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700764 if (next_arg_index_ < 0) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700765 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700766 return 0;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700767 }
768 unsigned arg_index = next_arg_index_++;
769 if (arg_index < args_.size())
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700770 return &args_[arg_index];
Victor Zverovich9646e382014-08-27 09:13:42 -0700771 error = "argument index is out of range in format";
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700772 return 0;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700773}
774
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700775const Arg *fmt::internal::FormatterBase::get_arg(
776 unsigned arg_index, const char *&error) {
777 if (next_arg_index_ > 0) {
778 error = "cannot switch from automatic to manual argument indexing";
779 return 0;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700780 }
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700781 next_arg_index_ = -1;
782 if (arg_index < args_.size())
783 return &args_[arg_index];
784 error = "argument index is out of range in format";
785 return 0;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700786}
787
Victor Zverovich7cae7632013-09-06 20:23:42 -0700788template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700789void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700790 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700791 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700792 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700793 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700794 spec.align_ = ALIGN_LEFT;
795 break;
796 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700797 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
798 break;
799 case '0':
800 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700801 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700802 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700803 spec.flags_ |= SIGN_FLAG;
804 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700805 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700806 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700807 break;
808 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700809 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700810 return;
811 }
812 }
813}
814
Victor Zverovichcb743c02014-06-19 07:40:35 -0700815template <typename Char>
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700816const Arg &fmt::internal::PrintfFormatter<Char>::get_arg(
817 const Char *s, unsigned arg_index) {
818 const char *error = 0;
819 const Arg *arg = arg_index == UINT_MAX ?
820 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
821 if (error)
822 throw FormatError(!*s ? "invalid format string" : error);
823 return *arg;
824}
825
826template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700827unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700828 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700829 unsigned arg_index = UINT_MAX;
830 Char c = *s;
831 if (c >= '0' && c <= '9') {
832 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700833 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700834 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700835 if (*s == '$') { // value is an argument index
836 ++s;
837 arg_index = value;
838 } else {
839 if (c == '0')
840 spec.fill_ = '0';
841 if (value != 0) {
842 // Nonzero value means that we parsed width and don't need to
843 // parse it or flags again, so return now.
844 spec.width_ = value;
845 return arg_index;
846 }
847 }
848 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700849 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700850 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700851 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700852 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700853 } else if (*s == '*') {
854 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700855 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700856 }
857 return arg_index;
858}
859
Victor Zverovich1f19b982014-06-16 07:49:30 -0700860template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700861void fmt::internal::PrintfFormatter<Char>::format(
Victor Zveroviche78904b2014-04-23 08:27:50 -0700862 BasicWriter<Char> &writer, BasicStringRef<Char> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700863 const ArgList &args) {
Victor Zveroviche78904b2014-04-23 08:27:50 -0700864 const Char *start = format.c_str();
Victor Zveroviche78904b2014-04-23 08:27:50 -0700865 args_ = args;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700866 next_arg_index_ = 0;
867 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700868 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700869 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700870 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700871 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700872 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700873 start = ++s;
874 continue;
875 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700876 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700877
Victor Zverovichcb743c02014-06-19 07:40:35 -0700878 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700879 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700880
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700881 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700882 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700883
884 // Parse precision.
885 if (*s == '.') {
886 ++s;
887 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700888 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700889 } else if (*s == '*') {
890 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700891 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700892 }
893 }
894
Victor Zverovich56fc5252014-08-28 07:48:55 -0700895 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700896 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700897 spec.flags_ &= ~HASH_FLAG;
898 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700899 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700900 spec.align_ = ALIGN_NUMERIC;
901 else
902 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700903 }
904
Victor Zverovichf4156b52014-07-30 08:39:07 -0700905 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700906 switch (*s++) {
907 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700908 if (*s == 'h')
909 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700910 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700911 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700912 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700913 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700914 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700915 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700916 else
917 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700918 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700919 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700920 ArgConverter<intmax_t>(arg, *s).visit(arg);
921 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700922 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700923 ArgConverter<size_t>(arg, *s).visit(arg);
924 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700925 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700926 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
927 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700928 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700929 // printf produces garbage when 'L' is omitted for long double, no
930 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700931 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700932 default:
933 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700934 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700935 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700936
937 // Parse type.
938 if (!*s)
939 throw FormatError("invalid format string");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700940 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700941 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
942 // Normalize type.
943 switch (spec.type_) {
944 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700945 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700946 break;
947 case 'c':
948 // TODO: handle wchar_t
949 CharConverter(arg).visit(arg);
950 break;
951 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700952 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700953
954 start = s;
955
956 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700957 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700958 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700959 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700960 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700961 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700962 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700963 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700964 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700965 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700966 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700967 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700968 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700969 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700970 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700971 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700972 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700973 typedef typename BasicWriter<Char>::CharPtr CharPtr;
974 CharPtr out = CharPtr();
975 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700976 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700977 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700978 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700979 std::fill_n(out, spec.width_ - 1, fill);
980 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700981 } else {
982 std::fill_n(out + 1, spec.width_ - 1, fill);
983 }
984 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700985 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700986 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700987 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700988 break;
989 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700990 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700991 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700992 break;
993 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700994 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700995 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700996 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700997 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700998 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700999 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -07001000 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001001 break;
1002 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001003 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -07001004 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001005 spec.flags_= HASH_FLAG;
1006 spec.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -07001007 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001008 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001009 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001010 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -07001011 internal::report_unknown_type(spec.type_, "object");
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001012 const void *s = "s";
1013 arg.custom.format(&writer, arg.custom.value, &s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001014 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001015 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001016 default:
1017 assert(false);
1018 break;
1019 }
1020 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001021 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001022}
1023
1024template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001025const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001026 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001027 const Char *s = format_str;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001028 const char *error = 0;
Victor Zveroviche8251562014-07-08 16:20:33 -07001029 FormatSpec spec;
1030 if (*s == ':') {
1031 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001032 arg.custom.format(this, arg.custom.value, &s);
1033 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001034 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001035 ++s;
1036 // Parse fill and alignment.
1037 if (Char c = *s) {
1038 const Char *p = s + 1;
1039 spec.align_ = ALIGN_DEFAULT;
1040 do {
1041 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001042 case '<':
1043 spec.align_ = ALIGN_LEFT;
1044 break;
1045 case '>':
1046 spec.align_ = ALIGN_RIGHT;
1047 break;
1048 case '=':
1049 spec.align_ = ALIGN_NUMERIC;
1050 break;
1051 case '^':
1052 spec.align_ = ALIGN_CENTER;
1053 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001054 }
1055 if (spec.align_ != ALIGN_DEFAULT) {
1056 if (p != s) {
1057 if (c == '}') break;
1058 if (c == '{')
Victor Zverovich42de4f12014-08-27 08:24:31 -07001059 throw FormatError("invalid fill character '{'");
Victor Zveroviche8251562014-07-08 16:20:33 -07001060 s += 2;
1061 spec.fill_ = c;
1062 } else ++s;
1063 if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zverovich42de4f12014-08-27 08:24:31 -07001064 throw FormatError("format specifier '=' requires numeric argument");
Victor Zveroviche8251562014-07-08 16:20:33 -07001065 break;
1066 }
1067 } while (--p >= s);
1068 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001069
Victor Zveroviche8251562014-07-08 16:20:33 -07001070 // Parse sign.
1071 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001072 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001073 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001074 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1075 break;
1076 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001077 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001078 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001079 break;
1080 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001081 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001082 spec.flags_ |= SIGN_FLAG;
1083 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001084 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001085
Victor Zveroviche8251562014-07-08 16:20:33 -07001086 if (*s == '#') {
1087 if (arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zverovich42de4f12014-08-27 08:24:31 -07001088 // TODO: make FormatError accept arguments
1089 throw FormatError("format specifier '#' requires numeric argument");
Victor Zveroviche8251562014-07-08 16:20:33 -07001090 spec.flags_ |= HASH_FLAG;
1091 ++s;
1092 }
1093
1094 // Parse width and zero flag.
1095 if ('0' <= *s && *s <= '9') {
1096 if (*s == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001097 if (arg.type > Arg::LAST_NUMERIC_TYPE)
Victor Zverovich42de4f12014-08-27 08:24:31 -07001098 throw FormatError("format specifier '0' requires numeric argument");
Victor Zveroviche8251562014-07-08 16:20:33 -07001099 spec.align_ = ALIGN_NUMERIC;
1100 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -07001101 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001102 // Zero may be parsed again as a part of the width, but it is simpler
1103 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001104 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001105 if (error)
Victor Zverovich42de4f12014-08-27 08:24:31 -07001106 throw FormatError(error);
Victor Zveroviche8251562014-07-08 16:20:33 -07001107 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001108
Victor Zveroviche8251562014-07-08 16:20:33 -07001109 // Parse precision.
1110 if (*s == '.') {
1111 ++s;
1112 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001113 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001114 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001115 if (error)
Victor Zverovich42de4f12014-08-27 08:24:31 -07001116 throw FormatError(error);
Victor Zveroviche8251562014-07-08 16:20:33 -07001117 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001118 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001119 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001120 if (*s++ != '}')
1121 throw FormatError("unmatched '{' in format");
Victor Zveroviche8251562014-07-08 16:20:33 -07001122 ULongLong value = 0;
1123 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001124 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001125 if (precision_arg.int_value < 0)
Victor Zverovich42de4f12014-08-27 08:24:31 -07001126 throw FormatError("negative precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001127 value = precision_arg.int_value;
1128 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001129 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001130 value = precision_arg.uint_value;
1131 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001132 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001133 if (precision_arg.long_long_value < 0)
Victor Zverovich42de4f12014-08-27 08:24:31 -07001134 throw FormatError("negative precision in format");
Victor Zverovich56f12b72013-11-22 07:45:43 -08001135 value = precision_arg.long_long_value;
1136 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001137 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001138 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001139 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001140 default:
Victor Zverovich42de4f12014-08-27 08:24:31 -07001141 throw FormatError("precision is not integer");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001142 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001143 if (value > INT_MAX)
Victor Zverovich279c7a62014-08-28 06:50:52 -07001144 throw FormatError("number is too big");
Victor Zveroviche8251562014-07-08 16:20:33 -07001145 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001146 } else {
Victor Zverovich42de4f12014-08-27 08:24:31 -07001147 throw FormatError("missing precision in format");
Victor Zverovich7cae7632013-09-06 20:23:42 -07001148 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001149 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
Victor Zverovich42de4f12014-08-27 08:24:31 -07001150 throw FormatError(
Victor Zveroviche8251562014-07-08 16:20:33 -07001151 "precision specifier requires floating-point argument");
1152 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001153 }
1154
Victor Zveroviche8251562014-07-08 16:20:33 -07001155 // Parse type.
1156 if (*s != '}' && *s)
1157 spec.type_ = static_cast<char>(*s++);
1158 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001159
Victor Zveroviche8251562014-07-08 16:20:33 -07001160 if (*s++ != '}')
1161 throw FormatError("unmatched '{' in format");
1162 start_ = s;
1163
1164 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001165 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001166 return s;
1167}
1168
1169template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001170void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001171 BasicStringRef<Char> format_str, const ArgList &args) {
1172 const Char *s = start_ = format_str.c_str();
1173 args_ = args;
1174 next_arg_index_ = 0;
1175 while (*s) {
1176 Char c = *s++;
1177 if (c != '{' && c != '}') continue;
1178 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001179 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001180 start_ = ++s;
1181 continue;
1182 }
1183 if (c == '}')
1184 throw FormatError("unmatched '}' in format");
Victor Zverovichc1db2932014-07-24 08:53:27 -07001185 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001186 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001187 s = format(s, arg);
1188 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001189 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001190}
1191
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001192void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001193 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich75b5eb42014-07-27 15:09:05 -07001194 // FIXME: format_system_error may throw
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001195 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001196}
1197
Victor Zverovich400812a2014-04-30 12:38:17 -07001198#ifdef _WIN32
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001199void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001200 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich75b5eb42014-07-27 15:09:05 -07001201 // FIXME: format_windows_error may throw
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001202 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001203}
Victor Zverovich400812a2014-04-30 12:38:17 -07001204#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001205
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001206void fmt::print(std::FILE *f, StringRef format_str, const ArgList &args) {
Victor Zverovich2e039632014-06-28 19:44:39 -07001207 Writer w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001208 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001209 std::fwrite(w.data(), 1, w.size(), f);
1210}
1211
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001212void fmt::print(std::ostream &os, StringRef format_str, const ArgList &args) {
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001213 Writer w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001214 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001215 os.write(w.data(), w.size());
1216}
1217
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001218void fmt::print_colored(Color c, StringRef format, const ArgList &args) {
1219 char escape[] = "\x1b[30m";
1220 escape[3] = '0' + static_cast<char>(c);
1221 std::fputs(escape, stdout);
1222 print(format, args);
1223 std::fputs(RESET_COLOR, stdout);
1224}
1225
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001226int fmt::fprintf(std::FILE *f, StringRef format, const ArgList &args) {
Victor Zverovichd5b81962014-06-28 21:56:40 -07001227 Writer w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001228 printf(w, format, args);
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001229 return std::fwrite(w.data(), 1, w.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001230}
1231
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001232// Explicit instantiations for char.
1233
Victor Zverovich93e41252013-09-08 13:07:04 -07001234template fmt::BasicWriter<char>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001235 fmt::BasicWriter<char>::fill_padding(CharPtr buffer,
Victor Zverovich93e41252013-09-08 13:07:04 -07001236 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001237
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001238template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001239 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001240
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001241template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001242 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001243
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001244// Explicit instantiations for wchar_t.
1245
Victor Zverovich7cae7632013-09-06 20:23:42 -07001246template fmt::BasicWriter<wchar_t>::CharPtr
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001247 fmt::BasicWriter<wchar_t>::fill_padding(CharPtr buffer,
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001248 unsigned total_size, std::size_t content_size, wchar_t fill);
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001249
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001250template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001251 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001252
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001253template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001254 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001255 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001256
1257#if _MSC_VER
1258# pragma warning(pop)
1259#endif