blob: a4c9cee68e61873af52d9ea1be81d98c80d66623 [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 Zveroviche3a44c12014-07-09 06:56:36 -07004 Copyright (c) 2012 - 2014, 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
Victor Zverovich859a4972014-04-30 06:55:21 -070038#ifdef _WIN32
Constantine Tarasenkov6aace692014-06-11 02:38:57 +040039# ifdef __MINGW32__
40# include <cstring>
41# endif
Victor Zverovich859a4972014-04-30 06:55:21 -070042# include <windows.h>
43#endif
44
Victor Zverovich6e5551e2014-07-02 06:33:25 -070045using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080046
Victor Zverovich8b76e972014-10-06 08:30:55 -070047// Check if exceptions are disabled.
48#if __GNUC__ && !__EXCEPTIONS
49# define FMT_EXCEPTIONS 0
50#endif
51#if _MSC_VER && !_HAS_EXCEPTIONS
52# define FMT_EXCEPTIONS 0
53#endif
54#ifndef FMT_EXCEPTIONS
55# define FMT_EXCEPTIONS 1
56#endif
57
58#if FMT_EXCEPTIONS
59# define FMT_TRY try
60# define FMT_CATCH(x) catch (x)
61#else
62# define FMT_TRY if (true)
63# define FMT_CATCH(x) if (false)
64#endif
65
66#ifndef FMT_THROW
67# if FMT_EXCEPTIONS
68# define FMT_THROW(x) throw x
69# else
70# define FMT_THROW(x) assert(false)
71# endif
72#endif
73
Victor Zverovichd9c605c2014-11-28 06:40:57 -080074#ifdef FMT_HEADER_ONLY
75# define FMT_FUNC inline
Victor Zverovichc2a69032014-11-28 15:30:03 -080076#else
77# define FMT_FUNC
Victor Zverovichd9c605c2014-11-28 06:40:57 -080078#endif
79
jdale88a9862fd2014-03-11 18:56:24 +000080#if _MSC_VER
81# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070082# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050083# pragma warning(disable: 4702) // unreachable code
jdale88a9862fd2014-03-11 18:56:24 +000084#endif
85
Victor Zverovich9ff3b972013-09-07 10:15:08 -070086namespace {
87
88#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070089# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080090#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070091inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080092 va_list args;
93 va_start(args, format);
94 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
95 va_end(args);
96 return result;
97}
Victor Zverovichb9a568b2014-09-19 07:51:42 -070098# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -070099#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800100
Victor Zverovichadce0242014-08-17 07:53:55 -0700101// Checks if a value fits in int - used to avoid warnings about comparing
102// signed and unsigned integers.
103template <bool IsSigned>
104struct IntChecker {
105 template <typename T>
106 static bool fits_in_int(T value) {
107 unsigned max = INT_MAX;
108 return value <= max;
109 }
110};
111
112template <>
113struct IntChecker<true> {
114 template <typename T>
115 static bool fits_in_int(T value) {
116 return value >= INT_MIN && value <= INT_MAX;
117 }
118};
119
Victor Zverovich43fe1002014-02-19 14:20:26 -0800120const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700121
Victor Zverovich22f75d82014-09-03 08:03:05 -0700122typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
123
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700124// Portable thread-safe version of strerror.
125// Sets buffer to point to a string describing the error code.
126// This can be either a pointer to a string stored in buffer,
127// or a pointer to some static immutable string.
128// Returns one of the following values:
129// 0 - success
130// ERANGE - buffer is not large enough to store the error message
131// other - failure
132// Buffer should be at least of size 1.
133int safe_strerror(
134 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
135 assert(buffer != 0 && buffer_size != 0);
136 int result = 0;
Victor Zverovichbdeffc32015-02-05 07:04:22 -0800137#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__
138 // XSI-compliant version of strerror_r.
139 result = strerror_r(error_code, buffer, buffer_size);
140 if (result != 0)
141 result = errno;
142#elif _GNU_SOURCE
143 // GNU-specific version of strerror_r.
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700144 char *message = strerror_r(error_code, buffer, buffer_size);
145 // If the buffer is full then the message is probably truncated.
146 if (message == buffer && strlen(buffer) == buffer_size - 1)
147 result = ERANGE;
148 buffer = message;
149#elif __MINGW32__
150 errno = 0;
151 (void)buffer_size;
152 buffer = strerror(error_code);
153 result = errno;
154#elif _WIN32
155 result = strerror_s(buffer, buffer_size, error_code);
156 // If the buffer is full then the message is probably truncated.
157 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
158 result = ERANGE;
159#else
160 result = strerror_r(error_code, buffer, buffer_size);
161 if (result == -1)
162 result = errno; // glibc versions before 2.13 return result in errno.
163#endif
164 return result;
165}
166
Victor Zverovich22f75d82014-09-03 08:03:05 -0700167void format_error_code(fmt::Writer &out, int error_code,
168 fmt::StringRef message) FMT_NOEXCEPT(true) {
169 // Report error code making sure that the output fits into
170 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
171 // bad_alloc.
172 out.clear();
173 static const char SEP[] = ": ";
Victor Zverovichdff21372014-12-16 07:01:01 -0800174 static const char ERR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700175 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
Victor Zverovichdff21372014-12-16 07:01:01 -0800176 // Subtract 2 to account for terminating null characters in SEP and ERR.
Victor Zverovich22f75d82014-09-03 08:03:05 -0700177 std::size_t error_code_size =
Victor Zverovichdff21372014-12-16 07:01:01 -0800178 sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700179 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700180 out << message << SEP;
Victor Zverovichdff21372014-12-16 07:01:01 -0800181 out << ERR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700182 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
183}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700184
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700185void report_error(FormatFunc func,
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700186 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700187 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700188 func(full_message, error_code, message);
189 // Use Writer::data instead of Writer::c_str to avoid potential memory
190 // allocation.
191 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
192 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700193}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700194
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700195// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
196class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
197 public:
198 template <typename T>
199 bool visit_any_int(T value) { return value == 0; }
200};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700201
202// Parses an unsigned integer advancing s to the end of the parsed input.
203// This function assumes that the first character of s is a digit.
204template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700205int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700206 assert('0' <= *s && *s <= '9');
207 unsigned value = 0;
208 do {
209 unsigned new_value = value * 10 + (*s++ - '0');
210 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700211 if (new_value < value) {
212 value = UINT_MAX;
213 break;
214 }
215 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700216 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700217 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700218 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700219 return value;
220}
Victor Zveroviche8251562014-07-08 16:20:33 -0700221
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700222inline void require_numeric_argument(const Arg &arg, char spec) {
223 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700224 std::string message =
225 fmt::format("format specifier '{}' requires numeric argument", spec);
226 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700227 }
228}
229
Victor Zveroviche8251562014-07-08 16:20:33 -0700230template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700231void check_sign(const Char *&s, const Arg &arg) {
232 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700233 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700234 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700235 FMT_THROW(fmt::FormatError(fmt::format(
236 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700237 }
238 ++s;
239}
240
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700241// Checks if an argument is a valid printf width specifier and sets
242// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700243class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700244 private:
245 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700246
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800247 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
248
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700249 public:
250 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700251
Victor Zverovich9d74f952014-07-16 07:27:54 -0700252 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700253 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovichd707adc2014-10-13 06:59:18 -0700254 return 0;
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700255 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700256
Victor Zverovich9d74f952014-07-16 07:27:54 -0700257 template <typename T>
258 unsigned visit_any_int(T value) {
259 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
260 UnsignedType width = value;
261 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700262 spec_.align_ = fmt::ALIGN_LEFT;
263 width = 0 - width;
264 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700265 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700266 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700267 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700268 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700269};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700270
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700271class PrecisionHandler :
272 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
273 public:
274 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700275 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zverovich755ecb02014-10-13 08:39:38 -0700276 return 0;
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700277 }
278
279 template <typename T>
280 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700281 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700282 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700283 return static_cast<int>(value);
284 }
285};
286
Victor Zverovich32344d92014-08-28 08:11:21 -0700287// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700288template <typename T>
289class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
290 private:
291 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700292 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700293
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800294 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
295
Victor Zverovicheeca2232014-07-30 07:37:16 -0700296 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700297 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
298 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700299
300 template <typename U>
301 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700302 bool is_signed = type_ == 'd' || type_ == 'i';
303 using fmt::internal::Arg;
304 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700305 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700306 if (is_signed) {
307 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700308 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700309 } else {
310 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700311 arg_.uint_value = static_cast<unsigned>(
312 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700313 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700314 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700315 if (is_signed) {
316 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700317 arg_.long_long_value =
318 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700319 } else {
320 arg_.type = Arg::ULONG_LONG;
321 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700322 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700323 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700324 }
325 }
326};
327
Victor Zverovich32344d92014-08-28 08:11:21 -0700328// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700329class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
330 private:
331 fmt::internal::Arg &arg_;
332
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800333 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
334
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700335 public:
336 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
337
338 template <typename T>
339 void visit_any_int(T value) {
340 arg_.type = Arg::CHAR;
341 arg_.int_value = static_cast<char>(value);
342 }
343};
344
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700345// This function template is used to prevent compile errors when handling
346// incompatible string arguments, e.g. handling a wide string in a narrow
347// string formatter.
348template <typename Char>
349Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
350
351template <>
352inline Arg::StringValue<char> ignore_incompatible_str(
353 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
354
355template <>
356inline Arg::StringValue<wchar_t> ignore_incompatible_str(
357 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700358} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700359
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800360FMT_FUNC void fmt::SystemError::init(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800361 int err_code, StringRef format_str, ArgList args) {
362 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700363 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800364 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700365 std::runtime_error &base = *this;
366 base = std::runtime_error(w.str());
367}
368
Victor Zverovichb605b392013-09-09 22:21:40 -0700369template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700370int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700371 char *buffer, std::size_t size, const char *format,
372 unsigned width, int precision, T value) {
373 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700374 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700375 FMT_SNPRINTF(buffer, size, format, value) :
376 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700377 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700378 return precision < 0 ?
379 FMT_SNPRINTF(buffer, size, format, width, value) :
380 FMT_SNPRINTF(buffer, size, format, width, precision, value);
381}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700382
Victor Zverovichb605b392013-09-09 22:21:40 -0700383template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700384int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700385 wchar_t *buffer, std::size_t size, const wchar_t *format,
386 unsigned width, int precision, T value) {
387 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700388 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700389 swprintf(buffer, size, format, value) :
390 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700391 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700392 return precision < 0 ?
393 swprintf(buffer, size, format, width, value) :
394 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700395}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800396
Victor Zverovich311251e2014-11-29 06:58:00 -0800397template <typename T>
398const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800399 "0001020304050607080910111213141516171819"
400 "2021222324252627282930313233343536373839"
401 "4041424344454647484950515253545556575859"
402 "6061626364656667686970717273747576777879"
403 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800404
Victor Zverovichf1d85162014-02-19 13:02:22 -0800405#define FMT_POWERS_OF_10(factor) \
406 factor * 10, \
407 factor * 100, \
408 factor * 1000, \
409 factor * 10000, \
410 factor * 100000, \
411 factor * 1000000, \
412 factor * 10000000, \
413 factor * 100000000, \
414 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800415
Victor Zverovich311251e2014-11-29 06:58:00 -0800416template <typename T>
417const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
418 0, FMT_POWERS_OF_10(1)
419};
420
421template <typename T>
422const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800423 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800424 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800425 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700426 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800427 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800428 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800429};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800430
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800431FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800432 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700433 FMT_THROW(fmt::FormatError(
434 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800435 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700436 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700437 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700438 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800439}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700440
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700441#ifdef _WIN32
442
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800443FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700444 int length = MultiByteToWideChar(
445 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
Victor Zverovichdff21372014-12-16 07:01:01 -0800446 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700447 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800448 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700449 buffer_.resize(length);
450 length = MultiByteToWideChar(
451 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
452 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800453 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700454}
455
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800456FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700457 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700458 FMT_THROW(WindowsError(error_code,
459 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700460 }
461}
462
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800463FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700464 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
465 if (length == 0)
466 return GetLastError();
467 buffer_.resize(length);
468 length = WideCharToMultiByte(
469 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
470 if (length == 0)
471 return GetLastError();
472 return 0;
473}
474
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800475FMT_FUNC void fmt::WindowsError::init(
Victor Zverovich1d464042014-09-21 08:08:52 -0700476 int error_code, StringRef format_str, ArgList args) {
Victor Zverovich53201032014-06-30 14:26:29 -0700477 error_code_ = error_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700478 MemoryWriter w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700479 internal::format_windows_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700480 std::runtime_error &base = *this;
481 base = std::runtime_error(w.str());
482}
483
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700484#endif
485
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800486FMT_FUNC void fmt::internal::format_system_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700487 fmt::Writer &out, int error_code,
488 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700489 FMT_TRY {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700490 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700491 buffer.resize(INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700492 for (;;) {
Victor Zverovichaca49372014-11-24 07:38:26 -0800493 char *system_message = &buffer[0];
Victor Zverovich22f75d82014-09-03 08:03:05 -0700494 int result = safe_strerror(error_code, system_message, buffer.size());
495 if (result == 0) {
496 out << message << ": " << system_message;
497 return;
498 }
499 if (result != ERANGE)
500 break; // Can't get error message, report error code instead.
501 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700502 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700503 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700504 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700505}
506
507#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800508FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700509 fmt::Writer &out, int error_code,
510 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700511 class String {
512 private:
513 LPWSTR str_;
514
515 public:
516 String() : str_() {}
517 ~String() { LocalFree(str_); }
518 LPWSTR *ptr() { return &str_; }
519 LPCWSTR c_str() const { return str_; }
520 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700521 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700522 String system_message;
523 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
524 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
525 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
526 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
527 UTF16ToUTF8 utf8_message;
528 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
529 out << message << ": " << utf8_message;
530 return;
531 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700532 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700533 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700534 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700535}
536#endif
537
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700538// An argument formatter.
539template <typename Char>
540class fmt::internal::ArgFormatter :
541 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
542 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700543 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700544 fmt::BasicWriter<Char> &writer_;
545 fmt::FormatSpec &spec_;
546 const Char *format_;
547
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800548 FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
549
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700550 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700551 ArgFormatter(
552 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700553 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700554
Victor Zverovich9d74f952014-07-16 07:27:54 -0700555 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700556 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700557
558 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700559 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700560
561 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700562 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700563 spec_.flags_ |= CHAR_FLAG;
564 writer_.write_int(value, spec_);
565 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700566 }
567 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700568 FMT_THROW(FormatError("invalid format specifier for char"));
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700569 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
Victor Zverovich43aebf52015-01-08 07:56:08 -0800570 Char fill = static_cast<Char>(spec_.fill());
571 if (spec_.precision_ == 0) {
572 std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
573 return;
574 }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700575 CharPtr out = CharPtr();
576 if (spec_.width_ > 1) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700577 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700578 if (spec_.align_ == fmt::ALIGN_RIGHT) {
579 std::fill_n(out, spec_.width_ - 1, fill);
580 out += spec_.width_ - 1;
581 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700582 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700583 } else {
584 std::fill_n(out + 1, spec_.width_ - 1, fill);
585 }
586 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700587 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700588 }
589 *out = static_cast<Char>(value);
590 }
591
592 void visit_string(Arg::StringValue<char> value) {
593 writer_.write_str(value, spec_);
594 }
595 void visit_wstring(Arg::StringValue<wchar_t> value) {
596 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
597 }
598
599 void visit_pointer(const void *value) {
600 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700601 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700602 spec_.flags_ = fmt::HASH_FLAG;
603 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700604 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700605 }
606
607 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700608 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700609 }
610};
611
Victor Zverovichd1ded562014-09-29 08:48:16 -0700612template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700613template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700614void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800615 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700616 // Check if StrChar is convertible to Char.
617 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700618 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700619 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800620 const StrChar *str_value = s.value;
621 std::size_t str_size = s.size;
622 if (str_size == 0) {
623 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700624 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800625 if (*str_value)
626 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700627 }
Victor Zverovich43aebf52015-01-08 07:56:08 -0800628 if (spec.precision_ >= 0 && spec.precision_ < str_size)
629 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800630 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700631}
632
633template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700634inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700635 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700636 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700637 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700638 if (error) {
639 FMT_THROW(FormatError(
640 *s != '}' && *s != ':' ? "invalid format string" : error));
641 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700642 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700643}
644
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800645FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700646 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700647 Arg arg = args_[arg_index];
648 if (arg.type == Arg::NONE)
649 error = "argument index out of range";
650 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700651}
652
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700653inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700654 if (next_arg_index_ >= 0)
655 return do_get_arg(next_arg_index_++, error);
656 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700657 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700658}
659
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700660inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700661 unsigned arg_index, const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700662 if (next_arg_index_ <= 0) {
663 next_arg_index_ = -1;
664 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700665 }
Victor Zverovich605d2602014-08-29 07:45:55 -0700666 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700667 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700668}
669
Victor Zverovich7cae7632013-09-06 20:23:42 -0700670template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700671void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700672 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700673 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700674 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700675 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700676 spec.align_ = ALIGN_LEFT;
677 break;
678 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700679 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
680 break;
681 case '0':
682 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700683 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700684 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700685 spec.flags_ |= SIGN_FLAG;
686 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700687 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700688 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700689 break;
690 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700691 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700692 return;
693 }
694 }
695}
696
Victor Zverovichcb743c02014-06-19 07:40:35 -0700697template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700698Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700699 const Char *s, unsigned arg_index) {
700 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700701 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700702 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
703 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700704 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700705 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700706}
707
708template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700709unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700710 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700711 unsigned arg_index = UINT_MAX;
712 Char c = *s;
713 if (c >= '0' && c <= '9') {
714 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700715 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700716 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700717 if (*s == '$') { // value is an argument index
718 ++s;
719 arg_index = value;
720 } else {
721 if (c == '0')
722 spec.fill_ = '0';
723 if (value != 0) {
724 // Nonzero value means that we parsed width and don't need to
725 // parse it or flags again, so return now.
726 spec.width_ = value;
727 return arg_index;
728 }
729 }
730 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700731 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700732 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700733 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700734 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700735 } else if (*s == '*') {
736 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700737 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700738 }
739 return arg_index;
740}
741
Victor Zverovich1f19b982014-06-16 07:49:30 -0700742template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700743void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800744 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700745 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800746 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700747 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700748 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700749 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700750 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700751 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700752 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700753 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700754 start = ++s;
755 continue;
756 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700757 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700758
Victor Zverovichcb743c02014-06-19 07:40:35 -0700759 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700760 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700761
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700762 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700763 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700764
765 // Parse precision.
766 if (*s == '.') {
767 ++s;
768 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700769 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700770 } else if (*s == '*') {
771 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700772 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700773 }
774 }
775
Victor Zverovich56fc5252014-08-28 07:48:55 -0700776 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700777 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700778 spec.flags_ &= ~HASH_FLAG;
779 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700780 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700781 spec.align_ = ALIGN_NUMERIC;
782 else
783 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700784 }
785
Victor Zverovichf4156b52014-07-30 08:39:07 -0700786 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700787 switch (*s++) {
788 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700789 if (*s == 'h')
790 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700791 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700792 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700793 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700794 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700795 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700796 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700797 else
798 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700799 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700800 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700801 ArgConverter<intmax_t>(arg, *s).visit(arg);
802 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700803 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700804 ArgConverter<size_t>(arg, *s).visit(arg);
805 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700806 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700807 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
808 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700809 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700810 // printf produces garbage when 'L' is omitted for long double, no
811 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700812 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700813 default:
814 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700815 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700816 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700817
818 // Parse type.
819 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700820 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700821 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700822 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
823 // Normalize type.
824 switch (spec.type_) {
825 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700826 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700827 break;
828 case 'c':
829 // TODO: handle wchar_t
830 CharConverter(arg).visit(arg);
831 break;
832 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700833 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700834
835 start = s;
836
837 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700838 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700839 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700840 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700841 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700842 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700843 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700844 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700845 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700846 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700847 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700848 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700849 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700850 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700851 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700852 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700853 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700854 typedef typename BasicWriter<Char>::CharPtr CharPtr;
855 CharPtr out = CharPtr();
856 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700857 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700858 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700859 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700860 std::fill_n(out, spec.width_ - 1, fill);
861 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700862 } else {
863 std::fill_n(out + 1, spec.width_ - 1, fill);
864 }
865 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700866 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700867 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700868 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700869 break;
870 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700871 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700872 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700873 break;
874 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700875 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700876 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -0700877 case Arg::CSTRING:
878 arg.string.size = 0;
879 writer.write_str(arg.string, spec);
880 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700881 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700882 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700883 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700884 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700885 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700886 break;
887 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700888 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700889 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700890 spec.flags_= HASH_FLAG;
891 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -0700892 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700893 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700894 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700895 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700896 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800897 const void *str_format = "s";
898 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700899 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700900 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700901 default:
902 assert(false);
903 break;
904 }
905 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700906 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700907}
908
909template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700910const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700911 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700912 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -0700913 FormatSpec spec;
914 if (*s == ':') {
915 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700916 arg.custom.format(this, arg.custom.value, &s);
917 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700918 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700919 ++s;
920 // Parse fill and alignment.
921 if (Char c = *s) {
922 const Char *p = s + 1;
923 spec.align_ = ALIGN_DEFAULT;
924 do {
925 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700926 case '<':
927 spec.align_ = ALIGN_LEFT;
928 break;
929 case '>':
930 spec.align_ = ALIGN_RIGHT;
931 break;
932 case '=':
933 spec.align_ = ALIGN_NUMERIC;
934 break;
935 case '^':
936 spec.align_ = ALIGN_CENTER;
937 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700938 }
939 if (spec.align_ != ALIGN_DEFAULT) {
940 if (p != s) {
941 if (c == '}') break;
942 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700943 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700944 s += 2;
945 spec.fill_ = c;
946 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700947 if (spec.align_ == ALIGN_NUMERIC)
948 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -0700949 break;
950 }
951 } while (--p >= s);
952 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700953
Victor Zveroviche8251562014-07-08 16:20:33 -0700954 // Parse sign.
955 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700956 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700957 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700958 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
959 break;
960 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700961 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700962 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700963 break;
964 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700965 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700966 spec.flags_ |= SIGN_FLAG;
967 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700968 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700969
Victor Zveroviche8251562014-07-08 16:20:33 -0700970 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700971 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -0700972 spec.flags_ |= HASH_FLAG;
973 ++s;
974 }
975
976 // Parse width and zero flag.
977 if ('0' <= *s && *s <= '9') {
978 if (*s == '0') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700979 require_numeric_argument(arg, '0');
Victor Zveroviche8251562014-07-08 16:20:33 -0700980 spec.align_ = ALIGN_NUMERIC;
981 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700982 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700983 // Zero may be parsed again as a part of the width, but it is simpler
984 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700985 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700986 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700987
Victor Zveroviche8251562014-07-08 16:20:33 -0700988 // Parse precision.
989 if (*s == '.') {
990 ++s;
991 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700992 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700993 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700994 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700995 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700996 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -0700997 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700998 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700999 ULongLong value = 0;
1000 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001001 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001002 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001003 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001004 value = precision_arg.int_value;
1005 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001006 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001007 value = precision_arg.uint_value;
1008 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001009 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001010 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001011 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001012 value = precision_arg.long_long_value;
1013 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001014 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001015 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001016 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001017 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001018 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001019 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001020 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001021 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001022 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001023 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001024 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001025 }
Victor Zverovich43aebf52015-01-08 07:56:08 -08001026 if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001027 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001028 fmt::format("precision not allowed in {} format specifier",
1029 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001030 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001031 }
1032
Victor Zveroviche8251562014-07-08 16:20:33 -07001033 // Parse type.
1034 if (*s != '}' && *s)
1035 spec.type_ = static_cast<char>(*s++);
1036 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001037
Victor Zveroviche8251562014-07-08 16:20:33 -07001038 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001039 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001040 start_ = s;
1041
1042 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001043 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001044 return s;
1045}
1046
1047template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001048void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001049 BasicStringRef<Char> format_str, const ArgList &args) {
1050 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001051 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001052 while (*s) {
1053 Char c = *s++;
1054 if (c != '{' && c != '}') continue;
1055 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001056 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001057 start_ = ++s;
1058 continue;
1059 }
1060 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001061 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001062 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001063 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001064 s = format(s, arg);
1065 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001066 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001067}
1068
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001069FMT_FUNC void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001070 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001071 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001072}
1073
Victor Zverovich400812a2014-04-30 12:38:17 -07001074#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001075FMT_FUNC void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001076 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001077 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001078}
Victor Zverovich400812a2014-04-30 12:38:17 -07001079#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001080
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001081FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001082 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001083 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001084 std::fwrite(w.data(), 1, w.size(), f);
1085}
1086
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001087FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001088 print(stdout, format_str, args);
1089}
1090
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001091FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001092 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001093 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001094 os.write(w.data(), w.size());
1095}
1096
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001097FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001098 char escape[] = "\x1b[30m";
1099 escape[3] = '0' + static_cast<char>(c);
1100 std::fputs(escape, stdout);
1101 print(format, args);
1102 std::fputs(RESET_COLOR, stdout);
1103}
1104
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001105FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001106 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001107 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001108 std::size_t size = w.size();
1109 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001110}
1111
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001112// Explicit instantiations for char.
1113
Victor Zverovichf43caef2014-09-25 07:21:48 -07001114template const char *fmt::BasicFormatter<char>::format(
1115 const char *&format_str, const fmt::internal::Arg &arg);
1116
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001117template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001118 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001119
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001120template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001121 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001122
Victor Zverovich14f25772014-09-19 08:45:05 -07001123template int fmt::internal::CharTraits<char>::format_float(
1124 char *buffer, std::size_t size, const char *format,
1125 unsigned width, int precision, double value);
1126
1127template int fmt::internal::CharTraits<char>::format_float(
1128 char *buffer, std::size_t size, const char *format,
1129 unsigned width, int precision, long double value);
1130
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001131// Explicit instantiations for wchar_t.
1132
Victor Zverovichf43caef2014-09-25 07:21:48 -07001133template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1134 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1135
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001136template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001137 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001138
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001139template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001140 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001141 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001142
Victor Zverovich14f25772014-09-19 08:45:05 -07001143template int fmt::internal::CharTraits<wchar_t>::format_float(
1144 wchar_t *buffer, std::size_t size, const wchar_t *format,
1145 unsigned width, int precision, double value);
1146
1147template int fmt::internal::CharTraits<wchar_t>::format_float(
1148 wchar_t *buffer, std::size_t size, const wchar_t *format,
1149 unsigned width, int precision, long double value);
1150
jdale88a9862fd2014-03-11 18:56:24 +00001151#if _MSC_VER
1152# pragma warning(pop)
1153#endif