blob: 7fd0308e5b06949e11c09ed4a26b1dc27e478722 [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 Zverovich408c84c2016-05-04 06:27:03 -07004 Copyright (c) 2012 - 2016, 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 Zveroviche160c2b2016-05-22 16:07:50 -070028#include "fmt/format.h"
Glen Stark72d51e02016-06-08 01:23:32 +020029#include "fmt/printf.h"
Victor Zverovichfbfedcf2013-01-14 15:16:20 -080030
Victor Zverovich859a4972014-04-30 06:55:21 -070031#include <string.h>
32
Victor Zverovich72f896d2012-12-12 09:17:28 -080033#include <cctype>
Victor Zverovich5d15bdd2014-07-01 16:23:50 -070034#include <cerrno>
Victor Zverovichf28645f2014-04-24 12:37:06 -070035#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070036#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080037#include <cstdarg>
vitaut7dcf0512015-11-13 06:52:13 -080038#include <cstddef> // for std::ptrdiff_t
Victor Zverovich9ff3b972013-09-07 10:15:08 -070039
vitaut24c309f2015-06-12 07:15:57 -070040#if defined(_WIN32) && defined(__MINGW32__)
41# include <cstring>
42#endif
43
44#if FMT_USE_WINDOWS_H
vitaut67ce3942015-04-30 07:48:36 -070045# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
46# include <windows.h>
47# else
48# define NOMINMAX
49# include <windows.h>
50# undef NOMINMAX
51# endif
Ryuuke5a9dc8f2015-02-08 16:08:29 +000052#endif
53
Victor Zverovich6e5551e2014-07-02 06:33:25 -070054using fmt::internal::Arg;
Victor Zverovich447e02c2014-02-15 10:48:34 -080055
Victor Zverovich8b76e972014-10-06 08:30:55 -070056#if FMT_EXCEPTIONS
57# define FMT_TRY try
58# define FMT_CATCH(x) catch (x)
59#else
60# define FMT_TRY if (true)
61# define FMT_CATCH(x) if (false)
62#endif
63
Ingo van Lilb4b13ee2015-11-02 12:34:46 +010064#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +000065# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070066# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050067# pragma warning(disable: 4702) // unreachable code
vitautdf47d812015-03-16 18:53:14 -070068// Disable deprecation warning for strerror. The latter is not called but
69// MSVC fails to detect it.
70# pragma warning(disable: 4996)
jdale88a9862fd2014-03-11 18:56:24 +000071#endif
72
vitaut341b98c2015-03-14 13:39:33 -070073// Dummy implementations of strerror_r and strerror_s called if corresponding
74// system functions are not available.
vitautc669cbe2015-07-07 07:05:17 -070075static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
76 return fmt::internal::Null<>();
vitaut341b98c2015-03-14 13:39:33 -070077}
vitautc669cbe2015-07-07 07:05:17 -070078static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
79 return fmt::internal::Null<>();
vitaut341b98c2015-03-14 13:39:33 -070080}
81
vitaut8725d072015-06-12 07:56:58 -070082namespace fmt {
Victor Zverovichb26e76e2016-06-14 08:11:33 -070083
84FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {}
Victor Zverovich9bb213e2016-08-25 08:38:07 -070085FMT_FUNC format_error::~format_error() throw() {}
Victor Zverovichb26e76e2016-06-14 08:11:33 -070086FMT_FUNC SystemError::~SystemError() throw() {}
87
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 Zverovich7004d1e2015-02-08 19:54:39 -0800109const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700110
vitautbfdca8b2016-04-20 09:11:33 -0700111typedef void (*FormatFunc)(Writer &, int, StringRef);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700112
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700113// Portable thread-safe version of strerror.
114// Sets buffer to point to a string describing the error code.
115// This can be either a pointer to a string stored in buffer,
116// or a pointer to some static immutable string.
117// Returns one of the following values:
118// 0 - success
119// ERANGE - buffer is not large enough to store the error message
120// other - failure
121// Buffer should be at least of size 1.
122int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800123 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
vitaut8ab665a2015-06-22 08:17:23 -0700124 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700125
vitaut341b98c2015-03-14 13:39:33 -0700126 class StrError {
127 private:
128 int error_code_;
129 char *&buffer_;
130 std::size_t buffer_size_;
131
vitautda052ae2015-03-21 07:53:39 -0700132 // A noop assignment operator to avoid bogus warnings.
133 void operator=(const StrError &) {}
134
vitaut341b98c2015-03-14 13:39:33 -0700135 // Handle the result of XSI-compliant version of strerror_r.
136 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700137 // glibc versions before 2.13 return result in errno.
138 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700139 }
140
141 // Handle the result of GNU-specific version of strerror_r.
142 int handle(char *message) {
143 // If the buffer is full then the message is probably truncated.
144 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
145 return ERANGE;
146 buffer_ = message;
147 return 0;
148 }
149
150 // Handle the case when strerror_r is not available.
vitautbfdca8b2016-04-20 09:11:33 -0700151 int handle(internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700152 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
153 }
154
155 // Fallback to strerror_s when strerror_r is not available.
156 int fallback(int result) {
157 // If the buffer is full then the message is probably truncated.
158 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
159 ERANGE : result;
160 }
161
162 // Fallback to strerror if strerror_r and strerror_s are not available.
vitautbfdca8b2016-04-20 09:11:33 -0700163 int fallback(internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700164 errno = 0;
165 buffer_ = strerror(error_code_);
166 return errno;
167 }
168
169 public:
Radu Popescu0affb232015-08-04 12:52:44 +0200170 StrError(int err_code, char *&buf, std::size_t buf_size)
171 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
vitaut341b98c2015-03-14 13:39:33 -0700172
vitaut63f6c102015-06-14 09:36:23 -0700173 int run() {
174 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
175 return handle(strerror_r(error_code_, buffer_, buffer_size_));
176 }
vitaut341b98c2015-03-14 13:39:33 -0700177 };
178 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700179}
180
vitautbfdca8b2016-04-20 09:11:33 -0700181void format_error_code(Writer &out, int error_code,
182 StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700183 // Report error code making sure that the output fits into
184 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
185 // bad_alloc.
186 out.clear();
187 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700188 static const char ERROR_STR[] = "error ";
vitaut1addec92015-03-21 20:16:36 -0700189 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
190 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
vitautbfdca8b2016-04-20 09:11:33 -0700191 typedef internal::IntTraits<int>::MainType MainType;
vitaut9d577ca2016-03-02 07:01:21 -0800192 MainType abs_value = static_cast<MainType>(error_code);
193 if (internal::is_negative(error_code)) {
194 abs_value = 0 - abs_value;
195 ++error_code_size;
196 }
vitautbfdca8b2016-04-20 09:11:33 -0700197 error_code_size += internal::count_digits(abs_value);
198 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700199 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700200 out << ERROR_STR << error_code;
vitautbfdca8b2016-04-20 09:11:33 -0700201 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700202}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700203
vitautbfdca8b2016-04-20 09:11:33 -0700204void report_error(FormatFunc func, int error_code,
205 StringRef message) FMT_NOEXCEPT {
206 MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700207 func(full_message, error_code, message);
208 // Use Writer::data instead of Writer::c_str to avoid potential memory
209 // allocation.
210 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
211 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700212}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700213} // namespace
vitaut270069b2015-06-16 07:36:32 -0700214
215namespace internal {
216
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600217// This method is used to preserve binary compatibility with fmt 3.0.
218// It can be removed in 4.0.
219FMT_FUNC void format_system_error(
220 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
221 fmt::format_system_error(out, error_code, message);
222}
vitaut270069b2015-06-16 07:36:32 -0700223} // namespace internal
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700224
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700225FMT_FUNC void SystemError::init(
vitaut438bd9b2015-06-26 07:43:54 -0700226 int err_code, CStringRef format_str, ArgList args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800227 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700228 MemoryWriter w;
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600229 format_system_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700230 std::runtime_error &base = *this;
231 base = std::runtime_error(w.str());
232}
233
Victor Zverovichb605b392013-09-09 22:21:40 -0700234template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700235int internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700236 char *buffer, std::size_t size, const char *format,
237 unsigned width, int precision, T value) {
238 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700239 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700240 FMT_SNPRINTF(buffer, size, format, value) :
241 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700242 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700243 return precision < 0 ?
244 FMT_SNPRINTF(buffer, size, format, width, value) :
245 FMT_SNPRINTF(buffer, size, format, width, precision, value);
246}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700247
Victor Zverovichb605b392013-09-09 22:21:40 -0700248template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700249int internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700250 wchar_t *buffer, std::size_t size, const wchar_t *format,
251 unsigned width, int precision, T value) {
252 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700253 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000254 FMT_SWPRINTF(buffer, size, format, value) :
255 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700256 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700257 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000258 FMT_SWPRINTF(buffer, size, format, width, value) :
259 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700260}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800261
Victor Zverovich311251e2014-11-29 06:58:00 -0800262template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700263const char internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800264 "0001020304050607080910111213141516171819"
265 "2021222324252627282930313233343536373839"
266 "4041424344454647484950515253545556575859"
267 "6061626364656667686970717273747576777879"
268 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800269
Victor Zverovichf1d85162014-02-19 13:02:22 -0800270#define FMT_POWERS_OF_10(factor) \
271 factor * 10, \
272 factor * 100, \
273 factor * 1000, \
274 factor * 10000, \
275 factor * 100000, \
276 factor * 1000000, \
277 factor * 10000000, \
278 factor * 100000000, \
279 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800280
Victor Zverovich311251e2014-11-29 06:58:00 -0800281template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700282const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800283 0, FMT_POWERS_OF_10(1)
284};
285
286template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700287const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800288 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800289 FMT_POWERS_OF_10(1),
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700290 FMT_POWERS_OF_10(ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700291 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800292 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700293 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800294};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800295
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700296FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800297 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800298 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700299 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700300 format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800301 }
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700302 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700303 format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700304 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800305}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700306
vitaut24c309f2015-06-12 07:15:57 -0700307#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700308
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700309FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800310 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700311 if (s.size() > INT_MAX)
312 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
313 int s_size = static_cast<int>(s.size());
314 int length = MultiByteToWideChar(
315 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700316 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800317 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700318 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700319 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700320 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700321 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800322 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700323 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700324}
325
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700326FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700327 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700328 FMT_THROW(WindowsError(error_code,
329 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700330 }
331}
332
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700333FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700334 if (s.size() > INT_MAX)
335 return ERROR_INVALID_PARAMETER;
336 int s_size = static_cast<int>(s.size());
337 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700338 if (length == 0)
339 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700340 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700341 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700342 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700343 if (length == 0)
344 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700345 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700346 return 0;
347}
348
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700349FMT_FUNC void WindowsError::init(
vitautba09c1b2015-06-26 09:23:11 -0700350 int err_code, CStringRef format_str, ArgList args) {
Carter Li3f574c12015-02-17 10:11:42 +0800351 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700352 MemoryWriter w;
Carter Li3f574c12015-02-17 10:11:42 +0800353 internal::format_windows_error(w, err_code, format(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700354 std::runtime_error &base = *this;
355 base = std::runtime_error(w.str());
356}
357
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700358FMT_FUNC void internal::format_windows_error(
359 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700360 FMT_TRY {
Michael Winterberg2a05a872016-03-02 17:35:34 -0800361 MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
362 buffer.resize(INLINE_BUFFER_SIZE);
363 for (;;) {
364 wchar_t *system_message = &buffer[0];
365 int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
366 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
367 system_message, static_cast<uint32_t>(buffer.size()), 0);
368 if (result != 0) {
369 UTF16ToUTF8 utf8_message;
370 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
371 out << message << ": " << utf8_message;
372 return;
373 }
374 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700375 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800376 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
377 break; // Can't get error message, report error code instead.
378 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700379 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700380 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800381 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700382}
vitaut24c309f2015-06-12 07:15:57 -0700383
384#endif // FMT_USE_WINDOWS_H
385
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700386FMT_FUNC void format_system_error(
387 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700388 FMT_TRY {
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600389 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
390 buffer.resize(internal::INLINE_BUFFER_SIZE);
vitaut24c309f2015-06-12 07:15:57 -0700391 for (;;) {
392 char *system_message = &buffer[0];
393 int result = safe_strerror(error_code, system_message, buffer.size());
394 if (result == 0) {
395 out << message << ": " << system_message;
396 return;
397 }
398 if (result != ERANGE)
399 break; // Can't get error message, report error code instead.
400 buffer.resize(buffer.size() * 2);
401 }
402 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800403 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
vitaut24c309f2015-06-12 07:15:57 -0700404}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700405
jamboree7487bde2015-06-10 09:32:59 +0800406template <typename Char>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700407void internal::ArgMap<Char>::init(const ArgList &args) {
jamboree7487bde2015-06-10 09:32:59 +0800408 if (!map_.empty())
409 return;
vitauta98583d2015-06-10 08:49:22 -0700410 typedef internal::NamedArg<Char> NamedArg;
vitautfccff7b2015-06-11 07:19:00 -0700411 const NamedArg *named_arg = 0;
vitauta98583d2015-06-10 08:49:22 -0700412 bool use_values =
413 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
jamboree7487bde2015-06-10 09:32:59 +0800414 if (use_values) {
415 for (unsigned i = 0;/*nothing*/; ++i) {
416 internal::Arg::Type arg_type = args.type(i);
417 switch (arg_type) {
418 case internal::Arg::NONE:
419 return;
420 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700421 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800422 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800423 break;
424 default:
425 /*nothing*/;
426 }
427 }
428 return;
429 }
vitauta98583d2015-06-10 08:49:22 -0700430 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800431 internal::Arg::Type arg_type = args.type(i);
432 if (arg_type == internal::Arg::NAMED_ARG) {
vitauta98583d2015-06-10 08:49:22 -0700433 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800434 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800435 }
436 }
vitauta98583d2015-06-10 08:49:22 -0700437 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
jamboree7487bde2015-06-10 09:32:59 +0800438 switch (args.args_[i].type) {
439 case internal::Arg::NONE:
440 return;
441 case internal::Arg::NAMED_ARG:
vitauta98583d2015-06-10 08:49:22 -0700442 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
Michael Winterberg4af764d2016-01-10 15:30:34 -0800443 map_.push_back(Pair(named_arg->name, *named_arg));
jamboree7487bde2015-06-10 09:32:59 +0800444 break;
445 default:
446 /*nothing*/;
447 }
448 }
449}
450
Victor Zverovichd1ded562014-09-29 08:48:16 -0700451template <typename Char>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700452void internal::FixedBuffer<Char>::grow(std::size_t) {
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800453 FMT_THROW(std::runtime_error("buffer overflow"));
454}
455
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700456FMT_FUNC Arg internal::FormatterBase::do_get_arg(
Victor Zverovich605d2602014-08-29 07:45:55 -0700457 unsigned arg_index, const char *&error) {
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700458 Arg arg = args_[arg_index];
jamboree7487bde2015-06-10 09:32:59 +0800459 switch (arg.type) {
460 case Arg::NONE:
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700461 error = "argument index out of range";
jamboree7487bde2015-06-10 09:32:59 +0800462 break;
463 case Arg::NAMED_ARG:
464 arg = *static_cast<const internal::Arg*>(arg.pointer);
Patrik Weiskircher6178bc62016-02-23 12:59:26 -0500465 break;
jamboree7487bde2015-06-10 09:32:59 +0800466 default:
467 /*nothing*/;
468 }
Victor Zverovichbeb00ed2014-09-23 07:59:43 -0700469 return arg;
Victor Zverovich4edc88f2014-07-16 08:38:15 -0700470}
471
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700472FMT_FUNC void report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800473 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800474 // 'fmt::' is for bcc32.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700475 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700476}
477
vitaut24c309f2015-06-12 07:15:57 -0700478#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700479FMT_FUNC void report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800480 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800481 // 'fmt::' is for bcc32.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700482 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700483}
Victor Zverovich400812a2014-04-30 12:38:17 -0700484#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700485
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700486FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700487 MemoryWriter w;
Victor Zverovichdd4323f2014-08-21 08:49:13 -0700488 w.write(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700489 std::fwrite(w.data(), 1, w.size(), f);
490}
491
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700492FMT_FUNC void print(CStringRef format_str, ArgList args) {
Victor Zverovich163178e2014-09-25 07:08:25 -0700493 print(stdout, format_str, args);
494}
495
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700496FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700497 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100498 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700499 std::fputs(escape, stdout);
500 print(format, args);
501 std::fputs(RESET_COLOR, stdout);
502}
503
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700504template <typename Char>
505void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args);
506
507FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700508 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -0700509 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -0800510 std::size_t size = w.size();
511 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700512}
513
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800514#ifndef FMT_HEADER_ONLY
515
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700516template struct internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -0700517
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700518// Explicit instantiations for char.
519
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700520template void internal::FixedBuffer<char>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800521
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700522template void internal::ArgMap<char>::init(const ArgList &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700523
Victor Zverovichab054532016-07-20 08:21:13 -0700524template void PrintfFormatter<char>::format(CStringRef format);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700525
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700526template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700527 char *buffer, std::size_t size, const char *format,
528 unsigned width, int precision, double value);
529
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700530template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700531 char *buffer, std::size_t size, const char *format,
532 unsigned width, int precision, long double value);
533
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700534// Explicit instantiations for wchar_t.
535
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700536template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800537
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700538template void internal::ArgMap<wchar_t>::init(const ArgList &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700539
Victor Zverovichab054532016-07-20 08:21:13 -0700540template void PrintfFormatter<wchar_t>::format(WCStringRef format);
jdale88a9862fd2014-03-11 18:56:24 +0000541
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700542template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700543 wchar_t *buffer, std::size_t size, const wchar_t *format,
544 unsigned width, int precision, double value);
545
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700546template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700547 wchar_t *buffer, std::size_t size, const wchar_t *format,
548 unsigned width, int precision, long double value);
549
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800550#endif // FMT_HEADER_ONLY
551
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700552} // namespace fmt
553
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100554#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000555# pragma warning(pop)
556#endif