blob: 962c47055573349f965741077337e19d9bd5520d [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
Ingo van Lilb4b13ee2015-11-02 12:34:46 +010058#if defined(_MSC_VER) && !_HAS_EXCEPTIONS
Victor Zverovich8b76e972014-10-06 08:30:55 -070059# 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
Ingo van Lilb4b13ee2015-11-02 12:34:46 +010087#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +000088# 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.
vitautc669cbe2015-07-07 07:05:17 -070098static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
99 return fmt::internal::Null<>();
vitaut341b98c2015-03-14 13:39:33 -0700100}
vitautc669cbe2015-07-07 07:05:17 -0700101static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
102 return fmt::internal::Null<>();
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 }
vitaut6484a152015-07-08 07:35:57 -0700136 static bool fits_in_int(bool) { return true; }
Victor Zverovichadce0242014-08-17 07:53:55 -0700137};
138
139template <>
140struct IntChecker<true> {
141 template <typename T>
142 static bool fits_in_int(T value) {
vitautfb277232015-10-22 07:33:01 -0700143 return value >= INT_MIN && value <= INT_MAX;
Victor Zverovichadce0242014-08-17 07:53:55 -0700144 }
vitaut17960dd2015-10-28 06:23:22 -0700145 static bool fits_in_int(int) { return true; }
Victor Zverovichadce0242014-08-17 07:53:55 -0700146};
147
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800148const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700149
Victor Zverovich22f75d82014-09-03 08:03:05 -0700150typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
151
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700152// Portable thread-safe version of strerror.
153// Sets buffer to point to a string describing the error code.
154// This can be either a pointer to a string stored in buffer,
155// or a pointer to some static immutable string.
156// Returns one of the following values:
157// 0 - success
158// ERANGE - buffer is not large enough to store the error message
159// other - failure
160// Buffer should be at least of size 1.
161int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800162 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
vitaut8ab665a2015-06-22 08:17:23 -0700163 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700164
vitaut341b98c2015-03-14 13:39:33 -0700165 class StrError {
166 private:
167 int error_code_;
168 char *&buffer_;
169 std::size_t buffer_size_;
170
vitautda052ae2015-03-21 07:53:39 -0700171 // A noop assignment operator to avoid bogus warnings.
172 void operator=(const StrError &) {}
173
vitaut341b98c2015-03-14 13:39:33 -0700174 // Handle the result of XSI-compliant version of strerror_r.
175 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700176 // glibc versions before 2.13 return result in errno.
177 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700178 }
179
180 // Handle the result of GNU-specific version of strerror_r.
181 int handle(char *message) {
182 // If the buffer is full then the message is probably truncated.
183 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
184 return ERANGE;
185 buffer_ = message;
186 return 0;
187 }
188
189 // Handle the case when strerror_r is not available.
vitautc669cbe2015-07-07 07:05:17 -0700190 int handle(fmt::internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700191 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
192 }
193
194 // Fallback to strerror_s when strerror_r is not available.
195 int fallback(int result) {
196 // If the buffer is full then the message is probably truncated.
197 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
198 ERANGE : result;
199 }
200
201 // Fallback to strerror if strerror_r and strerror_s are not available.
vitautc669cbe2015-07-07 07:05:17 -0700202 int fallback(fmt::internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700203 errno = 0;
204 buffer_ = strerror(error_code_);
205 return errno;
206 }
207
208 public:
Radu Popescu0affb232015-08-04 12:52:44 +0200209 StrError(int err_code, char *&buf, std::size_t buf_size)
210 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
vitaut341b98c2015-03-14 13:39:33 -0700211
vitaut63f6c102015-06-14 09:36:23 -0700212 int run() {
213 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
214 return handle(strerror_r(error_code_, buffer_, buffer_size_));
215 }
vitaut341b98c2015-03-14 13:39:33 -0700216 };
217 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700218}
219
Victor Zverovich22f75d82014-09-03 08:03:05 -0700220void format_error_code(fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800221 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700222 // Report error code making sure that the output fits into
223 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
224 // bad_alloc.
225 out.clear();
226 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700227 static const char ERROR_STR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700228 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
vitaut1addec92015-03-21 20:16:36 -0700229 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
230 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
231 error_code_size += fmt::internal::count_digits(ec_value);
Victor Zverovich88e0db82014-09-05 08:04:26 -0700232 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700233 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700234 out << ERROR_STR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700235 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
236}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700237
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700238void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800239 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700240 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700241 func(full_message, error_code, message);
242 // Use Writer::data instead of Writer::c_str to avoid potential memory
243 // allocation.
244 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
245 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700246}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700247
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700248// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
249class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
250 public:
251 template <typename T>
252 bool visit_any_int(T value) { return value == 0; }
253};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700254
255// Parses an unsigned integer advancing s to the end of the parsed input.
256// This function assumes that the first character of s is a digit.
257template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700258int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700259 assert('0' <= *s && *s <= '9');
260 unsigned value = 0;
261 do {
262 unsigned new_value = value * 10 + (*s++ - '0');
263 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700264 if (new_value < value) {
265 value = UINT_MAX;
266 break;
267 }
268 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700269 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700270 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700271 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700272 return value;
273}
Victor Zveroviche8251562014-07-08 16:20:33 -0700274
jamboree7487bde2015-06-10 09:32:59 +0800275template <typename Char>
276inline bool is_name_start(Char c) {
277 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
278}
279
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700280inline void require_numeric_argument(const Arg &arg, char spec) {
281 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700282 std::string message =
283 fmt::format("format specifier '{}' requires numeric argument", spec);
284 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700285 }
286}
287
Victor Zveroviche8251562014-07-08 16:20:33 -0700288template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700289void check_sign(const Char *&s, const Arg &arg) {
290 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700291 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700292 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700293 FMT_THROW(fmt::FormatError(fmt::format(
294 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700295 }
296 ++s;
297}
298
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700299// Checks if an argument is a valid printf width specifier and sets
300// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700301class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700302 private:
303 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700304
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800305 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
306
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700307 public:
308 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700309
vitautd4ea2d72015-03-26 08:55:20 -0700310 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700311 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700312 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700313
Victor Zverovich9d74f952014-07-16 07:27:54 -0700314 template <typename T>
315 unsigned visit_any_int(T value) {
316 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
317 UnsignedType width = value;
318 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700319 spec_.align_ = fmt::ALIGN_LEFT;
320 width = 0 - width;
321 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700322 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700323 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700324 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700325 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700326};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700327
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700328class PrecisionHandler :
329 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
330 public:
vitautd4ea2d72015-03-26 08:55:20 -0700331 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700332 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700333 }
334
335 template <typename T>
336 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700337 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700338 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700339 return static_cast<int>(value);
340 }
341};
342
Victor Zverovich32344d92014-08-28 08:11:21 -0700343// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700344template <typename T>
345class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
346 private:
347 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700348 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700349
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800350 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
351
Victor Zverovicheeca2232014-07-30 07:37:16 -0700352 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700353 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
354 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700355
356 template <typename U>
357 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700358 bool is_signed = type_ == 'd' || type_ == 'i';
359 using fmt::internal::Arg;
360 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700361 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700362 if (is_signed) {
363 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700364 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700365 } else {
366 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700367 arg_.uint_value = static_cast<unsigned>(
368 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700369 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700370 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700371 if (is_signed) {
372 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700373 arg_.long_long_value =
374 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700375 } else {
376 arg_.type = Arg::ULONG_LONG;
377 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700378 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700379 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700380 }
381 }
382};
383
Victor Zverovich32344d92014-08-28 08:11:21 -0700384// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700385class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
386 private:
387 fmt::internal::Arg &arg_;
388
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800389 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
390
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700391 public:
392 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
393
394 template <typename T>
395 void visit_any_int(T value) {
396 arg_.type = Arg::CHAR;
397 arg_.int_value = static_cast<char>(value);
398 }
399};
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700400} // namespace
vitaut270069b2015-06-16 07:36:32 -0700401
402namespace internal {
403
404template <typename Impl, typename Char>
405class BasicArgFormatter : public ArgVisitor<Impl, void> {
406 private:
407 BasicWriter<Char> &writer_;
408 FormatSpec &spec_;
409
410 FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
411
412 protected:
413 BasicWriter<Char> &writer() { return writer_; }
414 const FormatSpec &spec() const { return spec_; }
415
416 public:
417 BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
418 : writer_(w), spec_(s) {}
419
420 template <typename T>
421 void visit_any_int(T value) { writer_.write_int(value, spec_); }
422
423 template <typename T>
424 void visit_any_double(T value) { writer_.write_double(value, spec_); }
425
426 void visit_bool(bool value) {
427 if (spec_.type_) {
428 writer_.write_int(value, spec_);
429 return;
430 }
431 const char *str_value = value ? "true" : "false";
432 Arg::StringValue<char> str = { str_value, strlen(str_value) };
433 writer_.write_str(str, spec_);
434 }
435
436 void visit_char(int value) {
437 if (spec_.type_ && spec_.type_ != 'c') {
438 spec_.flags_ |= CHAR_FLAG;
439 writer_.write_int(value, spec_);
440 return;
441 }
442 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
443 FMT_THROW(FormatError("invalid format specifier for char"));
444 typedef typename BasicWriter<Char>::CharPtr CharPtr;
vitaut147e5eb2015-06-17 07:21:16 -0700445 Char fill = internal::CharTraits<Char>::cast(spec_.fill());
vitaut270069b2015-06-16 07:36:32 -0700446 CharPtr out = CharPtr();
vitaut82acd482015-10-30 07:54:55 -0700447 const unsigned CHAR_WIDTH = 1;
vitaut316b05c2015-10-28 06:31:37 -0700448 if (spec_.width_ > CHAR_WIDTH) {
vitaut270069b2015-06-16 07:36:32 -0700449 out = writer_.grow_buffer(spec_.width_);
450 if (spec_.align_ == ALIGN_RIGHT) {
vitaut316b05c2015-10-28 06:31:37 -0700451 std::fill_n(out, spec_.width_ - CHAR_WIDTH, fill);
452 out += spec_.width_ - CHAR_WIDTH;
vitaut270069b2015-06-16 07:36:32 -0700453 } else if (spec_.align_ == ALIGN_CENTER) {
vitaut2d727e72015-10-28 07:01:28 -0700454 out = writer_.fill_padding(out, spec_.width_,
455 internal::check(CHAR_WIDTH), fill);
vitaut270069b2015-06-16 07:36:32 -0700456 } else {
vitaut316b05c2015-10-28 06:31:37 -0700457 std::fill_n(out + CHAR_WIDTH, spec_.width_ - CHAR_WIDTH, fill);
vitaut270069b2015-06-16 07:36:32 -0700458 }
459 } else {
vitaut2d727e72015-10-28 07:01:28 -0700460 out = writer_.grow_buffer(CHAR_WIDTH);
vitaut270069b2015-06-16 07:36:32 -0700461 }
vitaut147e5eb2015-06-17 07:21:16 -0700462 *out = internal::CharTraits<Char>::cast(value);
vitaut270069b2015-06-16 07:36:32 -0700463 }
464
465 void visit_string(Arg::StringValue<char> value) {
466 writer_.write_str(value, spec_);
467 }
468
469 using ArgVisitor<Impl, void>::visit_wstring;
470
471 void visit_wstring(Arg::StringValue<Char> value) {
472 writer_.write_str(value, spec_);
473 }
474
475 void visit_pointer(const void *value) {
476 if (spec_.type_ && spec_.type_ != 'p')
477 report_unknown_type(spec_.type_, "pointer");
478 spec_.flags_ = HASH_FLAG;
479 spec_.type_ = 'x';
480 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
481 }
482};
483
484// An argument formatter.
485template <typename Char>
486class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
487 private:
488 BasicFormatter<Char> &formatter_;
489 const Char *format_;
490
491 public:
492 ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
493 : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
494 formatter_(f), format_(fmt) {}
495
496 void visit_custom(Arg::CustomValue c) {
497 c.format(&formatter_, c.value, &format_);
498 }
499};
500
501template <typename Char>
502class PrintfArgFormatter :
503 public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
504 public:
505 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
506 : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
507
508 void visit_char(int value) {
vitaut7fa17fe2015-08-04 07:55:33 -0700509 const FormatSpec &fmt_spec = this->spec();
vitautecdc7ec2015-08-04 08:01:28 -0700510 BasicWriter<Char> &w = this->writer();
vitaut7fa17fe2015-08-04 07:55:33 -0700511 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
vitautecdc7ec2015-08-04 08:01:28 -0700512 w.write_int(value, fmt_spec);
vitaut270069b2015-06-16 07:36:32 -0700513 typedef typename BasicWriter<Char>::CharPtr CharPtr;
514 CharPtr out = CharPtr();
vitaut7fa17fe2015-08-04 07:55:33 -0700515 if (fmt_spec.width_ > 1) {
vitaut270069b2015-06-16 07:36:32 -0700516 Char fill = ' ';
vitautecdc7ec2015-08-04 08:01:28 -0700517 out = w.grow_buffer(fmt_spec.width_);
vitaut7fa17fe2015-08-04 07:55:33 -0700518 if (fmt_spec.align_ != ALIGN_LEFT) {
519 std::fill_n(out, fmt_spec.width_ - 1, fill);
520 out += fmt_spec.width_ - 1;
vitaut270069b2015-06-16 07:36:32 -0700521 } else {
vitaut7fa17fe2015-08-04 07:55:33 -0700522 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
vitaut270069b2015-06-16 07:36:32 -0700523 }
524 } else {
vitautecdc7ec2015-08-04 08:01:28 -0700525 out = w.grow_buffer(1);
vitaut270069b2015-06-16 07:36:32 -0700526 }
527 *out = static_cast<Char>(value);
528 }
vitaut79d8f592015-09-08 08:36:20 -0700529
530 void visit_custom(Arg::CustomValue c) {
531 BasicFormatter<Char> formatter(ArgList(), this->writer());
vitautef710de2015-09-18 16:26:41 -0700532 const Char format_str[] = {'}', 0};
533 const Char *format = format_str;
vitaut79d8f592015-09-08 08:36:20 -0700534 c.format(&formatter, c.value, &format);
535 }
vitaut270069b2015-06-16 07:36:32 -0700536};
537} // namespace internal
vitaut8725d072015-06-12 07:56:58 -0700538} // namespace fmt
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700539
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800540FMT_FUNC void fmt::SystemError::init(
vitaut438bd9b2015-06-26 07:43:54 -0700541 int err_code, CStringRef format_str, ArgList args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800542 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700543 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800544 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700545 std::runtime_error &base = *this;
546 base = std::runtime_error(w.str());
547}
548
Victor Zverovichb605b392013-09-09 22:21:40 -0700549template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700550int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700551 char *buffer, std::size_t size, const char *format,
552 unsigned width, int precision, T value) {
553 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700554 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700555 FMT_SNPRINTF(buffer, size, format, value) :
556 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700557 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700558 return precision < 0 ?
559 FMT_SNPRINTF(buffer, size, format, width, value) :
560 FMT_SNPRINTF(buffer, size, format, width, precision, value);
561}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700562
Victor Zverovichb605b392013-09-09 22:21:40 -0700563template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700564int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700565 wchar_t *buffer, std::size_t size, const wchar_t *format,
566 unsigned width, int precision, T value) {
567 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700568 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000569 FMT_SWPRINTF(buffer, size, format, value) :
570 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700571 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700572 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000573 FMT_SWPRINTF(buffer, size, format, width, value) :
574 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700575}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800576
Victor Zverovich311251e2014-11-29 06:58:00 -0800577template <typename T>
578const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800579 "0001020304050607080910111213141516171819"
580 "2021222324252627282930313233343536373839"
581 "4041424344454647484950515253545556575859"
582 "6061626364656667686970717273747576777879"
583 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800584
Victor Zverovichf1d85162014-02-19 13:02:22 -0800585#define FMT_POWERS_OF_10(factor) \
586 factor * 10, \
587 factor * 100, \
588 factor * 1000, \
589 factor * 10000, \
590 factor * 100000, \
591 factor * 1000000, \
592 factor * 10000000, \
593 factor * 100000000, \
594 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800595
Victor Zverovich311251e2014-11-29 06:58:00 -0800596template <typename T>
597const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
598 0, FMT_POWERS_OF_10(1)
599};
600
601template <typename T>
602const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800603 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800604 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800605 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700606 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800607 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800608 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800609};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800610
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800611FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800612 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800613 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700614 FMT_THROW(fmt::FormatError(
615 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800616 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700617 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700618 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700619 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800620}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700621
vitaut24c309f2015-06-12 07:15:57 -0700622#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700623
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800624FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800625 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700626 if (s.size() > INT_MAX)
627 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
628 int s_size = static_cast<int>(s.size());
629 int length = MultiByteToWideChar(
630 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700631 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800632 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700633 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700634 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700635 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700636 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800637 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700638 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700639}
640
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800641FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700642 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700643 FMT_THROW(WindowsError(error_code,
644 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700645 }
646}
647
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800648FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700649 if (s.size() > INT_MAX)
650 return ERROR_INVALID_PARAMETER;
651 int s_size = static_cast<int>(s.size());
652 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700653 if (length == 0)
654 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700655 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700656 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700657 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700658 if (length == 0)
659 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700660 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700661 return 0;
662}
663
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800664FMT_FUNC void fmt::WindowsError::init(
vitautba09c1b2015-06-26 09:23:11 -0700665 int err_code, CStringRef format_str, ArgList args) {
Carter Li3f574c12015-02-17 10:11:42 +0800666 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700667 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800668 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700669 std::runtime_error &base = *this;
670 base = std::runtime_error(w.str());
671}
672
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800673FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700674 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800675 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700676 class String {
677 private:
678 LPWSTR str_;
679
680 public:
681 String() : str_() {}
682 ~String() { LocalFree(str_); }
683 LPWSTR *ptr() { return &str_; }
684 LPCWSTR c_str() const { return str_; }
685 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700686 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700687 String system_message;
688 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
689 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
690 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
691 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
692 UTF16ToUTF8 utf8_message;
693 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
694 out << message << ": " << utf8_message;
695 return;
696 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700697 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700698 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700699 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700700}
vitaut24c309f2015-06-12 07:15:57 -0700701
702#endif // FMT_USE_WINDOWS_H
703
704FMT_FUNC void fmt::internal::format_system_error(
705 fmt::Writer &out, int error_code,
706 fmt::StringRef message) FMT_NOEXCEPT {
707 FMT_TRY {
708 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
709 buffer.resize(INLINE_BUFFER_SIZE);
710 for (;;) {
711 char *system_message = &buffer[0];
712 int result = safe_strerror(error_code, system_message, buffer.size());
713 if (result == 0) {
714 out << message << ": " << system_message;
715 return;
716 }
717 if (result != ERANGE)
718 break; // Can't get error message, report error code instead.
719 buffer.resize(buffer.size() * 2);
720 }
721 } FMT_CATCH(...) {}
722 format_error_code(out, error_code, message);
723}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700724
jamboree7487bde2015-06-10 09:32:59 +0800725template <typename Char>
vitauta98583d2015-06-10 08:49:22 -0700726void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800727 if (!map_.empty())
728 return;
vitauta98583d2015-06-10 08:49:22 -0700729 typedef internal::NamedArg<Char> NamedArg;
vitautfccff7b2015-06-11 07:19:00 -0700730 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700731 bool use_values =
732 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800733 if (use_values) {
734 for (unsigned i = 0;/*nothing*/; ++i) {
735 internal::Arg::Type arg_type = args.type(i);
736 switch (arg_type) {
737 case internal::Arg::NONE:
738 return;
739 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700740 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800741 map_.insert(Pair(named_arg->name, *named_arg));
742 break;
743 default:
744 /*nothing*/;
745 }
746 }
747 return;
748 }
vitauta98583d2015-06-10 08:49:22 -0700749 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800750 internal::Arg::Type arg_type = args.type(i);
751 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700752 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800753 map_.insert(Pair(named_arg->name, *named_arg));
754 }
755 }
vitauta98583d2015-06-10 08:49:22 -0700756 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800757 switch (args.args_[i].type) {
758 case internal::Arg::NONE:
759 return;
760 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700761 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800762 map_.insert(Pair(named_arg->name, *named_arg));
763 break;
764 default:
765 /*nothing*/;
766 }
767 }
768}
769
Victor Zverovichd1ded562014-09-29 08:48:16 -0700770template <typename Char>
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800771void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
772 FMT_THROW(std::runtime_error("buffer overflow"));
773}
774
775template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700776template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700777void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800778 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700779 // Check if StrChar is convertible to Char.
780 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700781 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700782 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800783 const StrChar *str_value = s.value;
784 std::size_t str_size = s.size;
785 if (str_size == 0) {
vitautcd097d32015-10-21 06:16:55 -0700786 if (!str_value) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700787 FMT_THROW(FormatError("string pointer is null"));
vitautcd097d32015-10-21 06:16:55 -0700788 return;
789 }
790 if (*str_value)
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800791 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700792 }
Victor Zverovich59254412015-02-06 07:27:19 -0800793 std::size_t precision = spec.precision_;
794 if (spec.precision_ >= 0 && precision < str_size)
Victor Zverovich43aebf52015-01-08 07:56:08 -0800795 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800796 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700797}
798
799template <typename Char>
jamboree7487bde2015-06-10 09:32:59 +0800800inline Arg fmt::BasicFormatter<Char>::get_arg(
vitautfccff7b2015-06-11 07:19:00 -0700801 BasicStringRef<Char> arg_name, const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800802 if (check_no_auto_index(error)) {
vitautfccff7b2015-06-11 07:19:00 -0700803 map_.init(args());
804 const Arg *arg = map_.find(arg_name);
jamboree7487bde2015-06-10 09:32:59 +0800805 if (arg)
806 return *arg;
807 error = "argument not found";
808 }
809 return Arg();
810}
811
812template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700813inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700814 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700815 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700816 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700817 if (error) {
818 FMT_THROW(FormatError(
819 *s != '}' && *s != ':' ? "invalid format string" : error));
820 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700821 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700822}
823
jamboree7487bde2015-06-10 09:32:59 +0800824template <typename Char>
825inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
826 assert(is_name_start(*s));
827 const Char *start = s;
828 Char c;
829 do {
830 c = *++s;
jamboree3c99ed42015-06-11 12:03:22 +0800831 } while (is_name_start(c) || ('0' <= c && c <= '9'));
jamboree7487bde2015-06-10 09:32:59 +0800832 const char *error = 0;
833 Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
834 if (error)
835 FMT_THROW(fmt::FormatError(error));
836 return arg;
837}
838
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800839FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700840 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700841 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800842 switch (arg.type) {
843 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700844 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800845 break;
846 case Arg::NAMED_ARG:
847 arg = *static_cast<const internal::Arg*>(arg.pointer);
848 default:
849 /*nothing*/;
850 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700851 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700852}
853
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700854inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700855 if (next_arg_index_ >= 0)
856 return do_get_arg(next_arg_index_++, error);
857 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700858 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700859}
860
vitautfccff7b2015-06-11 07:19:00 -0700861inline bool fmt::internal::FormatterBase::check_no_auto_index(
862 const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800863 if (next_arg_index_ > 0) {
864 error = "cannot switch from automatic to manual argument indexing";
865 return false;
866 }
vitautfccff7b2015-06-11 07:19:00 -0700867 next_arg_index_ = -1;
jamboree7487bde2015-06-10 09:32:59 +0800868 return true;
869}
870
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700871inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700872 unsigned arg_index, const char *&error) {
vitautfccff7b2015-06-11 07:19:00 -0700873 return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700874}
875
Victor Zverovich7cae7632013-09-06 20:23:42 -0700876template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700877void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700878 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700879 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700880 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700881 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700882 spec.align_ = ALIGN_LEFT;
883 break;
884 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700885 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
886 break;
887 case '0':
888 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700889 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700890 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700891 spec.flags_ |= SIGN_FLAG;
892 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700893 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700894 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700895 break;
896 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700897 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700898 return;
899 }
900 }
901}
902
Victor Zverovichcb743c02014-06-19 07:40:35 -0700903template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700904Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700905 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800906 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700907 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700908 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700909 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
910 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700911 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700912 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700913}
914
915template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700916unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700917 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700918 unsigned arg_index = UINT_MAX;
919 Char c = *s;
920 if (c >= '0' && c <= '9') {
921 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700922 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700923 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700924 if (*s == '$') { // value is an argument index
925 ++s;
926 arg_index = value;
927 } else {
928 if (c == '0')
929 spec.fill_ = '0';
930 if (value != 0) {
931 // Nonzero value means that we parsed width and don't need to
932 // parse it or flags again, so return now.
933 spec.width_ = value;
934 return arg_index;
935 }
936 }
937 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700938 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700939 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700940 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700941 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700942 } else if (*s == '*') {
943 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700944 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700945 }
946 return arg_index;
947}
948
Victor Zverovich1f19b982014-06-16 07:49:30 -0700949template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700950void fmt::internal::PrintfFormatter<Char>::format(
vitaut20003762015-07-28 08:09:29 -0700951 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800952 const Char *start = format_str.c_str();
Victor Zverovich7cae7632013-09-06 20:23:42 -0700953 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700954 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700955 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700956 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700957 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700958 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700959 start = ++s;
960 continue;
961 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700962 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700963
Victor Zverovichcb743c02014-06-19 07:40:35 -0700964 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700965 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700966
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700967 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700968 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700969
970 // Parse precision.
971 if (*s == '.') {
972 ++s;
973 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700974 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700975 } else if (*s == '*') {
976 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700977 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700978 }
979 }
980
Victor Zverovich56fc5252014-08-28 07:48:55 -0700981 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700982 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700983 spec.flags_ &= ~HASH_FLAG;
984 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700985 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700986 spec.align_ = ALIGN_NUMERIC;
987 else
988 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700989 }
990
Victor Zverovichf4156b52014-07-30 08:39:07 -0700991 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700992 switch (*s++) {
993 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700994 if (*s == 'h')
995 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700996 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700997 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700998 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700999 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -07001000 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -07001001 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -07001002 else
1003 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -07001004 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001005 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -07001006 ArgConverter<intmax_t>(arg, *s).visit(arg);
1007 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001008 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -07001009 ArgConverter<size_t>(arg, *s).visit(arg);
1010 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001011 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -07001012 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
1013 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001014 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -07001015 // printf produces garbage when 'L' is omitted for long double, no
1016 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001017 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -07001018 default:
1019 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -07001020 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001021 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001022
1023 // Parse type.
1024 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001025 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001026 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -07001027 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
1028 // Normalize type.
1029 switch (spec.type_) {
1030 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -07001031 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -07001032 break;
1033 case 'c':
1034 // TODO: handle wchar_t
1035 CharConverter(arg).visit(arg);
1036 break;
1037 }
Victor Zverovichf4156b52014-07-30 08:39:07 -07001038 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001039
1040 start = s;
1041
1042 // Format argument.
vitaut270069b2015-06-16 07:36:32 -07001043 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001044 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001045 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001046}
1047
1048template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001049const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001050 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001051 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -07001052 FormatSpec spec;
1053 if (*s == ':') {
1054 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001055 arg.custom.format(this, arg.custom.value, &s);
1056 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001057 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001058 ++s;
1059 // Parse fill and alignment.
1060 if (Char c = *s) {
1061 const Char *p = s + 1;
1062 spec.align_ = ALIGN_DEFAULT;
1063 do {
1064 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001065 case '<':
1066 spec.align_ = ALIGN_LEFT;
1067 break;
1068 case '>':
1069 spec.align_ = ALIGN_RIGHT;
1070 break;
1071 case '=':
1072 spec.align_ = ALIGN_NUMERIC;
1073 break;
1074 case '^':
1075 spec.align_ = ALIGN_CENTER;
1076 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001077 }
1078 if (spec.align_ != ALIGN_DEFAULT) {
1079 if (p != s) {
1080 if (c == '}') break;
1081 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001082 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001083 s += 2;
1084 spec.fill_ = c;
1085 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001086 if (spec.align_ == ALIGN_NUMERIC)
1087 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -07001088 break;
1089 }
1090 } while (--p >= s);
1091 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001092
Victor Zveroviche8251562014-07-08 16:20:33 -07001093 // Parse sign.
1094 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001095 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001096 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001097 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1098 break;
1099 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001100 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001101 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001102 break;
1103 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001104 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001105 spec.flags_ |= SIGN_FLAG;
1106 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001107 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001108
Victor Zveroviche8251562014-07-08 16:20:33 -07001109 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001110 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -07001111 spec.flags_ |= HASH_FLAG;
1112 ++s;
1113 }
1114
jamboree54a6cb32015-06-04 13:59:37 +08001115 // Parse zero flag.
1116 if (*s == '0') {
vitaut8949a2e2015-06-08 06:53:18 -07001117 require_numeric_argument(arg, '0');
1118 spec.align_ = ALIGN_NUMERIC;
1119 spec.fill_ = '0';
1120 ++s;
jamboree54a6cb32015-06-04 13:59:37 +08001121 }
1122
1123 // Parse width.
1124 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001125 spec.width_ = parse_nonnegative_int(s);
jamboree54a6cb32015-06-04 13:59:37 +08001126 } else if (*s == '{') {
vitaut8949a2e2015-06-08 06:53:18 -07001127 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001128 Arg width_arg = is_name_start(*s) ?
1129 parse_arg_name(s) : parse_arg_index(s);
vitaut8949a2e2015-06-08 06:53:18 -07001130 if (*s++ != '}')
1131 FMT_THROW(FormatError("invalid format string"));
1132 ULongLong value = 0;
1133 switch (width_arg.type) {
1134 case Arg::INT:
1135 if (width_arg.int_value < 0)
1136 FMT_THROW(FormatError("negative width"));
1137 value = width_arg.int_value;
1138 break;
1139 case Arg::UINT:
1140 value = width_arg.uint_value;
1141 break;
1142 case Arg::LONG_LONG:
1143 if (width_arg.long_long_value < 0)
1144 FMT_THROW(FormatError("negative width"));
1145 value = width_arg.long_long_value;
1146 break;
1147 case Arg::ULONG_LONG:
1148 value = width_arg.ulong_long_value;
1149 break;
1150 default:
1151 FMT_THROW(FormatError("width is not integer"));
1152 }
1153 if (value > INT_MAX)
1154 FMT_THROW(FormatError("number is too big"));
1155 spec.width_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001156 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001157
Victor Zveroviche8251562014-07-08 16:20:33 -07001158 // Parse precision.
1159 if (*s == '.') {
1160 ++s;
1161 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001162 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001163 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001164 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001165 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001166 Arg precision_arg =
1167 is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001168 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001169 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001170 ULongLong value = 0;
1171 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001172 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001173 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001174 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001175 value = precision_arg.int_value;
1176 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001177 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001178 value = precision_arg.uint_value;
1179 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001180 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001181 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001182 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001183 value = precision_arg.long_long_value;
1184 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001185 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001186 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001187 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001188 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001189 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001190 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001191 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001192 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001193 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001194 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001195 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001196 }
vitautfd5c2e92015-06-11 08:58:31 -07001197 if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001198 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001199 fmt::format("precision not allowed in {} format specifier",
1200 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001201 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001202 }
1203
Victor Zveroviche8251562014-07-08 16:20:33 -07001204 // Parse type.
1205 if (*s != '}' && *s)
1206 spec.type_ = static_cast<char>(*s++);
1207 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001208
Victor Zveroviche8251562014-07-08 16:20:33 -07001209 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001210 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001211
1212 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001213 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001214 return s;
1215}
1216
1217template <typename Char>
vitaut20003762015-07-28 08:09:29 -07001218void fmt::BasicFormatter<Char>::format(BasicCStringRef<Char> format_str) {
vitaut0eac0372015-07-28 06:46:41 -07001219 const Char *s = format_str.c_str();
1220 const Char *start = s;
Victor Zveroviche8251562014-07-08 16:20:33 -07001221 while (*s) {
1222 Char c = *s++;
1223 if (c != '{' && c != '}') continue;
1224 if (*s == c) {
vitaut0eac0372015-07-28 06:46:41 -07001225 write(writer_, start, s);
1226 start = ++s;
Victor Zveroviche8251562014-07-08 16:20:33 -07001227 continue;
1228 }
1229 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001230 FMT_THROW(FormatError("unmatched '}' in format string"));
vitaut0eac0372015-07-28 06:46:41 -07001231 write(writer_, start, s - 1);
jamboree7487bde2015-06-10 09:32:59 +08001232 Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
vitaut0eac0372015-07-28 06:46:41 -07001233 start = s = format(s, arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001234 }
vitaut0eac0372015-07-28 06:46:41 -07001235 write(writer_, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001236}
1237
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001238FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001239 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001240 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001241}
1242
vitaut24c309f2015-06-12 07:15:57 -07001243#if FMT_USE_WINDOWS_H
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001244FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001245 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001246 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001247}
Victor Zverovich400812a2014-04-30 12:38:17 -07001248#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001249
vitaut438bd9b2015-06-26 07:43:54 -07001250FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001251 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001252 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001253 std::fwrite(w.data(), 1, w.size(), f);
1254}
1255
vitaut438bd9b2015-06-26 07:43:54 -07001256FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001257 print(stdout, format_str, args);
1258}
1259
vitaut438bd9b2015-06-26 07:43:54 -07001260FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001261 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001262 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001263 os.write(w.data(), w.size());
1264}
1265
vitaut438bd9b2015-06-26 07:43:54 -07001266FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001267 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +01001268 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001269 std::fputs(escape, stdout);
1270 print(format, args);
1271 std::fputs(RESET_COLOR, stdout);
1272}
1273
vitaut438bd9b2015-06-26 07:43:54 -07001274FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001275 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001276 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001277 std::size_t size = w.size();
1278 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001279}
1280
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001281#ifndef FMT_HEADER_ONLY
1282
vitaut9ca1ce22015-05-23 08:04:06 -07001283template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -07001284
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001285// Explicit instantiations for char.
1286
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001287template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
1288
Victor Zverovichf43caef2014-09-25 07:21:48 -07001289template const char *fmt::BasicFormatter<char>::format(
1290 const char *&format_str, const fmt::internal::Arg &arg);
1291
vitaut20003762015-07-28 08:09:29 -07001292template void fmt::BasicFormatter<char>::format(CStringRef format);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001293
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001294template void fmt::internal::PrintfFormatter<char>::format(
vitaut20003762015-07-28 08:09:29 -07001295 BasicWriter<char> &writer, CStringRef format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001296
Victor Zverovich14f25772014-09-19 08:45:05 -07001297template int fmt::internal::CharTraits<char>::format_float(
1298 char *buffer, std::size_t size, const char *format,
1299 unsigned width, int precision, double value);
1300
1301template int fmt::internal::CharTraits<char>::format_float(
1302 char *buffer, std::size_t size, const char *format,
1303 unsigned width, int precision, long double value);
1304
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001305// Explicit instantiations for wchar_t.
1306
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001307template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1308
Victor Zverovichf43caef2014-09-25 07:21:48 -07001309template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1310 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1311
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001312template void fmt::BasicFormatter<wchar_t>::format(
vitaut20003762015-07-28 08:09:29 -07001313 BasicCStringRef<wchar_t> format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001314
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001315template void fmt::internal::PrintfFormatter<wchar_t>::format(
vitaut20003762015-07-28 08:09:29 -07001316 BasicWriter<wchar_t> &writer, WCStringRef format);
jdale88a9862fd2014-03-11 18:56:24 +00001317
Victor Zverovich14f25772014-09-19 08:45:05 -07001318template int fmt::internal::CharTraits<wchar_t>::format_float(
1319 wchar_t *buffer, std::size_t size, const wchar_t *format,
1320 unsigned width, int precision, double value);
1321
1322template int fmt::internal::CharTraits<wchar_t>::format_float(
1323 wchar_t *buffer, std::size_t size, const wchar_t *format,
1324 unsigned width, int precision, long double value);
1325
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001326#endif // FMT_HEADER_ONLY
1327
Ingo van Lilb4b13ee2015-11-02 12:34:46 +01001328#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +00001329# pragma warning(pop)
1330#endif