blob: 222cc71f0f7d0b2815d6a171882c6a6c72c406fe [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 Zverovich8b76e972014-10-06 08:30:55 -070054#if FMT_EXCEPTIONS
55# define FMT_TRY try
56# define FMT_CATCH(x) catch (x)
57#else
58# define FMT_TRY if (true)
59# define FMT_CATCH(x) if (false)
60#endif
61
Ingo van Lilb4b13ee2015-11-02 12:34:46 +010062#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +000063# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070064# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050065# pragma warning(disable: 4702) // unreachable code
vitautdf47d812015-03-16 18:53:14 -070066// Disable deprecation warning for strerror. The latter is not called but
67// MSVC fails to detect it.
68# pragma warning(disable: 4996)
jdale88a9862fd2014-03-11 18:56:24 +000069#endif
70
vitaut341b98c2015-03-14 13:39:33 -070071// Dummy implementations of strerror_r and strerror_s called if corresponding
72// system functions are not available.
vitautc669cbe2015-07-07 07:05:17 -070073static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
74 return fmt::internal::Null<>();
vitaut341b98c2015-03-14 13:39:33 -070075}
vitautc669cbe2015-07-07 07:05:17 -070076static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
77 return fmt::internal::Null<>();
vitaut341b98c2015-03-14 13:39:33 -070078}
79
vitaut8725d072015-06-12 07:56:58 -070080namespace fmt {
Victor Zverovichb26e76e2016-06-14 08:11:33 -070081
82FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {}
Victor Zverovich9bb213e2016-08-25 08:38:07 -070083FMT_FUNC format_error::~format_error() throw() {}
Victor Zverovichb26e76e2016-06-14 08:11:33 -070084FMT_FUNC SystemError::~SystemError() throw() {}
85
Victor Zverovich9ff3b972013-09-07 10:15:08 -070086namespace {
87
88#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070089# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080090#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070091inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080092 va_list args;
93 va_start(args, format);
94 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
95 va_end(args);
96 return result;
97}
Victor Zverovichb9a568b2014-09-19 07:51:42 -070098# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -070099#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -0800100
cstamford55836ca2015-03-10 07:04:31 +0000101#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
102# define FMT_SWPRINTF snwprintf
103#else
104# define FMT_SWPRINTF swprintf
105#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
106
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800107const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700108
Victor Zverovichfefaf072017-02-14 16:29:47 -0500109typedef void (*FormatFunc)(buffer &, int, StringRef);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700110
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700111// Portable thread-safe version of strerror.
112// Sets buffer to point to a string describing the error code.
113// This can be either a pointer to a string stored in buffer,
114// or a pointer to some static immutable string.
115// Returns one of the following values:
116// 0 - success
117// ERANGE - buffer is not large enough to store the error message
118// other - failure
119// Buffer should be at least of size 1.
120int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800121 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
vitaut8ab665a2015-06-22 08:17:23 -0700122 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700123
vitaut341b98c2015-03-14 13:39:33 -0700124 class StrError {
125 private:
126 int error_code_;
127 char *&buffer_;
128 std::size_t buffer_size_;
129
vitautda052ae2015-03-21 07:53:39 -0700130 // A noop assignment operator to avoid bogus warnings.
131 void operator=(const StrError &) {}
132
vitaut341b98c2015-03-14 13:39:33 -0700133 // Handle the result of XSI-compliant version of strerror_r.
134 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700135 // glibc versions before 2.13 return result in errno.
136 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700137 }
138
139 // Handle the result of GNU-specific version of strerror_r.
140 int handle(char *message) {
141 // If the buffer is full then the message is probably truncated.
142 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
143 return ERANGE;
144 buffer_ = message;
145 return 0;
146 }
147
148 // Handle the case when strerror_r is not available.
vitautbfdca8b2016-04-20 09:11:33 -0700149 int handle(internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700150 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
151 }
152
153 // Fallback to strerror_s when strerror_r is not available.
154 int fallback(int result) {
155 // If the buffer is full then the message is probably truncated.
156 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
157 ERANGE : result;
158 }
159
160 // Fallback to strerror if strerror_r and strerror_s are not available.
vitautbfdca8b2016-04-20 09:11:33 -0700161 int fallback(internal::Null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700162 errno = 0;
163 buffer_ = strerror(error_code_);
164 return errno;
165 }
166
167 public:
Radu Popescu0affb232015-08-04 12:52:44 +0200168 StrError(int err_code, char *&buf, std::size_t buf_size)
169 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
vitaut341b98c2015-03-14 13:39:33 -0700170
vitaut63f6c102015-06-14 09:36:23 -0700171 int run() {
172 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
173 return handle(strerror_r(error_code_, buffer_, buffer_size_));
174 }
vitaut341b98c2015-03-14 13:39:33 -0700175 };
176 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700177}
178
Victor Zverovichfefaf072017-02-14 16:29:47 -0500179void format_error_code(buffer &out, int error_code,
vitautbfdca8b2016-04-20 09:11:33 -0700180 StringRef message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700181 // Report error code making sure that the output fits into
182 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
183 // bad_alloc.
184 out.clear();
185 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700186 static const char ERROR_STR[] = "error ";
vitaut1addec92015-03-21 20:16:36 -0700187 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
188 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
vitautbfdca8b2016-04-20 09:11:33 -0700189 typedef internal::IntTraits<int>::MainType MainType;
vitaut9d577ca2016-03-02 07:01:21 -0800190 MainType abs_value = static_cast<MainType>(error_code);
191 if (internal::is_negative(error_code)) {
192 abs_value = 0 - abs_value;
193 ++error_code_size;
194 }
vitautbfdca8b2016-04-20 09:11:33 -0700195 error_code_size += internal::count_digits(abs_value);
Victor Zverovichfefaf072017-02-14 16:29:47 -0500196 basic_writer<char> w(out);
Victor Zverovichec15ef72017-01-22 07:40:21 -0800197 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500198 w.write(message);
199 w.write(SEP);
Victor Zverovichec15ef72017-01-22 07:40:21 -0800200 }
Victor Zverovichfefaf072017-02-14 16:29:47 -0500201 w.write(ERROR_STR);
202 w.write(error_code);
vitautbfdca8b2016-04-20 09:11:33 -0700203 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700204}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700205
vitautbfdca8b2016-04-20 09:11:33 -0700206void report_error(FormatFunc func, int error_code,
207 StringRef message) FMT_NOEXCEPT {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500208 internal::MemoryBuffer<char> full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700209 func(full_message, error_code, message);
210 // Use Writer::data instead of Writer::c_str to avoid potential memory
211 // allocation.
212 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
213 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700214}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700215} // namespace
vitaut270069b2015-06-16 07:36:32 -0700216
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700217FMT_FUNC void SystemError::init(
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800218 int err_code, CStringRef format_str, args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800219 error_code_ = err_code;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500220 internal::MemoryBuffer<char> buf;
221 format_system_error(buf, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700222 std::runtime_error &base = *this;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500223 base = std::runtime_error(to_string(buf));
Victor Zverovich53201032014-06-30 14:26:29 -0700224}
225
Victor Zverovichb605b392013-09-09 22:21:40 -0700226template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700227int internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700228 char *buffer, std::size_t size, const char *format,
229 unsigned width, int precision, T value) {
230 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700231 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700232 FMT_SNPRINTF(buffer, size, format, value) :
233 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700234 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700235 return precision < 0 ?
236 FMT_SNPRINTF(buffer, size, format, width, value) :
237 FMT_SNPRINTF(buffer, size, format, width, precision, value);
238}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700239
Victor Zverovichb605b392013-09-09 22:21:40 -0700240template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700241int internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700242 wchar_t *buffer, std::size_t size, const wchar_t *format,
243 unsigned width, int precision, T value) {
244 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700245 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000246 FMT_SWPRINTF(buffer, size, format, value) :
247 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700248 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700249 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000250 FMT_SWPRINTF(buffer, size, format, width, value) :
251 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700252}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800253
Victor Zverovich311251e2014-11-29 06:58:00 -0800254template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700255const char internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800256 "0001020304050607080910111213141516171819"
257 "2021222324252627282930313233343536373839"
258 "4041424344454647484950515253545556575859"
259 "6061626364656667686970717273747576777879"
260 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800261
Victor Zverovichf1d85162014-02-19 13:02:22 -0800262#define FMT_POWERS_OF_10(factor) \
263 factor * 10, \
264 factor * 100, \
265 factor * 1000, \
266 factor * 10000, \
267 factor * 100000, \
268 factor * 1000000, \
269 factor * 10000000, \
270 factor * 100000000, \
271 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800272
Victor Zverovich311251e2014-11-29 06:58:00 -0800273template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700274const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800275 0, FMT_POWERS_OF_10(1)
276};
277
278template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700279const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800280 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800281 FMT_POWERS_OF_10(1),
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700282 FMT_POWERS_OF_10(ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700283 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800284 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700285 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800286};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800287
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700288FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800289 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800290 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700291 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700292 format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800293 }
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700294 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700295 format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700296 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800297}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700298
vitaut24c309f2015-06-12 07:15:57 -0700299#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700300
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700301FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800302 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700303 if (s.size() > INT_MAX)
304 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
305 int s_size = static_cast<int>(s.size());
306 int length = MultiByteToWideChar(
307 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700308 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800309 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700310 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700311 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700312 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700313 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800314 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700315 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700316}
317
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700318FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700319 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700320 FMT_THROW(WindowsError(error_code,
321 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700322 }
323}
324
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700325FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700326 if (s.size() > INT_MAX)
327 return ERROR_INVALID_PARAMETER;
328 int s_size = static_cast<int>(s.size());
329 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700330 if (length == 0)
331 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700332 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700333 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700334 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700335 if (length == 0)
336 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700337 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700338 return 0;
339}
340
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700341FMT_FUNC void WindowsError::init(
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800342 int err_code, CStringRef format_str, args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800343 error_code_ = err_code;
Victor Zveroviche022c212017-02-17 06:38:53 -0800344 internal::MemoryBuffer<char> buffer;
345 internal::format_windows_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700346 std::runtime_error &base = *this;
Victor Zveroviche022c212017-02-17 06:38:53 -0800347 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700348}
349
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700350FMT_FUNC void internal::format_windows_error(
Victor Zveroviche022c212017-02-17 06:38:53 -0800351 buffer &out, int error_code, StringRef message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700352 FMT_TRY {
Victor Zveroviche022c212017-02-17 06:38:53 -0800353 MemoryBuffer<wchar_t> buffer;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800354 buffer.resize(INLINE_BUFFER_SIZE);
355 for (;;) {
356 wchar_t *system_message = &buffer[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700357 int result = FormatMessageW(
358 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
359 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
360 system_message, static_cast<uint32_t>(buffer.size()), 0);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800361 if (result != 0) {
362 UTF16ToUTF8 utf8_message;
363 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zveroviche022c212017-02-17 06:38:53 -0800364 basic_writer<char> w(out);
365 w.write(message);
366 w.write(": ");
367 w.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800368 return;
369 }
370 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700371 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800372 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
373 break; // Can't get error message, report error code instead.
374 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700375 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700376 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800377 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700378}
vitaut24c309f2015-06-12 07:15:57 -0700379
380#endif // FMT_USE_WINDOWS_H
381
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700382FMT_FUNC void format_system_error(
Victor Zverovichfefaf072017-02-14 16:29:47 -0500383 buffer &out, int error_code, StringRef message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700384 FMT_TRY {
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600385 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
386 buffer.resize(internal::INLINE_BUFFER_SIZE);
vitaut24c309f2015-06-12 07:15:57 -0700387 for (;;) {
388 char *system_message = &buffer[0];
389 int result = safe_strerror(error_code, system_message, buffer.size());
390 if (result == 0) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500391 basic_writer<char> w(out);
392 w.write(message);
393 w.write(": ");
394 w.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700395 return;
396 }
397 if (result != ERANGE)
398 break; // Can't get error message, report error code instead.
399 buffer.resize(buffer.size() * 2);
400 }
401 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800402 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
vitaut24c309f2015-06-12 07:15:57 -0700403}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700404
jamboree7487bde2015-06-10 09:32:59 +0800405template <typename Char>
Victor Zverovichfefaf072017-02-14 16:29:47 -0500406void FixedBuffer<Char>::grow(std::size_t) {
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800407 FMT_THROW(std::runtime_error("buffer overflow"));
408}
409
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700410FMT_FUNC void report_system_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800411 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800412 // 'fmt::' is for bcc32.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700413 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700414}
415
vitaut24c309f2015-06-12 07:15:57 -0700416#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700417FMT_FUNC void report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800418 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800419 // 'fmt::' is for bcc32.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700420 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700421}
Victor Zverovich400812a2014-04-30 12:38:17 -0700422#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700423
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800424FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, args args) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500425 internal::MemoryBuffer<char> buffer;
426 vformat_to(buffer, format_str, args);
427 std::fwrite(buffer.data(), 1, buffer.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700428}
429
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800430FMT_FUNC void vprint(CStringRef format_str, args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700431 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700432}
433
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800434FMT_FUNC void vprint_colored(Color c, CStringRef format, args args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700435 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100436 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700437 std::fputs(escape, stdout);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700438 vprint(format, args);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700439 std::fputs(RESET_COLOR, stdout);
440}
441
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700442template <typename Char>
Victor Zverovich84286212016-12-30 12:11:27 -0800443void printf(basic_writer<Char> &w, BasicCStringRef<Char> format,
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800444 args args);
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700445
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800446FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500447 internal::MemoryBuffer<char> buffer;
448 printf(buffer, format, args);
449 std::size_t size = buffer.size();
450 return std::fwrite(
451 buffer.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700452}
453
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800454#ifndef FMT_HEADER_ONLY
455
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700456template struct internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -0700457
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700458// Explicit instantiations for char.
459
Victor Zverovichfefaf072017-02-14 16:29:47 -0500460template void FixedBuffer<char>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800461
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800462template void internal::ArgMap<context>::init(const args &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700463
Victor Zverovichfefaf072017-02-14 16:29:47 -0500464template void printf_context<char>::format(buffer &);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700465
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700466template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700467 char *buffer, std::size_t size, const char *format,
468 unsigned width, int precision, double value);
469
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700470template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700471 char *buffer, std::size_t size, const char *format,
472 unsigned width, int precision, long double value);
473
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700474// Explicit instantiations for wchar_t.
475
Victor Zverovich624c5862017-02-05 06:41:39 -0800476template class basic_context<wchar_t>;
Victor Zverovichd705d512016-12-29 09:07:39 -0800477
Victor Zverovichfefaf072017-02-14 16:29:47 -0500478template void FixedBuffer<wchar_t>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800479
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800480template void internal::ArgMap<wcontext>::init(const wargs &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700481
Victor Zverovichfefaf072017-02-14 16:29:47 -0500482template void printf_context<wchar_t>::format(wbuffer &);
jdale88a9862fd2014-03-11 18:56:24 +0000483
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700484template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700485 wchar_t *buffer, std::size_t size, const wchar_t *format,
486 unsigned width, int precision, double value);
487
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700488template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700489 wchar_t *buffer, std::size_t size, const wchar_t *format,
490 unsigned width, int precision, long double value);
491
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800492#endif // FMT_HEADER_ONLY
493
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700494} // namespace fmt
495
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100496#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000497# pragma warning(pop)
498#endif