blob: d1a449d6b1938e3100a9a1e31b857c07ab71a1c6 [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.
Victor Zverovichc333dca2017-02-19 08:41:38 -080073static inline fmt::internal::null<> strerror_r(int, char *, ...) {
74 return fmt::internal::null<>();
vitaut341b98c2015-03-14 13:39:33 -070075}
Victor Zverovichc333dca2017-02-19 08:41:38 -080076static 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
Victor Zverovich9bb213e2016-08-25 08:38:07 -070082FMT_FUNC format_error::~format_error() throw() {}
Victor Zverovichc333dca2017-02-19 08:41:38 -080083FMT_FUNC system_error::~system_error() throw() {}
Victor Zverovichb26e76e2016-06-14 08:11:33 -070084
Victor Zverovich9ff3b972013-09-07 10:15:08 -070085namespace {
86
87#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070088# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080089#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070090inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080091 va_list args;
92 va_start(args, format);
93 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
94 va_end(args);
95 return result;
96}
Victor Zverovichb9a568b2014-09-19 07:51:42 -070097# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -070098#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -080099
cstamford55836ca2015-03-10 07:04:31 +0000100#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
101# define FMT_SWPRINTF snwprintf
102#else
103# define FMT_SWPRINTF swprintf
104#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
105
Victor Zverovich7004d1e2015-02-08 19:54:39 -0800106const char RESET_COLOR[] = "\x1b[0m";
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700107
Victor Zverovich50e71672017-02-18 06:52:52 -0800108typedef void (*FormatFunc)(buffer &, int, string_view);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700109
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700110// Portable thread-safe version of strerror.
111// Sets buffer to point to a string describing the error code.
112// This can be either a pointer to a string stored in buffer,
113// or a pointer to some static immutable string.
114// Returns one of the following values:
115// 0 - success
116// ERANGE - buffer is not large enough to store the error message
117// other - failure
118// Buffer should be at least of size 1.
119int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800120 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
vitaut8ab665a2015-06-22 08:17:23 -0700121 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700122
vitaut341b98c2015-03-14 13:39:33 -0700123 class StrError {
124 private:
125 int error_code_;
126 char *&buffer_;
127 std::size_t buffer_size_;
128
vitautda052ae2015-03-21 07:53:39 -0700129 // A noop assignment operator to avoid bogus warnings.
130 void operator=(const StrError &) {}
131
vitaut341b98c2015-03-14 13:39:33 -0700132 // Handle the result of XSI-compliant version of strerror_r.
133 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700134 // glibc versions before 2.13 return result in errno.
135 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700136 }
137
138 // Handle the result of GNU-specific version of strerror_r.
139 int handle(char *message) {
140 // If the buffer is full then the message is probably truncated.
141 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
142 return ERANGE;
143 buffer_ = message;
144 return 0;
145 }
146
147 // Handle the case when strerror_r is not available.
Victor Zverovichc333dca2017-02-19 08:41:38 -0800148 int handle(internal::null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700149 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
150 }
151
152 // Fallback to strerror_s when strerror_r is not available.
153 int fallback(int result) {
154 // If the buffer is full then the message is probably truncated.
155 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
156 ERANGE : result;
157 }
158
159 // Fallback to strerror if strerror_r and strerror_s are not available.
Victor Zverovichc333dca2017-02-19 08:41:38 -0800160 int fallback(internal::null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700161 errno = 0;
162 buffer_ = strerror(error_code_);
163 return errno;
164 }
165
166 public:
Radu Popescu0affb232015-08-04 12:52:44 +0200167 StrError(int err_code, char *&buf, std::size_t buf_size)
168 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
vitaut341b98c2015-03-14 13:39:33 -0700169
vitaut63f6c102015-06-14 09:36:23 -0700170 int run() {
171 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
172 return handle(strerror_r(error_code_, buffer_, buffer_size_));
173 }
vitaut341b98c2015-03-14 13:39:33 -0700174 };
175 return StrError(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700176}
177
Victor Zverovichfefaf072017-02-14 16:29:47 -0500178void format_error_code(buffer &out, int error_code,
Victor Zverovich50e71672017-02-18 06:52:52 -0800179 string_view message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700180 // Report error code making sure that the output fits into
181 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
182 // bad_alloc.
183 out.clear();
184 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700185 static const char ERROR_STR[] = "error ";
vitaut1addec92015-03-21 20:16:36 -0700186 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
187 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800188 typedef internal::int_traits<int>::main_type main_type;
189 main_type abs_value = static_cast<main_type>(error_code);
vitaut9d577ca2016-03-02 07:01:21 -0800190 if (internal::is_negative(error_code)) {
191 abs_value = 0 - abs_value;
192 ++error_code_size;
193 }
vitautbfdca8b2016-04-20 09:11:33 -0700194 error_code_size += internal::count_digits(abs_value);
Victor Zverovichfefaf072017-02-14 16:29:47 -0500195 basic_writer<char> w(out);
Victor Zverovichec15ef72017-01-22 07:40:21 -0800196 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500197 w.write(message);
198 w.write(SEP);
Victor Zverovichec15ef72017-01-22 07:40:21 -0800199 }
Victor Zverovichfefaf072017-02-14 16:29:47 -0500200 w.write(ERROR_STR);
201 w.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,
Victor Zverovich50e71672017-02-18 06:52:52 -0800206 string_view message) FMT_NOEXCEPT {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800207 memory_buffer 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
Victor Zverovichc333dca2017-02-19 08:41:38 -0800216FMT_FUNC void system_error::init(
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800217 int err_code, CStringRef format_str, args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800218 error_code_ = err_code;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800219 memory_buffer buffer;
220 format_system_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700221 std::runtime_error &base = *this;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800222 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700223}
224
Victor Zverovichb605b392013-09-09 22:21:40 -0700225template <typename T>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800226int internal::char_traits<char>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700227 char *buffer, std::size_t size, const char *format,
228 unsigned width, int precision, T value) {
229 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700230 return precision < 0 ?
Victor Zverovichb605b392013-09-09 22:21:40 -0700231 FMT_SNPRINTF(buffer, size, format, value) :
232 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700233 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700234 return precision < 0 ?
235 FMT_SNPRINTF(buffer, size, format, width, value) :
236 FMT_SNPRINTF(buffer, size, format, width, precision, value);
237}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700238
Victor Zverovichb605b392013-09-09 22:21:40 -0700239template <typename T>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800240int internal::char_traits<wchar_t>::format_float(
Victor Zverovichb605b392013-09-09 22:21:40 -0700241 wchar_t *buffer, std::size_t size, const wchar_t *format,
242 unsigned width, int precision, T value) {
243 if (width == 0) {
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700244 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000245 FMT_SWPRINTF(buffer, size, format, value) :
246 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700247 }
Victor Zverovichb605b392013-09-09 22:21:40 -0700248 return precision < 0 ?
cstamford55836ca2015-03-10 07:04:31 +0000249 FMT_SWPRINTF(buffer, size, format, width, value) :
250 FMT_SWPRINTF(buffer, size, format, width, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700251}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800252
Victor Zverovich311251e2014-11-29 06:58:00 -0800253template <typename T>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800254const char internal::basic_data<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800255 "0001020304050607080910111213141516171819"
256 "2021222324252627282930313233343536373839"
257 "4041424344454647484950515253545556575859"
258 "6061626364656667686970717273747576777879"
259 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800260
Victor Zverovichf1d85162014-02-19 13:02:22 -0800261#define FMT_POWERS_OF_10(factor) \
262 factor * 10, \
263 factor * 100, \
264 factor * 1000, \
265 factor * 10000, \
266 factor * 100000, \
267 factor * 1000000, \
268 factor * 10000000, \
269 factor * 100000000, \
270 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800271
Victor Zverovich311251e2014-11-29 06:58:00 -0800272template <typename T>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800273const uint32_t internal::basic_data<T>::POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800274 0, FMT_POWERS_OF_10(1)
275};
276
277template <typename T>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800278const uint64_t internal::basic_data<T>::POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800279 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800280 FMT_POWERS_OF_10(1),
Victor Zverovich50e71672017-02-18 06:52:52 -0800281 FMT_POWERS_OF_10(ulong_long(1000000000)),
Victor Zverovich406c6122014-08-19 08:47:38 -0700282 // Multiply several constants instead of using a single long long constant
Victor Zverovichf1d85162014-02-19 13:02:22 -0800283 // to avoid warnings about C++98 not supporting long long.
Victor Zverovich50e71672017-02-18 06:52:52 -0800284 ulong_long(1000000000) * ulong_long(1000000000) * 10
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800285};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800286
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700287FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
Carter Li2d4631a2015-03-14 14:54:37 +0800288 (void)type;
Victor Zverovich877abaf2013-01-08 09:56:05 -0800289 if (std::isprint(static_cast<unsigned char>(code))) {
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700290 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700291 format("unknown format code '{}' for {}", code, type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800292 }
Victor Zverovich9bb213e2016-08-25 08:38:07 -0700293 FMT_THROW(format_error(
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700294 format("unknown format code '\\x{:02x}' for {}",
Victor Zverovich8b76e972014-10-06 08:30:55 -0700295 static_cast<unsigned>(code), type)));
Victor Zverovich877abaf2013-01-08 09:56:05 -0800296}
Victor Zverovich7cae7632013-09-06 20:23:42 -0700297
vitaut24c309f2015-06-12 07:15:57 -0700298#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700299
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800300FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800301 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700302 if (s.size() > INT_MAX)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800303 FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
vitautc3ba6152015-08-07 07:34:58 -0700304 int s_size = static_cast<int>(s.size());
305 int length = MultiByteToWideChar(
306 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700307 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800308 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700309 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700310 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700311 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700312 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800313 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700314 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700315}
316
Victor Zverovichc333dca2017-02-19 08:41:38 -0800317FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700318 if (int error_code = convert(s)) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800319 FMT_THROW(windows_error(error_code,
Victor Zverovich8b76e972014-10-06 08:30:55 -0700320 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700321 }
322}
323
Victor Zverovichc333dca2017-02-19 08:41:38 -0800324FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
vitautca747812015-08-07 07:08:46 -0700325 if (s.size() > INT_MAX)
326 return ERROR_INVALID_PARAMETER;
327 int s_size = static_cast<int>(s.size());
328 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700329 if (length == 0)
330 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700331 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700332 length = WideCharToMultiByte(
vitautca747812015-08-07 07:08:46 -0700333 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700334 if (length == 0)
335 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700336 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700337 return 0;
338}
339
Victor Zverovichc333dca2017-02-19 08:41:38 -0800340FMT_FUNC void windows_error::init(
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800341 int err_code, CStringRef format_str, args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800342 error_code_ = err_code;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800343 memory_buffer buffer;
Victor Zveroviche022c212017-02-17 06:38:53 -0800344 internal::format_windows_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700345 std::runtime_error &base = *this;
Victor Zveroviche022c212017-02-17 06:38:53 -0800346 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700347}
348
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700349FMT_FUNC void internal::format_windows_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800350 buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700351 FMT_TRY {
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800352 wmemory_buffer buffer;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800353 buffer.resize(INLINE_BUFFER_SIZE);
354 for (;;) {
355 wchar_t *system_message = &buffer[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700356 int result = FormatMessageW(
357 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
358 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
359 system_message, static_cast<uint32_t>(buffer.size()), 0);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800360 if (result != 0) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800361 utf16_to_utf8 utf8_message;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800362 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zveroviche022c212017-02-17 06:38:53 -0800363 basic_writer<char> w(out);
364 w.write(message);
365 w.write(": ");
366 w.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800367 return;
368 }
369 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700370 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800371 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
372 break; // Can't get error message, report error code instead.
373 buffer.resize(buffer.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700374 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700375 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800376 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
Victor Zverovich53b4c312014-04-30 15:00:41 -0700377}
vitaut24c309f2015-06-12 07:15:57 -0700378
379#endif // FMT_USE_WINDOWS_H
380
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700381FMT_FUNC void format_system_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800382 buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700383 FMT_TRY {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800384 memory_buffer buffer;
Victor Zverovichcc9b0512016-05-11 21:36:22 -0600385 buffer.resize(internal::INLINE_BUFFER_SIZE);
vitaut24c309f2015-06-12 07:15:57 -0700386 for (;;) {
387 char *system_message = &buffer[0];
388 int result = safe_strerror(error_code, system_message, buffer.size());
389 if (result == 0) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500390 basic_writer<char> w(out);
391 w.write(message);
392 w.write(": ");
393 w.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700394 return;
395 }
396 if (result != ERANGE)
397 break; // Can't get error message, report error code instead.
398 buffer.resize(buffer.size() * 2);
399 }
400 } FMT_CATCH(...) {}
vitaut66069712015-11-18 08:42:09 -0800401 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
vitaut24c309f2015-06-12 07:15:57 -0700402}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700403
jamboree7487bde2015-06-10 09:32:59 +0800404template <typename Char>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800405void basic_fixed_buffer<Char>::grow(std::size_t) {
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800406 FMT_THROW(std::runtime_error("buffer overflow"));
407}
408
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700409FMT_FUNC void report_system_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800410 int error_code, fmt::string_view message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800411 // 'fmt::' is for bcc32.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700412 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700413}
414
vitaut24c309f2015-06-12 07:15:57 -0700415#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700416FMT_FUNC void report_windows_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800417 int error_code, fmt::string_view message) FMT_NOEXCEPT {
vitaute5d59982015-11-20 07:56:16 -0800418 // 'fmt::' is for bcc32.
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700419 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700420}
Victor Zverovich400812a2014-04-30 12:38:17 -0700421#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700422
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800423FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800424 memory_buffer buffer;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500425 vformat_to(buffer, format_str, args);
426 std::fwrite(buffer.data(), 1, buffer.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700427}
428
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800429FMT_FUNC void vprint(CStringRef format_str, args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700430 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700431}
432
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800433FMT_FUNC void vprint_colored(Color c, CStringRef format, args args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700434 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100435 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700436 std::fputs(escape, stdout);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700437 vprint(format, args);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700438 std::fputs(RESET_COLOR, stdout);
439}
440
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700441template <typename Char>
Victor Zverovich84286212016-12-30 12:11:27 -0800442void printf(basic_writer<Char> &w, BasicCStringRef<Char> format,
Victor Zverovicha13b96e2017-02-05 06:54:03 -0800443 args args);
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700444
Victor Zverovich0854f8c2016-12-11 13:22:45 -0800445FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800446 memory_buffer buffer;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500447 printf(buffer, format, args);
448 std::size_t size = buffer.size();
449 return std::fwrite(
450 buffer.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 Zverovich6a2ff282017-02-19 06:46:51 -0800455template struct internal::basic_data<void>;
vitaut804a74c2015-05-14 12:58:42 -0700456
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700457// Explicit instantiations for char.
458
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800459template void basic_fixed_buffer<char>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800460
Victor Zverovichc333dca2017-02-19 08:41:38 -0800461template void internal::arg_map<context>::init(const args &args);
Victor Zverovich7cae7632013-09-06 20:23:42 -0700462
Victor Zverovichfefaf072017-02-14 16:29:47 -0500463template void printf_context<char>::format(buffer &);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700464
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800465template int internal::char_traits<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 Zverovich6a2ff282017-02-19 06:46:51 -0800469template int internal::char_traits<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 Zverovich624c5862017-02-05 06:41:39 -0800475template class basic_context<wchar_t>;
Victor Zverovichd705d512016-12-29 09:07:39 -0800476
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800477template void basic_fixed_buffer<wchar_t>::grow(std::size_t);
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800478
Victor Zverovichc333dca2017-02-19 08:41:38 -0800479template void internal::arg_map<wcontext>::init(const wargs &args);
Victor Zverovichbf8b29f2014-06-06 06:38:37 -0700480
Victor Zverovichfefaf072017-02-14 16:29:47 -0500481template void printf_context<wchar_t>::format(wbuffer &);
jdale88a9862fd2014-03-11 18:56:24 +0000482
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800483template int internal::char_traits<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 Zverovich6a2ff282017-02-19 06:46:51 -0800487template int internal::char_traits<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