blob: 01380504a099c3db23c19b4f27f31327ef9e33f3 [file] [log] [blame]
Victor Zverovichb076df42012-12-07 08:31:09 -08001/*
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07002 Formatting library for C++
Victor Zverovichfaccb4c2012-12-12 07:44:41 -08003
Victor Zveroviche3a44c12014-07-09 06:56:36 -07004 Copyright (c) 2012 - 2014, Victor Zverovich
Victor Zverovichfaccb4c2012-12-12 07:44:41 -08005 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Victor Zverovichb076df42012-12-07 08:31:09 -080026 */
27
Victor Zverovichfbfedcf2013-01-14 15:16:20 -080028#include "format.h"
29
Victor Zverovich859a4972014-04-30 06:55:21 -070030#include <string.h>
31
Victor Zverovich72f896d2012-12-12 09:17:28 -080032#include <cctype>
Victor Zverovich5d15bdd2014-07-01 16:23:50 -070033#include <cerrno>
Victor Zverovichf28645f2014-04-24 12:37:06 -070034#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070035#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080036#include <cstdarg>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070037
Victor Zverovich859a4972014-04-30 06:55:21 -070038#ifdef _WIN32
Constantine Tarasenkov6aace692014-06-11 02:38:57 +040039# ifdef __MINGW32__
40# include <cstring>
41# endif
Victor Zverovich859a4972014-04-30 06:55:21 -070042# include <windows.h>
43#endif
44
Victor Zverovich6e5551e2014-07-02 06:33:25 -070045using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080046
Victor Zverovich8b76e972014-10-06 08:30:55 -070047// Check if exceptions are disabled.
48#if __GNUC__ && !__EXCEPTIONS
49# define FMT_EXCEPTIONS 0
50#endif
51#if _MSC_VER && !_HAS_EXCEPTIONS
52# define FMT_EXCEPTIONS 0
53#endif
54#ifndef FMT_EXCEPTIONS
55# define FMT_EXCEPTIONS 1
56#endif
57
58#if FMT_EXCEPTIONS
59# define FMT_TRY try
60# define FMT_CATCH(x) catch (x)
61#else
62# define FMT_TRY if (true)
63# define FMT_CATCH(x) if (false)
64#endif
65
66#ifndef FMT_THROW
67# if FMT_EXCEPTIONS
68# define FMT_THROW(x) throw x
69# else
70# define FMT_THROW(x) assert(false)
71# endif
72#endif
73
Victor Zverovichd9c605c2014-11-28 06:40:57 -080074#ifdef FMT_HEADER_ONLY
75# define FMT_FUNC inline
Victor Zverovichc2a69032014-11-28 15:30:03 -080076#else
77# define FMT_FUNC
Victor Zverovichd9c605c2014-11-28 06:40:57 -080078#endif
79
jdale88a9862fd2014-03-11 18:56:24 +000080#if _MSC_VER
81# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070082# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050083# pragma warning(disable: 4702) // unreachable code
jdale88a9862fd2014-03-11 18:56:24 +000084#endif
85
Victor Zverovich9ff3b972013-09-07 10:15:08 -070086namespace {
87
88#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070089# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080090#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070091inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080092 va_list args;
93 va_start(args, format);
94 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
95 va_end(args);
96 return result;
97}
Victor Zverovichb9a568b2014-09-19 07:51:42 -070098# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -070099#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800100
Victor Zverovichadce0242014-08-17 07:53:55 -0700101// Checks if a value fits in int - used to avoid warnings about comparing
102// signed and unsigned integers.
103template <bool IsSigned>
104struct IntChecker {
105 template <typename T>
106 static bool fits_in_int(T value) {
107 unsigned max = INT_MAX;
108 return value <= max;
109 }
110};
111
112template <>
113struct IntChecker<true> {
114 template <typename T>
115 static bool fits_in_int(T value) {
116 return value >= INT_MIN && value <= INT_MAX;
117 }
118};
119
Victor Zverovich43fe1002014-02-19 14:20:26 -0800120const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700121
Victor Zverovich22f75d82014-09-03 08:03:05 -0700122typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
123
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700124// Portable thread-safe version of strerror.
125// Sets buffer to point to a string describing the error code.
126// This can be either a pointer to a string stored in buffer,
127// or a pointer to some static immutable string.
128// Returns one of the following values:
129// 0 - success
130// ERANGE - buffer is not large enough to store the error message
131// other - failure
132// Buffer should be at least of size 1.
133int safe_strerror(
134 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
135 assert(buffer != 0 && buffer_size != 0);
136 int result = 0;
137#ifdef _GNU_SOURCE
138 char *message = strerror_r(error_code, buffer, buffer_size);
139 // If the buffer is full then the message is probably truncated.
140 if (message == buffer && strlen(buffer) == buffer_size - 1)
141 result = ERANGE;
142 buffer = message;
143#elif __MINGW32__
144 errno = 0;
145 (void)buffer_size;
146 buffer = strerror(error_code);
147 result = errno;
148#elif _WIN32
149 result = strerror_s(buffer, buffer_size, error_code);
150 // If the buffer is full then the message is probably truncated.
151 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
152 result = ERANGE;
153#else
154 result = strerror_r(error_code, buffer, buffer_size);
155 if (result == -1)
156 result = errno; // glibc versions before 2.13 return result in errno.
157#endif
158 return result;
159}
160
Victor Zverovich22f75d82014-09-03 08:03:05 -0700161void format_error_code(fmt::Writer &out, int error_code,
162 fmt::StringRef message) FMT_NOEXCEPT(true) {
163 // Report error code making sure that the output fits into
164 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
165 // bad_alloc.
166 out.clear();
167 static const char SEP[] = ": ";
Victor Zverovichdff21372014-12-16 07:01:01 -0800168 static const char ERR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700169 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
Victor Zverovichdff21372014-12-16 07:01:01 -0800170 // Subtract 2 to account for terminating null characters in SEP and ERR.
Victor Zverovich22f75d82014-09-03 08:03:05 -0700171 std::size_t error_code_size =
Victor Zverovichdff21372014-12-16 07:01:01 -0800172 sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700173 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700174 out << message << SEP;
Victor Zverovichdff21372014-12-16 07:01:01 -0800175 out << ERR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700176 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
177}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700178
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700179void report_error(FormatFunc func,
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700180 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700181 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700182 func(full_message, error_code, message);
183 // Use Writer::data instead of Writer::c_str to avoid potential memory
184 // allocation.
185 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
186 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700187}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700188
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700189// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
190class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
191 public:
192 template <typename T>
193 bool visit_any_int(T value) { return value == 0; }
194};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700195
196// Parses an unsigned integer advancing s to the end of the parsed input.
197// This function assumes that the first character of s is a digit.
198template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700199int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700200 assert('0' <= *s && *s <= '9');
201 unsigned value = 0;
202 do {
203 unsigned new_value = value * 10 + (*s++ - '0');
204 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700205 if (new_value < value) {
206 value = UINT_MAX;
207 break;
208 }
209 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700210 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700211 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700212 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700213 return value;
214}
Victor Zveroviche8251562014-07-08 16:20:33 -0700215
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700216inline void require_numeric_argument(const Arg &arg, char spec) {
217 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700218 std::string message =
219 fmt::format("format specifier '{}' requires numeric argument", spec);
220 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700221 }
222}
223
Victor Zveroviche8251562014-07-08 16:20:33 -0700224template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700225void check_sign(const Char *&s, const Arg &arg) {
226 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700227 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700228 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700229 FMT_THROW(fmt::FormatError(fmt::format(
230 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700231 }
232 ++s;
233}
234
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700235// Checks if an argument is a valid printf width specifier and sets
236// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700237class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700238 private:
239 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700240
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800241 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
242
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700243 public:
244 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700245
Victor Zverovich9d74f952014-07-16 07:27:54 -0700246 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700247 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovichd707adc2014-10-13 06:59:18 -0700248 return 0;
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700249 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700250
Victor Zverovich9d74f952014-07-16 07:27:54 -0700251 template <typename T>
252 unsigned visit_any_int(T value) {
253 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
254 UnsignedType width = value;
255 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700256 spec_.align_ = fmt::ALIGN_LEFT;
257 width = 0 - width;
258 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700259 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700260 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700261 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700262 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700263};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700264
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700265class PrecisionHandler :
266 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
267 public:
268 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700269 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zverovich755ecb02014-10-13 08:39:38 -0700270 return 0;
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700271 }
272
273 template <typename T>
274 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700275 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700276 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700277 return static_cast<int>(value);
278 }
279};
280
Victor Zverovich32344d92014-08-28 08:11:21 -0700281// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700282template <typename T>
283class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
284 private:
285 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700286 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700287
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800288 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
289
Victor Zverovicheeca2232014-07-30 07:37:16 -0700290 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700291 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
292 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700293
294 template <typename U>
295 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700296 bool is_signed = type_ == 'd' || type_ == 'i';
297 using fmt::internal::Arg;
298 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700299 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700300 if (is_signed) {
301 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700302 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700303 } else {
304 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700305 arg_.uint_value = static_cast<unsigned>(
306 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700307 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700308 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700309 if (is_signed) {
310 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700311 arg_.long_long_value =
312 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700313 } else {
314 arg_.type = Arg::ULONG_LONG;
315 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700316 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700317 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700318 }
319 }
320};
321
Victor Zverovich32344d92014-08-28 08:11:21 -0700322// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700323class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
324 private:
325 fmt::internal::Arg &arg_;
326
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800327 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
328
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700329 public:
330 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
331
332 template <typename T>
333 void visit_any_int(T value) {
334 arg_.type = Arg::CHAR;
335 arg_.int_value = static_cast<char>(value);
336 }
337};
338
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700339// This function template is used to prevent compile errors when handling
340// incompatible string arguments, e.g. handling a wide string in a narrow
341// string formatter.
342template <typename Char>
343Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
344
345template <>
346inline Arg::StringValue<char> ignore_incompatible_str(
347 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
348
349template <>
350inline Arg::StringValue<wchar_t> ignore_incompatible_str(
351 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700352} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700353
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800354FMT_FUNC void fmt::SystemError::init(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800355 int err_code, StringRef format_str, ArgList args) {
356 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700357 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800358 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700359 std::runtime_error &base = *this;
360 base = std::runtime_error(w.str());
361}
362
Victor Zverovichb605b392013-09-09 22:21:40 -0700363template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700364int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700365 char *buffer, std::size_t size, const char *format,
366 unsigned width, int precision, T value) {
367 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700368 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700369 FMT_SNPRINTF(buffer, size, format, value) :
370 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700371 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700372 return precision < 0 ?
373 FMT_SNPRINTF(buffer, size, format, width, value) :
374 FMT_SNPRINTF(buffer, size, format, width, precision, value);
375}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700376
Victor Zverovichb605b392013-09-09 22:21:40 -0700377template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700378int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700379 wchar_t *buffer, std::size_t size, const wchar_t *format,
380 unsigned width, int precision, T value) {
381 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700382 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700383 swprintf(buffer, size, format, value) :
384 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700385 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700386 return precision < 0 ?
387 swprintf(buffer, size, format, width, value) :
388 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700389}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800390
Victor Zverovich311251e2014-11-29 06:58:00 -0800391template <typename T>
392const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800393 "0001020304050607080910111213141516171819"
394 "2021222324252627282930313233343536373839"
395 "4041424344454647484950515253545556575859"
396 "6061626364656667686970717273747576777879"
397 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800398
Victor Zverovichf1d85162014-02-19 13:02:22 -0800399#define FMT_POWERS_OF_10(factor) \
400 factor * 10, \
401 factor * 100, \
402 factor * 1000, \
403 factor * 10000, \
404 factor * 100000, \
405 factor * 1000000, \
406 factor * 10000000, \
407 factor * 100000000, \
408 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800409
Victor Zverovich311251e2014-11-29 06:58:00 -0800410template <typename T>
411const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
412 0, FMT_POWERS_OF_10(1)
413};
414
415template <typename T>
416const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800417 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800418 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800419 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700420 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800421 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800422 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800423};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800424
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800425FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800426 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700427 FMT_THROW(fmt::FormatError(
428 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800429 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700430 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700431 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700432 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800433}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700434
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700435#ifdef _WIN32
436
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800437FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700438 int length = MultiByteToWideChar(
439 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
Victor Zverovichdff21372014-12-16 07:01:01 -0800440 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700441 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800442 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700443 buffer_.resize(length);
444 length = MultiByteToWideChar(
445 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
446 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800447 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700448}
449
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800450FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700451 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700452 FMT_THROW(WindowsError(error_code,
453 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700454 }
455}
456
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800457FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700458 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
459 if (length == 0)
460 return GetLastError();
461 buffer_.resize(length);
462 length = WideCharToMultiByte(
463 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
464 if (length == 0)
465 return GetLastError();
466 return 0;
467}
468
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800469FMT_FUNC void fmt::WindowsError::init(
Victor Zverovich1d464042014-09-21 08:08:52 -0700470 int error_code, StringRef format_str, ArgList args) {
Victor Zverovich53201032014-06-30 14:26:29 -0700471 error_code_ = error_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700472 MemoryWriter w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700473 internal::format_windows_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700474 std::runtime_error &base = *this;
475 base = std::runtime_error(w.str());
476}
477
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700478#endif
479
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800480FMT_FUNC void fmt::internal::format_system_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700481 fmt::Writer &out, int error_code,
482 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700483 FMT_TRY {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700484 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700485 buffer.resize(INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700486 for (;;) {
Victor Zverovichaca49372014-11-24 07:38:26 -0800487 char *system_message = &buffer[0];
Victor Zverovich22f75d82014-09-03 08:03:05 -0700488 int result = safe_strerror(error_code, system_message, buffer.size());
489 if (result == 0) {
490 out << message << ": " << system_message;
491 return;
492 }
493 if (result != ERANGE)
494 break; // Can't get error message, report error code instead.
495 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700496 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700497 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700498 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700499}
500
501#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800502FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700503 fmt::Writer &out, int error_code,
504 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700505 class String {
506 private:
507 LPWSTR str_;
508
509 public:
510 String() : str_() {}
511 ~String() { LocalFree(str_); }
512 LPWSTR *ptr() { return &str_; }
513 LPCWSTR c_str() const { return str_; }
514 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700515 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700516 String system_message;
517 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
518 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
519 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
520 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
521 UTF16ToUTF8 utf8_message;
522 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
523 out << message << ": " << utf8_message;
524 return;
525 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700526 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700527 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700528 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700529}
530#endif
531
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700532// An argument formatter.
533template <typename Char>
534class fmt::internal::ArgFormatter :
535 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
536 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700537 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700538 fmt::BasicWriter<Char> &writer_;
539 fmt::FormatSpec &spec_;
540 const Char *format_;
541
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800542 FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
543
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700544 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700545 ArgFormatter(
546 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700547 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700548
Victor Zverovich9d74f952014-07-16 07:27:54 -0700549 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700550 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700551
552 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700553 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700554
555 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700556 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700557 spec_.flags_ |= CHAR_FLAG;
558 writer_.write_int(value, spec_);
559 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700560 }
561 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700562 FMT_THROW(FormatError("invalid format specifier for char"));
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700563 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
564 CharPtr out = CharPtr();
565 if (spec_.width_ > 1) {
566 Char fill = static_cast<Char>(spec_.fill());
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700567 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700568 if (spec_.align_ == fmt::ALIGN_RIGHT) {
569 std::fill_n(out, spec_.width_ - 1, fill);
570 out += spec_.width_ - 1;
571 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700572 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700573 } else {
574 std::fill_n(out + 1, spec_.width_ - 1, fill);
575 }
576 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700577 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700578 }
579 *out = static_cast<Char>(value);
580 }
581
582 void visit_string(Arg::StringValue<char> value) {
583 writer_.write_str(value, spec_);
584 }
585 void visit_wstring(Arg::StringValue<wchar_t> value) {
586 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
587 }
588
589 void visit_pointer(const void *value) {
590 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700591 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700592 spec_.flags_ = fmt::HASH_FLAG;
593 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700594 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700595 }
596
597 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700598 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700599 }
600};
601
Victor Zverovichd1ded562014-09-29 08:48:16 -0700602template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700603template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700604void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800605 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700606 // Check if StrChar is convertible to Char.
607 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700608 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700609 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800610 const StrChar *str_value = s.value;
611 std::size_t str_size = s.size;
612 if (str_size == 0) {
613 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700614 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800615 if (*str_value)
616 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700617 }
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800618 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700619}
620
621template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700622inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700623 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700624 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700625 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700626 if (error) {
627 FMT_THROW(FormatError(
628 *s != '}' && *s != ':' ? "invalid format string" : error));
629 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700630 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700631}
632
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800633FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700634 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700635 Arg arg = args_[arg_index];
636 if (arg.type == Arg::NONE)
637 error = "argument index out of range";
638 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700639}
640
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700641inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700642 if (next_arg_index_ >= 0)
643 return do_get_arg(next_arg_index_++, error);
644 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700645 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700646}
647
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700648inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700649 unsigned arg_index, const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700650 if (next_arg_index_ <= 0) {
651 next_arg_index_ = -1;
652 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700653 }
Victor Zverovich605d2602014-08-29 07:45:55 -0700654 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700655 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700656}
657
Victor Zverovich7cae7632013-09-06 20:23:42 -0700658template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700659void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700660 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700661 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700662 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700663 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700664 spec.align_ = ALIGN_LEFT;
665 break;
666 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700667 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
668 break;
669 case '0':
670 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700671 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700672 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700673 spec.flags_ |= SIGN_FLAG;
674 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700675 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700676 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700677 break;
678 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700679 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700680 return;
681 }
682 }
683}
684
Victor Zverovichcb743c02014-06-19 07:40:35 -0700685template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700686Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700687 const Char *s, unsigned arg_index) {
688 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700689 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700690 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
691 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700692 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700693 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700694}
695
696template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700697unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700698 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700699 unsigned arg_index = UINT_MAX;
700 Char c = *s;
701 if (c >= '0' && c <= '9') {
702 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700703 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700704 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700705 if (*s == '$') { // value is an argument index
706 ++s;
707 arg_index = value;
708 } else {
709 if (c == '0')
710 spec.fill_ = '0';
711 if (value != 0) {
712 // Nonzero value means that we parsed width and don't need to
713 // parse it or flags again, so return now.
714 spec.width_ = value;
715 return arg_index;
716 }
717 }
718 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700719 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700720 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700721 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700722 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700723 } else if (*s == '*') {
724 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700725 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700726 }
727 return arg_index;
728}
729
Victor Zverovich1f19b982014-06-16 07:49:30 -0700730template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700731void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800732 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700733 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800734 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700735 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700736 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700737 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700738 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700739 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700740 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700741 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700742 start = ++s;
743 continue;
744 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700745 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700746
Victor Zverovichcb743c02014-06-19 07:40:35 -0700747 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700748 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700749
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700750 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700751 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700752
753 // Parse precision.
754 if (*s == '.') {
755 ++s;
756 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700757 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700758 } else if (*s == '*') {
759 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700760 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700761 }
762 }
763
Victor Zverovich56fc5252014-08-28 07:48:55 -0700764 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700765 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700766 spec.flags_ &= ~HASH_FLAG;
767 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700768 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700769 spec.align_ = ALIGN_NUMERIC;
770 else
771 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700772 }
773
Victor Zverovichf4156b52014-07-30 08:39:07 -0700774 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700775 switch (*s++) {
776 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700777 if (*s == 'h')
778 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700779 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700780 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700781 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700782 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700783 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700784 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700785 else
786 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700787 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700788 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700789 ArgConverter<intmax_t>(arg, *s).visit(arg);
790 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700791 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700792 ArgConverter<size_t>(arg, *s).visit(arg);
793 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700794 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700795 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
796 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700797 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700798 // printf produces garbage when 'L' is omitted for long double, no
799 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700800 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700801 default:
802 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700803 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700804 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700805
806 // Parse type.
807 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700808 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700809 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700810 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
811 // Normalize type.
812 switch (spec.type_) {
813 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700814 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700815 break;
816 case 'c':
817 // TODO: handle wchar_t
818 CharConverter(arg).visit(arg);
819 break;
820 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700821 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700822
823 start = s;
824
825 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700826 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700827 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700828 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700829 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700830 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700831 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700832 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700833 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700834 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700835 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700836 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700837 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700838 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700839 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700840 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700841 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700842 typedef typename BasicWriter<Char>::CharPtr CharPtr;
843 CharPtr out = CharPtr();
844 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700845 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700846 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700847 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700848 std::fill_n(out, spec.width_ - 1, fill);
849 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700850 } else {
851 std::fill_n(out + 1, spec.width_ - 1, fill);
852 }
853 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700854 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700855 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700856 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700857 break;
858 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700859 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700860 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700861 break;
862 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700863 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700864 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -0700865 case Arg::CSTRING:
866 arg.string.size = 0;
867 writer.write_str(arg.string, spec);
868 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700869 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700870 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700871 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700872 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700873 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700874 break;
875 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700876 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700877 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700878 spec.flags_= HASH_FLAG;
879 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -0700880 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700881 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700882 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700883 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700884 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800885 const void *str_format = "s";
886 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700887 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700888 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700889 default:
890 assert(false);
891 break;
892 }
893 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700894 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700895}
896
897template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700898const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700899 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700900 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -0700901 FormatSpec spec;
902 if (*s == ':') {
903 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700904 arg.custom.format(this, arg.custom.value, &s);
905 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700906 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700907 ++s;
908 // Parse fill and alignment.
909 if (Char c = *s) {
910 const Char *p = s + 1;
911 spec.align_ = ALIGN_DEFAULT;
912 do {
913 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700914 case '<':
915 spec.align_ = ALIGN_LEFT;
916 break;
917 case '>':
918 spec.align_ = ALIGN_RIGHT;
919 break;
920 case '=':
921 spec.align_ = ALIGN_NUMERIC;
922 break;
923 case '^':
924 spec.align_ = ALIGN_CENTER;
925 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700926 }
927 if (spec.align_ != ALIGN_DEFAULT) {
928 if (p != s) {
929 if (c == '}') break;
930 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700931 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700932 s += 2;
933 spec.fill_ = c;
934 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700935 if (spec.align_ == ALIGN_NUMERIC)
936 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -0700937 break;
938 }
939 } while (--p >= s);
940 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700941
Victor Zveroviche8251562014-07-08 16:20:33 -0700942 // Parse sign.
943 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700944 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700945 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700946 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
947 break;
948 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700949 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700950 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700951 break;
952 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700953 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700954 spec.flags_ |= SIGN_FLAG;
955 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700956 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700957
Victor Zveroviche8251562014-07-08 16:20:33 -0700958 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700959 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -0700960 spec.flags_ |= HASH_FLAG;
961 ++s;
962 }
963
964 // Parse width and zero flag.
965 if ('0' <= *s && *s <= '9') {
966 if (*s == '0') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700967 require_numeric_argument(arg, '0');
Victor Zveroviche8251562014-07-08 16:20:33 -0700968 spec.align_ = ALIGN_NUMERIC;
969 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700970 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700971 // Zero may be parsed again as a part of the width, but it is simpler
972 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700973 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700974 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700975
Victor Zveroviche8251562014-07-08 16:20:33 -0700976 // Parse precision.
977 if (*s == '.') {
978 ++s;
979 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700980 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700981 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700982 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700983 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700984 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -0700985 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700986 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700987 ULongLong value = 0;
988 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700989 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700990 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700991 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -0700992 value = precision_arg.int_value;
993 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700994 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700995 value = precision_arg.uint_value;
996 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700997 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -0800998 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700999 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001000 value = precision_arg.long_long_value;
1001 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001002 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001003 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001004 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001005 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001006 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001007 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001008 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001009 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001010 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001011 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001012 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001013 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001014 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001015 FMT_THROW(FormatError(
1016 "precision specifier requires floating-point argument"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001017 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001018 }
1019
Victor Zveroviche8251562014-07-08 16:20:33 -07001020 // Parse type.
1021 if (*s != '}' && *s)
1022 spec.type_ = static_cast<char>(*s++);
1023 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001024
Victor Zveroviche8251562014-07-08 16:20:33 -07001025 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001026 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001027 start_ = s;
1028
1029 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001030 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001031 return s;
1032}
1033
1034template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001035void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001036 BasicStringRef<Char> format_str, const ArgList &args) {
1037 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001038 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001039 while (*s) {
1040 Char c = *s++;
1041 if (c != '{' && c != '}') continue;
1042 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001043 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001044 start_ = ++s;
1045 continue;
1046 }
1047 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001048 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001049 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001050 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001051 s = format(s, arg);
1052 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001053 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001054}
1055
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001056FMT_FUNC void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001057 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001058 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001059}
1060
Victor Zverovich400812a2014-04-30 12:38:17 -07001061#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001062FMT_FUNC void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001063 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001064 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001065}
Victor Zverovich400812a2014-04-30 12:38:17 -07001066#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001067
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001068FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001069 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001070 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001071 std::fwrite(w.data(), 1, w.size(), f);
1072}
1073
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001074FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001075 print(stdout, format_str, args);
1076}
1077
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001078FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001079 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001080 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001081 os.write(w.data(), w.size());
1082}
1083
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001084FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001085 char escape[] = "\x1b[30m";
1086 escape[3] = '0' + static_cast<char>(c);
1087 std::fputs(escape, stdout);
1088 print(format, args);
1089 std::fputs(RESET_COLOR, stdout);
1090}
1091
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001092FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001093 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001094 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001095 std::size_t size = w.size();
1096 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001097}
1098
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001099// Explicit instantiations for char.
1100
Victor Zverovichf43caef2014-09-25 07:21:48 -07001101template const char *fmt::BasicFormatter<char>::format(
1102 const char *&format_str, const fmt::internal::Arg &arg);
1103
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001104template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001105 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001106
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001107template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001108 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001109
Victor Zverovich14f25772014-09-19 08:45:05 -07001110template int fmt::internal::CharTraits<char>::format_float(
1111 char *buffer, std::size_t size, const char *format,
1112 unsigned width, int precision, double value);
1113
1114template int fmt::internal::CharTraits<char>::format_float(
1115 char *buffer, std::size_t size, const char *format,
1116 unsigned width, int precision, long double value);
1117
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001118// Explicit instantiations for wchar_t.
1119
Victor Zverovichf43caef2014-09-25 07:21:48 -07001120template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1121 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1122
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001123template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001124 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001125
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001126template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001127 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001128 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001129
Victor Zverovich14f25772014-09-19 08:45:05 -07001130template int fmt::internal::CharTraits<wchar_t>::format_float(
1131 wchar_t *buffer, std::size_t size, const wchar_t *format,
1132 unsigned width, int precision, double value);
1133
1134template int fmt::internal::CharTraits<wchar_t>::format_float(
1135 wchar_t *buffer, std::size_t size, const wchar_t *format,
1136 unsigned width, int precision, long double value);
1137
jdale88a9862fd2014-03-11 18:56:24 +00001138#if _MSC_VER
1139# pragma warning(pop)
1140#endif