blob: c21b1b7a2dd7df5dd8787dbb1464f25ef8282148 [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
Thomas Bernardabde38b2018-08-17 11:22:56 +0200195#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovich6ebc1a92018-05-20 17:16:34 -0700196class locale {
197 private:
198 std::locale locale_;
199
200 public:
201 explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
202 std::locale get() { return locale_; }
203};
204
Victor Zverovich2a4e9482018-07-21 09:13:21 -0700205FMT_FUNC size_t internal::count_code_points(u8string_view s) {
206 const char8_t *data = s.data();
207 int num_code_points = 0;
208 for (size_t i = 0, size = s.size(); i != size; ++i) {
209 if ((data[i].value & 0xc0) != 0x80)
210 ++num_code_points;
211 }
212 return num_code_points;
213}
214
Victor Zverovich7f351de2017-12-03 09:18:06 -0800215template <typename Char>
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800216FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
217 std::locale loc = lp ? lp->locale().get() : std::locale();
218 return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
Victor Zverovich7f351de2017-12-03 09:18:06 -0800219}
Thomas Bernardabde38b2018-08-17 11:22:56 +0200220#else
221template <typename Char>
222FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
223 return FMT_STATIC_THOUSANDS_SEPARATOR;
224}
225#endif
Victor Zverovich7f351de2017-12-03 09:18:06 -0800226
Victor Zverovichc333dca2017-02-19 08:41:38 -0800227FMT_FUNC void system_error::init(
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800228 int err_code, string_view format_str, format_args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800229 error_code_ = err_code;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800230 memory_buffer buffer;
231 format_system_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700232 std::runtime_error &base = *this;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800233 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700234}
235
Victor Zverovichcd900972018-04-21 17:26:24 -0700236namespace internal {
Victor Zverovichb605b392013-09-09 22:21:40 -0700237template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700238int char_traits<char>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700239 char *buffer, std::size_t size, const char *format, int precision, T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700240 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700241 FMT_SNPRINTF(buffer, size, format, value) :
242 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovichb605b392013-09-09 22:21:40 -0700243}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700244
Victor Zverovichb605b392013-09-09 22:21:40 -0700245template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700246int char_traits<wchar_t>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700247 wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
248 T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700249 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700250 FMT_SWPRINTF(buffer, size, format, value) :
251 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700252}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800253
Victor Zverovich311251e2014-11-29 06:58:00 -0800254template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700255const char basic_data<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800256 "0001020304050607080910111213141516171819"
257 "2021222324252627282930313233343536373839"
258 "4041424344454647484950515253545556575859"
259 "6061626364656667686970717273747576777879"
260 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800261
Victor Zverovichf1d85162014-02-19 13:02:22 -0800262#define FMT_POWERS_OF_10(factor) \
263 factor * 10, \
264 factor * 100, \
265 factor * 1000, \
266 factor * 10000, \
267 factor * 100000, \
268 factor * 1000000, \
269 factor * 10000000, \
270 factor * 100000000, \
271 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800272
Victor Zverovich311251e2014-11-29 06:58:00 -0800273template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700274const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700275 1, FMT_POWERS_OF_10(1)
276};
277
278template <typename T>
279const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800280 0, FMT_POWERS_OF_10(1)
281};
282
283template <typename T>
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700284const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800285 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800286 FMT_POWERS_OF_10(1),
Victor Zverovich016aceb2017-08-26 09:09:43 -0700287 FMT_POWERS_OF_10(1000000000ull),
288 10000000000000000000ull
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800289};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800290
Victor Zverovich2768af22018-04-29 06:33:05 -0700291// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
292// These are generated by support/compute-powers.py.
293template <typename T>
294const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
Victor Zverovich9de31212018-08-15 06:54:43 -0700295 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
296 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
297 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
298 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
299 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
300 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
301 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
302 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
303 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
304 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
305 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
306 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
307 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
308 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
309 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
310 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
311 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
312 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
313 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
314 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
315 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
316 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
317 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
318 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
319 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
320 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
321 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
322 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
323 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
Victor Zverovich2768af22018-04-29 06:33:05 -0700324};
325
326// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
327// to significands above.
328template <typename T>
329const int16_t basic_data<T>::POW10_EXPONENTS[] = {
330 -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
331 -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
332 -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
333 -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
334 -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
335 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
336 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
337 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
338};
339
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530340template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
341template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
342
Victor Zverovichcd900972018-04-21 17:26:24 -0700343FMT_FUNC fp operator*(fp x, fp y) {
344 // Multiply 32-bit parts of significands.
345 uint64_t mask = (1ULL << 32) - 1;
346 uint64_t a = x.f >> 32, b = x.f & mask;
347 uint64_t c = y.f >> 32, d = y.f & mask;
348 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
349 // Compute mid 64-bit of result and round.
350 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
Daniela Engert6cd66612018-04-30 10:07:43 +0200351 return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
Victor Zverovichcd900972018-04-21 17:26:24 -0700352}
Victor Zverovich468c2432018-05-27 10:57:26 -0700353
354FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
355 const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
356 int index = static_cast<int>(std::ceil(
Victor Zverovich4e4b8572018-05-28 11:25:07 -0700357 (min_exponent + fp::significand_size - 1) * one_over_log2_10));
Victor Zverovich468c2432018-05-27 10:57:26 -0700358 // Decimal exponent of the first (smallest) cached power of 10.
359 const int first_dec_exp = -348;
Victor Zverovich9de31212018-08-15 06:54:43 -0700360 // Difference between 2 consecutive decimal exponents in cached powers of 10.
Victor Zverovich468c2432018-05-27 10:57:26 -0700361 const int dec_exp_step = 8;
362 index = (index - first_dec_exp - 1) / dec_exp_step + 1;
363 pow10_exponent = first_dec_exp + index * dec_exp_step;
364 return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
365}
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700366
Victor Zveroviche483a012018-08-26 09:51:49 -0700367// Writes the exponent exp in the form "[+-]d{1,3}" to buffer.
Victor Zverovich0de44a42018-08-26 08:12:35 -0700368FMT_FUNC char *write_exponent(char *buffer, int exp) {
369 FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
370 if (exp < 0) {
371 *buffer++ = '-';
372 exp = -exp;
Victor Zveroviche483a012018-08-26 09:51:49 -0700373 } else {
374 *buffer++ = '+';
Victor Zverovich0de44a42018-08-26 08:12:35 -0700375 }
376 if (exp >= 100) {
medithe95a71892018-08-29 15:38:56 +0200377 *buffer++ = static_cast<char>('0' + exp / 100);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700378 exp %= 100;
379 const char *d = data::DIGITS + exp * 2;
380 *buffer++ = d[0];
381 *buffer++ = d[1];
382 } else if (exp >= 10) {
383 const char *d = data::DIGITS + exp * 2;
384 *buffer++ = d[0];
385 *buffer++ = d[1];
386 } else {
medithe95a71892018-08-29 15:38:56 +0200387 *buffer++ = static_cast<char>('0' + exp);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700388 }
389 return buffer;
390}
391
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700392// Generates output using Grisu2 digit-gen algorithm.
393FMT_FUNC void grisu2_gen_digits(
394 const fp &scaled_value, const fp &scaled_upper, uint64_t delta,
395 char *buffer, size_t &size, int &dec_exp) {
396 internal::fp one(1ull << -scaled_upper.e, scaled_upper.e);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700397 // hi (p1 in Grisu) contains the most significant digits of scaled_upper.
398 // hi = floor(scaled_upper / one).
399 uint32_t hi = static_cast<uint32_t>(scaled_upper.f >> -one.e);
400 // lo (p2 in Grisu) contains the least significants digits of scaled_upper.
401 // lo = scaled_upper mod 1.
402 uint64_t lo = scaled_upper.f & (one.f - 1);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700403 size = 0;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700404 auto exp = count_digits(hi); // kappa in Grisu.
405 while (exp > 0) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700406 uint32_t digit = 0;
407 // This optimization by miloyip reduces the number of integer divisions by
408 // one per iteration.
Victor Zverovich0de44a42018-08-26 08:12:35 -0700409 switch (exp) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700410 case 10: digit = hi / 1000000000; hi %= 1000000000; break;
411 case 9: digit = hi / 100000000; hi %= 100000000; break;
412 case 8: digit = hi / 10000000; hi %= 10000000; break;
413 case 7: digit = hi / 1000000; hi %= 1000000; break;
414 case 6: digit = hi / 100000; hi %= 100000; break;
415 case 5: digit = hi / 10000; hi %= 10000; break;
416 case 4: digit = hi / 1000; hi %= 1000; break;
417 case 3: digit = hi / 100; hi %= 100; break;
418 case 2: digit = hi / 10; hi %= 10; break;
419 case 1: digit = hi; hi = 0; break;
420 default:
421 FMT_ASSERT(false, "invalid number of digits");
422 }
423 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200424 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700425 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700426 uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
427 if (remainder <= delta) {
Victor Zverovich0de44a42018-08-26 08:12:35 -0700428 dec_exp += exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700429 // TODO: use scaled_value
430 (void)scaled_value;
431 return;
432 }
433 }
434 for (;;) {
435 lo *= 10;
436 delta *= 10;
437 char digit = static_cast<char>(lo >> -one.e);
438 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200439 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700440 lo &= one.f - 1;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700441 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700442 if (lo < delta) {
Victor Zverovich0de44a42018-08-26 08:12:35 -0700443 dec_exp += exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700444 return;
445 }
446 }
447}
448
Victor Zverovich0de44a42018-08-26 08:12:35 -0700449// Prettifies the output of the Grisu2 algorithm.
450// The number is given as v = buffer * 10^exp.
Victor Zveroviche483a012018-08-26 09:51:49 -0700451FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp, char type,
452 size_t precision, bool print_decimal_point) {
453 int int_size = static_cast<int>(size);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700454 // 10^(full_exp - 1) <= v <= 10^full_exp.
Victor Zveroviche483a012018-08-26 09:51:49 -0700455 int full_exp = int_size + exp;
456 if (int_size <= full_exp && full_exp <= 21) {
457 // 1234e7 -> 12340000000
458 std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
459 char *p = buffer + full_exp;
460 if (print_decimal_point && size < precision) {
461 *p++ = '.';
462 auto fill_size = precision - size;
463 std::uninitialized_fill_n(p, fill_size, '0');
464 p += fill_size;
465 }
466 size = to_unsigned(p - buffer);
467 } else if (0 < full_exp && full_exp <= 21) {
468 // 1234e-2 -> 12.34
469 size_t fractional_size = to_unsigned(int_size - full_exp);
470 std::memmove(buffer + full_exp + 1, buffer + full_exp, fractional_size);
471 buffer[full_exp] = '.';
472 if (type == 'f' && fractional_size < precision) {
473 size_t num_zeros = precision - fractional_size;
474 std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0');
475 size += num_zeros;
476 }
477 ++size;
478 } else if (-6 < full_exp && full_exp <= 0) {
479 // 1234e-6 -> 0.001234
480 int offset = 2 - full_exp;
481 std::memmove(buffer + offset, buffer, size);
482 buffer[0] = '0';
483 buffer[1] = '.';
484 std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
485 size = to_unsigned(int_size + offset);
486 } else {
487 // Insert a decimal point after the first digit and add an exponent.
488 std::memmove(buffer + 2, buffer + 1, size - 1);
489 buffer[1] = '.';
490 char *p = buffer + size + 1;
491 *p++ = 'e';
492 size = to_unsigned(write_exponent(p, full_exp - 1) - buffer);
493 }
Victor Zverovich0de44a42018-08-26 08:12:35 -0700494}
495
Victor Zveroviche483a012018-08-26 09:51:49 -0700496FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size,
497 int &dec_exp) {
498 FMT_ASSERT(value > 0, "value is nonpositive");
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700499 fp fp_value(value);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700500 fp lower, upper; // w^- and w^+ in the Grisu paper.
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700501 fp_value.compute_boundaries(lower, upper);
502 // Find a cached power of 10 close to 1 / upper.
Victor Zverovich0de44a42018-08-26 08:12:35 -0700503 const int min_exp = -60; // alpha in Grisu.
504 auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700505 min_exp - (upper.e + fp::significand_size), dec_exp);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700506 dec_exp = -dec_exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700507 fp_value.normalize();
508 fp scaled_value = fp_value * dec_pow;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700509 fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu.
510 fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu.
511 ++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
512 --scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700513 uint64_t delta = scaled_upper.f - scaled_lower.f;
514 grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp);
Victor Zveroviche483a012018-08-26 09:51:49 -0700515}
516
517// Formats value using Grisu2 algorithm. Grisu2 doesn't give any guarantees on
518// the shortness of the result.
519FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type,
520 int precision, bool print_decimal_point) {
521 FMT_ASSERT(value >= 0, "value is negative");
522 int dec_exp = 0; // K in Grisu.
523 if (value > 0) {
524 grisu2_format_positive(value, buffer, size, dec_exp);
525 } else {
526 *buffer = '0';
527 size = 1;
528 }
529 size_t unsigned_precision = precision >= 0 ? precision : 6;
530 if (size > unsigned_precision) {
531 // TODO: round instead of truncating
medithe95a71892018-08-29 15:38:56 +0200532 dec_exp += static_cast<int>(size - unsigned_precision);
Victor Zveroviche483a012018-08-26 09:51:49 -0700533 size = unsigned_precision;
534 }
535 grisu2_prettify(buffer, size, dec_exp, type, unsigned_precision,
536 print_decimal_point);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700537}
Victor Zverovichcd900972018-04-21 17:26:24 -0700538} // namespace internal
539
vitaut24c309f2015-06-12 07:15:57 -0700540#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700541
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800542FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800543 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700544 if (s.size() > INT_MAX)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800545 FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
vitautc3ba6152015-08-07 07:34:58 -0700546 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200547 if (s_size == 0) {
548 // MultiByteToWideChar does not support zero length, handle separately.
549 buffer_.resize(1);
550 buffer_[0] = 0;
551 return;
552 }
553
vitautc3ba6152015-08-07 07:34:58 -0700554 int length = MultiByteToWideChar(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800555 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700556 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800557 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700558 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700559 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700560 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700561 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800562 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700563 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700564}
565
Victor Zverovichc333dca2017-02-19 08:41:38 -0800566FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700567 if (int error_code = convert(s)) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800568 FMT_THROW(windows_error(error_code,
Victor Zverovich8b76e972014-10-06 08:30:55 -0700569 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700570 }
571}
572
Victor Zverovichc333dca2017-02-19 08:41:38 -0800573FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
vitautca747812015-08-07 07:08:46 -0700574 if (s.size() > INT_MAX)
575 return ERROR_INVALID_PARAMETER;
576 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200577 if (s_size == 0) {
578 // WideCharToMultiByte does not support zero length, handle separately.
579 buffer_.resize(1);
580 buffer_[0] = 0;
581 return 0;
582 }
583
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800584 int length = WideCharToMultiByte(
585 CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700586 if (length == 0)
587 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700588 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700589 length = WideCharToMultiByte(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800590 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700591 if (length == 0)
592 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700593 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700594 return 0;
595}
596
Victor Zverovichc333dca2017-02-19 08:41:38 -0800597FMT_FUNC void windows_error::init(
Victor Zverovich7f351de2017-12-03 09:18:06 -0800598 int err_code, string_view format_str, format_args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800599 error_code_ = err_code;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800600 memory_buffer buffer;
Victor Zveroviche022c212017-02-17 06:38:53 -0800601 internal::format_windows_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700602 std::runtime_error &base = *this;
Victor Zveroviche022c212017-02-17 06:38:53 -0800603 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700604}
605
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700606FMT_FUNC void internal::format_windows_error(
Victor Zverovichf6fd38b2018-01-15 08:22:31 -0800607 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700608 FMT_TRY {
Victor Zverovichc0954452018-01-06 09:09:50 -0800609 wmemory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800610 buf.resize(inline_buffer_size);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800611 for (;;) {
Victor Zverovichc0954452018-01-06 09:09:50 -0800612 wchar_t *system_message = &buf[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700613 int result = FormatMessageW(
614 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800615 FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
616 system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800617 if (result != 0) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800618 utf16_to_utf8 utf8_message;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800619 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800620 writer w(out);
Victor Zveroviche022c212017-02-17 06:38:53 -0800621 w.write(message);
622 w.write(": ");
623 w.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800624 return;
625 }
626 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700627 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800628 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
629 break; // Can't get error message, report error code instead.
Victor Zverovichc0954452018-01-06 09:09:50 -0800630 buf.resize(buf.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700631 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700632 } FMT_CATCH(...) {}
Victor Zverovichc0954452018-01-06 09:09:50 -0800633 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700634}
vitaut24c309f2015-06-12 07:15:57 -0700635
636#endif // FMT_USE_WINDOWS_H
637
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700638FMT_FUNC void format_system_error(
Victor Zverovichc2fecb92018-01-14 14:15:59 -0800639 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700640 FMT_TRY {
Victor Zverovich36634142017-12-26 09:00:22 -0800641 memory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800642 buf.resize(inline_buffer_size);
vitaut24c309f2015-06-12 07:15:57 -0700643 for (;;) {
Victor Zverovich36634142017-12-26 09:00:22 -0800644 char *system_message = &buf[0];
645 int result = safe_strerror(error_code, system_message, buf.size());
vitaut24c309f2015-06-12 07:15:57 -0700646 if (result == 0) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800647 writer w(out);
Victor Zverovichfefaf072017-02-14 16:29:47 -0500648 w.write(message);
649 w.write(": ");
650 w.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700651 return;
652 }
653 if (result != ERANGE)
654 break; // Can't get error message, report error code instead.
Victor Zverovich36634142017-12-26 09:00:22 -0800655 buf.resize(buf.size() * 2);
vitaut24c309f2015-06-12 07:15:57 -0700656 }
657 } FMT_CATCH(...) {}
Victor Zverovichf164e4c2018-02-01 16:49:47 -0800658 format_error_code(out, error_code, message);
vitaut24c309f2015-06-12 07:15:57 -0700659}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700660
jamboree7487bde2015-06-10 09:32:59 +0800661template <typename Char>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800662void basic_fixed_buffer<Char>::grow(std::size_t) {
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800663 FMT_THROW(std::runtime_error("buffer overflow"));
664}
665
Abdó Roig-Marangesaf0f21d2017-12-09 16:50:53 +0100666FMT_FUNC void internal::error_handler::on_error(const char *message) {
Victor Zverovich94edb1a2017-12-06 07:42:42 -0800667 FMT_THROW(format_error(message));
668}
669
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700670FMT_FUNC void report_system_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800671 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700672 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700673}
674
vitaut24c309f2015-06-12 07:15:57 -0700675#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700676FMT_FUNC void report_windows_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800677 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700678 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700679}
Victor Zverovich400812a2014-04-30 12:38:17 -0700680#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700681
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800682FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800683 memory_buffer buffer;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500684 vformat_to(buffer, format_str, args);
685 std::fwrite(buffer.data(), 1, buffer.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700686}
687
Daniela Engert2570f1a2018-04-26 20:32:14 +0200688FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
689 wmemory_buffer buffer;
690 vformat_to(buffer, format_str, args);
691 std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
692}
693
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800694FMT_FUNC void vprint(string_view format_str, format_args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700695 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700696}
697
Daniela Engert2570f1a2018-04-26 20:32:14 +0200698FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
699 vprint(stdout, format_str, args);
700}
701
Remotionce500632018-06-09 00:33:39 +0200702#ifndef FMT_EXTENDED_COLORS
Victor Zverovichbb471092018-03-04 11:25:40 -0800703FMT_FUNC void vprint_colored(color c, string_view format, format_args args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700704 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100705 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700706 std::fputs(escape, stdout);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700707 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530708 std::fputs(internal::data::RESET_COLOR, stdout);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700709}
710
Daniela Engert2570f1a2018-04-26 20:32:14 +0200711FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args) {
712 wchar_t escape[] = L"\x1b[30m";
713 escape[3] = static_cast<wchar_t>('0' + c);
714 std::fputws(escape, stdout);
715 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530716 std::fputws(internal::data::WRESET_COLOR, stdout);
Daniela Engert2570f1a2018-04-26 20:32:14 +0200717}
Remotionce500632018-06-09 00:33:39 +0200718#else
719namespace internal {
720FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) {
721 out[offset + 0] = static_cast<char>('0' + c / 100);
722 out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
723 out[offset + 2] = static_cast<char>('0' + c % 10);
724}
725} // namespace internal
726
727FMT_FUNC void vprint_rgb(rgb fd, string_view format, format_args args) {
728 char escape_fd[] = "\x1b[38;2;000;000;000m";
Remotionce500632018-06-09 00:33:39 +0200729 internal::to_esc(fd.r, escape_fd, 7);
730 internal::to_esc(fd.g, escape_fd, 11);
731 internal::to_esc(fd.b, escape_fd, 15);
732
733 std::fputs(escape_fd, stdout);
734 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530735 std::fputs(internal::data::RESET_COLOR, stdout);
Remotionce500632018-06-09 00:33:39 +0200736}
737
738FMT_FUNC void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) {
739 char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
740 char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
Remotionce500632018-06-09 00:33:39 +0200741 internal::to_esc(fd.r, escape_fd, 7);
742 internal::to_esc(fd.g, escape_fd, 11);
743 internal::to_esc(fd.b, escape_fd, 15);
744
745 internal::to_esc(bg.r, escape_bg, 7);
746 internal::to_esc(bg.g, escape_bg, 11);
747 internal::to_esc(bg.b, escape_bg, 15);
748
749 std::fputs(escape_fd, stdout);
750 std::fputs(escape_bg, stdout);
751 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530752 std::fputs(internal::data::RESET_COLOR, stdout);
Remotionce500632018-06-09 00:33:39 +0200753}
754#endif
Thomas Bernardabde38b2018-08-17 11:22:56 +0200755#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800756FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
Thomas Bernardabde38b2018-08-17 11:22:56 +0200757#endif
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800758
Victor Zverovich838400d2018-05-12 08:33:51 -0700759FMT_END_NAMESPACE
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700760
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100761#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000762# pragma warning(pop)
763#endif
Victor Zverovich3da71d52018-03-21 07:50:59 -0700764
765#endif // FMT_FORMAT_INL_H_