blob: 92479615acafa9845415ae91dff3b0cd843a22bc [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
vitautbfdca8b2016-04-20 09:11:33 -0700109typedef void (*FormatFunc)(Writer &, 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
vitautbfdca8b2016-04-20 09:11:33 -0700179void format_error_code(Writer &out, int error_code,
180 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);
196 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
Victor Zverovich22f75d82014-09-03 08:03:05 -0700197 out << message << SEP;
vitaut1addec92015-03-21 20:16:36 -0700198 out << ERROR_STR << error_code;
vitautbfdca8b2016-04-20 09:11:33 -0700199 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700200}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700201
vitautbfdca8b2016-04-20 09:11:33 -0700202void report_error(FormatFunc func, int error_code,
203 StringRef message) FMT_NOEXCEPT {
204 MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700205 func(full_message, error_code, message);
206 // Use Writer::data instead of Writer::c_str to avoid potential memory
207 // allocation.
208 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
209 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700210}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700211} // namespace
vitaut270069b2015-06-16 07:36:32 -0700212
213namespace internal {
214
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600215// This method is used to preserve binary compatibility with fmt 3.0.
216// It can be removed in 4.0.
217FMT_FUNC void format_system_error(
218 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
219 fmt::format_system_error(out, error_code, message);
220}
vitaut270069b2015-06-16 07:36:32 -0700221} // namespace internal
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700222
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700223FMT_FUNC void SystemError::init(
Victor Zverovichfc73e102016-08-25 08:50:07 -0700224 int err_code, CStringRef format_str, format_args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800225 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700226 MemoryWriter w;
Victor Zverovichb903f5c2016-08-26 09:10:23 -0700227 format_system_error(w, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700228 std::runtime_error &base = *this;
229 base = std::runtime_error(w.str());
230}
231
Victor Zverovichb605b392013-09-09 22:21:40 -0700232template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700233int internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700234 char *buffer, std::size_t size, const char *format,
235 unsigned width, int precision, T value) {
236 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700237 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700238 FMT_SNPRINTF(buffer, size, format, value) :
239 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700240 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700241 return precision < 0 ?
242 FMT_SNPRINTF(buffer, size, format, width, value) :
243 FMT_SNPRINTF(buffer, size, format, width, precision, value);
244}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700245
Victor Zverovichb605b392013-09-09 22:21:40 -0700246template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700247int internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700248 wchar_t *buffer, std::size_t size, const wchar_t *format,
249 unsigned width, int precision, T value) {
250 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700251 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000252 FMT_SWPRINTF(buffer, size, format, value) :
253 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700254 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700255 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000256 FMT_SWPRINTF(buffer, size, format, width, value) :
257 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700258}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800259
Victor Zverovich311251e2014-11-29 06:58:00 -0800260template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700261const char internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800262 "0001020304050607080910111213141516171819"
263 "2021222324252627282930313233343536373839"
264 "4041424344454647484950515253545556575859"
265 "6061626364656667686970717273747576777879"
266 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800267
Victor Zverovichf1d85162014-02-19 13:02:22 -0800268#define FMT_POWERS_OF_10(factor) \
269 factor * 10, \
270 factor * 100, \
271 factor * 1000, \
272 factor * 10000, \
273 factor * 100000, \
274 factor * 1000000, \
275 factor * 10000000, \
276 factor * 100000000, \
277 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800278
Victor Zverovich311251e2014-11-29 06:58:00 -0800279template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700280const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800281 0, FMT_POWERS_OF_10(1)
282};
283
284template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700285const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800286 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800287 FMT_POWERS_OF_10(1),
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700288 FMT_POWERS_OF_10(ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700289 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800290 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700291 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800292};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800293
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700294FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800295 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800296 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700297 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700298 format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800299 }
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700300 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700301 format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700302 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800303}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700304
vitaut24c309f2015-06-12 07:15:57 -0700305#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700306
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700307FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800308 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700309 if (s.size() > INT_MAX)
310 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
311 int s_size = static_cast<int>(s.size());
312 int length = MultiByteToWideChar(
313 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700314 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800315 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700316 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700317 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700318 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700319 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800320 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700321 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700322}
323
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700324FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700325 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700326 FMT_THROW(WindowsError(error_code,
327 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700328 }
329}
330
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700331FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700332 if (s.size() > INT_MAX)
333 return ERROR_INVALID_PARAMETER;
334 int s_size = static_cast<int>(s.size());
335 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700336 if (length == 0)
337 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700338 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700339 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700340 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700341 if (length == 0)
342 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700343 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700344 return 0;
345}
346
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700347FMT_FUNC void WindowsError::init(
Victor Zverovichfc73e102016-08-25 08:50:07 -0700348 int err_code, CStringRef format_str, format_args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800349 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700350 MemoryWriter w;
Victor Zverovichc4212f92016-09-28 07:09:26 -0700351 internal::format_windows_error(w, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700352 std::runtime_error &base = *this;
353 base = std::runtime_error(w.str());
354}
355
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700356FMT_FUNC void internal::format_windows_error(
357 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700358 FMT_TRY {
Michael Winterberg2a05a872016-03-02 17:35:34 -0800359 MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
360 buffer.resize(INLINE_BUFFER_SIZE);
361 for (;;) {
362 wchar_t *system_message = &buffer[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700363 int result = FormatMessageW(
364 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
365 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
366 system_message, static_cast<uint32_t>(buffer.size()), 0);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800367 if (result != 0) {
368 UTF16ToUTF8 utf8_message;
369 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
370 out << message << ": " << utf8_message;
371 return;
372 }
373 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700374 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800375 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
376 break; // Can't get error message, report error code instead.
377 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700378 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700379 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800380 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700381}
vitaut24c309f2015-06-12 07:15:57 -0700382
383#endif // FMT_USE_WINDOWS_H
384
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700385FMT_FUNC void format_system_error(
386 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700387 FMT_TRY {
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600388 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
389 buffer.resize(internal::INLINE_BUFFER_SIZE);
vitaut24c309f2015-06-12 07:15:57 -0700390 for (;;) {
391 char *system_message = &buffer[0];
392 int result = safe_strerror(error_code, system_message, buffer.size());
393 if (result == 0) {
394 out << message << ": " << system_message;
395 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 Zverovich0d5ef5c2016-07-12 06:59:35 -0700406void internal::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 Zverovich0028ce52016-08-26 17:23:13 -0700424FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, format_args args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700425 MemoryWriter w;
Victor Zverovich0d8aca82016-08-27 08:16:49 -0700426 w.vwrite(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700427 std::fwrite(w.data(), 1, w.size(), f);
428}
429
Victor Zverovich0028ce52016-08-26 17:23:13 -0700430FMT_FUNC void vprint(CStringRef format_str, format_args args) {
431 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700432}
433
Victor Zverovich0028ce52016-08-26 17:23:13 -0700434FMT_FUNC void vprint_colored(Color c, CStringRef format, 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 Zverovich0028ce52016-08-26 17:23:13 -0700443void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format,
444 format_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 Zverovichd1ded562014-09-29 08:48:16 -0700447 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -0700448 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -0800449 std::size_t size = w.size();
450 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700451}
452
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800453#ifndef FMT_HEADER_ONLY
454
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700455template struct internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -0700456
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700457// Explicit instantiations for char.
458
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700459template void internal::FixedBuffer<char>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800460
Victor Zverovichd705d512016-12-29 09:07:39 -0800461template void internal::ArgMap<format_context>::init(const format_args &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700462
Victor Zverovich9998f662016-11-06 16:11:24 -0800463template void printf_context<char>::format(Writer &writer);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700464
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700465template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700466 char *buffer, std::size_t size, const char *format,
467 unsigned width, int precision, double value);
468
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700469template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700470 char *buffer, std::size_t size, const char *format,
471 unsigned width, int precision, long double value);
472
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700473// Explicit instantiations for wchar_t.
474
Victor Zverovichd705d512016-12-29 09:07:39 -0800475template class basic_format_context<wchar_t>;
476
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700477template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800478
Victor Zverovichd705d512016-12-29 09:07:39 -0800479template void internal::ArgMap<wformat_context>::init(const wformat_args &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700480
Victor Zverovich9998f662016-11-06 16:11:24 -0800481template void printf_context<wchar_t>::format(WWriter &writer);
jdale88a9862fd2014-03-11 18:56:24 +0000482
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700483template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700484 wchar_t *buffer, std::size_t size, const wchar_t *format,
485 unsigned width, int precision, double value);
486
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700487template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700488 wchar_t *buffer, std::size_t size, const wchar_t *format,
489 unsigned width, int precision, long double value);
490
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800491#endif // FMT_HEADER_ONLY
492
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700493} // namespace fmt
494
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100495#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000496# pragma warning(pop)
497#endif