blob: 07ce60b7520343f2ba19de2840cb92da87c9d57c [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
Victor Zverovichd9c605c2014-11-28 06:40:57 -080084#ifdef FMT_HEADER_ONLY
85# define FMT_FUNC inline
Victor Zverovichc2a69032014-11-28 15:30:03 -080086#else
87# define FMT_FUNC
Victor Zverovichd9c605c2014-11-28 06:40:57 -080088#endif
89
jdale88a9862fd2014-03-11 18:56:24 +000090#if _MSC_VER
91# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070092# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050093# pragma warning(disable: 4702) // unreachable code
jdale88a9862fd2014-03-11 18:56:24 +000094#endif
95
Victor Zverovich9ff3b972013-09-07 10:15:08 -070096namespace {
97
98#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070099# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -0800100#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -0700101inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -0800102 va_list args;
103 va_start(args, format);
104 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
105 va_end(args);
106 return result;
107}
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700108# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700109#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800110
Victor Zverovichadce0242014-08-17 07:53:55 -0700111// Checks if a value fits in int - used to avoid warnings about comparing
112// signed and unsigned integers.
113template <bool IsSigned>
114struct IntChecker {
115 template <typename T>
116 static bool fits_in_int(T value) {
117 unsigned max = INT_MAX;
118 return value <= max;
119 }
120};
121
122template <>
123struct IntChecker<true> {
124 template <typename T>
125 static bool fits_in_int(T value) {
126 return value >= INT_MIN && value <= INT_MAX;
127 }
128};
129
Victor Zverovich43fe1002014-02-19 14:20:26 -0800130const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700131
Victor Zverovich22f75d82014-09-03 08:03:05 -0700132typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
133
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700134// Portable thread-safe version of strerror.
135// Sets buffer to point to a string describing the error code.
136// This can be either a pointer to a string stored in buffer,
137// or a pointer to some static immutable string.
138// Returns one of the following values:
139// 0 - success
140// ERANGE - buffer is not large enough to store the error message
141// other - failure
142// Buffer should be at least of size 1.
143int safe_strerror(
144 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) {
145 assert(buffer != 0 && buffer_size != 0);
146 int result = 0;
147#ifdef _GNU_SOURCE
148 char *message = strerror_r(error_code, buffer, buffer_size);
149 // If the buffer is full then the message is probably truncated.
150 if (message == buffer && strlen(buffer) == buffer_size - 1)
151 result = ERANGE;
152 buffer = message;
153#elif __MINGW32__
154 errno = 0;
155 (void)buffer_size;
156 buffer = strerror(error_code);
157 result = errno;
158#elif _WIN32
159 result = strerror_s(buffer, buffer_size, error_code);
160 // If the buffer is full then the message is probably truncated.
161 if (result == 0 && std::strlen(buffer) == buffer_size - 1)
162 result = ERANGE;
163#else
164 result = strerror_r(error_code, buffer, buffer_size);
165 if (result == -1)
166 result = errno; // glibc versions before 2.13 return result in errno.
167#endif
168 return result;
169}
170
Victor Zverovich22f75d82014-09-03 08:03:05 -0700171void format_error_code(fmt::Writer &out, int error_code,
172 fmt::StringRef message) FMT_NOEXCEPT(true) {
173 // Report error code making sure that the output fits into
174 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
175 // bad_alloc.
176 out.clear();
177 static const char SEP[] = ": ";
178 static const char ERROR[] = "error ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700179 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700180 // Subtract 2 to account for terminating null characters in SEP and ERROR.
Victor Zverovich22f75d82014-09-03 08:03:05 -0700181 std::size_t error_code_size =
Victor Zverovich88e0db82014-09-05 08:04:26 -0700182 sizeof(SEP) + sizeof(ERROR) + fmt::internal::count_digits(ec_value) - 2;
183 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700184 out << message << SEP;
185 out << ERROR << error_code;
186 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
187}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700188
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700189void report_error(FormatFunc func,
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700190 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700191 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700192 func(full_message, error_code, message);
193 // Use Writer::data instead of Writer::c_str to avoid potential memory
194 // allocation.
195 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
196 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700197}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700198
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700199// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
200class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
201 public:
202 template <typename T>
203 bool visit_any_int(T value) { return value == 0; }
204};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700205
206// Parses an unsigned integer advancing s to the end of the parsed input.
207// This function assumes that the first character of s is a digit.
208template <typename Char>
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700209int parse_nonnegative_int(const Char *&s) {
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700210 assert('0' <= *s && *s <= '9');
211 unsigned value = 0;
212 do {
213 unsigned new_value = value * 10 + (*s++ - '0');
214 // Check if value wrapped around.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700215 if (new_value < value) {
216 value = UINT_MAX;
217 break;
218 }
219 value = new_value;
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700220 } while ('0' <= *s && *s <= '9');
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700221 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700222 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700223 return value;
224}
Victor Zveroviche8251562014-07-08 16:20:33 -0700225
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700226inline void require_numeric_argument(const Arg &arg, char spec) {
227 if (arg.type > Arg::LAST_NUMERIC_TYPE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700228 std::string message =
229 fmt::format("format specifier '{}' requires numeric argument", spec);
230 FMT_THROW(fmt::FormatError(message));
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700231 }
232}
233
Victor Zveroviche8251562014-07-08 16:20:33 -0700234template <typename Char>
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700235void check_sign(const Char *&s, const Arg &arg) {
236 char sign = static_cast<char>(*s);
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700237 require_numeric_argument(arg, sign);
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700238 if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700239 FMT_THROW(fmt::FormatError(fmt::format(
240 "format specifier '{}' requires signed argument", sign)));
Victor Zverovich3947a7a2014-08-29 06:57:53 -0700241 }
242 ++s;
243}
244
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700245// Checks if an argument is a valid printf width specifier and sets
246// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700247class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700248 private:
249 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700250
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800251 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
252
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700253 public:
254 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700255
Victor Zverovich9d74f952014-07-16 07:27:54 -0700256 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700257 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovichd707adc2014-10-13 06:59:18 -0700258 return 0;
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700259 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700260
Victor Zverovich9d74f952014-07-16 07:27:54 -0700261 template <typename T>
262 unsigned visit_any_int(T value) {
263 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
264 UnsignedType width = value;
265 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700266 spec_.align_ = fmt::ALIGN_LEFT;
267 width = 0 - width;
268 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700269 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700270 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700271 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700272 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700273};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700274
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700275class PrecisionHandler :
276 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
277 public:
278 unsigned visit_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700279 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zverovich755ecb02014-10-13 08:39:38 -0700280 return 0;
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700281 }
282
283 template <typename T>
284 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700285 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700286 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700287 return static_cast<int>(value);
288 }
289};
290
Victor Zverovich32344d92014-08-28 08:11:21 -0700291// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700292template <typename T>
293class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
294 private:
295 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700296 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700297
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800298 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
299
Victor Zverovicheeca2232014-07-30 07:37:16 -0700300 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700301 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
302 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700303
304 template <typename U>
305 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700306 bool is_signed = type_ == 'd' || type_ == 'i';
307 using fmt::internal::Arg;
308 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700309 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700310 if (is_signed) {
311 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700312 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700313 } else {
314 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700315 arg_.uint_value = static_cast<unsigned>(
316 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700317 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700318 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700319 if (is_signed) {
320 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700321 arg_.long_long_value =
322 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700323 } else {
324 arg_.type = Arg::ULONG_LONG;
325 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700326 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700327 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700328 }
329 }
330};
331
Victor Zverovich32344d92014-08-28 08:11:21 -0700332// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700333class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
334 private:
335 fmt::internal::Arg &arg_;
336
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800337 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
338
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700339 public:
340 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
341
342 template <typename T>
343 void visit_any_int(T value) {
344 arg_.type = Arg::CHAR;
345 arg_.int_value = static_cast<char>(value);
346 }
347};
348
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700349// This function template is used to prevent compile errors when handling
350// incompatible string arguments, e.g. handling a wide string in a narrow
351// string formatter.
352template <typename Char>
353Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
354
355template <>
356inline Arg::StringValue<char> ignore_incompatible_str(
357 Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
358
359template <>
360inline Arg::StringValue<wchar_t> ignore_incompatible_str(
361 Arg::StringValue<wchar_t> s) { return s; }
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700362} // namespace
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700363
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800364FMT_FUNC void fmt::SystemError::init(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800365 int err_code, StringRef format_str, ArgList args) {
366 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700367 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800368 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700369 std::runtime_error &base = *this;
370 base = std::runtime_error(w.str());
371}
372
Victor Zverovichb605b392013-09-09 22:21:40 -0700373template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700374int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700375 char *buffer, std::size_t size, const char *format,
376 unsigned width, int precision, T value) {
377 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700378 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700379 FMT_SNPRINTF(buffer, size, format, value) :
380 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700381 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700382 return precision < 0 ?
383 FMT_SNPRINTF(buffer, size, format, width, value) :
384 FMT_SNPRINTF(buffer, size, format, width, precision, value);
385}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700386
Victor Zverovichb605b392013-09-09 22:21:40 -0700387template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700388int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700389 wchar_t *buffer, std::size_t size, const wchar_t *format,
390 unsigned width, int precision, T value) {
391 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700392 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700393 swprintf(buffer, size, format, value) :
394 swprintf(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700395 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700396 return precision < 0 ?
397 swprintf(buffer, size, format, width, value) :
398 swprintf(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700399}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800400
Victor Zverovich311251e2014-11-29 06:58:00 -0800401template <typename T>
402const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800403 "0001020304050607080910111213141516171819"
404 "2021222324252627282930313233343536373839"
405 "4041424344454647484950515253545556575859"
406 "6061626364656667686970717273747576777879"
407 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800408
Victor Zverovichf1d85162014-02-19 13:02:22 -0800409#define FMT_POWERS_OF_10(factor) \
410 factor * 10, \
411 factor * 100, \
412 factor * 1000, \
413 factor * 10000, \
414 factor * 100000, \
415 factor * 1000000, \
416 factor * 10000000, \
417 factor * 100000000, \
418 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800419
Victor Zverovich311251e2014-11-29 06:58:00 -0800420template <typename T>
421const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
422 0, FMT_POWERS_OF_10(1)
423};
424
425template <typename T>
426const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800427 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800428 FMT_POWERS_OF_10(1),
429 FMT_POWERS_OF_10(ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700430 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800431 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich6f6fe512014-02-15 11:16:44 -0800432 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800433};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800434
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800435FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Victor Zverovich877abaf2013-01-08 09:56:05 -0800436 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700437 FMT_THROW(fmt::FormatError(
438 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800439 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700440 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700441 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700442 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800443}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700444
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700445#ifdef _WIN32
446
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800447FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700448 int length = MultiByteToWideChar(
449 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
450 static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16";
451 if (length == 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700452 FMT_THROW(WindowsError(GetLastError(), ERROR));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700453 buffer_.resize(length);
454 length = MultiByteToWideChar(
455 CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
456 if (length == 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700457 FMT_THROW(WindowsError(GetLastError(), ERROR));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700458}
459
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800460FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700461 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700462 FMT_THROW(WindowsError(error_code,
463 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700464 }
465}
466
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800467FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700468 int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
469 if (length == 0)
470 return GetLastError();
471 buffer_.resize(length);
472 length = WideCharToMultiByte(
473 CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
474 if (length == 0)
475 return GetLastError();
476 return 0;
477}
478
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800479FMT_FUNC void fmt::WindowsError::init(
Victor Zverovich1d464042014-09-21 08:08:52 -0700480 int error_code, StringRef format_str, ArgList args) {
Victor Zverovich53201032014-06-30 14:26:29 -0700481 error_code_ = error_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700482 MemoryWriter w;
Victor Zverovich75b5eb42014-07-27 15:09:05 -0700483 internal::format_windows_error(w, error_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700484 std::runtime_error &base = *this;
485 base = std::runtime_error(w.str());
486}
487
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700488#endif
489
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800490FMT_FUNC void fmt::internal::format_system_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700491 fmt::Writer &out, int error_code,
492 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700493 FMT_TRY {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700494 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700495 buffer.resize(INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700496 for (;;) {
Victor Zverovichaca49372014-11-24 07:38:26 -0800497 char *system_message = &buffer[0];
Victor Zverovich22f75d82014-09-03 08:03:05 -0700498 int result = safe_strerror(error_code, system_message, buffer.size());
499 if (result == 0) {
500 out << message << ": " << system_message;
501 return;
502 }
503 if (result != ERANGE)
504 break; // Can't get error message, report error code instead.
505 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700506 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700507 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700508 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700509}
510
511#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800512FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700513 fmt::Writer &out, int error_code,
514 fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700515 class String {
516 private:
517 LPWSTR str_;
518
519 public:
520 String() : str_() {}
521 ~String() { LocalFree(str_); }
522 LPWSTR *ptr() { return &str_; }
523 LPCWSTR c_str() const { return str_; }
524 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700525 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700526 String system_message;
527 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
528 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
529 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
530 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
531 UTF16ToUTF8 utf8_message;
532 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
533 out << message << ": " << utf8_message;
534 return;
535 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700536 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700537 } FMT_CATCH(...) {}
Victor Zverovich22f75d82014-09-03 08:03:05 -0700538 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700539}
540#endif
541
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700542// An argument formatter.
543template <typename Char>
544class fmt::internal::ArgFormatter :
545 public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
546 private:
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700547 fmt::BasicFormatter<Char> &formatter_;
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700548 fmt::BasicWriter<Char> &writer_;
549 fmt::FormatSpec &spec_;
550 const Char *format_;
551
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800552 FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
553
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700554 public:
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700555 ArgFormatter(
556 fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700557 : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700558
Victor Zverovich9d74f952014-07-16 07:27:54 -0700559 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700560 void visit_any_int(T value) { writer_.write_int(value, spec_); }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700561
562 template <typename T>
Victor Zverovichc1db2932014-07-24 08:53:27 -0700563 void visit_any_double(T value) { writer_.write_double(value, spec_); }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700564
565 void visit_char(int value) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700566 if (spec_.type_ && spec_.type_ != 'c') {
Victor Zverovichd699c2a2014-07-25 08:24:27 -0700567 spec_.flags_ |= CHAR_FLAG;
568 writer_.write_int(value, spec_);
569 return;
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700570 }
571 if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700572 FMT_THROW(FormatError("invalid format specifier for char"));
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700573 typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
574 CharPtr out = CharPtr();
575 if (spec_.width_ > 1) {
576 Char fill = static_cast<Char>(spec_.fill());
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700577 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700578 if (spec_.align_ == fmt::ALIGN_RIGHT) {
579 std::fill_n(out, spec_.width_ - 1, fill);
580 out += spec_.width_ - 1;
581 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700582 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700583 } else {
584 std::fill_n(out + 1, spec_.width_ - 1, fill);
585 }
586 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700587 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700588 }
589 *out = static_cast<Char>(value);
590 }
591
592 void visit_string(Arg::StringValue<char> value) {
593 writer_.write_str(value, spec_);
594 }
595 void visit_wstring(Arg::StringValue<wchar_t> value) {
596 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
597 }
598
599 void visit_pointer(const void *value) {
600 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700601 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700602 spec_.flags_ = fmt::HASH_FLAG;
603 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700604 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700605 }
606
607 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700608 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700609 }
610};
611
Victor Zverovichd1ded562014-09-29 08:48:16 -0700612template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700613template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700614void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800615 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700616 // Check if StrChar is convertible to Char.
617 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700618 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700619 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800620 const StrChar *str_value = s.value;
621 std::size_t str_size = s.size;
622 if (str_size == 0) {
623 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700624 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800625 if (*str_value)
626 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700627 }
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800628 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700629}
630
631template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700632inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700633 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700634 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700635 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700636 if (error) {
637 FMT_THROW(FormatError(
638 *s != '}' && *s != ':' ? "invalid format string" : error));
639 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700640 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700641}
642
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800643FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700644 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700645 Arg arg = args_[arg_index];
646 if (arg.type == Arg::NONE)
647 error = "argument index out of range";
648 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700649}
650
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700651inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700652 if (next_arg_index_ >= 0)
653 return do_get_arg(next_arg_index_++, error);
654 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700655 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700656}
657
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700658inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700659 unsigned arg_index, const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700660 if (next_arg_index_ <= 0) {
661 next_arg_index_ = -1;
662 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700663 }
Victor Zverovich605d2602014-08-29 07:45:55 -0700664 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700665 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700666}
667
Victor Zverovich7cae7632013-09-06 20:23:42 -0700668template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700669void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700670 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700671 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700672 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700673 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700674 spec.align_ = ALIGN_LEFT;
675 break;
676 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700677 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
678 break;
679 case '0':
680 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700681 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700682 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700683 spec.flags_ |= SIGN_FLAG;
684 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700685 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700686 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700687 break;
688 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700689 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700690 return;
691 }
692 }
693}
694
Victor Zverovichcb743c02014-06-19 07:40:35 -0700695template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700696Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700697 const Char *s, unsigned arg_index) {
698 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700699 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700700 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
701 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700702 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700703 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700704}
705
706template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700707unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700708 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700709 unsigned arg_index = UINT_MAX;
710 Char c = *s;
711 if (c >= '0' && c <= '9') {
712 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700713 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700714 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700715 if (*s == '$') { // value is an argument index
716 ++s;
717 arg_index = value;
718 } else {
719 if (c == '0')
720 spec.fill_ = '0';
721 if (value != 0) {
722 // Nonzero value means that we parsed width and don't need to
723 // parse it or flags again, so return now.
724 spec.width_ = value;
725 return arg_index;
726 }
727 }
728 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700729 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700730 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700731 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700732 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700733 } else if (*s == '*') {
734 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700735 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700736 }
737 return arg_index;
738}
739
Victor Zverovich1f19b982014-06-16 07:49:30 -0700740template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700741void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800742 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700743 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800744 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700745 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700746 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700747 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700748 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700749 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700750 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700751 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700752 start = ++s;
753 continue;
754 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700755 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700756
Victor Zverovichcb743c02014-06-19 07:40:35 -0700757 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700758 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700759
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700760 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700761 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700762
763 // Parse precision.
764 if (*s == '.') {
765 ++s;
766 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700767 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700768 } else if (*s == '*') {
769 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700770 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700771 }
772 }
773
Victor Zverovich56fc5252014-08-28 07:48:55 -0700774 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700775 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700776 spec.flags_ &= ~HASH_FLAG;
777 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700778 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700779 spec.align_ = ALIGN_NUMERIC;
780 else
781 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700782 }
783
Victor Zverovichf4156b52014-07-30 08:39:07 -0700784 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700785 switch (*s++) {
786 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700787 if (*s == 'h')
788 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700789 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700790 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700791 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700792 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700793 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700794 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700795 else
796 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700797 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700798 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700799 ArgConverter<intmax_t>(arg, *s).visit(arg);
800 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700801 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700802 ArgConverter<size_t>(arg, *s).visit(arg);
803 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700804 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700805 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
806 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700807 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700808 // printf produces garbage when 'L' is omitted for long double, no
809 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700810 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700811 default:
812 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700813 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700814 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700815
816 // Parse type.
817 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700818 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700819 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700820 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
821 // Normalize type.
822 switch (spec.type_) {
823 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700824 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700825 break;
826 case 'c':
827 // TODO: handle wchar_t
828 CharConverter(arg).visit(arg);
829 break;
830 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700831 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700832
833 start = s;
834
835 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700836 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700837 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700838 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700839 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700840 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700841 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700842 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700843 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700844 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700845 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700846 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700847 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700848 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700849 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700850 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700851 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700852 typedef typename BasicWriter<Char>::CharPtr CharPtr;
853 CharPtr out = CharPtr();
854 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700855 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700856 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700857 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700858 std::fill_n(out, spec.width_ - 1, fill);
859 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700860 } else {
861 std::fill_n(out + 1, spec.width_ - 1, fill);
862 }
863 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700864 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700865 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700866 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700867 break;
868 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700869 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700870 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700871 break;
872 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700873 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700874 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -0700875 case Arg::CSTRING:
876 arg.string.size = 0;
877 writer.write_str(arg.string, spec);
878 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700879 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700880 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700881 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700882 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700883 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700884 break;
885 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700886 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700887 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700888 spec.flags_= HASH_FLAG;
889 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -0700890 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700891 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700892 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700893 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700894 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800895 const void *str_format = "s";
896 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700897 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700898 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700899 default:
900 assert(false);
901 break;
902 }
903 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700904 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700905}
906
907template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700908const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700909 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700910 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -0700911 FormatSpec spec;
912 if (*s == ':') {
913 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700914 arg.custom.format(this, arg.custom.value, &s);
915 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700916 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700917 ++s;
918 // Parse fill and alignment.
919 if (Char c = *s) {
920 const Char *p = s + 1;
921 spec.align_ = ALIGN_DEFAULT;
922 do {
923 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700924 case '<':
925 spec.align_ = ALIGN_LEFT;
926 break;
927 case '>':
928 spec.align_ = ALIGN_RIGHT;
929 break;
930 case '=':
931 spec.align_ = ALIGN_NUMERIC;
932 break;
933 case '^':
934 spec.align_ = ALIGN_CENTER;
935 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700936 }
937 if (spec.align_ != ALIGN_DEFAULT) {
938 if (p != s) {
939 if (c == '}') break;
940 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700941 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700942 s += 2;
943 spec.fill_ = c;
944 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700945 if (spec.align_ == ALIGN_NUMERIC)
946 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -0700947 break;
948 }
949 } while (--p >= s);
950 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700951
Victor Zveroviche8251562014-07-08 16:20:33 -0700952 // Parse sign.
953 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700954 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700955 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700956 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
957 break;
958 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700959 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700960 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700961 break;
962 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700963 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700964 spec.flags_ |= SIGN_FLAG;
965 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700966 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700967
Victor Zveroviche8251562014-07-08 16:20:33 -0700968 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700969 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -0700970 spec.flags_ |= HASH_FLAG;
971 ++s;
972 }
973
974 // Parse width and zero flag.
975 if ('0' <= *s && *s <= '9') {
976 if (*s == '0') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700977 require_numeric_argument(arg, '0');
Victor Zveroviche8251562014-07-08 16:20:33 -0700978 spec.align_ = ALIGN_NUMERIC;
979 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700980 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700981 // Zero may be parsed again as a part of the width, but it is simpler
982 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700983 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700984 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700985
Victor Zveroviche8251562014-07-08 16:20:33 -0700986 // Parse precision.
987 if (*s == '.') {
988 ++s;
989 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700990 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700991 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700992 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700993 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700994 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -0700995 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700996 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700997 ULongLong value = 0;
998 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700999 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001000 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001001 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001002 value = precision_arg.int_value;
1003 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001004 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001005 value = precision_arg.uint_value;
1006 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001007 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001008 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001009 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001010 value = precision_arg.long_long_value;
1011 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001012 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001013 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001014 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001015 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001016 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001017 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001018 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001019 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001020 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001021 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001022 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001023 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001024 if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001025 FMT_THROW(FormatError(
1026 "precision specifier requires floating-point argument"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001027 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001028 }
1029
Victor Zveroviche8251562014-07-08 16:20:33 -07001030 // Parse type.
1031 if (*s != '}' && *s)
1032 spec.type_ = static_cast<char>(*s++);
1033 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001034
Victor Zveroviche8251562014-07-08 16:20:33 -07001035 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001036 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001037 start_ = s;
1038
1039 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001040 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001041 return s;
1042}
1043
1044template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001045void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001046 BasicStringRef<Char> format_str, const ArgList &args) {
1047 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001048 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001049 while (*s) {
1050 Char c = *s++;
1051 if (c != '{' && c != '}') continue;
1052 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001053 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001054 start_ = ++s;
1055 continue;
1056 }
1057 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001058 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001059 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001060 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001061 s = format(s, arg);
1062 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001063 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001064}
1065
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001066FMT_FUNC void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001067 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001068 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001069}
1070
Victor Zverovich400812a2014-04-30 12:38:17 -07001071#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001072FMT_FUNC void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001073 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001074 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001075}
Victor Zverovich400812a2014-04-30 12:38:17 -07001076#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001077
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001078FMT_FUNC void fmt::print(std::FILE *f, 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 Zverovichd5b81962014-06-28 21:56:40 -07001081 std::fwrite(w.data(), 1, w.size(), f);
1082}
1083
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001084FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001085 print(stdout, format_str, args);
1086}
1087
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001088FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001089 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001090 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001091 os.write(w.data(), w.size());
1092}
1093
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001094FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001095 char escape[] = "\x1b[30m";
1096 escape[3] = '0' + static_cast<char>(c);
1097 std::fputs(escape, stdout);
1098 print(format, args);
1099 std::fputs(RESET_COLOR, stdout);
1100}
1101
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001102FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001103 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001104 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001105 std::size_t size = w.size();
1106 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001107}
1108
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001109// Explicit instantiations for char.
1110
Victor Zverovichf43caef2014-09-25 07:21:48 -07001111template const char *fmt::BasicFormatter<char>::format(
1112 const char *&format_str, const fmt::internal::Arg &arg);
1113
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001114template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001115 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001116
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001117template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001118 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001119
Victor Zverovich14f25772014-09-19 08:45:05 -07001120template int fmt::internal::CharTraits<char>::format_float(
1121 char *buffer, std::size_t size, const char *format,
1122 unsigned width, int precision, double value);
1123
1124template int fmt::internal::CharTraits<char>::format_float(
1125 char *buffer, std::size_t size, const char *format,
1126 unsigned width, int precision, long double value);
1127
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001128// Explicit instantiations for wchar_t.
1129
Victor Zverovichf43caef2014-09-25 07:21:48 -07001130template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1131 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1132
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001133template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001134 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001135
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001136template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001137 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001138 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001139
Victor Zverovich14f25772014-09-19 08:45:05 -07001140template int fmt::internal::CharTraits<wchar_t>::format_float(
1141 wchar_t *buffer, std::size_t size, const wchar_t *format,
1142 unsigned width, int precision, double value);
1143
1144template int fmt::internal::CharTraits<wchar_t>::format_float(
1145 wchar_t *buffer, std::size_t size, const wchar_t *format,
1146 unsigned width, int precision, long double value);
1147
jdale88a9862fd2014-03-11 18:56:24 +00001148#if _MSC_VER
1149# pragma warning(pop)
1150#endif