1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-11-27 Meco Man porting for rt_vsnprintf as the fully functional version
9 * 2024-11-19 Meco Man move to klibc
10 */
11
12 /**
13 * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
14 * 2021-2022, Haifa, Palestine/Israel
15 * @author (c) Marco Paland (info@paland.com)
16 * 2014-2019, PALANDesign Hannover, Germany
17 *
18 * @note Others have made smaller contributions to this file: see the
19 * contributors page at https://github.com/eyalroz/printf/graphs/contributors
20 * or ask one of the authors. The original code for exponential specifiers was
21 * contributed by Martijn Jasperse <m.jasperse@gmail.com>.
22 *
23 * @brief Small stand-alone implementation of the printf family of functions
24 * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
25 * a very limited resources.
26 *
27 * @note the implementations are thread-safe; re-entrant; use no functions from
28 * the standard library; and do not dynamically allocate any memory.
29 *
30 * @license The MIT License (MIT)
31 *
32 * Permission is hereby granted, free of charge, to any person obtaining a copy
33 * of this software and associated documentation files (the "Software"), to deal
34 * in the Software without restriction, including without limitation the rights
35 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36 * copies of the Software, and to permit persons to whom the Software is
37 * furnished to do so, subject to the following conditions:
38 *
39 * The above copyright notice and this permission notice shall be included in
40 * all copies or substantial portions of the Software.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48 * THE SOFTWARE.
49 */
50
51 #include <rtthread.h>
52 #include <stdio.h>
53 #include <stdint.h>
54 #include <limits.h>
55 #include <stdbool.h>
56
57 // 'ntoa' conversion buffer size, this must be big enough to hold one converted
58 // numeric number including padded zeros (dynamically created on stack)
59 #ifndef RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE
60 #define RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE 32
61 #endif
62
63 // size of the fixed (on-stack) buffer for printing individual decimal numbers.
64 // this must be big enough to hold one converted floating-point value including
65 // padded zeros.
66 #ifndef RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE
67 #define RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE 32
68 #endif
69
70 // Support for the decimal notation floating point conversion specifiers (%f, %F)
71 #ifndef RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
72 #define RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
73 #endif
74
75 // Support for the exponential notation floating point conversion specifiers (%e, %g, %E, %G)
76 #ifndef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
77 #define RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
78 #endif
79
80 // Support for the length write-back specifier (%n)
81 #ifndef RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
82 #define RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
83 #endif
84
85 // Default precision for the floating point conversion specifiers (the C standard sets this at 6)
86 #ifndef RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION
87 #define RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION 6
88 #endif
89
90 // According to the C languages standard, printf() and related functions must be able to print any
91 // integral number in floating-point notation, regardless of length, when using the %f specifier -
92 // possibly hundreds of characters, potentially overflowing your buffers. In this implementation,
93 // all values beyond this threshold are switched to exponential notation.
94 #ifndef RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL
95 #define RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL 9
96 #endif
97
98 // Support for the long long integral types (with the ll, z and t length modifiers for specifiers
99 // %d,%i,%o,%x,%X,%u, and with the %p specifier). Note: 'L' (long double) is not supported.
100 #ifndef RT_KLIBC_USING_VSNPRINTF_LONGLONG
101 #define RT_KLIBC_USING_VSNPRINTF_LONGLONG
102 #endif
103
104 // The number of terms in a Taylor series expansion of log_10(x) to
105 // use for approximation - including the power-zero term (i.e. the
106 // value at the point of expansion).
107 #ifndef RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS
108 #define RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS 4
109 #endif
110
111 // Be extra-safe, and don't assume format specifiers are completed correctly
112 // before the format string end.
113 #if !defined(RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER) || defined(RT_USING_DEBUG)
114 #define RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER
115 #endif
116
117 #if RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS <= 1
118 #error "At least one non-constant Taylor expansion is necessary for the log10() calculation"
119 #endif
120
121 ///////////////////////////////////////////////////////////////////////////////
122
123 #define PRINTF_PREFER_DECIMAL false
124 #define PRINTF_PREFER_EXPONENTIAL true
125
126 // The following will convert the number-of-digits into an exponential-notation literal
127 #define PRINTF_CONCATENATE(s1, s2) s1##s2
128 #define PRINTF_EXPAND_THEN_CONCATENATE(s1, s2) PRINTF_CONCATENATE(s1, s2)
129 #define PRINTF_FLOAT_NOTATION_THRESHOLD PRINTF_EXPAND_THEN_CONCATENATE(1e,RT_KLIBC_USING_VSNPRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL)
130
131 // internal flag definitions
132 #define FLAGS_ZEROPAD (1U << 0U)
133 #define FLAGS_LEFT (1U << 1U)
134 #define FLAGS_PLUS (1U << 2U)
135 #define FLAGS_SPACE (1U << 3U)
136 #define FLAGS_HASH (1U << 4U)
137 #define FLAGS_UPPERCASE (1U << 5U)
138 #define FLAGS_CHAR (1U << 6U)
139 #define FLAGS_SHORT (1U << 7U)
140 #define FLAGS_INT (1U << 8U)
141 // Only used with RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
142 #define FLAGS_LONG (1U << 9U)
143 #define FLAGS_LONG_LONG (1U << 10U)
144 #define FLAGS_PRECISION (1U << 11U)
145 #define FLAGS_ADAPT_EXP (1U << 12U)
146 #define FLAGS_POINTER (1U << 13U)
147 // Note: Similar, but not identical, effect as FLAGS_HASH
148 #define FLAGS_SIGNED (1U << 14U)
149 // Only used with RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
150
151 #ifdef RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
152
153 #define FLAGS_INT8 FLAGS_CHAR
154
155 #if (SHRT_MAX == 32767LL)
156 #define FLAGS_INT16 FLAGS_SHORT
157 #elif (INT_MAX == 32767LL)
158 #define FLAGS_INT16 FLAGS_INT
159 #elif (LONG_MAX == 32767LL)
160 #define FLAGS_INT16 FLAGS_LONG
161 #elif (LLONG_MAX == 32767LL)
162 #define FLAGS_INT16 FLAGS_LONG_LONG
163 #else
164 #error "No basic integer type has a size of 16 bits exactly"
165 #endif
166
167 #if (SHRT_MAX == 2147483647LL)
168 #define FLAGS_INT32 FLAGS_SHORT
169 #elif (INT_MAX == 2147483647LL)
170 #define FLAGS_INT32 FLAGS_INT
171 #elif (LONG_MAX == 2147483647LL)
172 #define FLAGS_INT32 FLAGS_LONG
173 #elif (LLONG_MAX == 2147483647LL)
174 #define FLAGS_INT32 FLAGS_LONG_LONG
175 #else
176 #error "No basic integer type has a size of 32 bits exactly"
177 #endif
178
179 #if (SHRT_MAX == 9223372036854775807LL)
180 #define FLAGS_INT64 FLAGS_SHORT
181 #elif (INT_MAX == 9223372036854775807LL)
182 #define FLAGS_INT64 FLAGS_INT
183 #elif (LONG_MAX == 9223372036854775807LL)
184 #define FLAGS_INT64 FLAGS_LONG
185 #elif (LLONG_MAX == 9223372036854775807LL)
186 #define FLAGS_INT64 FLAGS_LONG_LONG
187 #else
188 #error "No basic integer type has a size of 64 bits exactly"
189 #endif
190
191 #endif // RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
192
193
194 typedef unsigned int printf_flags_t;
195
196 #define BASE_BINARY 2
197 #define BASE_OCTAL 8
198 #define BASE_DECIMAL 10
199 #define BASE_HEX 16
200
201 typedef uint8_t numeric_base_t;
202
203 #ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
204 typedef unsigned long long printf_unsigned_value_t;
205 typedef long long printf_signed_value_t;
206 #else
207 typedef unsigned long printf_unsigned_value_t;
208 typedef long printf_signed_value_t;
209 #endif
210
211 // The printf()-family functions return an `int`; it is therefore
212 // unnecessary/inappropriate to use size_t - often larger than int
213 // in practice - for non-negative related values, such as widths,
214 // precisions, offsets into buffers used for printing and the sizes
215 // of these buffers. instead, we use:
216 typedef unsigned int printf_size_t;
217 #define PRINTF_MAX_POSSIBLE_BUFFER_SIZE INT_MAX
218 // If we were to nitpick, this would actually be INT_MAX + 1,
219 // since INT_MAX is the maximum return value, which excludes the
220 // trailing '\0'.
221
222 #if defined(RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS) || defined(RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS)
223 #include <float.h>
224 #if FLT_RADIX != 2
225 #error "Non-binary-radix floating-point types are unsupported."
226 #endif
227
228 #if DBL_MANT_DIG == 24
229
230 #define DOUBLE_SIZE_IN_BITS 32
231 typedef uint32_t double_uint_t;
232 #define DOUBLE_EXPONENT_MASK 0xFFU
233 #define DOUBLE_BASE_EXPONENT 127
234 #define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -38
235 #define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 1e-38
236
237 #elif DBL_MANT_DIG == 53
238
239 #define DOUBLE_SIZE_IN_BITS 64
240 typedef uint64_t double_uint_t;
241 #define DOUBLE_EXPONENT_MASK 0x7FFU
242 #define DOUBLE_BASE_EXPONENT 1023
243 #define DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10 -308
244 #define DOUBLE_MAX_SUBNORMAL_POWER_OF_10 ((double)1e-308L)
245
246 #else
247 #error "Unsupported double type configuration"
248 #endif
249 #define DOUBLE_STORED_MANTISSA_BITS (DBL_MANT_DIG - 1)
250
251 typedef union {
252 double_uint_t U;
253 double F;
254 } double_with_bit_access;
255
256 // This is unnecessary in C99, since compound initializers can be used,
257 // but:
258 // 1. Some compilers are finicky about this;
259 // 2. Some people may want to convert this to C89;
260 // 3. If you try to use it as C++, only C++20 supports compound literals
get_bit_access(double x)261 static inline double_with_bit_access get_bit_access(double x)
262 {
263 double_with_bit_access dwba;
264 dwba.F = x;
265 return dwba;
266 }
267
get_sign_bit(double x)268 static inline int get_sign_bit(double x)
269 {
270 // The sign is stored in the highest bit
271 return (int) (get_bit_access(x).U >> (DOUBLE_SIZE_IN_BITS - 1));
272 }
273
get_exp2(double_with_bit_access x)274 static inline int get_exp2(double_with_bit_access x)
275 {
276 // The exponent in an IEEE-754 floating-point number occupies a contiguous
277 // sequence of bits (e.g. 52..62 for 64-bit doubles), but with a non-trivial representation: An
278 // unsigned offset from some negative value (with the extremal offset values reserved for
279 // special use).
280 return (int)((x.U >> DOUBLE_STORED_MANTISSA_BITS ) & DOUBLE_EXPONENT_MASK) - DOUBLE_BASE_EXPONENT;
281 }
282 #define PRINTF_ABS(_x) ( (_x) > 0 ? (_x) : -(_x) )
283
284 #endif // (RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS || RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS)
285
286 // Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid
287 // and well-defined, but if you're not careful you can easily trigger undefined
288 // behavior with -LONG_MIN or -LLONG_MIN
289 #define ABS_FOR_PRINTING(_x) ((printf_unsigned_value_t) ( (_x) > 0 ? (_x) : -((printf_signed_value_t)_x) ))
290
291 // wrapper (used as buffer) for output function type
292 //
293 // One of the following must hold:
294 // 1. max_chars is 0
295 // 2. buffer is non-null
296 // 3. function is non-null
297 //
298 // ... otherwise bad things will happen.
299 typedef struct {
300 void (*function)(char c, void* extra_arg);
301 void* extra_function_arg;
302 char* buffer;
303 printf_size_t pos;
304 printf_size_t max_chars;
305 } output_gadget_t;
306
307 // Note: This function currently assumes it is not passed a '\0' c,
308 // or alternatively, that '\0' can be passed to the function in the output
309 // gadget. The former assumption holds within the printf library. It also
310 // assumes that the output gadget has been properly initialized.
putchar_via_gadget(output_gadget_t * gadget,char c)311 static inline void putchar_via_gadget(output_gadget_t* gadget, char c)
312 {
313 printf_size_t write_pos = gadget->pos++;
314 // We're _always_ increasing pos, so as to count how may characters
315 // _would_ have been written if not for the max_chars limitation
316 if (write_pos >= gadget->max_chars) {
317 return;
318 }
319 if (gadget->function != NULL) {
320 // No check for c == '\0' .
321 gadget->function(c, gadget->extra_function_arg);
322 }
323 else {
324 // it must be the case that gadget->buffer != NULL , due to the constraint
325 // on output_gadget_t ; and note we're relying on write_pos being non-negative.
326 gadget->buffer[write_pos] = c;
327 }
328 }
329
330 // Possibly-write the string-terminating '\0' character
append_termination_with_gadget(output_gadget_t * gadget)331 static inline void append_termination_with_gadget(output_gadget_t* gadget)
332 {
333 if (gadget->function != NULL || gadget->max_chars == 0) {
334 return;
335 }
336 if (gadget->buffer == NULL) {
337 return;
338 }
339 printf_size_t null_char_pos = gadget->pos < gadget->max_chars ? gadget->pos : gadget->max_chars - 1;
340 gadget->buffer[null_char_pos] = '\0';
341 }
342
discarding_gadget(void)343 static inline output_gadget_t discarding_gadget(void)
344 {
345 output_gadget_t gadget;
346 gadget.function = NULL;
347 gadget.extra_function_arg = NULL;
348 gadget.buffer = NULL;
349 gadget.pos = 0;
350 gadget.max_chars = 0;
351 return gadget;
352 }
353
buffer_gadget(char * buffer,size_t buffer_size)354 static inline output_gadget_t buffer_gadget(char* buffer, size_t buffer_size)
355 {
356 printf_size_t usable_buffer_size = (buffer_size > PRINTF_MAX_POSSIBLE_BUFFER_SIZE) ?
357 PRINTF_MAX_POSSIBLE_BUFFER_SIZE : (printf_size_t) buffer_size;
358 output_gadget_t result = discarding_gadget();
359 if (buffer != NULL) {
360 result.buffer = buffer;
361 result.max_chars = usable_buffer_size;
362 }
363 return result;
364 }
365
366 // internal secure strlen
367 // @return The length of the string (excluding the terminating 0) limited by 'maxsize'
368 // @note strlen uses size_t, but wes only use this function with printf_size_t
369 // variables - hence the signature.
strnlen_s_(const char * str,printf_size_t maxsize)370 static inline printf_size_t strnlen_s_(const char* str, printf_size_t maxsize)
371 {
372 const char* s;
373 for (s = str; *s && maxsize--; ++s);
374 return (printf_size_t)(s - str);
375 }
376
377
378 // internal test if char is a digit (0-9)
379 // @return true if char is a digit
is_digit_(char ch)380 static inline bool is_digit_(char ch)
381 {
382 return (ch >= '0') && (ch <= '9');
383 }
384
385
386 // internal ASCII string to printf_size_t conversion
atou_(const char ** str)387 static printf_size_t atou_(const char** str)
388 {
389 printf_size_t i = 0U;
390 while (is_digit_(**str)) {
391 i = i * 10U + (printf_size_t)(*((*str)++) - '0');
392 }
393 return i;
394 }
395
396
397 // output the specified string in reverse, taking care of any zero-padding
out_rev_(output_gadget_t * output,const char * buf,printf_size_t len,printf_size_t width,printf_flags_t flags)398 static void out_rev_(output_gadget_t* output, const char* buf, printf_size_t len, printf_size_t width, printf_flags_t flags)
399 {
400 const printf_size_t start_pos = output->pos;
401
402 // pad spaces up to given width
403 if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
404 for (printf_size_t i = len; i < width; i++) {
405 putchar_via_gadget(output, ' ');
406 }
407 }
408
409 // reverse string
410 while (len) {
411 putchar_via_gadget(output, buf[--len]);
412 }
413
414 // append pad spaces up to given width
415 if (flags & FLAGS_LEFT) {
416 while (output->pos - start_pos < width) {
417 putchar_via_gadget(output, ' ');
418 }
419 }
420 }
421
422
423 // Invoked by print_integer after the actual number has been printed, performing necessary
424 // work on the number's prefix (as the number is initially printed in reverse order)
print_integer_finalization(output_gadget_t * output,char * buf,printf_size_t len,bool negative,numeric_base_t base,printf_size_t precision,printf_size_t width,printf_flags_t flags)425 static void print_integer_finalization(output_gadget_t* output, char* buf, printf_size_t len, bool negative, numeric_base_t base, printf_size_t precision, printf_size_t width, printf_flags_t flags)
426 {
427 printf_size_t unpadded_len = len;
428
429 // pad with leading zeros
430 {
431 if (!(flags & FLAGS_LEFT)) {
432 if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
433 width--;
434 }
435 while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
436 buf[len++] = '0';
437 }
438 }
439
440 while ((len < precision) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
441 buf[len++] = '0';
442 }
443
444 if (base == BASE_OCTAL && (len > unpadded_len)) {
445 // Since we've written some zeros, we've satisfied the alternative format leading space requirement
446 flags &= ~FLAGS_HASH;
447 }
448 }
449
450 // handle hash
451 if (flags & (FLAGS_HASH | FLAGS_POINTER)) {
452 if (!(flags & FLAGS_PRECISION) && len && ((len == precision) || (len == width))) {
453 // Let's take back some padding digits to fit in what will eventually
454 // be the format-specific prefix
455 if (unpadded_len < len) {
456 len--; // This should suffice for BASE_OCTAL
457 }
458 if (len && (base == BASE_HEX || base == BASE_BINARY) && (unpadded_len < len)) {
459 len--; // ... and an extra one for 0x or 0b
460 }
461 }
462 if ((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
463 buf[len++] = 'x';
464 }
465 else if ((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
466 buf[len++] = 'X';
467 }
468 else if ((base == BASE_BINARY) && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE)) {
469 buf[len++] = 'b';
470 }
471 if (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE) {
472 buf[len++] = '0';
473 }
474 }
475
476 if (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE) {
477 if (negative) {
478 buf[len++] = '-';
479 }
480 else if (flags & FLAGS_PLUS) {
481 buf[len++] = '+'; // ignore the space if the '+' exists
482 }
483 else if (flags & FLAGS_SPACE) {
484 buf[len++] = ' ';
485 }
486 }
487
488 out_rev_(output, buf, len, width, flags);
489 }
490
491 // An internal itoa-like function
print_integer(output_gadget_t * output,printf_unsigned_value_t value,bool negative,numeric_base_t base,printf_size_t precision,printf_size_t width,printf_flags_t flags)492 static void print_integer(output_gadget_t* output, printf_unsigned_value_t value, bool negative, numeric_base_t base, printf_size_t precision, printf_size_t width, printf_flags_t flags)
493 {
494 char buf[RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE];
495 printf_size_t len = 0U;
496
497 if (!value) {
498 if ( !(flags & FLAGS_PRECISION) ) {
499 buf[len++] = '0';
500 flags &= ~FLAGS_HASH;
501 // We drop this flag this since either the alternative and regular modes of the specifier
502 // don't differ on 0 values, or (in the case of octal) we've already provided the special
503 // handling for this mode.
504 }
505 else if (base == BASE_HEX) {
506 flags &= ~FLAGS_HASH;
507 // We drop this flag this since either the alternative and regular modes of the specifier
508 // don't differ on 0 values
509 }
510 }
511 else {
512 do {
513 const char digit = (char)(value % base);
514 buf[len++] = (char)(digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10);
515 value /= base;
516 } while (value && (len < RT_KLIBC_USING_VSNPRINTF_INTEGER_BUFFER_SIZE));
517 }
518
519 print_integer_finalization(output, buf, len, negative, base, precision, width, flags);
520 }
521
522 #if defined(RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS) || defined(RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS)
523
524 // Stores a fixed-precision representation of a double relative
525 // to a fixed precision (which cannot be determined by examining this structure)
526 struct double_components {
527 int_fast64_t integral;
528 int_fast64_t fractional;
529 // ... truncation of the actual fractional part of the double value, scaled
530 // by the precision value
531 bool is_negative;
532 };
533
534 #define NUM_DECIMAL_DIGITS_IN_INT64_T 18
535 #define PRINTF_MAX_PRECOMPUTED_POWER_OF_10 NUM_DECIMAL_DIGITS_IN_INT64_T
536 static const double powers_of_10[NUM_DECIMAL_DIGITS_IN_INT64_T] = {
537 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08,
538 1e09, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17
539 };
540
541 #define PRINTF_MAX_SUPPORTED_PRECISION NUM_DECIMAL_DIGITS_IN_INT64_T - 1
542
543
544 // Break up a double number - which is known to be a finite non-negative number -
545 // into its base-10 parts: integral - before the decimal point, and fractional - after it.
546 // Taken the precision into account, but does not change it even internally.
get_components(double number,printf_size_t precision)547 static struct double_components get_components(double number, printf_size_t precision)
548 {
549 struct double_components number_;
550 number_.is_negative = get_sign_bit(number);
551 double abs_number = (number_.is_negative) ? -number : number;
552 number_.integral = (int_fast64_t)abs_number;
553 double remainder = (abs_number - (double) number_.integral) * powers_of_10[precision];
554 number_.fractional = (int_fast64_t)remainder;
555
556 remainder -= (double) number_.fractional;
557
558 if (remainder > 0.5) {
559 ++number_.fractional;
560 // handle rollover, e.g. case 0.99 with precision 1 is 1.0
561 if ((double) number_.fractional >= powers_of_10[precision]) {
562 number_.fractional = 0;
563 ++number_.integral;
564 }
565 }
566 else if ((remainder == 0.5) && ((number_.fractional == 0U) || (number_.fractional & 1U))) {
567 // if halfway, round up if odd OR if last digit is 0
568 ++number_.fractional;
569 }
570
571 if (precision == 0U) {
572 remainder = abs_number - (double) number_.integral;
573 if ((!(remainder < 0.5) || (remainder > 0.5)) && (number_.integral & 1)) {
574 // exactly 0.5 and ODD, then round up
575 // 1.5 -> 2, but 2.5 -> 2
576 ++number_.integral;
577 }
578 }
579 return number_;
580 }
581
582 #ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
583 struct scaling_factor {
584 double raw_factor;
585 bool multiply; // if true, need to multiply by raw_factor; otherwise need to divide by it
586 };
587
apply_scaling(double num,struct scaling_factor normalization)588 static double apply_scaling(double num, struct scaling_factor normalization)
589 {
590 return normalization.multiply ? num * normalization.raw_factor : num / normalization.raw_factor;
591 }
592
unapply_scaling(double normalized,struct scaling_factor normalization)593 static double unapply_scaling(double normalized, struct scaling_factor normalization)
594 {
595 #if defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */
596 // accounting for a static analysis bug in GCC 6.x and earlier
597 #pragma GCC diagnostic push
598 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
599 #endif
600 return normalization.multiply ? normalized / normalization.raw_factor : normalized * normalization.raw_factor;
601 #if defined(__GNUC__) && !defined(__ARMCC_VERSION) /* GCC */
602 #pragma GCC diagnostic pop
603 #endif
604 }
605
update_normalization(struct scaling_factor sf,double extra_multiplicative_factor)606 static struct scaling_factor update_normalization(struct scaling_factor sf, double extra_multiplicative_factor)
607 {
608 struct scaling_factor result;
609 if (sf.multiply) {
610 result.multiply = true;
611 result.raw_factor = sf.raw_factor * extra_multiplicative_factor;
612 }
613 else {
614 int factor_exp2 = get_exp2(get_bit_access(sf.raw_factor));
615 int extra_factor_exp2 = get_exp2(get_bit_access(extra_multiplicative_factor));
616
617 // Divide the larger-exponent raw raw_factor by the smaller
618 if (PRINTF_ABS(factor_exp2) > PRINTF_ABS(extra_factor_exp2)) {
619 result.multiply = false;
620 result.raw_factor = sf.raw_factor / extra_multiplicative_factor;
621 }
622 else {
623 result.multiply = true;
624 result.raw_factor = extra_multiplicative_factor / sf.raw_factor;
625 }
626 }
627 return result;
628 }
629
get_normalized_components(bool negative,printf_size_t precision,double non_normalized,struct scaling_factor normalization,int floored_exp10)630 static struct double_components get_normalized_components(bool negative, printf_size_t precision, double non_normalized, struct scaling_factor normalization, int floored_exp10)
631 {
632 struct double_components components;
633 components.is_negative = negative;
634 double scaled = apply_scaling(non_normalized, normalization);
635
636 bool close_to_representation_extremum = ( (-floored_exp10 + (int) precision) >= DBL_MAX_10_EXP - 1 );
637 if (close_to_representation_extremum) {
638 // We can't have a normalization factor which also accounts for the precision, i.e. moves
639 // some decimal digits into the mantissa, since it's unrepresentable, or nearly unrepresentable.
640 // So, we'll give up early on getting extra precision...
641 return get_components(negative ? -scaled : scaled, precision);
642 }
643 components.integral = (int_fast64_t) scaled;
644 double remainder = non_normalized - unapply_scaling((double) components.integral, normalization);
645 double prec_power_of_10 = powers_of_10[precision];
646 struct scaling_factor account_for_precision = update_normalization(normalization, prec_power_of_10);
647 double scaled_remainder = apply_scaling(remainder, account_for_precision);
648 double rounding_threshold = 0.5;
649
650 components.fractional = (int_fast64_t) scaled_remainder; // when precision == 0, the assigned value should be 0
651 scaled_remainder -= (double) components.fractional; //when precision == 0, this will not change scaled_remainder
652
653 components.fractional += (scaled_remainder >= rounding_threshold);
654 if (scaled_remainder == rounding_threshold) {
655 // banker's rounding: Round towards the even number (making the mean error 0)
656 components.fractional &= ~((int_fast64_t) 0x1);
657 }
658 // handle rollover, e.g. the case of 0.99 with precision 1 becoming (0,100),
659 // and must then be corrected into (1, 0).
660 // Note: for precision = 0, this will "translate" the rounding effect from
661 // the fractional part to the integral part where it should actually be
662 // felt (as prec_power_of_10 is 1)
663 if ((double) components.fractional >= prec_power_of_10) {
664 components.fractional = 0;
665 ++components.integral;
666 }
667 return components;
668 }
669 #endif // RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
670
print_broken_up_decimal(struct double_components number_,output_gadget_t * output,printf_size_t precision,printf_size_t width,printf_flags_t flags,char * buf,printf_size_t len)671 static void print_broken_up_decimal(
672 struct double_components number_, output_gadget_t* output, printf_size_t precision,
673 printf_size_t width, printf_flags_t flags, char *buf, printf_size_t len)
674 {
675 if (precision != 0U) {
676 // do fractional part, as an unsigned number
677
678 printf_size_t count = precision;
679
680 // %g/%G mandates we skip the trailing 0 digits...
681 if ((flags & FLAGS_ADAPT_EXP) && !(flags & FLAGS_HASH) && (number_.fractional > 0)) {
682 while(true) {
683 int_fast64_t digit = number_.fractional % 10U;
684 if (digit != 0) {
685 break;
686 }
687 --count;
688 number_.fractional /= 10U;
689
690 }
691 // ... and even the decimal point if there are no
692 // non-zero fractional part digits (see below)
693 }
694
695 if (number_.fractional > 0 || !(flags & FLAGS_ADAPT_EXP) || (flags & FLAGS_HASH) ) {
696 while (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) {
697 --count;
698 buf[len++] = (char)('0' + number_.fractional % 10U);
699 if (!(number_.fractional /= 10U)) {
700 break;
701 }
702 }
703 // add extra 0s
704 while ((len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) && (count > 0U)) {
705 buf[len++] = '0';
706 --count;
707 }
708 if (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) {
709 buf[len++] = '.';
710 }
711 }
712 }
713 else {
714 if ((flags & FLAGS_HASH) && (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE)) {
715 buf[len++] = '.';
716 }
717 }
718
719 // Write the integer part of the number (it comes after the fractional
720 // since the character order is reversed)
721 while (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) {
722 buf[len++] = (char)('0' + (number_.integral % 10));
723 if (!(number_.integral /= 10)) {
724 break;
725 }
726 }
727
728 // pad leading zeros
729 if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
730 if (width && (number_.is_negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
731 width--;
732 }
733 while ((len < width) && (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE)) {
734 buf[len++] = '0';
735 }
736 }
737
738 if (len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) {
739 if (number_.is_negative) {
740 buf[len++] = '-';
741 }
742 else if (flags & FLAGS_PLUS) {
743 buf[len++] = '+'; // ignore the space if the '+' exists
744 }
745 else if (flags & FLAGS_SPACE) {
746 buf[len++] = ' ';
747 }
748 }
749
750 out_rev_(output, buf, len, width, flags);
751 }
752
753 // internal ftoa for fixed decimal floating point
print_decimal_number(output_gadget_t * output,double number,printf_size_t precision,printf_size_t width,printf_flags_t flags,char * buf,printf_size_t len)754 static void print_decimal_number(output_gadget_t* output, double number, printf_size_t precision, printf_size_t width, printf_flags_t flags, char* buf, printf_size_t len)
755 {
756 struct double_components value_ = get_components(number, precision);
757 print_broken_up_decimal(value_, output, precision, width, flags, buf, len);
758 }
759
760 #ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
761
762 // A floor function - but one which only works for numbers whose
763 // floor value is representable by an int.
bastardized_floor(double x)764 static int bastardized_floor(double x)
765 {
766 if (x >= 0) { return (int) x; }
767 int n = (int) x;
768 return ( ((double) n) == x ) ? n : n-1;
769 }
770
771 // Computes the base-10 logarithm of the input number - which must be an actual
772 // positive number (not infinity or NaN, nor a sub-normal)
log10_of_positive(double positive_number)773 static double log10_of_positive(double positive_number)
774 {
775 // The implementation follows David Gay (https://www.ampl.com/netlib/fp/dtoa.c).
776 //
777 // Since log_10 ( M * 2^x ) = log_10(M) + x , we can separate the components of
778 // our input number, and need only solve log_10(M) for M between 1 and 2 (as
779 // the base-2 mantissa is always 1-point-something). In that limited range, a
780 // Taylor series expansion of log10(x) should serve us well enough; and we'll
781 // take the mid-point, 1.5, as the point of expansion.
782
783 double_with_bit_access dwba = get_bit_access(positive_number);
784 // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
785 int exp2 = get_exp2(dwba);
786 // drop the exponent, so dwba.F comes into the range [1,2)
787 dwba.U = (dwba.U & (((double_uint_t) (1) << DOUBLE_STORED_MANTISSA_BITS) - 1U)) |
788 ((double_uint_t) DOUBLE_BASE_EXPONENT << DOUBLE_STORED_MANTISSA_BITS);
789 double z = (dwba.F - 1.5);
790 return (
791 // Taylor expansion around 1.5:
792 0.1760912590556812420 // Expansion term 0: ln(1.5) / ln(10)
793 + z * 0.2895296546021678851 // Expansion term 1: (M - 1.5) * 2/3 / ln(10)
794 #if RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS > 2
795 - z*z * 0.0965098848673892950 // Expansion term 2: (M - 1.5)^2 * 2/9 / ln(10)
796 #if RT_KLIBC_USING_VSNPRINTF_LOG10_TAYLOR_TERMS > 3
797 + z*z*z * 0.0428932821632841311 // Expansion term 2: (M - 1.5)^3 * 8/81 / ln(10)
798 #endif
799 #endif
800 // exact log_2 of the exponent x, with logarithm base change
801 + exp2 * 0.30102999566398119521 // = exp2 * log_10(2) = exp2 * ln(2)/ln(10)
802 );
803 }
804
805
pow10_of_int(int floored_exp10)806 static double pow10_of_int(int floored_exp10)
807 {
808 // A crude hack for avoiding undesired behavior with barely-normal or slightly-subnormal values.
809 if (floored_exp10 == DOUBLE_MAX_SUBNORMAL_EXPONENT_OF_10) {
810 return DOUBLE_MAX_SUBNORMAL_POWER_OF_10;
811 }
812 // Compute 10^(floored_exp10) but (try to) make sure that doesn't overflow
813 double_with_bit_access dwba;
814 int exp2 = bastardized_floor(floored_exp10 * 3.321928094887362 + 0.5);
815 const double z = floored_exp10 * 2.302585092994046 - exp2 * 0.6931471805599453;
816 const double z2 = z * z;
817 dwba.U = ((double_uint_t)(exp2) + DOUBLE_BASE_EXPONENT) << DOUBLE_STORED_MANTISSA_BITS;
818 // compute exp(z) using continued fractions,
819 // see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
820 dwba.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
821 return dwba.F;
822 }
823
print_exponential_number(output_gadget_t * output,double number,printf_size_t precision,printf_size_t width,printf_flags_t flags,char * buf,printf_size_t len)824 static void print_exponential_number(output_gadget_t* output, double number, printf_size_t precision, printf_size_t width, printf_flags_t flags, char* buf, printf_size_t len)
825 {
826 const bool negative = get_sign_bit(number);
827 // This number will decrease gradually (by factors of 10) as we "extract" the exponent out of it
828 double abs_number = negative ? -number : number;
829
830 int floored_exp10;
831 bool abs_exp10_covered_by_powers_table;
832 struct scaling_factor normalization;
833
834
835 // Determine the decimal exponent
836 if (abs_number == 0.0) {
837 // TODO: This is a special-case for 0.0 (and -0.0); but proper handling is required for denormals more generally.
838 floored_exp10 = 0; // ... and no need to set a normalization factor or check the powers table
839 }
840 else {
841 double exp10 = log10_of_positive(abs_number);
842 floored_exp10 = bastardized_floor(exp10);
843 double p10 = pow10_of_int(floored_exp10);
844 // correct for rounding errors
845 if (abs_number < p10) {
846 floored_exp10--;
847 p10 /= 10;
848 }
849 abs_exp10_covered_by_powers_table = PRINTF_ABS(floored_exp10) < PRINTF_MAX_PRECOMPUTED_POWER_OF_10;
850 normalization.raw_factor = abs_exp10_covered_by_powers_table ? powers_of_10[PRINTF_ABS(floored_exp10)] : p10;
851 }
852
853 // We now begin accounting for the widths of the two parts of our printed field:
854 // the decimal part after decimal exponent extraction, and the base-10 exponent part.
855 // For both of these, the value of 0 has a special meaning, but not the same one:
856 // a 0 exponent-part width means "don't print the exponent"; a 0 decimal-part width
857 // means "use as many characters as necessary".
858
859 bool fall_back_to_decimal_only_mode = false;
860 if (flags & FLAGS_ADAPT_EXP) {
861 int required_significant_digits = (precision == 0) ? 1 : (int) precision;
862 // Should we want to fall-back to "%f" mode, and only print the decimal part?
863 fall_back_to_decimal_only_mode = (floored_exp10 >= -4 && floored_exp10 < required_significant_digits);
864 // Now, let's adjust the precision
865 // This also decided how we adjust the precision value - as in "%g" mode,
866 // "precision" is the number of _significant digits_, and this is when we "translate"
867 // the precision value to an actual number of decimal digits.
868 int precision_ = fall_back_to_decimal_only_mode ?
869 (int) precision - 1 - floored_exp10 :
870 (int) precision - 1; // the presence of the exponent ensures only one significant digit comes before the decimal point
871 precision = (precision_ > 0 ? (unsigned) precision_ : 0U);
872 flags |= FLAGS_PRECISION; // make sure print_broken_up_decimal respects our choice above
873 }
874
875 normalization.multiply = (floored_exp10 < 0 && abs_exp10_covered_by_powers_table);
876 bool should_skip_normalization = (fall_back_to_decimal_only_mode || floored_exp10 == 0);
877 struct double_components decimal_part_components =
878 should_skip_normalization ?
879 get_components(negative ? -abs_number : abs_number, precision) :
880 get_normalized_components(negative, precision, abs_number, normalization, floored_exp10);
881
882 // Account for roll-over, e.g. rounding from 9.99 to 100.0 - which effects
883 // the exponent and may require additional tweaking of the parts
884 if (fall_back_to_decimal_only_mode) {
885 if ((flags & FLAGS_ADAPT_EXP) && floored_exp10 >= -1 && decimal_part_components.integral == powers_of_10[floored_exp10 + 1]) {
886 floored_exp10++; // Not strictly necessary, since floored_exp10 is no longer really used
887 precision--;
888 // ... and it should already be the case that decimal_part_components.fractional == 0
889 }
890 // TODO: What about rollover strictly within the fractional part?
891 }
892 else {
893 if (decimal_part_components.integral >= 10) {
894 floored_exp10++;
895 decimal_part_components.integral = 1;
896 decimal_part_components.fractional = 0;
897 }
898 }
899
900 // the floored_exp10 format is "E%+03d" and largest possible floored_exp10 value for a 64-bit double
901 // is "307" (for 2^1023), so we set aside 4-5 characters overall
902 printf_size_t exp10_part_width = fall_back_to_decimal_only_mode ? 0U : (PRINTF_ABS(floored_exp10) < 100) ? 4U : 5U;
903
904 printf_size_t decimal_part_width =
905 ((flags & FLAGS_LEFT) && exp10_part_width) ?
906 // We're padding on the right, so the width constraint is the exponent part's
907 // problem, not the decimal part's, so we'll use as many characters as we need:
908 0U :
909 // We're padding on the left; so the width constraint is the decimal part's
910 // problem. Well, can both the decimal part and the exponent part fit within our overall width?
911 ((width > exp10_part_width) ?
912 // Yes, so we limit our decimal part's width.
913 // (Note this is trivially valid even if we've fallen back to "%f" mode)
914 width - exp10_part_width :
915 // No; we just give up on any restriction on the decimal part and use as many
916 // characters as we need
917 0U);
918
919 const printf_size_t printed_exponential_start_pos = output->pos;
920 print_broken_up_decimal(decimal_part_components, output, precision, decimal_part_width, flags, buf, len);
921
922 if (! fall_back_to_decimal_only_mode) {
923 putchar_via_gadget(output, (flags & FLAGS_UPPERCASE) ? 'E' : 'e');
924 print_integer(output,
925 ABS_FOR_PRINTING(floored_exp10),
926 floored_exp10 < 0, 10, 0, exp10_part_width - 1,
927 FLAGS_ZEROPAD | FLAGS_PLUS);
928 if (flags & FLAGS_LEFT) {
929 // We need to right-pad with spaces to meet the width requirement
930 while (output->pos - printed_exponential_start_pos < width) {
931 putchar_via_gadget(output, ' ');
932 }
933 }
934 }
935 }
936 #endif // RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
937
print_floating_point(output_gadget_t * output,double value,printf_size_t precision,printf_size_t width,printf_flags_t flags,bool prefer_exponential)938 static void print_floating_point(output_gadget_t* output, double value, printf_size_t precision, printf_size_t width, printf_flags_t flags, bool prefer_exponential)
939 {
940 char buf[RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE];
941 printf_size_t len = 0U;
942
943 // test for special values
944 if (value != value) {
945 out_rev_(output, "nan", 3, width, flags);
946 return;
947 }
948 if (value < -DBL_MAX) {
949 out_rev_(output, "fni-", 4, width, flags);
950 return;
951 }
952 if (value > DBL_MAX) {
953 out_rev_(output, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
954 return;
955 }
956
957 if (!prefer_exponential &&
958 ((value > PRINTF_FLOAT_NOTATION_THRESHOLD) || (value < -PRINTF_FLOAT_NOTATION_THRESHOLD))) {
959 // The required behavior of standard printf is to print _every_ integral-part digit -- which could mean
960 // printing hundreds of characters, overflowing any fixed internal buffer and necessitating a more complicated
961 // implementation.
962 #ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
963 print_exponential_number(output, value, precision, width, flags, buf, len);
964 #endif
965 return;
966 }
967
968 // set default precision, if not set explicitly
969 if (!(flags & FLAGS_PRECISION)) {
970 precision = RT_KLIBC_USING_VSNPRINTF_FLOAT_PRECISION;
971 }
972
973 // limit precision so that our integer holding the fractional part does not overflow
974 while ((len < RT_KLIBC_USING_VSNPRINTF_DECIMAL_BUFFER_SIZE) && (precision > PRINTF_MAX_SUPPORTED_PRECISION)) {
975 buf[len++] = '0'; // This respects the precision in terms of result length only
976 precision--;
977 }
978
979 #ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
980 if (prefer_exponential)
981 print_exponential_number(output, value, precision, width, flags, buf, len);
982 else
983 #endif
984 print_decimal_number(output, value, precision, width, flags, buf, len);
985 }
986
987 #endif // (RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS || RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS)
988
989 // Advances the format pointer past the flags, and returns the parsed flags
990 // due to the characters passed
parse_flags(const char ** format)991 static printf_flags_t parse_flags(const char** format)
992 {
993 printf_flags_t flags = 0U;
994 do {
995 switch (**format) {
996 case '0': flags |= FLAGS_ZEROPAD; (*format)++; break;
997 case '-': flags |= FLAGS_LEFT; (*format)++; break;
998 case '+': flags |= FLAGS_PLUS; (*format)++; break;
999 case ' ': flags |= FLAGS_SPACE; (*format)++; break;
1000 case '#': flags |= FLAGS_HASH; (*format)++; break;
1001 default : return flags;
1002 }
1003 } while (true);
1004 }
1005
format_string_loop(output_gadget_t * output,const char * format,va_list args)1006 static inline void format_string_loop(output_gadget_t* output, const char* format, va_list args)
1007 {
1008 #ifdef RT_KLIBC_USING_VSNPRINTF_CHECK_NUL_IN_FORMAT_SPECIFIER
1009 #define ADVANCE_IN_FORMAT_STRING(cptr_) do { (cptr_)++; if (!*(cptr_)) return; } while(0)
1010 #else
1011 #define ADVANCE_IN_FORMAT_STRING(cptr_) (cptr_)++
1012 #endif
1013
1014
1015 while (*format)
1016 {
1017 if (*format != '%') {
1018 // A regular content character
1019 putchar_via_gadget(output, *format);
1020 format++;
1021 continue;
1022 }
1023 // We're parsing a format specifier: %[flags][width][.precision][length]
1024 ADVANCE_IN_FORMAT_STRING(format);
1025
1026 printf_flags_t flags = parse_flags(&format);
1027
1028 // evaluate width field
1029 printf_size_t width = 0U;
1030 if (is_digit_(*format)) {
1031 width = (printf_size_t) atou_(&format);
1032 }
1033 else if (*format == '*') {
1034 const int w = va_arg(args, int);
1035 if (w < 0) {
1036 flags |= FLAGS_LEFT; // reverse padding
1037 width = (printf_size_t)-w;
1038 }
1039 else {
1040 width = (printf_size_t)w;
1041 }
1042 ADVANCE_IN_FORMAT_STRING(format);
1043 }
1044
1045 // evaluate precision field
1046 printf_size_t precision = 0U;
1047 if (*format == '.') {
1048 flags |= FLAGS_PRECISION;
1049 ADVANCE_IN_FORMAT_STRING(format);
1050 if (is_digit_(*format)) {
1051 precision = (printf_size_t) atou_(&format);
1052 }
1053 else if (*format == '*') {
1054 const int precision_ = va_arg(args, int);
1055 precision = precision_ > 0 ? (printf_size_t) precision_ : 0U;
1056 ADVANCE_IN_FORMAT_STRING(format);
1057 }
1058 }
1059
1060 // evaluate length field
1061 switch (*format) {
1062 #ifdef RT_KLIBC_USING_VSNPRINTF_MSVC_STYLE_INTEGER_SPECIFIERS
1063 case 'I' : {
1064 ADVANCE_IN_FORMAT_STRING(format);
1065 // Greedily parse for size in bits: 8, 16, 32 or 64
1066 switch(*format) {
1067 case '8': flags |= FLAGS_INT8;
1068 ADVANCE_IN_FORMAT_STRING(format);
1069 break;
1070 case '1':
1071 ADVANCE_IN_FORMAT_STRING(format);
1072 if (*format == '6') { format++; flags |= FLAGS_INT16; }
1073 break;
1074 case '3':
1075 ADVANCE_IN_FORMAT_STRING(format);
1076 if (*format == '2') { ADVANCE_IN_FORMAT_STRING(format); flags |= FLAGS_INT32; }
1077 break;
1078 case '6':
1079 ADVANCE_IN_FORMAT_STRING(format);
1080 if (*format == '4') { ADVANCE_IN_FORMAT_STRING(format); flags |= FLAGS_INT64; }
1081 break;
1082 default: break;
1083 }
1084 break;
1085 }
1086 #endif
1087 case 'l' :
1088 flags |= FLAGS_LONG;
1089 ADVANCE_IN_FORMAT_STRING(format);
1090 if (*format == 'l') {
1091 flags |= FLAGS_LONG_LONG;
1092 ADVANCE_IN_FORMAT_STRING(format);
1093 }
1094 break;
1095 case 'h' :
1096 flags |= FLAGS_SHORT;
1097 ADVANCE_IN_FORMAT_STRING(format);
1098 if (*format == 'h') {
1099 flags |= FLAGS_CHAR;
1100 ADVANCE_IN_FORMAT_STRING(format);
1101 }
1102 break;
1103 case 't' :
1104 flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
1105 ADVANCE_IN_FORMAT_STRING(format);
1106 break;
1107 case 'j' :
1108 flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
1109 ADVANCE_IN_FORMAT_STRING(format);
1110 break;
1111 case 'z' :
1112 flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
1113 ADVANCE_IN_FORMAT_STRING(format);
1114 break;
1115 default:
1116 break;
1117 }
1118
1119 // evaluate specifier
1120 switch (*format) {
1121 case 'd' :
1122 case 'i' :
1123 case 'u' :
1124 case 'x' :
1125 case 'X' :
1126 case 'o' :
1127 case 'b' : {
1128
1129 if (*format == 'd' || *format == 'i') {
1130 flags |= FLAGS_SIGNED;
1131 }
1132
1133 numeric_base_t base;
1134 if (*format == 'x' || *format == 'X') {
1135 base = BASE_HEX;
1136 }
1137 else if (*format == 'o') {
1138 base = BASE_OCTAL;
1139 }
1140 else if (*format == 'b') {
1141 base = BASE_BINARY;
1142 }
1143 else {
1144 base = BASE_DECIMAL;
1145 flags &= ~FLAGS_HASH; // decimal integers have no alternative presentation
1146 }
1147
1148 if (*format == 'X') {
1149 flags |= FLAGS_UPPERCASE;
1150 }
1151
1152 format++;
1153 // ignore '0' flag when precision is given
1154 if (flags & FLAGS_PRECISION) {
1155 flags &= ~FLAGS_ZEROPAD;
1156 }
1157
1158 if (flags & FLAGS_SIGNED) {
1159 // A signed specifier: d, i or possibly I + bit size if enabled
1160
1161 if (flags & FLAGS_LONG_LONG) {
1162 #ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
1163 const long long value = va_arg(args, long long);
1164 print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
1165 #endif
1166 }
1167 else if (flags & FLAGS_LONG) {
1168 const long value = va_arg(args, long);
1169 print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
1170 }
1171 else {
1172 // We never try to interpret the argument as something potentially-smaller than int,
1173 // due to integer promotion rules: Even if the user passed a short int, short unsigned
1174 // etc. - these will come in after promotion, as int's (or unsigned for the case of
1175 // short unsigned when it has the same size as int)
1176 const int value =
1177 (flags & FLAGS_CHAR) ? (signed char) va_arg(args, int) :
1178 (flags & FLAGS_SHORT) ? (short int) va_arg(args, int) :
1179 va_arg(args, int);
1180 print_integer(output, ABS_FOR_PRINTING(value), value < 0, base, precision, width, flags);
1181 }
1182 }
1183 else {
1184 // An unsigned specifier: u, x, X, o, b
1185
1186 flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
1187
1188 if (flags & FLAGS_LONG_LONG) {
1189 #ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
1190 print_integer(output, (printf_unsigned_value_t) va_arg(args, unsigned long long), false, base, precision, width, flags);
1191 #endif
1192 }
1193 else if (flags & FLAGS_LONG) {
1194 print_integer(output, (printf_unsigned_value_t) va_arg(args, unsigned long), false, base, precision, width, flags);
1195 }
1196 else {
1197 const unsigned int value =
1198 (flags & FLAGS_CHAR) ? (unsigned char)va_arg(args, unsigned int) :
1199 (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(args, unsigned int) :
1200 va_arg(args, unsigned int);
1201 print_integer(output, (printf_unsigned_value_t) value, false, base, precision, width, flags);
1202 }
1203 }
1204 break;
1205 }
1206 #ifdef RT_KLIBC_USING_VSNPRINTF_DECIMAL_SPECIFIERS
1207 case 'f' :
1208 case 'F' :
1209 if (*format == 'F') flags |= FLAGS_UPPERCASE;
1210 print_floating_point(output, va_arg(args, double), precision, width, flags, PRINTF_PREFER_DECIMAL);
1211 format++;
1212 break;
1213 #endif
1214 #ifdef RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
1215 case 'e':
1216 case 'E':
1217 case 'g':
1218 case 'G':
1219 if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
1220 if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
1221 print_floating_point(output, va_arg(args, double), precision, width, flags, PRINTF_PREFER_EXPONENTIAL);
1222 format++;
1223 break;
1224 #endif // RT_KLIBC_USING_VSNPRINTF_EXPONENTIAL_SPECIFIERS
1225 case 'c' : {
1226 printf_size_t l = 1U;
1227 // pre padding
1228 if (!(flags & FLAGS_LEFT)) {
1229 while (l++ < width) {
1230 putchar_via_gadget(output, ' ');
1231 }
1232 }
1233 // char output
1234 putchar_via_gadget(output, (char) va_arg(args, int) );
1235 // post padding
1236 if (flags & FLAGS_LEFT) {
1237 while (l++ < width) {
1238 putchar_via_gadget(output, ' ');
1239 }
1240 }
1241 format++;
1242 break;
1243 }
1244
1245 case 's' : {
1246 const char* p = va_arg(args, char*);
1247 if (p == NULL) {
1248 out_rev_(output, ")llun(", 6, width, flags);
1249 }
1250 else {
1251 printf_size_t l = strnlen_s_(p, precision ? precision : PRINTF_MAX_POSSIBLE_BUFFER_SIZE);
1252 // pre padding
1253 if (flags & FLAGS_PRECISION) {
1254 l = (l < precision ? l : precision);
1255 }
1256 if (!(flags & FLAGS_LEFT)) {
1257 while (l++ < width) {
1258 putchar_via_gadget(output, ' ');
1259 }
1260 }
1261 // string output
1262 while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision)) {
1263 putchar_via_gadget(output, *(p++));
1264 --precision;
1265 }
1266 // post padding
1267 if (flags & FLAGS_LEFT) {
1268 while (l++ < width) {
1269 putchar_via_gadget(output, ' ');
1270 }
1271 }
1272 }
1273 format++;
1274 break;
1275 }
1276
1277 case 'p' : {
1278 width = sizeof(void*) * 2U + 2; // 2 hex chars per byte + the "0x" prefix
1279 flags |= FLAGS_ZEROPAD | FLAGS_POINTER;
1280 uintptr_t value = (uintptr_t)va_arg(args, void*);
1281 (value == (uintptr_t) NULL) ?
1282 out_rev_(output, ")lin(", 5, width, flags) :
1283 print_integer(output, (printf_unsigned_value_t) value, false, BASE_HEX, precision, width, flags);
1284 format++;
1285 break;
1286 }
1287
1288 case '%' :
1289 putchar_via_gadget(output, '%');
1290 format++;
1291 break;
1292
1293 // Many people prefer to disable support for %n, as it lets the caller
1294 // engineer a write to an arbitrary location, of a value the caller
1295 // effectively controls - which could be a security concern in some cases.
1296 #ifdef RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
1297 case 'n' : {
1298 if (flags & FLAGS_CHAR) *(va_arg(args, char*)) = (char) output->pos;
1299 else if (flags & FLAGS_SHORT) *(va_arg(args, short*)) = (short) output->pos;
1300 else if (flags & FLAGS_LONG) *(va_arg(args, long*)) = (long) output->pos;
1301 #ifdef RT_KLIBC_USING_VSNPRINTF_LONGLONG
1302 else if (flags & FLAGS_LONG_LONG) *(va_arg(args, long long*)) = (long long int) output->pos;
1303 #endif // RT_KLIBC_USING_VSNPRINTF_LONGLONG
1304 else *(va_arg(args, int*)) = (int) output->pos;
1305 format++;
1306 break;
1307 }
1308 #endif // RT_KLIBC_USING_VSNPRINTF_WRITEBACK_SPECIFIER
1309
1310 default :
1311 putchar_via_gadget(output, *format);
1312 format++;
1313 break;
1314 }
1315 }
1316 }
1317
1318 // internal vsnprintf - used for implementing _all library functions
vsnprintf_impl(output_gadget_t * output,const char * format,va_list args)1319 static int vsnprintf_impl(output_gadget_t* output, const char* format, va_list args)
1320 {
1321 // Note: The library only calls vsnprintf_impl() with output->pos being 0. However, it is
1322 // possible to call this function with a non-zero pos value for some "remedial printing".
1323 format_string_loop(output, format, args);
1324
1325 // termination
1326 append_termination_with_gadget(output);
1327
1328 // return written chars without terminating \0
1329 return (int)output->pos;
1330 }
1331
1332 ///////////////////////////////////////////////////////////////////////////////
1333
1334 /**
1335 * @brief This function will fill a formatted string to buffer.
1336 *
1337 * @param buf is the buffer to save formatted string.
1338 *
1339 * @param size is the size of buffer.
1340 *
1341 * @param fmt is the format parameters.
1342 *
1343 * @param args is a list of variable parameters.
1344 *
1345 * @return The number of characters actually written to buffer.
1346 */
rt_vsnprintf(char * buf,rt_size_t size,const char * fmt,va_list args)1347 int rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args)
1348 {
1349 output_gadget_t gadget = buffer_gadget(buf, size);
1350 return vsnprintf_impl(&gadget, fmt, args);
1351 }
1352