Flow123d  release_3.0.0-1212-g8801db3
format.cc
Go to the documentation of this file.
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 "system/fmt/format.h"
29 #include "system/fmt/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 
54 using 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.
75 static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
76  return fmt::internal::Null<>();
77 }
78 static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
79  return fmt::internal::Null<>();
80 }
81 
82 namespace fmt {
83 
87 
88 namespace {
89 
90 #ifndef _MSC_VER
91 # define FMT_SNPRINTF snprintf
92 #else // _MSC_VER
93 inline 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 
109 const char RESET_COLOR[] = "\x1b[0m";
110 
111 typedef 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.
122 int 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  strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
175  return handle(strerror_r(error_code_, buffer_, buffer_size_));
176  }
177  };
178  return StrError(error_code, buffer, buffer_size).run();
179 }
180 
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 
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.
220  Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
221  fmt::format_system_error(out, error_code, message);
222 }
223 } // namespace internal
224 } // namespace fmt
225 
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 
235 template <typename T>
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 
249 template <typename T>
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 
263 template <typename T>
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 
282 template <typename T>
284  0, FMT_POWERS_OF_10(1)
285 };
286 
287 template <typename T>
289  0,
290  FMT_POWERS_OF_10(1),
291  FMT_POWERS_OF_10(fmt::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  fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
295 };
296 
297 FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
298  (void)type;
299  if (std::isprint(static_cast<unsigned char>(code))) {
301  fmt::format("unknown format code '{}' for {}", code, type)));
302  }
304  fmt::format("unknown format code '\\x{:02x}' for {}",
305  static_cast<unsigned>(code), type)));
306 }
307 
308 #if FMT_USE_WINDOWS_H
309 
310 FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::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, 0, 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 
327 FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::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 
335  if (s.size() > INT_MAX)
336  return ERROR_INVALID_PARAMETER;
337  int s_size = static_cast<int>(s.size());
338  int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
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, 0, 0);
344  if (length == 0)
345  return GetLastError();
346  buffer_[length] = 0;
347  return 0;
348 }
349 
350 FMT_FUNC void fmt::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 
359 FMT_FUNC void fmt::internal::format_windows_error(
360  fmt::Writer &out, int error_code,
361  fmt::StringRef message) FMT_NOEXCEPT {
362  FMT_TRY {
364  buffer.resize(INLINE_BUFFER_SIZE);
365  for (;;) {
366  wchar_t *system_message = &buffer[0];
367  int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
368  0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
369  system_message, static_cast<uint32_t>(buffer.size()), 0);
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 
389  fmt::Writer &out, int error_code,
390  fmt::StringRef message) FMT_NOEXCEPT {
391  FMT_TRY {
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 
409 template <typename Char>
411  if (!map_.empty())
412  return;
414  const NamedArg *named_arg = 0;
415  bool use_values =
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;
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;
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 
454 template <typename Char>
456  FMT_THROW(std::runtime_error("buffer overflow"));
457 }
458 
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 
476  int error_code, fmt::StringRef message) FMT_NOEXCEPT {
477  // 'fmt::' is for bcc32.
478  fmt::report_error(format_system_error, error_code, message);
479 }
480 
481 #if FMT_USE_WINDOWS_H
482 FMT_FUNC void fmt::report_windows_error(
483  int error_code, fmt::StringRef message) FMT_NOEXCEPT {
484  // 'fmt::' is for bcc32.
485  fmt::report_error(internal::format_windows_error, error_code, message);
486 }
487 #endif
488 
489 FMT_FUNC void fmt::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 
495 FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
496  print(stdout, format_str, args);
497 }
498 
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 
507 FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
508  MemoryWriter w;
509  printf(w, format, args);
510  std::size_t size = w.size();
511  return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
512 }
513 
514 #ifndef FMT_HEADER_ONLY
515 
516 template struct fmt::internal::BasicData<void>;
517 
518 // Explicit instantiations for char.
519 
520 template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
521 
522 template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args);
523 
526 
528  char *buffer, std::size_t size, const char *format,
529  unsigned width, int precision, double value);
530 
532  char *buffer, std::size_t size, const char *format,
533  unsigned width, int precision, long double value);
534 
535 // Explicit instantiations for wchar_t.
536 
537 template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
538 
539 template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args);
540 
542  BasicWriter<wchar_t> &writer, WCStringRef format);
543 
545  wchar_t *buffer, std::size_t size, const wchar_t *format,
546  unsigned width, int precision, double value);
547 
549  wchar_t *buffer, std::size_t size, const wchar_t *format,
550  unsigned width, int precision, long double value);
551 
552 #endif // FMT_HEADER_ONLY
553 
554 #ifdef _MSC_VER
555 # pragma warning(pop)
556 #endif
MapType::value_type Pair
Definition: format.h:1781
#define FMT_NOEXCEPT
Definition: format.h:190
bool is_negative(T value)
Definition: format.h:808
#define FMT_ASSERT(condition, message)
Definition: format.h:229
const Char * data() const
Definition: format.h:449
void resize(std::size_t new_size)
Definition: format.h:620
FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args)
Definition: format.cc:489
FMT_API void report_unknown_type(char code, const char *type)
Definition: format.cc:297
static fmt::internal::Null strerror_s(char *, std::size_t,...)
Definition: format.cc:78
void write(BasicCStringRef< Char > format, ArgList args)
Definition: format.h:2480
std::string format(CStringRef format_str, ArgList args)
Definition: format.h:3141
static fmt::internal::Null strerror_r(int, char *,...)
Definition: format.cc:75
FMT_GCC_EXTENSION typedef unsigned long long ULongLong
Definition: format.h:369
void init(int err_code, CStringRef format_str, ArgList args)
Definition: format.cc:226
std::basic_string< Char > str() const
Definition: format.h:2451
const void * pointer
Definition: format.h:1014
FMT_FUNC void format_system_error(Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
Definition: format.cc:219
BasicStringRef< Char > name
Definition: format.h:1308
const Char * data() const FMT_NOEXCEPT
Definition: format.h:2433
#define FMT_THROW(x)
Definition: format.h:172
FMT_API void grow(std::size_t size)
Definition: format.cc:455
Yes & convert(fmt::ULongLong)
FMT_API void print_colored(Color c, CStringRef format, ArgList args)
Definition: format.cc:499
#define FMT_SNPRINTF
Definition: format.cc:91
static constexpr bool value
Definition: json.hpp:87
BasicStringRef< char > StringRef
Definition: format.h:483
FMT_API void format(BasicWriter< Char > &writer, BasicCStringRef< Char > format_str)
Definition: printf.h:344
BasicMemoryWriter< char > MemoryWriter
Definition: format.h:3016
#define FMT_FUNC
Definition: format.h:3799
#define FMT_SWPRINTF
Definition: format.cc:106
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args)
Definition: ostream.cc:56
BasicWriter< char > Writer
Definition: format.h:376
std::size_t size() const
Definition: format.h:612
std::size_t size() const
Definition: format.h:2427
FMT_API void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT
Definition: format.cc:475
std::size_t size() const
Definition: format.h:452
const internal::Arg * args_
Definition: format.h:1341
Color
Definition: format.h:3122
internal::NamedArg< char > arg(StringRef name, const T &arg)
Definition: format.h:3291
FMT_API void init(const ArgList &args)
Definition: format.cc:410
unsigned count_digits(uint64_t n)
Definition: format.h:861
FMT_API Arg do_get_arg(unsigned arg_index, const char *&error)
Definition: format.cc:459
#define FMT_POWERS_OF_10(factor)
Definition: format.cc:271
Definition: format.cc:82
#define FMT_CATCH(x)
Definition: format.cc:61
FMT_API void format_system_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT
Definition: format.cc:388
const internal::Value * values_
Definition: format.h:1340
#define FMT_TRY
Definition: format.cc:60
internal::Arg::Type type(unsigned index) const
Definition: format.h:1344
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: printf.h:444