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