HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_FormatImpl.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_FormatImpl.h ( UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __UT_FormatImpl__
12 #define __UT_FormatImpl__
13 
14 #if !defined(__UT_Format__)
15 #error UT_FormatImpl.h should only be included by UT_Format.h
16 #endif
17 
18 #include "UT_StackBuffer.h"
19 
20 #include <SYS/SYS_FormatNumber.h>
21 #include <SYS/SYS_ParseNumber.h>
22 #include <SYS/SYS_String.h>
23 
24 namespace UT { namespace Format {
25 
26 template <typename T, unsigned N>
27 inline size_t
28 ArgValue::customArrayWrapper(
29  char *buffer, size_t buffer_size, const void *value)
30 {
31  const char* beg_str = "[";
32  const char* end_str = "]";
33  Writer writer(buffer, buffer_size);
34  Formatter<> f;
35  const T* ptr = static_cast<const T*>(value);
36  size_t nb_needed = writer(beg_str, beg_str + 1);
37  for (unsigned i = 0; i < N; ++i)
38  {
39  if (i < N - 1)
40  nb_needed += f.format(writer, "{}, ", {ptr[i]});
41  else
42  nb_needed += f.format(writer, "{}", {ptr[i]});
43  }
44  nb_needed += writer(end_str, end_str + 1);
45  return nb_needed;
46 }
47 
48 namespace Detail
49 {
50  // To avoid having to include UT_Unicode.h. Rare enough that we don't
51  // really care about a single function call.
52  UT_API size_t formatCodePoint(
53  char *buffer, size_t buffer_size, utf32 cp);
54 
55  // Returns true if the FILE pointer represents a buffered stream.
56  UT_API bool isBufferedFile(FILE *f);
57 }
58 
59 template<typename W>
60 size_t
62  W &writer,
63  const char *str,
64  size_t str_size,
65  const FormatSpec &spec)
66 {
67  str_size = std::min(str_size, spec.str_width);
68 
69  // Do we need to fill or adjust?
70  if (str_size >= spec.field_width)
71  return writer(str, str + str_size);
72 
73  size_t buf_size = spec.field_width;
74  UT_StackBuffer<char> buf(buf_size);
75  char *ptr = buf.array();
76 
77  switch (spec.align)
78  {
79  case FormatSpec::Left:
80  std::copy(str, str + str_size, ptr);
81  std::fill(ptr + str_size, ptr + buf_size, spec.fill);
82  break;
83  case FormatSpec::Center:
84  {
85  size_t left_size = (buf_size - str_size) / 2;
86  std::fill(ptr, ptr + left_size, spec.fill);
87  std::copy(str, str + str_size, ptr + left_size);
88  std::fill(ptr + left_size + str_size, ptr + buf_size, spec.fill);
89  break;
90  }
91  case FormatSpec::Number:
92  if (str_size && (*str == '-' || *str == '+' || *str == ' '))
93  {
94  *ptr++ = *str++;
95  buf_size--;
96  str_size--;
97  }
98  // no break
99  case FormatSpec::Right:
100  {
101  size_t shift = buf_size - str_size;
102  std::fill(ptr, ptr + shift, spec.fill);
103  std::copy(str, str + str_size, ptr + shift);
104  break;
105  }
106  }
107 
108  return writer(buf.array(), buf.array() + buf.size());
109 }
110 
111 template<typename W>
112 size_t
114  W &writer,
115  const FormatSpec &spec,
116  const ArgValue &arg)
117 {
118  int64 v = getIntValueFromArg(arg);
119 
120  // Clamp so we don't wrap values around for int64, etc.
121  if (v < 0)
122  v = 0;
123  else if (v > std::numeric_limits<int>::max())
125 
126  size_t nb_needed = Detail::formatCodePoint(nullptr, 0, utf32(v));
127  if (!nb_needed)
128  return 0;
129 
130  UT_StackBuffer<char> buf(nb_needed);
131 
132  Detail::formatCodePoint(buf.array(), nb_needed, utf32(v));
133 
134  return formatAdjustAndFill(writer, buf.array(), nb_needed, spec);
135 }
136 
137 template<typename W>
138 size_t
139 Formatter<W>::formatPercentage(
140  W &writer,
141  const FormatSpec &spec,
142  const ArgValue &arg)
143 {
145 
146  if (spec.sign == FormatSpec::Plus || spec.sign == FormatSpec::Space)
147  flags = flags | SYS_FormatFlags::AddPlus;
148 
149  if (spec.digit_grouping)
150  flags = flags | SYS_FormatFlags::DigitGrouping;
151 
152  fpreal64 perc = getFloatValueFromArg(arg) * 100.0;
153 
154  size_t nb_needed = SYSformatFloat(
155  nullptr, 0, perc, spec.precision == -1 ? 2 : spec.precision,
157 
158  UT_StackBuffer<char> buf(nb_needed + 1);
159  SYSformatFloat(buf.array(), nb_needed, perc,
160  spec.precision == -1 ? 2 : spec.precision,
162  buf.array()[nb_needed] = '%';
163 
164  return formatAdjustAndFill(writer, buf.array(), nb_needed + 1, spec);
165 }
166 
167 
168 template<typename W>
169 size_t
170 Formatter<W>::formatInteger(
171  W &writer,
172  const FormatSpec &spec,
173  const ArgValue &arg)
174 {
175  // Figure out the size we need.
177  int base = 10;
178  int min_digits = 0;
179 
180  switch(spec.type)
181  {
182  case 'B':
183  flags = flags | SYS_FormatFlags::UpperCase;
184  // no break
185  case 'b':
186  base = 2;
187  break;
188  case 'c':
189  return formatCodePoint(writer, spec, arg);
190  case 'd':
191  case 'n':
192  base = 10;
193  break;
194  case 'o':
195  base = 8;
196  break;
197  case 'X':
198  flags = flags | SYS_FormatFlags::UpperCase;
199  // no break
200  case 'x':
201  base = 16;
202  break;
203  }
204 
205  if (spec.alt_form)
206  flags = flags | SYS_FormatFlags::AddCPrefix;
207 
208  if (spec.sign == FormatSpec::Plus || spec.sign == FormatSpec::Space)
209  flags = flags | SYS_FormatFlags::AddPlus;
210 
211  if (spec.digit_grouping)
212  flags = flags | SYS_FormatFlags::DigitGrouping;
213 
214  size_t nb_needed = 0;
215 
216 #define SIZE_CASE(TYPE, VAL) \
217  case ArgValue::Type::TYPE: \
218  nb_needed = SYSformatInteger(nullptr, 0, arg.VAL, base, min_digits, flags); \
219  break;
220 
221  switch(arg.type())
222  {
223  SIZE_CASE(Int8, myI8)
224  SIZE_CASE(UInt8, myU8)
225  SIZE_CASE(Int16, myI16)
226  SIZE_CASE(UInt16, myU16)
227  SIZE_CASE(Int32, myI32)
228  SIZE_CASE(UInt32, myU32)
229  SIZE_CASE(Int64, myI64)
230  SIZE_CASE(UInt64, myU64)
231  default:
232  UT_ASSERT_MSG(false, "Not an integer type.");
233  break;
234  }
235 #undef SIZE_CASE
236 
237  UT_StackBuffer<char> buf(nb_needed);
238 
239 #define FMT_CASE(TYPE, VAL) \
240  case ArgValue::Type::TYPE: \
241  SYSformatInteger(buf, nb_needed, arg.VAL, base, min_digits, flags); \
242  break;
243 
244  switch(arg.type())
245  {
246  FMT_CASE(Int8, myI8)
247  FMT_CASE(UInt8, myU8)
248  FMT_CASE(Int16, myI16)
249  FMT_CASE(UInt16, myU16)
250  FMT_CASE(Int32, myI32)
251  FMT_CASE(UInt32, myU32)
252  FMT_CASE(Int64, myI64)
253  FMT_CASE(UInt64, myU64)
254  default:
255  break;
256  }
257 #undef FMT_CASE
258 
259  if (nb_needed && spec.sign == FormatSpec::Space && buf.array()[0] == '+')
260  buf.array()[0] = ' ';
261 
262  return formatAdjustAndFill(writer, buf.array(), nb_needed, spec);
263 }
264 
265 template<typename W>
266 size_t
267 Formatter<W>::formatFloat(
268  W &writer,
269  const FormatSpec &spec,
270  const ArgValue &arg)
271 {
274 
275  switch(spec.type)
276  {
277  case 'E':
278  flags = flags | SYS_FormatFlags::UpperCase;
279  // no break
280  case 'e':
282  break;
283  case 'F':
284  flags = flags | SYS_FormatFlags::UpperCase;
285  // no break
286  case 'f':
287  notation = SYS_FormatNotation::Fixed;
288  break;
289  case 'G':
290  flags = flags | SYS_FormatFlags::UpperCase;
291  // no break
292  case 'g':
293  notation = SYS_FormatNotation::Shortest;
294  break;
295  case 'X':
296  flags = flags | SYS_FormatFlags::UpperCase;
297  // no break
298  case 'x':
300  break;
301  case '%':
302  return formatPercentage(writer, spec, arg);
303  }
304 
305  if (spec.sign == FormatSpec::Plus || spec.sign == FormatSpec::Space)
306  flags = flags | SYS_FormatFlags::AddPlus;
307 
308  if (spec.digit_grouping)
309  flags = flags | SYS_FormatFlags::DigitGrouping;
310 
311  size_t nb_needed = 0;
312 
313 #define SIZE_CASE(TYPE, VAL, PREC) \
314  case ArgValue::Type::TYPE: \
315  nb_needed = SYSformatFloat(nullptr, 0, arg.VAL, \
316  spec.precision == -1 ? PREC : spec.precision, notation, flags); \
317  break;
318  switch(arg.type())
319  {
320  SIZE_CASE(Float16, myF16, 4)
321  SIZE_CASE(Float32, myF32, 6)
322  SIZE_CASE(Float64, myF64, 8)
323  default:
324  UT_ASSERT_MSG(false, "Not a float type.");
325  break;
326  }
327 #undef SIZE_CASE
328 
329  UT_StackBuffer<char> buf(nb_needed);
330 
331 #define SIZE_CASE(TYPE, VAL, PREC) \
332  case ArgValue::Type::TYPE: \
333  SYSformatFloat(buf, nb_needed, arg.VAL, \
334  spec.precision == -1 ? PREC : spec.precision, notation, flags); \
335  break;
336  switch(arg.type())
337  {
338  SIZE_CASE(Float16, myF16, 4)
339  SIZE_CASE(Float32, myF32, 6)
340  SIZE_CASE(Float64, myF64, 8)
341  default:
342  break;
343  }
344 #undef SIZE_CASE
345 
346  if (nb_needed && spec.sign == FormatSpec::Space && buf.array()[0] == '+')
347  buf.array()[0] = ' ';
348 
349  return formatAdjustAndFill(writer, buf.array(), nb_needed, spec);
350 }
351 
352 template<typename W>
353 size_t
354 Formatter<W>::formatString(
355  W &writer,
356  const FormatSpec &spec,
357  const ArgValue &arg)
358 {
359  static const char null[] = "(null)";
360 
361  if (arg.type() == ArgValue::Type::SizedString)
362  {
363  if (arg.mySizedStr.myStr)
364  return formatAdjustAndFill(writer, arg.mySizedStr.myStr, arg.mySizedStr.mySize, spec);
365  }
366  else if (arg.type() == ArgValue::Type::ZeroString)
367  {
368  if (arg.myStr)
369  return formatAdjustAndFill(writer, arg.myStr, ::strlen(arg.myStr), spec);
370  }
371  else if (arg.type() == ArgValue::Type::CharString)
372  {
373  return formatAdjustAndFill(writer, &arg.myChar, 1, spec);
374  }
375  else
376  {
377  UT_ASSERT_MSG(false, "Not a string type");
378  }
379 
380  return formatAdjustAndFill(writer, null, sizeof(null) - 1, spec);
381 }
382 
383 template<typename W>
384 size_t
385 Formatter<W>::formatPointer(
386  W &writer,
387  const FormatSpec &spec,
388  const ArgValue &arg)
389 {
390  UT_ASSERT_MSG(arg.type() == ArgValue::Type::Pointer, "Not a pointer type");
391 
392  uintptr_t val = reinterpret_cast<uintptr_t>(arg.myPtr);
393  int min_digits = sizeof(intptr_t) * 2;
395 
396  size_t nb_needed = SYSformatInteger(nullptr, 0, val, 16, min_digits, flags);
397 
398  UT_StackBuffer<char> buf(nb_needed);
399 
400  SYSformatInteger(buf.array(), nb_needed, val, 16, min_digits, flags);
401 
402  return formatAdjustAndFill(writer, buf.array(), nb_needed, spec);
403 }
404 
405 template<typename W>
406 size_t
407 Formatter<W>::formatCustom(
408  W &writer,
409  const FormatSpec &spec,
410  const ArgValue &arg)
411 {
412  size_t nb_needed = arg.formatCustom(
414 
415  // Don't ask for more than the string width.
416  nb_needed = std::min(nb_needed, spec.str_width);
417 
418  UT_StackBuffer<char> buf(nb_needed);
419 
420  arg.formatCustom(buf.array(), nb_needed);
421 
422  return formatAdjustAndFill(writer, buf.array(), nb_needed, spec);
423 }
424 
425 template<typename W>
426 size_t
427 Formatter<W>::formatArg(
428  W &writer,
429  const FormatSpec &spec,
430  const ArgValue &arg)
431 {
432  if (arg.isInteger())
433  return formatInteger(writer, spec, arg);
434  else if (arg.isFloat())
435  return formatFloat(writer, spec, arg);
436  else if (arg.isString())
437  return formatString(writer, spec, arg);
438  else if (arg.isPointer())
439  return formatPointer(writer, spec, arg);
440  else if (arg.isCustom())
441  return formatCustom(writer, spec, arg);
442  else
443  {
444  UT_ASSERT_MSG(false, "Unknown argument type.");
445  return 0;
446  }
447 }
448 
449 template<typename W>
450 int64
451 Formatter<W>::getIntValueFromArg(const ArgValue &arg)
452 {
453  int64 v = 0;
454  switch(arg.type())
455  {
456  case ArgValue::Type::Int8: v = arg.myI8; break;
457  case ArgValue::Type::UInt8: v = arg.myU8; break;
458  case ArgValue::Type::Int16: v = arg.myI16; break;
459  case ArgValue::Type::UInt16: v = arg.myU16; break;
460  case ArgValue::Type::Int32: v = arg.myI32; break;
461  case ArgValue::Type::UInt32: v = arg.myU32; break;
462  case ArgValue::Type::Int64: v = arg.myI64; break;
463  case ArgValue::Type::UInt64: v = int64(arg.myU64); break;
464  case ArgValue::Type::Float16: v = int64(arg.myF16); break;
465  case ArgValue::Type::Float32: v = int64(arg.myF32); break;
466  case ArgValue::Type::Float64: v = int64(arg.myF64); break;
467  default:
468  // Don't care.
469  break;
470  }
471 
472  return v;
473 }
474 
475 template<typename W>
476 fpreal64
477 Formatter<W>::getFloatValueFromArg(const ArgValue &arg)
478 {
479  fpreal64 v = 0;
480  switch(arg.type())
481  {
482  case ArgValue::Type::Int8: v = fpreal64(arg.myI8); break;
483  case ArgValue::Type::UInt8: v = fpreal64(arg.myU8); break;
484  case ArgValue::Type::Int16: v = fpreal64(arg.myI16); break;
485  case ArgValue::Type::UInt16: v = fpreal64(arg.myU16); break;
486  case ArgValue::Type::Int32: v = fpreal64(arg.myI32); break;
487  case ArgValue::Type::UInt32: v = fpreal64(arg.myU32); break;
488  case ArgValue::Type::Int64: v = fpreal64(arg.myI64); break;
489  case ArgValue::Type::UInt64: v = fpreal64(arg.myU64); break;
490  case ArgValue::Type::Float16: v = fpreal64(arg.myF16); break;
491  case ArgValue::Type::Float32: v = fpreal64(arg.myF32); break;
492  case ArgValue::Type::Float64: v = arg.myF64; break;
493  default:
494  // Don't care.
495  break;
496  }
497 
498  return v;
499 }
500 
501 
502 template<typename W>
503 const ArgValue &
504 Formatter<W>::getFormatArg(
505  const char *&ptr,
506  const ArgValue args[],
507  size_t nb_args)
508 {
509  static ArgValue empty_arg;
510 
511  size_t arg_index;
512 
513  if (SYSisdigit(*ptr))
514  {
515  if (myNextArgIndex > 0)
516  {
517  if (myReportErrors)
518  UT_ASSERT_MSG(false, "Can't switch from auto to manual indexing.");
519  return empty_arg;
520  }
521 
522  const char *end = nullptr;
523  uint64 num;
524  SYSparseInteger(ptr, end, num, 10);
525  arg_index = num;
526  ptr = end;
527  myNextArgIndex = -1;
528  }
529  else if (*ptr == '}' || *ptr == ':')
530  {
531  if (myNextArgIndex < 0)
532  {
533  if (myReportErrors)
534  UT_ASSERT_MSG(false, "Can't switch from manual to auto indexing.");
535  return empty_arg;
536  }
537 
538  arg_index = myNextArgIndex++;
539  }
540  else
541  {
542  if (myReportErrors)
543  UT_ASSERT_MSG(SYSisdigit(*ptr) || *ptr == '}' || *ptr == ':',
544  "Invalid format string.");
545  return empty_arg;
546  }
547 
548  if (arg_index >= nb_args)
549  {
550  if (myReportErrors)
551  UT_ASSERT_MSG(false, "Argument index out of bounds.");
552  return empty_arg;
553  }
554 
555  return args[arg_index];
556 }
557 
558 
559 template<typename W>
560 const ArgValue &
561 Formatter<W>::getPrintfArg(
562  const char *&ptr,
563  const ArgValue args[],
564  size_t nb_args)
565 {
566  static ArgValue empty_arg;
567 
568  size_t arg_index;
569 
570  if (*ptr == '(')
571  {
572  if (!SYSisdigit(ptr[1]))
573  {
574  if (myReportErrors)
575  UT_ASSERT_MSG(SYSisdigit(ptr[1]), "Invalid format string.");
576  return empty_arg;
577  }
578 
579  if (myNextArgIndex > 0)
580  {
581  if (myReportErrors)
582  UT_ASSERT_MSG(false, "Can't switch from auto to manual indexing.");
583  return empty_arg;
584  }
585 
586  const char *end = nullptr;
587  uint64 num;
588  SYSparseInteger(ptr + 1, end, num, 10);
589 
590  if (*end != ')')
591  {
592  if (myReportErrors)
593  UT_ASSERT_MSG(*end == ')', "Invalid format string.");
594  return empty_arg;
595  }
596 
597  arg_index = num;
598  ptr = end + 1;
599  myNextArgIndex = -1;
600  }
601  else
602  {
603  if (myNextArgIndex < 0)
604  {
605  if (myReportErrors)
606  UT_ASSERT_MSG(false, "Can't switch from manual to auto indexing.");
607  return empty_arg;
608  }
609 
610  arg_index = myNextArgIndex++;
611  }
612 
613  if (arg_index >= nb_args)
614  {
615  if (myReportErrors)
616  UT_ASSERT_MSG(false, "Argument index out of bounds.");
617  return empty_arg;
618  }
619 
620  return args[arg_index];
621 }
622 
623 
624 template<typename W>
625 bool
626 Formatter<W>::parseFormatSpec(
627  const char *&ptr,
628  const ArgValue &arg,
629  const ArgValue args[],
630  size_t nb_args,
631  FormatSpec &spec)
632 {
633  auto isAlignmentChar = [](char c) -> bool
634  { return c == '<' || c == '^' || c == '>' || c == '='; };
635 
636  // Numeric values are right-aligned by default.
637  if (arg.isNumeric())
638  spec.align = FormatSpec::Right;
639 
640  // Digit grouping can be globally overridden.
641  spec.digit_grouping = myDigitGroupings;
642 
643  char c = *ptr++;
644 
645  if (c == '}')
646  return true;
647 
648  if (c != ':')
649  {
650  if (myReportErrors)
651  UT_ASSERT_MSG(c != ':', "Invalid format character");
652  return false;
653  }
654 
655  // Parse fill+alignment
656  c = *ptr;
657 
658  char align_char = '\0';
659  char fill_char = '\0';
660 
661  // Check first if the next character is an alignment char, in that case
662  // the first one is the fill char.
663  if (c && isAlignmentChar(ptr[1]))
664  {
665  if (c == '{')
666  {
667  if (myReportErrors)
668  UT_ASSERT_MSG(c != '\0', "'{' is not a valid fill char.");
669  return false;
670  }
671  fill_char = c;
672  align_char = ptr[1];
673  ptr += 2;
674  }
675  else if (isAlignmentChar(c))
676  {
677  align_char = c;
678  ptr++;
679  }
680 
681  switch(align_char)
682  {
683  case '<': spec.align = FormatSpec::Left; break;
684  case '^': spec.align = FormatSpec::Center; break;
685  case '>': spec.align = FormatSpec::Right; break;
686  case '=':
687  // If argument is not numeric, just leave it at the default.
688  if (arg.isNumeric())
689  spec.align = FormatSpec::Number;
690  break;
691  }
692 
693  if (fill_char)
694  spec.fill = fill_char;
695 
696  if (c == '}')
697  return true;
698 
699  // Check sign.
700  switch (*ptr)
701  {
702  case '+': spec.sign = FormatSpec::Plus; ptr++; break;
703  case '-': spec.sign = FormatSpec::Minus; ptr++; break;
704  case ' ': spec.sign = FormatSpec::Space; ptr++; break;
705  }
706 
707  if (*ptr == '#')
708  {
709  spec.alt_form = true;
710  ptr++;
711  }
712 
713  if (*ptr == ',')
714  {
715  spec.digit_grouping = true;
716  ptr++;
717  }
718 
719  if (*ptr == '0')
720  {
721  spec.align = FormatSpec::Number;
722  spec.fill = '0';
723  ptr++;
724  }
725 
726  if (SYSisdigit(*ptr))
727  {
728  const char *end = nullptr;
729  SYSparseInteger(ptr, end, spec.field_width, 10);
730  ptr = end;
731  }
732  else if (*ptr == '{')
733  {
734  ptr++;
735 
736  const ArgValue &warg = getFormatArg(ptr, args, nb_args);
737  if (warg.isEmpty())
738  return false;
739 
740  if (*ptr++ != '}')
741  {
742  if (myReportErrors)
743  UT_ASSERT_MSG(c != '\0', "Missing closing '}' for width argument.");
744  return false;
745  }
746 
747  spec.field_width = (int)std::max(int64(0), getIntValueFromArg(warg));
748  }
749 
750  if (*ptr == '.')
751  {
752  ptr++;
753 
755 
756  if (SYSisdigit(*ptr))
757  {
758  const char *end = nullptr;
759  SYSparseInteger(ptr, end, precision, 10);
760  ptr = end;
761 
762  if (arg.isFloat())
763  spec.precision = precision;
764  else
765  spec.str_width = precision;
766  }
767  else if (*ptr == '{')
768  {
769  ptr++;
770 
771  const ArgValue &parg = getFormatArg(ptr, args, nb_args);
772  if (parg.isEmpty())
773  return false;
774 
775  if (*ptr++ != '}')
776  {
777  if (myReportErrors)
778  UT_ASSERT_MSG(c != '\0', "Missing closing '}' for precision argument.");
779  return false;
780  }
781 
782  precision = (int)std::max(int64(0), getIntValueFromArg(parg));
783 
784  if (arg.isFloat())
785  spec.precision = precision;
786  else
787  spec.str_width = precision;
788  }
789  }
790 
791  if (*ptr && *ptr!= '}')
792  spec.type = *ptr++;
793 
794  if (*ptr++ != '}')
795  {
796  if (myReportErrors)
797  UT_ASSERT_MSG(c != '\0', "Missing closing '}' in format string.");
798  return false;
799  }
800 
801  return true;
802 }
803 
804 
805 template<typename W>
806 bool
807 Formatter<W>::parsePrintfSpec(
808  const char *&ptr,
809  const ArgValue &arg,
810  const ArgValue args[],
811  size_t nb_args,
812  FormatSpec &spec)
813 {
814  // getPrintfArg should've gotten us past any positional argument indicator.
815  spec.align = FormatSpec::Right;
816  spec.digit_grouping = myDigitGroupings;
817 
818  while(*ptr)
819  {
820  if (*ptr == '-')
821  {
822  spec.align = FormatSpec::Left;
823  ptr++;
824  }
825  else if (*ptr == '+' || *ptr == ' ')
826  {
827  spec.sign = *ptr == '+' ? FormatSpec::Plus : FormatSpec::Space;
828  ptr++;
829  }
830  else if (*ptr == '#')
831  {
832  spec.alt_form = true;
833  ptr++;
834  }
835  else if (*ptr == '\'')
836  {
837  spec.digit_grouping = true;
838  ptr++;
839  }
840  else if (*ptr == '0')
841  {
842  if (arg.isNumeric())
843  spec.fill = '0';
844  ptr++;
845  }
846  else
847  break;
848  }
849 
850  // Parse the width.
851  if (SYSisdigit(*ptr))
852  {
853  const char *end = nullptr;
854  SYSparseInteger(ptr, end, spec.field_width, 10);
855  ptr = end;
856  }
857  else if (*ptr == '(')
858  {
859  const ArgValue &warg = getPrintfArg(ptr, args, nb_args);
860  if (warg.isEmpty())
861  return false;
862 
863  spec.field_width = (int)std::max(int64(0), getIntValueFromArg(warg));
864  }
865 
866  // Parse precision, if any.
867  if (*ptr == '.')
868  {
869  ptr++;
870 
872 
873  if (SYSisdigit(*ptr))
874  {
875  const char *end = nullptr;
876  SYSparseInteger(ptr, end, precision, 10);
877  ptr = end;
878 
879  if (arg.isFloat())
880  spec.precision = precision;
881  else
882  spec.str_width = precision;
883  }
884  else if (*ptr == '(')
885  {
886  const ArgValue &parg = getPrintfArg(ptr, args, nb_args);
887  if (parg.isEmpty())
888  return false;
889 
890  precision = (int)std::max(int64(0), getIntValueFromArg(parg));
891 
892  if (arg.isFloat())
893  spec.precision = precision;
894  else
895  spec.str_width = precision;
896  }
897  }
898 
899  // Formatting codes. Skip over the size specifiers.
900  if (*ptr == 'j' || *ptr == 'z' || *ptr == 't' || *ptr == 'L' ||
901  *ptr == 'w' /* MS extension */ )
902  ptr++;
903  else if (*ptr == 'l' || *ptr == 'h')
904  {
905  ptr++;
906  if (ptr[-1] == ptr[0])
907  ++ptr;
908  }
909  else if (*ptr == 'I')
910  {
911  // MS extension
912  ptr++;
913  if (ptr[0] == '3' && ptr[1] == '2')
914  ptr += 2;
915  else if (ptr[0] == '6' && ptr[1] == '4')
916  ptr += 2;
917  }
918 
919  // Specifier
920  if (*ptr == 'd' || *ptr == 'i')
921  {
922  spec.type = 'd';
923  ptr++;
924  }
925  else if (::strchr("bceEfFgGopsuxX", *ptr) != nullptr)
926  {
927  spec.type = *ptr++;
928  }
929  else if (*ptr == 'a' || *ptr == 'A')
930  {
931  spec.type = *ptr == 'a' ? 'x' : 'X';
932  ptr++;
933  }
934  else
935  {
936  if (myReportErrors)
937  UT_ASSERT_MSG(::strchr("aAbcdeEfFgGiopsuxX", *ptr) != nullptr,
938  "Unknown specifier character.");
939  return false;
940  }
941 
942  return true;
943 }
944 
945 template<typename W>
946 size_t
947 Formatter<W>::format(W &writer, const char * format,
948  std::initializer_list<ArgValue> args)
949 {
950  return this->format(writer, format, args.begin(), args.size());
951 }
952 
953 
954 template<typename W>
955 size_t
956 Formatter<W>::format(W &writer, const char * format,
957  const ArgValue args[], size_t nb_args)
958 {
959  if (!format || !*format)
960  return 0;
961 
962  WriteTracker wt(writer);
963 
964  myNextArgIndex = 0;
965 
966  const char *ptr = format;
967 
968  while (*ptr)
969  {
970  char c = *ptr++;
971 
972  // Iterate until we have a curly brace.
973  if (c != '{' && c != '}')
974  continue;
975 
976  // If it's either curly brace repeated, just write out up until the
977  // first brace, skip over the second and continue.
978  if (*ptr == c)
979  {
980  if (!wt.write(format, ptr))
981  return wt.written();
982 
983  format = ++ptr;
984  continue;
985  }
986 
987  // Single close curly brace. That's an error.
988  if (c == '}')
989  {
990  if (myReportErrors)
991  UT_ASSERT_MSG(false, "Unmatched '}' in format string.");
992  return wt.written();
993  }
994 
995  // We have a formatting code. Write what we have so far.
996  if (!wt.write(format, ptr - 1))
997  return wt.written();
998 
999  const ArgValue &arg = getFormatArg(ptr, args, nb_args);
1000  if (arg.isEmpty())
1001  return wt.written();
1002 
1003  FormatSpec spec;
1004  if (!parseFormatSpec(ptr, arg, args, nb_args, spec))
1005  return wt.written();
1006 
1007  wt.increment(formatArg(writer, spec, arg));
1008 
1009  format = ptr;
1010  }
1011 
1012  wt.write(format, ptr);
1013 
1014  return wt.written();
1015 }
1016 
1017 template<typename W>
1018 size_t
1019 Formatter<W>::printf(W &writer, const char * format,
1020  std::initializer_list<ArgValue> args)
1021 {
1022  return this->printf(writer, format, args.begin(), args.size());
1023 }
1024 
1025 template<typename W>
1026 size_t
1027 Formatter<W>::printf(W &writer, const char * format,
1028  const ArgValue args[], size_t nb_args)
1029 {
1030  if (!format || !*format)
1031  return 0;
1032 
1033  WriteTracker wt(writer);
1034 
1035  myNextArgIndex = 0;
1036 
1037  const char *ptr = format;
1038 
1039  while (*ptr)
1040  {
1041  char c = *ptr++;
1042 
1043  // Iterate until we have a %
1044  if (c != '%')
1045  continue;
1046 
1047  // If it's a % repeated, then print it out and continue.
1048  if (*ptr == c)
1049  {
1050  if (!wt.write(format, ptr))
1051  return wt.written();
1052 
1053  format = ++ptr;
1054  continue;
1055  }
1056 
1057  // We have a formatting code. Write what we have so far.
1058  if (!wt.write(format, ptr - 1))
1059  return wt.written();
1060 
1061  const ArgValue &arg = getPrintfArg(ptr, args, nb_args);
1062  if (arg.isEmpty())
1063  return wt.written();
1064 
1065  FormatSpec spec;
1066  if (!parsePrintfSpec(ptr, arg, args, nb_args, spec))
1067  return wt.written();
1068 
1069  wt.increment(formatArg(writer, spec, arg));
1070 
1071  format = ptr;
1072  }
1073 
1074  wt.write(format, ptr);
1075 
1076  return wt.written();
1077 }
1078 
1079 
1080 } }
1081 
1082 template<typename... Args>
1083 size_t UTformat(FILE *file, const char *format, const Args& ...args)
1084 {
1085  if (!file)
1086  return 0;
1087 
1088  using namespace UT::Format;
1089 
1090  FileWriter w(file);
1091 
1092  if (Detail::isBufferedFile(file))
1093  {
1095  return f.format(w, format, {args...});
1096  }
1097  else
1098  {
1099  Writer bw;
1101 
1102  size_t nb_size = f.format(bw, format, {args...});
1103 
1104  UT_StackBuffer<char> s(nb_size);
1105  bw.setBuffer(s.array(), nb_size);
1106  f.format(bw, format, {args...});
1107 
1108  return w(s.begin(), s.end());
1109  }
1110 }
1111 
1112 template<typename... Args>
1113 size_t UTformat(const char *format, const Args& ...args)
1114 {
1115  return UTformat(stdout, format, args...);
1116 }
1117 
1118 
1119 template<typename... Args>
1120 size_t UTformat(std::ostream &os, const char *format, const Args& ...args)
1121 {
1122  using namespace UT::Format;
1123  StreamWriter w(os);
1124 
1126  return f.format(w, format, {args...});
1127 }
1128 
1129 template<typename... Args>
1130 size_t UTformat(char *buffer, size_t buffer_size, const char *format,
1131  const Args& ...args)
1132 {
1133  using namespace UT::Format;
1134  if (!buffer)
1135  buffer_size = std::numeric_limits<size_t>::max();
1136 
1137  Writer w(buffer, buffer_size);
1138 
1140  return f.format(w, format, {args...});
1141 }
1142 
1143 template<typename... Args>
1144 size_t UTprintf(FILE *file, const char *format, const Args& ...args)
1145 {
1146  if (!file)
1147  return 0;
1148 
1149  using namespace UT::Format;
1150 
1151  FileWriter w(file);
1152 
1153  if (Detail::isBufferedFile(file))
1154  {
1156  return f.printf(w, format, {args...});
1157  }
1158  else
1159  {
1160  Writer bw;
1162 
1163  size_t nb_size = f.printf(bw, format, {args...});
1164 
1165  UT_StackBuffer<char> s(nb_size);
1166  bw.setBuffer(s.array(), nb_size);
1167  f.printf(bw, format, {args...});
1168 
1169  return w(s.begin(), s.end());
1170  }
1171 }
1172 
1173 template<typename... Args>
1174 size_t UTprintf(const char *format, const Args& ...args)
1175 {
1176  return UTprintf(stdout, format, args...);
1177 }
1178 
1179 
1180 template<typename... Args>
1181 size_t UTprintf(std::ostream &os, const char *format, const Args& ...args)
1182 {
1183  using namespace UT::Format;
1184  StreamWriter w(os);
1185 
1187  return f.printf(w, format, {args...});
1188 }
1189 
1190 template<typename... Args>
1191 size_t UTprintf(char *buffer, size_t buffer_size, const char *format,
1192  const Args& ...args)
1193 {
1194  using namespace UT::Format;
1195  if (!buffer)
1196  buffer_size = std::numeric_limits<size_t>::max();
1197 
1198  Writer w(buffer, buffer_size);
1199 
1201  return f.printf(w, format, {args...});
1202 }
1203 
1204 
1205 #endif // __UT_FormatImpl__
size_t printf(W &writer, const char *format, std::initializer_list< ArgValue > args)
size_t format(W &writer, const char *format, std::initializer_list< ArgValue > args)
unsigned int utf32
Definition: SYS_Types.h:49
SYS_FormatFlags
SYS_API size_t SYSformatInteger(char *buffer, size_t buffer_size, int8 number, int base=10, int min_digits=0, SYS_FormatFlags flags=SYS_FormatFlags::None)
void setBuffer(char *buffer, size_t buffer_size)
Definition: UT_Format.h:279
size_t UTprintf(FILE *file, const char *format, const Args &...args)
iterator end()
const GLdouble * v
Definition: glcorearb.h:836
size_t UTformat(FILE *file, const char *format, const Args &...args)
UT_API bool isBufferedFile(FILE *f)
png_voidp ptr
Definition: png.h:2145
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1221
GLbitfield flags
Definition: glcorearb.h:1595
#define UT_API
Definition: UT_API.h:13
SYS_FormatNotation
Specifies the notation to use when formatting floating point numbers.
GLuint buffer
Definition: glcorearb.h:659
png_uint_32 i
Definition: png.h:2877
long long int64
Definition: SYS_Types.h:107
GLfloat f
Definition: glcorearb.h:1925
unsigned long long uint64
Definition: SYS_Types.h:108
#define FMT_CASE(TYPE, VAL)
SYS_API SYS_ParseStatus SYSparseInteger(const char *begin, const char *&end, int8 &number, int base=0, SYS_ParseFlags flags=SYS_ParseFlags::None)
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
double fpreal64
Definition: SYS_Types.h:192
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER typedef long long unsigned int Int64
Definition: ImathInt64.h:56
GLuint GLuint end
Definition: glcorearb.h:474
UT_API size_t formatCodePoint(char *buffer, size_t buffer_size, utf32 cp)
A specialized Writer class that writes to a std::ostream object.
Definition: UT_Format.h:320
SYS_API size_t SYSformatFloat(char *buffer, size_t buffer_size, fpreal16 number, uint32 precision=4, SYS_FormatNotation notation=SYS_FormatNotation::Shortest, SYS_FormatFlags flags=SYS_FormatFlags::None)
A specialized Writer class that writes to a stdio FILE buffer.
Definition: UT_Format.h:309
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2539
GLenum GLint GLint * precision
Definition: glcorearb.h:1924
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:107
bool isEmpty() const
Definition: UT_Format.h:508
GLsizei const GLfloat * value
Definition: glcorearb.h:823
#define UT_ASSERT_MSG(ZZ, MM)
Definition: UT_Assert.h:129
typedef int
Definition: png.h:1175
Just output the raw number in the given base.
png_infop png_bytep png_size_t buffer_size
Definition: png.h:2124
GLuint GLfloat * val
Definition: glcorearb.h:1607
GA_API const UT_StringHolder N
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:107
png_infop png_uint_32 int num
Definition: png.h:2158
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:856
if(rank==1) return rank
iterator begin()
#define SIZE_CASE(TYPE, VAL)
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129