format.cc revision 1daddec15105ce9e91c27dddb38140aee802d9da
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#include "printf.h" 30 31#include <string.h> 32 33#include <cctype> 34#include <cerrno> 35#include <climits> 36#include <cmath> 37#include <cstdarg> 38#include <cstddef> // for std::ptrdiff_t 39 40#if defined(_WIN32) && defined(__MINGW32__) 41# include <cstring> 42#endif 43 44#if FMT_USE_WINDOWS_H 45# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) 46# include <windows.h> 47# else 48# define NOMINMAX 49# include <windows.h> 50# undef NOMINMAX 51# endif 52#endif 53 54using fmt::internal::Arg; 55 56#if FMT_EXCEPTIONS 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. 75static inline fmt::internal::Null<> strerror_r(int, char *, ...) { 76 return fmt::internal::Null<>(); 77} 78static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { 79 return fmt::internal::Null<>(); 80} 81 82namespace fmt { 83 84FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} 85FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {} 86FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} 87 88namespace { 89 90#ifndef _MSC_VER 91# define FMT_SNPRINTF snprintf 92#else // _MSC_VER 93inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { 94 va_list args; 95 va_start(args, format); 96 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); 97 va_end(args); 98 return result; 99} 100# define FMT_SNPRINTF fmt_snprintf 101#endif // _MSC_VER 102 103#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) 104# define FMT_SWPRINTF snwprintf 105#else 106# define FMT_SWPRINTF swprintf 107#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) 108 109const char RESET_COLOR[] = "\x1b[0m"; 110 111typedef void (*FormatFunc)(Writer &, int, StringRef); 112 113// Portable thread-safe version of strerror. 114// Sets buffer to point to a string describing the error code. 115// This can be either a pointer to a string stored in buffer, 116// or a pointer to some static immutable string. 117// Returns one of the following values: 118// 0 - success 119// ERANGE - buffer is not large enough to store the error message 120// other - failure 121// Buffer should be at least of size 1. 122int safe_strerror( 123 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { 124 FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); 125 126 class StrError { 127 private: 128 int error_code_; 129 char *&buffer_; 130 std::size_t buffer_size_; 131 132 // A noop assignment operator to avoid bogus warnings. 133 void operator=(const StrError &) {} 134 135 // Handle the result of XSI-compliant version of strerror_r. 136 int handle(int result) { 137 // glibc versions before 2.13 return result in errno. 138 return result == -1 ? errno : result; 139 } 140 141 // Handle the result of GNU-specific version of strerror_r. 142 int handle(char *message) { 143 // If the buffer is full then the message is probably truncated. 144 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) 145 return ERANGE; 146 buffer_ = message; 147 return 0; 148 } 149 150 // Handle the case when strerror_r is not available. 151 int handle(internal::Null<>) { 152 return fallback(strerror_s(buffer_, buffer_size_, error_code_)); 153 } 154 155 // Fallback to strerror_s when strerror_r is not available. 156 int fallback(int result) { 157 // If the buffer is full then the message is probably truncated. 158 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? 159 ERANGE : result; 160 } 161 162 // Fallback to strerror if strerror_r and strerror_s are not available. 163 int fallback(internal::Null<>) { 164 errno = 0; 165 buffer_ = strerror(error_code_); 166 return errno; 167 } 168 169 public: 170 StrError(int err_code, char *&buf, std::size_t buf_size) 171 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} 172 173 int run() { 174 // Suppress a warning about unused strerror_r. 175 strerror_r(0, FMT_NULL, ""); 176 return handle(strerror_r(error_code_, buffer_, buffer_size_)); 177 } 178 }; 179 return StrError(error_code, buffer, buffer_size).run(); 180} 181 182void 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 205void 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 216namespace internal { 217 218// This method is used to preserve binary compatibility with fmt 3.0. 219// It can be removed in 4.0. 220FMT_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 226FMT_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 235template <typename T> 236int 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 249template <typename T> 250int 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 263template <typename T> 264const 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 282template <typename T> 283const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = { 284 0, FMT_POWERS_OF_10(1) 285}; 286 287template <typename T> 288const 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 297FMT_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 310FMT_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, FMT_NULL, 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 327FMT_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 334FMT_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( 339 CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); 340 if (length == 0) 341 return GetLastError(); 342 buffer_.resize(length + 1); 343 length = WideCharToMultiByte( 344 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); 345 if (length == 0) 346 return GetLastError(); 347 buffer_[length] = 0; 348 return 0; 349} 350 351FMT_FUNC void WindowsError::init( 352 int err_code, CStringRef format_str, ArgList args) { 353 error_code_ = err_code; 354 MemoryWriter w; 355 internal::format_windows_error(w, err_code, format(format_str, args)); 356 std::runtime_error &base = *this; 357 base = std::runtime_error(w.str()); 358} 359 360FMT_FUNC void internal::format_windows_error( 361 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { 362 FMT_TRY { 363 MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; 364 buffer.resize(INLINE_BUFFER_SIZE); 365 for (;;) { 366 wchar_t *system_message = &buffer[0]; 367 int result = FormatMessageW( 368 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 369 FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 370 system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL); 371 if (result != 0) { 372 UTF16ToUTF8 utf8_message; 373 if (utf8_message.convert(system_message) == ERROR_SUCCESS) { 374 out << message << ": " << utf8_message; 375 return; 376 } 377 break; 378 } 379 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 380 break; // Can't get error message, report error code instead. 381 buffer.resize(buffer.size() * 2); 382 } 383 } FMT_CATCH(...) {} 384 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. 385} 386 387#endif // FMT_USE_WINDOWS_H 388 389FMT_FUNC void format_system_error( 390 Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { 391 FMT_TRY { 392 internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer; 393 buffer.resize(internal::INLINE_BUFFER_SIZE); 394 for (;;) { 395 char *system_message = &buffer[0]; 396 int result = safe_strerror(error_code, system_message, buffer.size()); 397 if (result == 0) { 398 out << message << ": " << system_message; 399 return; 400 } 401 if (result != ERANGE) 402 break; // Can't get error message, report error code instead. 403 buffer.resize(buffer.size() * 2); 404 } 405 } FMT_CATCH(...) {} 406 fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. 407} 408 409template <typename Char> 410void internal::ArgMap<Char>::init(const ArgList &args) { 411 if (!map_.empty()) 412 return; 413 typedef internal::NamedArg<Char> NamedArg; 414 const NamedArg *named_arg = FMT_NULL; 415 bool use_values = 416 args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; 417 if (use_values) { 418 for (unsigned i = 0;/*nothing*/; ++i) { 419 internal::Arg::Type arg_type = args.type(i); 420 switch (arg_type) { 421 case internal::Arg::NONE: 422 return; 423 case internal::Arg::NAMED_ARG: 424 named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); 425 map_.push_back(Pair(named_arg->name, *named_arg)); 426 break; 427 default: 428 /*nothing*/; 429 } 430 } 431 return; 432 } 433 for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { 434 internal::Arg::Type arg_type = args.type(i); 435 if (arg_type == internal::Arg::NAMED_ARG) { 436 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); 437 map_.push_back(Pair(named_arg->name, *named_arg)); 438 } 439 } 440 for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { 441 switch (args.args_[i].type) { 442 case internal::Arg::NONE: 443 return; 444 case internal::Arg::NAMED_ARG: 445 named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); 446 map_.push_back(Pair(named_arg->name, *named_arg)); 447 break; 448 default: 449 /*nothing*/; 450 } 451 } 452} 453 454template <typename Char> 455void internal::FixedBuffer<Char>::grow(std::size_t) { 456 FMT_THROW(std::runtime_error("buffer overflow")); 457} 458 459FMT_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 return arg; 473} 474 475FMT_FUNC void report_system_error( 476 int error_code, fmt::StringRef message) FMT_NOEXCEPT { 477 // 'fmt::' is for bcc32. 478 report_error(format_system_error, error_code, message); 479} 480 481#if FMT_USE_WINDOWS_H 482FMT_FUNC void report_windows_error( 483 int error_code, fmt::StringRef message) FMT_NOEXCEPT { 484 // 'fmt::' is for bcc32. 485 report_error(internal::format_windows_error, error_code, message); 486} 487#endif 488 489FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { 490 MemoryWriter w; 491 w.write(format_str, args); 492 std::fwrite(w.data(), 1, w.size(), f); 493} 494 495FMT_FUNC void print(CStringRef format_str, ArgList args) { 496 print(stdout, format_str, args); 497} 498 499FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { 500 char escape[] = "\x1b[30m"; 501 escape[3] = static_cast<char>('0' + c); 502 std::fputs(escape, stdout); 503 print(format, args); 504 std::fputs(RESET_COLOR, stdout); 505} 506 507template <typename Char> 508void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args); 509 510FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { 511 MemoryWriter w; 512 printf(w, format, args); 513 std::size_t size = w.size(); 514 return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); 515} 516 517#ifndef FMT_HEADER_ONLY 518 519template struct internal::BasicData<void>; 520 521// Explicit instantiations for char. 522 523template void internal::FixedBuffer<char>::grow(std::size_t); 524 525template void internal::ArgMap<char>::init(const ArgList &args); 526 527template void PrintfFormatter<char>::format(CStringRef format); 528 529template int internal::CharTraits<char>::format_float( 530 char *buffer, std::size_t size, const char *format, 531 unsigned width, int precision, double value); 532 533template int internal::CharTraits<char>::format_float( 534 char *buffer, std::size_t size, const char *format, 535 unsigned width, int precision, long double value); 536 537// Explicit instantiations for wchar_t. 538 539template void internal::FixedBuffer<wchar_t>::grow(std::size_t); 540 541template void internal::ArgMap<wchar_t>::init(const ArgList &args); 542 543template void PrintfFormatter<wchar_t>::format(WCStringRef format); 544 545template int internal::CharTraits<wchar_t>::format_float( 546 wchar_t *buffer, std::size_t size, const wchar_t *format, 547 unsigned width, int precision, double value); 548 549template int internal::CharTraits<wchar_t>::format_float( 550 wchar_t *buffer, std::size_t size, const wchar_t *format, 551 unsigned width, int precision, long double value); 552 553#endif // FMT_HEADER_ONLY 554 555} // namespace fmt 556 557#ifdef _MSC_VER 558# pragma warning(pop) 559#endif 560