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