Flow123d  release_2.2.0-914-gf1a3a4f
printf.h
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  For the license information refer to format.h.
8  */
9 
10 #ifndef FMT_PRINTF_H_
11 #define FMT_PRINTF_H_
12 
13 #include <algorithm> // std::fill_n
14 #include <limits> // std::numeric_limits
15 
16 #include "system/fmt/format.h"
17 
18 namespace fmt {
19 namespace internal {
20 
21 // Checks if a value fits in int - used to avoid warnings about comparing
22 // signed and unsigned integers.
23 template <bool IsSigned>
24 struct IntChecker {
25  template <typename T>
26  static bool fits_in_int(T value) {
27  unsigned max = std::numeric_limits<int>::max();
28  return value <= max;
29  }
30  static bool fits_in_int(bool) { return true; }
31 };
32 
33 template <>
34 struct IntChecker<true> {
35  template <typename T>
36  static bool fits_in_int(T value) {
37  return value >= std::numeric_limits<int>::min() &&
38  value <= std::numeric_limits<int>::max();
39  }
40  static bool fits_in_int(int) { return true; }
41 };
42 
43 class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
44  public:
46  FMT_THROW(FormatError("precision is not integer"));
47  }
48 
49  template <typename T>
51  if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
52  FMT_THROW(FormatError("number is too big"));
53  return static_cast<int>(value);
54  }
55 };
56 
57 // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
58 class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
59  public:
60  template <typename T>
61  bool visit_any_int(T value) { return value == 0; }
62 };
63 
64 template <typename T, typename U>
65 struct is_same {
66  enum { value = 0 };
67 };
68 
69 template <typename T>
70 struct is_same<T, T> {
71  enum { value = 1 };
72 };
73 
74 // An argument visitor that converts an integer argument to T for printf,
75 // if T is an integral type. If T is void, the argument is converted to
76 // corresponding signed or unsigned type depending on the type specifier:
77 // 'd' and 'i' - signed, other - unsigned)
78 template <typename T = void>
79 class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
80  private:
82  wchar_t type_;
83 
85 
86  public:
87  ArgConverter(internal::Arg &arg, wchar_t type)
88  : arg_(arg), type_(type) {}
89 
90  void visit_bool(bool value) {
91  if (type_ != 's')
92  visit_any_int(value);
93  }
94 
95  template <typename U>
96  void visit_any_int(U value) {
97  bool is_signed = type_ == 'd' || type_ == 'i';
98  using internal::Arg;
99  typedef typename internal::Conditional<
100  is_same<T, void>::value, U, T>::type TargetType;
101  if (sizeof(TargetType) <= sizeof(int)) {
102  // Extra casts are used to silence warnings.
103  if (is_signed) {
104  arg_.type = Arg::INT;
105  arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
106  } else {
107  arg_.type = Arg::UINT;
108  typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
109  arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
110  }
111  } else {
112  if (is_signed) {
113  arg_.type = Arg::LONG_LONG;
114  // glibc's printf doesn't sign extend arguments of smaller types:
115  // std::printf("%lld", -42); // prints "4294967254"
116  // but we don't have to do the same because it's a UB.
117  arg_.long_long_value = static_cast<LongLong>(value);
118  } else {
119  arg_.type = Arg::ULONG_LONG;
120  arg_.ulong_long_value =
121  static_cast<typename internal::MakeUnsigned<U>::Type>(value);
122  }
123  }
124  }
125 };
126 
127 // Converts an integer argument to char for printf.
128 class CharConverter : public ArgVisitor<CharConverter, void> {
129  private:
131 
133 
134  public:
135  explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
136 
137  template <typename T>
139  arg_.type = internal::Arg::CHAR;
140  arg_.int_value = static_cast<char>(value);
141  }
142 };
143 
144 // Checks if an argument is a valid printf width specifier and sets
145 // left alignment if it is negative.
146 class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
147  private:
149 
151 
152  public:
153  explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
154 
156  FMT_THROW(FormatError("width is not integer"));
157  }
158 
159  template <typename T>
160  unsigned visit_any_int(T value) {
161  typedef typename internal::IntTraits<T>::MainType UnsignedType;
162  UnsignedType width = static_cast<UnsignedType>(value);
163  if (internal::is_negative(value)) {
164  spec_.align_ = ALIGN_LEFT;
165  width = 0 - width;
166  }
167  unsigned int_max = std::numeric_limits<int>::max();
168  if (width > int_max)
169  FMT_THROW(FormatError("number is too big"));
170  return static_cast<unsigned>(width);
171  }
172 };
173 
174 template <typename Impl, typename Char>
175 class BasicPrintfArgFormatter : public ArgFormatterBase<Impl, Char> {
176  private:
178  this->spec().type_ = 0;
179  this->write("(nil)");
180  }
181 
183 
184  public:
186  : ArgFormatterBase<Impl, Char>(w, s) {}
187 
188  void visit_bool(bool value) {
189  FormatSpec &fmt_spec = this->spec();
190  if (fmt_spec.type_ != 's')
191  return this->visit_any_int(value);
192  fmt_spec.type_ = 0;
193  this->write(value);
194  }
195 
196  void visit_char(int value) {
197  const FormatSpec &fmt_spec = this->spec();
198  BasicWriter<Char> &w = this->writer();
199  if (fmt_spec.type_ && fmt_spec.type_ != 'c')
200  w.write_int(value, fmt_spec);
201  typedef typename BasicWriter<Char>::CharPtr CharPtr;
202  CharPtr out = CharPtr();
203  if (fmt_spec.width_ > 1) {
204  Char fill = ' ';
205  out = w.grow_buffer(fmt_spec.width_);
206  if (fmt_spec.align_ != ALIGN_LEFT) {
207  std::fill_n(out, fmt_spec.width_ - 1, fill);
208  out += fmt_spec.width_ - 1;
209  } else {
210  std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
211  }
212  } else {
213  out = w.grow_buffer(1);
214  }
215  *out = static_cast<Char>(value);
216  }
217 
218  void visit_cstring(const char *value) {
219  if (value)
220  Base::visit_cstring(value);
221  else if (this->spec().type_ == 'p')
222  write_null_pointer();
223  else
224  this->write("(null)");
225  }
226 
227  void visit_pointer(const void *value) {
228  if (value)
229  return Base::visit_pointer(value);
230  this->spec().type_ = 0;
231  write_null_pointer();
232  }
233 
235  BasicFormatter<Char> formatter(ArgList(), this->writer());
236  const Char format_str[] = {'}', 0};
237  const Char *format = format_str;
238  c.format(&formatter, c.value, &format);
239  }
240 };
241 
242 /** The default printf argument formatter. */
243 template <typename Char>
245  : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char> {
246  public:
247  /** Constructs an argument formatter object. */
249  : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
250 };
251 
252 // A printf formatter.
253 template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
255  private:
256  void parse_flags(FormatSpec &spec, const Char *&s);
257 
258  // Returns the argument with specified index or, if arg_index is equal
259  // to the maximum unsigned value, the next argument.
260  Arg get_arg(const Char *s,
261  unsigned arg_index = (std::numeric_limits<unsigned>::max)());
262 
263  // Parses argument index, flags and width and returns the argument index.
264  unsigned parse_header(const Char *&s, FormatSpec &spec);
265 
266  public:
267  explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {}
268  FMT_API void format(BasicWriter<Char> &writer,
269  BasicCStringRef<Char> format_str);
270 };
271 
272 template <typename Char, typename AF>
274  for (;;) {
275  switch (*s++) {
276  case '-':
277  spec.align_ = ALIGN_LEFT;
278  break;
279  case '+':
280  spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
281  break;
282  case '0':
283  spec.fill_ = '0';
284  break;
285  case ' ':
286  spec.flags_ |= SIGN_FLAG;
287  break;
288  case '#':
289  spec.flags_ |= HASH_FLAG;
290  break;
291  default:
292  --s;
293  return;
294  }
295  }
296 }
297 
298 template <typename Char, typename AF>
299 Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, unsigned arg_index) {
300  (void)s;
301  const char *error = 0;
302  Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
303  next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
304  if (error)
305  FMT_THROW(FormatError(!*s ? "invalid format string" : error));
306  return arg;
307 }
308 
309 template <typename Char, typename AF>
311  const Char *&s, FormatSpec &spec) {
312  unsigned arg_index = std::numeric_limits<unsigned>::max();
313  Char c = *s;
314  if (c >= '0' && c <= '9') {
315  // Parse an argument index (if followed by '$') or a width possibly
316  // preceded with '0' flag(s).
317  unsigned value = parse_nonnegative_int(s);
318  if (*s == '$') { // value is an argument index
319  ++s;
320  arg_index = value;
321  } else {
322  if (c == '0')
323  spec.fill_ = '0';
324  if (value != 0) {
325  // Nonzero value means that we parsed width and don't need to
326  // parse it or flags again, so return now.
327  spec.width_ = value;
328  return arg_index;
329  }
330  }
331  }
332  parse_flags(spec, s);
333  // Parse width.
334  if (*s >= '0' && *s <= '9') {
335  spec.width_ = parse_nonnegative_int(s);
336  } else if (*s == '*') {
337  ++s;
338  spec.width_ = WidthHandler(spec).visit(get_arg(s));
339  }
340  return arg_index;
341 }
342 
343 template <typename Char, typename AF>
345  BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) {
346  const Char *start = format_str.c_str();
347  const Char *s = start;
348  while (*s) {
349  Char c = *s++;
350  if (c != '%') continue;
351  if (*s == c) {
352  write(writer, start, s);
353  start = ++s;
354  continue;
355  }
356  write(writer, start, s - 1);
357 
358  FormatSpec spec;
359  spec.align_ = ALIGN_RIGHT;
360 
361  // Parse argument index, flags and width.
362  unsigned arg_index = parse_header(s, spec);
363 
364  // Parse precision.
365  if (*s == '.') {
366  ++s;
367  if ('0' <= *s && *s <= '9') {
368  spec.precision_ = static_cast<int>(parse_nonnegative_int(s));
369  } else if (*s == '*') {
370  ++s;
371  spec.precision_ = PrecisionHandler().visit(get_arg(s));
372  }
373  }
374 
375  Arg arg = get_arg(s, arg_index);
376  if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg))
377  spec.flags_ &= ~to_unsigned<int>(HASH_FLAG);
378  if (spec.fill_ == '0') {
379  if (arg.type <= Arg::LAST_NUMERIC_TYPE)
380  spec.align_ = ALIGN_NUMERIC;
381  else
382  spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
383  }
384 
385  // Parse length and convert the argument to the required type.
386  switch (*s++) {
387  case 'h':
388  if (*s == 'h')
389  ArgConverter<signed char>(arg, *++s).visit(arg);
390  else
391  ArgConverter<short>(arg, *s).visit(arg);
392  break;
393  case 'l':
394  if (*s == 'l')
395  ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
396  else
397  ArgConverter<long>(arg, *s).visit(arg);
398  break;
399  case 'j':
400  ArgConverter<intmax_t>(arg, *s).visit(arg);
401  break;
402  case 'z':
403  ArgConverter<std::size_t>(arg, *s).visit(arg);
404  break;
405  case 't':
406  ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
407  break;
408  case 'L':
409  // printf produces garbage when 'L' is omitted for long double, no
410  // need to do the same.
411  break;
412  default:
413  --s;
414  ArgConverter<void>(arg, *s).visit(arg);
415  }
416 
417  // Parse type.
418  if (!*s)
419  FMT_THROW(FormatError("invalid format string"));
420  spec.type_ = static_cast<char>(*s++);
421  if (arg.type <= Arg::LAST_INTEGER_TYPE) {
422  // Normalize type.
423  switch (spec.type_) {
424  case 'i': case 'u':
425  spec.type_ = 'd';
426  break;
427  case 'c':
428  // TODO: handle wchar_t
429  CharConverter(arg).visit(arg);
430  break;
431  }
432  }
433 
434  start = s;
435 
436  // Format argument.
437  AF(writer, spec).visit(arg);
438  }
439  write(writer, start, s);
440 }
441 } // namespace internal
442 
443 template <typename Char>
445  internal::PrintfFormatter<Char>(args).format(w, format);
446 }
447 
448 /**
449  \rst
450  Formats arguments and returns the result as a string.
451 
452  **Example**::
453 
454  std::string message = fmt::sprintf("The answer is %d", 42);
455  \endrst
456 */
457 inline std::string sprintf(CStringRef format, ArgList args) {
458  MemoryWriter w;
459  printf(w, format, args);
460  return w.str();
461 }
462 FMT_VARIADIC(std::string, sprintf, CStringRef)
463 
464 inline std::wstring sprintf(WCStringRef format, ArgList args) {
465  WMemoryWriter w;
466  printf(w, format, args);
467  return w.str();
468 }
469 FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
470 
471 /**
472  \rst
473  Prints formatted data to the file *f*.
474 
475  **Example**::
476 
477  fmt::fprintf(stderr, "Don't %s!", "panic");
478  \endrst
479  */
480 FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
481 FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
482 
483 /**
484  \rst
485  Prints formatted data to ``stdout``.
486 
487  **Example**::
488 
489  fmt::printf("Elapsed time: %.2f seconds", 1.23);
490  \endrst
491  */
492 inline int printf(CStringRef format, ArgList args) {
493  return fprintf(stdout, format, args);
494 }
496 } // namespace fmt
497 
498 #endif // FMT_PRINTF_H_
internal::Arg & arg_
Definition: printf.h:81
void visit_any_int(U value)
Definition: printf.h:96
CharConverter(internal::Arg &arg)
Definition: printf.h:135
bool is_negative(T value)
Definition: format.h:808
Alignment align_
Definition: format.h:1592
ArgFormatterBase< Impl, Char > Base
Definition: printf.h:182
#define FMT_VARIADIC(ReturnType, func,...)
Definition: format.h:3407
wchar_t fill_
Definition: format.h:1582
void visit_pointer(const void *value)
Definition: printf.h:227
void visit_any_int(T value)
Definition: printf.h:138
std::string format(CStringRef format_str, ArgList args)
Definition: format.h:3141
unsigned width_
Definition: format.h:1579
const Char * c_str() const
Definition: format.h:528
void write(const mValue &value, std::ostream &os, unsigned int options=0)
std::basic_string< Char > str() const
Definition: format.h:2451
unsigned parse_nonnegative_int(const Char *&s)
Definition: format.h:3451
#define FMT_THROW(x)
Definition: format.h:172
static bool fits_in_int(int)
Definition: printf.h:40
bool flag(unsigned f) const
Definition: format.h:1621
void visit_bool(bool value)
Definition: printf.h:90
static constexpr bool value
Definition: json.hpp:87
#define FMT_API
Definition: format.h:75
FMT_API void format(BasicWriter< Char > &writer, BasicCStringRef< Char > format_str)
Definition: printf.h:344
CharPtr grow_buffer(std::size_t n)
Definition: format.h:2330
unsigned visit_any_int(T value)
Definition: printf.h:160
std::string sprintf(CStringRef format, ArgList args)
Definition: printf.h:457
unsigned uint_value
Definition: format.h:1009
WidthHandler(FormatSpec &spec)
Definition: printf.h:153
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args)
Definition: ostream.cc:56
unsigned parse_header(const Char *&s, FormatSpec &spec)
Definition: printf.h:310
#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: format.h:211
void write_int(T value, Spec spec)
Definition: format.h:2707
void parse_flags(FormatSpec &spec, const Char *&s)
Definition: printf.h:273
internal::CharTraits< Char >::CharPtr CharPtr
Definition: format.h:2314
static bool fits_in_int(bool)
Definition: printf.h:30
ArgConverter(internal::Arg &arg, wchar_t type)
Definition: printf.h:87
int visit_any_int(T value)
Definition: printf.h:50
internal::NamedArg< char > arg(StringRef name, const T &arg)
Definition: format.h:3291
PrintfFormatter(const ArgList &args)
Definition: printf.h:267
Arg get_arg(const Char *s, unsigned arg_index=(std::numeric_limits< unsigned >::max)())
Definition: printf.h:299
PrintfArgFormatter(BasicWriter< Char > &w, FormatSpec &s)
Definition: printf.h:248
BasicPrintfArgFormatter(BasicWriter< Char > &w, FormatSpec &s)
Definition: printf.h:185
void visit_custom(Arg::CustomValue c)
Definition: printf.h:234
ULongLong ulong_long_value
Definition: format.h:1011
Definition: format.cc:82
unsigned flags_
Definition: format.h:1613
Arg get_arg(unsigned arg_index, const char *&error)
Definition: format.h:1923
LongLong long_long_value
Definition: format.h:1010
static bool fits_in_int(T value)
Definition: printf.h:26
bool visit_any_int(T value)
Definition: printf.h:61
#define FMT_VARIADIC_W(ReturnType, func,...)
Definition: format.h:3410
void visit_cstring(const char *value)
Definition: printf.h:218
static bool fits_in_int(T value)
Definition: printf.h:36
internal::Arg & arg_
Definition: printf.h:130
FMT_GCC_EXTENSION typedef long long LongLong
Definition: format.h:368
Result visit(const Arg &arg)
Definition: format.h:1516
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: printf.h:444