blob: 3dd42e1a4461c0159e5c70da849060ea0aadfa80 [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 Zverovich84286212016-12-30 12:11:27 -0800109typedef 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
Victor Zverovich84286212016-12-30 12:11:27 -0800179void format_error_code(writer &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 Zverovichec15ef72017-01-22 07:40:21 -0800196 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
197 out.write(message);
198 out.write(SEP);
199 }
200 out.write(ERROR_STR);
201 out.write(error_code);
vitautbfdca8b2016-04-20 09:11:33 -0700202 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700203}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700204
vitautbfdca8b2016-04-20 09:11:33 -0700205void report_error(FormatFunc func, int error_code,
206 StringRef message) FMT_NOEXCEPT {
207 MemoryWriter full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700208 func(full_message, error_code, message);
209 // Use Writer::data instead of Writer::c_str to avoid potential memory
210 // allocation.
211 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
212 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700213}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700214} // namespace
vitaut270069b2015-06-16 07:36:32 -0700215
216namespace internal {
217
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600218// This method is used to preserve binary compatibility with fmt 3.0.
219// It can be removed in 4.0.
220FMT_FUNC void format_system_error(
Victor Zverovich84286212016-12-30 12:11:27 -0800221 writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600222 fmt::format_system_error(out, error_code, message);
223}
vitaut270069b2015-06-16 07:36:32 -0700224} // namespace internal
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700225
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700226FMT_FUNC void SystemError::init(
Victor Zverovichfc73e102016-08-25 08:50:07 -0700227 int err_code, CStringRef format_str, format_args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800228 error_code_ = err_code;
Victor Zverovichd1ded562014-09-29 08:48:16 -0700229 MemoryWriter w;
Victor Zverovichb903f5c2016-08-26 09:10:23 -0700230 format_system_error(w, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700231 std::runtime_error &base = *this;
232 base = std::runtime_error(w.str());
233}
234
Victor Zverovichb605b392013-09-09 22:21:40 -0700235template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700236int internal::CharTraits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700237 char *buffer, std::size_t size, const char *format,
238 unsigned width, int precision, T value) {
239 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700240 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700241 FMT_SNPRINTF(buffer, size, format, value) :
242 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700243 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700244 return precision < 0 ?
245 FMT_SNPRINTF(buffer, size, format, width, value) :
246 FMT_SNPRINTF(buffer, size, format, width, precision, value);
247}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700248
Victor Zverovichb605b392013-09-09 22:21:40 -0700249template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700250int internal::CharTraits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700251 wchar_t *buffer, std::size_t size, const wchar_t *format,
252 unsigned width, int precision, T value) {
253 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700254 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000255 FMT_SWPRINTF(buffer, size, format, value) :
256 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700257 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700258 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000259 FMT_SWPRINTF(buffer, size, format, width, value) :
260 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700261}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800262
Victor Zverovich311251e2014-11-29 06:58:00 -0800263template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700264const char internal::BasicData<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800265 "0001020304050607080910111213141516171819"
266 "2021222324252627282930313233343536373839"
267 "4041424344454647484950515253545556575859"
268 "6061626364656667686970717273747576777879"
269 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800270
Victor Zverovichf1d85162014-02-19 13:02:22 -0800271#define FMT_POWERS_OF_10(factor) \
272 factor * 10, \
273 factor * 100, \
274 factor * 1000, \
275 factor * 10000, \
276 factor * 100000, \
277 factor * 1000000, \
278 factor * 10000000, \
279 factor * 100000000, \
280 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800281
Victor Zverovich311251e2014-11-29 06:58:00 -0800282template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700283const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800284 0, FMT_POWERS_OF_10(1)
285};
286
287template <typename T>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700288const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800289 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800290 FMT_POWERS_OF_10(1),
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700291 FMT_POWERS_OF_10(ULongLong(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700292 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800293 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700294 ULongLong(1000000000) * ULongLong(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800295};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800296
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700297FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800298 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800299 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700300 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700301 format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800302 }
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700303 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700304 format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700305 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800306}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700307
vitaut24c309f2015-06-12 07:15:57 -0700308#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700309
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700310FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800311 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700312 if (s.size() > INT_MAX)
313 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
314 int s_size = static_cast<int>(s.size());
315 int length = MultiByteToWideChar(
316 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700317 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800318 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700319 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700320 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700321 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700322 if (length == 0)
Victor Zverovichdff21372014-12-16 07:01:01 -0800323 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700324 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700325}
326
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700327FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700328 if (int error_code = convert(s)) {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700329 FMT_THROW(WindowsError(error_code,
330 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700331 }
332}
333
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700334FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
vitautca747812015-08-07 07:08:46 -0700335 if (s.size() > INT_MAX)
336 return ERROR_INVALID_PARAMETER;
337 int s_size = static_cast<int>(s.size());
338 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700339 if (length == 0)
340 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700341 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700342 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700343 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700344 if (length == 0)
345 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700346 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700347 return 0;
348}
349
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700350FMT_FUNC void WindowsError::init(
Victor Zverovichfc73e102016-08-25 08:50:07 -0700351 int err_code, CStringRef format_str, format_args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800352 error_code_ = err_code;
Victor Zverovich8c4db502014-09-29 09:17:02 -0700353 MemoryWriter w;
Victor Zverovichc4212f92016-09-28 07:09:26 -0700354 internal::format_windows_error(w, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700355 std::runtime_error &base = *this;
356 base = std::runtime_error(w.str());
357}
358
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700359FMT_FUNC void internal::format_windows_error(
Victor Zverovich84286212016-12-30 12:11:27 -0800360 writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700361 FMT_TRY {
Michael Winterberg2a05a872016-03-02 17:35:34 -0800362 MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
363 buffer.resize(INLINE_BUFFER_SIZE);
364 for (;;) {
365 wchar_t *system_message = &buffer[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700366 int result = FormatMessageW(
367 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
368 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
369 system_message, static_cast<uint32_t>(buffer.size()), 0);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800370 if (result != 0) {
371 UTF16ToUTF8 utf8_message;
372 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zverovichec15ef72017-01-22 07:40:21 -0800373 out.write(message);
374 out.write(": ");
375 out.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800376 return;
377 }
378 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700379 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800380 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
381 break; // Can't get error message, report error code instead.
382 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700383 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700384 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800385 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700386}
vitaut24c309f2015-06-12 07:15:57 -0700387
388#endif // FMT_USE_WINDOWS_H
389
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700390FMT_FUNC void format_system_error(
Victor Zverovich84286212016-12-30 12:11:27 -0800391 writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700392 FMT_TRY {
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600393 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
394 buffer.resize(internal::INLINE_BUFFER_SIZE);
vitaut24c309f2015-06-12 07:15:57 -0700395 for (;;) {
396 char *system_message = &buffer[0];
397 int result = safe_strerror(error_code, system_message, buffer.size());
398 if (result == 0) {
Victor Zverovichec15ef72017-01-22 07:40:21 -0800399 out.write(message);
400 out.write(": ");
401 out.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700402 return;
403 }
404 if (result != ERANGE)
405 break; // Can't get error message, report error code instead.
406 buffer.resize(buffer.size() * 2);
407 }
408 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800409 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
vitaut24c309f2015-06-12 07:15:57 -0700410}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700411
jamboree7487bde2015-06-10 09:32:59 +0800412template <typename Char>
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700413void internal::FixedBuffer<Char>::grow(std::size_t) {
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800414 FMT_THROW(std::runtime_error("buffer overflow"));
415}
416
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700417FMT_FUNC void report_system_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(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700421}
422
vitaut24c309f2015-06-12 07:15:57 -0700423#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700424FMT_FUNC void report_windows_error(
Carter Lie2583ab2015-02-14 09:58:29 +0800425 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800426 // 'fmt::' is for bcc32.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700427 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700428}
Victor Zverovich400812a2014-04-30 12:38:17 -0700429#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700430
Victor Zverovich0028ce52016-08-26 17:23:13 -0700431FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, format_args args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700432 MemoryWriter w;
Victor Zverovichec15ef72017-01-22 07:40:21 -0800433 w.vformat(format_str, args);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700434 std::fwrite(w.data(), 1, w.size(), f);
435}
436
Victor Zverovich0028ce52016-08-26 17:23:13 -0700437FMT_FUNC void vprint(CStringRef format_str, format_args args) {
438 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700439}
440
Victor Zverovich0028ce52016-08-26 17:23:13 -0700441FMT_FUNC void vprint_colored(Color c, CStringRef format, format_args args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700442 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100443 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700444 std::fputs(escape, stdout);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700445 vprint(format, args);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700446 std::fputs(RESET_COLOR, stdout);
447}
448
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700449template <typename Char>
Victor Zverovich84286212016-12-30 12:11:27 -0800450void printf(basic_writer<Char> &w, BasicCStringRef<Char> format,
Victor Zverovich0028ce52016-08-26 17:23:13 -0700451 format_args args);
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700452
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800453FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) {
Victor Zverovichd1ded562014-09-29 08:48:16 -0700454 MemoryWriter w;
Victor Zverovich21111cc2014-06-29 19:52:26 -0700455 printf(w, format, args);
Victor Zverovich615c1ee2014-11-14 09:40:01 -0800456 std::size_t size = w.size();
457 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700458}
459
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800460#ifndef FMT_HEADER_ONLY
461
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700462template struct internal::BasicData<void>;
vitaut804a74c2015-05-14 12:58:42 -0700463
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700464// Explicit instantiations for char.
465
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700466template void internal::FixedBuffer<char>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800467
Victor Zverovich624c5862017-02-05 06:41:39 -0800468template void internal::ArgMap<context>::init(const format_args &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700469
Victor Zverovich84286212016-12-30 12:11:27 -0800470template void printf_context<char>::format(writer &writer);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700471
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700472template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700473 char *buffer, std::size_t size, const char *format,
474 unsigned width, int precision, double value);
475
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700476template int internal::CharTraits<char>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700477 char *buffer, std::size_t size, const char *format,
478 unsigned width, int precision, long double value);
479
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700480// Explicit instantiations for wchar_t.
481
Victor Zverovich624c5862017-02-05 06:41:39 -0800482template class basic_context<wchar_t>;
Victor Zverovichd705d512016-12-29 09:07:39 -0800483
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700484template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800485
Victor Zverovich624c5862017-02-05 06:41:39 -0800486template void internal::ArgMap<wcontext>::init(const wformat_args &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700487
Victor Zverovich84286212016-12-30 12:11:27 -0800488template void printf_context<wchar_t>::format(wwriter &writer);
jdale88a9862fd2014-03-11 18:56:24 +0000489
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700490template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700491 wchar_t *buffer, std::size_t size, const wchar_t *format,
492 unsigned width, int precision, double value);
493
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700494template int internal::CharTraits<wchar_t>::format_float(
Victor Zverovich14f25772014-09-19 08:45:05 -0700495 wchar_t *buffer, std::size_t size, const wchar_t *format,
496 unsigned width, int precision, long double value);
497
Victor Zverovichc09c42f2015-03-01 09:43:33 -0800498#endif // FMT_HEADER_ONLY
499
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700500} // namespace fmt
501
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100502#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000503# pragma warning(pop)
504#endif