blob: 0c400aef4eaa8bb61afd42f81894f287b8f678a3 [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;
Victor Zverovich43aebf52015-01-08 07:56:08 -0800564 Char fill = static_cast<Char>(spec_.fill());
565 if (spec_.precision_ == 0) {
566 std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
567 return;
568 }
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700569 CharPtr out = CharPtr();
570 if (spec_.width_ > 1) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700571 out = writer_.grow_buffer(spec_.width_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700572 if (spec_.align_ == fmt::ALIGN_RIGHT) {
573 std::fill_n(out, spec_.width_ - 1, fill);
574 out += spec_.width_ - 1;
575 } else if (spec_.align_ == fmt::ALIGN_CENTER) {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700576 out = writer_.fill_padding(out, spec_.width_, 1, fill);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700577 } else {
578 std::fill_n(out + 1, spec_.width_ - 1, fill);
579 }
580 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700581 out = writer_.grow_buffer(1);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700582 }
583 *out = static_cast<Char>(value);
584 }
585
586 void visit_string(Arg::StringValue<char> value) {
587 writer_.write_str(value, spec_);
588 }
589 void visit_wstring(Arg::StringValue<wchar_t> value) {
590 writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
591 }
592
593 void visit_pointer(const void *value) {
594 if (spec_.type_ && spec_.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700595 fmt::internal::report_unknown_type(spec_.type_, "pointer");
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700596 spec_.flags_ = fmt::HASH_FLAG;
597 spec_.type_ = 'x';
Victor Zverovichc1db2932014-07-24 08:53:27 -0700598 writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700599 }
600
601 void visit_custom(Arg::CustomValue c) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700602 c.format(&formatter_, c.value, &format_);
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700603 }
604};
605
Victor Zverovichd1ded562014-09-29 08:48:16 -0700606template <typename Char>
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700607template <typename StrChar>
Victor Zverovichd1ded562014-09-29 08:48:16 -0700608void fmt::BasicWriter<Char>::write_str(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800609 const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
Victor Zverovich2a1c0c92014-07-26 09:45:03 -0700610 // Check if StrChar is convertible to Char.
611 internal::CharTraits<Char>::convert(StrChar());
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700612 if (spec.type_ && spec.type_ != 's')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700613 internal::report_unknown_type(spec.type_, "string");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800614 const StrChar *str_value = s.value;
615 std::size_t str_size = s.size;
616 if (str_size == 0) {
617 if (!str_value)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700618 FMT_THROW(FormatError("string pointer is null"));
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800619 if (*str_value)
620 str_size = std::char_traits<StrChar>::length(str_value);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700621 }
Victor Zverovich43aebf52015-01-08 07:56:08 -0800622 if (spec.precision_ >= 0 && spec.precision_ < str_size)
623 str_size = spec.precision_;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800624 write_str(str_value, str_size, spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700625}
626
627template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700628inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
Victor Zverovich9646e382014-08-27 09:13:42 -0700629 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700630 Arg arg = *s < '0' || *s > '9' ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700631 next_arg(error) : get_arg(parse_nonnegative_int(s), error);
Victor Zverovich8b76e972014-10-06 08:30:55 -0700632 if (error) {
633 FMT_THROW(FormatError(
634 *s != '}' && *s != ':' ? "invalid format string" : error));
635 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700636 return arg;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700637}
638
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800639FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700640 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700641 Arg arg = args_[arg_index];
642 if (arg.type == Arg::NONE)
643 error = "argument index out of range";
644 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700645}
646
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700647inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700648 if (next_arg_index_ >= 0)
649 return do_get_arg(next_arg_index_++, error);
650 error = "cannot switch from manual to automatic argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700651 return Arg();
Victor Zverovich605d2602014-08-29 07:45:55 -0700652}
653
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700654inline Arg fmt::internal::FormatterBase::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700655 unsigned arg_index, const char *&error) {
Victor Zverovich605d2602014-08-29 07:45:55 -0700656 if (next_arg_index_ <= 0) {
657 next_arg_index_ = -1;
658 return do_get_arg(arg_index, error);
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700659 }
Victor Zverovich605d2602014-08-29 07:45:55 -0700660 error = "cannot switch from automatic to manual argument indexing";
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700661 return Arg();
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700662}
663
Victor Zverovich7cae7632013-09-06 20:23:42 -0700664template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700665void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700666 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700667 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700668 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700669 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700670 spec.align_ = ALIGN_LEFT;
671 break;
672 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700673 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
674 break;
675 case '0':
676 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700677 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700678 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700679 spec.flags_ |= SIGN_FLAG;
680 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700681 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700682 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700683 break;
684 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700685 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700686 return;
687 }
688 }
689}
690
Victor Zverovichcb743c02014-06-19 07:40:35 -0700691template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700692Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700693 const Char *s, unsigned arg_index) {
694 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700695 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700696 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
697 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700698 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700699 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700700}
701
702template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700703unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700704 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700705 unsigned arg_index = UINT_MAX;
706 Char c = *s;
707 if (c >= '0' && c <= '9') {
708 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700709 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700710 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700711 if (*s == '$') { // value is an argument index
712 ++s;
713 arg_index = value;
714 } else {
715 if (c == '0')
716 spec.fill_ = '0';
717 if (value != 0) {
718 // Nonzero value means that we parsed width and don't need to
719 // parse it or flags again, so return now.
720 spec.width_ = value;
721 return arg_index;
722 }
723 }
724 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700725 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700726 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700727 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700728 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700729 } else if (*s == '*') {
730 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700731 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700732 }
733 return arg_index;
734}
735
Victor Zverovich1f19b982014-06-16 07:49:30 -0700736template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700737void fmt::internal::PrintfFormatter<Char>::format(
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800738 BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700739 const ArgList &args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800740 const Char *start = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -0700741 set_args(args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700742 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700743 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700744 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700745 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700746 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700747 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700748 start = ++s;
749 continue;
750 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700751 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700752
Victor Zverovichcb743c02014-06-19 07:40:35 -0700753 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700754 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700755
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700756 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700757 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700758
759 // Parse precision.
760 if (*s == '.') {
761 ++s;
762 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700763 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700764 } else if (*s == '*') {
765 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700766 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700767 }
768 }
769
Victor Zverovich56fc5252014-08-28 07:48:55 -0700770 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700771 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700772 spec.flags_ &= ~HASH_FLAG;
773 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700774 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700775 spec.align_ = ALIGN_NUMERIC;
776 else
777 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700778 }
779
Victor Zverovichf4156b52014-07-30 08:39:07 -0700780 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700781 switch (*s++) {
782 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700783 if (*s == 'h')
784 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700785 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700786 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700787 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700788 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700789 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700790 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700791 else
792 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700793 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700794 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700795 ArgConverter<intmax_t>(arg, *s).visit(arg);
796 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700797 case 'z':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700798 ArgConverter<size_t>(arg, *s).visit(arg);
799 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700800 case 't':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700801 ArgConverter<ptrdiff_t>(arg, *s).visit(arg);
802 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700803 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700804 // printf produces garbage when 'L' is omitted for long double, no
805 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700806 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700807 default:
808 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700809 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700810 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700811
812 // Parse type.
813 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700814 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700815 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700816 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
817 // Normalize type.
818 switch (spec.type_) {
819 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700820 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700821 break;
822 case 'c':
823 // TODO: handle wchar_t
824 CharConverter(arg).visit(arg);
825 break;
826 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700827 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700828
829 start = s;
830
831 // Format argument.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700832 switch (arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700833 case Arg::INT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700834 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700835 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700836 case Arg::UINT:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700837 writer.write_int(arg.uint_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700838 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700839 case Arg::LONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700840 writer.write_int(arg.long_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700841 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700842 case Arg::ULONG_LONG:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700843 writer.write_int(arg.ulong_long_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700844 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700845 case Arg::CHAR: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700846 if (spec.type_ && spec.type_ != 'c')
Victor Zverovichc1db2932014-07-24 08:53:27 -0700847 writer.write_int(arg.int_value, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700848 typedef typename BasicWriter<Char>::CharPtr CharPtr;
849 CharPtr out = CharPtr();
850 if (spec.width_ > 1) {
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700851 Char fill = ' ';
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700852 out = writer.grow_buffer(spec.width_);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700853 if (spec.align_ != ALIGN_LEFT) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700854 std::fill_n(out, spec.width_ - 1, fill);
855 out += spec.width_ - 1;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700856 } else {
857 std::fill_n(out + 1, spec.width_ - 1, fill);
858 }
859 } else {
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700860 out = writer.grow_buffer(1);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700861 }
Victor Zverovichcb743c02014-06-19 07:40:35 -0700862 *out = static_cast<Char>(arg.int_value);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700863 break;
864 }
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700865 case Arg::DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700866 writer.write_double(arg.double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700867 break;
868 case Arg::LONG_DOUBLE:
Victor Zverovichc1db2932014-07-24 08:53:27 -0700869 writer.write_double(arg.long_double_value, spec);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700870 break;
Victor Zverovich75a2ea02014-09-25 07:10:44 -0700871 case Arg::CSTRING:
872 arg.string.size = 0;
873 writer.write_str(arg.string, spec);
874 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700875 case Arg::STRING:
Victor Zverovich53201032014-06-30 14:26:29 -0700876 writer.write_str(arg.string, spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700877 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700878 case Arg::WSTRING:
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700879 writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700880 break;
881 case Arg::POINTER:
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700882 if (spec.type_ && spec.type_ != 'p')
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700883 internal::report_unknown_type(spec.type_, "pointer");
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700884 spec.flags_= HASH_FLAG;
885 spec.type_ = 'x';
Victor Zverovichab6e7592014-09-23 08:21:58 -0700886 writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700887 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700888 case Arg::CUSTOM: {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700889 if (spec.type_)
Victor Zverovichf634ccb2014-07-26 08:42:19 -0700890 internal::report_unknown_type(spec.type_, "object");
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800891 const void *str_format = "s";
892 arg.custom.format(&writer, arg.custom.value, &str_format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700893 break;
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700894 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700895 default:
896 assert(false);
897 break;
898 }
899 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700900 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700901}
902
903template <typename Char>
Victor Zverovichb9a06ba2014-07-08 16:38:50 -0700904const Char *fmt::BasicFormatter<Char>::format(
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700905 const Char *&format_str, const Arg &arg) {
Victor Zveroviche8251562014-07-08 16:20:33 -0700906 const Char *s = format_str;
Victor Zveroviche8251562014-07-08 16:20:33 -0700907 FormatSpec spec;
908 if (*s == ':') {
909 if (arg.type == Arg::CUSTOM) {
Victor Zverovich271fa8c2014-08-29 07:23:54 -0700910 arg.custom.format(this, arg.custom.value, &s);
911 return s;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700912 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700913 ++s;
914 // Parse fill and alignment.
915 if (Char c = *s) {
916 const Char *p = s + 1;
917 spec.align_ = ALIGN_DEFAULT;
918 do {
919 switch (*p) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700920 case '<':
921 spec.align_ = ALIGN_LEFT;
922 break;
923 case '>':
924 spec.align_ = ALIGN_RIGHT;
925 break;
926 case '=':
927 spec.align_ = ALIGN_NUMERIC;
928 break;
929 case '^':
930 spec.align_ = ALIGN_CENTER;
931 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700932 }
933 if (spec.align_ != ALIGN_DEFAULT) {
934 if (p != s) {
935 if (c == '}') break;
936 if (c == '{')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700937 FMT_THROW(FormatError("invalid fill character '{'"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700938 s += 2;
939 spec.fill_ = c;
940 } else ++s;
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700941 if (spec.align_ == ALIGN_NUMERIC)
942 require_numeric_argument(arg, '=');
Victor Zveroviche8251562014-07-08 16:20:33 -0700943 break;
944 }
945 } while (--p >= s);
946 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700947
Victor Zveroviche8251562014-07-08 16:20:33 -0700948 // Parse sign.
949 switch (*s) {
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700950 case '+':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700951 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700952 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
953 break;
954 case '-':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700955 check_sign(s, arg);
Victor Zverovicha7d94f02014-07-22 12:37:10 -0700956 spec.flags_ |= MINUS_FLAG;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700957 break;
958 case ' ':
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700959 check_sign(s, arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700960 spec.flags_ |= SIGN_FLAG;
961 break;
Victor Zveroviche8251562014-07-08 16:20:33 -0700962 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700963
Victor Zveroviche8251562014-07-08 16:20:33 -0700964 if (*s == '#') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700965 require_numeric_argument(arg, '#');
Victor Zveroviche8251562014-07-08 16:20:33 -0700966 spec.flags_ |= HASH_FLAG;
967 ++s;
968 }
969
970 // Parse width and zero flag.
971 if ('0' <= *s && *s <= '9') {
972 if (*s == '0') {
Victor Zverovich5debb2a2014-08-29 08:16:10 -0700973 require_numeric_argument(arg, '0');
Victor Zveroviche8251562014-07-08 16:20:33 -0700974 spec.align_ = ALIGN_NUMERIC;
975 spec.fill_ = '0';
Victor Zverovich7cae7632013-09-06 20:23:42 -0700976 }
Victor Zveroviche8251562014-07-08 16:20:33 -0700977 // Zero may be parsed again as a part of the width, but it is simpler
978 // and more efficient than checking if the next char is a digit.
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700979 spec.width_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700980 }
Victor Zverovich7cae7632013-09-06 20:23:42 -0700981
Victor Zveroviche8251562014-07-08 16:20:33 -0700982 // Parse precision.
983 if (*s == '.') {
984 ++s;
985 spec.precision_ = 0;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700986 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700987 spec.precision_ = parse_nonnegative_int(s);
Victor Zveroviche8251562014-07-08 16:20:33 -0700988 } else if (*s == '{') {
Victor Zverovich7cae7632013-09-06 20:23:42 -0700989 ++s;
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700990 const Arg &precision_arg = parse_arg_index(s);
Victor Zverovich42de4f12014-08-27 08:24:31 -0700991 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -0700992 FMT_THROW(FormatError("invalid format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -0700993 ULongLong value = 0;
994 switch (precision_arg.type) {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700995 case Arg::INT:
Victor Zverovich7cae7632013-09-06 20:23:42 -0700996 if (precision_arg.int_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700997 FMT_THROW(FormatError("negative precision"));
Victor Zverovich7cae7632013-09-06 20:23:42 -0700998 value = precision_arg.int_value;
999 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001000 case Arg::UINT:
Victor Zverovich7cae7632013-09-06 20:23:42 -07001001 value = precision_arg.uint_value;
1002 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001003 case Arg::LONG_LONG:
Victor Zverovich56f12b72013-11-22 07:45:43 -08001004 if (precision_arg.long_long_value < 0)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001005 FMT_THROW(FormatError("negative precision"));
Victor Zverovich56f12b72013-11-22 07:45:43 -08001006 value = precision_arg.long_long_value;
1007 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001008 case Arg::ULONG_LONG:
Gregory Czajkowskia65542b2013-11-18 22:58:39 -08001009 value = precision_arg.ulong_long_value;
Victor Zverovicha4e72b42013-11-21 09:11:58 -08001010 break;
Victor Zverovich7cae7632013-09-06 20:23:42 -07001011 default:
Victor Zverovich8b76e972014-10-06 08:30:55 -07001012 FMT_THROW(FormatError("precision is not integer"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001013 }
Victor Zveroviche8251562014-07-08 16:20:33 -07001014 if (value > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -07001015 FMT_THROW(FormatError("number is too big"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001016 spec.precision_ = static_cast<int>(value);
Victor Zveroviche8251562014-07-08 16:20:33 -07001017 } else {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001018 FMT_THROW(FormatError("missing precision specifier"));
Victor Zverovich7cae7632013-09-06 20:23:42 -07001019 }
Victor Zverovich43aebf52015-01-08 07:56:08 -08001020 if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
Victor Zverovich8b76e972014-10-06 08:30:55 -07001021 FMT_THROW(FormatError(
Victor Zverovich43aebf52015-01-08 07:56:08 -08001022 fmt::format("precision not allowed in {} format specifier",
1023 arg.type == Arg::POINTER ? "pointer" : "integer")));
Victor Zveroviche8251562014-07-08 16:20:33 -07001024 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001025 }
1026
Victor Zveroviche8251562014-07-08 16:20:33 -07001027 // Parse type.
1028 if (*s != '}' && *s)
1029 spec.type_ = static_cast<char>(*s++);
1030 }
Victor Zverovich7cae7632013-09-06 20:23:42 -07001031
Victor Zveroviche8251562014-07-08 16:20:33 -07001032 if (*s++ != '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001033 FMT_THROW(FormatError("missing '}' in format string"));
Victor Zveroviche8251562014-07-08 16:20:33 -07001034 start_ = s;
1035
1036 // Format argument.
Victor Zverovich4edc88f2014-07-16 08:38:15 -07001037 internal::ArgFormatter<Char>(*this, spec, s - 1).visit(arg);
Victor Zveroviche8251562014-07-08 16:20:33 -07001038 return s;
1039}
1040
1041template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001042void fmt::BasicFormatter<Char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001043 BasicStringRef<Char> format_str, const ArgList &args) {
1044 const Char *s = start_ = format_str.c_str();
Victor Zverovich605d2602014-08-29 07:45:55 -07001045 set_args(args);
Victor Zveroviche8251562014-07-08 16:20:33 -07001046 while (*s) {
1047 Char c = *s++;
1048 if (c != '{' && c != '}') continue;
1049 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -07001050 write(writer_, start_, s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001051 start_ = ++s;
1052 continue;
1053 }
1054 if (c == '}')
Victor Zverovich8b76e972014-10-06 08:30:55 -07001055 FMT_THROW(FormatError("unmatched '}' in format string"));
Victor Zverovichc1db2932014-07-24 08:53:27 -07001056 write(writer_, start_, s - 1);
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001057 Arg arg = parse_arg_index(s);
Victor Zveroviche8251562014-07-08 16:20:33 -07001058 s = format(s, arg);
1059 }
Victor Zverovichc1db2932014-07-24 08:53:27 -07001060 write(writer_, start_, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001061}
1062
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001063FMT_FUNC void fmt::report_system_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001064 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001065 report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001066}
1067
Victor Zverovich400812a2014-04-30 12:38:17 -07001068#ifdef _WIN32
Victor Zverovichb49a1b42014-12-09 06:32:07 -08001069FMT_FUNC void fmt::report_windows_error(
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001070 int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) {
Victor Zverovichd8b9f412014-07-29 06:38:05 -07001071 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -07001072}
Victor Zverovich400812a2014-04-30 12:38:17 -07001073#endif
Victor Zverovichf7939862014-04-30 10:18:11 -07001074
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001075FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001076 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001077 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001078 std::fwrite(w.data(), 1, w.size(), f);
1079}
1080
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001081FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -07001082 print(stdout, format_str, args);
1083}
1084
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001085FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001086 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -07001087 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -07001088 os.write(w.data(), w.size());
1089}
1090
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001091FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -07001092 char escape[] = "\x1b[30m";
1093 escape[3] = '0' + static_cast<char>(c);
1094 std::fputs(escape, stdout);
1095 print(format, args);
1096 std::fputs(RESET_COLOR, stdout);
1097}
1098
Victor Zverovichd9c605c2014-11-28 06:40:57 -08001099FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -07001100 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -07001101 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -08001102 std::size_t size = w.size();
1103 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -07001104}
1105
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001106// Explicit instantiations for char.
1107
Victor Zverovichf43caef2014-09-25 07:21:48 -07001108template const char *fmt::BasicFormatter<char>::format(
1109 const char *&format_str, const fmt::internal::Arg &arg);
1110
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001111template void fmt::BasicFormatter<char>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001112 BasicStringRef<char> format, const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -07001113
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001114template void fmt::internal::PrintfFormatter<char>::format(
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001115 BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001116
Victor Zverovich14f25772014-09-19 08:45:05 -07001117template int fmt::internal::CharTraits<char>::format_float(
1118 char *buffer, std::size_t size, const char *format,
1119 unsigned width, int precision, double value);
1120
1121template int fmt::internal::CharTraits<char>::format_float(
1122 char *buffer, std::size_t size, const char *format,
1123 unsigned width, int precision, long double value);
1124
Victor Zverovich9ff3b972013-09-07 10:15:08 -07001125// Explicit instantiations for wchar_t.
1126
Victor Zverovichf43caef2014-09-25 07:21:48 -07001127template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
1128 const wchar_t *&format_str, const fmt::internal::Arg &arg);
1129
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001130template void fmt::BasicFormatter<wchar_t>::format(
Victor Zveroviche8251562014-07-08 16:20:33 -07001131 BasicStringRef<wchar_t> format, const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001132
Victor Zverovich4d049cf2014-07-28 08:41:50 -07001133template void fmt::internal::PrintfFormatter<wchar_t>::format(
Victor Zverovichbf8b29f2014-06-06 06:38:37 -07001134 BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
Victor Zverovichea99bfb2014-06-24 07:54:26 -07001135 const ArgList &args);
jdale88a9862fd2014-03-11 18:56:24 +00001136
Victor Zverovich14f25772014-09-19 08:45:05 -07001137template int fmt::internal::CharTraits<wchar_t>::format_float(
1138 wchar_t *buffer, std::size_t size, const wchar_t *format,
1139 unsigned width, int precision, double value);
1140
1141template int fmt::internal::CharTraits<wchar_t>::format_float(
1142 wchar_t *buffer, std::size_t size, const wchar_t *format,
1143 unsigned width, int precision, long double value);
1144
jdale88a9862fd2014-03-11 18:56:24 +00001145#if _MSC_VER
1146# pragma warning(pop)
1147#endif