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