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