blob: e8714a33489fa5f65aa39925b92852577f8c589c [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;
vitautfccff7b2015-06-11 07:19:00 -0700593 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700594 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(
vitautfccff7b2015-06-11 07:19:00 -0700736 BasicStringRef<Char> arg_name, const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800737 if (check_no_auto_index(error)) {
vitautfccff7b2015-06-11 07:19:00 -0700738 map_.init(args());
739 const Arg *arg = map_.find(arg_name);
jamboree7487bde2015-06-10 09:32:59 +0800740 if (arg)
741 return *arg;
742 error = "argument not found";
743 }
744 return Arg();
745}
746
747template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700748inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700749 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700750 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700751 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700752 if (error) {
753 FMT_THROW(FormatError(
754 *s != '}' && *s != ':' ? "invalid format string" : error));
755 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700756 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700757}
758
jamboree7487bde2015-06-10 09:32:59 +0800759template <typename Char>
760inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
761 assert(is_name_start(*s));
762 const Char *start = s;
763 Char c;
764 do {
765 c = *++s;
jamboree3c99ed42015-06-11 12:03:22 +0800766 } while (is_name_start(c) || ('0' <= c && c <= '9'));
jamboree7487bde2015-06-10 09:32:59 +0800767 const char *error = 0;
768 Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
769 if (error)
770 FMT_THROW(fmt::FormatError(error));
771 return arg;
772}
773
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800774FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700775 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700776 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800777 switch (arg.type) {
778 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700779 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800780 break;
781 case Arg::NAMED_ARG:
782 arg = *static_cast<const internal::Arg*>(arg.pointer);
783 default:
784 /*nothing*/;
785 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700786 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700787}
788
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700789inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700790 if (next_arg_index_ >= 0)
791 return do_get_arg(next_arg_index_++, error);
792 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700793 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700794}
795
vitautfccff7b2015-06-11 07:19:00 -0700796inline bool fmt::internal::FormatterBase::check_no_auto_index(
797 const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800798 if (next_arg_index_ > 0) {
799 error = "cannot switch from automatic to manual argument indexing";
800 return false;
801 }
vitautfccff7b2015-06-11 07:19:00 -0700802 next_arg_index_ = -1;
jamboree7487bde2015-06-10 09:32:59 +0800803 return true;
804}
805
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700806inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700807 unsigned arg_index, const char *&error) {
vitautfccff7b2015-06-11 07:19:00 -0700808 return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700809}
810
Victor Zverovich7cae7632013-09-06 20:23:42 -0700811template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700812void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700813 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700814 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700815 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700816 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700817 spec.align_ = ALIGN_LEFT;
818 break;
819 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700820 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
821 break;
822 case '0':
823 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700824 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700825 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700826 spec.flags_ |= SIGN_FLAG;
827 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700828 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700829 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700830 break;
831 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700832 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700833 return;
834 }
835 }
836}
837
Victor Zverovichcb743c02014-06-19 07:40:35 -0700838template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700839Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700840 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800841 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700842 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700843 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700844 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
845 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700846 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700847 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700848}
849
850template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700851unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700852 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700853 unsigned arg_index = UINT_MAX;
854 Char c = *s;
855 if (c >= '0' && c <= '9') {
856 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700857 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700858 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700859 if (*s == '$') { // value is an argument index
860 ++s;
861 arg_index = value;
862 } else {
863 if (c == '0')
864 spec.fill_ = '0';
865 if (value != 0) {
866 // Nonzero value means that we parsed width and don't need to
867 // parse it or flags again, so return now.
868 spec.width_ = value;
869 return arg_index;
870 }
871 }
872 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700873 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700874 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700875 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700876 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700877 } else if (*s == '*') {
878 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700879 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700880 }
881 return arg_index;
882}
883
Victor Zverovich1f19b982014-06-16 07:49:30 -0700884template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700885void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800886 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700887 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800888 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700889 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700890 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700891 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700892 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700893 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700894 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700895 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700896 start = ++s;
897 continue;
898 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700899 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700900
Victor Zverovichcb743c02014-06-19 07:40:35 -0700901 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700902 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700903
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700904 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700905 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700906
907 // Parse precision.
908 if (*s == '.') {
909 ++s;
910 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700911 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700912 } else if (*s == '*') {
913 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700914 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700915 }
916 }
917
Victor Zverovich56fc5252014-08-28 07:48:55 -0700918 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700919 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700920 spec.flags_ &= ~HASH_FLAG;
921 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700922 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700923 spec.align_ = ALIGN_NUMERIC;
924 else
925 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700926 }
927
Victor Zverovichf4156b52014-07-30 08:39:07 -0700928 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700929 switch (*s++) {
930 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700931 if (*s == 'h')
932 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700933 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700934 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700935 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700936 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700937 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700938 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700939 else
940 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700941 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700942 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700943 ArgConverter<intmax_t>(arg, *s).visit(arg);
944 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700945 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700946 ArgConverter<size_t>(arg, *s).visit(arg);
947 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700948 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700949 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
950 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700951 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700952 // printf produces garbage when 'L' is omitted for long double, no
953 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700954 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700955 default:
956 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700957 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700958 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700959
960 // Parse type.
961 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700962 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700963 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700964 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
965 // Normalize type.
966 switch (spec.type_) {
967 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700968 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700969 break;
970 case 'c':
971 // TODO: handle wchar_t
972 CharConverter(arg).visit(arg);
973 break;
974 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700975 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700976
977 start = s;
978
979 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700980 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700981 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700982 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700983 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700984 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700985 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700986 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700987 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700988 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700989 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700990 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700991 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700992 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700993 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700994 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700995 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700996 typedef typename BasicWriter<Char>::CharPtr CharPtr;
997 CharPtr out = CharPtr();
998 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700999 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001000 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001001 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001002 std::fill_n(out, spec.width_ - 1, fill);
1003 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001004 } else {
1005 std::fill_n(out + 1, spec.width_ - 1, fill);
1006 }
1007 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001008 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001009 }
Victor Zverovichcb743c02014-06-19 07:40:35 -07001010 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001011 break;
1012 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001013 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -07001014 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001015 break;
1016 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -07001017 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001018 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -07001019 case Arg::CSTRING:
1020 arg.string.size = 0;
1021 writer.write_str(arg.string, spec);
1022 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001023 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -07001024 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001025 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001026 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -07001027 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001028 break;
1029 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001030 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -07001031 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001032 spec.flags_= HASH_FLAG;
1033 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -07001034 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001035 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001036 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001037 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -07001038 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -08001039 const void *str_format = "s";
1040 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001041 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001042 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001043 default:
1044 assert(false);
1045 break;
1046 }
1047 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001048 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001049}
1050
1051template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001052const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001053 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001054 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -07001055 FormatSpec spec;
1056 if (*s == ':') {
1057 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001058 arg.custom.format(this, arg.custom.value, &s);
1059 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001060 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001061 ++s;
1062 // Parse fill and alignment.
1063 if (Char c = *s) {
1064 const Char *p = s + 1;
1065 spec.align_ = ALIGN_DEFAULT;
1066 do {
1067 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001068 case '<':
1069 spec.align_ = ALIGN_LEFT;
1070 break;
1071 case '>':
1072 spec.align_ = ALIGN_RIGHT;
1073 break;
1074 case '=':
1075 spec.align_ = ALIGN_NUMERIC;
1076 break;
1077 case '^':
1078 spec.align_ = ALIGN_CENTER;
1079 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001080 }
1081 if (spec.align_ != ALIGN_DEFAULT) {
1082 if (p != s) {
1083 if (c == '}') break;
1084 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001085 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001086 s += 2;
1087 spec.fill_ = c;
1088 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001089 if (spec.align_ == ALIGN_NUMERIC)
1090 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -07001091 break;
1092 }
1093 } while (--p >= s);
1094 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001095
Victor Zveroviche8251562014-07-08 16:20:33 -07001096 // Parse sign.
1097 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001098 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001099 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001100 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1101 break;
1102 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001103 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001104 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001105 break;
1106 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001107 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001108 spec.flags_ |= SIGN_FLAG;
1109 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001110 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001111
Victor Zveroviche8251562014-07-08 16:20:33 -07001112 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001113 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -07001114 spec.flags_ |= HASH_FLAG;
1115 ++s;
1116 }
1117
jamboree54a6cb32015-06-04 13:59:37 +08001118 // Parse zero flag.
1119 if (*s == '0') {
vitaut8949a2e2015-06-08 06:53:18 -07001120 require_numeric_argument(arg, '0');
1121 spec.align_ = ALIGN_NUMERIC;
1122 spec.fill_ = '0';
1123 ++s;
jamboree54a6cb32015-06-04 13:59:37 +08001124 }
1125
1126 // Parse width.
1127 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001128 spec.width_ = parse_nonnegative_int(s);
jamboree54a6cb32015-06-04 13:59:37 +08001129 } else if (*s == '{') {
vitaut8949a2e2015-06-08 06:53:18 -07001130 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001131 Arg width_arg = is_name_start(*s) ?
1132 parse_arg_name(s) : parse_arg_index(s);
vitaut8949a2e2015-06-08 06:53:18 -07001133 if (*s++ != '}')
1134 FMT_THROW(FormatError("invalid format string"));
1135 ULongLong value = 0;
1136 switch (width_arg.type) {
1137 case Arg::INT:
1138 if (width_arg.int_value < 0)
1139 FMT_THROW(FormatError("negative width"));
1140 value = width_arg.int_value;
1141 break;
1142 case Arg::UINT:
1143 value = width_arg.uint_value;
1144 break;
1145 case Arg::LONG_LONG:
1146 if (width_arg.long_long_value < 0)
1147 FMT_THROW(FormatError("negative width"));
1148 value = width_arg.long_long_value;
1149 break;
1150 case Arg::ULONG_LONG:
1151 value = width_arg.ulong_long_value;
1152 break;
1153 default:
1154 FMT_THROW(FormatError("width is not integer"));
1155 }
1156 if (value > INT_MAX)
1157 FMT_THROW(FormatError("number is too big"));
1158 spec.width_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001159 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001160
Victor Zveroviche8251562014-07-08 16:20:33 -07001161 // Parse precision.
1162 if (*s == '.') {
1163 ++s;
1164 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001165 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001166 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001167 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001168 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001169 Arg precision_arg =
1170 is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001171 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001172 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001173 ULongLong value = 0;
1174 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001175 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001176 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001177 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001178 value = precision_arg.int_value;
1179 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001180 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001181 value = precision_arg.uint_value;
1182 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001183 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001184 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001185 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001186 value = precision_arg.long_long_value;
1187 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001188 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001189 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001190 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001191 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001192 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001193 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001194 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001195 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001196 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001197 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001198 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001199 }
Victor Zverovich43aebf52015-01-08 07:56:08 -08001200 if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001201 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001202 fmt::format("precision not allowed in {} format specifier",
1203 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001204 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001205 }
1206
Victor Zveroviche8251562014-07-08 16:20:33 -07001207 // Parse type.
1208 if (*s != '}' && *s)
1209 spec.type_ = static_cast<char>(*s++);
1210 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001211
Victor Zveroviche8251562014-07-08 16:20:33 -07001212 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001213 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001214 start_ = s;
1215
1216 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001217 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001218 return s;
1219}
1220
1221template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001222void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001223 BasicStringRef<Char> format_str, const ArgList &args) {
1224 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001225 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001226 while (*s) {
1227 Char c = *s++;
1228 if (c != '{' && c != '}') continue;
1229 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001230 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001231 start_ = ++s;
1232 continue;
1233 }
1234 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001235 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001236 write(writer_, start_, s - 1);
jamboree7487bde2015-06-10 09:32:59 +08001237 Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001238 s = format(s, arg);
1239 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001240 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001241}
1242
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001243FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001244 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001245 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001246}
1247
Victor Zverovich400812a2014-04-30 12:38:17 -07001248#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001249FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001250 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001251 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001252}
Victor Zverovich400812a2014-04-30 12:38:17 -07001253#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001254
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001255FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001256 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001257 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001258 std::fwrite(w.data(), 1, w.size(), f);
1259}
1260
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001261FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001262 print(stdout, format_str, args);
1263}
1264
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001265FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001266 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001267 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001268 os.write(w.data(), w.size());
1269}
1270
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001271FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001272 char escape[] = "\x1b[30m";
1273 escape[3] = '0' + static_cast<char>(c);
1274 std::fputs(escape, stdout);
1275 print(format, args);
1276 std::fputs(RESET_COLOR, stdout);
1277}
1278
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001279FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001280 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001281 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001282 std::size_t size = w.size();
1283 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001284}
1285
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001286#ifndef FMT_HEADER_ONLY
1287
vitaut9ca1ce22015-05-23 08:04:06 -07001288template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -07001289
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001290// Explicit instantiations for char.
1291
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001292template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
1293
Victor Zverovichf43caef2014-09-25 07:21:48 -07001294template const char *fmt::BasicFormatter<char>::format(
1295 const char *&format_str, const fmt::internal::Arg &arg);
1296
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001297template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001298 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001299
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001300template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001301 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001302
Victor Zverovich14f25772014-09-19 08:45:05 -07001303template int fmt::internal::CharTraits<char>::format_float(
1304 char *buffer, std::size_t size, const char *format,
1305 unsigned width, int precision, double value);
1306
1307template int fmt::internal::CharTraits<char>::format_float(
1308 char *buffer, std::size_t size, const char *format,
1309 unsigned width, int precision, long double value);
1310
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001311// Explicit instantiations for wchar_t.
1312
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001313template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1314
Victor Zverovichf43caef2014-09-25 07:21:48 -07001315template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1316 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1317
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001318template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001319 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001320
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001321template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001322 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001323 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001324
Victor Zverovich14f25772014-09-19 08:45:05 -07001325template int fmt::internal::CharTraits<wchar_t>::format_float(
1326 wchar_t *buffer, std::size_t size, const wchar_t *format,
1327 unsigned width, int precision, double value);
1328
1329template int fmt::internal::CharTraits<wchar_t>::format_float(
1330 wchar_t *buffer, std::size_t size, const wchar_t *format,
1331 unsigned width, int precision, long double value);
1332
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001333#endif // FMT_HEADER_ONLY
1334
jdale88a9862fd2014-03-11 18:56:24 +00001335#if _MSC_VER
1336# pragma warning(pop)
1337#endif