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