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 // commented out by spdlog
29 // #include "format.h"
30 // #include "printf.h"
31
32 #include <string.h>
33
34 #include <cctype>
35 #include <cerrno>
36 #include <climits>
37 #include <cmath>
38 #include <cstdarg>
39 #include <cstddef> // for std::ptrdiff_t
40
41 #if defined(_WIN32) && defined(__MINGW32__)
42 # include <cstring>
43 #endif
44
45 #if FMT_USE_WINDOWS_H
46 # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
47 # include <windows.h>
48 # else
49 # define NOMINMAX
50 # include <windows.h>
51 # undef NOMINMAX
52 # endif
53 #endif
54
55 using fmt::internal::Arg;
56
57 #if FMT_EXCEPTIONS
58 # define FMT_TRY try
59 # define FMT_CATCH(x) catch (x)
60 #else
61 # define FMT_TRY if (true)
62 # define FMT_CATCH(x) if (false)
63 #endif
64
65 #ifdef _MSC_VER
66 # pragma warning(push)
67 # pragma warning(disable: 4127) // conditional expression is constant
68 # pragma warning(disable: 4702) // unreachable code
69 // Disable deprecation warning for strerror. The latter is not called but
70 // MSVC fails to detect it.
71 # pragma warning(disable: 4996)
72 #endif
73
74 // Dummy implementations of strerror_r and strerror_s called if corresponding
75 // system functions are not available.
strerror_r(int,char *,...)76 static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
77 return fmt::internal::Null<>();
78 }
strerror_s(char *,std::size_t,...)79 static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
80 return fmt::internal::Null<>();
81 }
82
83 namespace fmt {
84
~RuntimeError()85 FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {}
~FormatError()86 FMT_FUNC FormatError::~FormatError() throw() {}
~SystemError()87 FMT_FUNC SystemError::~SystemError() throw() {}
88
89 namespace {
90
91 #ifndef _MSC_VER
92 # define FMT_SNPRINTF snprintf
93 #else // _MSC_VER
94 inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
95 va_list args;
96 va_start(args, format);
97 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
98 va_end(args);
99 return result;
100 }
101 # define FMT_SNPRINTF fmt_snprintf
102 #endif // _MSC_VER
103
104 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
105 # define FMT_SWPRINTF snwprintf
106 #else
107 # define FMT_SWPRINTF swprintf
108 #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
109
110 const char RESET_COLOR[] = "\x1b[0m";
111
112 typedef void(*FormatFunc)(Writer &, int, StringRef);
113
114 // Portable thread-safe version of strerror.
115 // Sets buffer to point to a string describing the error code.
116 // This can be either a pointer to a string stored in buffer,
117 // or a pointer to some static immutable string.
118 // Returns one of the following values:
119 // 0 - success
120 // ERANGE - buffer is not large enough to store the error message
121 // other - failure
122 // Buffer should be at least of size 1.
safe_strerror(int error_code,char * & buffer,std::size_t buffer_size)123 int safe_strerror(
124 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{
125 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
126
127 class StrError {
128 private:
129 int error_code_;
130 char *&buffer_;
131 std::size_t buffer_size_;
132
133 // A noop assignment operator to avoid bogus warnings.
134 void operator=(const StrError &) {}
135
136 // Handle the result of XSI-compliant version of strerror_r.
137 int handle(int result) {
138 // glibc versions before 2.13 return result in errno.
139 return result == -1 ? errno : result;
140 }
141
142 // Handle the result of GNU-specific version of strerror_r.
143 int handle(char *message) {
144 // If the buffer is full then the message is probably truncated.
145 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
146 return ERANGE;
147 buffer_ = message;
148 return 0;
149 }
150
151 // Handle the case when strerror_r is not available.
152 int handle(internal::Null<>) {
153 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
154 }
155
156 // Fallback to strerror_s when strerror_r is not available.
157 int fallback(int result) {
158 // If the buffer is full then the message is probably truncated.
159 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
160 ERANGE : result;
161 }
162
163 // Fallback to strerror if strerror_r and strerror_s are not available.
164 int fallback(internal::Null<>) {
165 errno = 0;
166 buffer_ = strerror(error_code_);
167 return errno;
168 }
169
170 public:
171 StrError(int err_code, char *&buf, std::size_t buf_size)
172 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
173
174 int run() {
175 strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
176 return handle(strerror_r(error_code_, buffer_, buffer_size_));
177 }
178 };
179 return StrError(error_code, buffer, buffer_size).run();
180 }
181
format_error_code(Writer & out,int error_code,StringRef message)182 void format_error_code(Writer &out, int error_code,
183 StringRef message) FMT_NOEXCEPT{
184 // Report error code making sure that the output fits into
185 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
186 // bad_alloc.
187 out.clear();
188 static const char SEP[] = ": ";
189 static const char ERROR_STR[] = "error ";
190 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
191 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
192 typedef internal::IntTraits<int>::MainType MainType;
193 MainType abs_value = static_cast<MainType>(error_code);
194 if (internal::is_negative(error_code)) {
195 abs_value = 0 - abs_value;
196 ++error_code_size;
197 }
198 error_code_size += internal::count_digits(abs_value);
199 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
200 out << message << SEP;
201 out << ERROR_STR << error_code;
202 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
203 }
204
report_error(FormatFunc func,int error_code,StringRef message)205 void report_error(FormatFunc func, int error_code,
206 StringRef message) FMT_NOEXCEPT{
207 MemoryWriter full_message;
208 func(full_message, error_code, message);
209 // Use Writer::data instead of Writer::c_str to avoid potential memory
210 // allocation.
211 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
212 std::fputc('\n', stderr);
213 }
214 } // namespace
215
216 namespace internal {
217
218 // This method is used to preserve binary compatibility with fmt 3.0.
219 // It can be removed in 4.0.
format_system_error(Writer & out,int error_code,StringRef message)220 FMT_FUNC void format_system_error(
221 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{
222 fmt::format_system_error(out, error_code, message);
223 }
224 } // namespace internal
225
init(int err_code,CStringRef format_str,ArgList args)226 FMT_FUNC void SystemError::init(
227 int err_code, CStringRef format_str, ArgList args) {
228 error_code_ = err_code;
229 MemoryWriter w;
230 format_system_error(w, err_code, format(format_str, args));
231 std::runtime_error &base = *this;
232 base = std::runtime_error(w.str());
233 }
234
235 template <typename T>
format_float(char * buffer,std::size_t size,const char * format,unsigned width,int precision,T value)236 int internal::CharTraits<char>::format_float(
237 char *buffer, std::size_t size, const char *format,
238 unsigned width, int precision, T value) {
239 if (width == 0) {
240 return precision < 0 ?
241 FMT_SNPRINTF(buffer, size, format, value) :
242 FMT_SNPRINTF(buffer, size, format, precision, value);
243 }
244 return precision < 0 ?
245 FMT_SNPRINTF(buffer, size, format, width, value) :
246 FMT_SNPRINTF(buffer, size, format, width, precision, value);
247 }
248
249 template <typename T>
format_float(wchar_t * buffer,std::size_t size,const wchar_t * format,unsigned width,int precision,T value)250 int internal::CharTraits<wchar_t>::format_float(
251 wchar_t *buffer, std::size_t size, const wchar_t *format,
252 unsigned width, int precision, T value) {
253 if (width == 0) {
254 return precision < 0 ?
255 FMT_SWPRINTF(buffer, size, format, value) :
256 FMT_SWPRINTF(buffer, size, format, precision, value);
257 }
258 return precision < 0 ?
259 FMT_SWPRINTF(buffer, size, format, width, value) :
260 FMT_SWPRINTF(buffer, size, format, width, precision, value);
261 }
262
263 template <typename T>
264 const char internal::BasicData<T>::DIGITS[] =
265 "0001020304050607080910111213141516171819"
266 "2021222324252627282930313233343536373839"
267 "4041424344454647484950515253545556575859"
268 "6061626364656667686970717273747576777879"
269 "8081828384858687888990919293949596979899";
270
271 #define FMT_POWERS_OF_10(factor) \
272 factor * 10, \
273 factor * 100, \
274 factor * 1000, \
275 factor * 10000, \
276 factor * 100000, \
277 factor * 1000000, \
278 factor * 10000000, \
279 factor * 100000000, \
280 factor * 1000000000
281
282 template <typename T>
283 const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
284 0, FMT_POWERS_OF_10(1)
285 };
286
287 template <typename T>
288 const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
289 0,
290 FMT_POWERS_OF_10(1),
291 FMT_POWERS_OF_10(ULongLong(1000000000)),
292 // Multiply several constants instead of using a single long long constant
293 // to avoid warnings about C++98 not supporting long long.
294 ULongLong(1000000000) * ULongLong(1000000000) * 10
295 };
296
report_unknown_type(char code,const char * type)297 FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
298 (void)type;
299 if (std::isprint(static_cast<unsigned char>(code))) {
300 FMT_THROW(FormatError(
301 format("unknown format code '{}' for {}", code, type)));
302 }
303 FMT_THROW(FormatError(
304 format("unknown format code '\\x{:02x}' for {}",
305 static_cast<unsigned>(code), type)));
306 }
307
308 #if FMT_USE_WINDOWS_H
309
UTF8ToUTF16(StringRef s)310 FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
311 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
312 if (s.size() > INT_MAX)
313 FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
314 int s_size = static_cast<int>(s.size());
315 int length = MultiByteToWideChar(
316 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
317 if (length == 0)
318 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
319 buffer_.resize(length + 1);
320 length = MultiByteToWideChar(
321 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
322 if (length == 0)
323 FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
324 buffer_[length] = 0;
325 }
326
UTF16ToUTF8(WStringRef s)327 FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
328 if (int error_code = convert(s)) {
329 FMT_THROW(WindowsError(error_code,
330 "cannot convert string from UTF-16 to UTF-8"));
331 }
332 }
333
convert(WStringRef s)334 FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
335 if (s.size() > INT_MAX)
336 return ERROR_INVALID_PARAMETER;
337 int s_size = static_cast<int>(s.size());
338 int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
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, 0, 0);
344 if (length == 0)
345 return GetLastError();
346 buffer_[length] = 0;
347 return 0;
348 }
349
init(int err_code,CStringRef format_str,ArgList args)350 FMT_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
format_windows_error(Writer & out,int error_code,StringRef message)359 FMT_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(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
367 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
368 system_message, static_cast<uint32_t>(buffer.size()), 0);
369 if (result != 0) {
370 UTF16ToUTF8 utf8_message;
371 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
372 out << message << ": " << utf8_message;
373 return;
374 }
375 break;
376 }
377 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
378 break; // Can't get error message, report error code instead.
379 buffer.resize(buffer.size() * 2);
380 }
381 } FMT_CATCH(...) {}
382 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
383 }
384
385 #endif // FMT_USE_WINDOWS_H
386
format_system_error(Writer & out,int error_code,StringRef message)387 FMT_FUNC void format_system_error(
388 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT{
389 FMT_TRY{
390 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
391 buffer.resize(internal::INLINE_BUFFER_SIZE);
392 for (;;) {
393 char *system_message = &buffer[0];
394 int result = safe_strerror(error_code, system_message, buffer.size());
395 if (result == 0) {
396 out << message << ": " << system_message;
397 return;
398 }
399 if (result != ERANGE)
400 break; // Can't get error message, report error code instead.
401 buffer.resize(buffer.size() * 2);
402 }
403 } FMT_CATCH(...) {}
404 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
405 }
406
407 template <typename Char>
init(const ArgList & args)408 void internal::ArgMap<Char>::init(const ArgList &args) {
409 if (!map_.empty())
410 return;
411 typedef internal::NamedArg<Char> NamedArg;
412 const NamedArg *named_arg = 0;
413 bool use_values =
414 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
415 if (use_values) {
416 for (unsigned i = 0;/*nothing*/; ++i) {
417 internal::Arg::Type arg_type = args.type(i);
418 switch (arg_type) {
419 case internal::Arg::NONE:
420 return;
421 case internal::Arg::NAMED_ARG:
422 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
423 map_.push_back(Pair(named_arg->name, *named_arg));
424 break;
425 default:
426 /*nothing*/
427 ;
428 }
429 }
430 return;
431 }
432 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
433 internal::Arg::Type arg_type = args.type(i);
434 if (arg_type == internal::Arg::NAMED_ARG) {
435 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
436 map_.push_back(Pair(named_arg->name, *named_arg));
437 }
438 }
439 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
440 switch (args.args_[i].type) {
441 case internal::Arg::NONE:
442 return;
443 case internal::Arg::NAMED_ARG:
444 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
445 map_.push_back(Pair(named_arg->name, *named_arg));
446 break;
447 default:
448 /*nothing*/
449 ;
450 }
451 }
452 }
453
454 template <typename Char>
grow(std::size_t)455 void internal::FixedBuffer<Char>::grow(std::size_t) {
456 FMT_THROW(std::runtime_error("buffer overflow"));
457 }
458
do_get_arg(unsigned arg_index,const char * & error)459 FMT_FUNC Arg internal::FormatterBase::do_get_arg(
460 unsigned arg_index, const char *&error) {
461 Arg arg = args_[arg_index];
462 switch (arg.type) {
463 case Arg::NONE:
464 error = "argument index out of range";
465 break;
466 case Arg::NAMED_ARG:
467 arg = *static_cast<const internal::Arg*>(arg.pointer);
468 break;
469 default:
470 /*nothing*/
471 ;
472 }
473 return arg;
474 }
475
report_system_error(int error_code,fmt::StringRef message)476 FMT_FUNC void report_system_error(
477 int error_code, fmt::StringRef message) FMT_NOEXCEPT{
478 // 'fmt::' is for bcc32.
479 report_error(format_system_error, error_code, message);
480 }
481
482 #if FMT_USE_WINDOWS_H
report_windows_error(int error_code,fmt::StringRef message)483 FMT_FUNC void report_windows_error(
484 int error_code, fmt::StringRef message) FMT_NOEXCEPT{
485 // 'fmt::' is for bcc32.
486 report_error(internal::format_windows_error, error_code, message);
487 }
488 #endif
489
print(std::FILE * f,CStringRef format_str,ArgList args)490 FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
491 MemoryWriter w;
492 w.write(format_str, args);
493 std::fwrite(w.data(), 1, w.size(), f);
494 }
495
print(CStringRef format_str,ArgList args)496 FMT_FUNC void print(CStringRef format_str, ArgList args) {
497 print(stdout, format_str, args);
498 }
499
print_colored(Color c,CStringRef format,ArgList args)500 FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
501 char escape[] = "\x1b[30m";
502 escape[3] = static_cast<char>('0' + c);
503 std::fputs(escape, stdout);
504 print(format, args);
505 std::fputs(RESET_COLOR, stdout);
506 }
507
508 template <typename Char>
509 void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args);
510
fprintf(std::FILE * f,CStringRef format,ArgList args)511 FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {
512 MemoryWriter w;
513 printf(w, format, args);
514 std::size_t size = w.size();
515 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
516 }
517
518 #ifndef FMT_HEADER_ONLY
519
520 template struct internal::BasicData<void>;
521
522 // Explicit instantiations for char.
523
524 template void internal::FixedBuffer<char>::grow(std::size_t);
525
526 template void internal::ArgMap<char>::init(const ArgList &args);
527
528 template void PrintfFormatter<char>::format(CStringRef format);
529
530 template int internal::CharTraits<char>::format_float(
531 char *buffer, std::size_t size, const char *format,
532 unsigned width, int precision, double value);
533
534 template int internal::CharTraits<char>::format_float(
535 char *buffer, std::size_t size, const char *format,
536 unsigned width, int precision, long double value);
537
538 // Explicit instantiations for wchar_t.
539
540 template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
541
542 template void internal::ArgMap<wchar_t>::init(const ArgList &args);
543
544 template void PrintfFormatter<wchar_t>::format(WCStringRef format);
545
546 template int internal::CharTraits<wchar_t>::format_float(
547 wchar_t *buffer, std::size_t size, const wchar_t *format,
548 unsigned width, int precision, double value);
549
550 template int internal::CharTraits<wchar_t>::format_float(
551 wchar_t *buffer, std::size_t size, const wchar_t *format,
552 unsigned width, int precision, long double value);
553
554 #endif // FMT_HEADER_ONLY
555
556 } // namespace fmt
557
558 #ifdef _MSC_VER
559 # pragma warning(pop)
560 #endif