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