blob: 1257f2b0f2cf7ade98e14a73f1b920f07be3d9d1 [file] [log] [blame]
Victor Zverovichc0954452018-01-06 09:09:50 -08001// Formatting library for C++
2//
3// Copyright (c) 2012 - 2016, Victor Zverovich
4// All rights reserved.
5//
6// For the license information refer to format.h.
Victor Zverovichb076df42012-12-07 08:31:09 -08007
Victor Zverovich3da71d52018-03-21 07:50:59 -07008#ifndef FMT_FORMAT_INL_H_
9#define FMT_FORMAT_INL_H_
10
Victor Zverovichf853d942018-01-20 10:28:10 -080011#include "format.h"
Victor Zverovichfbfedcf2013-01-14 15:16:20 -080012
Victor Zverovich859a4972014-04-30 06:55:21 -070013#include <string.h>
14
Victor Zverovich72f896d2012-12-12 09:17:28 -080015#include <cctype>
Victor Zverovich5d15bdd2014-07-01 16:23:50 -070016#include <cerrno>
Victor Zverovichf28645f2014-04-24 12:37:06 -070017#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070018#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080019#include <cstdarg>
vitaut7dcf0512015-11-13 06:52:13 -080020#include <cstddef> // for std::ptrdiff_t
Victor Zverovich0de44a42018-08-26 08:12:35 -070021#include <cstring> // for std::memmove
Thomas Bernardabde38b2018-08-17 11:22:56 +020022#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
23# include <locale>
24#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070025
vitaut24c309f2015-06-12 07:15:57 -070026#if FMT_USE_WINDOWS_H
Victor Zverovichc753a2a2018-01-28 20:26:25 -080027# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
28# define WIN32_LEAN_AND_MEAN
29# endif
vitaut67ce3942015-04-30 07:48:36 -070030# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
31# include <windows.h>
32# else
33# define NOMINMAX
34# include <windows.h>
35# undef NOMINMAX
36# endif
Ryuuke5a9dc8f2015-02-08 16:08:29 +000037#endif
38
Victor Zverovich8b76e972014-10-06 08:30:55 -070039#if FMT_EXCEPTIONS
40# define FMT_TRY try
41# define FMT_CATCH(x) catch (x)
42#else
43# define FMT_TRY if (true)
44# define FMT_CATCH(x) if (false)
45#endif
46
Ingo van Lilb4b13ee2015-11-02 12:34:46 +010047#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +000048# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070049# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050050# pragma warning(disable: 4702) // unreachable code
vitautdf47d812015-03-16 18:53:14 -070051// Disable deprecation warning for strerror. The latter is not called but
52// MSVC fails to detect it.
53# pragma warning(disable: 4996)
jdale88a9862fd2014-03-11 18:56:24 +000054#endif
55
vitaut341b98c2015-03-14 13:39:33 -070056// Dummy implementations of strerror_r and strerror_s called if corresponding
57// system functions are not available.
Victor Zverovich6cb68f92018-02-10 06:28:33 -080058inline fmt::internal::null<> strerror_r(int, char *, ...) {
Victor Zverovichc333dca2017-02-19 08:41:38 -080059 return fmt::internal::null<>();
vitaut341b98c2015-03-14 13:39:33 -070060}
Victor Zverovich6cb68f92018-02-10 06:28:33 -080061inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
Victor Zverovichc333dca2017-02-19 08:41:38 -080062 return fmt::internal::null<>();
vitaut341b98c2015-03-14 13:39:33 -070063}
64
Victor Zverovich838400d2018-05-12 08:33:51 -070065FMT_BEGIN_NAMESPACE
Victor Zverovichb26e76e2016-06-14 08:11:33 -070066
Victor Zverovich9ff3b972013-09-07 10:15:08 -070067namespace {
68
69#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070070# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080071#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070072inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080073 va_list args;
74 va_start(args, format);
75 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
76 va_end(args);
77 return result;
78}
Victor Zverovichb9a568b2014-09-19 07:51:42 -070079# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -070080#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -080081
cstamford55836ca2015-03-10 07:04:31 +000082#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
83# define FMT_SWPRINTF snwprintf
84#else
85# define FMT_SWPRINTF swprintf
86#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
87
Victor Zverovichc2fecb92018-01-14 14:15:59 -080088typedef void (*FormatFunc)(internal::buffer &, int, string_view);
Victor Zverovich22f75d82014-09-03 08:03:05 -070089
Victor Zverovichf2c9df82014-09-05 08:44:41 -070090// Portable thread-safe version of strerror.
91// Sets buffer to point to a string describing the error code.
92// This can be either a pointer to a string stored in buffer,
93// or a pointer to some static immutable string.
94// Returns one of the following values:
95// 0 - success
96// ERANGE - buffer is not large enough to store the error message
97// other - failure
98// Buffer should be at least of size 1.
99int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800100 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
Victor Zverovich92a250f2018-02-07 07:16:00 -0800101 FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700102
Victor Zverovich69823bf2018-05-19 08:57:31 -0700103 class dispatcher {
vitaut341b98c2015-03-14 13:39:33 -0700104 private:
105 int error_code_;
106 char *&buffer_;
107 std::size_t buffer_size_;
108
vitautda052ae2015-03-21 07:53:39 -0700109 // A noop assignment operator to avoid bogus warnings.
Victor Zverovich69823bf2018-05-19 08:57:31 -0700110 void operator=(const dispatcher &) {}
vitautda052ae2015-03-21 07:53:39 -0700111
vitaut341b98c2015-03-14 13:39:33 -0700112 // Handle the result of XSI-compliant version of strerror_r.
113 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700114 // glibc versions before 2.13 return result in errno.
115 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700116 }
117
118 // Handle the result of GNU-specific version of strerror_r.
119 int handle(char *message) {
120 // If the buffer is full then the message is probably truncated.
121 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
122 return ERANGE;
123 buffer_ = message;
124 return 0;
125 }
126
127 // Handle the case when strerror_r is not available.
Victor Zverovichc333dca2017-02-19 08:41:38 -0800128 int handle(internal::null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700129 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
130 }
131
132 // Fallback to strerror_s when strerror_r is not available.
133 int fallback(int result) {
134 // If the buffer is full then the message is probably truncated.
135 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
136 ERANGE : result;
137 }
138
139 // Fallback to strerror if strerror_r and strerror_s are not available.
Victor Zverovichc333dca2017-02-19 08:41:38 -0800140 int fallback(internal::null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700141 errno = 0;
142 buffer_ = strerror(error_code_);
143 return errno;
144 }
145
146 public:
Victor Zverovich69823bf2018-05-19 08:57:31 -0700147 dispatcher(int err_code, char *&buf, std::size_t buf_size)
Radu Popescu0affb232015-08-04 12:52:44 +0200148 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
vitaut341b98c2015-03-14 13:39:33 -0700149
vitaut63f6c102015-06-14 09:36:23 -0700150 int run() {
vitaut63f6c102015-06-14 09:36:23 -0700151 return handle(strerror_r(error_code_, buffer_, buffer_size_));
152 }
vitaut341b98c2015-03-14 13:39:33 -0700153 };
Victor Zverovich69823bf2018-05-19 08:57:31 -0700154 return dispatcher(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700155}
156
Victor Zverovichc2fecb92018-01-14 14:15:59 -0800157void format_error_code(internal::buffer &out, int error_code,
Victor Zverovich50e71672017-02-18 06:52:52 -0800158 string_view message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700159 // Report error code making sure that the output fits into
Victor Zverovichf1ede632018-03-04 10:33:42 -0800160 // inline_buffer_size to avoid dynamic memory allocation and potential
Victor Zverovich22f75d82014-09-03 08:03:05 -0700161 // bad_alloc.
Victor Zverovichf423e462017-03-11 07:43:26 -0800162 out.resize(0);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700163 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700164 static const char ERROR_STR[] = "error ";
vitaut1addec92015-03-21 20:16:36 -0700165 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
166 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800167 typedef internal::int_traits<int>::main_type main_type;
168 main_type abs_value = static_cast<main_type>(error_code);
vitaut9d577ca2016-03-02 07:01:21 -0800169 if (internal::is_negative(error_code)) {
170 abs_value = 0 - abs_value;
171 ++error_code_size;
172 }
vitautbfdca8b2016-04-20 09:11:33 -0700173 error_code_size += internal::count_digits(abs_value);
Victor Zverovich217e7c72018-01-14 07:19:23 -0800174 writer w(out);
Victor Zverovichf1ede632018-03-04 10:33:42 -0800175 if (message.size() <= inline_buffer_size - error_code_size) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500176 w.write(message);
177 w.write(SEP);
Victor Zverovichec15ef72017-01-22 07:40:21 -0800178 }
Victor Zverovichfefaf072017-02-14 16:29:47 -0500179 w.write(ERROR_STR);
180 w.write(error_code);
Victor Zverovichf1ede632018-03-04 10:33:42 -0800181 assert(out.size() <= inline_buffer_size);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700182}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700183
vitautbfdca8b2016-04-20 09:11:33 -0700184void report_error(FormatFunc func, int error_code,
Victor Zverovich50e71672017-02-18 06:52:52 -0800185 string_view message) FMT_NOEXCEPT {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800186 memory_buffer full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700187 func(full_message, error_code, message);
188 // Use Writer::data instead of Writer::c_str to avoid potential memory
189 // allocation.
190 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
191 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700192}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700193} // namespace
vitaut270069b2015-06-16 07:36:32 -0700194
Victor Zverovich38325242018-10-03 18:22:26 -0700195FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
Victor Zverovichf8027412018-09-30 11:39:20 -0700196 const char8_t *data = s.data();
197 size_t num_code_points = 0;
198 for (size_t i = 0, size = s.size(); i != size; ++i) {
199 if ((data[i] & 0xc0) != 0x80)
200 ++num_code_points;
201 }
202 return num_code_points;
203}
204
Thomas Bernardabde38b2018-08-17 11:22:56 +0200205#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovich6ebc1a92018-05-20 17:16:34 -0700206class locale {
207 private:
208 std::locale locale_;
209
210 public:
211 explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
212 std::locale get() { return locale_; }
213};
214
Victor Zverovichf8027412018-09-30 11:39:20 -0700215namespace internal {
Victor Zverovich7f351de2017-12-03 09:18:06 -0800216template <typename Char>
Victor Zverovichf8027412018-09-30 11:39:20 -0700217FMT_FUNC Char thousands_sep(locale_provider *lp) {
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800218 std::locale loc = lp ? lp->locale().get() : std::locale();
219 return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
Victor Zverovich7f351de2017-12-03 09:18:06 -0800220}
Victor Zverovichf8027412018-09-30 11:39:20 -0700221template <> FMT_FUNC char8_t thousands_sep<char8_t>(locale_provider *) {
222 return static_cast<char8_t>(',');
223}
224}
Thomas Bernardabde38b2018-08-17 11:22:56 +0200225#else
226template <typename Char>
227FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
228 return FMT_STATIC_THOUSANDS_SEPARATOR;
229}
230#endif
Victor Zverovich7f351de2017-12-03 09:18:06 -0800231
Victor Zverovichc333dca2017-02-19 08:41:38 -0800232FMT_FUNC void system_error::init(
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800233 int err_code, string_view format_str, format_args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800234 error_code_ = err_code;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800235 memory_buffer buffer;
236 format_system_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700237 std::runtime_error &base = *this;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800238 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700239}
240
Victor Zverovichcd900972018-04-21 17:26:24 -0700241namespace internal {
Victor Zverovichb605b392013-09-09 22:21:40 -0700242template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700243int char_traits<char>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700244 char *buffer, std::size_t size, const char *format, int precision, T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700245 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700246 FMT_SNPRINTF(buffer, size, format, value) :
247 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovichb605b392013-09-09 22:21:40 -0700248}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700249
Victor Zverovichb605b392013-09-09 22:21:40 -0700250template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700251int char_traits<wchar_t>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700252 wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
253 T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700254 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700255 FMT_SWPRINTF(buffer, size, format, value) :
256 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700257}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800258
Victor Zverovich311251e2014-11-29 06:58:00 -0800259template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700260const char basic_data<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800261 "0001020304050607080910111213141516171819"
262 "2021222324252627282930313233343536373839"
263 "4041424344454647484950515253545556575859"
264 "6061626364656667686970717273747576777879"
265 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800266
Victor Zverovichf1d85162014-02-19 13:02:22 -0800267#define FMT_POWERS_OF_10(factor) \
268 factor * 10, \
269 factor * 100, \
270 factor * 1000, \
271 factor * 10000, \
272 factor * 100000, \
273 factor * 1000000, \
274 factor * 10000000, \
275 factor * 100000000, \
276 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800277
Victor Zverovich311251e2014-11-29 06:58:00 -0800278template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700279const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700280 1, FMT_POWERS_OF_10(1)
281};
282
283template <typename T>
284const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800285 0, FMT_POWERS_OF_10(1)
286};
287
288template <typename T>
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700289const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800290 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800291 FMT_POWERS_OF_10(1),
Victor Zverovich016aceb2017-08-26 09:09:43 -0700292 FMT_POWERS_OF_10(1000000000ull),
293 10000000000000000000ull
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800294};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800295
Victor Zverovich2768af22018-04-29 06:33:05 -0700296// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
297// These are generated by support/compute-powers.py.
298template <typename T>
299const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
Victor Zverovich9de31212018-08-15 06:54:43 -0700300 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
301 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
302 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
303 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
304 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
305 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
306 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
307 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
308 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
309 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
310 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
311 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
312 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
313 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
314 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
315 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
316 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
317 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
318 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
319 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
320 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
321 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
322 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
323 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
324 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
325 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
326 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
327 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
328 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
Victor Zverovich2768af22018-04-29 06:33:05 -0700329};
330
331// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
332// to significands above.
333template <typename T>
334const int16_t basic_data<T>::POW10_EXPONENTS[] = {
335 -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
336 -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
337 -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
338 -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
339 -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
340 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
341 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
342 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
343};
344
Daniela Engert73c53d72018-09-17 18:21:24 +0200345template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;";
346template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530347template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
348template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
349
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700350// A handmade floating-point number f * pow(2, e).
351class fp {
352 private:
353 typedef uint64_t significand_type;
354
355 // All sizes are in bits.
356 static FMT_CONSTEXPR_DECL const int char_size =
357 std::numeric_limits<unsigned char>::digits;
358 // Subtract 1 to account for an implicit most significant bit in the
359 // normalized form.
360 static FMT_CONSTEXPR_DECL const int double_significand_size =
361 std::numeric_limits<double>::digits - 1;
362 static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
363 1ull << double_significand_size;
364
365 public:
366 significand_type f;
367 int e;
368
369 static FMT_CONSTEXPR_DECL const int significand_size =
370 sizeof(significand_type) * char_size;
371
372 fp(): f(0), e(0) {}
373 fp(uint64_t f, int e): f(f), e(e) {}
374
375 // Constructs fp from an IEEE754 double. It is a template to prevent compile
376 // errors on platforms where double is not IEEE754.
377 template <typename Double>
378 explicit fp(Double d) {
379 // Assume double is in the format [sign][exponent][significand].
380 typedef std::numeric_limits<Double> limits;
medithe8cbfb6e2018-09-11 15:14:39 +0200381 const int double_size = static_cast<int>(sizeof(Double) * char_size);
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700382 const int exponent_size =
383 double_size - double_significand_size - 1; // -1 for sign
384 const uint64_t significand_mask = implicit_bit - 1;
385 const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
386 const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
387 auto u = bit_cast<uint64_t>(d);
388 auto biased_e = (u & exponent_mask) >> double_significand_size;
389 f = u & significand_mask;
390 if (biased_e != 0)
391 f += implicit_bit;
392 else
393 biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
394 e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
395 }
396
397 // Normalizes the value converted from double and multiplied by (1 << SHIFT).
398 template <int SHIFT = 0>
399 void normalize() {
400 // Handle subnormals.
401 auto shifted_implicit_bit = implicit_bit << SHIFT;
402 while ((f & shifted_implicit_bit) == 0) {
403 f <<= 1;
404 --e;
405 }
406 // Subtract 1 to account for hidden bit.
407 auto offset = significand_size - double_significand_size - SHIFT - 1;
408 f <<= offset;
409 e -= offset;
410 }
411
412 // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where
413 // a boundary is a value half way between the number and its predecessor
414 // (lower) or successor (upper). The upper boundary is normalized and lower
415 // has the same exponent but may be not normalized.
416 void compute_boundaries(fp &lower, fp &upper) const {
417 lower = f == implicit_bit ?
418 fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
419 upper = fp((f << 1) + 1, e - 1);
420 upper.normalize<1>(); // 1 is to account for the exponent shift above.
421 lower.f <<= lower.e - upper.e;
422 lower.e = upper.e;
423 }
424};
425
426// Returns an fp number representing x - y. Result may not be normalized.
427inline fp operator-(fp x, fp y) {
428 FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands");
429 return fp(x.f - y.f, x.e);
430}
431
432// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
433// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
434FMT_API fp operator*(fp x, fp y);
435
436// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
437// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
438FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
439
Victor Zverovichcd900972018-04-21 17:26:24 -0700440FMT_FUNC fp operator*(fp x, fp y) {
441 // Multiply 32-bit parts of significands.
442 uint64_t mask = (1ULL << 32) - 1;
443 uint64_t a = x.f >> 32, b = x.f & mask;
444 uint64_t c = y.f >> 32, d = y.f & mask;
445 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
446 // Compute mid 64-bit of result and round.
447 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
Daniela Engert6cd66612018-04-30 10:07:43 +0200448 return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
Victor Zverovichcd900972018-04-21 17:26:24 -0700449}
Victor Zverovich468c2432018-05-27 10:57:26 -0700450
451FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
452 const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
453 int index = static_cast<int>(std::ceil(
Victor Zverovich4e4b8572018-05-28 11:25:07 -0700454 (min_exponent + fp::significand_size - 1) * one_over_log2_10));
Victor Zverovich468c2432018-05-27 10:57:26 -0700455 // Decimal exponent of the first (smallest) cached power of 10.
456 const int first_dec_exp = -348;
Victor Zverovich9de31212018-08-15 06:54:43 -0700457 // Difference between 2 consecutive decimal exponents in cached powers of 10.
Victor Zverovich468c2432018-05-27 10:57:26 -0700458 const int dec_exp_step = 8;
459 index = (index - first_dec_exp - 1) / dec_exp_step + 1;
460 pow10_exponent = first_dec_exp + index * dec_exp_step;
461 return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
462}
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700463
Victor Zverovich50b18a32018-10-13 22:14:36 -0700464FMT_FUNC bool grisu2_round(
465 char *buffer, size_t &size, size_t max_digits, uint64_t delta,
466 uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {
Victor Zverovich69929752018-10-13 07:44:34 -0700467 while (remainder < diff && delta - remainder >= exp &&
468 (remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
469 --buffer[size - 1];
470 remainder += exp;
471 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700472 if (size > max_digits) {
473 --size;
474 ++exp10;
475 if (buffer[size] >= '5')
476 return false;
477 }
478 return true;
Victor Zverovich69929752018-10-13 07:44:34 -0700479}
480
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700481// Generates output using Grisu2 digit-gen algorithm.
Victor Zverovich50b18a32018-10-13 22:14:36 -0700482FMT_FUNC bool grisu2_gen_digits(
483 char *buffer, size_t &size, uint32_t hi, uint64_t lo, int &exp,
484 uint64_t delta, const fp &one, const fp &diff, size_t max_digits) {
Victor Zverovich69929752018-10-13 07:44:34 -0700485 // Generate digits for the most significant part (hi).
Victor Zverovich0de44a42018-08-26 08:12:35 -0700486 while (exp > 0) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700487 uint32_t digit = 0;
488 // This optimization by miloyip reduces the number of integer divisions by
489 // one per iteration.
Victor Zverovich0de44a42018-08-26 08:12:35 -0700490 switch (exp) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700491 case 10: digit = hi / 1000000000; hi %= 1000000000; break;
492 case 9: digit = hi / 100000000; hi %= 100000000; break;
493 case 8: digit = hi / 10000000; hi %= 10000000; break;
494 case 7: digit = hi / 1000000; hi %= 1000000; break;
495 case 6: digit = hi / 100000; hi %= 100000; break;
496 case 5: digit = hi / 10000; hi %= 10000; break;
497 case 4: digit = hi / 1000; hi %= 1000; break;
498 case 3: digit = hi / 100; hi %= 100; break;
499 case 2: digit = hi / 10; hi %= 10; break;
500 case 1: digit = hi; hi = 0; break;
501 default:
502 FMT_ASSERT(false, "invalid number of digits");
503 }
504 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200505 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700506 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700507 uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700508 if (remainder <= delta || size > max_digits) {
509 return grisu2_round(
510 buffer, size, max_digits, delta, remainder,
511 static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
512 diff.f, exp);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700513 }
514 }
Victor Zverovich69929752018-10-13 07:44:34 -0700515 // Generate digits for the least significant part (lo).
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700516 for (;;) {
517 lo *= 10;
518 delta *= 10;
519 char digit = static_cast<char>(lo >> -one.e);
520 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200521 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700522 lo &= one.f - 1;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700523 --exp;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700524 if (lo < delta || size > max_digits) {
525 return grisu2_round(buffer, size, max_digits, delta, lo, one.f,
526 diff.f * data::POWERS_OF_10_32[-exp], exp);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700527 }
528 }
529}
530
Victor Zverovich69929752018-10-13 07:44:34 -0700531// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700532FMT_FUNC char *write_exponent(char *buffer, int exp) {
533 FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
534 if (exp < 0) {
535 *buffer++ = '-';
536 exp = -exp;
537 } else {
538 *buffer++ = '+';
539 }
540 if (exp >= 100) {
541 *buffer++ = static_cast<char>('0' + exp / 100);
542 exp %= 100;
543 const char *d = data::DIGITS + exp * 2;
544 *buffer++ = d[0];
545 *buffer++ = d[1];
546 } else {
547 const char *d = data::DIGITS + exp * 2;
548 *buffer++ = d[0];
549 *buffer++ = d[1];
550 }
551 return buffer;
552}
553
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700554#if FMT_CLANG_VERSION
555# define FMT_FALLTHROUGH [[clang::fallthrough]];
medithe981797f2018-09-07 17:53:15 +0200556#elif FMT_GCC_VERSION >= 700
557# define FMT_FALLTHROUGH [[gnu::fallthrough]];
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700558#else
559# define FMT_FALLTHROUGH
560#endif
Victor Zveroviche483a012018-08-26 09:51:49 -0700561
Victor Zverovich50b18a32018-10-13 22:14:36 -0700562struct gen_digits_params {
563 unsigned min_digits;
564 unsigned max_digits;
565 bool fixed;
566 bool upper;
567 bool trailing_zeros;
568
569 // Creates digit generation parameters from format specifiers for a number in
570 // the range [pow(10, exp - 1), pow(10, exp) or 0 if exp == 1.
571 gen_digits_params(const grisu2_specs &specs, int exp)
572 : min_digits(specs.precision >= 0 ? to_unsigned(specs.precision) : 6),
573 fixed(false), upper(false), trailing_zeros(false) {
574 switch (specs.type) {
575 case 'G':
576 upper = true;
577 FMT_FALLTHROUGH
578 case '\0': case 'g':
579 trailing_zeros = (specs.flags & HASH_FLAG) != 0;
580 if (-4 <= exp && exp < static_cast<int>(min_digits) + 1) {
581 fixed = true;
582 if (!specs.type && trailing_zeros && exp >= 0)
583 min_digits = to_unsigned(exp) + 1;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700584 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700585 break;
586 case 'F':
587 upper = true;
588 FMT_FALLTHROUGH
589 case 'f': {
590 fixed = true;
591 trailing_zeros = true;
592 int adjusted_min_digits = static_cast<int>(min_digits) + exp;
593 if (adjusted_min_digits > 0)
594 min_digits = to_unsigned(adjusted_min_digits);
595 break;
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700596 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700597 case 'E':
598 upper = true;
599 FMT_FALLTHROUGH
600 case 'e':
601 ++min_digits;
602 break;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700603 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700604 max_digits = min_digits;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700605 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700606};
607
608// The number is given as v = buffer * pow(10, exp).
609FMT_FUNC void format_float(char *buffer, size_t &size, int exp,
610 const gen_digits_params &params) {
611 if (!params.fixed) {
612 // Insert a decimal point after the first digit and add an exponent.
613 std::memmove(buffer + 2, buffer + 1, size - 1);
614 buffer[1] = '.';
615 exp += static_cast<int>(size) - 1;
616 if (size < params.min_digits) {
617 std::uninitialized_fill_n(buffer + size + 1,
618 params.min_digits - size, '0');
619 size = params.min_digits;
620 }
621 char *p = buffer + size + 1;
622 *p++ = params.upper ? 'E' : 'e';
623 size = to_unsigned(write_exponent(p, exp) - buffer);
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700624 return;
625 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700626 // pow(10, full_exp - 1) <= v <= pow(10, full_exp).
627 int int_size = static_cast<int>(size);
628 int full_exp = int_size + exp;
629 const int exp_threshold = 21;
630 if (int_size <= full_exp && full_exp <= exp_threshold) {
631 // 1234e7 -> 12340000000[.0+]
632 std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
633 char *p = buffer + full_exp;
634 int num_zeros = static_cast<int>(params.min_digits) - full_exp;
635 if (num_zeros > 0 && params.trailing_zeros) {
636 *p++ = '.';
637 std::uninitialized_fill_n(p, num_zeros, '0');
638 p += num_zeros;
639 }
640 size = to_unsigned(p - buffer);
641 } else if (full_exp > 0) {
642 // 1234e-2 -> 12.34[0+]
643 int fractional_size = -exp;
644 std::memmove(buffer + full_exp + 1, buffer + full_exp,
645 to_unsigned(fractional_size));
646 buffer[full_exp] = '.';
647 ++size;
648 if (!params.trailing_zeros) {
649 // Remove trailing zeros.
650 while (buffer[size - 1] == '0') --size;
651 } else if (params.min_digits >= size) {
652 // Add trailing zeros.
653 size_t num_zeros = params.min_digits - size + 1;
654 std::uninitialized_fill_n(buffer + size, num_zeros, '0');
655 size += to_unsigned(num_zeros);
656 }
657 } else {
658 // 1234e-6 -> 0.001234
659 int offset = 2 - full_exp;
660 std::memmove(buffer + offset, buffer, size);
661 buffer[0] = '0';
662 buffer[1] = '.';
663 std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
664 size = to_unsigned(int_size + offset);
665 }
666}
667
668template <typename Double>
669FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
Victor Zveroviche8efdef2018-10-17 08:19:46 -0700670 grisu2_format(Double value, buffer &buf, grisu2_specs specs) {
Victor Zverovich50b18a32018-10-13 22:14:36 -0700671 FMT_ASSERT(value >= 0, "value is negative");
Victor Zveroviche8efdef2018-10-17 08:19:46 -0700672 char *buffer = buf.data();
Victor Zverovich50b18a32018-10-13 22:14:36 -0700673 if (value == 0) {
674 gen_digits_params params(specs, 1);
675 *buffer = '0';
Victor Zveroviche8efdef2018-10-17 08:19:46 -0700676 size_t size = 1;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700677 format_float(buffer, size, 0, params);
Victor Zveroviche8efdef2018-10-17 08:19:46 -0700678 FMT_ASSERT(buf.capacity() >= size, "");
679 buf.resize(size);
Victor Zverovich50b18a32018-10-13 22:14:36 -0700680 return true;
681 }
682
683 fp fp_value(value);
684 fp lower, upper; // w^- and w^+ in the Grisu paper.
685 fp_value.compute_boundaries(lower, upper);
686
687 // Find a cached power of 10 close to 1 / upper and use it to scale upper.
688 const int min_exp = -60; // alpha in Grisu.
689 int cached_exp = 0; // K in Grisu.
690 auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
691 min_exp - (upper.e + fp::significand_size), cached_exp);
692 cached_exp = -cached_exp;
693 upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
694 --upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
695 fp one(1ull << -upper.e, upper.e);
696 // hi (p1 in Grisu) contains the most significant digits of scaled_upper.
697 // hi = floor(upper / one).
698 uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
699 int exp = static_cast<int>(count_digits(hi)); // kappa in Grisu.
700 gen_digits_params params(specs, cached_exp + exp);
701 fp_value.normalize();
702 fp scaled_value = fp_value * cached_pow;
703 lower = lower * cached_pow; // \tilde{M}^- in Grisu.
704 ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
705 uint64_t delta = upper.f - lower.f;
706 fp diff = upper - scaled_value; // wp_w in Grisu.
707 // lo (p2 in Grisu) contains the least significants digits of scaled_upper.
708 // lo = supper % one.
709 uint64_t lo = upper.f & (one.f - 1);
Victor Zveroviche8efdef2018-10-17 08:19:46 -0700710 size_t size = 0;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700711 if (!grisu2_gen_digits(buffer, size, hi, lo, exp, delta, one, diff,
712 params.max_digits)) {
713 return false;
714 }
715 format_float(buffer, size, cached_exp + exp, params);
Victor Zveroviche8efdef2018-10-17 08:19:46 -0700716 FMT_ASSERT(buf.capacity() >= size, "");
717 buf.resize(size);
Victor Zverovich50b18a32018-10-13 22:14:36 -0700718 return true;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700719}
Victor Zverovichcd900972018-04-21 17:26:24 -0700720} // namespace internal
721
vitaut24c309f2015-06-12 07:15:57 -0700722#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700723
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800724FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800725 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700726 if (s.size() > INT_MAX)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800727 FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
vitautc3ba6152015-08-07 07:34:58 -0700728 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200729 if (s_size == 0) {
730 // MultiByteToWideChar does not support zero length, handle separately.
731 buffer_.resize(1);
732 buffer_[0] = 0;
733 return;
734 }
735
vitautc3ba6152015-08-07 07:34:58 -0700736 int length = MultiByteToWideChar(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800737 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700738 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800739 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700740 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700741 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700742 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700743 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800744 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700745 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700746}
747
Victor Zverovichc333dca2017-02-19 08:41:38 -0800748FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700749 if (int error_code = convert(s)) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800750 FMT_THROW(windows_error(error_code,
Victor Zverovich8b76e972014-10-06 08:30:55 -0700751 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700752 }
753}
754
Victor Zverovichc333dca2017-02-19 08:41:38 -0800755FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
vitautca747812015-08-07 07:08:46 -0700756 if (s.size() > INT_MAX)
757 return ERROR_INVALID_PARAMETER;
758 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200759 if (s_size == 0) {
760 // WideCharToMultiByte does not support zero length, handle separately.
761 buffer_.resize(1);
762 buffer_[0] = 0;
763 return 0;
764 }
765
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800766 int length = WideCharToMultiByte(
767 CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700768 if (length == 0)
769 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700770 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700771 length = WideCharToMultiByte(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800772 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700773 if (length == 0)
774 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700775 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700776 return 0;
777}
778
Victor Zverovichc333dca2017-02-19 08:41:38 -0800779FMT_FUNC void windows_error::init(
Victor Zverovich7f351de2017-12-03 09:18:06 -0800780 int err_code, string_view format_str, format_args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800781 error_code_ = err_code;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800782 memory_buffer buffer;
Victor Zveroviche022c212017-02-17 06:38:53 -0800783 internal::format_windows_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700784 std::runtime_error &base = *this;
Victor Zveroviche022c212017-02-17 06:38:53 -0800785 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700786}
787
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700788FMT_FUNC void internal::format_windows_error(
Victor Zverovichf6fd38b2018-01-15 08:22:31 -0800789 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700790 FMT_TRY {
Victor Zverovichc0954452018-01-06 09:09:50 -0800791 wmemory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800792 buf.resize(inline_buffer_size);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800793 for (;;) {
Victor Zverovichc0954452018-01-06 09:09:50 -0800794 wchar_t *system_message = &buf[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700795 int result = FormatMessageW(
796 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800797 FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
798 system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800799 if (result != 0) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800800 utf16_to_utf8 utf8_message;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800801 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800802 writer w(out);
Victor Zveroviche022c212017-02-17 06:38:53 -0800803 w.write(message);
804 w.write(": ");
805 w.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800806 return;
807 }
808 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700809 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800810 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
811 break; // Can't get error message, report error code instead.
Victor Zverovichc0954452018-01-06 09:09:50 -0800812 buf.resize(buf.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700813 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700814 } FMT_CATCH(...) {}
Victor Zverovichc0954452018-01-06 09:09:50 -0800815 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700816}
vitaut24c309f2015-06-12 07:15:57 -0700817
818#endif // FMT_USE_WINDOWS_H
819
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700820FMT_FUNC void format_system_error(
Victor Zverovichc2fecb92018-01-14 14:15:59 -0800821 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700822 FMT_TRY {
Victor Zverovich36634142017-12-26 09:00:22 -0800823 memory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800824 buf.resize(inline_buffer_size);
vitaut24c309f2015-06-12 07:15:57 -0700825 for (;;) {
Victor Zverovich36634142017-12-26 09:00:22 -0800826 char *system_message = &buf[0];
827 int result = safe_strerror(error_code, system_message, buf.size());
vitaut24c309f2015-06-12 07:15:57 -0700828 if (result == 0) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800829 writer w(out);
Victor Zverovichfefaf072017-02-14 16:29:47 -0500830 w.write(message);
831 w.write(": ");
832 w.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700833 return;
834 }
835 if (result != ERANGE)
836 break; // Can't get error message, report error code instead.
Victor Zverovich36634142017-12-26 09:00:22 -0800837 buf.resize(buf.size() * 2);
vitaut24c309f2015-06-12 07:15:57 -0700838 }
839 } FMT_CATCH(...) {}
Victor Zverovichf164e4c2018-02-01 16:49:47 -0800840 format_error_code(out, error_code, message);
vitaut24c309f2015-06-12 07:15:57 -0700841}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700842
Abdó Roig-Marangesaf0f21d2017-12-09 16:50:53 +0100843FMT_FUNC void internal::error_handler::on_error(const char *message) {
Victor Zverovich94edb1a2017-12-06 07:42:42 -0800844 FMT_THROW(format_error(message));
845}
846
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700847FMT_FUNC void report_system_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800848 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700849 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700850}
851
vitaut24c309f2015-06-12 07:15:57 -0700852#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700853FMT_FUNC void report_windows_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800854 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700855 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700856}
Victor Zverovich400812a2014-04-30 12:38:17 -0700857#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700858
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800859FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800860 memory_buffer buffer;
Victor Zverovich38325242018-10-03 18:22:26 -0700861 vformat_to(buffer, format_str,
862 basic_format_args<buffer_context<char>::type>(args));
Victor Zverovichfefaf072017-02-14 16:29:47 -0500863 std::fwrite(buffer.data(), 1, buffer.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700864}
865
Daniela Engert2570f1a2018-04-26 20:32:14 +0200866FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
867 wmemory_buffer buffer;
868 vformat_to(buffer, format_str, args);
869 std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
870}
871
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800872FMT_FUNC void vprint(string_view format_str, format_args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700873 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700874}
875
Daniela Engert2570f1a2018-04-26 20:32:14 +0200876FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
877 vprint(stdout, format_str, args);
878}
879
Thomas Bernardabde38b2018-08-17 11:22:56 +0200880#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800881FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
Thomas Bernardabde38b2018-08-17 11:22:56 +0200882#endif
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800883
Victor Zverovich838400d2018-05-12 08:33:51 -0700884FMT_END_NAMESPACE
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700885
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100886#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000887# pragma warning(pop)
888#endif
Victor Zverovich3da71d52018-03-21 07:50:59 -0700889
890#endif // FMT_FORMAT_INL_H_