blob: 92291c1b03738aea35b44d4383e39071eb2b07c0 [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 Zverovich7c0a2332015-03-03 21:04:45 -08004 Copyright (c) 2012 - 2015, 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 Zverovichfbfedcf2013-01-14 15:16:20 -080028#include "format.h"
29
Victor Zverovich859a4972014-04-30 06:55:21 -070030#include <string.h>
31
Victor Zverovich72f896d2012-12-12 09:17:28 -080032#include <cctype>
Victor Zverovich5d15bdd2014-07-01 16:23:50 -070033#include <cerrno>
Victor Zverovichf28645f2014-04-24 12:37:06 -070034#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070035#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080036#include <cstdarg>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070037
Ryuuke5a9dc8f2015-02-08 16:08:29 +000038#ifdef _WIN32
Ryuuke5a9dc8f2015-02-08 16:08:29 +000039# ifdef __MINGW32__
40# include <cstring>
41# endif
vitaut67ce3942015-04-30 07:48:36 -070042# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
43# include <windows.h>
44# else
45# define NOMINMAX
46# include <windows.h>
47# undef NOMINMAX
48# endif
Ryuuke5a9dc8f2015-02-08 16:08:29 +000049#endif
50
Victor Zverovich6e5551e2014-07-02 06:33:25 -070051using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080052
Victor Zverovich8b76e972014-10-06 08:30:55 -070053// Check if exceptions are disabled.
54#if __GNUC__ && !__EXCEPTIONS
55# define FMT_EXCEPTIONS 0
56#endif
57#if _MSC_VER && !_HAS_EXCEPTIONS
58# define FMT_EXCEPTIONS 0
59#endif
60#ifndef FMT_EXCEPTIONS
61# define FMT_EXCEPTIONS 1
62#endif
63
64#if FMT_EXCEPTIONS
65# define FMT_TRY try
66# define FMT_CATCH(x) catch (x)
67#else
68# define FMT_TRY if (true)
69# define FMT_CATCH(x) if (false)
70#endif
71
72#ifndef FMT_THROW
73# if FMT_EXCEPTIONS
74# define FMT_THROW(x) throw x
75# else
vitaut66915782015-03-25 07:24:26 -070076# define FMT_THROW(x) assert(false)
Victor Zverovich8b76e972014-10-06 08:30:55 -070077# endif
78#endif
79
Victor Zverovichd9c605c2014-11-28 06:40:57 -080080#ifdef FMT_HEADER_ONLY
81# define FMT_FUNC inline
Victor Zverovichc2a69032014-11-28 15:30:03 -080082#else
83# define FMT_FUNC
Victor Zverovichd9c605c2014-11-28 06:40:57 -080084#endif
85
jdale88a9862fd2014-03-11 18:56:24 +000086#if _MSC_VER
87# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070088# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050089# pragma warning(disable: 4702) // unreachable code
vitautdf47d812015-03-16 18:53:14 -070090// Disable deprecation warning for strerror. The latter is not called but
91// MSVC fails to detect it.
92# pragma warning(disable: 4996)
jdale88a9862fd2014-03-11 18:56:24 +000093#endif
94
vitaut341b98c2015-03-14 13:39:33 -070095// Dummy implementations of strerror_r and strerror_s called if corresponding
96// system functions are not available.
vitaut4825fb42015-03-16 08:43:33 -070097static inline fmt::internal::None<> strerror_r(int, char *, ...) {
98 return fmt::internal::None<>();
vitaut341b98c2015-03-14 13:39:33 -070099}
vitaut4825fb42015-03-16 08:43:33 -0700100static inline fmt::internal::None<> strerror_s(char *, std::size_t, ...) {
101 return fmt::internal::None<>();
vitaut341b98c2015-03-14 13:39:33 -0700102}
103
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700104namespace {
105
106#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700107# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -0800108#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -0700109inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -0800110 va_list args;
111 va_start(args, format);
112 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
113 va_end(args);
114 return result;
115}
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700116# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700117#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800118
cstamford55836ca2015-03-10 07:04:31 +0000119#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
120# define FMT_SWPRINTF snwprintf
121#else
122# define FMT_SWPRINTF swprintf
123#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
124
Victor Zverovichadce0242014-08-17 07:53:55 -0700125// Checks if a value fits in int - used to avoid warnings about comparing
126// signed and unsigned integers.
127template <bool IsSigned>
128struct IntChecker {
129 template <typename T>
130 static bool fits_in_int(T value) {
131 unsigned max = INT_MAX;
132 return value <= max;
133 }
134};
135
136template <>
137struct IntChecker<true> {
138 template <typename T>
139 static bool fits_in_int(T value) {
140 return value >= INT_MIN && value <= INT_MAX;
141 }
142};
143
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800144const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700145
Victor Zverovich22f75d82014-09-03 08:03:05 -0700146typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
147
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700148// Portable thread-safe version of strerror.
149// Sets buffer to point to a string describing the error code.
150// This can be either a pointer to a string stored in buffer,
151// or a pointer to some static immutable string.
152// Returns one of the following values:
153// 0 - success
154// ERANGE - buffer is not large enough to store the error message
155// other - failure
156// Buffer should be at least of size 1.
157int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800158 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700159 assert(buffer != 0 && buffer_size != 0);
vitaut341b98c2015-03-14 13:39:33 -0700160
vitaut341b98c2015-03-14 13:39:33 -0700161 class StrError {
162 private:
163 int error_code_;
164 char *&buffer_;
165 std::size_t buffer_size_;
166
vitautda052ae2015-03-21 07:53:39 -0700167 // A noop assignment operator to avoid bogus warnings.
168 void operator=(const StrError &) {}
169
vitaut341b98c2015-03-14 13:39:33 -0700170 // Handle the result of XSI-compliant version of strerror_r.
171 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700172 // glibc versions before 2.13 return result in errno.
173 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700174 }
175
176 // Handle the result of GNU-specific version of strerror_r.
177 int handle(char *message) {
178 // If the buffer is full then the message is probably truncated.
179 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
180 return ERANGE;
181 buffer_ = message;
182 return 0;
183 }
184
185 // Handle the case when strerror_r is not available.
vitaut4825fb42015-03-16 08:43:33 -0700186 int handle(fmt::internal::None<>) {
vitaut341b98c2015-03-14 13:39:33 -0700187 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
188 }
189
190 // Fallback to strerror_s when strerror_r is not available.
191 int fallback(int result) {
192 // If the buffer is full then the message is probably truncated.
193 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
194 ERANGE : result;
195 }
196
197 // Fallback to strerror if strerror_r and strerror_s are not available.
vitaut4825fb42015-03-16 08:43:33 -0700198 int fallback(fmt::internal::None<>) {
vitaut341b98c2015-03-14 13:39:33 -0700199 errno = 0;
200 buffer_ = strerror(error_code_);
201 return errno;
202 }
203
204 public:
205 StrError(int error_code, char *&buffer, std::size_t buffer_size)
206 : error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {}
207
208 int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); }
209 };
210 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700211}
212
Victor Zverovich22f75d82014-09-03 08:03:05 -0700213void format_error_code(fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800214 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700215 // Report error code making sure that the output fits into
216 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
217 // bad_alloc.
218 out.clear();
219 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700220 static const char ERROR_STR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700221 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
vitaut1addec92015-03-21 20:16:36 -0700222 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
223 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
224 error_code_size += fmt::internal::count_digits(ec_value);
Victor Zverovich88e0db82014-09-05 08:04:26 -0700225 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700226 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700227 out << ERROR_STR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700228 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
229}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700230
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700231void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800232 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700233 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700234 func(full_message, error_code, message);
235 // Use Writer::data instead of Writer::c_str to avoid potential memory
236 // allocation.
237 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
238 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700239}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700240
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700241// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
242class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
243 public:
244 template <typename T>
245 bool visit_any_int(T value) { return value == 0; }
246};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700247
248// Parses an unsigned integer advancing s to the end of the parsed input.
249// This function assumes that the first character of s is a digit.
250template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700251int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700252 assert('0' <= *s && *s <= '9');
253 unsigned value = 0;
254 do {
255 unsigned new_value = value * 10 + (*s++ - '0');
256 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700257 if (new_value < value) {
258 value = UINT_MAX;
259 break;
260 }
261 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700262 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700263 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700264 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700265 return value;
266}
Victor Zveroviche8251562014-07-08 16:20:33 -0700267
jamboree7487bde2015-06-10 09:32:59 +0800268template <typename Char>
269inline bool is_name_start(Char c) {
270 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
271}
272
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700273inline void require_numeric_argument(const Arg &arg, char spec) {
274 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700275 std::string message =
276 fmt::format("format specifier '{}' requires numeric argument", spec);
277 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700278 }
279}
280
Victor Zveroviche8251562014-07-08 16:20:33 -0700281template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700282void check_sign(const Char *&s, const Arg &arg) {
283 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700284 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700285 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700286 FMT_THROW(fmt::FormatError(fmt::format(
287 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700288 }
289 ++s;
290}
291
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700292// Checks if an argument is a valid printf width specifier and sets
293// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700294class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700295 private:
296 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700297
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800298 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
299
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700300 public:
301 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700302
vitautd4ea2d72015-03-26 08:55:20 -0700303 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700304 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700305 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700306
Victor Zverovich9d74f952014-07-16 07:27:54 -0700307 template <typename T>
308 unsigned visit_any_int(T value) {
309 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
310 UnsignedType width = value;
311 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700312 spec_.align_ = fmt::ALIGN_LEFT;
313 width = 0 - width;
314 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700315 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700316 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700317 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700318 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700319};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700320
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700321class PrecisionHandler :
322 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
323 public:
vitautd4ea2d72015-03-26 08:55:20 -0700324 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700325 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700326 }
327
328 template <typename T>
329 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700330 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700331 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700332 return static_cast<int>(value);
333 }
334};
335
Victor Zverovich32344d92014-08-28 08:11:21 -0700336// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700337template <typename T>
338class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
339 private:
340 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700341 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700342
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800343 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
344
Victor Zverovicheeca2232014-07-30 07:37:16 -0700345 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700346 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
347 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700348
349 template <typename U>
350 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700351 bool is_signed = type_ == 'd' || type_ == 'i';
352 using fmt::internal::Arg;
353 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700354 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700355 if (is_signed) {
356 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700357 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700358 } else {
359 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700360 arg_.uint_value = static_cast<unsigned>(
361 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700362 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700363 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700364 if (is_signed) {
365 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700366 arg_.long_long_value =
367 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700368 } else {
369 arg_.type = Arg::ULONG_LONG;
370 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700371 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700372 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700373 }
374 }
375};
376
Victor Zverovich32344d92014-08-28 08:11:21 -0700377// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700378class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
379 private:
380 fmt::internal::Arg &arg_;
381
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800382 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
383
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700384 public:
385 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
386
387 template <typename T>
388 void visit_any_int(T value) {
389 arg_.type = Arg::CHAR;
390 arg_.int_value = static_cast<char>(value);
391 }
392};
393
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700394// This function template is used to prevent compile errors when handling
395// incompatible string arguments, e.g. handling a wide string in a narrow
396// string formatter.
397template <typename Char>
398Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
399
400template <>
401inline Arg::StringValue<char> ignore_incompatible_str(
402 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
403
404template <>
405inline Arg::StringValue<wchar_t> ignore_incompatible_str(
406 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700407} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700408
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800409FMT_FUNC void fmt::SystemError::init(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800410 int err_code, StringRef format_str, ArgList args) {
411 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700412 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800413 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700414 std::runtime_error &base = *this;
415 base = std::runtime_error(w.str());
416}
417
Victor Zverovichb605b392013-09-09 22:21:40 -0700418template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700419int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700420 char *buffer, std::size_t size, const char *format,
421 unsigned width, int precision, T value) {
422 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700423 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700424 FMT_SNPRINTF(buffer, size, format, value) :
425 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700426 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700427 return precision < 0 ?
428 FMT_SNPRINTF(buffer, size, format, width, value) :
429 FMT_SNPRINTF(buffer, size, format, width, precision, value);
430}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700431
Victor Zverovichb605b392013-09-09 22:21:40 -0700432template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700433int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700434 wchar_t *buffer, std::size_t size, const wchar_t *format,
435 unsigned width, int precision, T value) {
436 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700437 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000438 FMT_SWPRINTF(buffer, size, format, value) :
439 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700440 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700441 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000442 FMT_SWPRINTF(buffer, size, format, width, value) :
443 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700444}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800445
Victor Zverovich311251e2014-11-29 06:58:00 -0800446template <typename T>
447const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800448 "0001020304050607080910111213141516171819"
449 "2021222324252627282930313233343536373839"
450 "4041424344454647484950515253545556575859"
451 "6061626364656667686970717273747576777879"
452 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800453
Victor Zverovichf1d85162014-02-19 13:02:22 -0800454#define FMT_POWERS_OF_10(factor) \
455 factor * 10, \
456 factor * 100, \
457 factor * 1000, \
458 factor * 10000, \
459 factor * 100000, \
460 factor * 1000000, \
461 factor * 10000000, \
462 factor * 100000000, \
463 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800464
Victor Zverovich311251e2014-11-29 06:58:00 -0800465template <typename T>
466const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
467 0, FMT_POWERS_OF_10(1)
468};
469
470template <typename T>
471const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800472 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800473 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800474 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700475 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800476 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800477 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800478};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800479
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800480FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800481 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800482 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700483 FMT_THROW(fmt::FormatError(
484 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800485 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700486 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700487 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700488 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800489}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700490
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700491#ifdef _WIN32
492
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800493FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700494 int length = MultiByteToWideChar(
495 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
Victor Zverovichdff21372014-12-16 07:01:01 -0800496 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700497 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800498 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700499 buffer_.resize(length);
500 length = MultiByteToWideChar(
501 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
502 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800503 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700504}
505
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800506FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700507 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700508 FMT_THROW(WindowsError(error_code,
509 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700510 }
511}
512
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800513FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700514 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
515 if (length == 0)
516 return GetLastError();
517 buffer_.resize(length);
518 length = WideCharToMultiByte(
519 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
520 if (length == 0)
521 return GetLastError();
522 return 0;
523}
524
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800525FMT_FUNC void fmt::WindowsError::init(
Carter Li3f574c12015-02-17 10:11:42 +0800526 int err_code, StringRef format_str, ArgList args) {
527 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700528 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800529 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700530 std::runtime_error &base = *this;
531 base = std::runtime_error(w.str());
532}
533
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700534#endif
535
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800536FMT_FUNC void fmt::internal::format_system_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700537 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800538 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700539 FMT_TRY {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700540 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700541 buffer.resize(INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700542 for (;;) {
Victor Zverovichaca49372014-11-24 07:38:26 -0800543 char *system_message = &buffer[0];
Victor Zverovich22f75d82014-09-03 08:03:05 -0700544 int result = safe_strerror(error_code, system_message, buffer.size());
545 if (result == 0) {
546 out << message << ": " << system_message;
547 return;
548 }
549 if (result != ERANGE)
550 break; // Can't get error message, report error code instead.
551 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700552 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700553 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700554 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700555}
556
557#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800558FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700559 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800560 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700561 class String {
562 private:
563 LPWSTR str_;
564
565 public:
566 String() : str_() {}
567 ~String() { LocalFree(str_); }
568 LPWSTR *ptr() { return &str_; }
569 LPCWSTR c_str() const { return str_; }
570 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700571 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700572 String system_message;
573 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
574 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
575 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
576 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
577 UTF16ToUTF8 utf8_message;
578 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
579 out << message << ": " << utf8_message;
580 return;
581 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700582 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700583 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700584 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700585}
586#endif
587
jamboree7487bde2015-06-10 09:32:59 +0800588template <typename Char>
vitauta98583d2015-06-10 08:49:22 -0700589void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800590 if (!map_.empty())
591 return;
vitauta98583d2015-06-10 08:49:22 -0700592 typedef internal::NamedArg<Char> NamedArg;
593 const NamedArg* named_arg = 0;
594 bool use_values =
595 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800596 if (use_values) {
597 for (unsigned i = 0;/*nothing*/; ++i) {
598 internal::Arg::Type arg_type = args.type(i);
599 switch (arg_type) {
600 case internal::Arg::NONE:
601 return;
602 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700603 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800604 map_.insert(Pair(named_arg->name, *named_arg));
605 break;
606 default:
607 /*nothing*/;
608 }
609 }
610 return;
611 }
vitauta98583d2015-06-10 08:49:22 -0700612 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800613 internal::Arg::Type arg_type = args.type(i);
614 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700615 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800616 map_.insert(Pair(named_arg->name, *named_arg));
617 }
618 }
vitauta98583d2015-06-10 08:49:22 -0700619 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800620 switch (args.args_[i].type) {
621 case internal::Arg::NONE:
622 return;
623 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700624 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800625 map_.insert(Pair(named_arg->name, *named_arg));
626 break;
627 default:
628 /*nothing*/;
629 }
630 }
631}
632
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700633// An argument formatter.
634template <typename Char>
635class fmt::internal::ArgFormatter :
636 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
637 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700638 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700639 fmt::BasicWriter<Char> &writer_;
640 fmt::FormatSpec &spec_;
641 const Char *format_;
642
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800643 FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
644
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700645 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700646 ArgFormatter(
647 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700648 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700649
Victor Zverovich9d74f952014-07-16 07:27:54 -0700650 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700651 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700652
653 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700654 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700655
656 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700657 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700658 spec_.flags_ |= CHAR_FLAG;
659 writer_.write_int(value, spec_);
660 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700661 }
662 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700663 FMT_THROW(FormatError("invalid format specifier for char"));
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700664 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
Victor Zverovich43aebf52015-01-08 07:56:08 -0800665 Char fill = static_cast<Char>(spec_.fill());
666 if (spec_.precision_ == 0) {
667 std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
668 return;
669 }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700670 CharPtr out = CharPtr();
671 if (spec_.width_ > 1) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700672 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700673 if (spec_.align_ == fmt::ALIGN_RIGHT) {
674 std::fill_n(out, spec_.width_ - 1, fill);
675 out += spec_.width_ - 1;
676 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700677 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700678 } else {
679 std::fill_n(out + 1, spec_.width_ - 1, fill);
680 }
681 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700682 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700683 }
684 *out = static_cast<Char>(value);
685 }
686
687 void visit_string(Arg::StringValue<char> value) {
688 writer_.write_str(value, spec_);
689 }
690 void visit_wstring(Arg::StringValue<wchar_t> value) {
691 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
692 }
693
694 void visit_pointer(const void *value) {
695 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700696 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700697 spec_.flags_ = fmt::HASH_FLAG;
698 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700699 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700700 }
701
702 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700703 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700704 }
705};
706
Victor Zverovichd1ded562014-09-29 08:48:16 -0700707template <typename Char>
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800708void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
709 FMT_THROW(std::runtime_error("buffer overflow"));
710}
711
712template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700713template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700714void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800715 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700716 // Check if StrChar is convertible to Char.
717 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700718 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700719 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800720 const StrChar *str_value = s.value;
721 std::size_t str_size = s.size;
722 if (str_size == 0) {
723 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700724 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800725 if (*str_value)
726 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700727 }
Victor Zverovich59254412015-02-06 07:27:19 -0800728 std::size_t precision = spec.precision_;
729 if (spec.precision_ >= 0 && precision < str_size)
Victor Zverovich43aebf52015-01-08 07:56:08 -0800730 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800731 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700732}
733
734template <typename Char>
jamboree7487bde2015-06-10 09:32:59 +0800735inline Arg fmt::BasicFormatter<Char>::get_arg(
736 const BasicStringRef<Char>& arg_name, const char *&error) {
737 if (check_no_auto_index(error)) {
738 next_arg_index_ = -1;
739 map_.init(args_);
740 const Arg* arg = map_.find(arg_name);
741 if (arg)
742 return *arg;
743 error = "argument not found";
744 }
745 return Arg();
746}
747
748template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700749inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700750 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700751 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700752 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700753 if (error) {
754 FMT_THROW(FormatError(
755 *s != '}' && *s != ':' ? "invalid format string" : error));
756 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700757 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700758}
759
jamboree7487bde2015-06-10 09:32:59 +0800760template <typename Char>
761inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
762 assert(is_name_start(*s));
763 const Char *start = s;
764 Char c;
765 do {
766 c = *++s;
jamboree3c99ed42015-06-11 12:03:22 +0800767 } while (is_name_start(c) || ('0' <= c && c <= '9'));
jamboree7487bde2015-06-10 09:32:59 +0800768 const char *error = 0;
769 Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
770 if (error)
771 FMT_THROW(fmt::FormatError(error));
772 return arg;
773}
774
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800775FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700776 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700777 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800778 switch (arg.type) {
779 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700780 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800781 break;
782 case Arg::NAMED_ARG:
783 arg = *static_cast<const internal::Arg*>(arg.pointer);
784 default:
785 /*nothing*/;
786 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700787 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700788}
789
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700790inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700791 if (next_arg_index_ >= 0)
792 return do_get_arg(next_arg_index_++, error);
793 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700794 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700795}
796
jamboree7487bde2015-06-10 09:32:59 +0800797inline bool fmt::internal::FormatterBase::check_no_auto_index(const char *&error) {
798 if (next_arg_index_ > 0) {
799 error = "cannot switch from automatic to manual argument indexing";
800 return false;
801 }
802 return true;
803}
804
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700805inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700806 unsigned arg_index, const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800807 if (check_no_auto_index(error)) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700808 next_arg_index_ = -1;
809 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700810 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700811 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700812}
813
Victor Zverovich7cae7632013-09-06 20:23:42 -0700814template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700815void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700816 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700817 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700818 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700819 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700820 spec.align_ = ALIGN_LEFT;
821 break;
822 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700823 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
824 break;
825 case '0':
826 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700827 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700828 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700829 spec.flags_ |= SIGN_FLAG;
830 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700831 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700832 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700833 break;
834 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700835 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700836 return;
837 }
838 }
839}
840
Victor Zverovichcb743c02014-06-19 07:40:35 -0700841template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700842Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700843 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800844 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700845 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700846 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700847 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
848 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700849 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700850 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700851}
852
853template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700854unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700855 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700856 unsigned arg_index = UINT_MAX;
857 Char c = *s;
858 if (c >= '0' && c <= '9') {
859 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700860 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700861 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700862 if (*s == '$') { // value is an argument index
863 ++s;
864 arg_index = value;
865 } else {
866 if (c == '0')
867 spec.fill_ = '0';
868 if (value != 0) {
869 // Nonzero value means that we parsed width and don't need to
870 // parse it or flags again, so return now.
871 spec.width_ = value;
872 return arg_index;
873 }
874 }
875 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700876 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700877 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700878 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700879 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700880 } else if (*s == '*') {
881 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700882 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700883 }
884 return arg_index;
885}
886
Victor Zverovich1f19b982014-06-16 07:49:30 -0700887template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700888void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800889 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700890 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800891 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700892 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700893 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700894 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700895 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700896 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700897 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700898 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700899 start = ++s;
900 continue;
901 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700902 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700903
Victor Zverovichcb743c02014-06-19 07:40:35 -0700904 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700905 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700906
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700907 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700908 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700909
910 // Parse precision.
911 if (*s == '.') {
912 ++s;
913 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700914 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700915 } else if (*s == '*') {
916 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700917 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700918 }
919 }
920
Victor Zverovich56fc5252014-08-28 07:48:55 -0700921 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700922 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700923 spec.flags_ &= ~HASH_FLAG;
924 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700925 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700926 spec.align_ = ALIGN_NUMERIC;
927 else
928 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700929 }
930
Victor Zverovichf4156b52014-07-30 08:39:07 -0700931 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700932 switch (*s++) {
933 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700934 if (*s == 'h')
935 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700936 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700937 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700938 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700939 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700940 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700941 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700942 else
943 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700944 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700945 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700946 ArgConverter<intmax_t>(arg, *s).visit(arg);
947 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700948 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700949 ArgConverter<size_t>(arg, *s).visit(arg);
950 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700951 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700952 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
953 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700954 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700955 // printf produces garbage when 'L' is omitted for long double, no
956 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700957 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700958 default:
959 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700960 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700961 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700962
963 // Parse type.
964 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700965 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700966 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700967 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
968 // Normalize type.
969 switch (spec.type_) {
970 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700971 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700972 break;
973 case 'c':
974 // TODO: handle wchar_t
975 CharConverter(arg).visit(arg);
976 break;
977 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700978 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700979
980 start = s;
981
982 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700983 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700984 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700985 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700986 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700987 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700988 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700989 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700990 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700991 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700992 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700993 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700994 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700995 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700996 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700997 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700998 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700999 typedef typename BasicWriter<Char>::CharPtr CharPtr;
1000 CharPtr out = CharPtr();
1001 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001002 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001003 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001004 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001005 std::fill_n(out, spec.width_ - 1, fill);
1006 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001007 } else {
1008 std::fill_n(out + 1, spec.width_ - 1, fill);
1009 }
1010 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001011 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001012 }
Victor Zverovichcb743c02014-06-19 07:40:35 -07001013 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001014 break;
1015 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001016 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -07001017 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001018 break;
1019 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -07001020 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001021 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -07001022 case Arg::CSTRING:
1023 arg.string.size = 0;
1024 writer.write_str(arg.string, spec);
1025 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001026 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -07001027 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001028 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001029 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -07001030 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001031 break;
1032 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001033 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -07001034 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001035 spec.flags_= HASH_FLAG;
1036 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -07001037 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001038 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001039 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001040 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -07001041 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -08001042 const void *str_format = "s";
1043 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001044 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001045 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001046 default:
1047 assert(false);
1048 break;
1049 }
1050 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001051 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001052}
1053
1054template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001055const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001056 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001057 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -07001058 FormatSpec spec;
1059 if (*s == ':') {
1060 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001061 arg.custom.format(this, arg.custom.value, &s);
1062 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001063 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001064 ++s;
1065 // Parse fill and alignment.
1066 if (Char c = *s) {
1067 const Char *p = s + 1;
1068 spec.align_ = ALIGN_DEFAULT;
1069 do {
1070 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001071 case '<':
1072 spec.align_ = ALIGN_LEFT;
1073 break;
1074 case '>':
1075 spec.align_ = ALIGN_RIGHT;
1076 break;
1077 case '=':
1078 spec.align_ = ALIGN_NUMERIC;
1079 break;
1080 case '^':
1081 spec.align_ = ALIGN_CENTER;
1082 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001083 }
1084 if (spec.align_ != ALIGN_DEFAULT) {
1085 if (p != s) {
1086 if (c == '}') break;
1087 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001088 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001089 s += 2;
1090 spec.fill_ = c;
1091 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001092 if (spec.align_ == ALIGN_NUMERIC)
1093 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -07001094 break;
1095 }
1096 } while (--p >= s);
1097 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001098
Victor Zveroviche8251562014-07-08 16:20:33 -07001099 // Parse sign.
1100 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001101 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001102 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001103 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1104 break;
1105 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001106 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001107 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001108 break;
1109 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001110 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001111 spec.flags_ |= SIGN_FLAG;
1112 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001113 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001114
Victor Zveroviche8251562014-07-08 16:20:33 -07001115 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001116 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -07001117 spec.flags_ |= HASH_FLAG;
1118 ++s;
1119 }
1120
jamboree54a6cb32015-06-04 13:59:37 +08001121 // Parse zero flag.
1122 if (*s == '0') {
vitaut8949a2e2015-06-08 06:53:18 -07001123 require_numeric_argument(arg, '0');
1124 spec.align_ = ALIGN_NUMERIC;
1125 spec.fill_ = '0';
1126 ++s;
jamboree54a6cb32015-06-04 13:59:37 +08001127 }
1128
1129 // Parse width.
1130 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001131 spec.width_ = parse_nonnegative_int(s);
jamboree54a6cb32015-06-04 13:59:37 +08001132 } else if (*s == '{') {
vitaut8949a2e2015-06-08 06:53:18 -07001133 ++s;
jamboree7487bde2015-06-10 09:32:59 +08001134 const Arg &width_arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
vitaut8949a2e2015-06-08 06:53:18 -07001135 if (*s++ != '}')
1136 FMT_THROW(FormatError("invalid format string"));
1137 ULongLong value = 0;
1138 switch (width_arg.type) {
1139 case Arg::INT:
1140 if (width_arg.int_value < 0)
1141 FMT_THROW(FormatError("negative width"));
1142 value = width_arg.int_value;
1143 break;
1144 case Arg::UINT:
1145 value = width_arg.uint_value;
1146 break;
1147 case Arg::LONG_LONG:
1148 if (width_arg.long_long_value < 0)
1149 FMT_THROW(FormatError("negative width"));
1150 value = width_arg.long_long_value;
1151 break;
1152 case Arg::ULONG_LONG:
1153 value = width_arg.ulong_long_value;
1154 break;
1155 default:
1156 FMT_THROW(FormatError("width is not integer"));
1157 }
1158 if (value > INT_MAX)
1159 FMT_THROW(FormatError("number is too big"));
1160 spec.width_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001161 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001162
Victor Zveroviche8251562014-07-08 16:20:33 -07001163 // Parse precision.
1164 if (*s == '.') {
1165 ++s;
1166 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001167 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001168 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001169 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001170 ++s;
jamboree7487bde2015-06-10 09:32:59 +08001171 const Arg &precision_arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001172 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001173 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001174 ULongLong value = 0;
1175 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001176 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001177 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001178 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001179 value = precision_arg.int_value;
1180 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001181 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001182 value = precision_arg.uint_value;
1183 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001184 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001185 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001186 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001187 value = precision_arg.long_long_value;
1188 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001189 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001190 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001191 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001192 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001193 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001194 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001195 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001196 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001197 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001198 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001199 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001200 }
Victor Zverovich43aebf52015-01-08 07:56:08 -08001201 if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001202 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001203 fmt::format("precision not allowed in {} format specifier",
1204 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001205 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001206 }
1207
Victor Zveroviche8251562014-07-08 16:20:33 -07001208 // Parse type.
1209 if (*s != '}' && *s)
1210 spec.type_ = static_cast<char>(*s++);
1211 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001212
Victor Zveroviche8251562014-07-08 16:20:33 -07001213 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001214 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001215 start_ = s;
1216
1217 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001218 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001219 return s;
1220}
1221
1222template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001223void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001224 BasicStringRef<Char> format_str, const ArgList &args) {
1225 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001226 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001227 while (*s) {
1228 Char c = *s++;
1229 if (c != '{' && c != '}') continue;
1230 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001231 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001232 start_ = ++s;
1233 continue;
1234 }
1235 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001236 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001237 write(writer_, start_, s - 1);
jamboree7487bde2015-06-10 09:32:59 +08001238 Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001239 s = format(s, arg);
1240 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001241 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001242}
1243
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001244FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001245 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001246 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001247}
1248
Victor Zverovich400812a2014-04-30 12:38:17 -07001249#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001250FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001251 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001252 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001253}
Victor Zverovich400812a2014-04-30 12:38:17 -07001254#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001255
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001256FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001257 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001258 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001259 std::fwrite(w.data(), 1, w.size(), f);
1260}
1261
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001262FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001263 print(stdout, format_str, args);
1264}
1265
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001266FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001267 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001268 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001269 os.write(w.data(), w.size());
1270}
1271
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001272FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001273 char escape[] = "\x1b[30m";
1274 escape[3] = '0' + static_cast<char>(c);
1275 std::fputs(escape, stdout);
1276 print(format, args);
1277 std::fputs(RESET_COLOR, stdout);
1278}
1279
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001280FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001281 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001282 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001283 std::size_t size = w.size();
1284 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001285}
1286
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001287#ifndef FMT_HEADER_ONLY
1288
vitaut9ca1ce22015-05-23 08:04:06 -07001289template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -07001290
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001291// Explicit instantiations for char.
1292
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001293template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
1294
Victor Zverovichf43caef2014-09-25 07:21:48 -07001295template const char *fmt::BasicFormatter<char>::format(
1296 const char *&format_str, const fmt::internal::Arg &arg);
1297
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001298template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001299 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001300
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001301template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001302 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001303
Victor Zverovich14f25772014-09-19 08:45:05 -07001304template int fmt::internal::CharTraits<char>::format_float(
1305 char *buffer, std::size_t size, const char *format,
1306 unsigned width, int precision, double value);
1307
1308template int fmt::internal::CharTraits<char>::format_float(
1309 char *buffer, std::size_t size, const char *format,
1310 unsigned width, int precision, long double value);
1311
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001312// Explicit instantiations for wchar_t.
1313
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001314template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1315
Victor Zverovichf43caef2014-09-25 07:21:48 -07001316template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1317 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1318
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001319template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001320 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001321
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001322template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001323 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001324 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001325
Victor Zverovich14f25772014-09-19 08:45:05 -07001326template int fmt::internal::CharTraits<wchar_t>::format_float(
1327 wchar_t *buffer, std::size_t size, const wchar_t *format,
1328 unsigned width, int precision, double value);
1329
1330template int fmt::internal::CharTraits<wchar_t>::format_float(
1331 wchar_t *buffer, std::size_t size, const wchar_t *format,
1332 unsigned width, int precision, long double value);
1333
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001334#endif // FMT_HEADER_ONLY
1335
jdale88a9862fd2014-03-11 18:56:24 +00001336#if _MSC_VER
1337# pragma warning(pop)
1338#endif