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