blob: 1970d53c5007d60508f40d6e4baabafc27f1ae9a [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
Victor Zverovich32344d92014-08-28 08:11:21 -0700281// Converts an integer argument to an integral type T for printf.
Victor Zverovicheeca2232014-07-30 07:37:16 -0700282template <typename T>
283class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
284 private:
285 fmt::internal::Arg &arg_;
Victor Zveroviche22d6572014-08-08 06:51:09 -0700286 wchar_t type_;
Victor Zverovicheeca2232014-07-30 07:37:16 -0700287
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800288 FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
289
Victor Zverovicheeca2232014-07-30 07:37:16 -0700290 public:
Victor Zveroviche22d6572014-08-08 06:51:09 -0700291 ArgConverter(fmt::internal::Arg &arg, wchar_t type)
292 : arg_(arg), type_(type) {}
Victor Zverovicheeca2232014-07-30 07:37:16 -0700293
vitaut21573752015-11-13 07:18:44 -0800294 void visit_bool(bool value) {
295 if (type_ != 's')
296 visit_any_int(value);
297 }
298
Victor Zverovicheeca2232014-07-30 07:37:16 -0700299 template <typename U>
300 void visit_any_int(U value) {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700301 bool is_signed = type_ == 'd' || type_ == 'i';
302 using fmt::internal::Arg;
303 if (sizeof(T) <= sizeof(int)) {
Victor Zverovich32344d92014-08-28 08:11:21 -0700304 // Extra casts are used to silence warnings.
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700305 if (is_signed) {
306 arg_.type = Arg::INT;
Victor Zverovichbb016332014-08-15 09:03:59 -0700307 arg_.int_value = static_cast<int>(static_cast<T>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700308 } else {
309 arg_.type = Arg::UINT;
Victor Zverovich186734c2014-08-18 07:03:12 -0700310 arg_.uint_value = static_cast<unsigned>(
311 static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700312 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700313 } else {
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700314 if (is_signed) {
315 arg_.type = Arg::LONG_LONG;
Victor Zverovicha259c942014-08-01 07:15:27 -0700316 arg_.long_long_value =
317 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700318 } else {
319 arg_.type = Arg::ULONG_LONG;
320 arg_.ulong_long_value =
Victor Zverovicha259c942014-08-01 07:15:27 -0700321 static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700322 }
Victor Zverovicheeca2232014-07-30 07:37:16 -0700323 }
324 }
325};
326
Victor Zverovich32344d92014-08-28 08:11:21 -0700327// Converts an integer argument to char for printf.
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700328class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
329 private:
330 fmt::internal::Arg &arg_;
331
Victor Zverovich6f3c0952014-12-03 06:16:52 -0800332 FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
333
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700334 public:
335 explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
336
337 template <typename T>
338 void visit_any_int(T value) {
339 arg_.type = Arg::CHAR;
340 arg_.int_value = static_cast<char>(value);
341 }
342};
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700343} // namespace
vitaut270069b2015-06-16 07:36:32 -0700344
345namespace internal {
346
vitaut270069b2015-06-16 07:36:32 -0700347template <typename Char>
348class PrintfArgFormatter :
vitaut535dbdd2015-12-03 09:38:06 -0800349 public ArgFormatterBase<PrintfArgFormatter<Char>, Char> {
vitaut57ba9432015-11-12 06:09:08 -0800350
351 void write_null_pointer() {
vitaut1a2a3332015-11-23 21:01:28 -0800352 this->spec().type_ = 0;
353 this->write("(nil)");
vitaut57ba9432015-11-12 06:09:08 -0800354 }
355
vitaut535dbdd2015-12-03 09:38:06 -0800356 typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base;
vitaut1a2a3332015-11-23 21:01:28 -0800357
vitaut270069b2015-06-16 07:36:32 -0700358 public:
359 PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
vitaut535dbdd2015-12-03 09:38:06 -0800360 : ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {}
vitaut270069b2015-06-16 07:36:32 -0700361
vitaut21573752015-11-13 07:18:44 -0800362 void visit_bool(bool value) {
363 FormatSpec &fmt_spec = this->spec();
364 if (fmt_spec.type_ != 's')
365 return this->visit_any_int(value);
366 fmt_spec.type_ = 0;
vitaut1a2a3332015-11-23 21:01:28 -0800367 this->write(value);
vitaut21573752015-11-13 07:18:44 -0800368 }
369
vitaut270069b2015-06-16 07:36:32 -0700370 void visit_char(int value) {
vitaut7fa17fe2015-08-04 07:55:33 -0700371 const FormatSpec &fmt_spec = this->spec();
vitautecdc7ec2015-08-04 08:01:28 -0700372 BasicWriter<Char> &w = this->writer();
vitaut7fa17fe2015-08-04 07:55:33 -0700373 if (fmt_spec.type_ && fmt_spec.type_ != 'c')
vitautecdc7ec2015-08-04 08:01:28 -0700374 w.write_int(value, fmt_spec);
vitaut270069b2015-06-16 07:36:32 -0700375 typedef typename BasicWriter<Char>::CharPtr CharPtr;
376 CharPtr out = CharPtr();
vitaut7fa17fe2015-08-04 07:55:33 -0700377 if (fmt_spec.width_ > 1) {
vitaut270069b2015-06-16 07:36:32 -0700378 Char fill = ' ';
vitautecdc7ec2015-08-04 08:01:28 -0700379 out = w.grow_buffer(fmt_spec.width_);
vitaut7fa17fe2015-08-04 07:55:33 -0700380 if (fmt_spec.align_ != ALIGN_LEFT) {
381 std::fill_n(out, fmt_spec.width_ - 1, fill);
382 out += fmt_spec.width_ - 1;
vitaut270069b2015-06-16 07:36:32 -0700383 } else {
vitaut7fa17fe2015-08-04 07:55:33 -0700384 std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
vitaut270069b2015-06-16 07:36:32 -0700385 }
386 } else {
vitautecdc7ec2015-08-04 08:01:28 -0700387 out = w.grow_buffer(1);
vitaut270069b2015-06-16 07:36:32 -0700388 }
389 *out = static_cast<Char>(value);
390 }
vitaut79d8f592015-09-08 08:36:20 -0700391
vitautb5fda1c2015-11-11 07:57:19 -0800392 void visit_cstring(const char *value) {
393 if (value)
vitaut1a2a3332015-11-23 21:01:28 -0800394 Base::visit_cstring(value);
vitaut57ba9432015-11-12 06:09:08 -0800395 else if (this->spec().type_ == 'p')
396 write_null_pointer();
vitautb5fda1c2015-11-11 07:57:19 -0800397 else
vitaut1a2a3332015-11-23 21:01:28 -0800398 this->write("(null)");
vitautb5fda1c2015-11-11 07:57:19 -0800399 }
400
401 void visit_pointer(const void *value) {
402 if (value)
vitaut1a2a3332015-11-23 21:01:28 -0800403 return Base::visit_pointer(value);
404 this->spec().type_ = 0;
405 write_null_pointer();
vitautb5fda1c2015-11-11 07:57:19 -0800406 }
407
vitaut79d8f592015-09-08 08:36:20 -0700408 void visit_custom(Arg::CustomValue c) {
409 BasicFormatter<Char> formatter(ArgList(), this->writer());
vitautef710de2015-09-18 16:26:41 -0700410 const Char format_str[] = {'}', 0};
411 const Char *format = format_str;
vitaut79d8f592015-09-08 08:36:20 -0700412 c.format(&formatter, c.value, &format);
413 }
vitaut270069b2015-06-16 07:36:32 -0700414};
415} // namespace internal
vitaut8725d072015-06-12 07:56:58 -0700416} // namespace fmt
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700417
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800418FMT_FUNC void fmt::SystemError::init(
vitaut438bd9b2015-06-26 07:43:54 -0700419 int err_code, CStringRef format_str, ArgList args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800420 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700421 MemoryWriter w;
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800422 internal::format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700423 std::runtime_error &base = *this;
424 base = std::runtime_error(w.str());
425}
426
Victor Zverovichb605b392013-09-09 22:21:40 -0700427template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700428int fmt::internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700429 char *buffer, std::size_t size, const char *format,
430 unsigned width, int precision, T value) {
431 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700432 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700433 FMT_SNPRINTF(buffer, size, format, value) :
434 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700435 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700436 return precision < 0 ?
437 FMT_SNPRINTF(buffer, size, format, width, value) :
438 FMT_SNPRINTF(buffer, size, format, width, precision, value);
439}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700440
Victor Zverovichb605b392013-09-09 22:21:40 -0700441template <typename T>
Victor Zverovichb498ba02014-07-26 08:03:03 -0700442int fmt::internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700443 wchar_t *buffer, std::size_t size, const wchar_t *format,
444 unsigned width, int precision, T value) {
445 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700446 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000447 FMT_SWPRINTF(buffer, size, format, value) :
448 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700449 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700450 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000451 FMT_SWPRINTF(buffer, size, format, width, value) :
452 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700453}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800454
Victor Zverovich311251e2014-11-29 06:58:00 -0800455template <typename T>
456const char fmt::internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800457 "0001020304050607080910111213141516171819"
458 "2021222324252627282930313233343536373839"
459 "4041424344454647484950515253545556575859"
460 "6061626364656667686970717273747576777879"
461 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800462
Victor Zverovichf1d85162014-02-19 13:02:22 -0800463#define FMT_POWERS_OF_10(factor) \
464 factor * 10, \
465 factor * 100, \
466 factor * 1000, \
467 factor * 10000, \
468 factor * 100000, \
469 factor * 1000000, \
470 factor * 10000000, \
471 factor * 100000000, \
472 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800473
Victor Zverovich311251e2014-11-29 06:58:00 -0800474template <typename T>
475const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
476 0, FMT_POWERS_OF_10(1)
477};
478
479template <typename T>
480const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800481 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800482 FMT_POWERS_OF_10(1),
Victor Zverovichecd2b802014-12-17 06:42:26 -0800483 FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700484 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800485 // to avoid warnings about C++98 not supporting long long.
Victor Zverovichecd2b802014-12-17 06:42:26 -0800486 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800487};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800488
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800489FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800490 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800491 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700492 FMT_THROW(fmt::FormatError(
493 fmt::format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800494 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700495 FMT_THROW(fmt::FormatError(
Victor Zveroviche63a0ff2014-06-30 06:43:53 -0700496 fmt::format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700497 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800498}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700499
vitaut24c309f2015-06-12 07:15:57 -0700500#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700501
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800502FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800503 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700504 if (s.size() > INT_MAX)
505 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
506 int s_size = static_cast<int>(s.size());
507 int length = MultiByteToWideChar(
508 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700509 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800510 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700511 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700512 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700513 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700514 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800515 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700516 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700517}
518
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800519FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700520 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700521 FMT_THROW(WindowsError(error_code,
522 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700523 }
524}
525
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800526FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700527 if (s.size() > INT_MAX)
528 return ERROR_INVALID_PARAMETER;
529 int s_size = static_cast<int>(s.size());
530 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700531 if (length == 0)
532 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700533 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700534 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700535 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700536 if (length == 0)
537 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700538 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700539 return 0;
540}
541
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800542FMT_FUNC void fmt::WindowsError::init(
vitautba09c1b2015-06-26 09:23:11 -0700543 int err_code, CStringRef format_str, ArgList args) {
Carter Li3f574c12015-02-17 10:11:42 +0800544 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700545 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800546 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700547 std::runtime_error &base = *this;
548 base = std::runtime_error(w.str());
549}
550
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800551FMT_FUNC void fmt::internal::format_windows_error(
Victor Zverovich22f75d82014-09-03 08:03:05 -0700552 fmt::Writer &out, int error_code,
Carter Lie2583ab2015-02-14 09:58:29 +0800553 fmt::StringRef message) FMT_NOEXCEPT {
Victor Zverovich53b4c312014-04-30 15:00:41 -0700554 class String {
555 private:
556 LPWSTR str_;
557
558 public:
559 String() : str_() {}
560 ~String() { LocalFree(str_); }
561 LPWSTR *ptr() { return &str_; }
562 LPCWSTR c_str() const { return str_; }
563 };
Victor Zverovich8b76e972014-10-06 08:30:55 -0700564 FMT_TRY {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700565 String system_message;
566 if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
567 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
568 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
569 reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) {
570 UTF16ToUTF8 utf8_message;
571 if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) {
572 out << message << ": " << utf8_message;
573 return;
574 }
Victor Zverovich53b4c312014-04-30 15:00:41 -0700575 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700576 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800577 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700578}
vitaut24c309f2015-06-12 07:15:57 -0700579
580#endif // FMT_USE_WINDOWS_H
581
582FMT_FUNC void fmt::internal::format_system_error(
583 fmt::Writer &out, int error_code,
584 fmt::StringRef message) FMT_NOEXCEPT {
585 FMT_TRY {
586 MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
587 buffer.resize(INLINE_BUFFER_SIZE);
588 for (;;) {
589 char *system_message = &buffer[0];
590 int result = safe_strerror(error_code, system_message, buffer.size());
591 if (result == 0) {
592 out << message << ": " << system_message;
593 return;
594 }
595 if (result != ERANGE)
596 break; // Can't get error message, report error code instead.
597 buffer.resize(buffer.size() * 2);
598 }
599 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800600 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
vitaut24c309f2015-06-12 07:15:57 -0700601}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700602
jamboree7487bde2015-06-10 09:32:59 +0800603template <typename Char>
vitauta98583d2015-06-10 08:49:22 -0700604void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800605 if (!map_.empty())
606 return;
vitauta98583d2015-06-10 08:49:22 -0700607 typedef internal::NamedArg<Char> NamedArg;
vitautfccff7b2015-06-11 07:19:00 -0700608 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700609 bool use_values =
610 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800611 if (use_values) {
612 for (unsigned i = 0;/*nothing*/; ++i) {
613 internal::Arg::Type arg_type = args.type(i);
614 switch (arg_type) {
615 case internal::Arg::NONE:
616 return;
617 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700618 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800619 map_.insert(Pair(named_arg->name, *named_arg));
620 break;
621 default:
622 /*nothing*/;
623 }
624 }
625 return;
626 }
vitauta98583d2015-06-10 08:49:22 -0700627 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800628 internal::Arg::Type arg_type = args.type(i);
629 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700630 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800631 map_.insert(Pair(named_arg->name, *named_arg));
632 }
633 }
vitauta98583d2015-06-10 08:49:22 -0700634 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800635 switch (args.args_[i].type) {
636 case internal::Arg::NONE:
637 return;
638 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700639 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
jamboree7487bde2015-06-10 09:32:59 +0800640 map_.insert(Pair(named_arg->name, *named_arg));
641 break;
642 default:
643 /*nothing*/;
644 }
645 }
646}
647
Victor Zverovichd1ded562014-09-29 08:48:16 -0700648template <typename Char>
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800649void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
650 FMT_THROW(std::runtime_error("buffer overflow"));
651}
652
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800653FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700654 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700655 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800656 switch (arg.type) {
657 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700658 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800659 break;
660 case Arg::NAMED_ARG:
661 arg = *static_cast<const internal::Arg*>(arg.pointer);
662 default:
663 /*nothing*/;
664 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700665 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700666}
667
Victor Zverovich7cae7632013-09-06 20:23:42 -0700668template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700669void fmt::internal::PrintfFormatter<Char>::parse_flags(
Victor Zverovichcb743c02014-06-19 07:40:35 -0700670 FormatSpec &spec, const Char *&s) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700671 for (;;) {
Victor Zverovich1b801482014-06-07 08:57:55 -0700672 switch (*s++) {
Victor Zverovichbf790d22014-06-07 07:31:25 -0700673 case '-':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700674 spec.align_ = ALIGN_LEFT;
675 break;
676 case '+':
Victor Zverovichbf790d22014-06-07 07:31:25 -0700677 spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
678 break;
679 case '0':
680 spec.fill_ = '0';
Victor Zverovich1b801482014-06-07 08:57:55 -0700681 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700682 case ' ':
Victor Zverovich1b801482014-06-07 08:57:55 -0700683 spec.flags_ |= SIGN_FLAG;
684 break;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700685 case '#':
Victor Zverovichcb743c02014-06-19 07:40:35 -0700686 spec.flags_ |= HASH_FLAG;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700687 break;
688 default:
Victor Zverovich1b801482014-06-07 08:57:55 -0700689 --s;
Victor Zverovichbf790d22014-06-07 07:31:25 -0700690 return;
691 }
692 }
693}
694
Victor Zverovichcb743c02014-06-19 07:40:35 -0700695template <typename Char>
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700696Arg fmt::internal::PrintfFormatter<Char>::get_arg(
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700697 const Char *s, unsigned arg_index) {
Carter Li2d4631a2015-03-14 14:54:37 +0800698 (void)s;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700699 const char *error = 0;
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700700 Arg arg = arg_index == UINT_MAX ?
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700701 next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
702 if (error)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700703 FMT_THROW(FormatError(!*s ? "invalid format string" : error));
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700704 return arg;
Victor Zverovichc57d7a52014-08-28 08:05:47 -0700705}
706
707template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700708unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
Victor Zverovichf1dfd592014-07-16 08:49:23 -0700709 const Char *&s, FormatSpec &spec) {
Victor Zverovichcb743c02014-06-19 07:40:35 -0700710 unsigned arg_index = UINT_MAX;
711 Char c = *s;
712 if (c >= '0' && c <= '9') {
713 // Parse an argument index (if followed by '$') or a width possibly
Victor Zverovich879838a2014-06-20 07:34:02 -0700714 // preceded with '0' flag(s).
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700715 unsigned value = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700716 if (*s == '$') { // value is an argument index
717 ++s;
718 arg_index = value;
719 } else {
720 if (c == '0')
721 spec.fill_ = '0';
722 if (value != 0) {
723 // Nonzero value means that we parsed width and don't need to
724 // parse it or flags again, so return now.
725 spec.width_ = value;
726 return arg_index;
727 }
728 }
729 }
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700730 parse_flags(spec, s);
Victor Zverovich4099a122014-06-23 08:10:50 -0700731 // Parse width.
Victor Zverovichcb743c02014-06-19 07:40:35 -0700732 if (*s >= '0' && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700733 spec.width_ = parse_nonnegative_int(s);
Victor Zverovichcb743c02014-06-19 07:40:35 -0700734 } else if (*s == '*') {
735 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700736 spec.width_ = WidthHandler(spec).visit(get_arg(s));
Victor Zverovichcb743c02014-06-19 07:40:35 -0700737 }
738 return arg_index;
739}
740
Victor Zverovich1f19b982014-06-16 07:49:30 -0700741template <typename Char>
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700742void fmt::internal::PrintfFormatter<Char>::format(
vitaut20003762015-07-28 08:09:29 -0700743 BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800744 const Char *start = format_str.c_str();
Victor Zverovich7cae7632013-09-06 20:23:42 -0700745 const Char *s = start;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700746 while (*s) {
Victor Zverovich0fc73162013-09-07 12:52:52 -0700747 Char c = *s++;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700748 if (c != '%') continue;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700749 if (*s == c) {
Victor Zverovichc1db2932014-07-24 08:53:27 -0700750 write(writer, start, s);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700751 start = ++s;
752 continue;
753 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700754 write(writer, start, s - 1);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700755
Victor Zverovichcb743c02014-06-19 07:40:35 -0700756 FormatSpec spec;
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700757 spec.align_ = ALIGN_RIGHT;
Victor Zverovich7cae7632013-09-06 20:23:42 -0700758
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700759 // Parse argument index, flags and width.
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700760 unsigned arg_index = parse_header(s, spec);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700761
762 // Parse precision.
763 if (*s == '.') {
764 ++s;
765 if ('0' <= *s && *s <= '9') {
Victor Zverovich526b7fc2014-08-28 06:42:59 -0700766 spec.precision_ = parse_nonnegative_int(s);
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700767 } else if (*s == '*') {
768 ++s;
Victor Zverovich56fc5252014-08-28 07:48:55 -0700769 spec.precision_ = PrecisionHandler().visit(get_arg(s));
Victor Zverovich1a75ed02014-06-23 07:16:46 -0700770 }
771 }
772
Victor Zverovich56fc5252014-08-28 07:48:55 -0700773 Arg arg = get_arg(s, arg_index);
Victor Zveroviche4c4e4e2014-07-30 06:51:35 -0700774 if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
Victor Zverovichcb743c02014-06-19 07:40:35 -0700775 spec.flags_ &= ~HASH_FLAG;
776 if (spec.fill_ == '0') {
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700777 if (arg.type <= Arg::LAST_NUMERIC_TYPE)
Victor Zverovichcb743c02014-06-19 07:40:35 -0700778 spec.align_ = ALIGN_NUMERIC;
779 else
780 spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700781 }
782
Victor Zverovichf4156b52014-07-30 08:39:07 -0700783 // Parse length and convert the argument to the required type.
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700784 switch (*s++) {
785 case 'h':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700786 if (*s == 'h')
787 ArgConverter<signed char>(arg, *++s).visit(arg);
Victor Zverovich39b09302014-07-30 08:08:08 -0700788 else
Victor Zverovichf4156b52014-07-30 08:39:07 -0700789 ArgConverter<short>(arg, *s).visit(arg);
Victor Zverovicheeca2232014-07-30 07:37:16 -0700790 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700791 case 'l':
Victor Zverovichd3a70392014-08-12 08:36:19 -0700792 if (*s == 'l')
Victor Zveroviche488a282014-08-13 06:53:43 -0700793 ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
Victor Zverovichd3a70392014-08-12 08:36:19 -0700794 else
795 ArgConverter<long>(arg, *s).visit(arg);
Victor Zverovichd81fafc2014-07-31 07:43:14 -0700796 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700797 case 'j':
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700798 ArgConverter<intmax_t>(arg, *s).visit(arg);
799 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700800 case 'z':
vitaut7dcf0512015-11-13 06:52:13 -0800801 ArgConverter<std::size_t>(arg, *s).visit(arg);
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700802 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700803 case 't':
vitaut7dcf0512015-11-13 06:52:13 -0800804 ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700805 break;
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700806 case 'L':
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700807 // printf produces garbage when 'L' is omitted for long double, no
808 // need to do the same.
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700809 break;
Victor Zverovich316ae7e2014-08-09 10:04:35 -0700810 default:
811 --s;
Victor Zverovichbe00d8b2014-08-19 08:49:10 -0700812 ArgConverter<int>(arg, *s).visit(arg);
Victor Zverovichea99bfb2014-06-24 07:54:26 -0700813 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700814
815 // Parse type.
816 if (!*s)
Victor Zverovich8b76e972014-10-06 08:30:55 -0700817 FMT_THROW(FormatError("invalid format string"));
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700818 spec.type_ = static_cast<char>(*s++);
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700819 if (arg.type <= Arg::LAST_INTEGER_TYPE) {
820 // Normalize type.
821 switch (spec.type_) {
822 case 'i': case 'u':
Victor Zverovichf4156b52014-07-30 08:39:07 -0700823 spec.type_ = 'd';
Victor Zverovichc4a4a052014-08-19 08:14:21 -0700824 break;
825 case 'c':
826 // TODO: handle wchar_t
827 CharConverter(arg).visit(arg);
828 break;
829 }
Victor Zverovichf4156b52014-07-30 08:39:07 -0700830 }
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700831
832 start = s;
833
834 // Format argument.
vitaut270069b2015-06-16 07:36:32 -0700835 internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700836 }
Victor Zverovichc1db2932014-07-24 08:53:27 -0700837 write(writer, start, s);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700838}
839
Victor Zverovichd9c605c2014-11-28 06:40:57 -0800840FMT_FUNC void fmt::report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800841 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800842 // 'fmt::' is for bcc32.
843 fmt::report_error(internal::format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700844}
845
vitaut24c309f2015-06-12 07:15:57 -0700846#if FMT_USE_WINDOWS_H
Victor Zverovichb49a1b42014-12-09 06:32:07 -0800847FMT_FUNC void fmt::report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800848 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800849 // 'fmt::' is for bcc32.
850 fmt::report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700851}
Victor Zverovich400812a2014-04-30 12:38:17 -0700852#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700853
vitaut438bd9b2015-06-26 07:43:54 -0700854FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700855 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -0700856 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700857 std::fwrite(w.data(), 1, w.size(), f);
858}
859
vitaut438bd9b2015-06-26 07:43:54 -0700860FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -0700861 print(stdout, format_str, args);
862}
863
vitaut438bd9b2015-06-26 07:43:54 -0700864FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700865 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -0700866 w.write(format_str, args);
Victor Zveroviche3a44c12014-07-09 06:56:36 -0700867 os.write(w.data(), w.size());
868}
869
vitaut438bd9b2015-06-26 07:43:54 -0700870FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700871 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100872 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700873 std::fputs(escape, stdout);
874 print(format, args);
875 std::fputs(RESET_COLOR, stdout);
876}
877
vitaut438bd9b2015-06-26 07:43:54 -0700878FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700879 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -0700880 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -0800881 std::size_t size = w.size();
882 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700883}
884
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800885#ifndef FMT_HEADER_ONLY
886
vitaut9ca1ce22015-05-23 08:04:06 -0700887template struct fmt::internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -0700888
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700889// Explicit instantiations for char.
890
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800891template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
892
vitaut535dbdd2015-12-03 09:38:06 -0800893template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700894
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700895template void fmt::internal::PrintfFormatter<char>::format(
vitaut20003762015-07-28 08:09:29 -0700896 BasicWriter<char> &writer, CStringRef format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700897
Victor Zverovich14f25772014-09-19 08:45:05 -0700898template int fmt::internal::CharTraits<char>::format_float(
899 char *buffer, std::size_t size, const char *format,
900 unsigned width, int precision, double value);
901
902template int fmt::internal::CharTraits<char>::format_float(
903 char *buffer, std::size_t size, const char *format,
904 unsigned width, int precision, long double value);
905
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700906// Explicit instantiations for wchar_t.
907
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800908template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
909
vitaut535dbdd2015-12-03 09:38:06 -0800910template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700911
Victor Zverovich4d049cf2014-07-28 08:41:50 -0700912template void fmt::internal::PrintfFormatter<wchar_t>::format(
vitaut20003762015-07-28 08:09:29 -0700913 BasicWriter<wchar_t> &writer, WCStringRef format);
jdale88a9862fd2014-03-11 18:56:24 +0000914
Victor Zverovich14f25772014-09-19 08:45:05 -0700915template int fmt::internal::CharTraits<wchar_t>::format_float(
916 wchar_t *buffer, std::size_t size, const wchar_t *format,
917 unsigned width, int precision, double value);
918
919template int fmt::internal::CharTraits<wchar_t>::format_float(
920 wchar_t *buffer, std::size_t size, const wchar_t *format,
921 unsigned width, int precision, long double value);
922
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800923#endif // FMT_HEADER_ONLY
924
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100925#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000926# pragma warning(pop)
927#endif