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