blob: 5103c61fd5a8ecf88e4edbd784691b7bbd518bf2 [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.
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) {
143 return value >= INT_MIN && value <= INT_MAX;
144 }
145};
146
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800147const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700148
Victor Zverovich22f75d82014-09-03 08:03:05 -0700149typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
150
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700151// Portable thread-safe version of strerror.
152// Sets buffer to point to a string describing the error code.
153// This can be either a pointer to a string stored in buffer,
154// or a pointer to some static immutable string.
155// Returns one of the following values:
156// 0 - success
157// ERANGE - buffer is not large enough to store the error message
158// other - failure
159// Buffer should be at least of size 1.
160int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800161 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
vitaut8ab665a2015-06-22 08:17:23 -0700162 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700163
vitaut341b98c2015-03-14 13:39:33 -0700164 class StrError {
165 private:
166 int error_code_;
167 char *&buffer_;
168 std::size_t buffer_size_;
169
vitautda052ae2015-03-21 07:53:39 -0700170 // A noop assignment operator to avoid bogus warnings.
171 void operator=(const StrError &) {}
172
vitaut341b98c2015-03-14 13:39:33 -0700173 // Handle the result of XSI-compliant version of strerror_r.
174 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700175 // glibc versions before 2.13 return result in errno.
176 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700177 }
178
179 // Handle the result of GNU-specific version of strerror_r.
180 int handle(char *message) {
181 // If the buffer is full then the message is probably truncated.
182 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
183 return ERANGE;
184 buffer_ = message;
185 return 0;
186 }
187
188 // Handle the case when strerror_r is not available.
vitautc669cbe2015-07-07 07:05:17 -0700189 int handle(fmt::internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700190 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
191 }
192
193 // Fallback to strerror_s when strerror_r is not available.
194 int fallback(int result) {
195 // If the buffer is full then the message is probably truncated.
196 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
197 ERANGE : result;
198 }
199
200 // Fallback to strerror if strerror_r and strerror_s are not available.
vitautc669cbe2015-07-07 07:05:17 -0700201 int fallback(fmt::internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700202 errno = 0;
203 buffer_ = strerror(error_code_);
204 return errno;
205 }
206
207 public:
208 StrError(int error_code, char *&buffer, std::size_t buffer_size)
209 : error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {}
210
vitaut63f6c102015-06-14 09:36:23 -0700211 int run() {
212 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
213 return handle(strerror_r(error_code_, buffer_, buffer_size_));
214 }
vitaut341b98c2015-03-14 13:39:33 -0700215 };
216 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700217}
218
Victor Zverovich22f75d82014-09-03 08:03:05 -0700219void format_error_code(fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800220 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700221 // Report error code making sure that the output fits into
222 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
223 // bad_alloc.
224 out.clear();
225 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700226 static const char ERROR_STR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700227 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
vitaut1addec92015-03-21 20:16:36 -0700228 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
229 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
230 error_code_size += fmt::internal::count_digits(ec_value);
Victor Zverovich88e0db82014-09-05 08:04:26 -0700231 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700232 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700233 out << ERROR_STR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700234 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
235}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700236
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700237void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800238 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700239 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700240 func(full_message, error_code, message);
241 // Use Writer::data instead of Writer::c_str to avoid potential memory
242 // allocation.
243 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
244 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700245}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700246
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700247// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
248class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
249 public:
250 template <typename T>
251 bool visit_any_int(T value) { return value == 0; }
252};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700253
254// Parses an unsigned integer advancing s to the end of the parsed input.
255// This function assumes that the first character of s is a digit.
256template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700257int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700258 assert('0' <= *s && *s <= '9');
259 unsigned value = 0;
260 do {
261 unsigned new_value = value * 10 + (*s++ - '0');
262 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700263 if (new_value < value) {
264 value = UINT_MAX;
265 break;
266 }
267 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700268 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700269 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700270 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700271 return value;
272}
Victor Zveroviche8251562014-07-08 16:20:33 -0700273
jamboree7487bde2015-06-10 09:32:59 +0800274template <typename Char>
275inline bool is_name_start(Char c) {
276 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
277}
278
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700279inline void require_numeric_argument(const Arg &arg, char spec) {
280 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700281 std::string message =
282 fmt::format("format specifier '{}' requires numeric argument", spec);
283 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700284 }
285}
286
Victor Zveroviche8251562014-07-08 16:20:33 -0700287template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700288void check_sign(const Char *&s, const Arg &arg) {
289 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700290 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700291 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700292 FMT_THROW(fmt::FormatError(fmt::format(
293 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700294 }
295 ++s;
296}
297
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700298// Checks if an argument is a valid printf width specifier and sets
299// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700300class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700301 private:
302 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700303
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800304 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
305
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700306 public:
307 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700308
vitautd4ea2d72015-03-26 08:55:20 -0700309 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700310 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700311 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700312
Victor Zverovich9d74f952014-07-16 07:27:54 -0700313 template <typename T>
314 unsigned visit_any_int(T value) {
315 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
316 UnsignedType width = value;
317 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700318 spec_.align_ = fmt::ALIGN_LEFT;
319 width = 0 - width;
320 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700321 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700322 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700323 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700324 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700325};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700326
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700327class PrecisionHandler :
328 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
329 public:
vitautd4ea2d72015-03-26 08:55:20 -0700330 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700331 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700332 }
333
334 template <typename T>
335 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700336 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700337 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700338 return static_cast<int>(value);
339 }
340};
341
Victor Zverovich32344d92014-08-28 08:11:21 -0700342// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700343template <typename T>
344class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
345 private:
346 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700347 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700348
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800349 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
350
Victor Zverovicheeca2232014-07-30 07:37:16 -0700351 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700352 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
353 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700354
355 template <typename U>
356 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700357 bool is_signed = type_ == 'd' || type_ == 'i';
358 using fmt::internal::Arg;
359 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700360 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700361 if (is_signed) {
362 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700363 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700364 } else {
365 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700366 arg_.uint_value = static_cast<unsigned>(
367 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700368 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700369 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700370 if (is_signed) {
371 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700372 arg_.long_long_value =
373 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700374 } else {
375 arg_.type = Arg::ULONG_LONG;
376 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700377 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700378 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700379 }
380 }
381};
382
Victor Zverovich32344d92014-08-28 08:11:21 -0700383// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700384class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
385 private:
386 fmt::internal::Arg &arg_;
387
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800388 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
389
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700390 public:
391 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
392
393 template <typename T>
394 void visit_any_int(T value) {
395 arg_.type = Arg::CHAR;
396 arg_.int_value = static_cast<char>(value);
397 }
398};
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700399} // namespace
vitaut270069b2015-06-16 07:36:32 -0700400
401namespace internal {
402
403template <typename Impl, typename Char>
404class BasicArgFormatter : public ArgVisitor<Impl, void> {
405 private:
406 BasicWriter<Char> &writer_;
407 FormatSpec &spec_;
408
409 FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
410
411 protected:
412 BasicWriter<Char> &writer() { return writer_; }
413 const FormatSpec &spec() const { return spec_; }
414
415 public:
416 BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
417 : writer_(w), spec_(s) {}
418
419 template <typename T>
420 void visit_any_int(T value) { writer_.write_int(value, spec_); }
421
422 template <typename T>
423 void visit_any_double(T value) { writer_.write_double(value, spec_); }
424
425 void visit_bool(bool value) {
426 if (spec_.type_) {
427 writer_.write_int(value, spec_);
428 return;
429 }
430 const char *str_value = value ? "true" : "false";
431 Arg::StringValue<char> str = { str_value, strlen(str_value) };
432 writer_.write_str(str, spec_);
433 }
434
435 void visit_char(int value) {
436 if (spec_.type_ && spec_.type_ != 'c') {
437 spec_.flags_ |= CHAR_FLAG;
438 writer_.write_int(value, spec_);
439 return;
440 }
441 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
442 FMT_THROW(FormatError("invalid format specifier for char"));
443 typedef typename BasicWriter<Char>::CharPtr CharPtr;
vitaut147e5eb2015-06-17 07:21:16 -0700444 Char fill = internal::CharTraits<Char>::cast(spec_.fill());
vitaut270069b2015-06-16 07:36:32 -0700445 CharPtr out = CharPtr();
446 if (spec_.width_ > 1) {
447 out = writer_.grow_buffer(spec_.width_);
448 if (spec_.align_ == ALIGN_RIGHT) {
449 std::fill_n(out, spec_.width_ - 1, fill);
450 out += spec_.width_ - 1;
451 } else if (spec_.align_ == ALIGN_CENTER) {
452 out = writer_.fill_padding(out, spec_.width_, 1, fill);
453 } else {
454 std::fill_n(out + 1, spec_.width_ - 1, fill);
455 }
456 } else {
457 out = writer_.grow_buffer(1);
458 }
vitaut147e5eb2015-06-17 07:21:16 -0700459 *out = internal::CharTraits<Char>::cast(value);
vitaut270069b2015-06-16 07:36:32 -0700460 }
461
462 void visit_string(Arg::StringValue<char> value) {
463 writer_.write_str(value, spec_);
464 }
465
466 using ArgVisitor<Impl, void>::visit_wstring;
467
468 void visit_wstring(Arg::StringValue<Char> value) {
469 writer_.write_str(value, spec_);
470 }
471
472 void visit_pointer(const void *value) {
473 if (spec_.type_ && spec_.type_ != 'p')
474 report_unknown_type(spec_.type_, "pointer");
475 spec_.flags_ = HASH_FLAG;
476 spec_.type_ = 'x';
477 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
478 }
479};
480
481// An argument formatter.
482template <typename Char>
483class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
484 private:
485 BasicFormatter<Char> &formatter_;
486 const Char *format_;
487
488 public:
489 ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
490 : BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
491 formatter_(f), format_(fmt) {}
492
493 void visit_custom(Arg::CustomValue c) {
494 c.format(&formatter_, c.value, &format_);
495 }
496};
497
498template <typename Char>
499class PrintfArgFormatter :
500 public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
501 public:
502 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
503 : BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
504
505 void visit_char(int value) {
506 const FormatSpec &spec = this->spec();
507 BasicWriter<Char> &writer = this->writer();
508 if (spec.type_ && spec.type_ != 'c')
509 writer.write_int(value, spec);
510 typedef typename BasicWriter<Char>::CharPtr CharPtr;
511 CharPtr out = CharPtr();
512 if (spec.width_ > 1) {
513 Char fill = ' ';
514 out = writer.grow_buffer(spec.width_);
515 if (spec.align_ != ALIGN_LEFT) {
516 std::fill_n(out, spec.width_ - 1, fill);
517 out += spec.width_ - 1;
518 } else {
519 std::fill_n(out + 1, spec.width_ - 1, fill);
520 }
521 } else {
522 out = writer.grow_buffer(1);
523 }
524 *out = static_cast<Char>(value);
525 }
526};
527} // namespace internal
vitaut8725d072015-06-12 07:56:58 -0700528} // namespace fmt
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700529
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800530FMT_FUNC void fmt::SystemError::init(
vitaut438bd9b2015-06-26 07:43:54 -0700531 int err_code, CStringRef format_str, ArgList args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800532 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700533 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800534 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700535 std::runtime_error &base = *this;
536 base = std::runtime_error(w.str());
537}
538
Victor Zverovichb605b392013-09-09 22:21:40 -0700539template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700540int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700541 char *buffer, std::size_t size, const char *format,
542 unsigned width, int precision, T value) {
543 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700544 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700545 FMT_SNPRINTF(buffer, size, format, value) :
546 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700547 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700548 return precision < 0 ?
549 FMT_SNPRINTF(buffer, size, format, width, value) :
550 FMT_SNPRINTF(buffer, size, format, width, precision, value);
551}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700552
Victor Zverovichb605b392013-09-09 22:21:40 -0700553template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700554int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700555 wchar_t *buffer, std::size_t size, const wchar_t *format,
556 unsigned width, int precision, T value) {
557 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700558 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000559 FMT_SWPRINTF(buffer, size, format, value) :
560 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700561 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700562 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000563 FMT_SWPRINTF(buffer, size, format, width, value) :
564 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700565}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800566
Victor Zverovich311251e2014-11-29 06:58:00 -0800567template <typename T>
568const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800569 "0001020304050607080910111213141516171819"
570 "2021222324252627282930313233343536373839"
571 "4041424344454647484950515253545556575859"
572 "6061626364656667686970717273747576777879"
573 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800574
Victor Zverovichf1d85162014-02-19 13:02:22 -0800575#define FMT_POWERS_OF_10(factor) \
576 factor * 10, \
577 factor * 100, \
578 factor * 1000, \
579 factor * 10000, \
580 factor * 100000, \
581 factor * 1000000, \
582 factor * 10000000, \
583 factor * 100000000, \
584 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800585
Victor Zverovich311251e2014-11-29 06:58:00 -0800586template <typename T>
587const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
588 0, FMT_POWERS_OF_10(1)
589};
590
591template <typename T>
592const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800593 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800594 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800595 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700596 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800597 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800598 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800599};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800600
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800601FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800602 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800603 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700604 FMT_THROW(fmt::FormatError(
605 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800606 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700607 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700608 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700609 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800610}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700611
vitaut24c309f2015-06-12 07:15:57 -0700612#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700613
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800614FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700615 int length = MultiByteToWideChar(
vitautba09c1b2015-06-26 09:23:11 -0700616 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0);
Victor Zverovichdff21372014-12-16 07:01:01 -0800617 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700618 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800619 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700620 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700621 length = MultiByteToWideChar(
vitautba09c1b2015-06-26 09:23:11 -0700622 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700623 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800624 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700625 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700626}
627
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800628FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700629 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700630 FMT_THROW(WindowsError(error_code,
631 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700632 }
633}
634
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800635FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
vitautba09c1b2015-06-26 09:23:11 -0700636 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700637 if (length == 0)
638 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700639 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700640 length = WideCharToMultiByte(
vitautba09c1b2015-06-26 09:23:11 -0700641 CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700642 if (length == 0)
643 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700644 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700645 return 0;
646}
647
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800648FMT_FUNC void fmt::WindowsError::init(
vitautba09c1b2015-06-26 09:23:11 -0700649 int err_code, CStringRef format_str, ArgList args) {
Carter Li3f574c12015-02-17 10:11:42 +0800650 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700651 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800652 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700653 std::runtime_error &base = *this;
654 base = std::runtime_error(w.str());
655}
656
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800657FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700658 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800659 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700660 class String {
661 private:
662 LPWSTR str_;
663
664 public:
665 String() : str_() {}
666 ~String() { LocalFree(str_); }
667 LPWSTR *ptr() { return &str_; }
668 LPCWSTR c_str() const { return str_; }
669 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700670 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700671 String system_message;
672 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
673 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
674 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
675 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
676 UTF16ToUTF8 utf8_message;
677 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
678 out << message << ": " << utf8_message;
679 return;
680 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700681 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700682 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700683 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700684}
vitaut24c309f2015-06-12 07:15:57 -0700685
686#endif // FMT_USE_WINDOWS_H
687
688FMT_FUNC void fmt::internal::format_system_error(
689 fmt::Writer &out, int error_code,
690 fmt::StringRef message) FMT_NOEXCEPT {
691 FMT_TRY {
692 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
693 buffer.resize(INLINE_BUFFER_SIZE);
694 for (;;) {
695 char *system_message = &buffer[0];
696 int result = safe_strerror(error_code, system_message, buffer.size());
697 if (result == 0) {
698 out << message << ": " << system_message;
699 return;
700 }
701 if (result != ERANGE)
702 break; // Can't get error message, report error code instead.
703 buffer.resize(buffer.size() * 2);
704 }
705 } FMT_CATCH(...) {}
706 format_error_code(out, error_code, message);
707}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700708
jamboree7487bde2015-06-10 09:32:59 +0800709template <typename Char>
vitauta98583d2015-06-10 08:49:22 -0700710void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800711 if (!map_.empty())
712 return;
vitauta98583d2015-06-10 08:49:22 -0700713 typedef internal::NamedArg<Char> NamedArg;
vitautfccff7b2015-06-11 07:19:00 -0700714 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700715 bool use_values =
716 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800717 if (use_values) {
718 for (unsigned i = 0;/*nothing*/; ++i) {
719 internal::Arg::Type arg_type = args.type(i);
720 switch (arg_type) {
721 case internal::Arg::NONE:
722 return;
723 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700724 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800725 map_.insert(Pair(named_arg->name, *named_arg));
726 break;
727 default:
728 /*nothing*/;
729 }
730 }
731 return;
732 }
vitauta98583d2015-06-10 08:49:22 -0700733 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800734 internal::Arg::Type arg_type = args.type(i);
735 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700736 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800737 map_.insert(Pair(named_arg->name, *named_arg));
738 }
739 }
vitauta98583d2015-06-10 08:49:22 -0700740 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800741 switch (args.args_[i].type) {
742 case internal::Arg::NONE:
743 return;
744 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700745 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800746 map_.insert(Pair(named_arg->name, *named_arg));
747 break;
748 default:
749 /*nothing*/;
750 }
751 }
752}
753
Victor Zverovichd1ded562014-09-29 08:48:16 -0700754template <typename Char>
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800755void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
756 FMT_THROW(std::runtime_error("buffer overflow"));
757}
758
759template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700760template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700761void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800762 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700763 // Check if StrChar is convertible to Char.
764 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700765 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700766 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800767 const StrChar *str_value = s.value;
768 std::size_t str_size = s.size;
769 if (str_size == 0) {
770 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700771 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800772 if (*str_value)
773 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700774 }
Victor Zverovich59254412015-02-06 07:27:19 -0800775 std::size_t precision = spec.precision_;
776 if (spec.precision_ >= 0 && precision < str_size)
Victor Zverovich43aebf52015-01-08 07:56:08 -0800777 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800778 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700779}
780
781template <typename Char>
jamboree7487bde2015-06-10 09:32:59 +0800782inline Arg fmt::BasicFormatter<Char>::get_arg(
vitautfccff7b2015-06-11 07:19:00 -0700783 BasicStringRef<Char> arg_name, const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800784 if (check_no_auto_index(error)) {
vitautfccff7b2015-06-11 07:19:00 -0700785 map_.init(args());
786 const Arg *arg = map_.find(arg_name);
jamboree7487bde2015-06-10 09:32:59 +0800787 if (arg)
788 return *arg;
789 error = "argument not found";
790 }
791 return Arg();
792}
793
794template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700795inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700796 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700797 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700798 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700799 if (error) {
800 FMT_THROW(FormatError(
801 *s != '}' && *s != ':' ? "invalid format string" : error));
802 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700803 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700804}
805
jamboree7487bde2015-06-10 09:32:59 +0800806template <typename Char>
807inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
808 assert(is_name_start(*s));
809 const Char *start = s;
810 Char c;
811 do {
812 c = *++s;
jamboree3c99ed42015-06-11 12:03:22 +0800813 } while (is_name_start(c) || ('0' <= c && c <= '9'));
jamboree7487bde2015-06-10 09:32:59 +0800814 const char *error = 0;
815 Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
816 if (error)
817 FMT_THROW(fmt::FormatError(error));
818 return arg;
819}
820
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800821FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700822 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700823 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800824 switch (arg.type) {
825 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700826 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800827 break;
828 case Arg::NAMED_ARG:
829 arg = *static_cast<const internal::Arg*>(arg.pointer);
830 default:
831 /*nothing*/;
832 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700833 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700834}
835
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700836inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700837 if (next_arg_index_ >= 0)
838 return do_get_arg(next_arg_index_++, error);
839 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700840 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700841}
842
vitautfccff7b2015-06-11 07:19:00 -0700843inline bool fmt::internal::FormatterBase::check_no_auto_index(
844 const char *&error) {
jamboree7487bde2015-06-10 09:32:59 +0800845 if (next_arg_index_ > 0) {
846 error = "cannot switch from automatic to manual argument indexing";
847 return false;
848 }
vitautfccff7b2015-06-11 07:19:00 -0700849 next_arg_index_ = -1;
jamboree7487bde2015-06-10 09:32:59 +0800850 return true;
851}
852
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700853inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700854 unsigned arg_index, const char *&error) {
vitautfccff7b2015-06-11 07:19:00 -0700855 return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700856}
857
Victor Zverovich7cae7632013-09-06 20:23:42 -0700858template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700859void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700860 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700861 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700862 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700863 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700864 spec.align_ = ALIGN_LEFT;
865 break;
866 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700867 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
868 break;
869 case '0':
870 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700871 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700872 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700873 spec.flags_ |= SIGN_FLAG;
874 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700875 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700876 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700877 break;
878 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700879 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700880 return;
881 }
882 }
883}
884
Victor Zverovichcb743c02014-06-19 07:40:35 -0700885template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700886Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700887 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800888 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700889 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700890 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700891 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
892 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700893 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700894 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700895}
896
897template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700898unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700899 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700900 unsigned arg_index = UINT_MAX;
901 Char c = *s;
902 if (c >= '0' && c <= '9') {
903 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700904 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700905 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700906 if (*s == '$') { // value is an argument index
907 ++s;
908 arg_index = value;
909 } else {
910 if (c == '0')
911 spec.fill_ = '0';
912 if (value != 0) {
913 // Nonzero value means that we parsed width and don't need to
914 // parse it or flags again, so return now.
915 spec.width_ = value;
916 return arg_index;
917 }
918 }
919 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700920 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700921 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700922 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700923 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700924 } else if (*s == '*') {
925 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700926 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700927 }
928 return arg_index;
929}
930
Victor Zverovich1f19b982014-06-16 07:49:30 -0700931template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700932void fmt::internal::PrintfFormatter<Char>::format(
vitaut438bd9b2015-06-26 07:43:54 -0700933 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700934 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800935 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700936 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700937 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700938 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700939 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700940 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700941 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700942 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700943 start = ++s;
944 continue;
945 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700946 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700947
Victor Zverovichcb743c02014-06-19 07:40:35 -0700948 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700949 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700950
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700951 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700952 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700953
954 // Parse precision.
955 if (*s == '.') {
956 ++s;
957 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700958 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700959 } else if (*s == '*') {
960 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700961 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700962 }
963 }
964
Victor Zverovich56fc5252014-08-28 07:48:55 -0700965 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700966 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700967 spec.flags_ &= ~HASH_FLAG;
968 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700969 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700970 spec.align_ = ALIGN_NUMERIC;
971 else
972 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700973 }
974
Victor Zverovichf4156b52014-07-30 08:39:07 -0700975 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700976 switch (*s++) {
977 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700978 if (*s == 'h')
979 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700980 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700981 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700982 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700983 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700984 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700985 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700986 else
987 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700988 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700989 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700990 ArgConverter<intmax_t>(arg, *s).visit(arg);
991 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700992 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700993 ArgConverter<size_t>(arg, *s).visit(arg);
994 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700995 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700996 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
997 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700998 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700999 // printf produces garbage when 'L' is omitted for long double, no
1000 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001001 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -07001002 default:
1003 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -07001004 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001005 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001006
1007 // Parse type.
1008 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001009 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001010 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -07001011 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
1012 // Normalize type.
1013 switch (spec.type_) {
1014 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -07001015 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -07001016 break;
1017 case 'c':
1018 // TODO: handle wchar_t
1019 CharConverter(arg).visit(arg);
1020 break;
1021 }
Victor Zverovichf4156b52014-07-30 08:39:07 -07001022 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001023
1024 start = s;
1025
1026 // Format argument.
vitaut270069b2015-06-16 07:36:32 -07001027 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001028 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001029 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001030}
1031
1032template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -07001033const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001034 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -07001035 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -07001036 FormatSpec spec;
1037 if (*s == ':') {
1038 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -07001039 arg.custom.format(this, arg.custom.value, &s);
1040 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001041 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001042 ++s;
1043 // Parse fill and alignment.
1044 if (Char c = *s) {
1045 const Char *p = s + 1;
1046 spec.align_ = ALIGN_DEFAULT;
1047 do {
1048 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001049 case '<':
1050 spec.align_ = ALIGN_LEFT;
1051 break;
1052 case '>':
1053 spec.align_ = ALIGN_RIGHT;
1054 break;
1055 case '=':
1056 spec.align_ = ALIGN_NUMERIC;
1057 break;
1058 case '^':
1059 spec.align_ = ALIGN_CENTER;
1060 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001061 }
1062 if (spec.align_ != ALIGN_DEFAULT) {
1063 if (p != s) {
1064 if (c == '}') break;
1065 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001066 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001067 s += 2;
1068 spec.fill_ = c;
1069 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001070 if (spec.align_ == ALIGN_NUMERIC)
1071 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -07001072 break;
1073 }
1074 } while (--p >= s);
1075 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001076
Victor Zveroviche8251562014-07-08 16:20:33 -07001077 // Parse sign.
1078 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001079 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001080 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001081 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
1082 break;
1083 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001084 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -07001085 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001086 break;
1087 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001088 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001089 spec.flags_ |= SIGN_FLAG;
1090 break;
Victor Zveroviche8251562014-07-08 16:20:33 -07001091 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001092
Victor Zveroviche8251562014-07-08 16:20:33 -07001093 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -07001094 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -07001095 spec.flags_ |= HASH_FLAG;
1096 ++s;
1097 }
1098
jamboree54a6cb32015-06-04 13:59:37 +08001099 // Parse zero flag.
1100 if (*s == '0') {
vitaut8949a2e2015-06-08 06:53:18 -07001101 require_numeric_argument(arg, '0');
1102 spec.align_ = ALIGN_NUMERIC;
1103 spec.fill_ = '0';
1104 ++s;
jamboree54a6cb32015-06-04 13:59:37 +08001105 }
1106
1107 // Parse width.
1108 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001109 spec.width_ = parse_nonnegative_int(s);
jamboree54a6cb32015-06-04 13:59:37 +08001110 } else if (*s == '{') {
vitaut8949a2e2015-06-08 06:53:18 -07001111 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001112 Arg width_arg = is_name_start(*s) ?
1113 parse_arg_name(s) : parse_arg_index(s);
vitaut8949a2e2015-06-08 06:53:18 -07001114 if (*s++ != '}')
1115 FMT_THROW(FormatError("invalid format string"));
1116 ULongLong value = 0;
1117 switch (width_arg.type) {
1118 case Arg::INT:
1119 if (width_arg.int_value < 0)
1120 FMT_THROW(FormatError("negative width"));
1121 value = width_arg.int_value;
1122 break;
1123 case Arg::UINT:
1124 value = width_arg.uint_value;
1125 break;
1126 case Arg::LONG_LONG:
1127 if (width_arg.long_long_value < 0)
1128 FMT_THROW(FormatError("negative width"));
1129 value = width_arg.long_long_value;
1130 break;
1131 case Arg::ULONG_LONG:
1132 value = width_arg.ulong_long_value;
1133 break;
1134 default:
1135 FMT_THROW(FormatError("width is not integer"));
1136 }
1137 if (value > INT_MAX)
1138 FMT_THROW(FormatError("number is too big"));
1139 spec.width_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001140 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001141
Victor Zveroviche8251562014-07-08 16:20:33 -07001142 // Parse precision.
1143 if (*s == '.') {
1144 ++s;
1145 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001146 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001147 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001148 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001149 ++s;
vitautfccff7b2015-06-11 07:19:00 -07001150 Arg precision_arg =
1151 is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001152 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001153 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001154 ULongLong value = 0;
1155 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001156 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001157 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001158 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001159 value = precision_arg.int_value;
1160 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001161 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001162 value = precision_arg.uint_value;
1163 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001164 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001165 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001166 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001167 value = precision_arg.long_long_value;
1168 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001169 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001170 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001171 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001172 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001173 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001174 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001175 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001176 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001177 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001178 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001179 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001180 }
vitautfd5c2e92015-06-11 08:58:31 -07001181 if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001182 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001183 fmt::format("precision not allowed in {} format specifier",
1184 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001185 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001186 }
1187
Victor Zveroviche8251562014-07-08 16:20:33 -07001188 // Parse type.
1189 if (*s != '}' && *s)
1190 spec.type_ = static_cast<char>(*s++);
1191 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001192
Victor Zveroviche8251562014-07-08 16:20:33 -07001193 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001194 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001195
1196 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001197 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001198 return s;
1199}
1200
1201template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001202void fmt::BasicFormatter<Char>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001203 BasicCStringRef<Char> format_str, const ArgList &args) {
vitaut0eac0372015-07-28 06:46:41 -07001204 const Char *s = format_str.c_str();
1205 const Char *start = s;
Victor Zverovich605d2602014-08-29 07:45:55 -07001206 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001207 while (*s) {
1208 Char c = *s++;
1209 if (c != '{' && c != '}') continue;
1210 if (*s == c) {
vitaut0eac0372015-07-28 06:46:41 -07001211 write(writer_, start, s);
1212 start = ++s;
Victor Zveroviche8251562014-07-08 16:20:33 -07001213 continue;
1214 }
1215 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001216 FMT_THROW(FormatError("unmatched '}' in format string"));
vitaut0eac0372015-07-28 06:46:41 -07001217 write(writer_, start, s - 1);
jamboree7487bde2015-06-10 09:32:59 +08001218 Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
vitaut0eac0372015-07-28 06:46:41 -07001219 start = s = format(s, arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001220 }
vitaut0eac0372015-07-28 06:46:41 -07001221 write(writer_, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001222}
1223
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001224FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001225 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001226 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001227}
1228
vitaut24c309f2015-06-12 07:15:57 -07001229#if FMT_USE_WINDOWS_H
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001230FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001231 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001232 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001233}
Victor Zverovich400812a2014-04-30 12:38:17 -07001234#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001235
vitaut438bd9b2015-06-26 07:43:54 -07001236FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001237 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001238 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001239 std::fwrite(w.data(), 1, w.size(), f);
1240}
1241
vitaut438bd9b2015-06-26 07:43:54 -07001242FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001243 print(stdout, format_str, args);
1244}
1245
vitaut438bd9b2015-06-26 07:43:54 -07001246FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001247 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001248 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001249 os.write(w.data(), w.size());
1250}
1251
vitaut438bd9b2015-06-26 07:43:54 -07001252FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001253 char escape[] = "\x1b[30m";
1254 escape[3] = '0' + static_cast<char>(c);
1255 std::fputs(escape, stdout);
1256 print(format, args);
1257 std::fputs(RESET_COLOR, stdout);
1258}
1259
vitaut438bd9b2015-06-26 07:43:54 -07001260FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001261 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001262 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001263 std::size_t size = w.size();
1264 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001265}
1266
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001267#ifndef FMT_HEADER_ONLY
1268
vitaut9ca1ce22015-05-23 08:04:06 -07001269template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -07001270
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001271// Explicit instantiations for char.
1272
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001273template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
1274
Victor Zverovichf43caef2014-09-25 07:21:48 -07001275template const char *fmt::BasicFormatter<char>::format(
1276 const char *&format_str, const fmt::internal::Arg &arg);
1277
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001278template void fmt::BasicFormatter<char>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001279 CStringRef format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001280
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001281template void fmt::internal::PrintfFormatter<char>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001282 BasicWriter<char> &writer, CStringRef format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001283
Victor Zverovich14f25772014-09-19 08:45:05 -07001284template int fmt::internal::CharTraits<char>::format_float(
1285 char *buffer, std::size_t size, const char *format,
1286 unsigned width, int precision, double value);
1287
1288template int fmt::internal::CharTraits<char>::format_float(
1289 char *buffer, std::size_t size, const char *format,
1290 unsigned width, int precision, long double value);
1291
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001292// Explicit instantiations for wchar_t.
1293
Victor Zverovich7c0d5752015-03-01 18:19:56 -08001294template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
1295
Victor Zverovichf43caef2014-09-25 07:21:48 -07001296template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1297 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1298
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001299template void fmt::BasicFormatter<wchar_t>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001300 BasicCStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001301
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001302template void fmt::internal::PrintfFormatter<wchar_t>::format(
vitaut438bd9b2015-06-26 07:43:54 -07001303 BasicWriter<wchar_t> &writer, WCStringRef format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001304 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001305
Victor Zverovich14f25772014-09-19 08:45:05 -07001306template int fmt::internal::CharTraits<wchar_t>::format_float(
1307 wchar_t *buffer, std::size_t size, const wchar_t *format,
1308 unsigned width, int precision, double value);
1309
1310template int fmt::internal::CharTraits<wchar_t>::format_float(
1311 wchar_t *buffer, std::size_t size, const wchar_t *format,
1312 unsigned width, int precision, long double value);
1313
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001314#endif // FMT_HEADER_ONLY
1315
jdale88a9862fd2014-03-11 18:56:24 +00001316#if _MSC_VER
1317# pragma warning(pop)
1318#endif