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 53using 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. 74static inline fmt::internal::Null<> strerror_r(int, char *, ...) { 75 return fmt::internal::Null<>(); 76} 77static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { 78 return fmt::internal::Null<>(); 79} 80 81namespace fmt { 82 83FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} 84FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {} 85FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} 86 87namespace { 88 89#ifndef _MSC_VER 90# define FMT_SNPRINTF snprintf 91#else // _MSC_VER 92inline 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 108const char RESET_COLOR[] = "\x1b[0m"; 109 110typedef 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. 121int 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 181void 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 204void 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 215namespace internal { 216 217// This method is used to preserve binary compatibility with fmt 3.0. 218// It can be removed in 4.0. 219FMT_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 225FMT_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 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, 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 296FMT_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 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::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 453template <typename Char> 454void internal::FixedBuffer<Char>::grow(std::size_t) { 455 FMT_THROW(std::runtime_error("buffer overflow")); 456} 457 458FMT_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 474FMT_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 481FMT_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 488FMT_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 494FMT_FUNC void print(CStringRef format_str, ArgList args) { 495 print(stdout, format_str, args); 496} 497 498FMT_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 508template struct internal::BasicData<void>; 509 510// Explicit instantiations for char. 511 512template void internal::FixedBuffer<char>::grow(std::size_t); 513 514template void internal::ArgMap<char>::init(const ArgList &args); 515 516template int internal::CharTraits<char>::format_float( 517 char *buffer, std::size_t size, const char *format, 518 unsigned width, int precision, double value); 519 520template 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 526template void internal::FixedBuffer<wchar_t>::grow(std::size_t); 527 528template void internal::ArgMap<wchar_t>::init(const ArgList &args); 529 530template 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 534template 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