blob: 2703763e47fdf24fbf15a228a650dfed6a65159d [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 Zverovichf8027412018-09-30 11:39:20 -0700195FMT_FUNC size_t internal::count_code_points(u8string_view s) {
196 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
464// Generates output using Grisu2 digit-gen algorithm.
465FMT_FUNC void grisu2_gen_digits(
466 const fp &scaled_value, const fp &scaled_upper, uint64_t delta,
467 char *buffer, size_t &size, int &dec_exp) {
468 internal::fp one(1ull << -scaled_upper.e, scaled_upper.e);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700469 // hi (p1 in Grisu) contains the most significant digits of scaled_upper.
470 // hi = floor(scaled_upper / one).
471 uint32_t hi = static_cast<uint32_t>(scaled_upper.f >> -one.e);
472 // lo (p2 in Grisu) contains the least significants digits of scaled_upper.
473 // lo = scaled_upper mod 1.
474 uint64_t lo = scaled_upper.f & (one.f - 1);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700475 size = 0;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700476 auto exp = count_digits(hi); // kappa in Grisu.
477 while (exp > 0) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700478 uint32_t digit = 0;
479 // This optimization by miloyip reduces the number of integer divisions by
480 // one per iteration.
Victor Zverovich0de44a42018-08-26 08:12:35 -0700481 switch (exp) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700482 case 10: digit = hi / 1000000000; hi %= 1000000000; break;
483 case 9: digit = hi / 100000000; hi %= 100000000; break;
484 case 8: digit = hi / 10000000; hi %= 10000000; break;
485 case 7: digit = hi / 1000000; hi %= 1000000; break;
486 case 6: digit = hi / 100000; hi %= 100000; break;
487 case 5: digit = hi / 10000; hi %= 10000; break;
488 case 4: digit = hi / 1000; hi %= 1000; break;
489 case 3: digit = hi / 100; hi %= 100; break;
490 case 2: digit = hi / 10; hi %= 10; break;
491 case 1: digit = hi; hi = 0; break;
492 default:
493 FMT_ASSERT(false, "invalid number of digits");
494 }
495 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200496 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700497 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700498 uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
499 if (remainder <= delta) {
Victor Zverovich0de44a42018-08-26 08:12:35 -0700500 dec_exp += exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700501 // TODO: use scaled_value
502 (void)scaled_value;
503 return;
504 }
505 }
506 for (;;) {
507 lo *= 10;
508 delta *= 10;
509 char digit = static_cast<char>(lo >> -one.e);
510 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200511 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700512 lo &= one.f - 1;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700513 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700514 if (lo < delta) {
Victor Zverovich0de44a42018-08-26 08:12:35 -0700515 dec_exp += exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700516 return;
517 }
518 }
519}
520
Victor Zverovichd7f17612018-09-26 08:45:34 -0700521template <typename Double>
522FMT_FUNC void grisu2_format_positive(Double value, char *buffer, size_t &size,
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700523 int &dec_exp) {
524 FMT_ASSERT(value > 0, "value is nonpositive");
525 fp fp_value(value);
526 fp lower, upper; // w^- and w^+ in the Grisu paper.
527 fp_value.compute_boundaries(lower, upper);
528 // Find a cached power of 10 close to 1 / upper.
529 const int min_exp = -60; // alpha in Grisu.
530 auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
531 min_exp - (upper.e + fp::significand_size), dec_exp);
532 dec_exp = -dec_exp;
533 fp_value.normalize();
534 fp scaled_value = fp_value * dec_pow;
535 fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu.
536 fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu.
537 ++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
538 --scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
539 uint64_t delta = scaled_upper.f - scaled_lower.f;
540 grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp);
541}
542
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700543FMT_FUNC void round(char *buffer, size_t &size, int &exp,
544 int digits_to_remove) {
545 size -= to_unsigned(digits_to_remove);
546 exp += digits_to_remove;
547 int digit = buffer[size] - '0';
548 // TODO: proper rounding and carry
549 if (digit > 5 || (digit == 5 && (digits_to_remove > 1 ||
550 (buffer[size - 1] - '0') % 2) != 0)) {
551 ++buffer[size - 1];
552 }
553}
554
555// Writes the exponent exp in the form "[+-]d{1,3}" to buffer.
556FMT_FUNC char *write_exponent(char *buffer, int exp) {
557 FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
558 if (exp < 0) {
559 *buffer++ = '-';
560 exp = -exp;
561 } else {
562 *buffer++ = '+';
563 }
564 if (exp >= 100) {
565 *buffer++ = static_cast<char>('0' + exp / 100);
566 exp %= 100;
567 const char *d = data::DIGITS + exp * 2;
568 *buffer++ = d[0];
569 *buffer++ = d[1];
570 } else {
571 const char *d = data::DIGITS + exp * 2;
572 *buffer++ = d[0];
573 *buffer++ = d[1];
574 }
575 return buffer;
576}
577
578FMT_FUNC void format_exp_notation(
579 char *buffer, size_t &size, int exp, int precision, bool upper) {
580 // Insert a decimal point after the first digit and add an exponent.
581 std::memmove(buffer + 2, buffer + 1, size - 1);
582 buffer[1] = '.';
583 exp += static_cast<int>(size) - 1;
584 int num_digits = precision - static_cast<int>(size) + 1;
585 if (num_digits > 0) {
586 std::uninitialized_fill_n(buffer + size + 1, num_digits, '0');
587 size += to_unsigned(num_digits);
588 } else if (num_digits < 0) {
589 round(buffer, size, exp, -num_digits);
590 }
591 char *p = buffer + size + 1;
592 *p++ = upper ? 'E' : 'e';
593 size = to_unsigned(write_exponent(p, exp) - buffer);
594}
595
Victor Zverovich0de44a42018-08-26 08:12:35 -0700596// Prettifies the output of the Grisu2 algorithm.
597// The number is given as v = buffer * 10^exp.
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700598FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700599 int precision, bool upper) {
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700600 // pow(10, full_exp - 1) <= v <= pow(10, full_exp).
Victor Zveroviche483a012018-08-26 09:51:49 -0700601 int int_size = static_cast<int>(size);
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700602 int full_exp = int_size + exp;
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700603 const int exp_threshold = 21;
604 if (int_size <= full_exp && full_exp <= exp_threshold) {
605 // 1234e7 -> 12340000000[.0+]
Victor Zveroviche483a012018-08-26 09:51:49 -0700606 std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
607 char *p = buffer + full_exp;
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700608 if (precision > 0) {
Victor Zveroviche483a012018-08-26 09:51:49 -0700609 *p++ = '.';
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700610 std::uninitialized_fill_n(p, precision, '0');
611 p += precision;
Victor Zveroviche483a012018-08-26 09:51:49 -0700612 }
613 size = to_unsigned(p - buffer);
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700614 } else if (0 < full_exp && full_exp <= exp_threshold) {
615 // 1234e-2 -> 12.34[0+]
616 int fractional_size = -exp;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700617 std::memmove(buffer + full_exp + 1, buffer + full_exp,
618 to_unsigned(fractional_size));
Victor Zveroviche483a012018-08-26 09:51:49 -0700619 buffer[full_exp] = '.';
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700620 int num_zeros = precision - fractional_size;
621 if (num_zeros > 0) {
Victor Zveroviche483a012018-08-26 09:51:49 -0700622 std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0');
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700623 size += to_unsigned(num_zeros);
Victor Zveroviche483a012018-08-26 09:51:49 -0700624 }
625 ++size;
626 } else if (-6 < full_exp && full_exp <= 0) {
627 // 1234e-6 -> 0.001234
628 int offset = 2 - full_exp;
629 std::memmove(buffer + offset, buffer, size);
630 buffer[0] = '0';
631 buffer[1] = '.';
632 std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
633 size = to_unsigned(int_size + offset);
634 } else {
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700635 format_exp_notation(buffer, size, exp, precision, upper);
Victor Zveroviche483a012018-08-26 09:51:49 -0700636 }
Victor Zverovich0de44a42018-08-26 08:12:35 -0700637}
638
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700639#if FMT_CLANG_VERSION
640# define FMT_FALLTHROUGH [[clang::fallthrough]];
medithe981797f2018-09-07 17:53:15 +0200641#elif FMT_GCC_VERSION >= 700
642# define FMT_FALLTHROUGH [[gnu::fallthrough]];
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700643#else
644# define FMT_FALLTHROUGH
645#endif
Victor Zveroviche483a012018-08-26 09:51:49 -0700646
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700647// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any
648// guarantees on the shortness of the result.
Victor Zverovichd7f17612018-09-26 08:45:34 -0700649template <typename Double>
650FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t)>::type
651 grisu2_format(Double value, char *buffer, size_t &size, char type,
652 int precision, bool write_decimal_point) {
Victor Zveroviche483a012018-08-26 09:51:49 -0700653 FMT_ASSERT(value >= 0, "value is negative");
654 int dec_exp = 0; // K in Grisu.
655 if (value > 0) {
656 grisu2_format_positive(value, buffer, size, dec_exp);
657 } else {
658 *buffer = '0';
659 size = 1;
660 }
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700661 const int default_precision = 6;
662 if (precision < 0)
663 precision = default_precision;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700664 bool upper = false;
665 switch (type) {
666 case 'G':
667 upper = true;
668 FMT_FALLTHROUGH
669 case '\0': case 'g': {
670 int digits_to_remove = static_cast<int>(size) - precision;
671 if (digits_to_remove > 0) {
672 round(buffer, size, dec_exp, digits_to_remove);
673 // Remove trailing zeros.
674 while (size > 0 && buffer[size - 1] == '0') {
675 --size;
676 ++dec_exp;
677 }
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700678 }
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700679 precision = 0;
680 break;
Victor Zveroviche483a012018-08-26 09:51:49 -0700681 }
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700682 case 'F':
683 upper = true;
684 FMT_FALLTHROUGH
685 case 'f': {
686 int digits_to_remove = -dec_exp - precision;
687 if (digits_to_remove > 0) {
688 if (digits_to_remove >= static_cast<int>(size))
689 digits_to_remove = static_cast<int>(size) - 1;
690 round(buffer, size, dec_exp, digits_to_remove);
691 }
692 break;
693 }
694 case 'e': case 'E':
695 format_exp_notation(buffer, size, dec_exp, precision, type == 'E');
696 return;
697 }
698 if (write_decimal_point && precision < 1)
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700699 precision = 1;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700700 grisu2_prettify(buffer, size, dec_exp, precision, upper);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700701}
Victor Zverovichcd900972018-04-21 17:26:24 -0700702} // namespace internal
703
vitaut24c309f2015-06-12 07:15:57 -0700704#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700705
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800706FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800707 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700708 if (s.size() > INT_MAX)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800709 FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
vitautc3ba6152015-08-07 07:34:58 -0700710 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200711 if (s_size == 0) {
712 // MultiByteToWideChar does not support zero length, handle separately.
713 buffer_.resize(1);
714 buffer_[0] = 0;
715 return;
716 }
717
vitautc3ba6152015-08-07 07:34:58 -0700718 int length = MultiByteToWideChar(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800719 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700720 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800721 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700722 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700723 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700724 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700725 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800726 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700727 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700728}
729
Victor Zverovichc333dca2017-02-19 08:41:38 -0800730FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700731 if (int error_code = convert(s)) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800732 FMT_THROW(windows_error(error_code,
Victor Zverovich8b76e972014-10-06 08:30:55 -0700733 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700734 }
735}
736
Victor Zverovichc333dca2017-02-19 08:41:38 -0800737FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
vitautca747812015-08-07 07:08:46 -0700738 if (s.size() > INT_MAX)
739 return ERROR_INVALID_PARAMETER;
740 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200741 if (s_size == 0) {
742 // WideCharToMultiByte does not support zero length, handle separately.
743 buffer_.resize(1);
744 buffer_[0] = 0;
745 return 0;
746 }
747
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800748 int length = WideCharToMultiByte(
749 CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700750 if (length == 0)
751 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700752 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700753 length = WideCharToMultiByte(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800754 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700755 if (length == 0)
756 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700757 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700758 return 0;
759}
760
Victor Zverovichc333dca2017-02-19 08:41:38 -0800761FMT_FUNC void windows_error::init(
Victor Zverovich7f351de2017-12-03 09:18:06 -0800762 int err_code, string_view format_str, format_args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800763 error_code_ = err_code;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800764 memory_buffer buffer;
Victor Zveroviche022c212017-02-17 06:38:53 -0800765 internal::format_windows_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700766 std::runtime_error &base = *this;
Victor Zveroviche022c212017-02-17 06:38:53 -0800767 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700768}
769
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700770FMT_FUNC void internal::format_windows_error(
Victor Zverovichf6fd38b2018-01-15 08:22:31 -0800771 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700772 FMT_TRY {
Victor Zverovichc0954452018-01-06 09:09:50 -0800773 wmemory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800774 buf.resize(inline_buffer_size);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800775 for (;;) {
Victor Zverovichc0954452018-01-06 09:09:50 -0800776 wchar_t *system_message = &buf[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700777 int result = FormatMessageW(
778 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800779 FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
780 system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800781 if (result != 0) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800782 utf16_to_utf8 utf8_message;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800783 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800784 writer w(out);
Victor Zveroviche022c212017-02-17 06:38:53 -0800785 w.write(message);
786 w.write(": ");
787 w.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800788 return;
789 }
790 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700791 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800792 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
793 break; // Can't get error message, report error code instead.
Victor Zverovichc0954452018-01-06 09:09:50 -0800794 buf.resize(buf.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700795 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700796 } FMT_CATCH(...) {}
Victor Zverovichc0954452018-01-06 09:09:50 -0800797 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700798}
vitaut24c309f2015-06-12 07:15:57 -0700799
800#endif // FMT_USE_WINDOWS_H
801
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700802FMT_FUNC void format_system_error(
Victor Zverovichc2fecb92018-01-14 14:15:59 -0800803 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700804 FMT_TRY {
Victor Zverovich36634142017-12-26 09:00:22 -0800805 memory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800806 buf.resize(inline_buffer_size);
vitaut24c309f2015-06-12 07:15:57 -0700807 for (;;) {
Victor Zverovich36634142017-12-26 09:00:22 -0800808 char *system_message = &buf[0];
809 int result = safe_strerror(error_code, system_message, buf.size());
vitaut24c309f2015-06-12 07:15:57 -0700810 if (result == 0) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800811 writer w(out);
Victor Zverovichfefaf072017-02-14 16:29:47 -0500812 w.write(message);
813 w.write(": ");
814 w.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700815 return;
816 }
817 if (result != ERANGE)
818 break; // Can't get error message, report error code instead.
Victor Zverovich36634142017-12-26 09:00:22 -0800819 buf.resize(buf.size() * 2);
vitaut24c309f2015-06-12 07:15:57 -0700820 }
821 } FMT_CATCH(...) {}
Victor Zverovichf164e4c2018-02-01 16:49:47 -0800822 format_error_code(out, error_code, message);
vitaut24c309f2015-06-12 07:15:57 -0700823}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700824
jamboree7487bde2015-06-10 09:32:59 +0800825template <typename Char>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800826void basic_fixed_buffer<Char>::grow(std::size_t) {
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800827 FMT_THROW(std::runtime_error("buffer overflow"));
828}
829
Abdó Roig-Marangesaf0f21d2017-12-09 16:50:53 +0100830FMT_FUNC void internal::error_handler::on_error(const char *message) {
Victor Zverovich94edb1a2017-12-06 07:42:42 -0800831 FMT_THROW(format_error(message));
832}
833
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700834FMT_FUNC void report_system_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800835 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700836 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700837}
838
vitaut24c309f2015-06-12 07:15:57 -0700839#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700840FMT_FUNC void report_windows_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800841 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700842 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700843}
Victor Zverovich400812a2014-04-30 12:38:17 -0700844#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700845
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800846FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800847 memory_buffer buffer;
Victor Zverovich5bced122018-09-30 07:03:08 -0700848 vformat_to(buffer, format_str, basic_format_args<buffer_context<char>::type>(args));
Victor Zverovichfefaf072017-02-14 16:29:47 -0500849 std::fwrite(buffer.data(), 1, buffer.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700850}
851
Daniela Engert2570f1a2018-04-26 20:32:14 +0200852FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
853 wmemory_buffer buffer;
854 vformat_to(buffer, format_str, args);
855 std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
856}
857
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800858FMT_FUNC void vprint(string_view format_str, format_args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700859 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700860}
861
Daniela Engert2570f1a2018-04-26 20:32:14 +0200862FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
863 vprint(stdout, format_str, args);
864}
865
Thomas Bernardabde38b2018-08-17 11:22:56 +0200866#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800867FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
Thomas Bernardabde38b2018-08-17 11:22:56 +0200868#endif
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800869
Victor Zverovich838400d2018-05-12 08:33:51 -0700870FMT_END_NAMESPACE
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700871
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100872#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000873# pragma warning(pop)
874#endif
Victor Zverovich3da71d52018-03-21 07:50:59 -0700875
876#endif // FMT_FORMAT_INL_H_