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