NGL  6.5
The NCCA Graphics Library
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 "fmt/ostream.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() &&
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:
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 } // namespace internal
174 
192 template <typename Impl, typename Char>
193 class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char> {
194  private:
196  this->spec().type_ = 0;
197  this->write("(nil)");
198  }
199 
201 
202  public:
211  : internal::ArgFormatterBase<Impl, Char>(writer, spec) {}
212 
214  void visit_bool(bool value) {
215  FormatSpec &fmt_spec = this->spec();
216  if (fmt_spec.type_ != 's')
217  return this->visit_any_int(value);
218  fmt_spec.type_ = 0;
219  this->write(value);
220  }
221 
223  void visit_char(int value) {
224  const FormatSpec &fmt_spec = this->spec();
225  BasicWriter<Char> &w = this->writer();
226  if (fmt_spec.type_ && fmt_spec.type_ != 'c')
227  w.write_int(value, fmt_spec);
228  typedef typename BasicWriter<Char>::CharPtr CharPtr;
229  CharPtr out = CharPtr();
230  if (fmt_spec.width_ > 1) {
231  Char fill = ' ';
232  out = w.grow_buffer(fmt_spec.width_);
233  if (fmt_spec.align_ != ALIGN_LEFT) {
234  std::fill_n(out, fmt_spec.width_ - 1, fill);
235  out += fmt_spec.width_ - 1;
236  } else {
237  std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
238  }
239  } else {
240  out = w.grow_buffer(1);
241  }
242  *out = static_cast<Char>(value);
243  }
244 
246  void visit_cstring(const char *value) {
247  if (value)
248  Base::visit_cstring(value);
249  else if (this->spec().type_ == 'p')
250  write_null_pointer();
251  else
252  this->write("(null)");
253  }
254 
256  void visit_pointer(const void *value) {
257  if (value)
258  return Base::visit_pointer(value);
259  this->spec().type_ = 0;
260  write_null_pointer();
261  }
262 
265  BasicFormatter<Char> formatter(ArgList(), this->writer());
266  const Char format_str[] = {'}', 0};
267  const Char *format = format_str;
268  c.format(&formatter, c.value, &format);
269  }
270 };
271 
273 template <typename Char>
275  : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char> {
276  public:
279  : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
280 };
281 
283 template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
285  private:
287 
288  void parse_flags(FormatSpec &spec, const Char *&s);
289 
290  // Returns the argument with specified index or, if arg_index is equal
291  // to the maximum unsigned value, the next argument.
292  internal::Arg get_arg(
293  const Char *s,
294  unsigned arg_index = (std::numeric_limits<unsigned>::max)());
295 
296  // Parses argument index, flags and width and returns the argument index.
297  unsigned parse_header(const Char *&s, FormatSpec &spec);
298 
299  public:
307  explicit PrintfFormatter(const ArgList &args, BasicWriter<Char> &w)
308  : FormatterBase(args), writer_(w) {}
309 
311  FMT_API void format(BasicCStringRef<Char> format_str);
312 };
313 
314 template <typename Char, typename AF>
316  for (;;) {
317  switch (*s++) {
318  case '-':
319  spec.align_ = ALIGN_LEFT;
320  break;
321  case '+':
322  spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
323  break;
324  case '0':
325  spec.fill_ = '0';
326  break;
327  case ' ':
328  spec.flags_ |= SIGN_FLAG;
329  break;
330  case '#':
331  spec.flags_ |= HASH_FLAG;
332  break;
333  default:
334  --s;
335  return;
336  }
337  }
338 }
339 
340 template <typename Char, typename AF>
342  unsigned arg_index) {
343  (void)s;
344  const char *error = 0;
345  internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
346  next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
347  if (error)
348  FMT_THROW(FormatError(!*s ? "invalid format string" : error));
349  return arg;
350 }
351 
352 template <typename Char, typename AF>
354  const Char *&s, FormatSpec &spec) {
355  unsigned arg_index = std::numeric_limits<unsigned>::max();
356  Char c = *s;
357  if (c >= '0' && c <= '9') {
358  // Parse an argument index (if followed by '$') or a width possibly
359  // preceded with '0' flag(s).
361  if (*s == '$') { // value is an argument index
362  ++s;
363  arg_index = value;
364  } else {
365  if (c == '0')
366  spec.fill_ = '0';
367  if (value != 0) {
368  // Nonzero value means that we parsed width and don't need to
369  // parse it or flags again, so return now.
370  spec.width_ = value;
371  return arg_index;
372  }
373  }
374  }
375  parse_flags(spec, s);
376  // Parse width.
377  if (*s >= '0' && *s <= '9') {
379  } else if (*s == '*') {
380  ++s;
381  spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));
382  }
383  return arg_index;
384 }
385 
386 template <typename Char, typename AF>
388  const Char *start = format_str.c_str();
389  const Char *s = start;
390  while (*s) {
391  Char c = *s++;
392  if (c != '%') continue;
393  if (*s == c) {
394  write(writer_, start, s);
395  start = ++s;
396  continue;
397  }
398  write(writer_, start, s - 1);
399 
400  FormatSpec spec;
401  spec.align_ = ALIGN_RIGHT;
402 
403  // Parse argument index, flags and width.
404  unsigned arg_index = parse_header(s, spec);
405 
406  // Parse precision.
407  if (*s == '.') {
408  ++s;
409  if ('0' <= *s && *s <= '9') {
410  spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));
411  } else if (*s == '*') {
412  ++s;
413  spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));
414  }
415  }
416 
417  using internal::Arg;
418  Arg arg = get_arg(s, arg_index);
419  if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))
420  spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
421  if (spec.fill_ == '0') {
422  if (arg.type <= Arg::LAST_NUMERIC_TYPE)
423  spec.align_ = ALIGN_NUMERIC;
424  else
425  spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
426  }
427 
428  // Parse length and convert the argument to the required type.
430  switch (*s++) {
431  case 'h':
432  if (*s == 'h')
433  ArgConverter<signed char>(arg, *++s).visit(arg);
434  else
435  ArgConverter<short>(arg, *s).visit(arg);
436  break;
437  case 'l':
438  if (*s == 'l')
439  ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
440  else
441  ArgConverter<long>(arg, *s).visit(arg);
442  break;
443  case 'j':
444  ArgConverter<intmax_t>(arg, *s).visit(arg);
445  break;
446  case 'z':
447  ArgConverter<std::size_t>(arg, *s).visit(arg);
448  break;
449  case 't':
450  ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
451  break;
452  case 'L':
453  // printf produces garbage when 'L' is omitted for long double, no
454  // need to do the same.
455  break;
456  default:
457  --s;
458  ArgConverter<void>(arg, *s).visit(arg);
459  }
460 
461  // Parse type.
462  if (!*s)
463  FMT_THROW(FormatError("invalid format string"));
464  spec.type_ = static_cast<char>(*s++);
465  if (arg.type <= Arg::LAST_INTEGER_TYPE) {
466  // Normalize type.
467  switch (spec.type_) {
468  case 'i': case 'u':
469  spec.type_ = 'd';
470  break;
471  case 'c':
472  // TODO: handle wchar_t
473  internal::CharConverter(arg).visit(arg);
474  break;
475  }
476  }
477 
478  start = s;
479 
480  // Format argument.
481  AF(writer_, spec).visit(arg);
482  }
483  write(writer_, start, s);
484 }
485 
486 template <typename Char>
488  PrintfFormatter<Char>(args, w).format(format);
489 }
490 
501  MemoryWriter w;
502  printf(w, format, args);
503  return w.str();
504 }
506 
507 inline std::wstring sprintf(WCStringRef format, ArgList args) {
509  printf(w, format, args);
510  return w.str();
511 }
512 FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
513 
514 
523 FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
524 FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
525 
526 
535 inline int printf(CStringRef format, ArgList args) {
536  return fprintf(stdout, format, args);
537 }
539 
540 
549 inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
550  MemoryWriter w;
551  printf(w, format_str, args);
552  internal::write(os, w);
553  return static_cast<int>(w.size());
554 }
555 FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
556 } // namespace fmt
557 
558 #endif // FMT_PRINTF_H_
unsigned flags_
Definition: format.h:1648
void visit_cstring(const char *value)
Definition: printf.h:246
bool is_negative(T value)
Definition: format.h:811
FMT_API void format(BasicCStringRef< Char > format_str)
Definition: printf.h:387
#define FMT_VARIADIC(ReturnType, func,...)
Definition: format.h:3440
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1256
void visit_pointer(const void *value)
Definition: printf.h:256
static bool fits_in_int(T value)
Definition: printf.h:26
const GLfloat * c
Definition: glew.h:16629
CharPtr grow_buffer(std::size_t n)
Definition: format.h:2365
FMT_FUNC void write(std::ostream &os, Writer &w)
Definition: ostream.cc:15
std::string format(CStringRef format_str, ArgList args)
Definition: format.h:3175
int visit_any_int(T value)
Definition: printf.h:50
FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args)
Definition: format.cc:507
Definition: format.h:316
internal::Arg & arg_
Definition: printf.h:81
GLsizei const GLfloat * value
Definition: glew.h:1852
WidthHandler(FormatSpec &spec)
Definition: printf.h:153
bool flag(unsigned f) const
Definition: format.h:1656
static bool fits_in_int(bool)
Definition: printf.h:30
typedef void(GLAPIENTRY *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target
Alignment align_
Definition: format.h:1627
unsigned visit_any_int(T value)
Definition: printf.h:160
unsigned parse_nonnegative_int(const Char *&s)
Definition: format.h:3484
PrintfFormatter(const ArgList &args, BasicWriter< Char > &w)
Definition: printf.h:307
internal::Arg & arg_
Definition: printf.h:130
wchar_t fill_
Definition: format.h:1617
#define FMT_THROW(x)
Definition: format.h:172
const Char * c_str() const
Definition: format.h:531
Arg get_arg(unsigned arg_index, const char *&error)
Definition: format.h:1958
#define FMT_API
Definition: format.h:75
void visit_char(int value)
Definition: printf.h:223
PrintfArgFormatter(BasicWriter< Char > &w, FormatSpec &s)
Definition: printf.h:278
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1893
ULongLong ulong_long_value
Definition: format.h:1015
internal::Arg get_arg(const Char *s, unsigned arg_index=(std::numeric_limits< unsigned >::max)())
Definition: printf.h:341
GLuint start
Definition: glew.h:1256
void visit_bool(bool value)
Definition: printf.h:90
std::string sprintf(CStringRef format, ArgList args)
Definition: printf.h:500
BasicPrintfArgFormatter(BasicWriter< Char > &writer, FormatSpec &spec)
Definition: printf.h:210
unsigned parse_header(const Char *&s, FormatSpec &spec)
Definition: printf.h:353
BasicWriter< Char > & writer_
Definition: printf.h:286
static bool fits_in_int(int)
Definition: printf.h:40
#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: format.h:211
void visit_bool(bool value)
Definition: printf.h:214
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: glew.h:1257
internal::CharTraits< Char >::CharPtr CharPtr
Definition: format.h:2349
void visit_any_int(U value)
Definition: printf.h:96
internal::NamedArg< char > arg(StringRef name, const T &arg)
Definition: format.h:3325
unsigned width_
Definition: format.h:1614
LongLong long_long_value
Definition: format.h:1014
Result visit(const Arg &arg)
Definition: format.h:1551
void visit_custom(internal::Arg::CustomValue c)
Definition: printf.h:264
Definition: format.cc:82
void visit_any_int(T value)
Definition: printf.h:138
bool visit_any_int(T value)
Definition: printf.h:61
void parse_flags(FormatSpec &spec, const Char *&s)
Definition: printf.h:315
GLint GLint GLint GLint GLint GLint GLsizei width
Definition: glew.h:1255
ArgConverter(internal::Arg &arg, wchar_t type)
Definition: printf.h:87
static bool fits_in_int(T value)
Definition: printf.h:36
GLdouble s
Definition: glew.h:1393
std::basic_string< Char > str() const
Definition: format.h:2486
unsigned uint_value
Definition: format.h:1013
#define FMT_VARIADIC_W(ReturnType, func,...)
Definition: format.h:3443
internal::ArgFormatterBase< Impl, Char > Base
Definition: printf.h:200
GLsizei const GLchar *const * string
Definition: glew.h:1847
void write_int(T value, Spec spec)
Definition: format.h:2741
FMT_GCC_EXTENSION typedef long long LongLong
Definition: format.h:368
CharConverter(internal::Arg &arg)
Definition: printf.h:135
std::size_t size() const
Definition: format.h:2462
GLclampf f
Definition: glew.h:3511
void printf(BasicWriter< Char > &w, BasicCStringRef< Char > format, ArgList args)
Definition: printf.h:487