Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
format.cc
Go to the documentation of this file.
1/*
2 Formatting library for C++
3
4 Copyright (c) 2012 - 2016, Victor Zverovich
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "format.h"
29
30#include <string.h>
31
32#include <cctype>
33#include <cerrno>
34#include <climits>
35#include <cmath>
36#include <cstdarg>
37#include <cstddef> // for std::ptrdiff_t
38
39#if defined(_WIN32) && defined(__MINGW32__)
40# include <cstring>
41#endif
42
44# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
45# define WIN32_LEAN_AND_MEAN
46# endif
47# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
48# include <windows.h>
49# else
50# define NOMINMAX
51# include <windows.h>
52# undef NOMINMAX
53# endif
54#endif
55
57# define FMT_TRY try
58# define FMT_CATCH(x) catch (x)
59#else
60# define FMT_TRY if (true)
61# define FMT_CATCH(x) if (false)
62#endif
63
64#ifdef _MSC_VER
65# pragma warning(push)
66# pragma warning(disable: 4127) // conditional expression is constant
67# pragma warning(disable: 4702) // unreachable code
68// Disable deprecation warning for strerror. The latter is not called but
69// MSVC fails to detect it.
70# pragma warning(disable: 4996)
71#endif
72
73// Dummy implementations of strerror_r and strerror_s called if corresponding
74// system functions are not available.
76static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
77 return fmt::internal::Null<>();
78}
80static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
81 return fmt::internal::Null<>();
82}
83
84namespace fmt {
85
86FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
89
90namespace {
91
92#ifndef _MSC_VER
93# define FMT_SNPRINTF snprintf
94#else // _MSC_VER
95inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
96 va_list args;
97 va_start(args, format);
98 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
99 va_end(args);
100 return result;
101}
102# define FMT_SNPRINTF fmt_snprintf
103#endif // _MSC_VER
104
105#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
106# define FMT_SWPRINTF snwprintf
107#else
108# define FMT_SWPRINTF swprintf
109#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
110
111const char RESET_COLOR[] = "\x1b[0m";
112
113typedef void (*FormatFunc)(Writer &, int, StringRef);
114
115// Portable thread-safe version of strerror.
116// Sets buffer to point to a string describing the error code.
117// This can be either a pointer to a string stored in buffer,
118// or a pointer to some static immutable string.
119// Returns one of the following values:
120// 0 - success
121// ERANGE - buffer is not large enough to store the error message
122// other - failure
123// Buffer should be at least of size 1.
125 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
126 FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
127
128 class StrError {
129 private:
130 int error_code_;
131 char *&buffer_;
132 std::size_t buffer_size_;
133
134 // A noop assignment operator to avoid bogus warnings.
135 void operator=(const StrError &) {}
136
137 // Handle the result of XSI-compliant version of strerror_r.
138 int handle(int result) {
139 // glibc versions before 2.13 return result in errno.
140 return result == -1 ? errno : result;
141 }
142
143 // Handle the result of GNU-specific version of strerror_r.
144 int handle(char *message) {
145 // If the buffer is full then the message is probably truncated.
146 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
147 return ERANGE;
148 buffer_ = message;
149 return 0;
150 }
151
152 // Handle the case when strerror_r is not available.
153 int handle(internal::Null<>) {
154 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
155 }
156
157 // Fallback to strerror_s when strerror_r is not available.
158 int fallback(int result) {
159 // If the buffer is full then the message is probably truncated.
160 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
161 ERANGE : result;
162 }
163
164#ifdef __c2__
165# pragma clang diagnostic push
166# pragma clang diagnostic ignored "-Wdeprecated-declarations"
167#endif
168
169 // Fallback to strerror if strerror_r and strerror_s are not available.
170 int fallback(internal::Null<>) {
171 errno = 0;
172 buffer_ = strerror(error_code_);
173 return errno;
174 }
175
176#ifdef __c2__
177# pragma clang diagnostic pop
178#endif
179
180 public:
181 StrError(int err_code, char *&buf, std::size_t buf_size)
182 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
183
184 int run() {
185 return handle(strerror_r(error_code_, buffer_, buffer_size_));
186 }
187 };
188 return StrError(error_code, buffer, buffer_size).run();
189}
190
191void format_error_code(Writer &out, int error_code,
192 StringRef message) FMT_NOEXCEPT {
193 // Report error code making sure that the output fits into
194 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
195 // bad_alloc.
196 out.clear();
197 static const char SEP[] = ": ";
198 static const char ERROR_STR[] = "error ";
199 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
200 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
201 typedef internal::IntTraits<int>::MainType MainType;
202 MainType abs_value = static_cast<MainType>(error_code);
203 if (internal::is_negative(error_code)) {
204 abs_value = 0 - abs_value;
205 ++error_code_size;
206 }
207 error_code_size += internal::count_digits(abs_value);
208 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
209 out << message << SEP;
210 out << ERROR_STR << error_code;
211 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
212}
213
214void report_error(FormatFunc func, int error_code,
215 StringRef message) FMT_NOEXCEPT {
216 MemoryWriter full_message;
217 func(full_message, error_code, message);
218 // Use Writer::data instead of Writer::c_str to avoid potential memory
219 // allocation.
220 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
221 std::fputc('\n', stderr);
222}
223} // namespace
224
226 int err_code, CStringRef format_str, ArgList args) {
227 error_code_ = err_code;
228 MemoryWriter w;
229 format_system_error(w, err_code, format(format_str, args));
230 std::runtime_error &base = *this;
231 base = std::runtime_error(w.str());
232}
233
234template <typename T>
235int internal::CharTraits<char>::format_float(
236 char *buffer, std::size_t size, const char *format,
237 unsigned width, int precision, T value) {
238 if (width == 0) {
239 return precision < 0 ?
240 FMT_SNPRINTF(buffer, size, format, value) :
241 FMT_SNPRINTF(buffer, size, format, precision, value);
242 }
243 return precision < 0 ?
244 FMT_SNPRINTF(buffer, size, format, width, value) :
245 FMT_SNPRINTF(buffer, size, format, width, precision, value);
246}
247
248template <typename T>
249int internal::CharTraits<wchar_t>::format_float(
250 wchar_t *buffer, std::size_t size, const wchar_t *format,
251 unsigned width, int precision, T value) {
252 if (width == 0) {
253 return precision < 0 ?
254 FMT_SWPRINTF(buffer, size, format, value) :
255 FMT_SWPRINTF(buffer, size, format, precision, value);
256 }
257 return precision < 0 ?
258 FMT_SWPRINTF(buffer, size, format, width, value) :
259 FMT_SWPRINTF(buffer, size, format, width, precision, value);
260}
261
262template <typename T>
263const char internal::BasicData<T>::DIGITS[] =
264 "0001020304050607080910111213141516171819"
265 "2021222324252627282930313233343536373839"
266 "4041424344454647484950515253545556575859"
267 "6061626364656667686970717273747576777879"
268 "8081828384858687888990919293949596979899";
269
270#define FMT_POWERS_OF_10(factor)
271 factor * 10,
272 factor * 100,
273 factor * 1000,
274 factor * 10000,
275 factor * 100000,
276 factor * 1000000,
277 factor * 10000000,
278 factor * 100000000,
279 factor * 1000000000
280
281template <typename T>
282const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
283 0, FMT_POWERS_OF_10(1)
284};
285
286template <typename T>
287const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
288 0,
290 FMT_POWERS_OF_10(ULongLong(1000000000)),
291 // Multiply several constants instead of using a single long long constant
292 // to avoid warnings about C++98 not supporting long long.
293 ULongLong(1000000000) * ULongLong(1000000000) * 10
294};
295
296FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
297 (void)type;
298 if (std::isprint(static_cast<unsigned char>(code))) {
300 format("unknown format code '{}' for {}", code, type)));
301 }
303 format("unknown format code '\\x{:02x}' for {}",
304 static_cast<unsigned>(code), type)));
305}
306
308
309FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
310 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
311 if (s.size() > INT_MAX)
312 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
313 int s_size = static_cast<int>(s.size());
314 int length = MultiByteToWideChar(
315 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
316 if (length == 0)
317 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
318 buffer_.resize(length + 1);
319 length = MultiByteToWideChar(
320 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
321 if (length == 0)
322 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
323 buffer_[length] = 0;
324}
325
326FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
327 if (int error_code = convert(s)) {
328 FMT_THROW(WindowsError(error_code,
329 "cannot convert string from UTF-16 to UTF-8"));
330 }
331}
332
333FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
334 if (s.size() > INT_MAX)
335 return ERROR_INVALID_PARAMETER;
336 int s_size = static_cast<int>(s.size());
337 int length = WideCharToMultiByte(
338 CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
339 if (length == 0)
340 return GetLastError();
341 buffer_.resize(length + 1);
342 length = WideCharToMultiByte(
343 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
344 if (length == 0)
345 return GetLastError();
346 buffer_[length] = 0;
347 return 0;
348}
349
350FMT_FUNC void WindowsError::init(
351 int err_code, CStringRef format_str, ArgList args) {
352 error_code_ = err_code;
353 MemoryWriter w;
354 internal::format_windows_error(w, err_code, format(format_str, args));
355 std::runtime_error &base = *this;
356 base = std::runtime_error(w.str());
357}
358
359FMT_FUNC void internal::format_windows_error(
360 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
361 FMT_TRY {
362 MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
363 buffer.resize(INLINE_BUFFER_SIZE);
364 for (;;) {
365 wchar_t *system_message = &buffer[0];
366 int result = FormatMessageW(
367 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
368 FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
369 system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
370 if (result != 0) {
371 UTF16ToUTF8 utf8_message;
372 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
373 out << message << ": " << utf8_message;
374 return;
375 }
376 break;
377 }
378 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
379 break; // Can't get error message, report error code instead.
380 buffer.resize(buffer.size() * 2);
381 }
382 } FMT_CATCH(...) {}
383 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
384}
385
386#endif // FMT_USE_WINDOWS_H
387
388FMT_FUNC void format_system_error(
389 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
390 FMT_TRY {
391 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
392 buffer.resize(internal::INLINE_BUFFER_SIZE);
393 for (;;) {
394 char *system_message = &buffer[0];
395 int result = safe_strerror(error_code, system_message, buffer.size());
396 if (result == 0) {
397 out << message << ": " << system_message;
398 return;
399 }
400 if (result != ERANGE)
401 break; // Can't get error message, report error code instead.
402 buffer.resize(buffer.size() * 2);
403 }
404 } FMT_CATCH(...) {}
405 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
406}
407
408template <typename Char>
409void internal::FixedBuffer<Char>::grow(std::size_t) {
410 FMT_THROW(std::runtime_error("buffer overflow"));
411}
412
414 unsigned arg_index, const char *&error) {
415 internal::Arg arg = args_[arg_index];
416 switch (arg.type) {
417 case internal::Arg::NONE:
418 error = "argument index out of range";
419 break;
420 case internal::Arg::NAMED_ARG:
421 arg = *static_cast<const internal::Arg*>(arg.pointer);
422 break;
423 default:
424 /*nothing*/;
425 }
426 return arg;
427}
428
429FMT_FUNC void report_system_error(
430 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
431 // 'fmt::' is for bcc32.
432 report_error(format_system_error, error_code, message);
433}
434
436FMT_FUNC void report_windows_error(
437 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
438 // 'fmt::' is for bcc32.
439 report_error(internal::format_windows_error, error_code, message);
440}
441#endif
442
443FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
444 MemoryWriter w;
445 w.write(format_str, args);
446 std::fwrite(w.data(), 1, w.size(), f);
447}
448
449FMT_FUNC void print(CStringRef format_str, ArgList args) {
450 print(stdout, format_str, args);
451}
452
453FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
454 char escape[] = "\x1b[30m";
455 escape[3] = static_cast<char>('0' + c);
456 std::fputs(escape, stdout);
457 print(format, args);
458 std::fputs(RESET_COLOR, stdout);
459}
460
461#ifndef FMT_HEADER_ONLY
462
463template struct internal::BasicData<void>;
464
465// Explicit instantiations for char.
466
467template void internal::FixedBuffer<char>::grow(std::size_t);
468
469template FMT_API int internal::CharTraits<char>::format_float(
470 char *buffer, std::size_t size, const char *format,
471 unsigned width, int precision, double value);
472
473template FMT_API int internal::CharTraits<char>::format_float(
474 char *buffer, std::size_t size, const char *format,
475 unsigned width, int precision, long double value);
476
477// Explicit instantiations for wchar_t.
478
479template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
480
481template FMT_API int internal::CharTraits<wchar_t>::format_float(
482 wchar_t *buffer, std::size_t size, const wchar_t *format,
483 unsigned width, int precision, double value);
484
485template FMT_API int internal::CharTraits<wchar_t>::format_float(
486 wchar_t *buffer, std::size_t size, const wchar_t *format,
487 unsigned width, int precision, long double value);
488
489#endif // FMT_HEADER_ONLY
490
491} // namespace fmt
492
493#ifdef _MSC_VER
494# pragma warning(pop)
495#endif
FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE
Definition format.cc:87
FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE
Definition format.cc:88
int format_float(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value)
Definition format.cc:235
int format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value)
Definition format.cc:249
FMT_API Arg do_get_arg(unsigned arg_index, const char *&error)
Definition format.cc:413
#define FMT_TRY
Definition format.cc:57
static FMT_MAYBE_UNUSED fmt::internal::Null strerror_r(int, char *,...)
Definition format.cc:76
#define FMT_SWPRINTF
Definition format.cc:108
#define FMT_SNPRINTF
Definition format.cc:93
#define FMT_CATCH(x)
Definition format.cc:58
#define FMT_POWERS_OF_10(factor)
Definition format.cc:270
static FMT_MAYBE_UNUSED fmt::internal::Null strerror_s(char *, std::size_t,...)
Definition format.cc:80
#define FMT_FUNC
Definition format.h:4170
#define FMT_ASSERT(condition, message)
Definition format.h:337
#define FMT_EXCEPTIONS
Definition format.h:217
#define FMT_MAYBE_UNUSED
Definition format.h:170
#define FMT_USE_WINDOWS_H
Definition format.h:1115
#define FMT_API
Definition format.h:94
#define FMT_DTOR_NOEXCEPT
Definition format.h:254
#define FMT_THROW(x)
Definition format.h:222
#define FMT_NOEXCEPT
Definition format.h:243
#define FMT_NULL
Definition format.h:273
int safe_strerror(int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT
Definition format.cc:124
void format_error_code(Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
Definition format.cc:191
void report_error(FormatFunc func, int error_code, StringRef message) FMT_NOEXCEPT
Definition format.cc:214
void(* FormatFunc)(Writer &, int, StringRef)
Definition format.cc:113
Definition format.h:408
Color
Definition format.h:3424
Definition json.hpp:4518