1 /* Copyright (c) 2002, Alexander Popov (sasho@vip.bg)
2 Copyright (c) 2002,2004,2005 Joerg Wunsch
3 Copyright (c) 2005, Helmut Wallner
4 Copyright (c) 2007, Dmitry Xmelkov
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16 * Neither the name of the copyright holders nor the names of
17 contributors may be used to endorse or promote products derived
18 from this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /* From: Id: printf_p_new.c,v 1.1.1.9 2002/10/15 20:10:28 joerg_wunsch Exp */
34 /* $Id: vfprintf.c 2191 2010-11-05 13:45:57Z arcanum $ */
35
36 #define _DEFAULT_SOURCE
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h>
42 #include "stdio_private.h"
43 #include "../../libm/common/math_config.h"
44
45 #ifdef WIDE_CHARS
46 #include <wchar.h>
47 #define CHAR wchar_t
48 #define UCHAR wchar_t
49 #undef vfprintf
50 #define vfprintf vfwprintf
51 #else
52 #define CHAR char
53 #define UCHAR unsigned char
54 #endif
55
56 #ifdef PICOLIBC_FLOAT_PRINTF_SCANF
57 static inline float
printf_float_get(uint32_t u)58 printf_float_get(uint32_t u)
59 {
60 return asfloat(u);
61 }
62
63 #define PRINTF_FLOAT_ARG(ap) (printf_float_get(va_arg(ap, uint32_t)))
64 typedef float printf_float_t;
65 typedef int32_t printf_float_int_t;
66 #define ASUINT(a) asuint(a)
67 #define EXP_BIAS 127
68
69 #define dtoa ftoa
70 #define DTOA_MINUS FTOA_MINUS
71 #define DTOA_ZERO FTOA_ZERO
72 #define DTOA_INF FTOA_INF
73 #define DTOA_NAN FTOA_NAN
74 #define DTOA_CARRY FTOA_CARRY
75 #define DTOA_MAX_DIG FTOA_MAX_DIG
76 #define __dtoa_engine(x,dtoa,dig,f,dec) __ftoa_engine(x,dtoa,dig,f,dec)
77 #include "ftoa_engine.h"
78
79 #else
80
81 #define PRINTF_FLOAT_ARG(ap) va_arg(ap, double)
82 typedef double printf_float_t;
83 typedef int64_t printf_float_int_t;
84 #define ASUINT(a) asuint64(a)
85 #define EXP_BIAS 1023
86 #include "dtoa_engine.h"
87
88 #if defined(_WANT_IO_LONG_DOUBLE) && __SIZEOF_LONG_DOUBLE__ > __SIZEOF_DOUBLE__
89 # define PICOLIBC_LONG_DOUBLE_PRINTF_SCANF
90 # include "ldtoa_engine.h"
91 #endif
92
93 #endif
94
95 /*
96 * This file can be compiled into more than one flavour. The default
97 * is to offer the usual modifiers and integer formatting support
98 * (level 1). Level 2 includes floating point support.
99 */
100
101 #ifndef PRINTF_LEVEL
102 # define PRINTF_LEVEL PRINTF_FLT
103 # ifndef FORMAT_DEFAULT_DOUBLE
104 # define vfprintf __d_vfprintf
105 # endif
106 #endif
107
108 #if PRINTF_LEVEL == PRINTF_STD || PRINTF_LEVEL == PRINTF_FLT
109
110 #if ((PRINTF_LEVEL >= PRINTF_FLT) || defined(_WANT_IO_LONG_LONG))
111 #define PRINTF_LONGLONG
112 #endif
113
114 #if ((PRINTF_LEVEL >= PRINTF_FLT) || defined(_WANT_IO_POS_ARGS))
115 #define PRINTF_POSITIONAL
116 #endif
117
118 #ifdef PRINTF_LONGLONG
119 typedef unsigned long long ultoa_unsigned_t;
120 typedef long long ultoa_signed_t;
121 #define SIZEOF_ULTOA __SIZEOF_LONG_LONG__
122 #define arg_to_t(ap, flags, _s_, _result_) \
123 if ((flags) & FL_LONG) { \
124 if ((flags) & FL_REPD_TYPE) \
125 (_result_) = va_arg(ap, _s_ long long); \
126 else \
127 (_result_) = va_arg(ap, _s_ long); \
128 } else { \
129 (_result_) = va_arg(ap, _s_ int); \
130 if ((flags) & FL_SHORT) { \
131 if ((flags) & FL_REPD_TYPE) \
132 (_result_) = (_s_ char) (_result_); \
133 else \
134 (_result_) = (_s_ short) (_result_); \
135 } \
136 }
137 #else
138 typedef unsigned long ultoa_unsigned_t;
139 typedef long ultoa_signed_t;
140 #define SIZEOF_ULTOA __SIZEOF_LONG__
141 #define arg_to_t(ap, flags, _s_, _result_) \
142 if ((flags) & FL_LONG) { \
143 if ((flags) & FL_REPD_TYPE) \
144 (_result_) = (_s_ long) va_arg(ap, _s_ long long);\
145 else \
146 (_result_) = va_arg(ap, _s_ long); \
147 } else { \
148 (_result_) = va_arg(ap, _s_ int); \
149 if ((flags) & FL_SHORT) { \
150 if ((flags) & FL_REPD_TYPE) \
151 (_result_) = (_s_ char) (_result_); \
152 else \
153 (_result_) = (_s_ short) (_result_); \
154 } \
155 }
156 #endif
157
158 #if SIZEOF_ULTOA <= 4
159 #ifdef _WANT_IO_PERCENT_B
160 #define PRINTF_BUF_SIZE 32
161 #else
162 #define PRINTF_BUF_SIZE 11
163 #endif
164 #else
165 #ifdef _WANT_IO_PERCENT_B
166 #define PRINTF_BUF_SIZE 64
167 #else
168 #define PRINTF_BUF_SIZE 22
169 #endif
170 #endif
171
172 // At the call site the address of the result_var is taken (e.g. "&ap")
173 // That way, it's clear that these macros *will* modify that variable
174 #define arg_to_unsigned(ap, flags, result_var) arg_to_t(ap, flags, unsigned, result_var)
175 #define arg_to_signed(ap, flags, result_var) arg_to_t(ap, flags, signed, result_var)
176
177 #include "ultoa_invert.c"
178
179 /* Order is relevant here and matches order in format string */
180
181 #define FL_ZFILL 0x0001
182 #define FL_PLUS 0x0002
183 #define FL_SPACE 0x0004
184 #define FL_LPAD 0x0008
185 #define FL_ALT 0x0010
186
187 #define FL_WIDTH 0x0020
188 #define FL_PREC 0x0040
189
190 #define FL_LONG 0x0080
191 #define FL_SHORT 0x0100
192 #define FL_REPD_TYPE 0x0200
193
194 #define FL_NEGATIVE 0x0400
195
196 #ifdef _WANT_IO_C99_FORMATS
197 #define FL_FLTHEX 0x0800
198 #endif
199 #define FL_FLTEXP 0x1000
200 #define FL_FLTFIX 0x2000
201
202 #ifdef PRINTF_POSITIONAL
203
204 typedef struct {
205 va_list ap;
206 } my_va_list;
207
208 /*
209 * Repeatedly scan the format string finding argument position values
210 * and types to slowly walk the argument vector until it points at the
211 * target_argno so that the outer printf code can then extract it.
212 */
213 static void
skip_to_arg(const CHAR * fmt_orig,my_va_list * ap,int target_argno)214 skip_to_arg(const CHAR *fmt_orig, my_va_list *ap, int target_argno)
215 {
216 unsigned c; /* holds a char from the format string */
217 uint16_t flags;
218 int current_argno = 1;
219 int argno;
220 int width;
221 const CHAR *fmt = fmt_orig;
222
223 while (current_argno < target_argno) {
224 for (;;) {
225 c = *fmt++;
226 if (!c) return;
227 if (c == '%') {
228 c = *fmt++;
229 if (c != '%') break;
230 }
231 }
232 flags = 0;
233 width = 0;
234 argno = 0;
235
236 /*
237 * Scan the format string until we hit current_argno. This can
238 * either be a value, width or precision field.
239 */
240 do {
241 if (flags < FL_WIDTH) {
242 switch (c) {
243 case '0':
244 continue;
245 case '+':
246 case ' ':
247 continue;
248 case '-':
249 continue;
250 case '#':
251 continue;
252 case '\'':
253 continue;
254 }
255 }
256
257 if (flags < FL_LONG) {
258 if (c >= '0' && c <= '9') {
259 c -= '0';
260 width = 10 * width + c;
261 flags |= FL_WIDTH;
262 continue;
263 }
264 if (c == '$') {
265 /*
266 * If we've already seen the value position, any
267 * other positions will be either width or
268 * precisions. We can handle those in the same
269 * fashion as they're both 'int' type
270 */
271 if (argno) {
272 if (width == current_argno) {
273 c = 'c';
274 argno = width;
275 break;
276 }
277 }
278 else
279 argno = width;
280 width = 0;
281 continue;
282 }
283
284 if (c == '*') {
285 width = 0;
286 continue;
287 }
288
289 if (c == '.') {
290 width = 0;
291 continue;
292 }
293 }
294
295 if (c == 'l') {
296 if (flags & FL_LONG)
297 flags |= FL_REPD_TYPE;
298 flags |= FL_LONG;
299 continue;
300 }
301
302 if (c == 'h') {
303 if (flags & FL_SHORT)
304 flags |= FL_REPD_TYPE;
305 flags |= FL_SHORT;
306 continue;
307 }
308
309 /* alias for 'll' */
310 if (c == 'L') {
311 flags |= FL_REPD_TYPE;
312 flags |= FL_LONG;
313 continue;
314 }
315
316 #ifdef _WANT_IO_C99_FORMATS
317
318 #define CHECK_LONGLONG(type) else if (sizeof(type) == sizeof(long long)) flags |= FL_LONG|FL_REPD_TYPE;
319
320 #define CHECK_INT_SIZE(letter, type) \
321 if (c == letter) { \
322 if (sizeof(type) == sizeof(int)) \
323 ; \
324 else if (sizeof(type) == sizeof(long)) \
325 flags |= FL_LONG; \
326 CHECK_LONGLONG(type) \
327 else if (sizeof(type) == sizeof(short)) \
328 flags |= FL_SHORT; \
329 continue; \
330 }
331
332 CHECK_INT_SIZE('j', intmax_t);
333 CHECK_INT_SIZE('z', size_t);
334 CHECK_INT_SIZE('t', ptrdiff_t);
335 #endif
336 break;
337 } while ( (c = *fmt++) != 0);
338 if (argno == 0)
339 break;
340 if (argno == current_argno) {
341 if ((TOLOW(c) >= 'e' && TOLOW(c) <= 'g')
342 #ifdef _WANT_IO_C99_FORMATS
343 || TOLOW(c) == 'a'
344 #endif
345 ) {
346 #ifdef PICOLIBC_LONG_DOUBLE_PRINTF_SCANF
347 if ((flags & (FL_LONG | FL_REPD_TYPE)) == (FL_LONG | FL_REPD_TYPE))
348 (void) va_arg(ap->ap, long double);
349 else
350 #endif
351 (void) PRINTF_FLOAT_ARG(ap->ap);
352 } else if (c == 'c') {
353 (void) va_arg (ap->ap, int);
354 } else if (c == 's') {
355 (void) va_arg (ap->ap, char *);
356 } else if (c == 'd' || c == 'i') {
357 ultoa_signed_t x_s;
358 arg_to_signed(ap->ap, flags, x_s);
359 } else {
360 ultoa_unsigned_t x;
361 arg_to_unsigned(ap->ap, flags, x);
362 }
363 ++current_argno;
364 fmt = fmt_orig;
365 }
366 }
367 }
368 #endif
369
vfprintf(FILE * stream,const CHAR * fmt,va_list ap_orig)370 int vfprintf (FILE * stream, const CHAR *fmt, va_list ap_orig)
371 {
372 unsigned c; /* holds a char from the format string */
373 uint16_t flags;
374 int width;
375 int prec;
376 #ifdef PRINTF_POSITIONAL
377 int argno;
378 my_va_list my_ap;
379 const CHAR *fmt_orig = fmt;
380 #define ap my_ap.ap
381 #else
382 #define ap ap_orig
383 #endif
384 union {
385 char __buf[PRINTF_BUF_SIZE]; /* size for -1 in smallest base, without '\0' */
386 #if PRINTF_LEVEL >= PRINTF_FLT
387 struct dtoa __dtoa;
388 #ifdef PICOLIBC_LONG_DOUBLE_PRINTF_SCANF
389 struct ldtoa __ldtoa;
390 #endif
391 #endif
392 } u;
393 const char * pnt;
394 size_t size;
395
396 #define buf (u.__buf)
397 #define _dtoa (u.__dtoa)
398
399 int stream_len = 0;
400
401 #ifndef my_putc
402 int (*put)(char, FILE *) = stream->put;
403 #define my_putc(c, stream) do { ++stream_len; if (put(c, stream) < 0) goto fail; } while(0)
404 #endif
405
406 if ((stream->flags & __SWR) == 0)
407 return EOF;
408
409 #ifdef PRINTF_POSITIONAL
410 va_copy(ap, ap_orig);
411 #endif
412
413 for (;;) {
414
415 for (;;) {
416 c = *fmt++;
417 if (!c) goto ret;
418 if (c == '%') {
419 c = *fmt++;
420 if (c != '%') break;
421 }
422 my_putc (c, stream);
423 }
424
425 flags = 0;
426 width = 0;
427 prec = 0;
428 #ifdef PRINTF_POSITIONAL
429 argno = 0;
430 #endif
431
432 do {
433 if (flags < FL_WIDTH) {
434 switch (c) {
435 case '0':
436 flags |= FL_ZFILL;
437 continue;
438 case '+':
439 flags |= FL_PLUS;
440 FALLTHROUGH;
441 case ' ':
442 flags |= FL_SPACE;
443 continue;
444 case '-':
445 flags |= FL_LPAD;
446 continue;
447 case '#':
448 flags |= FL_ALT;
449 continue;
450 case '\'':
451 /*
452 * C/POSIX locale has an empty thousands_sep
453 * value, so we can just ignore this character
454 */
455 continue;
456 }
457 }
458
459 if (flags < FL_LONG) {
460 if (c >= '0' && c <= '9') {
461 c -= '0';
462 if (flags & FL_PREC) {
463 prec = 10*prec + c;
464 continue;
465 }
466 width = 10*width + c;
467 flags |= FL_WIDTH;
468 continue;
469 }
470 if (c == '*') {
471 #ifdef PRINTF_POSITIONAL
472 /*
473 * Positional args must be used together, so wait
474 * for the value to appear before dealing with
475 * width and precision fields
476 */
477 if (argno)
478 continue;
479 #endif
480 if (flags & FL_PREC) {
481 prec = va_arg(ap, int);
482 } else {
483 width = va_arg(ap, int);
484 flags |= FL_WIDTH;
485 if (width < 0) {
486 width = -width;
487 flags |= FL_LPAD;
488 }
489 }
490 continue;
491 }
492 if (c == '.') {
493 if (flags & FL_PREC)
494 goto ret;
495 flags |= FL_PREC;
496 continue;
497 }
498 #ifdef PRINTF_POSITIONAL
499 /* Check for positional args */
500 if (c == '$') {
501 /* Check if we've already got the arg position and
502 * are adding width or precision fields
503 */
504 if (argno) {
505 va_end(ap);
506 va_copy(ap, ap_orig);
507 skip_to_arg(fmt_orig, &my_ap, (flags & FL_PREC) ? prec : width);
508 if (flags & FL_PREC)
509 prec = va_arg(ap, int);
510 else
511 width = va_arg(ap, int);
512 } else {
513 argno = width;
514 flags = 0;
515 width = 0;
516 prec = 0;
517 }
518 continue;
519 }
520 #endif
521 }
522
523 if (c == 'l') {
524 if (flags & FL_LONG)
525 flags |= FL_REPD_TYPE;
526 flags |= FL_LONG;
527 continue;
528 }
529
530 if (c == 'h') {
531 if (flags & FL_SHORT)
532 flags |= FL_REPD_TYPE;
533 flags |= FL_SHORT;
534 continue;
535 }
536
537 /* alias for 'll' */
538 if (c == 'L') {
539 flags |= FL_REPD_TYPE;
540 flags |= FL_LONG;
541 continue;
542 }
543
544 #define CHECK_LONGLONG(type) else if (sizeof(type) == sizeof(long long)) flags |= FL_LONG|FL_REPD_TYPE;
545
546 #ifdef _WANT_IO_C99_FORMATS
547
548 #define CHECK_INT_SIZE(letter, type) \
549 if (c == letter) { \
550 if (sizeof(type) == sizeof(int)) \
551 ; \
552 else if (sizeof(type) == sizeof(long)) \
553 flags |= FL_LONG; \
554 CHECK_LONGLONG(type) \
555 else if (sizeof(type) == sizeof(short)) \
556 flags |= FL_SHORT; \
557 continue; \
558 }
559
560 CHECK_INT_SIZE('j', intmax_t);
561 CHECK_INT_SIZE('z', size_t);
562 CHECK_INT_SIZE('t', ptrdiff_t);
563 #endif
564
565 break;
566 } while ( (c = *fmt++) != 0);
567
568 #ifdef PRINTF_POSITIONAL
569 /* Set arg pointers for positional args */
570 if (argno) {
571 va_end(ap);
572 va_copy(ap, ap_orig);
573 skip_to_arg(fmt_orig, &my_ap, argno);
574 }
575 #endif
576
577 /* This can happen only when prec is set via a '*'
578 * specifier, in which case it works as if no precision
579 * was specified. Set the precision to zero and clear the
580 * flag.
581 */
582 if (prec < 0) {
583 prec = 0;
584 flags &= ~FL_PREC;
585 }
586
587 /* Only a format character is valid. */
588
589 #if 'F' != 'E'+1 || 'G' != 'F'+1 || 'f' != 'e'+1 || 'g' != 'f'+1
590 # error
591 #endif
592
593 #define TOCASE(c) ((c) - case_convert)
594
595 if ((TOLOW(c) >= 'e' && TOLOW(c) <= 'g')
596 #ifdef _WANT_IO_C99_FORMATS
597 || TOLOW(c) == 'a'
598 #endif
599 )
600 {
601 #if PRINTF_LEVEL >= PRINTF_FLT
602 uint8_t sign; /* sign character (or 0) */
603 uint8_t ndigs; /* number of digits to convert */
604 unsigned char case_convert; /* subtract to correct case */
605 int exp; /* exponent of most significant decimal digit */
606 int n; /* total width */
607 uint8_t ndigs_exp; /* number of digis in exponent */
608
609 /* deal with upper vs lower case */
610 case_convert = TOLOW(c) - c;
611 c = TOLOW(c);
612
613 #ifdef PICOLIBC_LONG_DOUBLE_PRINTF_SCANF
614 if ((flags & (FL_LONG | FL_REPD_TYPE)) == (FL_LONG | FL_REPD_TYPE))
615 {
616 long double fval;
617 fval = va_arg(ap, long double);
618
619 ndigs = 0;
620
621 #ifdef _WANT_IO_C99_FORMATS
622 if (c == 'a') {
623 _u128 fi;
624 _u128 s;
625
626 c = 'p';
627 flags |= FL_FLTEXP | FL_FLTHEX;
628
629 ndigs = (__LDBL_MANT_DIG__ + 3) / 4;
630 fi = asuint128(fval);
631
632
633 #if __LDBL_MANT_DIG__ == 64
634 #define LDENORM_EXP_BIAS 1
635 #define LEXP_BIAS (__LDBL_MAX_EXP__ + 2)
636 #define LSIG_BITS (__LDBL_MANT_DIG__)
637 #define LEXP_SHIFT __LDBL_MANT_DIG__
638 #else
639 #define LDENORM_EXP_BIAS 1
640 #define LEXP_BIAS (__LDBL_MAX_EXP__ - 1)
641 #define LSIG_MSB _u128_lshift(to_u128(1), __LDBL_MANT_DIG__-1)
642 #define LSIG_BITS (__LDBL_MANT_DIG__ - 1)
643 #define LEXP_SHIFT (__LDBL_MANT_DIG__ - 1)
644 #endif
645 #define LEXP_MASK ((__LDBL_MAX_EXP__ - 1) + __LDBL_MAX_EXP__)
646 #define LSIG_SHIFT 0
647 #define LSIG_MASK _u128_minus_64(_u128_lshift(to_u128(1), LSIG_BITS), 1)
648
649 exp = _u128_and_64(_u128_rshift(fi, LEXP_SHIFT), LEXP_MASK);
650 s = fi = _u128_lshift(_u128_and(fi, LSIG_MASK), LSIG_SHIFT);
651 if (!_u128_is_zero(s) || exp != 0) {
652 if (exp == 0)
653 exp = LDENORM_EXP_BIAS;
654 else
655 {
656 #ifdef LSIG_MSB
657 s = _u128_or(s, LSIG_MSB);
658 #endif
659 }
660 exp -= LEXP_BIAS;
661 }
662 _dtoa.flags = 0;
663 if (_i128_lt_zero(fi))
664 _dtoa.flags = DTOA_MINUS;
665
666 if (!(flags & FL_PREC))
667 prec = 0;
668 else if (prec >= (ndigs - 1))
669 prec = ndigs - 1;
670 else {
671 int bits = ((ndigs - 1) - prec) << 2;
672 _u128 half = _u128_lshift(to_u128(1), bits - 1);
673 _u128 mask = _u128_not(_u128_minus_64(_u128_lshift(half, 1), 1));
674
675 /* round even */
676 if (_u128_gt(_u128_and(s, _u128_not(mask)), half) || _u128_and_64(_u128_rshift(s, bits), 1) != 0)
677 s = _u128_plus(s, half);
678
679 s = _u128_and(s, mask);
680 }
681
682 if (exp == LEXP_BIAS + 1) {
683 if (!_u128_is_zero(fi))
684 _dtoa.flags |= DTOA_NAN;
685 else
686 _dtoa.flags |= DTOA_INF;
687 } else {
688 int8_t d;
689 for (d = ndigs - 1; d >= 0; d--) {
690 char dig = _u128_and_64(s, 0xf);
691 s = _u128_rshift(s, 4);
692 if (dig == 0 && d > prec)
693 continue;
694 if (dig <= 9)
695 dig += '0';
696 else
697 dig += TOCASE('a' - 10);
698 _dtoa.digits[d] = dig;
699 if (prec < d)
700 prec = d;
701 }
702 }
703 ndigs_exp = 1;
704 } else
705 #endif /* _WANT_IO_C99_FORMATS */
706 {
707 int ndecimal = 0; /* digits after decimal (for 'f' format) */
708 bool fmode = false;
709
710 if (!(flags & FL_PREC))
711 prec = 6;
712 if (c == 'e') {
713 ndigs = prec + 1;
714 flags |= FL_FLTEXP;
715 } else if (c == 'f') {
716 ndigs = DTOA_MAX_DIG;
717 ndecimal = prec;
718 flags |= FL_FLTFIX;
719 fmode = true;
720 } else {
721 c += 'e' - 'g';
722 ndigs = prec;
723 if (ndigs < 1) ndigs = 1;
724 }
725
726 if (ndigs > DTOA_MAX_DIG)
727 ndigs = DTOA_MAX_DIG;
728
729 ndigs = __dtoa_engine ((double) fval, &_dtoa, ndigs, fmode, ndecimal);
730 exp = _dtoa.exp;
731 ndigs_exp = 2;
732 }
733 }
734 else
735 #endif
736 {
737 printf_float_t fval; /* value to print */
738
739 fval = PRINTF_FLOAT_ARG(ap);
740
741 ndigs = 0;
742
743 #ifdef _WANT_IO_C99_FORMATS
744 if (c == 'a') {
745 printf_float_int_t fi;
746 ultoa_signed_t s;
747
748 c = 'p';
749 flags |= FL_FLTEXP | FL_FLTHEX;
750
751 #ifdef PICOLIBC_FLOAT_PRINTF_SCANF
752 ndigs = 7;
753 #else
754 ndigs = 14;
755 #endif
756 fi = ASUINT(fval);
757
758 _dtoa.digits[0] = '0';
759 #ifdef PICOLIBC_FLOAT_PRINTF_SCANF
760 #define EXP_SHIFT 23
761 #define EXP_MASK 0xff
762 #define SIG_SHIFT 1
763 #define SIG_MASK 0x7fffff
764 #else
765 #define EXP_SHIFT 52
766 #define EXP_MASK 0x7ff
767 #define SIG_SHIFT 0
768 #define SIG_MASK 0xfffffffffffffLL
769 #endif
770 exp = ((fi >> EXP_SHIFT) & EXP_MASK);
771 s = (fi & SIG_MASK) << SIG_SHIFT;
772 if (s | exp) {
773 if (!exp)
774 exp = 1;
775 else
776 _dtoa.digits[0] = '1';
777 exp -= EXP_BIAS;
778 }
779 _dtoa.flags = 0;
780 if (fi < 0)
781 _dtoa.flags = DTOA_MINUS;
782
783 if (!(flags & FL_PREC))
784 prec = 0;
785 else if (prec >= (ndigs - 1))
786 prec = ndigs - 1;
787 else {
788 int bits = ((ndigs - 1) - prec) << 2;
789 ultoa_signed_t half = ((ultoa_signed_t) 1) << (bits - 1);
790 ultoa_signed_t mask = ~((half << 1) - 1);
791
792 /* round even */
793 if ((s & ~mask) > half || ((s >> bits) & 1) != 0)
794 s += half;
795 /* special case rounding first digit */
796 if (s > (SIG_MASK << SIG_SHIFT))
797 _dtoa.digits[0]++;
798 s &= mask;
799 }
800
801 if (exp == EXP_BIAS + 1) {
802 if (s)
803 _dtoa.flags |= DTOA_NAN;
804 else
805 _dtoa.flags |= DTOA_INF;
806 } else {
807 uint8_t d;
808 for (d = ndigs - 1; d; d--) {
809 char dig = s & 0xf;
810 s >>= 4;
811 if (dig == 0 && d > prec)
812 continue;
813 if (dig <= 9)
814 dig += '0';
815 else
816 dig += TOCASE('a' - 10);
817 _dtoa.digits[d] = dig;
818 if (prec < d)
819 prec = d;
820 }
821 }
822 ndigs_exp = 1;
823 } else
824 #endif /* _WANT_IO_C99_FORMATS */
825 {
826 int ndecimal = 0; /* digits after decimal (for 'f' format) */
827 bool fmode = false;
828
829 if (!(flags & FL_PREC))
830 prec = 6;
831 if (c == 'e') {
832 ndigs = prec + 1;
833 flags |= FL_FLTEXP;
834 } else if (c == 'f') {
835 ndigs = DTOA_MAX_DIG;
836 ndecimal = prec;
837 flags |= FL_FLTFIX;
838 fmode = true;
839 } else {
840 c += 'e' - 'g';
841 ndigs = prec;
842 if (ndigs < 1) ndigs = 1;
843 }
844
845 if (ndigs > DTOA_MAX_DIG)
846 ndigs = DTOA_MAX_DIG;
847
848 ndigs = __dtoa_engine (fval, &_dtoa, ndigs, fmode, ndecimal);
849 exp = _dtoa.exp;
850 ndigs_exp = 2;
851 }
852 }
853 if (exp < -9 || 9 < exp)
854 ndigs_exp = 2;
855 if (exp < -99 || 99 < exp)
856 ndigs_exp = 3;
857 #ifndef PICOLIBC_FLOAT_PRINTF_SCANF
858 if (exp < -999 || 999 < exp)
859 ndigs_exp = 4;
860 #ifdef PICOLIBC_LONG_DOUBLE_PRINTF_SCANF
861 if (exp < -9999 || 9999 < exp)
862 ndigs_exp = 5;
863 #endif
864 #endif
865
866 sign = 0;
867 if (_dtoa.flags & DTOA_MINUS)
868 sign = '-';
869 else if (flags & FL_PLUS)
870 sign = '+';
871 else if (flags & FL_SPACE)
872 sign = ' ';
873
874 if (_dtoa.flags & (DTOA_NAN | DTOA_INF))
875 {
876 ndigs = sign ? 4 : 3;
877 if (width > ndigs) {
878 width -= ndigs;
879 if (!(flags & FL_LPAD)) {
880 do {
881 my_putc (' ', stream);
882 } while (--width);
883 }
884 } else {
885 width = 0;
886 }
887 if (sign)
888 my_putc (sign, stream);
889 pnt = "inf";
890 if (_dtoa.flags & DTOA_NAN)
891 pnt = "nan";
892 while ( (c = *pnt++) )
893 my_putc (TOCASE(c), stream);
894 }
895 else
896 {
897
898 if (!(flags & (FL_FLTEXP|FL_FLTFIX))) {
899
900 /* 'g(G)' format */
901
902 /*
903 * On entry to this block, prec is
904 * the number of digits to display.
905 *
906 * On exit, prec is the number of digits
907 * to display after the decimal point
908 */
909
910 /* Always show at least one digit */
911 if (prec == 0)
912 prec = 1;
913
914 /*
915 * Remove trailing zeros. The ryu code can emit them
916 * when rounding to fewer digits than required for
917 * exact output, the imprecise code often emits them
918 */
919 while (ndigs > 0 && _dtoa.digits[ndigs-1] == '0')
920 ndigs--;
921
922 /* Save requested precision */
923 int req_prec = prec;
924
925 /* Limit output precision to ndigs unless '#' */
926 if (!(flags & FL_ALT))
927 prec = ndigs;
928
929 /*
930 * Figure out whether to use 'f' or 'e' format. The spec
931 * says to use 'f' if the exponent is >= -4 and < requested
932 * precision.
933 */
934 if (-4 <= exp && exp < req_prec)
935 {
936 flags |= FL_FLTFIX;
937
938 /* Compute how many digits to show after the decimal.
939 *
940 * If exp is negative, then we need to show that
941 * many leading zeros plus the requested precision
942 *
943 * If exp is less than prec, then we need to show a
944 * number of digits past the decimal point,
945 * including (potentially) some trailing zeros
946 *
947 * (these two cases end up computing the same value,
948 * and are both caught by the exp < prec test,
949 * so they share the same branch of the 'if')
950 *
951 * If exp is at least 'prec', then we don't show
952 * any digits past the decimal point.
953 */
954 if (exp < prec)
955 prec = prec - (exp + 1);
956 else
957 prec = 0;
958 } else {
959 /* Compute how many digits to show after the decimal */
960 prec = prec - 1;
961 }
962 }
963
964 /* Conversion result length, width := free space length */
965 if (flags & FL_FLTFIX)
966 n = (exp>0 ? exp+1 : 1);
967 else {
968 n = 3; /* 1e+ */
969 #ifdef _WANT_IO_C99_FORMATS
970 if (flags & FL_FLTHEX)
971 n += 2; /* or 0x1p+ */
972 #endif
973 n += ndigs_exp; /* add exponent */
974 }
975 if (sign)
976 n += 1;
977 if (prec)
978 n += prec + 1;
979 else if (flags & FL_ALT)
980 n += 1;
981
982 width = width > n ? width - n : 0;
983
984 /* Output before first digit */
985 if (!(flags & (FL_LPAD | FL_ZFILL))) {
986 while (width) {
987 my_putc (' ', stream);
988 width--;
989 }
990 }
991 if (sign)
992 my_putc (sign, stream);
993
994 #ifdef _WANT_IO_C99_FORMATS
995 if ((flags & FL_FLTHEX)) {
996 my_putc('0', stream);
997 my_putc(TOCASE('x'), stream);
998 }
999 #endif
1000
1001 if (!(flags & FL_LPAD)) {
1002 while (width) {
1003 my_putc ('0', stream);
1004 width--;
1005 }
1006 }
1007
1008 if (flags & FL_FLTFIX) { /* 'f' format */
1009 char out;
1010
1011 /* At this point, we should have
1012 *
1013 * exp exponent of leftmost digit in _dtoa.digits
1014 * ndigs number of buffer digits to print
1015 * prec number of digits after decimal
1016 *
1017 * In the loop, 'n' walks over the exponent value
1018 */
1019 n = exp > 0 ? exp : 0; /* exponent of left digit */
1020 do {
1021
1022 /* Insert decimal point at correct place */
1023 if (n == -1)
1024 my_putc ('.', stream);
1025
1026 /* Pull digits from buffer when in-range,
1027 * otherwise use 0
1028 */
1029 if (0 <= exp - n && exp - n < ndigs)
1030 out = _dtoa.digits[exp - n];
1031 else
1032 out = '0';
1033 if (--n < -prec) {
1034 break;
1035 }
1036 my_putc (out, stream);
1037 } while (1);
1038 if (n == exp
1039 && (_dtoa.digits[0] > '5'
1040 || (_dtoa.digits[0] == '5' && !(_dtoa.flags & DTOA_CARRY))) )
1041 {
1042 out = '1';
1043 }
1044 my_putc (out, stream);
1045 if ((flags & FL_ALT) && n == -1)
1046 my_putc('.', stream);
1047 } else { /* 'e(E)' format */
1048
1049 /* mantissa */
1050 if (_dtoa.digits[0] != '1')
1051 _dtoa.flags &= ~DTOA_CARRY;
1052 my_putc (_dtoa.digits[0], stream);
1053 if (prec > 0) {
1054 my_putc ('.', stream);
1055 uint8_t pos = 1;
1056 for (pos = 1; pos < 1 + prec; pos++)
1057 my_putc (pos < ndigs ? _dtoa.digits[pos] : '0', stream);
1058 } else if (flags & FL_ALT)
1059 my_putc ('.', stream);
1060
1061 /* exponent */
1062 my_putc (TOCASE(c), stream);
1063 sign = '+';
1064 if (exp < 0 || (exp == 0 && (_dtoa.flags & DTOA_CARRY) != 0)) {
1065 exp = -exp;
1066 sign = '-';
1067 }
1068 my_putc (sign, stream);
1069 #ifndef PICOLIBC_FLOAT_PRINTF_SCANF
1070 #ifdef PICOLIBC_LONG_DOUBLE_PRINTF_SCANF
1071 if (ndigs_exp > 4) {
1072 my_putc(exp / 10000 + '0', stream);
1073 exp %= 10000;
1074 }
1075 #endif
1076 if (ndigs_exp > 3) {
1077 my_putc(exp / 1000 + '0', stream);
1078 exp %= 1000;
1079 }
1080 #endif
1081 if (ndigs_exp > 2) {
1082 my_putc(exp / 100 + '0', stream);
1083 exp %= 100;
1084 }
1085 if (ndigs_exp > 1) {
1086 my_putc(exp / 10 + '0', stream);
1087 exp %= 10;
1088 }
1089 my_putc ('0' + exp, stream);
1090 }
1091 }
1092 #else /* to: PRINTF_LEVEL >= PRINTF_FLT */
1093 (void) PRINTF_FLOAT_ARG(ap);
1094 pnt = "*float*";
1095 size = sizeof ("*float*") - 1;
1096 goto str_lpad;
1097 #endif
1098 } else {
1099 int len, buf_len;
1100 #ifdef WIDE_CHARS
1101 CHAR *wstr = NULL;
1102 CHAR c_arg;
1103
1104 pnt = NULL;
1105 #endif
1106
1107 if (c == 'c') {
1108 #ifdef WIDE_CHARS
1109 c_arg = va_arg (ap, int);
1110 if (!(flags & FL_LONG))
1111 c_arg = (char) c_arg;
1112 wstr = &c_arg;
1113 #else
1114 buf[0] = va_arg (ap, int);
1115 pnt = buf;
1116 #endif
1117 size = 1;
1118 goto str_lpad;
1119 } else if (c == 's') {
1120 #ifdef WIDE_CHARS
1121 if (flags & FL_LONG) {
1122 wstr = va_arg(ap, CHAR *);
1123 if (wstr) {
1124 size = wcsnlen(wstr, (flags & FL_PREC) ? (size_t) prec : SIZE_MAX);
1125 goto str_lpad;
1126 }
1127 } else
1128 #endif
1129 pnt = va_arg (ap, char *);
1130 if (!pnt)
1131 pnt = "(null)";
1132 size = strnlen (pnt, (flags & FL_PREC) ? (size_t) prec : SIZE_MAX);
1133
1134 str_lpad:
1135 if (!(flags & FL_LPAD)) {
1136 while ((size_t) width > size) {
1137 my_putc (' ', stream);
1138 width--;
1139 }
1140 }
1141 width -= size;
1142 while (size--) {
1143 #ifdef WIDE_CHARS
1144 if (wstr)
1145 my_putc(*wstr++, stream);
1146 else
1147 #endif
1148 my_putc (*pnt++, stream);
1149 }
1150
1151 } else {
1152 if (c == 'd' || c == 'i') {
1153 ultoa_signed_t x_s;
1154
1155 arg_to_signed(ap, flags, x_s);
1156
1157 if (x_s < 0) {
1158 x_s = -x_s;
1159 flags |= FL_NEGATIVE;
1160 }
1161
1162 flags &= ~FL_ALT;
1163
1164 if (x_s == 0 && (flags & FL_PREC) && prec == 0)
1165 buf_len = 0;
1166 else
1167 buf_len = __ultoa_invert (x_s, buf, 10) - buf;
1168 } else {
1169 int base;
1170 ultoa_unsigned_t x;
1171
1172 if (c == 'u') {
1173 flags &= ~FL_ALT;
1174 base = 10;
1175 } else if (c == 'o') {
1176 base = 8;
1177 c = '\0';
1178 } else if (c == 'p') {
1179 base = 16;
1180 flags |= FL_ALT;
1181 c = 'x';
1182 if (sizeof(void *) > sizeof(int))
1183 flags |= FL_LONG;
1184 } else if (TOLOW(c) == 'x') {
1185 base = 16;
1186 if (c == 'X')
1187 base = 16 | XTOA_UPPER;
1188 #ifdef _WANT_IO_PERCENT_B
1189 } else if (TOLOW(c) == 'b') {
1190 base = 2;
1191 #endif
1192 } else {
1193 my_putc('%', stream);
1194 my_putc(c, stream);
1195 continue;
1196 }
1197
1198 flags &= ~(FL_PLUS | FL_SPACE);
1199
1200 arg_to_unsigned(ap, flags, x);
1201
1202 /* Zero gets no special alternate treatment */
1203 if (x == 0)
1204 flags &= ~FL_ALT;
1205
1206 if (x == 0 && (flags & FL_PREC) && prec == 0)
1207 buf_len = 0;
1208 else
1209 buf_len = __ultoa_invert (x, buf, base) - buf;
1210 }
1211
1212 len = buf_len;
1213
1214 /* Specified precision */
1215 if (flags & FL_PREC) {
1216
1217 /* Zfill ignored when precision specified */
1218 flags &= ~FL_ZFILL;
1219
1220 /* If the number is shorter than the precision, pad
1221 * on the left with zeros */
1222 if (len < prec) {
1223 len = prec;
1224
1225 /* Don't add the leading '0' for alternate octal mode */
1226 if (c == '\0')
1227 flags &= ~FL_ALT;
1228 }
1229 }
1230
1231 /* Alternate mode for octal/hex */
1232 if (flags & FL_ALT) {
1233
1234 len += 1;
1235 if (c != '\0')
1236 len += 1;
1237 } else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
1238 len += 1;
1239 }
1240
1241 /* Pad on the left ? */
1242 if (!(flags & FL_LPAD)) {
1243
1244 /* Pad with zeros, using the same loop as the
1245 * precision modifier
1246 */
1247 if (flags & FL_ZFILL) {
1248 prec = buf_len;
1249 if (len < width) {
1250 prec += width - len;
1251 len = width;
1252 }
1253 }
1254 while (len < width) {
1255 my_putc (' ', stream);
1256 len++;
1257 }
1258 }
1259
1260 /* Width remaining on right after value */
1261 width -= len;
1262
1263 /* Output leading characters */
1264 if (flags & FL_ALT) {
1265 my_putc ('0', stream);
1266 if (c != '\0')
1267 my_putc (c, stream);
1268 } else if (flags & (FL_NEGATIVE | FL_PLUS | FL_SPACE)) {
1269 unsigned char z = ' ';
1270 if (flags & FL_PLUS) z = '+';
1271 if (flags & FL_NEGATIVE) z = '-';
1272 my_putc (z, stream);
1273 }
1274
1275 /* Output leading zeros */
1276 while (prec > buf_len) {
1277 my_putc ('0', stream);
1278 prec--;
1279 }
1280
1281 /* Output value */
1282 while (buf_len)
1283 my_putc (buf[--buf_len], stream);
1284 }
1285 }
1286
1287 /* Tail is possible. */
1288 while (width-- > 0) {
1289 my_putc (' ', stream);
1290 }
1291 } /* for (;;) */
1292
1293 ret:
1294 #ifdef PRINTF_POSITIONAL
1295 va_end(ap);
1296 #endif
1297 return stream_len;
1298 #undef my_putc
1299 #undef ap
1300 fail:
1301 stream_len = -1;
1302 goto ret;
1303 }
1304
1305 #if defined(FORMAT_DEFAULT_DOUBLE) && !defined(vfprintf)
1306 #ifdef _HAVE_ALIAS_ATTRIBUTE
1307 __strong_reference(vfprintf, __d_vfprintf);
1308 #else
__d_vfprintf(FILE * stream,const char * fmt,va_list ap)1309 int __d_vfprintf (FILE * stream, const char *fmt, va_list ap) { return vfprintf(stream, fmt, ap); }
1310 #endif
1311 #endif
1312 #endif
1313