• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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