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
43 #if FMT_USE_WINDOWS_H
44 # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
45 # include <windows.h>
46 # else
47 # define NOMINMAX
48 # include <windows.h>
49 # undef NOMINMAX
50 # endif
51 #endif
52
53 using fmt::internal::Arg;
54
55 #if FMT_EXCEPTIONS
56 # define FMT_TRY try
57 # define FMT_CATCH(x) catch (x)
58 #else
59 # define FMT_TRY if (true)
60 # define FMT_CATCH(x) if (false)
61 #endif
62
63 #ifdef _MSC_VER
64 # pragma warning(push)
65 # pragma warning(disable: 4127) // conditional expression is constant
66 # pragma warning(disable: 4702) // unreachable code
67 // Disable deprecation warning for strerror. The latter is not called but
68 // MSVC fails to detect it.
69 # pragma warning(disable: 4996)
70 #endif
71
72 // Dummy implementations of strerror_r and strerror_s called if corresponding
73 // system functions are not available.
strerror_r(int,char *,...)74 static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
75 return fmt::internal::Null<>();
76 }
strerror_s(char *,std::size_t,...)77 static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
78 return fmt::internal::Null<>();
79 }
80
81 namespace fmt {
82
~RuntimeError()83 FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}
~FormatError()84 FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {}
~SystemError()85 FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {}
86
87 namespace {
88
89 #ifndef _MSC_VER
90 # define FMT_SNPRINTF snprintf
91 #else // _MSC_VER
92 inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
93 va_list args;
94 va_start(args, format);
95 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
96 va_end(args);
97 return result;
98 }
99 # define FMT_SNPRINTF fmt_snprintf
100 #endif // _MSC_VER
101
102 #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
103 # define FMT_SWPRINTF snwprintf
104 #else
105 # define FMT_SWPRINTF swprintf
106 #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
107
108 const char RESET_COLOR[] = "\x1b[0m";
109
110 typedef void (*FormatFunc)(Writer &, int, StringRef);
111
112 // Portable thread-safe version of strerror.
113 // Sets buffer to point to a string describing the error code.
114 // This can be either a pointer to a string stored in buffer,
115 // or a pointer to some static immutable string.
116 // Returns one of the following values:
117 // 0 - success
118 // ERANGE - buffer is not large enough to store the error message
119 // other - failure
120 // Buffer should be at least of size 1.
safe_strerror(int error_code,char * & buffer,std::size_t buffer_size)121 int safe_strerror(
122 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
123 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
124
125 class StrError {
126 private:
127 int error_code_;
128 char *&buffer_;
129 std::size_t buffer_size_;
130
131 // A noop assignment operator to avoid bogus warnings.
132 void operator=(const StrError &) {}
133
134 // Handle the result of XSI-compliant version of strerror_r.
135 int handle(int result) {
136 // glibc versions before 2.13 return result in errno.
137 return result == -1 ? errno : result;
138 }
139
140 // Handle the result of GNU-specific version of strerror_r.
141 int handle(char *message) {
142 // If the buffer is full then the message is probably truncated.
143 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
144 return ERANGE;
145 buffer_ = message;
146 return 0;
147 }
148
149 // Handle the case when strerror_r is not available.
150 int handle(internal::Null<>) {
151 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
152 }
153
154 // Fallback to strerror_s when strerror_r is not available.
155 int fallback(int result) {
156 // If the buffer is full then the message is probably truncated.
157 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
158 ERANGE : result;
159 }
160
161 // Fallback to strerror if strerror_r and strerror_s are not available.
162 int fallback(internal::Null<>) {
163 errno = 0;
164 buffer_ = strerror(error_code_);
165 return errno;
166 }
167
168 public:
169 StrError(int err_code, char *&buf, std::size_t buf_size)
170 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
171
172 int run() {
173 // Suppress a warning about unused strerror_r.
174 strerror_r(0, FMT_NULL, "");
175 return handle(strerror_r(error_code_, buffer_, buffer_size_));
176 }
177 };
178 return StrError(error_code, buffer, buffer_size).run();
179 }
180
format_error_code(Writer & out,int error_code,StringRef message)181 void format_error_code(Writer &out, int error_code,
182 StringRef message) FMT_NOEXCEPT {
183 // Report error code making sure that the output fits into
184 // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
185 // bad_alloc.
186 out.clear();
187 static const char SEP[] = ": ";
188 static const char ERROR_STR[] = "error ";
189 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
190 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
191 typedef internal::IntTraits<int>::MainType MainType;
192 MainType abs_value = static_cast<MainType>(error_code);
193 if (internal::is_negative(error_code)) {
194 abs_value = 0 - abs_value;
195 ++error_code_size;
196 }
197 error_code_size += internal::count_digits(abs_value);
198 if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
199 out << message << SEP;
200 out << ERROR_STR << error_code;
201 assert(out.size() <= internal::INLINE_BUFFER_SIZE);
202 }
203
report_error(FormatFunc func,int error_code,StringRef message)204 void report_error(FormatFunc func, int error_code,
205 StringRef message) FMT_NOEXCEPT {
206 MemoryWriter full_message;
207 func(full_message, error_code, message);
208 // Use Writer::data instead of Writer::c_str to avoid potential memory
209 // allocation.
210 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
211 std::fputc('\n', stderr);
212 }
213 } // namespace
214
215 namespace internal {
216
217 // This method is used to preserve binary compatibility with fmt 3.0.
218 // It can be removed in 4.0.
format_system_error(Writer & out,int error_code,StringRef message)219 FMT_FUNC void format_system_error(
220 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
221 fmt::format_system_error(out, error_code, message);
222 }
223 } // namespace internal
224
init(int err_code,CStringRef format_str,ArgList args)225 FMT_FUNC void SystemError::init(
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
234 template <typename T>
format_float(char * buffer,std::size_t size,const char * format,unsigned width,int precision,T value)235 int 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
248 template <typename T>
format_float(wchar_t * buffer,std::size_t size,const wchar_t * format,unsigned width,int precision,T value)249 int 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
262 template <typename T>
263 const 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
281 template <typename T>
282 const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
283 0, FMT_POWERS_OF_10(1)
284 };
285
286 template <typename T>
287 const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
288 0,
289 FMT_POWERS_OF_10(1),
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
report_unknown_type(char code,const char * type)296 FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
297 (void)type;
298 if (std::isprint(static_cast<unsigned char>(code))) {
299 FMT_THROW(FormatError(
300 format("unknown format code '{}' for {}", code, type)));
301 }
302 FMT_THROW(FormatError(
303 format("unknown format code '\\x{:02x}' for {}",
304 static_cast<unsigned>(code), type)));
305 }
306
307 #if FMT_USE_WINDOWS_H
308
UTF8ToUTF16(StringRef s)309 FMT_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
UTF16ToUTF8(WStringRef s)326 FMT_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
convert(WStringRef s)333 FMT_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
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(
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
format_system_error(Writer & out,int error_code,StringRef message)388 FMT_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
408 template <typename Char>
init(const ArgList & args)409 void internal::ArgMap<Char>::init(const ArgList &args) {
410 if (!map_.empty())
411 return;
412 typedef internal::NamedArg<Char> NamedArg;
413 const NamedArg *named_arg = FMT_NULL;
414 bool use_values =
415 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
416 if (use_values) {
417 for (unsigned i = 0;/*nothing*/; ++i) {
418 internal::Arg::Type arg_type = args.type(i);
419 switch (arg_type) {
420 case internal::Arg::NONE:
421 return;
422 case internal::Arg::NAMED_ARG:
423 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
424 map_.push_back(Pair(named_arg->name, *named_arg));
425 break;
426 default:
427 /*nothing*/;
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 template <typename Char>
grow(std::size_t)454 void internal::FixedBuffer<Char>::grow(std::size_t) {
455 FMT_THROW(std::runtime_error("buffer overflow"));
456 }
457
do_get_arg(unsigned arg_index,const char * & error)458 FMT_FUNC Arg internal::FormatterBase::do_get_arg(
459 unsigned arg_index, const char *&error) {
460 Arg arg = args_[arg_index];
461 switch (arg.type) {
462 case Arg::NONE:
463 error = "argument index out of range";
464 break;
465 case Arg::NAMED_ARG:
466 arg = *static_cast<const internal::Arg*>(arg.pointer);
467 break;
468 default:
469 /*nothing*/;
470 }
471 return arg;
472 }
473
report_system_error(int error_code,fmt::StringRef message)474 FMT_FUNC void report_system_error(
475 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
476 // 'fmt::' is for bcc32.
477 report_error(format_system_error, error_code, message);
478 }
479
480 #if FMT_USE_WINDOWS_H
report_windows_error(int error_code,fmt::StringRef message)481 FMT_FUNC void report_windows_error(
482 int error_code, fmt::StringRef message) FMT_NOEXCEPT {
483 // 'fmt::' is for bcc32.
484 report_error(internal::format_windows_error, error_code, message);
485 }
486 #endif
487
print(std::FILE * f,CStringRef format_str,ArgList args)488 FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
489 MemoryWriter w;
490 w.write(format_str, args);
491 std::fwrite(w.data(), 1, w.size(), f);
492 }
493
print(CStringRef format_str,ArgList args)494 FMT_FUNC void print(CStringRef format_str, ArgList args) {
495 print(stdout, format_str, args);
496 }
497
print_colored(Color c,CStringRef format,ArgList args)498 FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
499 char escape[] = "\x1b[30m";
500 escape[3] = static_cast<char>('0' + c);
501 std::fputs(escape, stdout);
502 print(format, args);
503 std::fputs(RESET_COLOR, stdout);
504 }
505
506 #ifndef FMT_HEADER_ONLY
507
508 template struct internal::BasicData<void>;
509
510 // Explicit instantiations for char.
511
512 template void internal::FixedBuffer<char>::grow(std::size_t);
513
514 template void internal::ArgMap<char>::init(const ArgList &args);
515
516 template int internal::CharTraits<char>::format_float(
517 char *buffer, std::size_t size, const char *format,
518 unsigned width, int precision, double value);
519
520 template int internal::CharTraits<char>::format_float(
521 char *buffer, std::size_t size, const char *format,
522 unsigned width, int precision, long double value);
523
524 // Explicit instantiations for wchar_t.
525
526 template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
527
528 template void internal::ArgMap<wchar_t>::init(const ArgList &args);
529
530 template int internal::CharTraits<wchar_t>::format_float(
531 wchar_t *buffer, std::size_t size, const wchar_t *format,
532 unsigned width, int precision, double value);
533
534 template int internal::CharTraits<wchar_t>::format_float(
535 wchar_t *buffer, std::size_t size, const wchar_t *format,
536 unsigned width, int precision, long double value);
537
538 #endif // FMT_HEADER_ONLY
539
540 } // namespace fmt
541
542 #ifdef _MSC_VER
543 # pragma warning(pop)
544 #endif
545