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