blob: 1a6e4e22d2f98ca8f189a08f5e69d4849c9d9e55 [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
Ryuuke5a9dc8f2015-02-08 16:08:29 +000038#ifdef _WIN32
Ryuuke5a9dc8f2015-02-08 16:08:29 +000039# ifdef __MINGW32__
40# include <cstring>
41# endif
42# include <windows.h>
Ryuuke5a9dc8f2015-02-08 16:08:29 +000043#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
Victor Zverovich37ad4362015-02-06 21:27:31 -080069# define FMT_RETURN_AFTER_THROW(x)
Victor Zverovich8b76e972014-10-06 08:30:55 -070070# else
71# define FMT_THROW(x) assert(false)
Victor Zverovich37ad4362015-02-06 21:27:31 -080072# define FMT_RETURN_AFTER_THROW(x) return x
Victor Zverovich8b76e972014-10-06 08:30:55 -070073# endif
74#endif
75
Victor Zverovichd9c605c2014-11-28 06:40:57 -080076#ifdef FMT_HEADER_ONLY
77# define FMT_FUNC inline
Victor Zverovichc2a69032014-11-28 15:30:03 -080078#else
79# define FMT_FUNC
Victor Zverovichd9c605c2014-11-28 06:40:57 -080080#endif
81
jdale88a9862fd2014-03-11 18:56:24 +000082#if _MSC_VER
83# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070084# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050085# pragma warning(disable: 4702) // unreachable code
jdale88a9862fd2014-03-11 18:56:24 +000086#endif
87
Victor Zverovich9ff3b972013-09-07 10:15:08 -070088namespace {
89
90#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070091# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080092#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070093inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080094 va_list args;
95 va_start(args, format);
96 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
97 va_end(args);
98 return result;
99}
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700100# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700101#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800102
Victor Zverovichadce0242014-08-17 07:53:55 -0700103// Checks if a value fits in int - used to avoid warnings about comparing
104// signed and unsigned integers.
105template <bool IsSigned>
106struct IntChecker {
107 template <typename T>
108 static bool fits_in_int(T value) {
109 unsigned max = INT_MAX;
110 return value <= max;
111 }
112};
113
114template <>
115struct IntChecker<true> {
116 template <typename T>
117 static bool fits_in_int(T value) {
118 return value >= INT_MIN && value <= INT_MAX;
119 }
120};
121
Ryuuke51ceef32015-02-07 22:39:08 +0000122#ifdef _WIN32
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800123const uint8_t WIN32_COLORS[] = {
124 0,
125 FOREGROUND_RED | FOREGROUND_INTENSITY,
126 FOREGROUND_GREEN | FOREGROUND_INTENSITY,
127 FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY,
128 FOREGROUND_BLUE | FOREGROUND_INTENSITY,
129 FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY,
130 FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
131 FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY
132};
Ryuuke51ceef32015-02-07 22:39:08 +0000133#else
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800134const char RESET_COLOR[] = "\x1b[0m";
Ryuuke51ceef32015-02-07 22:39:08 +0000135#endif
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700136
Victor Zverovich22f75d82014-09-03 08:03:05 -0700137typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
138
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700139// Portable thread-safe version of strerror.
140// Sets buffer to point to a string describing the error code.
141// This can be either a pointer to a string stored in buffer,
142// or a pointer to some static immutable string.
143// Returns one of the following values:
144// 0 - success
145// ERANGE - buffer is not large enough to store the error message
146// other - failure
147// Buffer should be at least of size 1.
148int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800149 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700150 assert(buffer != 0 && buffer_size != 0);
151 int result = 0;
Victor Zverovichbdeffc32015-02-05 07:04:22 -0800152#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__
153 // XSI-compliant version of strerror_r.
154 result = strerror_r(error_code, buffer, buffer_size);
155 if (result != 0)
156 result = errno;
157#elif _GNU_SOURCE
158 // GNU-specific version of strerror_r.
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700159 char *message = strerror_r(error_code, buffer, buffer_size);
160 // If the buffer is full then the message is probably truncated.
161 if (message == buffer && strlen(buffer) == buffer_size - 1)
162 result = ERANGE;
163 buffer = message;
164#elif __MINGW32__
165 errno = 0;
166 (void)buffer_size;
167 buffer = strerror(error_code);
168 result = errno;
169#elif _WIN32
170 result = strerror_s(buffer, buffer_size, error_code);
171 // If the buffer is full then the message is probably truncated.
172 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
173 result = ERANGE;
174#else
175 result = strerror_r(error_code, buffer, buffer_size);
176 if (result == -1)
177 result = errno; // glibc versions before 2.13 return result in errno.
178#endif
179 return result;
180}
181
Victor Zverovich22f75d82014-09-03 08:03:05 -0700182void format_error_code(fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800183 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700184 // Report error code making sure that the output fits into
185 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
186 // bad_alloc.
187 out.clear();
188 static const char SEP[] = ": ";
Victor Zverovichdff21372014-12-16 07:01:01 -0800189 static const char ERR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700190 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
Victor Zverovichdff21372014-12-16 07:01:01 -0800191 // Subtract 2 to account for terminating null characters in SEP and ERR.
Victor Zverovich22f75d82014-09-03 08:03:05 -0700192 std::size_t error_code_size =
Victor Zverovichdff21372014-12-16 07:01:01 -0800193 sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700194 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700195 out << message << SEP;
Victor Zverovichdff21372014-12-16 07:01:01 -0800196 out << ERR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700197 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
198}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700199
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700200void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800201 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700202 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700203 func(full_message, error_code, message);
204 // Use Writer::data instead of Writer::c_str to avoid potential memory
205 // allocation.
206 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
207 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700208}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700209
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700210// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
211class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
212 public:
213 template <typename T>
214 bool visit_any_int(T value) { return value == 0; }
215};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700216
217// Parses an unsigned integer advancing s to the end of the parsed input.
218// This function assumes that the first character of s is a digit.
219template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700220int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700221 assert('0' <= *s && *s <= '9');
222 unsigned value = 0;
223 do {
224 unsigned new_value = value * 10 + (*s++ - '0');
225 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700226 if (new_value < value) {
227 value = UINT_MAX;
228 break;
229 }
230 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700231 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700232 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700233 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700234 return value;
235}
Victor Zveroviche8251562014-07-08 16:20:33 -0700236
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700237inline void require_numeric_argument(const Arg &arg, char spec) {
238 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700239 std::string message =
240 fmt::format("format specifier '{}' requires numeric argument", spec);
241 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700242 }
243}
244
Victor Zveroviche8251562014-07-08 16:20:33 -0700245template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700246void check_sign(const Char *&s, const Arg &arg) {
247 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700248 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700249 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700250 FMT_THROW(fmt::FormatError(fmt::format(
251 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700252 }
253 ++s;
254}
255
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700256// Checks if an argument is a valid printf width specifier and sets
257// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700258class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700259 private:
260 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700261
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800262 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
263
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700264 public:
265 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700266
Victor Zverovich9d74f952014-07-16 07:27:54 -0700267 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700268 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich37ad4362015-02-06 21:27:31 -0800269 FMT_RETURN_AFTER_THROW(0);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700270 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700271
Victor Zverovich9d74f952014-07-16 07:27:54 -0700272 template <typename T>
273 unsigned visit_any_int(T value) {
274 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
275 UnsignedType width = value;
276 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700277 spec_.align_ = fmt::ALIGN_LEFT;
278 width = 0 - width;
279 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700280 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700281 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700282 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700283 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700284};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700285
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700286class PrecisionHandler :
287 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
288 public:
289 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700290 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zverovich37ad4362015-02-06 21:27:31 -0800291 FMT_RETURN_AFTER_THROW(0);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700292 }
293
294 template <typename T>
295 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700296 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700297 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700298 return static_cast<int>(value);
299 }
300};
301
Victor Zverovich32344d92014-08-28 08:11:21 -0700302// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700303template <typename T>
304class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
305 private:
306 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700307 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700308
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800309 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
310
Victor Zverovicheeca2232014-07-30 07:37:16 -0700311 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700312 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
313 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700314
315 template <typename U>
316 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700317 bool is_signed = type_ == 'd' || type_ == 'i';
318 using fmt::internal::Arg;
319 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700320 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700321 if (is_signed) {
322 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700323 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700324 } else {
325 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700326 arg_.uint_value = static_cast<unsigned>(
327 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700328 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700329 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700330 if (is_signed) {
331 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700332 arg_.long_long_value =
333 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700334 } else {
335 arg_.type = Arg::ULONG_LONG;
336 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700337 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700338 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700339 }
340 }
341};
342
Victor Zverovich32344d92014-08-28 08:11:21 -0700343// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700344class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
345 private:
346 fmt::internal::Arg &arg_;
347
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800348 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
349
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700350 public:
351 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
352
353 template <typename T>
354 void visit_any_int(T value) {
355 arg_.type = Arg::CHAR;
356 arg_.int_value = static_cast<char>(value);
357 }
358};
359
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700360// This function template is used to prevent compile errors when handling
361// incompatible string arguments, e.g. handling a wide string in a narrow
362// string formatter.
363template <typename Char>
364Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
365
366template <>
367inline Arg::StringValue<char> ignore_incompatible_str(
368 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
369
370template <>
371inline Arg::StringValue<wchar_t> ignore_incompatible_str(
372 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700373} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700374
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800375FMT_FUNC void fmt::SystemError::init(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800376 int err_code, StringRef format_str, ArgList args) {
377 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700378 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800379 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700380 std::runtime_error &base = *this;
381 base = std::runtime_error(w.str());
382}
383
Victor Zverovichb605b392013-09-09 22:21:40 -0700384template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700385int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700386 char *buffer, std::size_t size, const char *format,
387 unsigned width, int precision, T value) {
388 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700389 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700390 FMT_SNPRINTF(buffer, size, format, value) :
391 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700392 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700393 return precision < 0 ?
394 FMT_SNPRINTF(buffer, size, format, width, value) :
395 FMT_SNPRINTF(buffer, size, format, width, precision, value);
396}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700397
Victor Zverovichb605b392013-09-09 22:21:40 -0700398template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700399int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700400 wchar_t *buffer, std::size_t size, const wchar_t *format,
401 unsigned width, int precision, T value) {
402 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700403 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700404 swprintf(buffer, size, format, value) :
405 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700406 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700407 return precision < 0 ?
408 swprintf(buffer, size, format, width, value) :
409 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700410}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800411
Victor Zverovich311251e2014-11-29 06:58:00 -0800412template <typename T>
413const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800414 "0001020304050607080910111213141516171819"
415 "2021222324252627282930313233343536373839"
416 "4041424344454647484950515253545556575859"
417 "6061626364656667686970717273747576777879"
418 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800419
Victor Zverovichf1d85162014-02-19 13:02:22 -0800420#define FMT_POWERS_OF_10(factor) \
421 factor * 10, \
422 factor * 100, \
423 factor * 1000, \
424 factor * 10000, \
425 factor * 100000, \
426 factor * 1000000, \
427 factor * 10000000, \
428 factor * 100000000, \
429 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800430
Victor Zverovich311251e2014-11-29 06:58:00 -0800431template <typename T>
432const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
433 0, FMT_POWERS_OF_10(1)
434};
435
436template <typename T>
437const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800438 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800439 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800440 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700441 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800442 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800443 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800444};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800445
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800446FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800447 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700448 FMT_THROW(fmt::FormatError(
449 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800450 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700451 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700452 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700453 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800454}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700455
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700456#ifdef _WIN32
457
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800458FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700459 int length = MultiByteToWideChar(
460 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
Victor Zverovichdff21372014-12-16 07:01:01 -0800461 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700462 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800463 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700464 buffer_.resize(length);
465 length = MultiByteToWideChar(
466 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
467 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800468 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700469}
470
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800471FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700472 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700473 FMT_THROW(WindowsError(error_code,
474 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700475 }
476}
477
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800478FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700479 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
480 if (length == 0)
481 return GetLastError();
482 buffer_.resize(length);
483 length = WideCharToMultiByte(
484 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
485 if (length == 0)
486 return GetLastError();
487 return 0;
488}
489
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800490FMT_FUNC void fmt::WindowsError::init(
Victor Zverovich1d464042014-09-21 08:08:52 -0700491 int error_code, StringRef format_str, ArgList args) {
Victor Zverovich53201032014-06-30 14:26:29 -0700492 error_code_ = error_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700493 MemoryWriter w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700494 internal::format_windows_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700495 std::runtime_error &base = *this;
496 base = std::runtime_error(w.str());
497}
498
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700499#endif
500
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800501FMT_FUNC void fmt::internal::format_system_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700502 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800503 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700504 FMT_TRY {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700505 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700506 buffer.resize(INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700507 for (;;) {
Victor Zverovichaca49372014-11-24 07:38:26 -0800508 char *system_message = &buffer[0];
Victor Zverovich22f75d82014-09-03 08:03:05 -0700509 int result = safe_strerror(error_code, system_message, buffer.size());
510 if (result == 0) {
511 out << message << ": " << system_message;
512 return;
513 }
514 if (result != ERANGE)
515 break; // Can't get error message, report error code instead.
516 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700517 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700518 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700519 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700520}
521
522#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800523FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700524 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800525 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700526 class String {
527 private:
528 LPWSTR str_;
529
530 public:
531 String() : str_() {}
532 ~String() { LocalFree(str_); }
533 LPWSTR *ptr() { return &str_; }
534 LPCWSTR c_str() const { return str_; }
535 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700536 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700537 String system_message;
538 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
539 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
540 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
541 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
542 UTF16ToUTF8 utf8_message;
543 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
544 out << message << ": " << utf8_message;
545 return;
546 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700547 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700548 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700549 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700550}
551#endif
552
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700553// An argument formatter.
554template <typename Char>
555class fmt::internal::ArgFormatter :
556 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
557 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700558 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700559 fmt::BasicWriter<Char> &writer_;
560 fmt::FormatSpec &spec_;
561 const Char *format_;
562
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800563 FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
564
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700565 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700566 ArgFormatter(
567 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700568 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700569
Victor Zverovich9d74f952014-07-16 07:27:54 -0700570 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700571 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700572
573 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700574 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700575
576 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700577 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700578 spec_.flags_ |= CHAR_FLAG;
579 writer_.write_int(value, spec_);
580 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700581 }
582 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700583 FMT_THROW(FormatError("invalid format specifier for char"));
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700584 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
Victor Zverovich43aebf52015-01-08 07:56:08 -0800585 Char fill = static_cast<Char>(spec_.fill());
586 if (spec_.precision_ == 0) {
587 std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
588 return;
589 }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700590 CharPtr out = CharPtr();
591 if (spec_.width_ > 1) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700592 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700593 if (spec_.align_ == fmt::ALIGN_RIGHT) {
594 std::fill_n(out, spec_.width_ - 1, fill);
595 out += spec_.width_ - 1;
596 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700597 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700598 } else {
599 std::fill_n(out + 1, spec_.width_ - 1, fill);
600 }
601 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700602 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700603 }
604 *out = static_cast<Char>(value);
605 }
606
607 void visit_string(Arg::StringValue<char> value) {
608 writer_.write_str(value, spec_);
609 }
610 void visit_wstring(Arg::StringValue<wchar_t> value) {
611 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
612 }
613
614 void visit_pointer(const void *value) {
615 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700616 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700617 spec_.flags_ = fmt::HASH_FLAG;
618 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700619 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700620 }
621
622 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700623 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700624 }
625};
626
Victor Zverovichd1ded562014-09-29 08:48:16 -0700627template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700628template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700629void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800630 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700631 // Check if StrChar is convertible to Char.
632 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700633 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700634 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800635 const StrChar *str_value = s.value;
636 std::size_t str_size = s.size;
637 if (str_size == 0) {
638 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700639 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800640 if (*str_value)
641 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700642 }
Victor Zverovich59254412015-02-06 07:27:19 -0800643 std::size_t precision = spec.precision_;
644 if (spec.precision_ >= 0 && precision < str_size)
Victor Zverovich43aebf52015-01-08 07:56:08 -0800645 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800646 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700647}
648
649template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700650inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700651 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700652 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700653 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700654 if (error) {
655 FMT_THROW(FormatError(
656 *s != '}' && *s != ':' ? "invalid format string" : error));
657 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700658 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700659}
660
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800661FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700662 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700663 Arg arg = args_[arg_index];
664 if (arg.type == Arg::NONE)
665 error = "argument index out of range";
666 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700667}
668
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700669inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700670 if (next_arg_index_ >= 0)
671 return do_get_arg(next_arg_index_++, error);
672 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700673 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700674}
675
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700676inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700677 unsigned arg_index, const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700678 if (next_arg_index_ <= 0) {
679 next_arg_index_ = -1;
680 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700681 }
Victor Zverovich605d2602014-08-29 07:45:55 -0700682 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700683 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700684}
685
Victor Zverovich7cae7632013-09-06 20:23:42 -0700686template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700687void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700688 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700689 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700690 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700691 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700692 spec.align_ = ALIGN_LEFT;
693 break;
694 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700695 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
696 break;
697 case '0':
698 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700699 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700700 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700701 spec.flags_ |= SIGN_FLAG;
702 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700703 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700704 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700705 break;
706 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700707 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700708 return;
709 }
710 }
711}
712
Victor Zverovichcb743c02014-06-19 07:40:35 -0700713template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700714Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700715 const Char *s, unsigned arg_index) {
716 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700717 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700718 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
719 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700720 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700721 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700722}
723
724template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700725unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700726 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700727 unsigned arg_index = UINT_MAX;
728 Char c = *s;
729 if (c >= '0' && c <= '9') {
730 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700731 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700732 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700733 if (*s == '$') { // value is an argument index
734 ++s;
735 arg_index = value;
736 } else {
737 if (c == '0')
738 spec.fill_ = '0';
739 if (value != 0) {
740 // Nonzero value means that we parsed width and don't need to
741 // parse it or flags again, so return now.
742 spec.width_ = value;
743 return arg_index;
744 }
745 }
746 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700747 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700748 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700749 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700750 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700751 } else if (*s == '*') {
752 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700753 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700754 }
755 return arg_index;
756}
757
Victor Zverovich1f19b982014-06-16 07:49:30 -0700758template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700759void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800760 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700761 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800762 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700763 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700764 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700765 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700766 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700767 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700768 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700769 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700770 start = ++s;
771 continue;
772 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700773 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700774
Victor Zverovichcb743c02014-06-19 07:40:35 -0700775 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700776 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700777
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700778 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700779 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700780
781 // Parse precision.
782 if (*s == '.') {
783 ++s;
784 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700785 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700786 } else if (*s == '*') {
787 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700788 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700789 }
790 }
791
Victor Zverovich56fc5252014-08-28 07:48:55 -0700792 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700793 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700794 spec.flags_ &= ~HASH_FLAG;
795 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700796 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700797 spec.align_ = ALIGN_NUMERIC;
798 else
799 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700800 }
801
Victor Zverovichf4156b52014-07-30 08:39:07 -0700802 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700803 switch (*s++) {
804 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700805 if (*s == 'h')
806 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700807 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700808 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700809 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700810 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700811 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700812 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700813 else
814 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700815 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700816 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700817 ArgConverter<intmax_t>(arg, *s).visit(arg);
818 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700819 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700820 ArgConverter<size_t>(arg, *s).visit(arg);
821 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700822 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700823 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
824 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700825 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700826 // printf produces garbage when 'L' is omitted for long double, no
827 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700828 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700829 default:
830 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700831 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700832 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700833
834 // Parse type.
835 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700836 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700837 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700838 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
839 // Normalize type.
840 switch (spec.type_) {
841 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700842 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700843 break;
844 case 'c':
845 // TODO: handle wchar_t
846 CharConverter(arg).visit(arg);
847 break;
848 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700849 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700850
851 start = s;
852
853 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700854 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700855 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700856 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700857 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700858 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700859 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700860 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700861 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700862 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700863 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700864 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700865 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700866 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700867 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700868 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700869 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700870 typedef typename BasicWriter<Char>::CharPtr CharPtr;
871 CharPtr out = CharPtr();
872 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700873 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700874 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700875 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700876 std::fill_n(out, spec.width_ - 1, fill);
877 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700878 } else {
879 std::fill_n(out + 1, spec.width_ - 1, fill);
880 }
881 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700882 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700883 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700884 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700885 break;
886 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700887 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700888 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700889 break;
890 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700891 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700892 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -0700893 case Arg::CSTRING:
894 arg.string.size = 0;
895 writer.write_str(arg.string, spec);
896 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700897 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700898 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700899 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700900 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700901 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700902 break;
903 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700904 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700905 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700906 spec.flags_= HASH_FLAG;
907 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -0700908 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700909 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700910 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700911 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700912 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800913 const void *str_format = "s";
914 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700915 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700916 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700917 default:
918 assert(false);
919 break;
920 }
921 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700922 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700923}
924
925template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700926const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700927 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700928 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -0700929 FormatSpec spec;
930 if (*s == ':') {
931 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700932 arg.custom.format(this, arg.custom.value, &s);
933 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700934 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700935 ++s;
936 // Parse fill and alignment.
937 if (Char c = *s) {
938 const Char *p = s + 1;
939 spec.align_ = ALIGN_DEFAULT;
940 do {
941 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700942 case '<':
943 spec.align_ = ALIGN_LEFT;
944 break;
945 case '>':
946 spec.align_ = ALIGN_RIGHT;
947 break;
948 case '=':
949 spec.align_ = ALIGN_NUMERIC;
950 break;
951 case '^':
952 spec.align_ = ALIGN_CENTER;
953 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700954 }
955 if (spec.align_ != ALIGN_DEFAULT) {
956 if (p != s) {
957 if (c == '}') break;
958 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700959 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700960 s += 2;
961 spec.fill_ = c;
962 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700963 if (spec.align_ == ALIGN_NUMERIC)
964 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -0700965 break;
966 }
967 } while (--p >= s);
968 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700969
Victor Zveroviche8251562014-07-08 16:20:33 -0700970 // Parse sign.
971 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700972 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700973 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700974 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
975 break;
976 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700977 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700978 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700979 break;
980 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700981 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700982 spec.flags_ |= SIGN_FLAG;
983 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700984 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700985
Victor Zveroviche8251562014-07-08 16:20:33 -0700986 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700987 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -0700988 spec.flags_ |= HASH_FLAG;
989 ++s;
990 }
991
992 // Parse width and zero flag.
993 if ('0' <= *s && *s <= '9') {
994 if (*s == '0') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700995 require_numeric_argument(arg, '0');
Victor Zveroviche8251562014-07-08 16:20:33 -0700996 spec.align_ = ALIGN_NUMERIC;
997 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700998 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700999 // Zero may be parsed again as a part of the width, but it is simpler
1000 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001001 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001002 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001003
Victor Zveroviche8251562014-07-08 16:20:33 -07001004 // Parse precision.
1005 if (*s == '.') {
1006 ++s;
1007 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001008 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -07001009 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001010 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -07001011 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001012 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001013 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001014 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001015 ULongLong value = 0;
1016 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001017 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001018 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001019 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001020 value = precision_arg.int_value;
1021 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001022 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001023 value = precision_arg.uint_value;
1024 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001025 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001026 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001027 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001028 value = precision_arg.long_long_value;
1029 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001030 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001031 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001032 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001033 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001034 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001035 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001036 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001037 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001038 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001039 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001040 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001041 }
Victor Zverovich43aebf52015-01-08 07:56:08 -08001042 if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001043 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001044 fmt::format("precision not allowed in {} format specifier",
1045 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001046 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001047 }
1048
Victor Zveroviche8251562014-07-08 16:20:33 -07001049 // Parse type.
1050 if (*s != '}' && *s)
1051 spec.type_ = static_cast<char>(*s++);
1052 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001053
Victor Zveroviche8251562014-07-08 16:20:33 -07001054 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001055 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001056 start_ = s;
1057
1058 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001059 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001060 return s;
1061}
1062
1063template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001064void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001065 BasicStringRef<Char> format_str, const ArgList &args) {
1066 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001067 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001068 while (*s) {
1069 Char c = *s++;
1070 if (c != '{' && c != '}') continue;
1071 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001072 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001073 start_ = ++s;
1074 continue;
1075 }
1076 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001077 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001078 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001079 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001080 s = format(s, arg);
1081 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001082 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001083}
1084
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001085FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001086 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001087 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001088}
1089
Victor Zverovich400812a2014-04-30 12:38:17 -07001090#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001091FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001092 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001093 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001094}
Victor Zverovich400812a2014-04-30 12:38:17 -07001095#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001096
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001097FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001098 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001099 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001100 std::fwrite(w.data(), 1, w.size(), f);
1101}
1102
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001103FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001104 print(stdout, format_str, args);
1105}
1106
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001107FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001108 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001109 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001110 os.write(w.data(), w.size());
1111}
1112
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001113FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Ryuuke51ceef32015-02-07 22:39:08 +00001114#ifdef _WIN32
Victor Zverovich267382a2015-02-09 06:53:05 -08001115 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
1116 if (handle == INVALID_HANDLE_VALUE)
1117 FMT_THROW(WindowsError(GetLastError(), "cannot get output handle"));
Victor Zverovich7004d1e2015-02-08 19:54:39 -08001118 CONSOLE_SCREEN_BUFFER_INFO info_con;
1119 if (!GetConsoleScreenBufferInfo(handle, &info_con))
Victor Zverovich9368b6a2015-02-08 20:06:45 -08001120 FMT_THROW(WindowsError(GetLastError(), "cannot get console information"));
Victor Zverovich7004d1e2015-02-08 19:54:39 -08001121 WORD reset_color = info_con.wAttributes;
1122 WORD color = static_cast<int>(c) >= ARRAYSIZE(WIN32_COLORS) ? reset_color : WIN32_COLORS[c];
1123 if (!SetConsoleTextAttribute(handle, color))
Victor Zverovich9368b6a2015-02-08 20:06:45 -08001124 FMT_THROW(WindowsError(GetLastError(), "cannot set console color"));
Victor Zverovich7004d1e2015-02-08 19:54:39 -08001125 print(format, args);
1126 if (!SetConsoleTextAttribute(handle, reset_color))
Victor Zverovich9368b6a2015-02-08 20:06:45 -08001127 FMT_THROW(WindowsError(GetLastError(), "cannot set console color"));
Ryuuke51ceef32015-02-07 22:39:08 +00001128#else
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001129 char escape[] = "\x1b[30m";
1130 escape[3] = '0' + static_cast<char>(c);
1131 std::fputs(escape, stdout);
1132 print(format, args);
1133 std::fputs(RESET_COLOR, stdout);
Ryuuke51ceef32015-02-07 22:39:08 +00001134#endif
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001135}
1136
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001137FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001138 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001139 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001140 std::size_t size = w.size();
1141 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001142}
1143
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001144// Explicit instantiations for char.
1145
Victor Zverovichf43caef2014-09-25 07:21:48 -07001146template const char *fmt::BasicFormatter<char>::format(
1147 const char *&format_str, const fmt::internal::Arg &arg);
1148
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001149template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001150 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001151
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001152template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001153 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001154
Victor Zverovich14f25772014-09-19 08:45:05 -07001155template int fmt::internal::CharTraits<char>::format_float(
1156 char *buffer, std::size_t size, const char *format,
1157 unsigned width, int precision, double value);
1158
1159template int fmt::internal::CharTraits<char>::format_float(
1160 char *buffer, std::size_t size, const char *format,
1161 unsigned width, int precision, long double value);
1162
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001163// Explicit instantiations for wchar_t.
1164
Victor Zverovichf43caef2014-09-25 07:21:48 -07001165template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1166 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1167
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001168template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001169 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001170
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001171template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001172 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001173 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001174
Victor Zverovich14f25772014-09-19 08:45:05 -07001175template int fmt::internal::CharTraits<wchar_t>::format_float(
1176 wchar_t *buffer, std::size_t size, const wchar_t *format,
1177 unsigned width, int precision, double value);
1178
1179template int fmt::internal::CharTraits<wchar_t>::format_float(
1180 wchar_t *buffer, std::size_t size, const wchar_t *format,
1181 unsigned width, int precision, long double value);
1182
jdale88a9862fd2014-03-11 18:56:24 +00001183#if _MSC_VER
1184# pragma warning(pop)
1185#endif