blob: df6efa66db72a23c7da2800c007c925a1c1b6426 [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
vitaut24c309f2015-06-12 07:15:57 -070038#if defined(_WIN32) && defined(__MINGW32__)
39# include <cstring>
40#endif
41
42#if FMT_USE_WINDOWS_H
vitaut67ce3942015-04-30 07:48:36 -070043# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
44# include <windows.h>
45# else
46# define NOMINMAX
47# include <windows.h>
48# undef NOMINMAX
49# endif
Ryuuke5a9dc8f2015-02-08 16:08:29 +000050#endif
51
Victor Zverovich6e5551e2014-07-02 06:33:25 -070052using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080053
Victor Zverovich8b76e972014-10-06 08:30:55 -070054// Check if exceptions are disabled.
55#if __GNUC__ && !__EXCEPTIONS
56# define FMT_EXCEPTIONS 0
57#endif
58#if _MSC_VER && !_HAS_EXCEPTIONS
59# define FMT_EXCEPTIONS 0
60#endif
61#ifndef FMT_EXCEPTIONS
62# define FMT_EXCEPTIONS 1
63#endif
64
65#if FMT_EXCEPTIONS
66# define FMT_TRY try
67# define FMT_CATCH(x) catch (x)
68#else
69# define FMT_TRY if (true)
70# define FMT_CATCH(x) if (false)
71#endif
72
73#ifndef FMT_THROW
74# if FMT_EXCEPTIONS
75# define FMT_THROW(x) throw x
76# else
vitaut66915782015-03-25 07:24:26 -070077# define FMT_THROW(x) assert(false)
Victor Zverovich8b76e972014-10-06 08:30:55 -070078# endif
79#endif
80
Victor Zverovichd9c605c2014-11-28 06:40:57 -080081#ifdef FMT_HEADER_ONLY
82# define FMT_FUNC inline
Victor Zverovichc2a69032014-11-28 15:30:03 -080083#else
84# define FMT_FUNC
Victor Zverovichd9c605c2014-11-28 06:40:57 -080085#endif
86
jdale88a9862fd2014-03-11 18:56:24 +000087#if _MSC_VER
88# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070089# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050090# pragma warning(disable: 4702) // unreachable code
vitautdf47d812015-03-16 18:53:14 -070091// Disable deprecation warning for strerror. The latter is not called but
92// MSVC fails to detect it.
93# pragma warning(disable: 4996)
jdale88a9862fd2014-03-11 18:56:24 +000094#endif
95
vitaut341b98c2015-03-14 13:39:33 -070096// Dummy implementations of strerror_r and strerror_s called if corresponding
97// system functions are not available.
vitaut4825fb42015-03-16 08:43:33 -070098static inline fmt::internal::None<> strerror_r(int, char *, ...) {
99 return fmt::internal::None<>();
vitaut341b98c2015-03-14 13:39:33 -0700100}
vitaut4825fb42015-03-16 08:43:33 -0700101static inline fmt::internal::None<> strerror_s(char *, std::size_t, ...) {
102 return fmt::internal::None<>();
vitaut341b98c2015-03-14 13:39:33 -0700103}
104
vitaut8725d072015-06-12 07:56:58 -0700105namespace fmt {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700106namespace {
107
108#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700109# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -0800110#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -0700111inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -0800112 va_list args;
113 va_start(args, format);
114 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
115 va_end(args);
116 return result;
117}
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700118# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700119#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800120
cstamford55836ca2015-03-10 07:04:31 +0000121#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
122# define FMT_SWPRINTF snwprintf
123#else
124# define FMT_SWPRINTF swprintf
125#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
126
Victor Zverovichadce0242014-08-17 07:53:55 -0700127// Checks if a value fits in int - used to avoid warnings about comparing
128// signed and unsigned integers.
129template <bool IsSigned>
130struct IntChecker {
131 template <typename T>
132 static bool fits_in_int(T value) {
133 unsigned max = INT_MAX;
134 return value <= max;
135 }
136};
137
138template <>
139struct IntChecker<true> {
140 template <typename T>
141 static bool fits_in_int(T value) {
142 return value >= INT_MIN && value <= INT_MAX;
143 }
144};
145
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800146const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700147
Victor Zverovich22f75d82014-09-03 08:03:05 -0700148typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
149
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700150// Portable thread-safe version of strerror.
151// Sets buffer to point to a string describing the error code.
152// This can be either a pointer to a string stored in buffer,
153// or a pointer to some static immutable string.
154// Returns one of the following values:
155// 0 - success
156// ERANGE - buffer is not large enough to store the error message
157// other - failure
158// Buffer should be at least of size 1.
159int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800160 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
vitaut8ab665a2015-06-22 08:17:23 -0700161 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700162
vitaut341b98c2015-03-14 13:39:33 -0700163 class StrError {
164 private:
165 int error_code_;
166 char *&buffer_;
167 std::size_t buffer_size_;
168
vitautda052ae2015-03-21 07:53:39 -0700169 // A noop assignment operator to avoid bogus warnings.
170 void operator=(const StrError &) {}
171
vitaut341b98c2015-03-14 13:39:33 -0700172 // Handle the result of XSI-compliant version of strerror_r.
173 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700174 // glibc versions before 2.13 return result in errno.
175 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700176 }
177
178 // Handle the result of GNU-specific version of strerror_r.
179 int handle(char *message) {
180 // If the buffer is full then the message is probably truncated.
181 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
182 return ERANGE;
183 buffer_ = message;
184 return 0;
185 }
186
187 // Handle the case when strerror_r is not available.
vitaut4825fb42015-03-16 08:43:33 -0700188 int handle(fmt::internal::None<>) {
vitaut341b98c2015-03-14 13:39:33 -0700189 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
190 }
191
192 // Fallback to strerror_s when strerror_r is not available.
193 int fallback(int result) {
194 // If the buffer is full then the message is probably truncated.
195 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
196 ERANGE : result;
197 }
198
199 // Fallback to strerror if strerror_r and strerror_s are not available.
vitaut4825fb42015-03-16 08:43:33 -0700200 int fallback(fmt::internal::None<>) {
vitaut341b98c2015-03-14 13:39:33 -0700201 errno = 0;
202 buffer_ = strerror(error_code_);
203 return errno;
204 }
205
206 public:
207 StrError(int error_code, char *&buffer, std::size_t buffer_size)
208 : error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {}
209
vitaut63f6c102015-06-14 09:36:23 -0700210 int run() {
211 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
212 return handle(strerror_r(error_code_, buffer_, buffer_size_));
213 }
vitaut341b98c2015-03-14 13:39:33 -0700214 };
215 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700216}
217
Victor Zverovich22f75d82014-09-03 08:03:05 -0700218void format_error_code(fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800219 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700220 // Report error code making sure that the output fits into
221 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
222 // bad_alloc.
223 out.clear();
224 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700225 static const char ERROR_STR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700226 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
vitaut1addec92015-03-21 20:16:36 -0700227 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
228 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
229 error_code_size += fmt::internal::count_digits(ec_value);
Victor Zverovich88e0db82014-09-05 08:04:26 -0700230 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700231 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700232 out << ERROR_STR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700233 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
234}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700235
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700236void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800237 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700238 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700239 func(full_message, error_code, message);
240 // Use Writer::data instead of Writer::c_str to avoid potential memory
241 // allocation.
242 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
243 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700244}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700245
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700246// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
247class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
248 public:
249 template <typename T>
250 bool visit_any_int(T value) { return value == 0; }
251};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700252
253// Parses an unsigned integer advancing s to the end of the parsed input.
254// This function assumes that the first character of s is a digit.
255template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700256int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700257 assert('0' <= *s && *s <= '9');
258 unsigned value = 0;
259 do {
260 unsigned new_value = value * 10 + (*s++ - '0');
261 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700262 if (new_value < value) {
263 value = UINT_MAX;
264 break;
265 }
266 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700267 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700268 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700269 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700270 return value;
271}
Victor Zveroviche8251562014-07-08 16:20:33 -0700272
jamboree7487bde2015-06-10 09:32:59 +0800273template <typename Char>
274inline bool is_name_start(Char c) {
275 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
276}
277
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700278inline void require_numeric_argument(const Arg &arg, char spec) {
279 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700280 std::string message =
281 fmt::format("format specifier '{}' requires numeric argument", spec);
282 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700283 }
284}
285
Victor Zveroviche8251562014-07-08 16:20:33 -0700286template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700287void check_sign(const Char *&s, const Arg &arg) {
288 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700289 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700290 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700291 FMT_THROW(fmt::FormatError(fmt::format(
292 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700293 }
294 ++s;
295}
296
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700297// Checks if an argument is a valid printf width specifier and sets
298// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700299class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700300 private:
301 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700302
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800303 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
304
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700305 public:
306 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700307
vitautd4ea2d72015-03-26 08:55:20 -0700308 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700309 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700310 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700311
Victor Zverovich9d74f952014-07-16 07:27:54 -0700312 template <typename T>
313 unsigned visit_any_int(T value) {
314 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
315 UnsignedType width = value;
316 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700317 spec_.align_ = fmt::ALIGN_LEFT;
318 width = 0 - width;
319 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700320 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700321 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700322 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700323 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700324};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700325
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700326class PrecisionHandler :
327 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
328 public:
vitautd4ea2d72015-03-26 08:55:20 -0700329 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700330 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700331 }
332
333 template <typename T>
334 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700335 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700336 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700337 return static_cast<int>(value);
338 }
339};
340
Victor Zverovich32344d92014-08-28 08:11:21 -0700341// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700342template <typename T>
343class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
344 private:
345 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700346 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700347
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800348 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
349
Victor Zverovicheeca2232014-07-30 07:37:16 -0700350 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700351 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
352 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700353
354 template <typename U>
355 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700356 bool is_signed = type_ == 'd' || type_ == 'i';
357 using fmt::internal::Arg;
358 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700359 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700360 if (is_signed) {
361 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700362 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700363 } else {
364 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700365 arg_.uint_value = static_cast<unsigned>(
366 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700367 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700368 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700369 if (is_signed) {
370 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700371 arg_.long_long_value =
372 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700373 } else {
374 arg_.type = Arg::ULONG_LONG;
375 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700376 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700377 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700378 }
379 }
380};
381
Victor Zverovich32344d92014-08-28 08:11:21 -0700382// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700383class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
384 private:
385 fmt::internal::Arg &arg_;
386
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800387 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
388
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700389 public:
390 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
391
392 template <typename T>
393 void visit_any_int(T value) {
394 arg_.type = Arg::CHAR;
395 arg_.int_value = static_cast<char>(value);
396 }
397};
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700398} // namespace
vitaut270069b2015-06-16 07:36:32 -0700399
400namespace internal {
401
402template <typename Impl, typename Char>
403class BasicArgFormatter : public ArgVisitor<Impl, void> {
404 private:
405 BasicWriter<Char> &writer_;
406 FormatSpec &spec_;
407
408 FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
409
410 protected:
411 BasicWriter<Char> &writer() { return writer_; }
412 const FormatSpec &spec() const { return spec_; }
413
414 public:
415 BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
416 : writer_(w), spec_(s) {}
417
418 template <typename T>
419 void visit_any_int(T value) { writer_.write_int(value, spec_); }
420
421 template <typename T>
422 void visit_any_double(T value) { writer_.write_double(value, spec_); }
423
424 void visit_bool(bool value) {
425 if (spec_.type_) {
426 writer_.write_int(value, spec_);
427 return;
428 }
429 const char *str_value = value ? "true" : "false";
430 Arg::StringValue<char> str = { str_value, strlen(str_value) };
431 writer_.write_str(str, spec_);
432 }
433
434 void visit_char(int value) {
435 if (spec_.type_ && spec_.type_ != 'c') {
436 spec_.flags_ |= CHAR_FLAG;
437 writer_.write_int(value, spec_);
438 return;
439 }
440 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
441 FMT_THROW(FormatError("invalid format specifier for char"));
442 typedef typename BasicWriter<Char>::CharPtr CharPtr;
vitaut147e5eb2015-06-17 07:21:16 -0700443 Char fill = internal::CharTraits<Char>::cast(spec_.fill());
vitaut270069b2015-06-16 07:36:32 -0700444 CharPtr out = CharPtr();
445 if (spec_.width_ > 1) {
446 out = writer_.grow_buffer(spec_.width_);
447 if (spec_.align_ == ALIGN_RIGHT) {
448 std::fill_n(out, spec_.width_ - 1, fill);
449 out += spec_.width_ - 1;
450 } else if (spec_.align_ == ALIGN_CENTER) {
451 out = writer_.fill_padding(out, spec_.width_, 1, fill);
452 } else {
453 std::fill_n(out + 1, spec_.width_ - 1, fill);
454 }
455 } else {
456 out = writer_.grow_buffer(1);
457 }
vitaut147e5eb2015-06-17 07:21:16 -0700458 *out = internal::CharTraits<Char>::cast(value);
vitaut270069b2015-06-16 07:36:32 -0700459 }
460
461 void visit_string(Arg::StringValue<char> value) {
462 writer_.write_str(value, spec_);
463 }
464
465 using ArgVisitor<Impl, void>::visit_wstring;
466
467 void visit_wstring(Arg::StringValue<Char> value) {
468 writer_.write_str(value, spec_);
469 }
470
471 void visit_pointer(const void *value) {
472 if (spec_.type_ && spec_.type_ != 'p')
473 report_unknown_type(spec_.type_, "pointer");
474 spec_.flags_ = HASH_FLAG;
475 spec_.type_ = 'x';
476 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
477 }
478};
479
480// An argument formatter.
481template <typename Char>
482class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
483 private:
484 BasicFormatter<Char> &formatter_;
485 const Char *format_;
486
487 public:
488 ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
489 : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
490 formatter_(f), format_(fmt) {}
491
492 void visit_custom(Arg::CustomValue c) {
493 c.format(&formatter_, c.value, &format_);
494 }
495};
496
497template <typename Char>
498class PrintfArgFormatter :
499 public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
500 public:
501 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
502 : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
503
504 void visit_char(int value) {
505 const FormatSpec &spec = this->spec();
506 BasicWriter<Char> &writer = this->writer();
507 if (spec.type_ && spec.type_ != 'c')
508 writer.write_int(value, spec);
509 typedef typename BasicWriter<Char>::CharPtr CharPtr;
510 CharPtr out = CharPtr();
511 if (spec.width_ > 1) {
512 Char fill = ' ';
513 out = writer.grow_buffer(spec.width_);
514 if (spec.align_ != ALIGN_LEFT) {
515 std::fill_n(out, spec.width_ - 1, fill);
516 out += spec.width_ - 1;
517 } else {
518 std::fill_n(out + 1, spec.width_ - 1, fill);
519 }
520 } else {
521 out = writer.grow_buffer(1);
522 }
523 *out = static_cast<Char>(value);
524 }
525};
526} // namespace internal
vitaut8725d072015-06-12 07:56:58 -0700527} // namespace fmt
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700528
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800529FMT_FUNC void fmt::SystemError::init(
vitaut438bd9b2015-06-26 07:43:54 -0700530 int err_code, CStringRef format_str, ArgList args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800531 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700532 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800533 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700534 std::runtime_error &base = *this;
535 base = std::runtime_error(w.str());
536}
537
Victor Zverovichb605b392013-09-09 22:21:40 -0700538template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700539int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700540 char *buffer, std::size_t size, const char *format,
541 unsigned width, int precision, T value) {
542 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700543 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700544 FMT_SNPRINTF(buffer, size, format, value) :
545 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700546 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700547 return precision < 0 ?
548 FMT_SNPRINTF(buffer, size, format, width, value) :
549 FMT_SNPRINTF(buffer, size, format, width, precision, value);
550}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700551
Victor Zverovichb605b392013-09-09 22:21:40 -0700552template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700553int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700554 wchar_t *buffer, std::size_t size, const wchar_t *format,
555 unsigned width, int precision, T value) {
556 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700557 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000558 FMT_SWPRINTF(buffer, size, format, value) :
559 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700560 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700561 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000562 FMT_SWPRINTF(buffer, size, format, width, value) :
563 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700564}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800565
Victor Zverovich311251e2014-11-29 06:58:00 -0800566template <typename T>
567const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800568 "0001020304050607080910111213141516171819"
569 "2021222324252627282930313233343536373839"
570 "4041424344454647484950515253545556575859"
571 "6061626364656667686970717273747576777879"
572 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800573
Victor Zverovichf1d85162014-02-19 13:02:22 -0800574#define FMT_POWERS_OF_10(factor) \
575 factor * 10, \
576 factor * 100, \
577 factor * 1000, \
578 factor * 10000, \
579 factor * 100000, \
580 factor * 1000000, \
581 factor * 10000000, \
582 factor * 100000000, \
583 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800584
Victor Zverovich311251e2014-11-29 06:58:00 -0800585template <typename T>
586const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
587 0, FMT_POWERS_OF_10(1)
588};
589
590template <typename T>
591const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800592 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800593 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800594 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700595 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800596 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800597 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800598};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800599
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800600FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800601 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800602 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700603 FMT_THROW(fmt::FormatError(
604 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800605 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700606 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700607 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700608 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800609}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700610
vitaut24c309f2015-06-12 07:15:57 -0700611#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700612
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800613FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700614 int length = MultiByteToWideChar(
vitautba09c1b2015-06-26 09:23:11 -0700615 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0);
Victor Zverovichdff21372014-12-16 07:01:01 -0800616 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700617 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800618 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700619 buffer_.resize(length);
620 length = MultiByteToWideChar(
vitautba09c1b2015-06-26 09:23:11 -0700621 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700622 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800623 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700624}
625
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800626FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700627 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700628 FMT_THROW(WindowsError(error_code,
629 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700630 }
631}
632
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800633FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
vitautba09c1b2015-06-26 09:23:11 -0700634 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700635 if (length == 0)
636 return GetLastError();
637 buffer_.resize(length);
638 length = WideCharToMultiByte(
vitautba09c1b2015-06-26 09:23:11 -0700639 CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700640 if (length == 0)
641 return GetLastError();
642 return 0;
643}
644
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800645FMT_FUNC void fmt::WindowsError::init(
vitautba09c1b2015-06-26 09:23:11 -0700646 int err_code, CStringRef format_str, ArgList args) {
Carter Li3f574c12015-02-17 10:11:42 +0800647 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700648 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800649 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700650 std::runtime_error &base = *this;
651 base = std::runtime_error(w.str());
652}
653
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800654FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700655 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800656 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700657 class String {
658 private:
659 LPWSTR str_;
660
661 public:
662 String() : str_() {}
663 ~String() { LocalFree(str_); }
664 LPWSTR *ptr() { return &str_; }
665 LPCWSTR c_str() const { return str_; }
666 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700667 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700668 String system_message;
669 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
670 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
671 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
672 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
673 UTF16ToUTF8 utf8_message;
674 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
675 out << message << ": " << utf8_message;
676 return;
677 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700678 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700679 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700680 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700681}
vitaut24c309f2015-06-12 07:15:57 -0700682
683#endif // FMT_USE_WINDOWS_H
684
685FMT_FUNC void fmt::internal::format_system_error(
686 fmt::Writer &out, int error_code,
687 fmt::StringRef message) FMT_NOEXCEPT {
688 FMT_TRY {
689 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
690 buffer.resize(INLINE_BUFFER_SIZE);
691 for (;;) {
692 char *system_message = &buffer[0];
693 int result = safe_strerror(error_code, system_message, buffer.size());
694 if (result == 0) {
695 out << message << ": " << system_message;
696 return;
697 }
698 if (result != ERANGE)
699 break; // Can't get error message, report error code instead.
700 buffer.resize(buffer.size() * 2);
701 }
702 } FMT_CATCH(...) {}
703 format_error_code(out, error_code, message);
704}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700705
jamboree7487bde2015-06-10 09:32:59 +0800706template <typename Char>
vitauta98583d2015-06-10 08:49:22 -0700707void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800708 if (!map_.empty())
709 return;
vitauta98583d2015-06-10 08:49:22 -0700710 typedef internal::NamedArg<Char> NamedArg;
vitautfccff7b2015-06-11 07:19:00 -0700711 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700712 bool use_values =
713 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800714 if (use_values) {
715 for (unsigned i = 0;/*nothing*/; ++i) {
716 internal::Arg::Type arg_type = args.type(i);
717 switch (arg_type) {
718 case internal::Arg::NONE:
719 return;
720 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700721 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800722 map_.insert(Pair(named_arg->name, *named_arg));
723 break;
724 default:
725 /*nothing*/;
726 }
727 }
728 return;
729 }
vitauta98583d2015-06-10 08:49:22 -0700730 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800731 internal::Arg::Type arg_type = args.type(i);
732 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700733 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800734 map_.insert(Pair(named_arg->name, *named_arg));
735 }
736 }
vitauta98583d2015-06-10 08:49:22 -0700737 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800738 switch (args.args_[i].type) {
739 case internal::Arg::NONE:
740 return;
741 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700742 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800743 map_.insert(Pair(named_arg->name, *named_arg));
744 break;
745 default:
746 /*nothing*/;
747 }
748 }
749}
750
Victor Zverovichd1ded562014-09-29 08:48:16 -0700751template <typename Char>
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800752void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
753 FMT_THROW(std::runtime_error("buffer overflow"));
754}
755
756template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700757template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700758void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800759 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700760 // Check if StrChar is convertible to Char.
761 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700762 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700763 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800764 const StrChar *str_value = s.value;
765 std::size_t str_size = s.size;
766 if (str_size == 0) {
767 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700768 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800769 if (*str_value)
770 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700771 }
Victor Zverovich59254412015-02-06 07:27:19 -0800772 std::size_t precision = spec.precision_;
773 if (spec.precision_ >= 0 && precision < str_size)
Victor Zverovich43aebf52015-01-08 07:56:08 -0800774 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800775 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700776}
777
778template <typename Char>
jamboree7487bde2015-06-10 09:32:59 +0800779inline Arg fmt::BasicFormatter<Char>::get_arg(
vitautfccff7b2015-06-11 07:19:00 -0700780 BasicStringRef<Char> arg_name, const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800781 if (check_no_auto_index(error)) {
vitautfccff7b2015-06-11 07:19:00 -0700782 map_.init(args());
783 const Arg *arg = map_.find(arg_name);
jamboree7487bde2015-06-10 09:32:59 +0800784 if (arg)
785 return *arg;
786 error = "argument not found";
787 }
788 return Arg();
789}
790
791template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700792inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700793 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700794 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700795 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700796 if (error) {
797 FMT_THROW(FormatError(
798 *s != '}' && *s != ':' ? "invalid format string" : error));
799 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700800 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700801}
802
jamboree7487bde2015-06-10 09:32:59 +0800803template <typename Char>
804inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
805 assert(is_name_start(*s));
806 const Char *start = s;
807 Char c;
808 do {
809 c = *++s;
jamboree3c99ed42015-06-11 12:03:22 +0800810 } while (is_name_start(c) || ('0' <= c && c <= '9'));
jamboree7487bde2015-06-10 09:32:59 +0800811 const char *error = 0;
812 Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
813 if (error)
814 FMT_THROW(fmt::FormatError(error));
815 return arg;
816}
817
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800818FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700819 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700820 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800821 switch (arg.type) {
822 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700823 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800824 break;
825 case Arg::NAMED_ARG:
826 arg = *static_cast<const internal::Arg*>(arg.pointer);
827 default:
828 /*nothing*/;
829 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700830 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700831}
832
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700833inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700834 if (next_arg_index_ >= 0)
835 return do_get_arg(next_arg_index_++, error);
836 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700837 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700838}
839
vitautfccff7b2015-06-11 07:19:00 -0700840inline bool fmt::internal::FormatterBase::check_no_auto_index(
841 const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800842 if (next_arg_index_ > 0) {
843 error = "cannot switch from automatic to manual argument indexing";
844 return false;
845 }
vitautfccff7b2015-06-11 07:19:00 -0700846 next_arg_index_ = -1;
jamboree7487bde2015-06-10 09:32:59 +0800847 return true;
848}
849
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700850inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700851 unsigned arg_index, const char *&error) {
vitautfccff7b2015-06-11 07:19:00 -0700852 return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700853}
854
Victor Zverovich7cae7632013-09-06 20:23:42 -0700855template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700856void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700857 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700858 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700859 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700860 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700861 spec.align_ = ALIGN_LEFT;
862 break;
863 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700864 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
865 break;
866 case '0':
867 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700868 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700869 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700870 spec.flags_ |= SIGN_FLAG;
871 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700872 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700873 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700874 break;
875 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700876 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700877 return;
878 }
879 }
880}
881
Victor Zverovichcb743c02014-06-19 07:40:35 -0700882template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700883Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700884 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800885 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700886 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700887 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700888 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
889 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700890 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700891 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700892}
893
894template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700895unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700896 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700897 unsigned arg_index = UINT_MAX;
898 Char c = *s;
899 if (c >= '0' && c <= '9') {
900 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700901 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700902 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700903 if (*s == '$') { // value is an argument index
904 ++s;
905 arg_index = value;
906 } else {
907 if (c == '0')
908 spec.fill_ = '0';
909 if (value != 0) {
910 // Nonzero value means that we parsed width and don't need to
911 // parse it or flags again, so return now.
912 spec.width_ = value;
913 return arg_index;
914 }
915 }
916 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700917 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700918 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700919 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700920 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700921 } else if (*s == '*') {
922 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700923 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700924 }
925 return arg_index;
926}
927
Victor Zverovich1f19b982014-06-16 07:49:30 -0700928template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700929void fmt::internal::PrintfFormatter<Char>::format(
vitaut438bd9b2015-06-26 07:43:54 -0700930 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700931 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800932 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700933 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700934 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700935 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700936 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700937 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700938 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700939 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700940 start = ++s;
941 continue;
942 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700943 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700944
Victor Zverovichcb743c02014-06-19 07:40:35 -0700945 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700946 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700947
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700948 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700949 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700950
951 // Parse precision.
952 if (*s == '.') {
953 ++s;
954 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700955 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700956 } else if (*s == '*') {
957 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700958 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700959 }
960 }
961
Victor Zverovich56fc5252014-08-28 07:48:55 -0700962 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700963 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700964 spec.flags_ &= ~HASH_FLAG;
965 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700966 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700967 spec.align_ = ALIGN_NUMERIC;
968 else
969 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700970 }
971
Victor Zverovichf4156b52014-07-30 08:39:07 -0700972 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700973 switch (*s++) {
974 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700975 if (*s == 'h')
976 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700977 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700978 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700979 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700980 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700981 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700982 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700983 else
984 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700985 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700986 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700987 ArgConverter<intmax_t>(arg, *s).visit(arg);
988 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700989 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700990 ArgConverter<size_t>(arg, *s).visit(arg);
991 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700992 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700993 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
994 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700995 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700996 // printf produces garbage when 'L' is omitted for long double, no
997 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700998 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700999 default:
1000 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -07001001 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001002 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001003
1004 // Parse type.
1005 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001006 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001007 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -07001008 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
1009 // Normalize type.
1010 switch (spec.type_) {
1011 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -07001012 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -07001013 break;
1014 case 'c':
1015 // TODO: handle wchar_t
1016 CharConverter(arg).visit(arg);
1017 break;
1018 }
Victor Zverovichf4156b52014-07-30 08:39:07 -07001019 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001020
1021 start = s;
1022
1023 // Format argument.
vitaut270069b2015-06-16 07:36:32 -07001024 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001025 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001026 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001027}
1028
1029template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001030const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001031 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001032 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -07001033 FormatSpec spec;
1034 if (*s == ':') {
1035 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001036 arg.custom.format(this, arg.custom.value, &s);
1037 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001038 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001039 ++s;
1040 // Parse fill and alignment.
1041 if (Char c = *s) {
1042 const Char *p = s + 1;
1043 spec.align_ = ALIGN_DEFAULT;
1044 do {
1045 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001046 case '<':
1047 spec.align_ = ALIGN_LEFT;
1048 break;
1049 case '>':
1050 spec.align_ = ALIGN_RIGHT;
1051 break;
1052 case '=':
1053 spec.align_ = ALIGN_NUMERIC;
1054 break;
1055 case '^':
1056 spec.align_ = ALIGN_CENTER;
1057 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001058 }
1059 if (spec.align_ != ALIGN_DEFAULT) {
1060 if (p != s) {
1061 if (c == '}') break;
1062 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001063 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001064 s += 2;
1065 spec.fill_ = c;
1066 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001067 if (spec.align_ == ALIGN_NUMERIC)
1068 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -07001069 break;
1070 }
1071 } while (--p >= s);
1072 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001073
Victor Zveroviche8251562014-07-08 16:20:33 -07001074 // Parse sign.
1075 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001076 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001077 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001078 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1079 break;
1080 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001081 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001082 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001083 break;
1084 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001085 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001086 spec.flags_ |= SIGN_FLAG;
1087 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001088 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001089
Victor Zveroviche8251562014-07-08 16:20:33 -07001090 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001091 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -07001092 spec.flags_ |= HASH_FLAG;
1093 ++s;
1094 }
1095
jamboree54a6cb32015-06-04 13:59:37 +08001096 // Parse zero flag.
1097 if (*s == '0') {
vitaut8949a2e2015-06-08 06:53:18 -07001098 require_numeric_argument(arg, '0');
1099 spec.align_ = ALIGN_NUMERIC;
1100 spec.fill_ = '0';
1101 ++s;
jamboree54a6cb32015-06-04 13:59:37 +08001102 }
1103
1104 // Parse width.
1105 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001106 spec.width_ = parse_nonnegative_int(s);
jamboree54a6cb32015-06-04 13:59:37 +08001107 } else if (*s == '{') {
vitaut8949a2e2015-06-08 06:53:18 -07001108 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001109 Arg width_arg = is_name_start(*s) ?
1110 parse_arg_name(s) : parse_arg_index(s);
vitaut8949a2e2015-06-08 06:53:18 -07001111 if (*s++ != '}')
1112 FMT_THROW(FormatError("invalid format string"));
1113 ULongLong value = 0;
1114 switch (width_arg.type) {
1115 case Arg::INT:
1116 if (width_arg.int_value < 0)
1117 FMT_THROW(FormatError("negative width"));
1118 value = width_arg.int_value;
1119 break;
1120 case Arg::UINT:
1121 value = width_arg.uint_value;
1122 break;
1123 case Arg::LONG_LONG:
1124 if (width_arg.long_long_value < 0)
1125 FMT_THROW(FormatError("negative width"));
1126 value = width_arg.long_long_value;
1127 break;
1128 case Arg::ULONG_LONG:
1129 value = width_arg.ulong_long_value;
1130 break;
1131 default:
1132 FMT_THROW(FormatError("width is not integer"));
1133 }
1134 if (value > INT_MAX)
1135 FMT_THROW(FormatError("number is too big"));
1136 spec.width_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001137 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001138
Victor Zveroviche8251562014-07-08 16:20:33 -07001139 // Parse precision.
1140 if (*s == '.') {
1141 ++s;
1142 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001143 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001144 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001145 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001146 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001147 Arg precision_arg =
1148 is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001149 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001150 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001151 ULongLong value = 0;
1152 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001153 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001154 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001155 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001156 value = precision_arg.int_value;
1157 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001158 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001159 value = precision_arg.uint_value;
1160 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001161 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001162 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001163 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001164 value = precision_arg.long_long_value;
1165 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001166 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001167 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001168 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001169 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001170 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001171 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001172 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001173 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001174 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001175 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001176 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001177 }
vitautfd5c2e92015-06-11 08:58:31 -07001178 if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001179 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001180 fmt::format("precision not allowed in {} format specifier",
1181 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001182 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001183 }
1184
Victor Zveroviche8251562014-07-08 16:20:33 -07001185 // Parse type.
1186 if (*s != '}' && *s)
1187 spec.type_ = static_cast<char>(*s++);
1188 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001189
Victor Zveroviche8251562014-07-08 16:20:33 -07001190 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001191 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001192 start_ = s;
1193
1194 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001195 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001196 return s;
1197}
1198
1199template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001200void fmt::BasicFormatter<Char>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001201 BasicCStringRef<Char> format_str, const ArgList &args) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001202 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001203 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001204 while (*s) {
1205 Char c = *s++;
1206 if (c != '{' && c != '}') continue;
1207 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001208 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001209 start_ = ++s;
1210 continue;
1211 }
1212 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001213 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001214 write(writer_, start_, s - 1);
jamboree7487bde2015-06-10 09:32:59 +08001215 Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001216 s = format(s, arg);
1217 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001218 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001219}
1220
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001221FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001222 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001223 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001224}
1225
vitaut24c309f2015-06-12 07:15:57 -07001226#if FMT_USE_WINDOWS_H
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001227FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001228 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001229 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001230}
Victor Zverovich400812a2014-04-30 12:38:17 -07001231#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001232
vitaut438bd9b2015-06-26 07:43:54 -07001233FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001234 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001235 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001236 std::fwrite(w.data(), 1, w.size(), f);
1237}
1238
vitaut438bd9b2015-06-26 07:43:54 -07001239FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001240 print(stdout, format_str, args);
1241}
1242
vitaut438bd9b2015-06-26 07:43:54 -07001243FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001244 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001245 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001246 os.write(w.data(), w.size());
1247}
1248
vitaut438bd9b2015-06-26 07:43:54 -07001249FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001250 char escape[] = "\x1b[30m";
1251 escape[3] = '0' + static_cast<char>(c);
1252 std::fputs(escape, stdout);
1253 print(format, args);
1254 std::fputs(RESET_COLOR, stdout);
1255}
1256
vitaut438bd9b2015-06-26 07:43:54 -07001257FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001258 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001259 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001260 std::size_t size = w.size();
1261 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001262}
1263
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001264#ifndef FMT_HEADER_ONLY
1265
vitaut9ca1ce22015-05-23 08:04:06 -07001266template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -07001267
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001268// Explicit instantiations for char.
1269
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001270template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
1271
Victor Zverovichf43caef2014-09-25 07:21:48 -07001272template const char *fmt::BasicFormatter<char>::format(
1273 const char *&format_str, const fmt::internal::Arg &arg);
1274
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001275template void fmt::BasicFormatter<char>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001276 CStringRef format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001277
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001278template void fmt::internal::PrintfFormatter<char>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001279 BasicWriter<char> &writer, CStringRef format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001280
Victor Zverovich14f25772014-09-19 08:45:05 -07001281template int fmt::internal::CharTraits<char>::format_float(
1282 char *buffer, std::size_t size, const char *format,
1283 unsigned width, int precision, double value);
1284
1285template int fmt::internal::CharTraits<char>::format_float(
1286 char *buffer, std::size_t size, const char *format,
1287 unsigned width, int precision, long double value);
1288
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001289// Explicit instantiations for wchar_t.
1290
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001291template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1292
Victor Zverovichf43caef2014-09-25 07:21:48 -07001293template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1294 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1295
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001296template void fmt::BasicFormatter<wchar_t>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001297 BasicCStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001298
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001299template void fmt::internal::PrintfFormatter<wchar_t>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001300 BasicWriter<wchar_t> &writer, WCStringRef format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001301 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001302
Victor Zverovich14f25772014-09-19 08:45:05 -07001303template int fmt::internal::CharTraits<wchar_t>::format_float(
1304 wchar_t *buffer, std::size_t size, const wchar_t *format,
1305 unsigned width, int precision, double value);
1306
1307template int fmt::internal::CharTraits<wchar_t>::format_float(
1308 wchar_t *buffer, std::size_t size, const wchar_t *format,
1309 unsigned width, int precision, long double value);
1310
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001311#endif // FMT_HEADER_ONLY
1312
jdale88a9862fd2014-03-11 18:56:24 +00001313#if _MSC_VER
1314# pragma warning(pop)
1315#endif