blob: 995e5727e6de35809322997798474dad34028ca9 [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 ";
Victor Zverovich22f75d82014-09-03 08:03:05 -0700210 fmt::internal::IntTraits<int>::MainType ec_value = error_code;
vitaut1addec92015-03-21 20:16:36 -0700211 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
212 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
213 error_code_size += fmt::internal::count_digits(ec_value);
Victor Zverovich88e0db82014-09-05 08:04:26 -0700214 if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700215 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700216 out << ERROR_STR << error_code;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700217 assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
218}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700219
Victor Zverovichd8b9f412014-07-29 06:38:05 -0700220void report_error(FormatFunc func,
Carter Lie2583ab2015-02-14 09:58:29 +0800221 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700222 fmt::MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700223 func(full_message, error_code, message);
224 // Use Writer::data instead of Writer::c_str to avoid potential memory
225 // allocation.
226 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
227 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700228}
Victor Zverovichd29e5052014-06-30 07:12:09 -0700229
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700230// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
231class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
232 public:
233 template <typename T>
234 bool visit_any_int(T value) { return value == 0; }
235};
Victor Zverovich6e5551e2014-07-02 06:33:25 -0700236
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700237// Checks if an argument is a valid printf width specifier and sets
238// left alignment if it is negative.
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700239class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700240 private:
241 fmt::FormatSpec &spec_;
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700242
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800243 FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
244
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700245 public:
246 explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700247
vitautd4ea2d72015-03-26 08:55:20 -0700248 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700249 FMT_THROW(fmt::FormatError("width is not integer"));
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700250 }
Victor Zveroviche3a2ac82014-07-14 08:04:17 -0700251
Victor Zverovich9d74f952014-07-16 07:27:54 -0700252 template <typename T>
253 unsigned visit_any_int(T value) {
254 typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
255 UnsignedType width = value;
256 if (fmt::internal::is_negative(value)) {
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700257 spec_.align_ = fmt::ALIGN_LEFT;
258 width = 0 - width;
259 }
Victor Zverovich9d74f952014-07-16 07:27:54 -0700260 if (width > INT_MAX)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700261 FMT_THROW(fmt::FormatError("number is too big"));
Victor Zverovich9d74f952014-07-16 07:27:54 -0700262 return static_cast<unsigned>(width);
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700263 }
Victor Zverovich591ad0a2014-07-14 06:55:29 -0700264};
Victor Zverovich512e2ce2014-07-14 08:47:03 -0700265
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700266class PrecisionHandler :
267 public fmt::internal::ArgVisitor<PrecisionHandler, int> {
268 public:
vitautd4ea2d72015-03-26 08:55:20 -0700269 void report_unhandled_arg() {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700270 FMT_THROW(fmt::FormatError("precision is not integer"));
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
vitaut8474a622016-01-24 00:43:42 +0100281template <typename T, typename U>
282struct is_same {
283 enum { value = 0 };
284};
285
Victor Zverovicheeca2232014-07-30 07:37:16 -0700286template <typename T>
vitaut8474a622016-01-24 00:43:42 +0100287struct is_same<T, T> {
288 enum { value = 1 };
289};
290
291// An argument visitor that converts an integer argument to T for printf,
vitautbb7a80b2016-01-25 06:46:43 -0800292// if T is an integral type. If T is void, the argument is converted to
293// corresponding signed or unsigned type depending on the type specifier:
vitaut8474a622016-01-24 00:43:42 +0100294// 'd' and 'i' - signed, other - unsigned)
295template <typename T = void>
Victor Zverovicheeca2232014-07-30 07:37:16 -0700296class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
297 private:
298 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700299 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700300
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800301 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
302
Victor Zverovicheeca2232014-07-30 07:37:16 -0700303 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700304 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
305 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700306
vitaut21573752015-11-13 07:18:44 -0800307 void visit_bool(bool value) {
308 if (type_ != 's')
309 visit_any_int(value);
310 }
311
Victor Zverovicheeca2232014-07-30 07:37:16 -0700312 template <typename U>
313 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700314 bool is_signed = type_ == 'd' || type_ == 'i';
315 using fmt::internal::Arg;
vitaut8474a622016-01-24 00:43:42 +0100316 typedef typename fmt::internal::Conditional<
317 is_same<T, void>::value, U, T>::type TargetType;
318 if (sizeof(TargetType) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700319 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700320 if (is_signed) {
321 arg_.type = Arg::INT;
vitaut8474a622016-01-24 00:43:42 +0100322 arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700323 } else {
324 arg_.type = Arg::UINT;
vitaut8474a622016-01-24 00:43:42 +0100325 typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned;
326 arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700327 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700328 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700329 if (is_signed) {
330 arg_.type = Arg::LONG_LONG;
vitaut7ee287d2016-01-27 07:03:19 -0800331 // glibc's printf doesn't sign extend arguments of smaller types:
vitautae6368c2016-01-26 07:13:34 -0800332 // std::printf("%lld", -42); // prints "4294967254"
vitaut7ee287d2016-01-27 07:03:19 -0800333 // but we don't have to do the same because it's a UB.
334 arg_.long_long_value = value;
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700335 } else {
336 arg_.type = Arg::ULONG_LONG;
337 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700338 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700339 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700340 }
341 }
342};
343
Victor Zverovich32344d92014-08-28 08:11:21 -0700344// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700345class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
346 private:
347 fmt::internal::Arg &arg_;
348
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800349 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
350
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700351 public:
352 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
353
354 template <typename T>
355 void visit_any_int(T value) {
356 arg_.type = Arg::CHAR;
357 arg_.int_value = static_cast<char>(value);
358 }
359};
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700360} // namespace
vitaut270069b2015-06-16 07:36:32 -0700361
362namespace internal {
363
vitaut270069b2015-06-16 07:36:32 -0700364template <typename Char>
365class PrintfArgFormatter :
vitaut535dbdd2015-12-03 09:38:06 -0800366 public ArgFormatterBase<PrintfArgFormatter<Char>, Char> {
vitaut57ba9432015-11-12 06:09:08 -0800367
368 void write_null_pointer() {
vitaut1a2a3332015-11-23 21:01:28 -0800369 this->spec().type_ = 0;
370 this->write("(nil)");
vitaut57ba9432015-11-12 06:09:08 -0800371 }
372
vitaut535dbdd2015-12-03 09:38:06 -0800373 typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base;
vitaut1a2a3332015-11-23 21:01:28 -0800374
vitaut270069b2015-06-16 07:36:32 -0700375 public:
376 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
vitaut535dbdd2015-12-03 09:38:06 -0800377 : ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {}
vitaut270069b2015-06-16 07:36:32 -0700378
vitaut21573752015-11-13 07:18:44 -0800379 void visit_bool(bool value) {
380 FormatSpec &fmt_spec = this->spec();
381 if (fmt_spec.type_ != 's')
382 return this->visit_any_int(value);
383 fmt_spec.type_ = 0;
vitaut1a2a3332015-11-23 21:01:28 -0800384 this->write(value);
vitaut21573752015-11-13 07:18:44 -0800385 }
386
vitaut270069b2015-06-16 07:36:32 -0700387 void visit_char(int value) {
vitaut7fa17fe2015-08-04 07:55:33 -0700388 const FormatSpec &fmt_spec = this->spec();
vitautecdc7ec2015-08-04 08:01:28 -0700389 BasicWriter<Char> &w = this->writer();
vitaut7fa17fe2015-08-04 07:55:33 -0700390 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
vitautecdc7ec2015-08-04 08:01:28 -0700391 w.write_int(value, fmt_spec);
vitaut270069b2015-06-16 07:36:32 -0700392 typedef typename BasicWriter<Char>::CharPtr CharPtr;
393 CharPtr out = CharPtr();
vitaut7fa17fe2015-08-04 07:55:33 -0700394 if (fmt_spec.width_ > 1) {
vitaut270069b2015-06-16 07:36:32 -0700395 Char fill = ' ';
vitautecdc7ec2015-08-04 08:01:28 -0700396 out = w.grow_buffer(fmt_spec.width_);
vitaut7fa17fe2015-08-04 07:55:33 -0700397 if (fmt_spec.align_ != ALIGN_LEFT) {
398 std::fill_n(out, fmt_spec.width_ - 1, fill);
399 out += fmt_spec.width_ - 1;
vitaut270069b2015-06-16 07:36:32 -0700400 } else {
vitaut7fa17fe2015-08-04 07:55:33 -0700401 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
vitaut270069b2015-06-16 07:36:32 -0700402 }
403 } else {
vitautecdc7ec2015-08-04 08:01:28 -0700404 out = w.grow_buffer(1);
vitaut270069b2015-06-16 07:36:32 -0700405 }
406 *out = static_cast<Char>(value);
407 }
vitaut79d8f592015-09-08 08:36:20 -0700408
vitautb5fda1c2015-11-11 07:57:19 -0800409 void visit_cstring(const char *value) {
410 if (value)
vitaut1a2a3332015-11-23 21:01:28 -0800411 Base::visit_cstring(value);
vitaut57ba9432015-11-12 06:09:08 -0800412 else if (this->spec().type_ == 'p')
413 write_null_pointer();
vitautb5fda1c2015-11-11 07:57:19 -0800414 else
vitaut1a2a3332015-11-23 21:01:28 -0800415 this->write("(null)");
vitautb5fda1c2015-11-11 07:57:19 -0800416 }
417
418 void visit_pointer(const void *value) {
419 if (value)
vitaut1a2a3332015-11-23 21:01:28 -0800420 return Base::visit_pointer(value);
421 this->spec().type_ = 0;
422 write_null_pointer();
vitautb5fda1c2015-11-11 07:57:19 -0800423 }
424
vitaut79d8f592015-09-08 08:36:20 -0700425 void visit_custom(Arg::CustomValue c) {
426 BasicFormatter<Char> formatter(ArgList(), this->writer());
vitautef710de2015-09-18 16:26:41 -0700427 const Char format_str[] = {'}', 0};
428 const Char *format = format_str;
vitaut79d8f592015-09-08 08:36:20 -0700429 c.format(&formatter, c.value, &format);
430 }
vitaut270069b2015-06-16 07:36:32 -0700431};
432} // namespace internal
vitaut8725d072015-06-12 07:56:58 -0700433} // namespace fmt
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700434
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800435FMT_FUNC void fmt::SystemError::init(
vitaut438bd9b2015-06-26 07:43:54 -0700436 int err_code, CStringRef format_str, ArgList args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800437 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700438 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800439 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700440 std::runtime_error &base = *this;
441 base = std::runtime_error(w.str());
442}
443
Victor Zverovichb605b392013-09-09 22:21:40 -0700444template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700445int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700446 char *buffer, std::size_t size, const char *format,
447 unsigned width, int precision, T value) {
448 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700449 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700450 FMT_SNPRINTF(buffer, size, format, value) :
451 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700452 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700453 return precision < 0 ?
454 FMT_SNPRINTF(buffer, size, format, width, value) :
455 FMT_SNPRINTF(buffer, size, format, width, precision, value);
456}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700457
Victor Zverovichb605b392013-09-09 22:21:40 -0700458template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700459int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700460 wchar_t *buffer, std::size_t size, const wchar_t *format,
461 unsigned width, int precision, T value) {
462 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700463 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000464 FMT_SWPRINTF(buffer, size, format, value) :
465 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700466 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700467 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000468 FMT_SWPRINTF(buffer, size, format, width, value) :
469 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700470}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800471
Victor Zverovich311251e2014-11-29 06:58:00 -0800472template <typename T>
473const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800474 "0001020304050607080910111213141516171819"
475 "2021222324252627282930313233343536373839"
476 "4041424344454647484950515253545556575859"
477 "6061626364656667686970717273747576777879"
478 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800479
Victor Zverovichf1d85162014-02-19 13:02:22 -0800480#define FMT_POWERS_OF_10(factor) \
481 factor * 10, \
482 factor * 100, \
483 factor * 1000, \
484 factor * 10000, \
485 factor * 100000, \
486 factor * 1000000, \
487 factor * 10000000, \
488 factor * 100000000, \
489 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800490
Victor Zverovich311251e2014-11-29 06:58:00 -0800491template <typename T>
492const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
493 0, FMT_POWERS_OF_10(1)
494};
495
496template <typename T>
497const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800498 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800499 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800500 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700501 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800502 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800503 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800504};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800505
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800506FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800507 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800508 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700509 FMT_THROW(fmt::FormatError(
510 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800511 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700512 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700513 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700514 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800515}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700516
vitaut24c309f2015-06-12 07:15:57 -0700517#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700518
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800519FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800520 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700521 if (s.size() > INT_MAX)
522 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
523 int s_size = static_cast<int>(s.size());
524 int length = MultiByteToWideChar(
525 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700526 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800527 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700528 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700529 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700530 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
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_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700534}
535
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800536FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700537 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700538 FMT_THROW(WindowsError(error_code,
539 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700540 }
541}
542
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800543FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700544 if (s.size() > INT_MAX)
545 return ERROR_INVALID_PARAMETER;
546 int s_size = static_cast<int>(s.size());
547 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700548 if (length == 0)
549 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700550 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700551 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700552 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700553 if (length == 0)
554 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700555 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700556 return 0;
557}
558
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800559FMT_FUNC void fmt::WindowsError::init(
vitautba09c1b2015-06-26 09:23:11 -0700560 int err_code, CStringRef format_str, ArgList args) {
Carter Li3f574c12015-02-17 10:11:42 +0800561 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700562 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800563 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700564 std::runtime_error &base = *this;
565 base = std::runtime_error(w.str());
566}
567
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800568FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700569 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800570 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700571 class String {
572 private:
573 LPWSTR str_;
574
575 public:
576 String() : str_() {}
577 ~String() { LocalFree(str_); }
578 LPWSTR *ptr() { return &str_; }
579 LPCWSTR c_str() const { return str_; }
580 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700581 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700582 String system_message;
583 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
584 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
585 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
586 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
587 UTF16ToUTF8 utf8_message;
588 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
589 out << message << ": " << utf8_message;
590 return;
591 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700592 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700593 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800594 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700595}
vitaut24c309f2015-06-12 07:15:57 -0700596
597#endif // FMT_USE_WINDOWS_H
598
599FMT_FUNC void fmt::internal::format_system_error(
600 fmt::Writer &out, int error_code,
601 fmt::StringRef message) FMT_NOEXCEPT {
602 FMT_TRY {
603 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
604 buffer.resize(INLINE_BUFFER_SIZE);
605 for (;;) {
606 char *system_message = &buffer[0];
607 int result = safe_strerror(error_code, system_message, buffer.size());
608 if (result == 0) {
609 out << message << ": " << system_message;
610 return;
611 }
612 if (result != ERANGE)
613 break; // Can't get error message, report error code instead.
614 buffer.resize(buffer.size() * 2);
615 }
616 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800617 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
vitaut24c309f2015-06-12 07:15:57 -0700618}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700619
jamboree7487bde2015-06-10 09:32:59 +0800620template <typename Char>
vitauta98583d2015-06-10 08:49:22 -0700621void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800622 if (!map_.empty())
623 return;
vitauta98583d2015-06-10 08:49:22 -0700624 typedef internal::NamedArg<Char> NamedArg;
vitautfccff7b2015-06-11 07:19:00 -0700625 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700626 bool use_values =
627 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800628 if (use_values) {
629 for (unsigned i = 0;/*nothing*/; ++i) {
630 internal::Arg::Type arg_type = args.type(i);
631 switch (arg_type) {
632 case internal::Arg::NONE:
633 return;
634 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700635 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800636 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800637 break;
638 default:
639 /*nothing*/;
640 }
641 }
642 return;
643 }
vitauta98583d2015-06-10 08:49:22 -0700644 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800645 internal::Arg::Type arg_type = args.type(i);
646 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700647 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800648 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800649 }
650 }
vitauta98583d2015-06-10 08:49:22 -0700651 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800652 switch (args.args_[i].type) {
653 case internal::Arg::NONE:
654 return;
655 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700656 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800657 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800658 break;
659 default:
660 /*nothing*/;
661 }
662 }
663}
664
Victor Zverovichd1ded562014-09-29 08:48:16 -0700665template <typename Char>
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800666void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
667 FMT_THROW(std::runtime_error("buffer overflow"));
668}
669
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800670FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700671 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700672 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800673 switch (arg.type) {
674 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700675 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800676 break;
677 case Arg::NAMED_ARG:
678 arg = *static_cast<const internal::Arg*>(arg.pointer);
679 default:
680 /*nothing*/;
681 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700682 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700683}
684
Victor Zverovich7cae7632013-09-06 20:23:42 -0700685template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700686void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700687 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700688 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700689 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700690 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700691 spec.align_ = ALIGN_LEFT;
692 break;
693 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700694 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
695 break;
696 case '0':
697 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700698 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700699 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700700 spec.flags_ |= SIGN_FLAG;
701 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700702 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700703 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700704 break;
705 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700706 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700707 return;
708 }
709 }
710}
711
Victor Zverovichcb743c02014-06-19 07:40:35 -0700712template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700713Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700714 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800715 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700716 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700717 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700718 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
719 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700720 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700721 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700722}
723
724template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700725unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700726 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700727 unsigned arg_index = UINT_MAX;
728 Char c = *s;
729 if (c >= '0' && c <= '9') {
730 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700731 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700732 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700733 if (*s == '$') { // value is an argument index
734 ++s;
735 arg_index = value;
736 } else {
737 if (c == '0')
738 spec.fill_ = '0';
739 if (value != 0) {
740 // Nonzero value means that we parsed width and don't need to
741 // parse it or flags again, so return now.
742 spec.width_ = value;
743 return arg_index;
744 }
745 }
746 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700747 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700748 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700749 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700750 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700751 } else if (*s == '*') {
752 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700753 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700754 }
755 return arg_index;
756}
757
Victor Zverovich1f19b982014-06-16 07:49:30 -0700758template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700759void fmt::internal::PrintfFormatter<Char>::format(
vitaut20003762015-07-28 08:09:29 -0700760 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800761 const Char *start = format_str.c_str();
Victor Zverovich7cae7632013-09-06 20:23:42 -0700762 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700763 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700764 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700765 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700766 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700767 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700768 start = ++s;
769 continue;
770 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700771 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700772
Victor Zverovichcb743c02014-06-19 07:40:35 -0700773 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700774 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700775
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700776 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700777 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700778
779 // Parse precision.
780 if (*s == '.') {
781 ++s;
782 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700783 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700784 } else if (*s == '*') {
785 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700786 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700787 }
788 }
789
Victor Zverovich56fc5252014-08-28 07:48:55 -0700790 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700791 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700792 spec.flags_ &= ~HASH_FLAG;
793 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700794 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700795 spec.align_ = ALIGN_NUMERIC;
796 else
797 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700798 }
799
Victor Zverovichf4156b52014-07-30 08:39:07 -0700800 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700801 switch (*s++) {
802 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700803 if (*s == 'h')
804 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700805 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700806 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700807 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700808 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700809 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700810 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700811 else
812 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700813 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700814 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700815 ArgConverter<intmax_t>(arg, *s).visit(arg);
816 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700817 case 'z':
vitaut7dcf0512015-11-13 06:52:13 -0800818 ArgConverter<std::size_t>(arg, *s).visit(arg);
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700819 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700820 case 't':
vitaut7dcf0512015-11-13 06:52:13 -0800821 ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700822 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700823 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700824 // printf produces garbage when 'L' is omitted for long double, no
825 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700826 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700827 default:
828 --s;
vitaut8474a622016-01-24 00:43:42 +0100829 ArgConverter<void>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700830 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700831
832 // Parse type.
833 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700834 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700835 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700836 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
837 // Normalize type.
838 switch (spec.type_) {
839 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700840 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700841 break;
842 case 'c':
843 // TODO: handle wchar_t
844 CharConverter(arg).visit(arg);
845 break;
846 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700847 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700848
849 start = s;
850
851 // Format argument.
vitaut270069b2015-06-16 07:36:32 -0700852 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700853 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700854 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700855}
856
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800857FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800858 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800859 // 'fmt::' is for bcc32.
860 fmt::report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700861}
862
vitaut24c309f2015-06-12 07:15:57 -0700863#if FMT_USE_WINDOWS_H
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800864FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800865 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800866 // 'fmt::' is for bcc32.
867 fmt::report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700868}
Victor Zverovich400812a2014-04-30 12:38:17 -0700869#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700870
vitaut438bd9b2015-06-26 07:43:54 -0700871FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700872 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -0700873 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700874 std::fwrite(w.data(), 1, w.size(), f);
875}
876
vitaut438bd9b2015-06-26 07:43:54 -0700877FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -0700878 print(stdout, format_str, args);
879}
880
vitaut438bd9b2015-06-26 07:43:54 -0700881FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700882 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -0700883 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -0700884 os.write(w.data(), w.size());
885}
886
vitaut438bd9b2015-06-26 07:43:54 -0700887FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700888 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100889 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700890 std::fputs(escape, stdout);
891 print(format, args);
892 std::fputs(RESET_COLOR, stdout);
893}
894
vitaut438bd9b2015-06-26 07:43:54 -0700895FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700896 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -0700897 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -0800898 std::size_t size = w.size();
899 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700900}
901
Nicholas Hutchinson1a5a1702015-12-23 15:59:13 +1300902FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) {
903 MemoryWriter w;
904 printf(w, format, args);
905 os.write(w.data(), w.size());
906 return static_cast<int>(w.size());
907}
908
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800909#ifndef FMT_HEADER_ONLY
910
vitaut9ca1ce22015-05-23 08:04:06 -0700911template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -0700912
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700913// Explicit instantiations for char.
914
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800915template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
916
vitaut535dbdd2015-12-03 09:38:06 -0800917template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700918
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700919template void fmt::internal::PrintfFormatter<char>::format(
vitaut20003762015-07-28 08:09:29 -0700920 BasicWriter<char> &writer, CStringRef format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700921
Victor Zverovich14f25772014-09-19 08:45:05 -0700922template int fmt::internal::CharTraits<char>::format_float(
923 char *buffer, std::size_t size, const char *format,
924 unsigned width, int precision, double value);
925
926template int fmt::internal::CharTraits<char>::format_float(
927 char *buffer, std::size_t size, const char *format,
928 unsigned width, int precision, long double value);
929
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700930// Explicit instantiations for wchar_t.
931
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800932template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
933
vitaut535dbdd2015-12-03 09:38:06 -0800934template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700935
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700936template void fmt::internal::PrintfFormatter<wchar_t>::format(
vitaut20003762015-07-28 08:09:29 -0700937 BasicWriter<wchar_t> &writer, WCStringRef format);
jdale88a9862fd2014-03-11 18:56:24 +0000938
Victor Zverovich14f25772014-09-19 08:45:05 -0700939template int fmt::internal::CharTraits<wchar_t>::format_float(
940 wchar_t *buffer, std::size_t size, const wchar_t *format,
941 unsigned width, int precision, double value);
942
943template int fmt::internal::CharTraits<wchar_t>::format_float(
944 wchar_t *buffer, std::size_t size, const wchar_t *format,
945 unsigned width, int precision, long double value);
946
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800947#endif // FMT_HEADER_ONLY
948
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100949#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000950# pragma warning(pop)
951#endif