printf.c
Go to the documentation of this file.
1 // \author (c) Marco Paland (info@paland.com)
3 // 2014-2019, PALANDesign Hannover, Germany
4 //
5 // \license The MIT License (MIT)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 // THE SOFTWARE.
24 //
25 // \brief Tiny printf, sprintf and (v)SNPRINTF implementation, optimized for speed on
26 // embedded systems with a very limited resources. These routines are thread
27 // safe and reentrant!
28 // Use this instead of the bloated standard/newlib printf cause these use
29 // malloc for printf (and may not be thread safe).
30 //
32 
33 #include <stdbool.h>
34 #include <stdint.h>
35 
36 #include "printf.h"
37 
38 
39 // define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
40 // printf_config.h header file
41 // default: undefined
42 #ifdef PRINTF_INCLUDE_CONFIG_H
43 #include "printf_config.h"
44 #endif
45 
46 
47 // 'ntoa' conversion buffer size, this must be big enough to hold one converted
48 // numeric number including padded zeros (dynamically created on stack)
49 // default: 32 byte
50 #ifndef PRINTF_NTOA_BUFFER_SIZE
51 #define PRINTF_NTOA_BUFFER_SIZE 32U
52 #endif
53 
54 // 'ftoa' conversion buffer size, this must be big enough to hold one converted
55 // float number including padded zeros (dynamically created on stack)
56 // default: 32 byte
57 #ifndef PRINTF_FTOA_BUFFER_SIZE
58 #define PRINTF_FTOA_BUFFER_SIZE 32U
59 #endif
60 
61 // support for the floating point type (%f)
62 // default: activated
63 #ifndef PRINTF_DISABLE_SUPPORT_FLOAT
64 #define PRINTF_SUPPORT_FLOAT
65 #endif
66 
67 // support for exponential floating point notation (%e/%g)
68 // default: activated
69 #ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
70 #define PRINTF_SUPPORT_EXPONENTIAL
71 #endif
72 
73 // define the default floating point precision
74 // default: 6 digits
75 #ifndef PRINTF_DEFAULT_FLOAT_PRECISION
76 #define PRINTF_DEFAULT_FLOAT_PRECISION 6U
77 #endif
78 
79 // define the largest float suitable to print with %f
80 // default: 1e9
81 #ifndef PRINTF_MAX_FLOAT
82 #define PRINTF_MAX_FLOAT 1e9
83 #endif
84 
85 // support for the long long types (%llu or %p)
86 // default: activated
87 #ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
88 #define PRINTF_SUPPORT_LONG_LONG
89 #endif
90 
91 // support for the ptrdiff_t type (%t)
92 // ptrdiff_t is normally defined in <stddef.h> as long or long long type
93 // default: activated
94 #ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
95 #define PRINTF_SUPPORT_PTRDIFF_T
96 #endif
97 
99 
100 // internal flag definitions
101 #define FLAGS_ZEROPAD (1U << 0U)
102 #define FLAGS_LEFT (1U << 1U)
103 #define FLAGS_PLUS (1U << 2U)
104 #define FLAGS_SPACE (1U << 3U)
105 #define FLAGS_HASH (1U << 4U)
106 #define FLAGS_UPPERCASE (1U << 5U)
107 #define FLAGS_CHAR (1U << 6U)
108 #define FLAGS_SHORT (1U << 7U)
109 #define FLAGS_LONG (1U << 8U)
110 #define FLAGS_LONG_LONG (1U << 9U)
111 #define FLAGS_PRECISION (1U << 10U)
112 #define FLAGS_ADAPT_EXP (1U << 11U)
113 
114 
115 // import float.h for DBL_MAX
116 #if defined(PRINTF_SUPPORT_FLOAT)
117 #include <float.h>
118 #endif
119 
120 
121 // output function type
122 typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
123 
124 
125 // wrapper (used as buffer) for output function type
126 typedef struct {
127  void (*fct)(char character, void* arg);
128  void* arg;
130 
131 
132 // internal buffer output
133 static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
134 {
135  if (idx < maxlen) {
136  ((char*)buffer)[idx] = character;
137  }
138 }
139 
140 
141 // internal null output
142 static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
143 {
144  (void)character; (void)buffer; (void)idx; (void)maxlen;
145 }
146 
147 
148 // internal _putchar wrapper
149 static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
150 {
151  (void)buffer; (void)idx; (void)maxlen;
152  if (character) {
153  _putchar(character);
154  }
155 }
156 
157 
158 // internal output function wrapper
159 static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
160 {
161  (void)idx; (void)maxlen;
162  if (character) {
163  // buffer is the output fct pointer
164  ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
165  }
166 }
167 
168 
169 // internal secure strlen
170 // \return The length of the string (excluding the terminating 0) limited by 'maxsize'
171 static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
172 {
173  const char* s;
174  for (s = str; *s && maxsize--; ++s);
175  return (unsigned int)(s - str);
176 }
177 
178 
179 // internal test if char is a digit (0-9)
180 // \return true if char is a digit
181 static inline bool _is_digit(char ch)
182 {
183  return (ch >= '0') && (ch <= '9');
184 }
185 
186 
187 // internal ASCII string to unsigned int conversion
188 static unsigned int _atoi(const char** str)
189 {
190  unsigned int i = 0U;
191  while (_is_digit(**str)) {
192  i = i * 10U + (unsigned int)(*((*str)++) - '0');
193  }
194  return i;
195 }
196 
197 
198 // output the specified string in reverse, taking care of any zero-padding
199 static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
200 {
201  const size_t start_idx = idx;
202 
203  // pad spaces up to given width
204  if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
205  for (size_t i = len; i < width; i++) {
206  out(' ', buffer, idx++, maxlen);
207  }
208  }
209 
210  // reverse string
211  while (len) {
212  out(buf[--len], buffer, idx++, maxlen);
213  }
214 
215  // append pad spaces up to given width
216  if (flags & FLAGS_LEFT) {
217  while (idx - start_idx < width) {
218  out(' ', buffer, idx++, maxlen);
219  }
220  }
221 
222  return idx;
223 }
224 
225 
226 // internal itoa format
227 static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
228 {
229  // pad leading zeros
230  if (!(flags & FLAGS_LEFT)) {
231  if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
232  width--;
233  }
234  while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
235  buf[len++] = '0';
236  }
237  while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
238  buf[len++] = '0';
239  }
240  }
241 
242  // handle hash
243  if (flags & FLAGS_HASH) {
244  if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
245  len--;
246  if (len && (base == 16U)) {
247  len--;
248  }
249  }
250  if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
251  buf[len++] = 'x';
252  }
253  else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
254  buf[len++] = 'X';
255  }
256  else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
257  buf[len++] = 'b';
258  }
259  if (len < PRINTF_NTOA_BUFFER_SIZE) {
260  buf[len++] = '0';
261  }
262  }
263 
264  if (len < PRINTF_NTOA_BUFFER_SIZE) {
265  if (negative) {
266  buf[len++] = '-';
267  }
268  else if (flags & FLAGS_PLUS) {
269  buf[len++] = '+'; // ignore the space if the '+' exists
270  }
271  else if (flags & FLAGS_SPACE) {
272  buf[len++] = ' ';
273  }
274  }
275 
276  return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
277 }
278 
279 
280 // internal itoa for 'long' type
281 static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
282 {
283  char buf[PRINTF_NTOA_BUFFER_SIZE];
284  size_t len = 0U;
285 
286  // no hash for 0 values
287  if (!value) {
288  flags &= ~FLAGS_HASH;
289  }
290 
291  // write if precision != 0 and value is != 0
292  if (!(flags & FLAGS_PRECISION) || value) {
293  do {
294  const char digit = (char)(value % base);
295  buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
296  value /= base;
297  } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
298  }
299 
300  return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
301 }
302 
303 
304 // internal itoa for 'long long' type
305 #if defined(PRINTF_SUPPORT_LONG_LONG)
306 static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
307 {
308  char buf[PRINTF_NTOA_BUFFER_SIZE];
309  size_t len = 0U;
310 
311  // no hash for 0 values
312  if (!value) {
313  flags &= ~FLAGS_HASH;
314  }
315 
316  // write if precision != 0 and value is != 0
317  if (!(flags & FLAGS_PRECISION) || value) {
318  do {
319  const char digit = (char)(value % base);
320  buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
321  value /= base;
322  } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
323  }
324 
325  return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
326 }
327 #endif // PRINTF_SUPPORT_LONG_LONG
328 
329 
330 #if defined(PRINTF_SUPPORT_FLOAT)
331 
332 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
333 // forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
334 static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
335 #endif
336 
337 
338 // internal ftoa for fixed decimal floating point
339 static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
340 {
341  char buf[PRINTF_FTOA_BUFFER_SIZE];
342  size_t len = 0U;
343  double diff = 0.0;
344 
345  // powers of 10
346  static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
347 
348  // test for special values
349  if (value != value)
350  return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
351  if (value < -DBL_MAX)
352  return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
353  if (value > DBL_MAX)
354  return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
355 
356  // test for very large values
357  // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
358  if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
359 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
360  return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
361 #else
362  return 0U;
363 #endif
364  }
365 
366  // test for negative
367  bool negative = false;
368  if (value < 0) {
369  negative = true;
370  value = 0 - value;
371  }
372 
373  // set default precision, if not set explicitly
374  if (!(flags & FLAGS_PRECISION)) {
376  }
377  // limit precision to 9, cause a prec >= 10 can lead to overflow errors
378  while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
379  buf[len++] = '0';
380  prec--;
381  }
382 
383  int whole = (int)value;
384  double tmp = (value - whole) * pow10[prec];
385  unsigned long frac = (unsigned long)tmp;
386  diff = tmp - frac;
387 
388  if (diff > 0.5) {
389  ++frac;
390  // handle rollover, e.g. case 0.99 with prec 1 is 1.0
391  if (frac >= pow10[prec]) {
392  frac = 0;
393  ++whole;
394  }
395  }
396  else if (diff < 0.5) {
397  }
398  else if ((frac == 0U) || (frac & 1U)) {
399  // if halfway, round up if odd OR if last digit is 0
400  ++frac;
401  }
402 
403  if (prec == 0U) {
404  diff = value - (double)whole;
405  if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
406  // exactly 0.5 and ODD, then round up
407  // 1.5 -> 2, but 2.5 -> 2
408  ++whole;
409  }
410  }
411  else {
412  unsigned int count = prec;
413  // now do fractional part, as an unsigned number
414  while (len < PRINTF_FTOA_BUFFER_SIZE) {
415  --count;
416  buf[len++] = (char)(48U + (frac % 10U));
417  if (!(frac /= 10U)) {
418  break;
419  }
420  }
421  // add extra 0s
422  while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
423  buf[len++] = '0';
424  }
425  if (len < PRINTF_FTOA_BUFFER_SIZE) {
426  // add decimal
427  buf[len++] = '.';
428  }
429  }
430 
431  // do whole part, number is reversed
432  while (len < PRINTF_FTOA_BUFFER_SIZE) {
433  buf[len++] = (char)(48 + (whole % 10));
434  if (!(whole /= 10)) {
435  break;
436  }
437  }
438 
439  // pad leading zeros
440  if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
441  if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
442  width--;
443  }
444  while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
445  buf[len++] = '0';
446  }
447  }
448 
449  if (len < PRINTF_FTOA_BUFFER_SIZE) {
450  if (negative) {
451  buf[len++] = '-';
452  }
453  else if (flags & FLAGS_PLUS) {
454  buf[len++] = '+'; // ignore the space if the '+' exists
455  }
456  else if (flags & FLAGS_SPACE) {
457  buf[len++] = ' ';
458  }
459  }
460 
461  return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
462 }
463 
464 
465 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
466 // internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
467 static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
468 {
469  // check for NaN and special values
470  if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
471  return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
472  }
473 
474  // determine the sign
475  const bool negative = value < 0;
476  if (negative) {
477  value = -value;
478  }
479 
480  // default precision
481  if (!(flags & FLAGS_PRECISION)) {
483  }
484 
485  // determine the decimal exponent
486  // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
487  union {
488  uint64_t U;
489  double F;
490  } conv;
491 
492  conv.F = value;
493  int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
494  conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
495  // now approximate log10 from the log2 integer part and an expansion of ln around 1.5
496  int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
497  // now we want to compute 10^expval but we want to be sure it won't overflow
498  exp2 = (int)(expval * 3.321928094887362 + 0.5);
499  const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
500  const double z2 = z * z;
501  conv.U = (uint64_t)(exp2 + 1023) << 52U;
502  // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
503  conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
504  // correct for rounding errors
505  if (value < conv.F) {
506  expval--;
507  conv.F /= 10;
508  }
509 
510  // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
511  unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
512 
513  // in "%g" mode, "prec" is the number of *significant figures* not decimals
514  if (flags & FLAGS_ADAPT_EXP) {
515  // do we want to fall-back to "%f" mode?
516  if ((value >= 1e-4) && (value < 1e6)) {
517  if ((int)prec > expval) {
518  prec = (unsigned)((int)prec - expval - 1);
519  }
520  else {
521  prec = 0;
522  }
523  flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
524  // no characters in exponent
525  minwidth = 0U;
526  expval = 0;
527  }
528  else {
529  // we use one sigfig for the whole part
530  if ((prec > 0) && (flags & FLAGS_PRECISION)) {
531  --prec;
532  }
533  }
534  }
535 
536  // will everything fit?
537  unsigned int fwidth = width;
538  if (width > minwidth) {
539  // we didn't fall-back so subtract the characters required for the exponent
540  fwidth -= minwidth;
541  } else {
542  // not enough characters, so go back to default sizing
543  fwidth = 0U;
544  }
545  if ((flags & FLAGS_LEFT) && minwidth) {
546  // if we're padding on the right, DON'T pad the floating part
547  fwidth = 0U;
548  }
549 
550  // rescale the float value
551  if (expval) {
552  value /= conv.F;
553  }
554 
555  // output the floating part
556  const size_t start_idx = idx;
557  idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
558 
559  // output the exponent part
560  if (minwidth) {
561  // output the exponential symbol
562  out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
563  // output the exponent value
564  idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
565  // might need to right-pad spaces
566  if (flags & FLAGS_LEFT) {
567  while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
568  }
569  }
570  return idx;
571 }
572 #endif // PRINTF_SUPPORT_EXPONENTIAL
573 #endif // PRINTF_SUPPORT_FLOAT
574 
575 
576 // internal vsnprintf
577 static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
578 {
579  unsigned int flags, width, precision, n;
580  size_t idx = 0U;
581 
582  if (!buffer) {
583  // use null output function
584  out = _out_null;
585  }
586 
587  while (*format)
588  {
589  // format specifier? %[flags][width][.precision][length]
590  if (*format != '%') {
591  // no
592  out(*format, buffer, idx++, maxlen);
593  format++;
594  continue;
595  }
596  else {
597  // yes, evaluate it
598  format++;
599  }
600 
601  // evaluate flags
602  flags = 0U;
603  do {
604  switch (*format) {
605  case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
606  case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
607  case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
608  case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
609  case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
610  default : n = 0U; break;
611  }
612  } while (n);
613 
614  // evaluate width field
615  width = 0U;
616  if (_is_digit(*format)) {
617  width = _atoi(&format);
618  }
619  else if (*format == '*') {
620  const int w = va_arg(va, int);
621  if (w < 0) {
622  flags |= FLAGS_LEFT; // reverse padding
623  width = (unsigned int)-w;
624  }
625  else {
626  width = (unsigned int)w;
627  }
628  format++;
629  }
630 
631  // evaluate precision field
632  precision = 0U;
633  if (*format == '.') {
634  flags |= FLAGS_PRECISION;
635  format++;
636  if (_is_digit(*format)) {
637  precision = _atoi(&format);
638  }
639  else if (*format == '*') {
640  const int prec = (int)va_arg(va, int);
641  precision = prec > 0 ? (unsigned int)prec : 0U;
642  format++;
643  }
644  }
645 
646  // evaluate length field
647  switch (*format) {
648  case 'l' :
649  flags |= FLAGS_LONG;
650  format++;
651  if (*format == 'l') {
652  flags |= FLAGS_LONG_LONG;
653  format++;
654  }
655  break;
656  case 'h' :
657  flags |= FLAGS_SHORT;
658  format++;
659  if (*format == 'h') {
660  flags |= FLAGS_CHAR;
661  format++;
662  }
663  break;
664 #if defined(PRINTF_SUPPORT_PTRDIFF_T)
665  case 't' :
666  flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
667  format++;
668  break;
669 #endif
670  case 'j' :
671  flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
672  format++;
673  break;
674  case 'z' :
675  flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
676  format++;
677  break;
678  default :
679  break;
680  }
681 
682  // evaluate specifier
683  switch (*format) {
684  case 'd' :
685  case 'i' :
686  case 'u' :
687  case 'x' :
688  case 'X' :
689  case 'o' :
690  case 'b' : {
691  // set the base
692  unsigned int base;
693  if (*format == 'x' || *format == 'X') {
694  base = 16U;
695  }
696  else if (*format == 'o') {
697  base = 8U;
698  }
699  else if (*format == 'b') {
700  base = 2U;
701  }
702  else {
703  base = 10U;
704  flags &= ~FLAGS_HASH; // no hash for dec format
705  }
706  // uppercase
707  if (*format == 'X') {
708  flags |= FLAGS_UPPERCASE;
709  }
710 
711  // no plus or space flag for u, x, X, o, b
712  if ((*format != 'i') && (*format != 'd')) {
713  flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
714  }
715 
716  // ignore '0' flag when precision is given
717  if (flags & FLAGS_PRECISION) {
718  flags &= ~FLAGS_ZEROPAD;
719  }
720 
721  // convert the integer
722  if ((*format == 'i') || (*format == 'd')) {
723  // signed
724  if (flags & FLAGS_LONG_LONG) {
725 #if defined(PRINTF_SUPPORT_LONG_LONG)
726  const long long value = va_arg(va, long long);
727  idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
728 #endif
729  }
730  else if (flags & FLAGS_LONG) {
731  const long value = va_arg(va, long);
732  idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
733  }
734  else {
735  const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
736  idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
737  }
738  }
739  else {
740  // unsigned
741  if (flags & FLAGS_LONG_LONG) {
742 #if defined(PRINTF_SUPPORT_LONG_LONG)
743  idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
744 #endif
745  }
746  else if (flags & FLAGS_LONG) {
747  idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
748  }
749  else {
750  const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
751  idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
752  }
753  }
754  format++;
755  break;
756  }
757 #if defined(PRINTF_SUPPORT_FLOAT)
758  case 'f' :
759  case 'F' :
760  if (*format == 'F') flags |= FLAGS_UPPERCASE;
761  idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
762  format++;
763  break;
764 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
765  case 'e':
766  case 'E':
767  case 'g':
768  case 'G':
769  if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
770  if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
771  idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
772  format++;
773  break;
774 #endif // PRINTF_SUPPORT_EXPONENTIAL
775 #endif // PRINTF_SUPPORT_FLOAT
776  case 'c' : {
777  unsigned int l = 1U;
778  // pre padding
779  if (!(flags & FLAGS_LEFT)) {
780  while (l++ < width) {
781  out(' ', buffer, idx++, maxlen);
782  }
783  }
784  // char output
785  out((char)va_arg(va, int), buffer, idx++, maxlen);
786  // post padding
787  if (flags & FLAGS_LEFT) {
788  while (l++ < width) {
789  out(' ', buffer, idx++, maxlen);
790  }
791  }
792  format++;
793  break;
794  }
795 
796  case 's' : {
797  const char* p = va_arg(va, char*);
798  unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
799  // pre padding
800  if (flags & FLAGS_PRECISION) {
801  l = (l < precision ? l : precision);
802  }
803  if (!(flags & FLAGS_LEFT)) {
804  while (l++ < width) {
805  out(' ', buffer, idx++, maxlen);
806  }
807  }
808  // string output
809  while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
810  out(*(p++), buffer, idx++, maxlen);
811  }
812  // post padding
813  if (flags & FLAGS_LEFT) {
814  while (l++ < width) {
815  out(' ', buffer, idx++, maxlen);
816  }
817  }
818  format++;
819  break;
820  }
821 
822  case 'p' : {
823  width = sizeof(void*) * 2U;
824  flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
825 #if defined(PRINTF_SUPPORT_LONG_LONG)
826  const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
827  if (is_ll) {
828  idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
829  }
830  else {
831 #endif
832  idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
833 #if defined(PRINTF_SUPPORT_LONG_LONG)
834  }
835 #endif
836  format++;
837  break;
838  }
839 
840  case '%' :
841  out('%', buffer, idx++, maxlen);
842  format++;
843  break;
844 
845  default :
846  out(*format, buffer, idx++, maxlen);
847  format++;
848  break;
849  }
850  }
851 
852  // termination
853  out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
854 
855  // return written chars without terminating \0
856  return (int)idx;
857 }
858 
859 
861 
862 int printf_(const char* format, ...)
863 {
864  va_list va;
865  va_start(va, format);
866  char buffer[1];
867  const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
868  va_end(va);
869  return ret;
870 }
871 
872 
873 int sprintf_(char* buffer, const char* format, ...)
874 {
875  va_list va;
876  va_start(va, format);
877  const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
878  va_end(va);
879  return ret;
880 }
881 
882 
883 int snprintf_(char* buffer, size_t count, const char* format, ...)
884 {
885  va_list va;
886  va_start(va, format);
887  const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
888  va_end(va);
889  return ret;
890 }
891 
892 
893 int vprintf_(const char* format, va_list va)
894 {
895  char buffer[1];
896  return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
897 }
898 
899 
900 int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
901 {
902  return _vsnprintf(_out_buffer, buffer, count, format, va);
903 }
904 
905 
906 int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
907 {
908  va_list va;
909  va_start(va, format);
910  const out_fct_wrap_type out_fct_wrap = { out, arg };
911  const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
912  va_end(va);
913  return ret;
914 }
static size_t _ntoa_format(out_fct_type out, char *buffer, size_t idx, size_t maxlen, char *buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
Definition: printf.c:227
static void _out_fct(char character, void *buffer, size_t idx, size_t maxlen)
Definition: printf.c:159
static bool _is_digit(char ch)
Definition: printf.c:181
static unsigned int _strnlen_s(const char *str, size_t maxsize)
Definition: printf.c:171
#define FLAGS_LONG
Definition: test_suite.cpp:109
int vprintf_(const char *format, va_list va)
Definition: printf.c:893
#define FLAGS_PLUS
Definition: test_suite.cpp:103
XmlRpcServer s
GeneratorWrapper< T > value(T &&value)
Definition: catch.hpp:3589
#define FLAGS_ZEROPAD
Definition: test_suite.cpp:101
size_t count(InputIterator first, InputIterator last, T const &item)
Definition: catch.hpp:3206
static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
Definition: printf.c:306
#define PRINTF_FTOA_BUFFER_SIZE
Definition: printf.c:58
#define PRINTF_NTOA_BUFFER_SIZE
Definition: printf.c:51
#define FLAGS_UPPERCASE
Definition: test_suite.cpp:106
static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
Definition: printf.c:281
#define FLAGS_HASH
Definition: test_suite.cpp:105
void _putchar(char character)
#define FLAGS_ADAPT_EXP
Definition: test_suite.cpp:112
int fctprintf(void(*out)(char character, void *arg), void *arg, const char *format,...)
Definition: printf.c:906
int sprintf_(char *buffer, const char *format,...)
Definition: printf.c:873
#define PRINTF_DEFAULT_FLOAT_PRECISION
Definition: printf.c:76
static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
Definition: printf.c:339
static unsigned int _atoi(const char **str)
Definition: printf.c:188
#define FLAGS_CHAR
Definition: test_suite.cpp:107
static void _out_buffer(char character, void *buffer, size_t idx, size_t maxlen)
Definition: printf.c:133
static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
Definition: printf.c:467
static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, const char *format, va_list va)
Definition: printf.c:577
#define FLAGS_SPACE
Definition: test_suite.cpp:104
void(* out_fct_type)(char character, void *buffer, size_t idx, size_t maxlen)
Definition: printf.c:122
#define FLAGS_LONG_LONG
Definition: test_suite.cpp:110
static size_t _out_rev(out_fct_type out, char *buffer, size_t idx, size_t maxlen, const char *buf, size_t len, unsigned int width, unsigned int flags)
Definition: printf.c:199
int printf_(const char *format,...)
Definition: printf.c:862
int vsnprintf_(char *buffer, size_t count, const char *format, va_list va)
Definition: printf.c:900
#define FLAGS_SHORT
Definition: test_suite.cpp:108
static void _out_char(char character, void *buffer, size_t idx, size_t maxlen)
Definition: printf.c:149
static void _out_null(char character, void *buffer, size_t idx, size_t maxlen)
Definition: printf.c:142
int snprintf_(char *buffer, size_t count, const char *format,...)
Definition: printf.c:883
#define PRINTF_MAX_FLOAT
Definition: printf.c:82
#define FLAGS_LEFT
Definition: test_suite.cpp:102
#define FLAGS_PRECISION
Definition: test_suite.cpp:111


inertial_sense_ros
Author(s):
autogenerated on Sun Feb 28 2021 03:17:58