blob: 76f2283041dfc78eeccd12210f933a19526f2121 [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
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800122const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700123
Victor Zverovich22f75d82014-09-03 08:03:05 -0700124typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
125
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700126// Portable thread-safe version of strerror.
127// Sets buffer to point to a string describing the error code.
128// This can be either a pointer to a string stored in buffer,
129// or a pointer to some static immutable string.
130// Returns one of the following values:
131// 0 - success
132// ERANGE - buffer is not large enough to store the error message
133// other - failure
134// Buffer should be at least of size 1.
135int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800136 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700137 assert(buffer != 0 && buffer_size != 0);
138 int result = 0;
Victor Zverovichbdeffc32015-02-05 07:04:22 -0800139#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__
140 // XSI-compliant version of strerror_r.
141 result = strerror_r(error_code, buffer, buffer_size);
142 if (result != 0)
143 result = errno;
144#elif _GNU_SOURCE
145 // GNU-specific version of strerror_r.
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700146 char *message = strerror_r(error_code, buffer, buffer_size);
147 // If the buffer is full then the message is probably truncated.
148 if (message == buffer && strlen(buffer) == buffer_size - 1)
149 result = ERANGE;
150 buffer = message;
151#elif __MINGW32__
152 errno = 0;
153 (void)buffer_size;
154 buffer = strerror(error_code);
155 result = errno;
156#elif _WIN32
157 result = strerror_s(buffer, buffer_size, error_code);
158 // If the buffer is full then the message is probably truncated.
159 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
160 result = ERANGE;
161#else
162 result = strerror_r(error_code, buffer, buffer_size);
163 if (result == -1)
164 result = errno; // glibc versions before 2.13 return result in errno.
165#endif
166 return result;
167}
168
Victor Zverovich22f75d82014-09-03 08:03:05 -0700169void format_error_code(fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800170 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700171 // Report error code making sure that the output fits into
172 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
173 // bad_alloc.
174 out.clear();
175 static const char SEP[] = ": ";
Victor Zverovichdff21372014-12-16 07:01:01 -0800176 static const char ERR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700177 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
Victor Zverovichdff21372014-12-16 07:01:01 -0800178 // Subtract 2 to account for terminating null characters in SEP and ERR.
Victor Zverovich22f75d82014-09-03 08:03:05 -0700179 std::size_t error_code_size =
Victor Zverovichdff21372014-12-16 07:01:01 -0800180 sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700181 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700182 out << message << SEP;
Victor Zverovichdff21372014-12-16 07:01:01 -0800183 out << ERR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700184 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
185}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700186
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700187void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800188 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700189 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700190 func(full_message, error_code, message);
191 // Use Writer::data instead of Writer::c_str to avoid potential memory
192 // allocation.
193 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
194 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700195}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700196
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700197// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
198class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
199 public:
200 template <typename T>
201 bool visit_any_int(T value) { return value == 0; }
202};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700203
204// Parses an unsigned integer advancing s to the end of the parsed input.
205// This function assumes that the first character of s is a digit.
206template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700207int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700208 assert('0' <= *s && *s <= '9');
209 unsigned value = 0;
210 do {
211 unsigned new_value = value * 10 + (*s++ - '0');
212 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700213 if (new_value < value) {
214 value = UINT_MAX;
215 break;
216 }
217 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700218 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700219 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700220 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700221 return value;
222}
Victor Zveroviche8251562014-07-08 16:20:33 -0700223
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700224inline void require_numeric_argument(const Arg &arg, char spec) {
225 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700226 std::string message =
227 fmt::format("format specifier '{}' requires numeric argument", spec);
228 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700229 }
230}
231
Victor Zveroviche8251562014-07-08 16:20:33 -0700232template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700233void check_sign(const Char *&s, const Arg &arg) {
234 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700235 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700236 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700237 FMT_THROW(fmt::FormatError(fmt::format(
238 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700239 }
240 ++s;
241}
242
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700243// Checks if an argument is a valid printf width specifier and sets
244// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700245class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700246 private:
247 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700248
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800249 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
250
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700251 public:
252 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700253
Victor Zverovich9d74f952014-07-16 07:27:54 -0700254 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700255 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich37ad4362015-02-06 21:27:31 -0800256 FMT_RETURN_AFTER_THROW(0);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700257 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700258
Victor Zverovich9d74f952014-07-16 07:27:54 -0700259 template <typename T>
260 unsigned visit_any_int(T value) {
261 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
262 UnsignedType width = value;
263 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700264 spec_.align_ = fmt::ALIGN_LEFT;
265 width = 0 - width;
266 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700267 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700268 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700269 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700270 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700271};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700272
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700273class PrecisionHandler :
274 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
275 public:
276 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700277 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zverovich37ad4362015-02-06 21:27:31 -0800278 FMT_RETURN_AFTER_THROW(0);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700279 }
280
281 template <typename T>
282 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700283 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700284 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700285 return static_cast<int>(value);
286 }
287};
288
Victor Zverovich32344d92014-08-28 08:11:21 -0700289// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700290template <typename T>
291class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
292 private:
293 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700294 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700295
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800296 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
297
Victor Zverovicheeca2232014-07-30 07:37:16 -0700298 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700299 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
300 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700301
302 template <typename U>
303 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700304 bool is_signed = type_ == 'd' || type_ == 'i';
305 using fmt::internal::Arg;
306 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700307 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700308 if (is_signed) {
309 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700310 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700311 } else {
312 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700313 arg_.uint_value = static_cast<unsigned>(
314 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700315 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700316 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700317 if (is_signed) {
318 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700319 arg_.long_long_value =
320 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700321 } else {
322 arg_.type = Arg::ULONG_LONG;
323 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700324 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700325 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700326 }
327 }
328};
329
Victor Zverovich32344d92014-08-28 08:11:21 -0700330// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700331class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
332 private:
333 fmt::internal::Arg &arg_;
334
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800335 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
336
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700337 public:
338 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
339
340 template <typename T>
341 void visit_any_int(T value) {
342 arg_.type = Arg::CHAR;
343 arg_.int_value = static_cast<char>(value);
344 }
345};
346
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700347// This function template is used to prevent compile errors when handling
348// incompatible string arguments, e.g. handling a wide string in a narrow
349// string formatter.
350template <typename Char>
351Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
352
353template <>
354inline Arg::StringValue<char> ignore_incompatible_str(
355 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
356
357template <>
358inline Arg::StringValue<wchar_t> ignore_incompatible_str(
359 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700360} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700361
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800362FMT_FUNC void fmt::SystemError::init(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800363 int err_code, StringRef format_str, ArgList args) {
364 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700365 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800366 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700367 std::runtime_error &base = *this;
368 base = std::runtime_error(w.str());
369}
370
Victor Zverovichb605b392013-09-09 22:21:40 -0700371template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700372int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700373 char *buffer, std::size_t size, const char *format,
374 unsigned width, int precision, T value) {
375 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700376 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700377 FMT_SNPRINTF(buffer, size, format, value) :
378 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700379 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700380 return precision < 0 ?
381 FMT_SNPRINTF(buffer, size, format, width, value) :
382 FMT_SNPRINTF(buffer, size, format, width, precision, value);
383}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700384
Victor Zverovichb605b392013-09-09 22:21:40 -0700385template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700386int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700387 wchar_t *buffer, std::size_t size, const wchar_t *format,
388 unsigned width, int precision, T value) {
389 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700390 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700391 swprintf(buffer, size, format, value) :
392 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700393 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700394 return precision < 0 ?
395 swprintf(buffer, size, format, width, value) :
396 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700397}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800398
Victor Zverovich311251e2014-11-29 06:58:00 -0800399template <typename T>
400const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800401 "0001020304050607080910111213141516171819"
402 "2021222324252627282930313233343536373839"
403 "4041424344454647484950515253545556575859"
404 "6061626364656667686970717273747576777879"
405 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800406
Victor Zverovichf1d85162014-02-19 13:02:22 -0800407#define FMT_POWERS_OF_10(factor) \
408 factor * 10, \
409 factor * 100, \
410 factor * 1000, \
411 factor * 10000, \
412 factor * 100000, \
413 factor * 1000000, \
414 factor * 10000000, \
415 factor * 100000000, \
416 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800417
Victor Zverovich311251e2014-11-29 06:58:00 -0800418template <typename T>
419const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
420 0, FMT_POWERS_OF_10(1)
421};
422
423template <typename T>
424const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800425 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800426 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800427 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700428 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800429 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800430 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800431};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800432
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800433FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800434 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700435 FMT_THROW(fmt::FormatError(
436 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800437 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700438 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700439 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700440 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800441}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700442
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700443#ifdef _WIN32
444
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800445FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700446 int length = MultiByteToWideChar(
447 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
Victor Zverovichdff21372014-12-16 07:01:01 -0800448 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700449 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800450 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700451 buffer_.resize(length);
452 length = MultiByteToWideChar(
453 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
454 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800455 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700456}
457
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800458FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700459 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700460 FMT_THROW(WindowsError(error_code,
461 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700462 }
463}
464
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800465FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700466 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
467 if (length == 0)
468 return GetLastError();
469 buffer_.resize(length);
470 length = WideCharToMultiByte(
471 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
472 if (length == 0)
473 return GetLastError();
474 return 0;
475}
476
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800477FMT_FUNC void fmt::WindowsError::init(
Carter Li3f574c12015-02-17 10:11:42 +0800478 int err_code, StringRef format_str, ArgList args) {
479 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700480 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800481 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700482 std::runtime_error &base = *this;
483 base = std::runtime_error(w.str());
484}
485
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700486#endif
487
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800488FMT_FUNC void fmt::internal::format_system_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700489 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800490 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700491 FMT_TRY {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700492 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700493 buffer.resize(INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700494 for (;;) {
Victor Zverovichaca49372014-11-24 07:38:26 -0800495 char *system_message = &buffer[0];
Victor Zverovich22f75d82014-09-03 08:03:05 -0700496 int result = safe_strerror(error_code, system_message, buffer.size());
497 if (result == 0) {
498 out << message << ": " << system_message;
499 return;
500 }
501 if (result != ERANGE)
502 break; // Can't get error message, report error code instead.
503 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700504 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700505 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700506 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700507}
508
509#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800510FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700511 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800512 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700513 class String {
514 private:
515 LPWSTR str_;
516
517 public:
518 String() : str_() {}
519 ~String() { LocalFree(str_); }
520 LPWSTR *ptr() { return &str_; }
521 LPCWSTR c_str() const { return str_; }
522 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700523 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700524 String system_message;
525 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
526 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
527 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
528 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
529 UTF16ToUTF8 utf8_message;
530 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
531 out << message << ": " << utf8_message;
532 return;
533 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700534 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700535 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700536 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700537}
538#endif
539
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700540// An argument formatter.
541template <typename Char>
542class fmt::internal::ArgFormatter :
543 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
544 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700545 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700546 fmt::BasicWriter<Char> &writer_;
547 fmt::FormatSpec &spec_;
548 const Char *format_;
549
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800550 FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
551
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700552 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700553 ArgFormatter(
554 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700555 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700556
Victor Zverovich9d74f952014-07-16 07:27:54 -0700557 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700558 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700559
560 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700561 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700562
563 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700564 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700565 spec_.flags_ |= CHAR_FLAG;
566 writer_.write_int(value, spec_);
567 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700568 }
569 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700570 FMT_THROW(FormatError("invalid format specifier for char"));
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700571 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
Victor Zverovich43aebf52015-01-08 07:56:08 -0800572 Char fill = static_cast<Char>(spec_.fill());
573 if (spec_.precision_ == 0) {
574 std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
575 return;
576 }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700577 CharPtr out = CharPtr();
578 if (spec_.width_ > 1) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700579 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700580 if (spec_.align_ == fmt::ALIGN_RIGHT) {
581 std::fill_n(out, spec_.width_ - 1, fill);
582 out += spec_.width_ - 1;
583 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700584 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700585 } else {
586 std::fill_n(out + 1, spec_.width_ - 1, fill);
587 }
588 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700589 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700590 }
591 *out = static_cast<Char>(value);
592 }
593
594 void visit_string(Arg::StringValue<char> value) {
595 writer_.write_str(value, spec_);
596 }
597 void visit_wstring(Arg::StringValue<wchar_t> value) {
598 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
599 }
600
601 void visit_pointer(const void *value) {
602 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700603 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700604 spec_.flags_ = fmt::HASH_FLAG;
605 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700606 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700607 }
608
609 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700610 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700611 }
612};
613
Victor Zverovichd1ded562014-09-29 08:48:16 -0700614template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700615template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700616void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800617 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700618 // Check if StrChar is convertible to Char.
619 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700620 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700621 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800622 const StrChar *str_value = s.value;
623 std::size_t str_size = s.size;
624 if (str_size == 0) {
625 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700626 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800627 if (*str_value)
628 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700629 }
Victor Zverovich59254412015-02-06 07:27:19 -0800630 std::size_t precision = spec.precision_;
631 if (spec.precision_ >= 0 && precision < str_size)
Victor Zverovich43aebf52015-01-08 07:56:08 -0800632 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800633 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700634}
635
636template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700637inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700638 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700639 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700640 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700641 if (error) {
642 FMT_THROW(FormatError(
643 *s != '}' && *s != ':' ? "invalid format string" : error));
644 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700645 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700646}
647
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800648FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700649 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700650 Arg arg = args_[arg_index];
651 if (arg.type == Arg::NONE)
652 error = "argument index out of range";
653 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700654}
655
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700656inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700657 if (next_arg_index_ >= 0)
658 return do_get_arg(next_arg_index_++, error);
659 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700660 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700661}
662
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700663inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700664 unsigned arg_index, const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700665 if (next_arg_index_ <= 0) {
666 next_arg_index_ = -1;
667 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700668 }
Victor Zverovich605d2602014-08-29 07:45:55 -0700669 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700670 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700671}
672
Victor Zverovich7cae7632013-09-06 20:23:42 -0700673template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700674void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700675 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700676 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700677 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700678 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700679 spec.align_ = ALIGN_LEFT;
680 break;
681 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700682 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
683 break;
684 case '0':
685 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700686 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700687 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700688 spec.flags_ |= SIGN_FLAG;
689 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700690 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700691 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700692 break;
693 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700694 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700695 return;
696 }
697 }
698}
699
Victor Zverovichcb743c02014-06-19 07:40:35 -0700700template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700701Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700702 const Char *s, unsigned arg_index) {
703 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700704 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700705 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
706 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700707 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700708 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700709}
710
711template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700712unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700713 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700714 unsigned arg_index = UINT_MAX;
715 Char c = *s;
716 if (c >= '0' && c <= '9') {
717 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700718 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700719 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700720 if (*s == '$') { // value is an argument index
721 ++s;
722 arg_index = value;
723 } else {
724 if (c == '0')
725 spec.fill_ = '0';
726 if (value != 0) {
727 // Nonzero value means that we parsed width and don't need to
728 // parse it or flags again, so return now.
729 spec.width_ = value;
730 return arg_index;
731 }
732 }
733 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700734 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700735 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700736 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700737 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700738 } else if (*s == '*') {
739 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700740 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700741 }
742 return arg_index;
743}
744
Victor Zverovich1f19b982014-06-16 07:49:30 -0700745template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700746void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800747 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700748 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800749 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700750 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700751 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700752 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700753 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700754 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700755 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700756 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700757 start = ++s;
758 continue;
759 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700760 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700761
Victor Zverovichcb743c02014-06-19 07:40:35 -0700762 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700763 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700764
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700765 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700766 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700767
768 // Parse precision.
769 if (*s == '.') {
770 ++s;
771 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700772 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700773 } else if (*s == '*') {
774 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700775 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700776 }
777 }
778
Victor Zverovich56fc5252014-08-28 07:48:55 -0700779 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700780 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700781 spec.flags_ &= ~HASH_FLAG;
782 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700783 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700784 spec.align_ = ALIGN_NUMERIC;
785 else
786 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700787 }
788
Victor Zverovichf4156b52014-07-30 08:39:07 -0700789 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700790 switch (*s++) {
791 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700792 if (*s == 'h')
793 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700794 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700795 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700796 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700797 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700798 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700799 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700800 else
801 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700802 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700803 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700804 ArgConverter<intmax_t>(arg, *s).visit(arg);
805 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700806 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700807 ArgConverter<size_t>(arg, *s).visit(arg);
808 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700809 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700810 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
811 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700812 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700813 // printf produces garbage when 'L' is omitted for long double, no
814 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700815 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700816 default:
817 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700818 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700819 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700820
821 // Parse type.
822 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700823 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700824 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700825 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
826 // Normalize type.
827 switch (spec.type_) {
828 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700829 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700830 break;
831 case 'c':
832 // TODO: handle wchar_t
833 CharConverter(arg).visit(arg);
834 break;
835 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700836 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700837
838 start = s;
839
840 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700841 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700842 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700843 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700844 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700845 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700846 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700847 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700848 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700849 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700850 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700851 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700852 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700853 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700854 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700855 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700856 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700857 typedef typename BasicWriter<Char>::CharPtr CharPtr;
858 CharPtr out = CharPtr();
859 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700860 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700861 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700862 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700863 std::fill_n(out, spec.width_ - 1, fill);
864 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700865 } else {
866 std::fill_n(out + 1, spec.width_ - 1, fill);
867 }
868 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700869 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700870 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700871 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700872 break;
873 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700874 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700875 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700876 break;
877 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700878 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700879 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -0700880 case Arg::CSTRING:
881 arg.string.size = 0;
882 writer.write_str(arg.string, spec);
883 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700884 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700885 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700886 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700887 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700888 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700889 break;
890 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700891 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700892 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700893 spec.flags_= HASH_FLAG;
894 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -0700895 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700896 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700897 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700898 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700899 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800900 const void *str_format = "s";
901 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700902 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700903 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700904 default:
905 assert(false);
906 break;
907 }
908 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700909 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700910}
911
912template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700913const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700914 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700915 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -0700916 FormatSpec spec;
917 if (*s == ':') {
918 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700919 arg.custom.format(this, arg.custom.value, &s);
920 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700921 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700922 ++s;
923 // Parse fill and alignment.
924 if (Char c = *s) {
925 const Char *p = s + 1;
926 spec.align_ = ALIGN_DEFAULT;
927 do {
928 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700929 case '<':
930 spec.align_ = ALIGN_LEFT;
931 break;
932 case '>':
933 spec.align_ = ALIGN_RIGHT;
934 break;
935 case '=':
936 spec.align_ = ALIGN_NUMERIC;
937 break;
938 case '^':
939 spec.align_ = ALIGN_CENTER;
940 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700941 }
942 if (spec.align_ != ALIGN_DEFAULT) {
943 if (p != s) {
944 if (c == '}') break;
945 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700946 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700947 s += 2;
948 spec.fill_ = c;
949 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700950 if (spec.align_ == ALIGN_NUMERIC)
951 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -0700952 break;
953 }
954 } while (--p >= s);
955 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700956
Victor Zveroviche8251562014-07-08 16:20:33 -0700957 // Parse sign.
958 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700959 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700960 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700961 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
962 break;
963 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700964 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700965 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700966 break;
967 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700968 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700969 spec.flags_ |= SIGN_FLAG;
970 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700971 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700972
Victor Zveroviche8251562014-07-08 16:20:33 -0700973 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700974 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -0700975 spec.flags_ |= HASH_FLAG;
976 ++s;
977 }
978
979 // Parse width and zero flag.
980 if ('0' <= *s && *s <= '9') {
981 if (*s == '0') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700982 require_numeric_argument(arg, '0');
Victor Zveroviche8251562014-07-08 16:20:33 -0700983 spec.align_ = ALIGN_NUMERIC;
984 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700985 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700986 // Zero may be parsed again as a part of the width, but it is simpler
987 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700988 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700989 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700990
Victor Zveroviche8251562014-07-08 16:20:33 -0700991 // Parse precision.
992 if (*s == '.') {
993 ++s;
994 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700995 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700996 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700997 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700998 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700999 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -07001000 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001001 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001002 ULongLong value = 0;
1003 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001004 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001005 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001006 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001007 value = precision_arg.int_value;
1008 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001009 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001010 value = precision_arg.uint_value;
1011 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001012 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001013 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001014 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001015 value = precision_arg.long_long_value;
1016 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001017 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001018 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001019 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001020 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001021 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001022 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001023 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001024 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001025 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001026 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001027 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001028 }
Victor Zverovich43aebf52015-01-08 07:56:08 -08001029 if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001030 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001031 fmt::format("precision not allowed in {} format specifier",
1032 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001033 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001034 }
1035
Victor Zveroviche8251562014-07-08 16:20:33 -07001036 // Parse type.
1037 if (*s != '}' && *s)
1038 spec.type_ = static_cast<char>(*s++);
1039 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001040
Victor Zveroviche8251562014-07-08 16:20:33 -07001041 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001042 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001043 start_ = s;
1044
1045 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001046 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001047 return s;
1048}
1049
1050template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001051void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001052 BasicStringRef<Char> format_str, const ArgList &args) {
1053 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001054 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001055 while (*s) {
1056 Char c = *s++;
1057 if (c != '{' && c != '}') continue;
1058 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001059 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001060 start_ = ++s;
1061 continue;
1062 }
1063 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001064 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001065 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001066 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001067 s = format(s, arg);
1068 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001069 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001070}
1071
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001072FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001073 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001074 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001075}
1076
Victor Zverovich400812a2014-04-30 12:38:17 -07001077#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001078FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +08001079 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001080 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001081}
Victor Zverovich400812a2014-04-30 12:38:17 -07001082#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001083
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001084FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001085 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001086 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001087 std::fwrite(w.data(), 1, w.size(), f);
1088}
1089
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001090FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001091 print(stdout, format_str, args);
1092}
1093
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001094FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001095 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001096 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001097 os.write(w.data(), w.size());
1098}
1099
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001100FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001101 char escape[] = "\x1b[30m";
1102 escape[3] = '0' + static_cast<char>(c);
1103 std::fputs(escape, stdout);
1104 print(format, args);
1105 std::fputs(RESET_COLOR, stdout);
1106}
1107
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001108FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001109 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001110 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001111 std::size_t size = w.size();
1112 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001113}
1114
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001115#ifndef FMT_HEADER_ONLY
1116
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001117// Explicit instantiations for char.
1118
Victor Zverovichf43caef2014-09-25 07:21:48 -07001119template const char *fmt::BasicFormatter<char>::format(
1120 const char *&format_str, const fmt::internal::Arg &arg);
1121
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001122template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001123 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001124
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001125template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001126 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001127
Victor Zverovich14f25772014-09-19 08:45:05 -07001128template int fmt::internal::CharTraits<char>::format_float(
1129 char *buffer, std::size_t size, const char *format,
1130 unsigned width, int precision, double value);
1131
1132template int fmt::internal::CharTraits<char>::format_float(
1133 char *buffer, std::size_t size, const char *format,
1134 unsigned width, int precision, long double value);
1135
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001136// Explicit instantiations for wchar_t.
1137
Victor Zverovichf43caef2014-09-25 07:21:48 -07001138template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1139 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1140
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001141template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001142 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001143
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001144template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001145 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001146 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001147
Victor Zverovich14f25772014-09-19 08:45:05 -07001148template int fmt::internal::CharTraits<wchar_t>::format_float(
1149 wchar_t *buffer, std::size_t size, const wchar_t *format,
1150 unsigned width, int precision, double value);
1151
1152template int fmt::internal::CharTraits<wchar_t>::format_float(
1153 wchar_t *buffer, std::size_t size, const wchar_t *format,
1154 unsigned width, int precision, long double value);
1155
Victor Zverovichc09c42f2015-03-01 09:43:33 -08001156#endif // FMT_HEADER_ONLY
1157
jdale88a9862fd2014-03-11 18:56:24 +00001158#if _MSC_VER
1159# pragma warning(pop)
1160#endif