blob: a2c892a57cc85016c2c7127acb02402fef3a7e00 [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 Zverovichd53f2092012-12-16 15:06:31 -080028// Disable useless MSVC warnings.
Victor Zverovichf8c91062012-12-17 15:41:00 -080029#undef _CRT_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080030#define _CRT_SECURE_NO_WARNINGS
Victor Zverovichc240a122012-12-21 15:02:25 -080031#undef _SCL_SECURE_NO_WARNINGS
32#define _SCL_SECURE_NO_WARNINGS
Victor Zverovichd53f2092012-12-16 15:06:31 -080033
Victor Zverovichfbfedcf2013-01-14 15:16:20 -080034#include "format.h"
35
Victor Zverovich859a4972014-04-30 06:55:21 -070036#include <string.h>
37
Victor Zverovich72f896d2012-12-12 09:17:28 -080038#include <cctype>
Victor Zverovich5d15bdd2014-07-01 16:23:50 -070039#include <cerrno>
Victor Zverovichf28645f2014-04-24 12:37:06 -070040#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070041#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080042#include <cstdarg>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070043
Victor Zverovich859a4972014-04-30 06:55:21 -070044#ifdef _WIN32
Victor Zverovichdcd039d2014-05-01 07:09:42 -070045# define WIN32_LEAN_AND_MEAN
Constantine Tarasenkov6aace692014-06-11 02:38:57 +040046# ifdef __MINGW32__
47# include <cstring>
48# endif
Victor Zverovich859a4972014-04-30 06:55:21 -070049# include <windows.h>
Victor Zveroviched2bdba2014-04-30 07:41:54 -070050# undef ERROR
Victor Zverovich859a4972014-04-30 06:55:21 -070051#endif
52
Victor Zverovich591ad0a2014-07-14 06:55:29 -070053using fmt::LongLong;
Victor Zverovich447e02c2014-02-15 10:48:34 -080054using fmt::ULongLong;
Victor Zverovich6e5551e2014-07-02 06:33:25 -070055using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080056
Victor Zverovich8b76e972014-10-06 08:30:55 -070057// Check if exceptions are disabled.
58#if __GNUC__ && !__EXCEPTIONS
59# define FMT_EXCEPTIONS 0
60#endif
61#if _MSC_VER && !_HAS_EXCEPTIONS
62# define FMT_EXCEPTIONS 0
63#endif
64#ifndef FMT_EXCEPTIONS
65# define FMT_EXCEPTIONS 1
66#endif
67
68#if FMT_EXCEPTIONS
69# define FMT_TRY try
70# define FMT_CATCH(x) catch (x)
71#else
72# define FMT_TRY if (true)
73# define FMT_CATCH(x) if (false)
74#endif
75
76#ifndef FMT_THROW
77# if FMT_EXCEPTIONS
78# define FMT_THROW(x) throw x
79# else
80# define FMT_THROW(x) assert(false)
81# endif
82#endif
83
jdale88a9862fd2014-03-11 18:56:24 +000084#if _MSC_VER
85# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070086# pragma warning(disable: 4127) // conditional expression is constant
jdale88a9862fd2014-03-11 18:56:24 +000087#endif
88
Victor Zverovich9ff3b972013-09-07 10:15:08 -070089namespace {
90
91#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070092# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080093#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070094inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080095 va_list args;
96 va_start(args, format);
97 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
98 va_end(args);
99 return result;
100}
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700101# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700102#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800103
Victor Zverovichadce0242014-08-17 07:53:55 -0700104// Checks if a value fits in int - used to avoid warnings about comparing
105// signed and unsigned integers.
106template <bool IsSigned>
107struct IntChecker {
108 template <typename T>
109 static bool fits_in_int(T value) {
110 unsigned max = INT_MAX;
111 return value <= max;
112 }
113};
114
115template <>
116struct IntChecker<true> {
117 template <typename T>
118 static bool fits_in_int(T value) {
119 return value >= INT_MIN && value <= INT_MAX;
120 }
121};
122
Victor Zverovich43fe1002014-02-19 14:20:26 -0800123const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700124
Victor Zverovich22f75d82014-09-03 08:03:05 -0700125typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
126
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700127// Portable thread-safe version of strerror.
128// Sets buffer to point to a string describing the error code.
129// This can be either a pointer to a string stored in buffer,
130// or a pointer to some static immutable string.
131// Returns one of the following values:
132// 0 - success
133// ERANGE - buffer is not large enough to store the error message
134// other - failure
135// Buffer should be at least of size 1.
136int safe_strerror(
137 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
138 assert(buffer != 0 && buffer_size != 0);
139 int result = 0;
140#ifdef _GNU_SOURCE
141 char *message = strerror_r(error_code, buffer, buffer_size);
142 // If the buffer is full then the message is probably truncated.
143 if (message == buffer && strlen(buffer) == buffer_size - 1)
144 result = ERANGE;
145 buffer = message;
146#elif __MINGW32__
147 errno = 0;
148 (void)buffer_size;
149 buffer = strerror(error_code);
150 result = errno;
151#elif _WIN32
152 result = strerror_s(buffer, buffer_size, error_code);
153 // If the buffer is full then the message is probably truncated.
154 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
155 result = ERANGE;
156#else
157 result = strerror_r(error_code, buffer, buffer_size);
158 if (result == -1)
159 result = errno; // glibc versions before 2.13 return result in errno.
160#endif
161 return result;
162}
163
Victor Zverovich22f75d82014-09-03 08:03:05 -0700164void format_error_code(fmt::Writer &out, int error_code,
165 fmt::StringRef message) FMT_NOEXCEPT(true) {
166 // Report error code making sure that the output fits into
167 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
168 // bad_alloc.
169 out.clear();
170 static const char SEP[] = ": ";
171 static const char ERROR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700172 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700173 // Subtract 2 to account for terminating null characters in SEP and ERROR.
Victor Zverovich22f75d82014-09-03 08:03:05 -0700174 std::size_t error_code_size =
Victor Zverovich88e0db82014-09-05 08:04:26 -0700175 sizeof(SEP) + sizeof(ERROR) + fmt::internal::count_digits(ec_value) - 2;
176 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700177 out << message << SEP;
178 out << ERROR << error_code;
179 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
180}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700181
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700182void report_error(FormatFunc func,
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700183 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700184 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700185 func(full_message, error_code, message);
186 // Use Writer::data instead of Writer::c_str to avoid potential memory
187 // allocation.
188 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
189 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700190}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700191
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700192// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
193class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
194 public:
195 template <typename T>
196 bool visit_any_int(T value) { return value == 0; }
197};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700198
199// Parses an unsigned integer advancing s to the end of the parsed input.
200// This function assumes that the first character of s is a digit.
201template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700202int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700203 assert('0' <= *s && *s <= '9');
204 unsigned value = 0;
205 do {
206 unsigned new_value = value * 10 + (*s++ - '0');
207 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700208 if (new_value < value) {
209 value = UINT_MAX;
210 break;
211 }
212 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700213 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700214 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700215 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700216 return value;
217}
Victor Zveroviche8251562014-07-08 16:20:33 -0700218
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700219inline void require_numeric_argument(const Arg &arg, char spec) {
220 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700221 std::string message =
222 fmt::format("format specifier '{}' requires numeric argument", spec);
223 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700224 }
225}
226
Victor Zveroviche8251562014-07-08 16:20:33 -0700227template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700228void check_sign(const Char *&s, const Arg &arg) {
229 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700230 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700231 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700232 FMT_THROW(fmt::FormatError(fmt::format(
233 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700234 }
235 ++s;
236}
237
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700238// Checks if an argument is a valid printf width specifier and sets
239// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700240class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700241 private:
242 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700243
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700244 public:
245 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700246
Victor Zverovich9d74f952014-07-16 07:27:54 -0700247 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700248 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovichd707adc2014-10-13 06:59:18 -0700249 return 0;
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700250 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700251
Victor Zverovich9d74f952014-07-16 07:27:54 -0700252 template <typename T>
253 unsigned visit_any_int(T value) {
254 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
255 UnsignedType width = value;
256 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700257 spec_.align_ = fmt::ALIGN_LEFT;
258 width = 0 - width;
259 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700260 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700261 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700262 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700263 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700264};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700265
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700266class PrecisionHandler :
267 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
268 public:
269 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700270 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zverovich755ecb02014-10-13 08:39:38 -0700271 return 0;
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700272 }
273
274 template <typename T>
275 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700276 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700277 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700278 return static_cast<int>(value);
279 }
280};
281
Victor Zverovich32344d92014-08-28 08:11:21 -0700282// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700283template <typename T>
284class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
285 private:
286 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700287 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700288
289 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700290 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
291 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700292
293 template <typename U>
294 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700295 bool is_signed = type_ == 'd' || type_ == 'i';
296 using fmt::internal::Arg;
297 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700298 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700299 if (is_signed) {
300 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700301 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700302 } else {
303 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700304 arg_.uint_value = static_cast<unsigned>(
305 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700306 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700307 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700308 if (is_signed) {
309 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700310 arg_.long_long_value =
311 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700312 } else {
313 arg_.type = Arg::ULONG_LONG;
314 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700315 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700316 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700317 }
318 }
319};
320
Victor Zverovich32344d92014-08-28 08:11:21 -0700321// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700322class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
323 private:
324 fmt::internal::Arg &arg_;
325
326 public:
327 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
328
329 template <typename T>
330 void visit_any_int(T value) {
331 arg_.type = Arg::CHAR;
332 arg_.int_value = static_cast<char>(value);
333 }
334};
335
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700336// This function template is used to prevent compile errors when handling
337// incompatible string arguments, e.g. handling a wide string in a narrow
338// string formatter.
339template <typename Char>
340Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
341
342template <>
343inline Arg::StringValue<char> ignore_incompatible_str(
344 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
345
346template <>
347inline Arg::StringValue<wchar_t> ignore_incompatible_str(
348 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700349} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700350
Victor Zverovich53201032014-06-30 14:26:29 -0700351void fmt::SystemError::init(
Victor Zverovich1d464042014-09-21 08:08:52 -0700352 int error_code, StringRef format_str, ArgList args) {
Victor Zverovich53201032014-06-30 14:26:29 -0700353 error_code_ = error_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700354 MemoryWriter w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700355 internal::format_system_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700356 std::runtime_error &base = *this;
357 base = std::runtime_error(w.str());
358}
359
Victor Zverovichb605b392013-09-09 22:21:40 -0700360template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700361int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700362 char *buffer, std::size_t size, const char *format,
363 unsigned width, int precision, T value) {
364 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700365 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700366 FMT_SNPRINTF(buffer, size, format, value) :
367 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700368 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700369 return precision < 0 ?
370 FMT_SNPRINTF(buffer, size, format, width, value) :
371 FMT_SNPRINTF(buffer, size, format, width, precision, value);
372}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700373
Victor Zverovichb605b392013-09-09 22:21:40 -0700374template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700375int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700376 wchar_t *buffer, std::size_t size, const wchar_t *format,
377 unsigned width, int precision, T value) {
378 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700379 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700380 swprintf(buffer, size, format, value) :
381 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700382 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700383 return precision < 0 ?
384 swprintf(buffer, size, format, width, value) :
385 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700386}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800387
Victor Zverovich65d47e52013-09-09 06:51:03 -0700388const char fmt::internal::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800389 "0001020304050607080910111213141516171819"
390 "2021222324252627282930313233343536373839"
391 "4041424344454647484950515253545556575859"
392 "6061626364656667686970717273747576777879"
393 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800394
Victor Zverovichf1d85162014-02-19 13:02:22 -0800395#define FMT_POWERS_OF_10(factor) \
396 factor * 10, \
397 factor * 100, \
398 factor * 1000, \
399 factor * 10000, \
400 factor * 100000, \
401 factor * 1000000, \
402 factor * 10000000, \
403 factor * 100000000, \
404 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800405
Victor Zverovichf1d85162014-02-19 13:02:22 -0800406const uint32_t fmt::internal::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)};
Victor Zveroviche9b21912014-02-19 12:43:55 -0800407const uint64_t fmt::internal::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800408 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800409 FMT_POWERS_OF_10(1),
410 FMT_POWERS_OF_10(ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700411 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800412 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800413 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800414};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800415
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700416void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800417 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700418 FMT_THROW(fmt::FormatError(
419 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800420 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700421 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700422 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700423 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800424}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700425
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700426#ifdef _WIN32
427
428fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
429 int length = MultiByteToWideChar(
430 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
431 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
432 if (length == 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700433 FMT_THROW(WindowsError(GetLastError(), ERROR));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700434 buffer_.resize(length);
435 length = MultiByteToWideChar(
436 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
437 if (length == 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700438 FMT_THROW(WindowsError(GetLastError(), ERROR));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700439}
440
441fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700442 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700443 FMT_THROW(WindowsError(error_code,
444 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700445 }
446}
447
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700448int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700449 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
450 if (length == 0)
451 return GetLastError();
452 buffer_.resize(length);
453 length = WideCharToMultiByte(
454 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
455 if (length == 0)
456 return GetLastError();
457 return 0;
458}
459
Victor Zverovich53201032014-06-30 14:26:29 -0700460void fmt::WindowsError::init(
Victor Zverovich1d464042014-09-21 08:08:52 -0700461 int error_code, StringRef format_str, ArgList args) {
Victor Zverovich53201032014-06-30 14:26:29 -0700462 error_code_ = error_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700463 MemoryWriter w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700464 internal::format_windows_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700465 std::runtime_error &base = *this;
466 base = std::runtime_error(w.str());
467}
468
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700469#endif
470
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700471void fmt::internal::format_system_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700472 fmt::Writer &out, int error_code,
473 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700474 FMT_TRY {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700475 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700476 buffer.resize(INLINE_BUFFER_SIZE);
477 char *system_message = 0;
478 for (;;) {
479 system_message = &buffer[0];
480 int result = safe_strerror(error_code, system_message, buffer.size());
481 if (result == 0) {
482 out << message << ": " << system_message;
483 return;
484 }
485 if (result != ERANGE)
486 break; // Can't get error message, report error code instead.
487 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700488 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700489 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700490 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700491}
492
493#ifdef _WIN32
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700494void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700495 fmt::Writer &out, int error_code,
496 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700497 class String {
498 private:
499 LPWSTR str_;
500
501 public:
502 String() : str_() {}
503 ~String() { LocalFree(str_); }
504 LPWSTR *ptr() { return &str_; }
505 LPCWSTR c_str() const { return str_; }
506 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700507 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700508 String system_message;
509 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
510 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
511 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
512 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
513 UTF16ToUTF8 utf8_message;
514 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
515 out << message << ": " << utf8_message;
516 return;
517 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700518 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700519 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700520 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700521}
522#endif
523
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700524// An argument formatter.
525template <typename Char>
526class fmt::internal::ArgFormatter :
527 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
528 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700529 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700530 fmt::BasicWriter<Char> &writer_;
531 fmt::FormatSpec &spec_;
532 const Char *format_;
533
534 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700535 ArgFormatter(
536 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700537 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700538
Victor Zverovich9d74f952014-07-16 07:27:54 -0700539 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700540 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700541
542 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700543 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700544
545 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700546 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700547 spec_.flags_ |= CHAR_FLAG;
548 writer_.write_int(value, spec_);
549 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700550 }
551 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700552 FMT_THROW(FormatError("invalid format specifier for char"));
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700553 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
554 CharPtr out = CharPtr();
555 if (spec_.width_ > 1) {
556 Char fill = static_cast<Char>(spec_.fill());
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700557 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700558 if (spec_.align_ == fmt::ALIGN_RIGHT) {
559 std::fill_n(out, spec_.width_ - 1, fill);
560 out += spec_.width_ - 1;
561 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700562 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700563 } else {
564 std::fill_n(out + 1, spec_.width_ - 1, fill);
565 }
566 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700567 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700568 }
569 *out = static_cast<Char>(value);
570 }
571
572 void visit_string(Arg::StringValue<char> value) {
573 writer_.write_str(value, spec_);
574 }
575 void visit_wstring(Arg::StringValue<wchar_t> value) {
576 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
577 }
578
579 void visit_pointer(const void *value) {
580 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700581 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700582 spec_.flags_ = fmt::HASH_FLAG;
583 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700584 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700585 }
586
587 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700588 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700589 }
590};
591
Victor Zverovichd1ded562014-09-29 08:48:16 -0700592template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700593template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700594void fmt::BasicWriter<Char>::write_str(
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700595 const Arg::StringValue<StrChar> &str, const FormatSpec &spec) {
596 // Check if StrChar is convertible to Char.
597 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700598 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700599 internal::report_unknown_type(spec.type_, "string");
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700600 const StrChar *s = str.value;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700601 std::size_t size = str.size;
602 if (size == 0) {
603 if (!s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700604 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700605 if (*s)
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700606 size = std::char_traits<StrChar>::length(s);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700607 }
Victor Zverovich53201032014-06-30 14:26:29 -0700608 write_str(s, size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700609}
610
611template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700612inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700613 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700614 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700615 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700616 if (error) {
617 FMT_THROW(FormatError(
618 *s != '}' && *s != ':' ? "invalid format string" : error));
619 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700620 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700621}
622
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700623Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700624 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700625 Arg arg = args_[arg_index];
626 if (arg.type == Arg::NONE)
627 error = "argument index out of range";
628 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700629}
630
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700631inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700632 if (next_arg_index_ >= 0)
633 return do_get_arg(next_arg_index_++, error);
634 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700635 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700636}
637
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700638inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700639 unsigned arg_index, const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700640 if (next_arg_index_ <= 0) {
641 next_arg_index_ = -1;
642 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700643 }
Victor Zverovich605d2602014-08-29 07:45:55 -0700644 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700645 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700646}
647
Victor Zverovich7cae7632013-09-06 20:23:42 -0700648template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700649void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700650 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700651 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700652 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700653 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700654 spec.align_ = ALIGN_LEFT;
655 break;
656 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700657 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
658 break;
659 case '0':
660 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700661 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700662 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700663 spec.flags_ |= SIGN_FLAG;
664 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700665 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700666 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700667 break;
668 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700669 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700670 return;
671 }
672 }
673}
674
Victor Zverovichcb743c02014-06-19 07:40:35 -0700675template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700676Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700677 const Char *s, unsigned arg_index) {
678 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700679 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700680 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
681 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700682 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700683 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700684}
685
686template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700687unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700688 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700689 unsigned arg_index = UINT_MAX;
690 Char c = *s;
691 if (c >= '0' && c <= '9') {
692 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700693 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700694 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700695 if (*s == '$') { // value is an argument index
696 ++s;
697 arg_index = value;
698 } else {
699 if (c == '0')
700 spec.fill_ = '0';
701 if (value != 0) {
702 // Nonzero value means that we parsed width and don't need to
703 // parse it or flags again, so return now.
704 spec.width_ = value;
705 return arg_index;
706 }
707 }
708 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700709 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700710 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700711 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700712 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700713 } else if (*s == '*') {
714 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700715 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700716 }
717 return arg_index;
718}
719
Victor Zverovich1f19b982014-06-16 07:49:30 -0700720template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700721void fmt::internal::PrintfFormatter<Char>::format(
Victor Zveroviche78904b2014-04-23 08:27:50 -0700722 BasicWriter<Char> &writer, BasicStringRef<Char> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700723 const ArgList &args) {
Victor Zveroviche78904b2014-04-23 08:27:50 -0700724 const Char *start = format.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700725 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700726 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700727 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700728 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700729 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700730 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700731 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700732 start = ++s;
733 continue;
734 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700735 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700736
Victor Zverovichcb743c02014-06-19 07:40:35 -0700737 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700738 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700739
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700740 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700741 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700742
743 // Parse precision.
744 if (*s == '.') {
745 ++s;
746 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700747 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700748 } else if (*s == '*') {
749 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700750 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700751 }
752 }
753
Victor Zverovich56fc5252014-08-28 07:48:55 -0700754 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700755 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700756 spec.flags_ &= ~HASH_FLAG;
757 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700758 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700759 spec.align_ = ALIGN_NUMERIC;
760 else
761 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700762 }
763
Victor Zverovichf4156b52014-07-30 08:39:07 -0700764 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700765 switch (*s++) {
766 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700767 if (*s == 'h')
768 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700769 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700770 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700771 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700772 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700773 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700774 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700775 else
776 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700777 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700778 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700779 ArgConverter<intmax_t>(arg, *s).visit(arg);
780 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700781 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700782 ArgConverter<size_t>(arg, *s).visit(arg);
783 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700784 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700785 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
786 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700787 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700788 // printf produces garbage when 'L' is omitted for long double, no
789 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700790 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700791 default:
792 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700793 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700794 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700795
796 // Parse type.
797 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700798 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700799 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700800 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
801 // Normalize type.
802 switch (spec.type_) {
803 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700804 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700805 break;
806 case 'c':
807 // TODO: handle wchar_t
808 CharConverter(arg).visit(arg);
809 break;
810 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700811 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700812
813 start = s;
814
815 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700816 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700817 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700818 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700819 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700820 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700821 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700822 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700823 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700824 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700825 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700826 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700827 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700828 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700829 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700830 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700831 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700832 typedef typename BasicWriter<Char>::CharPtr CharPtr;
833 CharPtr out = CharPtr();
834 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700835 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700836 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700837 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700838 std::fill_n(out, spec.width_ - 1, fill);
839 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700840 } else {
841 std::fill_n(out + 1, spec.width_ - 1, fill);
842 }
843 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700844 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700845 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700846 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700847 break;
848 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700849 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700850 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700851 break;
852 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700853 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700854 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -0700855 case Arg::CSTRING:
856 arg.string.size = 0;
857 writer.write_str(arg.string, spec);
858 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700859 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700860 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700861 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700862 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700863 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700864 break;
865 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700866 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700867 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700868 spec.flags_= HASH_FLAG;
869 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -0700870 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700871 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700872 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700873 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700874 internal::report_unknown_type(spec.type_, "object");
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700875 const void *s = "s";
876 arg.custom.format(&writer, arg.custom.value, &s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700877 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700878 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700879 default:
880 assert(false);
881 break;
882 }
883 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700884 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700885}
886
887template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700888const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700889 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700890 const Char *s = format_str;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700891 const char *error = 0;
Victor Zveroviche8251562014-07-08 16:20:33 -0700892 FormatSpec spec;
893 if (*s == ':') {
894 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700895 arg.custom.format(this, arg.custom.value, &s);
896 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700897 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700898 ++s;
899 // Parse fill and alignment.
900 if (Char c = *s) {
901 const Char *p = s + 1;
902 spec.align_ = ALIGN_DEFAULT;
903 do {
904 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700905 case '<':
906 spec.align_ = ALIGN_LEFT;
907 break;
908 case '>':
909 spec.align_ = ALIGN_RIGHT;
910 break;
911 case '=':
912 spec.align_ = ALIGN_NUMERIC;
913 break;
914 case '^':
915 spec.align_ = ALIGN_CENTER;
916 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700917 }
918 if (spec.align_ != ALIGN_DEFAULT) {
919 if (p != s) {
920 if (c == '}') break;
921 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700922 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700923 s += 2;
924 spec.fill_ = c;
925 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700926 if (spec.align_ == ALIGN_NUMERIC)
927 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -0700928 break;
929 }
930 } while (--p >= s);
931 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700932
Victor Zveroviche8251562014-07-08 16:20:33 -0700933 // Parse sign.
934 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700935 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700936 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700937 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
938 break;
939 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700940 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700941 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700942 break;
943 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700944 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700945 spec.flags_ |= SIGN_FLAG;
946 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700947 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700948
Victor Zveroviche8251562014-07-08 16:20:33 -0700949 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700950 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -0700951 spec.flags_ |= HASH_FLAG;
952 ++s;
953 }
954
955 // Parse width and zero flag.
956 if ('0' <= *s && *s <= '9') {
957 if (*s == '0') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700958 require_numeric_argument(arg, '0');
Victor Zveroviche8251562014-07-08 16:20:33 -0700959 spec.align_ = ALIGN_NUMERIC;
960 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700961 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700962 // Zero may be parsed again as a part of the width, but it is simpler
963 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700964 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700965 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700966 FMT_THROW(FormatError(error));
Victor Zveroviche8251562014-07-08 16:20:33 -0700967 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700968
Victor Zveroviche8251562014-07-08 16:20:33 -0700969 // Parse precision.
970 if (*s == '.') {
971 ++s;
972 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700973 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700974 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700975 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700976 FMT_THROW(FormatError(error));
Victor Zveroviche8251562014-07-08 16:20:33 -0700977 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700978 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700979 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -0700980 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700981 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700982 ULongLong value = 0;
983 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700984 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700985 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700986 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -0700987 value = precision_arg.int_value;
988 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700989 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700990 value = precision_arg.uint_value;
991 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700992 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -0800993 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700994 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -0800995 value = precision_arg.long_long_value;
996 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700997 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -0800998 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -0800999 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001000 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001001 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001002 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001003 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001004 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001005 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001006 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001007 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001008 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001009 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001010 FMT_THROW(FormatError(
1011 "precision specifier requires floating-point argument"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001012 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001013 }
1014
Victor Zveroviche8251562014-07-08 16:20:33 -07001015 // Parse type.
1016 if (*s != '}' && *s)
1017 spec.type_ = static_cast<char>(*s++);
1018 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001019
Victor Zveroviche8251562014-07-08 16:20:33 -07001020 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001021 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001022 start_ = s;
1023
1024 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001025 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001026 return s;
1027}
1028
1029template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001030void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001031 BasicStringRef<Char> format_str, const ArgList &args) {
1032 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001033 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001034 while (*s) {
1035 Char c = *s++;
1036 if (c != '{' && c != '}') continue;
1037 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001038 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001039 start_ = ++s;
1040 continue;
1041 }
1042 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001043 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001044 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001045 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001046 s = format(s, arg);
1047 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001048 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001049}
1050
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001051void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001052 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001053 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001054}
1055
Victor Zverovich400812a2014-04-30 12:38:17 -07001056#ifdef _WIN32
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001057void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001058 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001059 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001060}
Victor Zverovich400812a2014-04-30 12:38:17 -07001061#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001062
Victor Zverovich1d464042014-09-21 08:08:52 -07001063void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001064 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001065 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001066 std::fwrite(w.data(), 1, w.size(), f);
1067}
1068
Victor Zverovich163178e2014-09-25 07:08:25 -07001069void fmt::print(StringRef format_str, ArgList args) {
1070 print(stdout, format_str, args);
1071}
1072
Victor Zverovich1d464042014-09-21 08:08:52 -07001073void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001074 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001075 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001076 os.write(w.data(), w.size());
1077}
1078
Victor Zverovich1d464042014-09-21 08:08:52 -07001079void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001080 char escape[] = "\x1b[30m";
1081 escape[3] = '0' + static_cast<char>(c);
1082 std::fputs(escape, stdout);
1083 print(format, args);
1084 std::fputs(RESET_COLOR, stdout);
1085}
1086
Victor Zverovich1d464042014-09-21 08:08:52 -07001087int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001088 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001089 printf(w, format, args);
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001090 return std::fwrite(w.data(), 1, w.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001091}
1092
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001093// Explicit instantiations for char.
1094
Victor Zverovichf43caef2014-09-25 07:21:48 -07001095template const char *fmt::BasicFormatter<char>::format(
1096 const char *&format_str, const fmt::internal::Arg &arg);
1097
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001098template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001099 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001100
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001101template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001102 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001103
Victor Zverovich14f25772014-09-19 08:45:05 -07001104template int fmt::internal::CharTraits<char>::format_float(
1105 char *buffer, std::size_t size, const char *format,
1106 unsigned width, int precision, double value);
1107
1108template int fmt::internal::CharTraits<char>::format_float(
1109 char *buffer, std::size_t size, const char *format,
1110 unsigned width, int precision, long double value);
1111
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001112// Explicit instantiations for wchar_t.
1113
Victor Zverovichf43caef2014-09-25 07:21:48 -07001114template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1115 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1116
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001117template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001118 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001119
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001120template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001121 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001122 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001123
Victor Zverovich14f25772014-09-19 08:45:05 -07001124template int fmt::internal::CharTraits<wchar_t>::format_float(
1125 wchar_t *buffer, std::size_t size, const wchar_t *format,
1126 unsigned width, int precision, double value);
1127
1128template int fmt::internal::CharTraits<wchar_t>::format_float(
1129 wchar_t *buffer, std::size_t size, const wchar_t *format,
1130 unsigned width, int precision, long double value);
1131
jdale88a9862fd2014-03-11 18:56:24 +00001132#if _MSC_VER
1133# pragma warning(pop)
1134#endif