1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/mpaland/printf
3 // Copyright (C) Marco Paland 2014-2019, PALANDesign Hannover, Germany
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
18 // Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
19 // embedded systems with a very limited resources. These routines are thread
20 // safe and reentrant!
21 // Use this instead of the bloated standard/newlib printf cause these use
22 // malloc for printf (and may not be thread safe).
23 //-----------------------------------------------------------------------------
28 // define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
29 // printf_config.h header file
31 #ifdef PRINTF_INCLUDE_CONFIG_H
32 #include "printf_config.h"
36 // 'ntoa' conversion buffer size, this must be big enough to hold one converted
37 // numeric number including padded zeros (dynamically created on stack)
39 #ifndef PRINTF_NTOA_BUFFER_SIZE
40 #define PRINTF_NTOA_BUFFER_SIZE 32U
43 // 'ftoa' conversion buffer size, this must be big enough to hold one converted
44 // float number including padded zeros (dynamically created on stack)
46 #ifndef PRINTF_FTOA_BUFFER_SIZE
47 #define PRINTF_FTOA_BUFFER_SIZE 32U
50 // support for the floating point type (%f)
52 #ifndef PRINTF_DISABLE_SUPPORT_FLOAT
53 #define PRINTF_SUPPORT_FLOAT
56 // support for exponential floating point notation (%e/%g)
58 #ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
59 #define PRINTF_SUPPORT_EXPONENTIAL
62 // define the default floating point precision
64 #ifndef PRINTF_DEFAULT_FLOAT_PRECISION
65 #define PRINTF_DEFAULT_FLOAT_PRECISION 6U
68 // define the largest float suitable to print with %f
70 #ifndef PRINTF_MAX_FLOAT
71 #define PRINTF_MAX_FLOAT 1e9
74 // support for the long long types (%llu or %p)
76 #ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
77 #define PRINTF_SUPPORT_LONG_LONG
80 // support for the ptrdiff_t type (%t)
81 // ptrdiff_t is normally defined in <stddef.h> as long or long long type
83 #ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
84 #define PRINTF_SUPPORT_PTRDIFF_T
87 ///////////////////////////////////////////////////////////////////////////////
89 // internal flag definitions
90 #define FLAGS_ZEROPAD (1U << 0U)
91 #define FLAGS_LEFT (1U << 1U)
92 #define FLAGS_PLUS (1U << 2U)
93 #define FLAGS_SPACE (1U << 3U)
94 #define FLAGS_HASH (1U << 4U)
95 #define FLAGS_UPPERCASE (1U << 5U)
96 #define FLAGS_CHAR (1U << 6U)
97 #define FLAGS_SHORT (1U << 7U)
98 #define FLAGS_LONG (1U << 8U)
99 #define FLAGS_LONG_LONG (1U << 9U)
100 #define FLAGS_PRECISION (1U << 10U)
101 #define FLAGS_ADAPT_EXP (1U << 11U)
104 // import float.h for DBL_MAX
105 #if defined(PRINTF_SUPPORT_FLOAT)
110 // output function type
111 typedef void (*out_fct_type
)(char character
, void *buffer
, size_t idx
, size_t maxlen
);
114 // wrapper (used as buffer) for output function type
116 void (*fct
)(char character
, void *arg
);
121 // internal buffer output
122 static void _out_buffer(char character
, void *buffer
, size_t idx
, size_t maxlen
) {
124 ((char *)buffer
)[idx
] = character
;
129 // internal null output
130 static void _out_null(char character
, void *buffer
, size_t idx
, size_t maxlen
) {
138 // internal _putchar wrapper
139 static void _out_char(char character
, void *buffer
, size_t idx
, size_t maxlen
) {
149 // internal output function wrapper
150 static void _out_fct(char character
, void *buffer
, size_t idx
, size_t maxlen
) {
154 // buffer is the output fct pointer
155 ((out_fct_wrap_type
*)buffer
)->fct(character
, ((out_fct_wrap_type
*)buffer
)->arg
);
160 // internal secure strlen
161 // \return The length of the string (excluding the terminating 0) limited by 'maxsize'
162 static unsigned int _strnlen_s(const char *str
, size_t maxsize
) {
164 for (s
= str
; *s
&& maxsize
--; ++s
);
165 return (unsigned int)(s
- str
);
169 // internal test if char is a digit (0-9)
170 // \return true if char is a digit
171 static bool _is_digit(char ch
) {
172 return (ch
>= '0') && (ch
<= '9');
176 // internal ASCII string to unsigned int conversion
177 static unsigned int _atoi(const char **str
) {
179 while (_is_digit(**str
)) {
180 i
= i
* 10U + (unsigned int)(*((*str
)++) - '0');
186 // output the specified string in reverse, taking care of any zero-padding
187 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
) {
188 const size_t start_idx
= idx
;
190 // pad spaces up to given width
191 if (!(flags
& FLAGS_LEFT
) && !(flags
& FLAGS_ZEROPAD
)) {
192 for (size_t i
= len
; i
< width
; i
++) {
193 out(' ', buffer
, idx
++, maxlen
);
199 out(buf
[--len
], buffer
, idx
++, maxlen
);
202 // append pad spaces up to given width
203 if (flags
& FLAGS_LEFT
) {
204 while (idx
- start_idx
< width
) {
205 out(' ', buffer
, idx
++, maxlen
);
213 // internal itoa format
214 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
) {
216 if (!(flags
& FLAGS_LEFT
)) {
217 if (width
&& (flags
& FLAGS_ZEROPAD
) && (negative
|| (flags
& (FLAGS_PLUS
| FLAGS_SPACE
)))) {
220 while ((len
< prec
) && (len
< PRINTF_NTOA_BUFFER_SIZE
)) {
223 while ((flags
& FLAGS_ZEROPAD
) && (len
< width
) && (len
< PRINTF_NTOA_BUFFER_SIZE
)) {
229 if (flags
& FLAGS_HASH
) {
230 if (!(flags
& FLAGS_PRECISION
) && len
&& ((len
== prec
) || (len
== width
))) {
232 if (len
&& (base
== 16U)) {
236 if ((base
== 16U) && !(flags
& FLAGS_UPPERCASE
) && (len
< PRINTF_NTOA_BUFFER_SIZE
)) {
238 } else if ((base
== 16U) && (flags
& FLAGS_UPPERCASE
) && (len
< PRINTF_NTOA_BUFFER_SIZE
)) {
240 } else if ((base
== 2U) && (len
< PRINTF_NTOA_BUFFER_SIZE
)) {
243 if (len
< PRINTF_NTOA_BUFFER_SIZE
) {
248 if (len
< PRINTF_NTOA_BUFFER_SIZE
) {
251 } else if (flags
& FLAGS_PLUS
) {
252 buf
[len
++] = '+'; // ignore the space if the '+' exists
253 } else if (flags
& FLAGS_SPACE
) {
258 return _out_rev(out
, buffer
, idx
, maxlen
, buf
, len
, width
, flags
);
262 // internal itoa for 'long' type
263 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
) {
264 char buf
[PRINTF_NTOA_BUFFER_SIZE
];
267 // no hash for 0 values
269 flags
&= ~FLAGS_HASH
;
272 // write if precision != 0 and value is != 0
273 if (!(flags
& FLAGS_PRECISION
) || value
) {
275 const char digit
= (char)(value
% base
);
276 buf
[len
++] = digit
< 10 ? '0' + digit
: ((flags
& FLAGS_UPPERCASE
) ? 'A' : 'a') + digit
- 10;
278 } while (value
&& (len
< PRINTF_NTOA_BUFFER_SIZE
));
281 return _ntoa_format(out
, buffer
, idx
, maxlen
, buf
, len
, negative
, (unsigned int)base
, prec
, width
, flags
);
285 // internal itoa for 'long long' type
286 #if defined(PRINTF_SUPPORT_LONG_LONG)
287 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
) {
288 char buf
[PRINTF_NTOA_BUFFER_SIZE
];
291 // no hash for 0 values
293 flags
&= ~FLAGS_HASH
;
296 // write if precision != 0 and value is != 0
297 if (!(flags
& FLAGS_PRECISION
) || value
) {
299 const char digit
= (char)(value
% base
);
300 buf
[len
++] = digit
< 10 ? '0' + digit
: ((flags
& FLAGS_UPPERCASE
) ? 'A' : 'a') + digit
- 10;
302 } while (value
&& (len
< PRINTF_NTOA_BUFFER_SIZE
));
305 return _ntoa_format(out
, buffer
, idx
, maxlen
, buf
, len
, negative
, (unsigned int)base
, prec
, width
, flags
);
307 #endif // PRINTF_SUPPORT_LONG_LONG
310 #if defined(PRINTF_SUPPORT_FLOAT)
312 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
313 // forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
314 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
);
318 // internal ftoa for fixed decimal floating point
319 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
) {
320 char buf
[PRINTF_FTOA_BUFFER_SIZE
];
325 static const double pow10
[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
327 // test for special values
329 return _out_rev(out
, buffer
, idx
, maxlen
, "nan", 3, width
, flags
);
330 if (value
< -DBL_MAX
)
331 return _out_rev(out
, buffer
, idx
, maxlen
, "fni-", 4, width
, flags
);
333 return _out_rev(out
, buffer
, idx
, maxlen
, (flags
& FLAGS_PLUS
) ? "fni+" : "fni", (flags
& FLAGS_PLUS
) ? 4U : 3U, width
, flags
);
335 // test for very large values
336 // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
337 if ((value
> PRINTF_MAX_FLOAT
) || (value
< -PRINTF_MAX_FLOAT
)) {
338 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
339 return _etoa(out
, buffer
, idx
, maxlen
, value
, prec
, width
, flags
);
346 bool negative
= false;
352 // set default precision, if not set explicitly
353 if (!(flags
& FLAGS_PRECISION
)) {
354 prec
= PRINTF_DEFAULT_FLOAT_PRECISION
;
356 // limit precision to 9, cause a prec >= 10 can lead to overflow errors
357 while ((len
< PRINTF_FTOA_BUFFER_SIZE
)) {
366 int whole
= (int)value
;
367 double tmp
= (value
- whole
) * pow10
[prec
];
368 unsigned long frac
= (unsigned long)tmp
;
373 // handle rollover, e.g. case 0.99 with prec 1 is 1.0
374 if (frac
>= pow10
[prec
]) {
378 } else if (diff
< 0.5) {
379 } else if ((frac
== 0U) || (frac
& 1U)) {
380 // if halfway, round up if odd OR if last digit is 0
385 diff
= value
- (double)whole
;
386 if (((diff
< 0.5) == false) || (whole
& 1)) {
387 // exactly 0.5 and ODD, then round up
388 // 1.5 -> 2, but 2.5 -> 2
392 unsigned int count
= prec
;
393 // now do fractional part, as an unsigned number
394 while (len
< PRINTF_FTOA_BUFFER_SIZE
) {
396 buf
[len
++] = (char)(48U + (frac
% 10U));
397 if (!(frac
/= 10U)) {
402 while ((len
< PRINTF_FTOA_BUFFER_SIZE
) && (count
-- > 0U)) {
405 if (len
< PRINTF_FTOA_BUFFER_SIZE
) {
411 // do whole part, number is reversed
412 while (len
< PRINTF_FTOA_BUFFER_SIZE
) {
413 buf
[len
++] = (char)(48 + (whole
% 10));
414 if (!(whole
/= 10)) {
420 if (!(flags
& FLAGS_LEFT
) && (flags
& FLAGS_ZEROPAD
)) {
421 if (width
&& (negative
|| (flags
& (FLAGS_PLUS
| FLAGS_SPACE
)))) {
424 while ((len
< width
) && (len
< PRINTF_FTOA_BUFFER_SIZE
)) {
429 if (len
< PRINTF_FTOA_BUFFER_SIZE
) {
432 } else if (flags
& FLAGS_PLUS
) {
433 buf
[len
++] = '+'; // ignore the space if the '+' exists
434 } else if (flags
& FLAGS_SPACE
) {
439 return _out_rev(out
, buffer
, idx
, maxlen
, buf
, len
, width
, flags
);
443 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
444 // internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
445 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
) {
446 // check for NaN and special values
447 if ((value
!= value
) || (value
> DBL_MAX
) || (value
< -DBL_MAX
)) {
448 return _ftoa(out
, buffer
, idx
, maxlen
, value
, prec
, width
, flags
);
451 // determine the sign
452 const bool negative
= value
< 0;
458 if (!(flags
& FLAGS_PRECISION
)) {
459 prec
= PRINTF_DEFAULT_FLOAT_PRECISION
;
462 // determine the decimal exponent
463 // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
470 int exp2
= (int)((conv
.U
>> 52U) & 0x07FFU
) - 1023; // effectively log2
471 conv
.U
= (conv
.U
& ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
472 // now approximate log10 from the log2 integer part and an expansion of ln around 1.5
473 int expval
= (int)(0.1760912590558 + exp2
* 0.301029995663981 + (conv
.F
- 1.5) * 0.289529654602168);
474 // now we want to compute 10^expval but we want to be sure it won't overflow
475 exp2
= (int)(expval
* 3.321928094887362 + 0.5);
476 const double z
= expval
* 2.302585092994046 - exp2
* 0.6931471805599453;
477 const double z2
= z
* z
;
478 conv
.U
= (uint64_t)(exp2
+ 1023) << 52U;
479 // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
480 conv
.F
*= 1 + 2 * z
/ (2 - z
+ (z2
/ (6 + (z2
/ (10 + z2
/ 14)))));
481 // correct for rounding errors
482 if (value
< conv
.F
) {
487 // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
488 unsigned int minwidth
= ((expval
< 100) && (expval
> -100)) ? 4U : 5U;
490 // in "%g" mode, "prec" is the number of *significant figures* not decimals
491 if (flags
& FLAGS_ADAPT_EXP
) {
492 // do we want to fall-back to "%f" mode?
493 if ((value
>= 1e-4) && (value
< 1e6
)) {
494 if ((int)prec
> expval
) {
495 prec
= (unsigned)((int)prec
- expval
- 1);
499 flags
|= FLAGS_PRECISION
; // make sure _ftoa respects precision
500 // no characters in exponent
504 // we use one sigfig for the whole part
505 if ((prec
> 0) && (flags
& FLAGS_PRECISION
)) {
511 // will everything fit?
512 unsigned int fwidth
= width
;
513 if (width
> minwidth
) {
514 // we didn't fall-back so subtract the characters required for the exponent
517 // not enough characters, so go back to default sizing
520 if ((flags
& FLAGS_LEFT
) && minwidth
) {
521 // if we're padding on the right, DON'T pad the floating part
525 // rescale the float value
530 // output the floating part
531 const size_t start_idx
= idx
;
532 idx
= _ftoa(out
, buffer
, idx
, maxlen
, negative
? -value
: value
, prec
, fwidth
, flags
& ~FLAGS_ADAPT_EXP
);
534 // output the exponent part
536 // output the exponential symbol
537 out((flags
& FLAGS_UPPERCASE
) ? 'E' : 'e', buffer
, idx
++, maxlen
);
538 // output the exponent value
539 idx
= _ntoa_long(out
, buffer
, idx
, maxlen
, (expval
< 0) ? -expval
: expval
, expval
< 0, 10, 0, minwidth
- 1, FLAGS_ZEROPAD
| FLAGS_PLUS
);
540 // might need to right-pad spaces
541 if (flags
& FLAGS_LEFT
) {
542 while (idx
- start_idx
< width
) out(' ', buffer
, idx
++, maxlen
);
547 #endif // PRINTF_SUPPORT_EXPONENTIAL
548 #endif // PRINTF_SUPPORT_FLOAT
551 // internal vsnprintf
552 static int _vsnprintf(out_fct_type out
, char *buffer
, const size_t maxlen
, const char *format
, va_list va
) {
553 unsigned int flags
, width
, precision
, n
;
557 // use null output function
562 // format specifier? %[flags][width][.precision][length]
563 if (*format
!= '%') {
565 out(*format
, buffer
, idx
++, maxlen
);
578 flags
|= FLAGS_ZEROPAD
;
593 flags
|= FLAGS_SPACE
;
608 // evaluate width field
610 if (_is_digit(*format
)) {
611 width
= _atoi(&format
);
612 } else if (*format
== '*') {
613 const int w
= va_arg(va
, int);
615 flags
|= FLAGS_LEFT
; // reverse padding
616 width
= (unsigned int) - w
;
618 width
= (unsigned int)w
;
623 // evaluate precision field
625 if (*format
== '.') {
626 flags
|= FLAGS_PRECISION
;
628 if (_is_digit(*format
)) {
629 precision
= _atoi(&format
);
630 } else if (*format
== '*') {
631 const int prec
= (int)va_arg(va
, int);
632 precision
= prec
> 0 ? (unsigned int)prec
: 0U;
637 // evaluate length field
642 if (*format
== 'l') {
643 flags
|= FLAGS_LONG_LONG
;
648 flags
|= FLAGS_SHORT
;
650 if (*format
== 'h') {
655 #if defined(PRINTF_SUPPORT_PTRDIFF_T)
657 flags
|= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG
: FLAGS_LONG_LONG
);
662 flags
|= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG
: FLAGS_LONG_LONG
);
666 flags
|= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG
: FLAGS_LONG_LONG
);
673 // evaluate specifier
684 if (*format
== 'x' || *format
== 'X') {
686 } else if (*format
== 'o') {
688 } else if (*format
== 'b') {
692 flags
&= ~FLAGS_HASH
; // no hash for dec format
695 if (*format
== 'X') {
696 flags
|= FLAGS_UPPERCASE
;
699 // no plus or space flag for u, x, X, o, b
700 if ((*format
!= 'i') && (*format
!= 'd')) {
701 flags
&= ~(FLAGS_PLUS
| FLAGS_SPACE
);
704 // ignore '0' flag when precision is given
705 if (flags
& FLAGS_PRECISION
) {
706 flags
&= ~FLAGS_ZEROPAD
;
709 // convert the integer
710 if ((*format
== 'i') || (*format
== 'd')) {
712 if (flags
& FLAGS_LONG_LONG
) {
713 #if defined(PRINTF_SUPPORT_LONG_LONG)
714 const long long value
= va_arg(va
, long long);
715 idx
= _ntoa_long_long(out
, buffer
, idx
, maxlen
, (unsigned long long)(value
> 0 ? value
: 0 - value
), value
< 0, base
, precision
, width
, flags
);
717 } else if (flags
& FLAGS_LONG
) {
718 const long value
= va_arg(va
, long);
719 idx
= _ntoa_long(out
, buffer
, idx
, maxlen
, (unsigned long)(value
> 0 ? value
: 0 - value
), value
< 0, base
, precision
, width
, flags
);
721 const int value
= (flags
& FLAGS_CHAR
) ? (char)va_arg(va
, int) : (flags
& FLAGS_SHORT
) ? (short int)va_arg(va
, int) : va_arg(va
, int);
722 idx
= _ntoa_long(out
, buffer
, idx
, maxlen
, (unsigned int)(value
> 0 ? value
: 0 - value
), value
< 0, base
, precision
, width
, flags
);
726 if (flags
& FLAGS_LONG_LONG
) {
727 #if defined(PRINTF_SUPPORT_LONG_LONG)
728 idx
= _ntoa_long_long(out
, buffer
, idx
, maxlen
, va_arg(va
, unsigned long long), false, base
, precision
, width
, flags
);
730 } else if (flags
& FLAGS_LONG
) {
731 idx
= _ntoa_long(out
, buffer
, idx
, maxlen
, va_arg(va
, unsigned long), false, base
, precision
, width
, flags
);
733 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);
734 idx
= _ntoa_long(out
, buffer
, idx
, maxlen
, value
, false, base
, precision
, width
, flags
);
740 #if defined(PRINTF_SUPPORT_FLOAT)
743 if (*format
== 'F') flags
|= FLAGS_UPPERCASE
;
744 idx
= _ftoa(out
, buffer
, idx
, maxlen
, va_arg(va
, double), precision
, width
, flags
);
747 #if defined(PRINTF_SUPPORT_EXPONENTIAL)
752 if ((*format
== 'g') || (*format
== 'G')) flags
|= FLAGS_ADAPT_EXP
;
753 if ((*format
== 'E') || (*format
== 'G')) flags
|= FLAGS_UPPERCASE
;
754 idx
= _etoa(out
, buffer
, idx
, maxlen
, va_arg(va
, double), precision
, width
, flags
);
757 #endif // PRINTF_SUPPORT_EXPONENTIAL
758 #endif // PRINTF_SUPPORT_FLOAT
762 if (!(flags
& FLAGS_LEFT
)) {
763 while (l
++ < width
) {
764 out(' ', buffer
, idx
++, maxlen
);
768 out((char)va_arg(va
, int), buffer
, idx
++, maxlen
);
770 if (flags
& FLAGS_LEFT
) {
771 while (l
++ < width
) {
772 out(' ', buffer
, idx
++, maxlen
);
780 const char *p
= va_arg(va
, char *);
781 unsigned int l
= _strnlen_s(p
, precision
? precision
: (size_t) - 1);
783 if (flags
& FLAGS_PRECISION
) {
784 l
= (l
< precision
? l
: precision
);
786 if (!(flags
& FLAGS_LEFT
)) {
787 while (l
++ < width
) {
788 out(' ', buffer
, idx
++, maxlen
);
792 while ((*p
!= 0) && (!(flags
& FLAGS_PRECISION
) || precision
--)) {
793 out(*(p
++), buffer
, idx
++, maxlen
);
796 if (flags
& FLAGS_LEFT
) {
797 while (l
++ < width
) {
798 out(' ', buffer
, idx
++, maxlen
);
806 width
= sizeof(void *) * 2U;
807 flags
|= FLAGS_ZEROPAD
| FLAGS_UPPERCASE
;
808 #if defined(PRINTF_SUPPORT_LONG_LONG)
809 const bool is_ll
= sizeof(uintptr_t) == sizeof(long long);
811 idx
= _ntoa_long_long(out
, buffer
, idx
, maxlen
, (uintptr_t)va_arg(va
, void *), false, 16U, precision
, width
, flags
);
814 idx
= _ntoa_long(out
, buffer
, idx
, maxlen
, (unsigned long)((uintptr_t)va_arg(va
, void *)), false, 16U, precision
, width
, flags
);
815 #if defined(PRINTF_SUPPORT_LONG_LONG)
823 out('%', buffer
, idx
++, maxlen
);
828 out(*format
, buffer
, idx
++, maxlen
);
835 out((char)0, buffer
, idx
< maxlen
? idx
: maxlen
- 1U, maxlen
);
837 // return written chars without terminating \0
842 ///////////////////////////////////////////////////////////////////////////////
844 int printf_(const char *format
, ...) {
846 va_start(va
, format
);
848 const int ret
= _vsnprintf(_out_char
, buffer
, (size_t) - 1, format
, va
);
854 int sprintf_(char *buffer
, const char *format
, ...) {
856 va_start(va
, format
);
857 const int ret
= _vsnprintf(_out_buffer
, buffer
, (size_t) - 1, format
, va
);
863 int snprintf_(char *buffer
, size_t count
, const char *format
, ...) {
865 va_start(va
, format
);
866 const int ret
= _vsnprintf(_out_buffer
, buffer
, count
, format
, va
);
872 int vprintf_(const char *format
, va_list va
) {
874 return _vsnprintf(_out_char
, buffer
, (size_t) - 1, format
, va
);
878 int vsnprintf_(char *buffer
, size_t count
, const char *format
, va_list va
) {
879 return _vsnprintf(_out_buffer
, buffer
, count
, format
, va
);
883 int fctprintf(void (*out
)(char character
, void *arg
), void *arg
, const char *format
, ...) {
885 va_start(va
, format
);
886 const out_fct_wrap_type out_fct_wrap
= { out
, arg
};
887 const int ret
= _vsnprintf(_out_fct
, (char *)(uintptr_t)&out_fct_wrap
, (size_t) - 1, format
, va
);