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