blob: 0857965e968eb63f156870d3cd07f5b8db3a8f58 [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 Zverovich7c0a2332015-03-03 21:04:45 -08004 Copyright (c) 2012 - 2015, 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>
vitaut7dcf0512015-11-13 06:52:13 -080037#include <cstddef> // for std::ptrdiff_t
Victor Zverovich9ff3b972013-09-07 10:15:08 -070038
vitaut24c309f2015-06-12 07:15:57 -070039#if defined(_WIN32) && defined(__MINGW32__)
40# include <cstring>
41#endif
42
43#if FMT_USE_WINDOWS_H
vitaut67ce3942015-04-30 07:48:36 -070044# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
45# include <windows.h>
46# else
47# define NOMINMAX
48# include <windows.h>
49# undef NOMINMAX
50# endif
Ryuuke5a9dc8f2015-02-08 16:08:29 +000051#endif
52
Victor Zverovich6e5551e2014-07-02 06:33:25 -070053using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080054
Victor Zverovich8b76e972014-10-06 08:30:55 -070055#if FMT_EXCEPTIONS
56# define FMT_TRY try
57# define FMT_CATCH(x) catch (x)
58#else
59# define FMT_TRY if (true)
60# define FMT_CATCH(x) if (false)
61#endif
62
Victor Zverovichd9c605c2014-11-28 06:40:57 -080063#ifdef FMT_HEADER_ONLY
64# define FMT_FUNC inline
Victor Zverovichc2a69032014-11-28 15:30:03 -080065#else
66# define FMT_FUNC
Victor Zverovichd9c605c2014-11-28 06:40:57 -080067#endif
68
Ingo van Lilb4b13ee2015-11-02 12:34:46 +010069#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +000070# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070071# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050072# pragma warning(disable: 4702) // unreachable code
vitautdf47d812015-03-16 18:53:14 -070073// Disable deprecation warning for strerror. The latter is not called but
74// MSVC fails to detect it.
75# pragma warning(disable: 4996)
jdale88a9862fd2014-03-11 18:56:24 +000076#endif
77
vitaut341b98c2015-03-14 13:39:33 -070078// Dummy implementations of strerror_r and strerror_s called if corresponding
79// system functions are not available.
vitautc669cbe2015-07-07 07:05:17 -070080static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
81 return fmt::internal::Null<>();
vitaut341b98c2015-03-14 13:39:33 -070082}
vitautc669cbe2015-07-07 07:05:17 -070083static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
84 return fmt::internal::Null<>();
vitaut341b98c2015-03-14 13:39:33 -070085}
86
vitaut8725d072015-06-12 07:56:58 -070087namespace fmt {
Victor Zverovich9ff3b972013-09-07 10:15:08 -070088namespace {
89
90#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070091# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080092#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070093inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080094 va_list args;
95 va_start(args, format);
96 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
97 va_end(args);
98 return result;
99}
Victor Zverovichb9a568b2014-09-19 07:51:42 -0700100# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700101#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800102
cstamford55836ca2015-03-10 07:04:31 +0000103#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
104# define FMT_SWPRINTF snwprintf
105#else
106# define FMT_SWPRINTF swprintf
107#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
108
Victor Zverovichadce0242014-08-17 07:53:55 -0700109// Checks if a value fits in int - used to avoid warnings about comparing
110// signed and unsigned integers.
111template <bool IsSigned>
112struct IntChecker {
113 template <typename T>
114 static bool fits_in_int(T value) {
115 unsigned max = INT_MAX;
116 return value <= max;
117 }
vitaut6484a152015-07-08 07:35:57 -0700118 static bool fits_in_int(bool) { return true; }
Victor Zverovichadce0242014-08-17 07:53:55 -0700119};
120
121template <>
122struct IntChecker<true> {
123 template <typename T>
124 static bool fits_in_int(T value) {
vitautfb277232015-10-22 07:33:01 -0700125 return value >= INT_MIN && value <= INT_MAX;
Victor Zverovichadce0242014-08-17 07:53:55 -0700126 }
vitaut17960dd2015-10-28 06:23:22 -0700127 static bool fits_in_int(int) { return true; }
Victor Zverovichadce0242014-08-17 07:53:55 -0700128};
129
Victor Zverovich7004d1e2015-02-08 19:54:39 -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(
Carter Lie2583ab2015-02-14 09:58:29 +0800144 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
vitaut8ab665a2015-06-22 08:17:23 -0700145 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700146
vitaut341b98c2015-03-14 13:39:33 -0700147 class StrError {
148 private:
149 int error_code_;
150 char *&buffer_;
151 std::size_t buffer_size_;
152
vitautda052ae2015-03-21 07:53:39 -0700153 // A noop assignment operator to avoid bogus warnings.
154 void operator=(const StrError &) {}
155
vitaut341b98c2015-03-14 13:39:33 -0700156 // Handle the result of XSI-compliant version of strerror_r.
157 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700158 // glibc versions before 2.13 return result in errno.
159 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700160 }
161
162 // Handle the result of GNU-specific version of strerror_r.
163 int handle(char *message) {
164 // If the buffer is full then the message is probably truncated.
165 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
166 return ERANGE;
167 buffer_ = message;
168 return 0;
169 }
170
171 // Handle the case when strerror_r is not available.
vitautc669cbe2015-07-07 07:05:17 -0700172 int handle(fmt::internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700173 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
174 }
175
176 // Fallback to strerror_s when strerror_r is not available.
177 int fallback(int result) {
178 // If the buffer is full then the message is probably truncated.
179 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
180 ERANGE : result;
181 }
182
183 // Fallback to strerror if strerror_r and strerror_s are not available.
vitautc669cbe2015-07-07 07:05:17 -0700184 int fallback(fmt::internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700185 errno = 0;
186 buffer_ = strerror(error_code_);
187 return errno;
188 }
189
190 public:
Radu Popescu0affb232015-08-04 12:52:44 +0200191 StrError(int err_code, char *&buf, std::size_t buf_size)
192 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
vitaut341b98c2015-03-14 13:39:33 -0700193
vitaut63f6c102015-06-14 09:36:23 -0700194 int run() {
195 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
196 return handle(strerror_r(error_code_, buffer_, buffer_size_));
197 }
vitaut341b98c2015-03-14 13:39:33 -0700198 };
199 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700200}
201
Victor Zverovich22f75d82014-09-03 08:03:05 -0700202void format_error_code(fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800203 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700204 // Report error code making sure that the output fits into
205 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
206 // bad_alloc.
207 out.clear();
208 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700209 static const char ERROR_STR[] = "error ";
vitaut1addec92015-03-21 20:16:36 -0700210 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
211 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
vitaut9d577ca2016-03-02 07:01:21 -0800212 typedef fmt::internal::IntTraits<int>::MainType MainType;
213 MainType abs_value = static_cast<MainType>(error_code);
214 if (internal::is_negative(error_code)) {
215 abs_value = 0 - abs_value;
216 ++error_code_size;
217 }
218 error_code_size += fmt::internal::count_digits(abs_value);
Victor Zverovich88e0db82014-09-05 08:04:26 -0700219 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700220 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700221 out << ERROR_STR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700222 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
223}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700224
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700225void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800226 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700227 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700228 func(full_message, error_code, message);
229 // Use Writer::data instead of Writer::c_str to avoid potential memory
230 // allocation.
231 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
232 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700233}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700234
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700235// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
236class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
237 public:
238 template <typename T>
239 bool visit_any_int(T value) { return value == 0; }
240};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700241
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700242// Checks if an argument is a valid printf width specifier and sets
243// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700244class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700245 private:
246 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700247
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800248 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
249
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700250 public:
251 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700252
vitautd4ea2d72015-03-26 08:55:20 -0700253 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700254 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700255 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700256
Victor Zverovich9d74f952014-07-16 07:27:54 -0700257 template <typename T>
258 unsigned visit_any_int(T value) {
259 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
260 UnsignedType width = value;
261 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700262 spec_.align_ = fmt::ALIGN_LEFT;
263 width = 0 - width;
264 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700265 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700266 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700267 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700268 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700269};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700270
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700271class PrecisionHandler :
272 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
273 public:
vitautd4ea2d72015-03-26 08:55:20 -0700274 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700275 FMT_THROW(fmt::FormatError("precision is not integer"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700276 }
277
278 template <typename T>
279 int visit_any_int(T value) {
Victor Zverovichadce0242014-08-17 07:53:55 -0700280 if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
Victor Zverovich8b76e972014-10-06 08:30:55 -0700281 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700282 return static_cast<int>(value);
283 }
284};
285
vitaut8474a622016-01-24 00:43:42 +0100286template <typename T, typename U>
287struct is_same {
288 enum { value = 0 };
289};
290
Victor Zverovicheeca2232014-07-30 07:37:16 -0700291template <typename T>
vitaut8474a622016-01-24 00:43:42 +0100292struct is_same<T, T> {
293 enum { value = 1 };
294};
295
296// An argument visitor that converts an integer argument to T for printf,
vitautbb7a80b2016-01-25 06:46:43 -0800297// if T is an integral type. If T is void, the argument is converted to
298// corresponding signed or unsigned type depending on the type specifier:
vitaut8474a622016-01-24 00:43:42 +0100299// 'd' and 'i' - signed, other - unsigned)
300template <typename T = void>
Victor Zverovicheeca2232014-07-30 07:37:16 -0700301class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
302 private:
303 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700304 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700305
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800306 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
307
Victor Zverovicheeca2232014-07-30 07:37:16 -0700308 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700309 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
310 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700311
vitaut21573752015-11-13 07:18:44 -0800312 void visit_bool(bool value) {
313 if (type_ != 's')
314 visit_any_int(value);
315 }
316
Victor Zverovicheeca2232014-07-30 07:37:16 -0700317 template <typename U>
318 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700319 bool is_signed = type_ == 'd' || type_ == 'i';
320 using fmt::internal::Arg;
vitaut8474a622016-01-24 00:43:42 +0100321 typedef typename fmt::internal::Conditional<
322 is_same<T, void>::value, U, T>::type TargetType;
323 if (sizeof(TargetType) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700324 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700325 if (is_signed) {
326 arg_.type = Arg::INT;
vitaut8474a622016-01-24 00:43:42 +0100327 arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700328 } else {
329 arg_.type = Arg::UINT;
vitaut8474a622016-01-24 00:43:42 +0100330 typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned;
331 arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700332 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700333 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700334 if (is_signed) {
335 arg_.type = Arg::LONG_LONG;
vitaut7ee287d2016-01-27 07:03:19 -0800336 // glibc's printf doesn't sign extend arguments of smaller types:
vitautae6368c2016-01-26 07:13:34 -0800337 // std::printf("%lld", -42); // prints "4294967254"
vitaut7ee287d2016-01-27 07:03:19 -0800338 // but we don't have to do the same because it's a UB.
339 arg_.long_long_value = value;
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700340 } else {
341 arg_.type = Arg::ULONG_LONG;
342 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700343 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700344 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700345 }
346 }
347};
348
Victor Zverovich32344d92014-08-28 08:11:21 -0700349// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700350class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
351 private:
352 fmt::internal::Arg &arg_;
353
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800354 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
355
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700356 public:
357 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
358
359 template <typename T>
360 void visit_any_int(T value) {
361 arg_.type = Arg::CHAR;
362 arg_.int_value = static_cast<char>(value);
363 }
364};
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700365} // namespace
vitaut270069b2015-06-16 07:36:32 -0700366
367namespace internal {
368
vitaut270069b2015-06-16 07:36:32 -0700369template <typename Char>
370class PrintfArgFormatter :
vitaut535dbdd2015-12-03 09:38:06 -0800371 public ArgFormatterBase<PrintfArgFormatter<Char>, Char> {
vitaut57ba9432015-11-12 06:09:08 -0800372
373 void write_null_pointer() {
vitaut1a2a3332015-11-23 21:01:28 -0800374 this->spec().type_ = 0;
375 this->write("(nil)");
vitaut57ba9432015-11-12 06:09:08 -0800376 }
377
vitaut535dbdd2015-12-03 09:38:06 -0800378 typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base;
vitaut1a2a3332015-11-23 21:01:28 -0800379
vitaut270069b2015-06-16 07:36:32 -0700380 public:
381 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
vitaut535dbdd2015-12-03 09:38:06 -0800382 : ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {}
vitaut270069b2015-06-16 07:36:32 -0700383
vitaut21573752015-11-13 07:18:44 -0800384 void visit_bool(bool value) {
385 FormatSpec &fmt_spec = this->spec();
386 if (fmt_spec.type_ != 's')
387 return this->visit_any_int(value);
388 fmt_spec.type_ = 0;
vitaut1a2a3332015-11-23 21:01:28 -0800389 this->write(value);
vitaut21573752015-11-13 07:18:44 -0800390 }
391
vitaut270069b2015-06-16 07:36:32 -0700392 void visit_char(int value) {
vitaut7fa17fe2015-08-04 07:55:33 -0700393 const FormatSpec &fmt_spec = this->spec();
vitautecdc7ec2015-08-04 08:01:28 -0700394 BasicWriter<Char> &w = this->writer();
vitaut7fa17fe2015-08-04 07:55:33 -0700395 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
vitautecdc7ec2015-08-04 08:01:28 -0700396 w.write_int(value, fmt_spec);
vitaut270069b2015-06-16 07:36:32 -0700397 typedef typename BasicWriter<Char>::CharPtr CharPtr;
398 CharPtr out = CharPtr();
vitaut7fa17fe2015-08-04 07:55:33 -0700399 if (fmt_spec.width_ > 1) {
vitaut270069b2015-06-16 07:36:32 -0700400 Char fill = ' ';
vitautecdc7ec2015-08-04 08:01:28 -0700401 out = w.grow_buffer(fmt_spec.width_);
vitaut7fa17fe2015-08-04 07:55:33 -0700402 if (fmt_spec.align_ != ALIGN_LEFT) {
403 std::fill_n(out, fmt_spec.width_ - 1, fill);
404 out += fmt_spec.width_ - 1;
vitaut270069b2015-06-16 07:36:32 -0700405 } else {
vitaut7fa17fe2015-08-04 07:55:33 -0700406 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
vitaut270069b2015-06-16 07:36:32 -0700407 }
408 } else {
vitautecdc7ec2015-08-04 08:01:28 -0700409 out = w.grow_buffer(1);
vitaut270069b2015-06-16 07:36:32 -0700410 }
411 *out = static_cast<Char>(value);
412 }
vitaut79d8f592015-09-08 08:36:20 -0700413
vitautb5fda1c2015-11-11 07:57:19 -0800414 void visit_cstring(const char *value) {
415 if (value)
vitaut1a2a3332015-11-23 21:01:28 -0800416 Base::visit_cstring(value);
vitaut57ba9432015-11-12 06:09:08 -0800417 else if (this->spec().type_ == 'p')
418 write_null_pointer();
vitautb5fda1c2015-11-11 07:57:19 -0800419 else
vitaut1a2a3332015-11-23 21:01:28 -0800420 this->write("(null)");
vitautb5fda1c2015-11-11 07:57:19 -0800421 }
422
423 void visit_pointer(const void *value) {
424 if (value)
vitaut1a2a3332015-11-23 21:01:28 -0800425 return Base::visit_pointer(value);
426 this->spec().type_ = 0;
427 write_null_pointer();
vitautb5fda1c2015-11-11 07:57:19 -0800428 }
429
vitaut79d8f592015-09-08 08:36:20 -0700430 void visit_custom(Arg::CustomValue c) {
431 BasicFormatter<Char> formatter(ArgList(), this->writer());
vitautef710de2015-09-18 16:26:41 -0700432 const Char format_str[] = {'}', 0};
433 const Char *format = format_str;
vitaut79d8f592015-09-08 08:36:20 -0700434 c.format(&formatter, c.value, &format);
435 }
vitaut270069b2015-06-16 07:36:32 -0700436};
437} // namespace internal
vitaut8725d072015-06-12 07:56:58 -0700438} // namespace fmt
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700439
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800440FMT_FUNC void fmt::SystemError::init(
vitaut438bd9b2015-06-26 07:43:54 -0700441 int err_code, CStringRef format_str, ArgList args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800442 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700443 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800444 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700445 std::runtime_error &base = *this;
446 base = std::runtime_error(w.str());
447}
448
Victor Zverovichb605b392013-09-09 22:21:40 -0700449template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700450int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700451 char *buffer, std::size_t size, const char *format,
452 unsigned width, int precision, T value) {
453 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700454 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700455 FMT_SNPRINTF(buffer, size, format, value) :
456 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700457 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700458 return precision < 0 ?
459 FMT_SNPRINTF(buffer, size, format, width, value) :
460 FMT_SNPRINTF(buffer, size, format, width, precision, value);
461}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700462
Victor Zverovichb605b392013-09-09 22:21:40 -0700463template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700464int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700465 wchar_t *buffer, std::size_t size, const wchar_t *format,
466 unsigned width, int precision, T value) {
467 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700468 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000469 FMT_SWPRINTF(buffer, size, format, value) :
470 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700471 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700472 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000473 FMT_SWPRINTF(buffer, size, format, width, value) :
474 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700475}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800476
Victor Zverovich311251e2014-11-29 06:58:00 -0800477template <typename T>
478const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800479 "0001020304050607080910111213141516171819"
480 "2021222324252627282930313233343536373839"
481 "4041424344454647484950515253545556575859"
482 "6061626364656667686970717273747576777879"
483 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800484
Victor Zverovichf1d85162014-02-19 13:02:22 -0800485#define FMT_POWERS_OF_10(factor) \
486 factor * 10, \
487 factor * 100, \
488 factor * 1000, \
489 factor * 10000, \
490 factor * 100000, \
491 factor * 1000000, \
492 factor * 10000000, \
493 factor * 100000000, \
494 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800495
Victor Zverovich311251e2014-11-29 06:58:00 -0800496template <typename T>
497const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
498 0, FMT_POWERS_OF_10(1)
499};
500
501template <typename T>
502const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800503 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800504 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800505 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700506 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800507 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800508 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800509};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800510
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800511FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800512 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800513 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700514 FMT_THROW(fmt::FormatError(
515 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800516 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700517 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700518 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700519 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800520}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700521
vitaut24c309f2015-06-12 07:15:57 -0700522#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700523
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800524FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800525 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700526 if (s.size() > INT_MAX)
527 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
528 int s_size = static_cast<int>(s.size());
529 int length = MultiByteToWideChar(
530 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700531 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800532 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700533 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700534 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700535 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700536 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800537 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700538 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700539}
540
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800541FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700542 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700543 FMT_THROW(WindowsError(error_code,
544 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700545 }
546}
547
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800548FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700549 if (s.size() > INT_MAX)
550 return ERROR_INVALID_PARAMETER;
551 int s_size = static_cast<int>(s.size());
552 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700553 if (length == 0)
554 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700555 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700556 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700557 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700558 if (length == 0)
559 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700560 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700561 return 0;
562}
563
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800564FMT_FUNC void fmt::WindowsError::init(
vitautba09c1b2015-06-26 09:23:11 -0700565 int err_code, CStringRef format_str, ArgList args) {
Carter Li3f574c12015-02-17 10:11:42 +0800566 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700567 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800568 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700569 std::runtime_error &base = *this;
570 base = std::runtime_error(w.str());
571}
572
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800573FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700574 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800575 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700576 class String {
577 private:
578 LPWSTR str_;
579
580 public:
581 String() : str_() {}
582 ~String() { LocalFree(str_); }
583 LPWSTR *ptr() { return &str_; }
584 LPCWSTR c_str() const { return str_; }
585 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700586 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700587 String system_message;
588 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
589 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
590 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
591 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
592 UTF16ToUTF8 utf8_message;
593 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
594 out << message << ": " << utf8_message;
595 return;
596 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700597 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700598 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800599 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700600}
vitaut24c309f2015-06-12 07:15:57 -0700601
602#endif // FMT_USE_WINDOWS_H
603
604FMT_FUNC void fmt::internal::format_system_error(
605 fmt::Writer &out, int error_code,
606 fmt::StringRef message) FMT_NOEXCEPT {
607 FMT_TRY {
608 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
609 buffer.resize(INLINE_BUFFER_SIZE);
610 for (;;) {
611 char *system_message = &buffer[0];
612 int result = safe_strerror(error_code, system_message, buffer.size());
613 if (result == 0) {
614 out << message << ": " << system_message;
615 return;
616 }
617 if (result != ERANGE)
618 break; // Can't get error message, report error code instead.
619 buffer.resize(buffer.size() * 2);
620 }
621 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800622 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
vitaut24c309f2015-06-12 07:15:57 -0700623}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700624
jamboree7487bde2015-06-10 09:32:59 +0800625template <typename Char>
vitauta98583d2015-06-10 08:49:22 -0700626void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800627 if (!map_.empty())
628 return;
vitauta98583d2015-06-10 08:49:22 -0700629 typedef internal::NamedArg<Char> NamedArg;
vitautfccff7b2015-06-11 07:19:00 -0700630 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700631 bool use_values =
632 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800633 if (use_values) {
634 for (unsigned i = 0;/*nothing*/; ++i) {
635 internal::Arg::Type arg_type = args.type(i);
636 switch (arg_type) {
637 case internal::Arg::NONE:
638 return;
639 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700640 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800641 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800642 break;
643 default:
644 /*nothing*/;
645 }
646 }
647 return;
648 }
vitauta98583d2015-06-10 08:49:22 -0700649 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800650 internal::Arg::Type arg_type = args.type(i);
651 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700652 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800653 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800654 }
655 }
vitauta98583d2015-06-10 08:49:22 -0700656 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800657 switch (args.args_[i].type) {
658 case internal::Arg::NONE:
659 return;
660 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700661 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800662 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800663 break;
664 default:
665 /*nothing*/;
666 }
667 }
668}
669
Victor Zverovichd1ded562014-09-29 08:48:16 -0700670template <typename Char>
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800671void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
672 FMT_THROW(std::runtime_error("buffer overflow"));
673}
674
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800675FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700676 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700677 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800678 switch (arg.type) {
679 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700680 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800681 break;
682 case Arg::NAMED_ARG:
683 arg = *static_cast<const internal::Arg*>(arg.pointer);
Patrik Weiskircher6178bc62016-02-23 12:59:26 -0500684 break;
jamboree7487bde2015-06-10 09:32:59 +0800685 default:
686 /*nothing*/;
687 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700688 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700689}
690
Victor Zverovich7cae7632013-09-06 20:23:42 -0700691template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700692void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700693 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700694 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700695 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700696 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700697 spec.align_ = ALIGN_LEFT;
698 break;
699 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700700 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
701 break;
702 case '0':
703 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700704 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700705 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700706 spec.flags_ |= SIGN_FLAG;
707 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700708 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700709 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700710 break;
711 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700712 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700713 return;
714 }
715 }
716}
717
Victor Zverovichcb743c02014-06-19 07:40:35 -0700718template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700719Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700720 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800721 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700722 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700723 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700724 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
725 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700726 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700727 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700728}
729
730template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700731unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700732 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700733 unsigned arg_index = UINT_MAX;
734 Char c = *s;
735 if (c >= '0' && c <= '9') {
736 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700737 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700738 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700739 if (*s == '$') { // value is an argument index
740 ++s;
741 arg_index = value;
742 } else {
743 if (c == '0')
744 spec.fill_ = '0';
745 if (value != 0) {
746 // Nonzero value means that we parsed width and don't need to
747 // parse it or flags again, so return now.
748 spec.width_ = value;
749 return arg_index;
750 }
751 }
752 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700753 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700754 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700755 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700756 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700757 } else if (*s == '*') {
758 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700759 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700760 }
761 return arg_index;
762}
763
Victor Zverovich1f19b982014-06-16 07:49:30 -0700764template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700765void fmt::internal::PrintfFormatter<Char>::format(
vitaut20003762015-07-28 08:09:29 -0700766 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800767 const Char *start = format_str.c_str();
Victor Zverovich7cae7632013-09-06 20:23:42 -0700768 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700769 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700770 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700771 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700772 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700773 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700774 start = ++s;
775 continue;
776 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700777 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700778
Victor Zverovichcb743c02014-06-19 07:40:35 -0700779 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700780 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700781
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700782 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700783 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700784
785 // Parse precision.
786 if (*s == '.') {
787 ++s;
788 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700789 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700790 } else if (*s == '*') {
791 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700792 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700793 }
794 }
795
Victor Zverovich56fc5252014-08-28 07:48:55 -0700796 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700797 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700798 spec.flags_ &= ~HASH_FLAG;
799 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700800 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700801 spec.align_ = ALIGN_NUMERIC;
802 else
803 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700804 }
805
Victor Zverovichf4156b52014-07-30 08:39:07 -0700806 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700807 switch (*s++) {
808 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700809 if (*s == 'h')
810 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700811 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700812 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700813 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700814 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700815 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700816 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700817 else
818 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700819 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700820 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700821 ArgConverter<intmax_t>(arg, *s).visit(arg);
822 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700823 case 'z':
vitaut7dcf0512015-11-13 06:52:13 -0800824 ArgConverter<std::size_t>(arg, *s).visit(arg);
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700825 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700826 case 't':
vitaut7dcf0512015-11-13 06:52:13 -0800827 ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700828 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700829 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700830 // printf produces garbage when 'L' is omitted for long double, no
831 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700832 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700833 default:
834 --s;
vitaut8474a622016-01-24 00:43:42 +0100835 ArgConverter<void>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700836 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700837
838 // Parse type.
839 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700840 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700841 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700842 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
843 // Normalize type.
844 switch (spec.type_) {
845 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700846 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700847 break;
848 case 'c':
849 // TODO: handle wchar_t
850 CharConverter(arg).visit(arg);
851 break;
852 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700853 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700854
855 start = s;
856
857 // Format argument.
vitaut270069b2015-06-16 07:36:32 -0700858 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700859 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700860 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700861}
862
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800863FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800864 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800865 // 'fmt::' is for bcc32.
866 fmt::report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700867}
868
vitaut24c309f2015-06-12 07:15:57 -0700869#if FMT_USE_WINDOWS_H
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800870FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800871 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800872 // 'fmt::' is for bcc32.
873 fmt::report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700874}
Victor Zverovich400812a2014-04-30 12:38:17 -0700875#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700876
vitaut438bd9b2015-06-26 07:43:54 -0700877FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700878 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -0700879 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700880 std::fwrite(w.data(), 1, w.size(), f);
881}
882
vitaut438bd9b2015-06-26 07:43:54 -0700883FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -0700884 print(stdout, format_str, args);
885}
886
vitaut438bd9b2015-06-26 07:43:54 -0700887FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700888 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -0700889 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -0700890 os.write(w.data(), w.size());
891}
892
vitaut438bd9b2015-06-26 07:43:54 -0700893FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700894 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100895 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700896 std::fputs(escape, stdout);
897 print(format, args);
898 std::fputs(RESET_COLOR, stdout);
899}
900
vitaut438bd9b2015-06-26 07:43:54 -0700901FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700902 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -0700903 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -0800904 std::size_t size = w.size();
905 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700906}
907
Nicholas Hutchinson1a5a1702015-12-23 15:59:13 +1300908FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) {
909 MemoryWriter w;
910 printf(w, format, args);
911 os.write(w.data(), w.size());
912 return static_cast<int>(w.size());
913}
914
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800915#ifndef FMT_HEADER_ONLY
916
vitaut9ca1ce22015-05-23 08:04:06 -0700917template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -0700918
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700919// Explicit instantiations for char.
920
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800921template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
922
vitaut535dbdd2015-12-03 09:38:06 -0800923template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700924
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700925template void fmt::internal::PrintfFormatter<char>::format(
vitaut20003762015-07-28 08:09:29 -0700926 BasicWriter<char> &writer, CStringRef format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700927
Victor Zverovich14f25772014-09-19 08:45:05 -0700928template int fmt::internal::CharTraits<char>::format_float(
929 char *buffer, std::size_t size, const char *format,
930 unsigned width, int precision, double value);
931
932template int fmt::internal::CharTraits<char>::format_float(
933 char *buffer, std::size_t size, const char *format,
934 unsigned width, int precision, long double value);
935
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700936// Explicit instantiations for wchar_t.
937
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800938template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
939
vitaut535dbdd2015-12-03 09:38:06 -0800940template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700941
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700942template void fmt::internal::PrintfFormatter<wchar_t>::format(
vitaut20003762015-07-28 08:09:29 -0700943 BasicWriter<wchar_t> &writer, WCStringRef format);
jdale88a9862fd2014-03-11 18:56:24 +0000944
Victor Zverovich14f25772014-09-19 08:45:05 -0700945template int fmt::internal::CharTraits<wchar_t>::format_float(
946 wchar_t *buffer, std::size_t size, const wchar_t *format,
947 unsigned width, int precision, double value);
948
949template int fmt::internal::CharTraits<wchar_t>::format_float(
950 wchar_t *buffer, std::size_t size, const wchar_t *format,
951 unsigned width, int precision, long double value);
952
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800953#endif // FMT_HEADER_ONLY
954
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100955#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000956# pragma warning(pop)
957#endif