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