vfprintf.c revision 1.55 1 /* $NetBSD: vfprintf.c,v 1.55 2007/01/26 00:37:30 cbiere Exp $ */
2
3 /*-
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #if defined(LIBC_SCCS) && !defined(lint)
37 #if 0
38 static char *sccsid = "@(#)vfprintf.c 5.50 (Berkeley) 12/16/92";
39 #else
40 __RCSID("$NetBSD: vfprintf.c,v 1.55 2007/01/26 00:37:30 cbiere Exp $");
41 #endif
42 #endif /* LIBC_SCCS and not lint */
43
44 /*
45 * Actual printf innards.
46 *
47 * This code is large and complicated...
48 */
49
50 #include "namespace.h"
51 #include <sys/types.h>
52
53 #include <assert.h>
54 #include <errno.h>
55 #include <stdarg.h>
56 #include <stddef.h>
57 #include <stdint.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <wchar.h>
62 #include <limits.h>
63
64 #include "reentrant.h"
65 #include "local.h"
66 #include "fvwrite.h"
67 #include "extern.h"
68
69 static int __sprint __P((FILE *, struct __suio *));
70 static int __sbprintf __P((FILE *, const char *, va_list))
71 __attribute__((__format__(__printf__, 2, 0)));
72
73 /*
74 * Flush out all the vectors defined by the given uio,
75 * then reset it so that it can be reused.
76 */
77 /* NB: async-signal-safe when fp->_flags & __SAFE */
78 static int
79 __sprint(fp, uio)
80 FILE *fp;
81 struct __suio *uio;
82 {
83 int err;
84
85 _DIAGASSERT(fp != NULL);
86 _DIAGASSERT(uio != NULL);
87
88 if (uio->uio_resid == 0) {
89 uio->uio_iovcnt = 0;
90 return (0);
91 }
92 err = __sfvwrite(fp, uio);
93 uio->uio_resid = 0;
94 uio->uio_iovcnt = 0;
95 return (err);
96 }
97
98 /*
99 * Helper function for `fprintf to unbuffered unix file': creates a
100 * temporary buffer. We only work on write-only files; this avoids
101 * worries about ungetc buffers and so forth.
102 */
103 static int
104 __sbprintf(fp, fmt, ap)
105 FILE *fp;
106 const char *fmt;
107 va_list ap;
108 {
109 int ret;
110 FILE fake;
111 struct __sfileext fakeext;
112 unsigned char buf[BUFSIZ];
113
114 _DIAGASSERT(fp != NULL);
115 _DIAGASSERT(fmt != NULL);
116
117 _FILEEXT_SETUP(&fake, &fakeext);
118
119 /* copy the important variables */
120 fake._flags = fp->_flags & ~__SNBF;
121 fake._file = fp->_file;
122 fake._cookie = fp->_cookie;
123 fake._write = fp->_write;
124
125 /* set up the buffer */
126 fake._bf._base = fake._p = buf;
127 fake._bf._size = fake._w = sizeof(buf);
128 fake._lbfsize = 0; /* not actually used, but Just In Case */
129
130 /* do the work, then copy any error status */
131 ret = vfprintf(&fake, fmt, ap);
132 if (ret >= 0 && fflush(&fake))
133 ret = -1;
134 if (fake._flags & __SERR)
135 fp->_flags |= __SERR;
136 return (ret);
137 }
138
139
140 #ifndef NO_FLOATING_POINT
141 #include <locale.h>
142 #include <math.h>
143 #include "floatio.h"
144
145 #define BUF (MAXEXP+MAXFRACT+1) /* + decimal point */
146 #define DEFPREC 6
147
148 static char *cvt __P((double, int, int, char *, int *, int, int *));
149 static int exponent __P((char *, int, int));
150
151 #else /* FLOATING_POINT */
152
153 #define BUF 40
154
155 #endif /* NO_FLOATING_POINT */
156
157 /*
158 * Macros for converting digits to letters and vice versa
159 */
160 #define to_digit(c) ((c) - '0')
161 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
162 #define to_char(n) ((char)((n) + '0'))
163
164 /*
165 * Flags used during conversion.
166 */
167 #define ALT 0x001 /* alternate form */
168 #define HEXPREFIX 0x002 /* add 0x or 0X prefix */
169 #define LADJUST 0x004 /* left adjustment */
170 #define LONGDBL 0x008 /* long double; unimplemented */
171 #define LONGINT 0x010 /* long integer */
172 #define QUADINT 0x020 /* quad integer */
173 #define SHORTINT 0x040 /* short integer */
174 #define MAXINT 0x080 /* (unsigned) intmax_t */
175 #define PTRINT 0x100 /* (unsigned) ptrdiff_t */
176 #define SIZEINT 0x200 /* (signed) size_t */
177 #define ZEROPAD 0x400 /* zero (as opposed to blank) pad */
178 #define FPT 0x800 /* Floating point number */
179
180 static inline int
181 add_digit(int value, int d)
182 {
183 unsigned ret;
184
185 ret = value * 10U + d;
186 if (__predict_false(value > (INT_MAX - 9) / 10)) {
187 if (value > INT_MAX / 10 || ret > INT_MAX)
188 return -1;
189 }
190 return ret;
191 }
192
193 int
194 vfprintf(fp, fmt0, ap)
195 FILE *fp;
196 const char *fmt0;
197 _BSD_VA_LIST_ ap;
198 {
199 int ret;
200
201 FLOCKFILE(fp);
202 ret = __vfprintf_unlocked(fp, fmt0, ap);
203 FUNLOCKFILE(fp);
204
205 return ret;
206 }
207
208
209
210 /* NB: async-signal-safe when fp->_flags & __SAFE */
211 int
212 __vfprintf_unlocked(fp, fmt0, ap)
213 FILE *fp;
214 const char *fmt0;
215 _BSD_VA_LIST_ ap;
216 {
217 const char *fmt;/* format string */
218 int ch; /* character from fmt */
219 int n; /* handy integer (short term usage) */
220 const char *cp; /* handy char pointer (short term usage) */
221 char *bp; /* handy char pointer (short term usage) */
222 struct __siov *iovp;/* for PRINT macro */
223 int flags; /* flags as above */
224 int ret; /* return value accumulator */
225 int width; /* width from format (%8d), or 0 */
226 int prec; /* precision from format (%.3d), or -1 */
227 char sign; /* sign prefix (' ', '+', '-', or \0) */
228 wchar_t wc;
229 mbstate_t ps;
230 #ifndef NO_FLOATING_POINT
231 char *decimal_point = NULL;
232 char softsign; /* temporary negative sign for floats */
233 double _double; /* double precision arguments %[eEfgG] */
234 int expt; /* integer value of exponent */
235 int expsize = 0; /* character count for expstr */
236 int ndig; /* actual number of digits returned by cvt */
237 char expstr[7]; /* buffer for exponent string */
238 char *dtoaresult = NULL;
239 #endif
240
241 #ifdef __GNUC__ /* gcc has builtin quad type (long long) SOS */
242 #define quad_t long long
243 #define u_quad_t unsigned long long
244 #endif
245
246 #define INTMAX_T intmax_t
247 #define UINTMAX_T uintmax_t
248
249 UINTMAX_T _uintmax; /* integer arguments %[diouxX] */
250 enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
251 int dprec; /* a copy of prec if [diouxX], 0 otherwise */
252 int realsz; /* field size expanded by dprec */
253 int size; /* size of converted field or string */
254 const char *xdigs = NULL;/* digits for [xX] conversion */
255 #define NIOV 8
256 struct __suio uio; /* output information: summary */
257 struct __siov iov[NIOV];/* ... and individual io vectors */
258 char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
259 char ox[2]; /* space for 0x hex-prefix */
260
261 /*
262 * Choose PADSIZE to trade efficiency vs. size. If larger printf
263 * fields occur frequently, increase PADSIZE and make the initialisers
264 * below longer.
265 */
266 #define PADSIZE 16 /* pad chunk size */
267 static const char blanks[PADSIZE] =
268 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
269 static const char zeroes[PADSIZE] =
270 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
271
272 /*
273 * BEWARE, these `goto error' on error, and PAD uses `n'.
274 */
275 #define PRINT(ptr, len) { \
276 iovp->iov_base = __UNCONST(ptr); \
277 iovp->iov_len = (len); \
278 uio.uio_resid += (len); \
279 iovp++; \
280 if (++uio.uio_iovcnt >= NIOV) { \
281 if (__sprint(fp, &uio)) \
282 goto error; \
283 iovp = iov; \
284 } \
285 }
286 #define PAD(howmany, with) { \
287 if ((n = (howmany)) > 0) { \
288 while (n > PADSIZE) { \
289 PRINT(with, PADSIZE); \
290 n -= PADSIZE; \
291 } \
292 PRINT(with, n); \
293 } \
294 }
295 #define FLUSH() { \
296 if (uio.uio_resid && __sprint(fp, &uio)) \
297 goto error; \
298 uio.uio_iovcnt = 0; \
299 iovp = iov; \
300 }
301
302 /*
303 * To extend shorts properly, we need both signed and unsigned
304 * argument extraction methods.
305 */
306 #define SARG() \
307 (flags&MAXINT ? va_arg(ap, intmax_t) : \
308 flags&PTRINT ? va_arg(ap, ptrdiff_t) : \
309 flags&SIZEINT ? va_arg(ap, ssize_t) : /* XXX */ \
310 flags&QUADINT ? va_arg(ap, quad_t) : \
311 flags&LONGINT ? va_arg(ap, long) : \
312 flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
313 (long)va_arg(ap, int))
314 #define UARG() \
315 (flags&MAXINT ? va_arg(ap, uintmax_t) : \
316 flags&PTRINT ? va_arg(ap, uintptr_t) : /* XXX */ \
317 flags&SIZEINT ? va_arg(ap, size_t) : \
318 flags&QUADINT ? va_arg(ap, u_quad_t) : \
319 flags&LONGINT ? va_arg(ap, u_long) : \
320 flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
321 (u_long)va_arg(ap, u_int))
322
323 _DIAGASSERT(fp != NULL);
324 _DIAGASSERT(fmt0 != NULL);
325
326 _SET_ORIENTATION(fp, -1);
327
328 /* sorry, fprintf(read_only_file, "") returns -1, not 0 */
329 if (cantwrite(fp)) {
330 errno = EBADF;
331 return (-1);
332 }
333
334 /* optimise fprintf(stderr) (and other unbuffered Unix files) */
335 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
336 fp->_file >= 0) {
337 ret = __sbprintf(fp, fmt0, ap);
338 return (ret);
339 }
340
341 fmt = fmt0;
342 uio.uio_iov = iovp = iov;
343 uio.uio_resid = 0;
344 uio.uio_iovcnt = 0;
345 ret = 0;
346
347 memset(&ps, 0, sizeof(ps));
348
349 /*
350 * Scan the format for conversions (`%' character).
351 */
352 for (;;) {
353 cp = fmt;
354 if (fp->_flags & __SAFE) {
355 for (; *fmt && *fmt != '%'; fmt++)
356 continue;
357 n = *fmt == '%';
358 } else {
359 while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
360 fmt += n;
361 if (wc == '%') {
362 fmt--;
363 break;
364 }
365 }
366 }
367 if (fmt != cp) {
368 ptrdiff_t m = fmt - cp;
369 if (m < 0 || m > INT_MAX - ret)
370 goto overflow;
371 PRINT(cp, m);
372 ret += m;
373 }
374 if (n <= 0)
375 goto done;
376 fmt++; /* skip over '%' */
377
378 flags = 0;
379 dprec = 0;
380 width = 0;
381 prec = -1;
382 sign = '\0';
383
384 rflag: ch = *fmt++;
385 reswitch: switch (ch) {
386 case ' ':
387 /*
388 * ``If the space and + flags both appear, the space
389 * flag will be ignored.''
390 * -- ANSI X3J11
391 */
392 if (!sign)
393 sign = ' ';
394 goto rflag;
395 case '#':
396 flags |= ALT;
397 goto rflag;
398 case '*':
399 /*
400 * ``A negative field width argument is taken as a
401 * - flag followed by a positive field width.''
402 * -- ANSI X3J11
403 * They don't exclude field widths read from args.
404 */
405 if ((width = va_arg(ap, int)) >= 0)
406 goto rflag;
407 if (-(unsigned)width > INT_MAX)
408 goto overflow;
409 width = -width;
410 /* FALLTHROUGH */
411 case '-':
412 flags |= LADJUST;
413 goto rflag;
414 case '+':
415 sign = '+';
416 goto rflag;
417 case '.':
418 if ((ch = *fmt++) == '*') {
419 n = va_arg(ap, int);
420 prec = n < 0 ? -1 : n;
421 goto rflag;
422 }
423 prec = 0;
424 while (ch == '0')
425 ch = *fmt++;
426 while (is_digit(ch)) {
427 prec = add_digit(prec, to_digit(ch));
428 if (prec < 0)
429 goto overflow;
430 ch = *fmt++;
431 }
432 goto reswitch;
433 case '0':
434 /*
435 * ``Note that 0 is taken as a flag, not as the
436 * beginning of a field width.''
437 * -- ANSI X3J11
438 */
439 flags |= ZEROPAD;
440 goto rflag;
441 case '1': case '2': case '3': case '4':
442 case '5': case '6': case '7': case '8': case '9':
443 width = 0;
444 do {
445 width = add_digit(width, to_digit(ch));
446 if (width < 0)
447 goto overflow;
448 ch = *fmt++;
449 } while (is_digit(ch));
450 goto reswitch;
451 #ifndef NO_FLOATING_POINT
452 case 'L':
453 flags |= LONGDBL;
454 goto rflag;
455 #endif
456 case 'h':
457 flags |= SHORTINT;
458 goto rflag;
459 case 'j':
460 flags |= MAXINT;
461 goto rflag;
462 case 'l':
463 if (*fmt == 'l') {
464 fmt++;
465 flags |= QUADINT;
466 } else {
467 flags |= LONGINT;
468 }
469 goto rflag;
470 case 'q':
471 flags |= QUADINT;
472 goto rflag;
473 case 't':
474 flags |= PTRINT;
475 goto rflag;
476 case 'z':
477 flags |= SIZEINT;
478 goto rflag;
479 case 'c':
480 *buf = va_arg(ap, int);
481 cp = buf;
482 size = 1;
483 sign = '\0';
484 break;
485 case 'D':
486 flags |= LONGINT;
487 /*FALLTHROUGH*/
488 case 'd':
489 case 'i':
490 _uintmax = SARG();
491 if ((intmax_t)_uintmax < 0) {
492 _uintmax = -_uintmax;
493 sign = '-';
494 }
495 base = DEC;
496 goto number;
497 #ifndef NO_FLOATING_POINT
498 case 'e':
499 case 'E':
500 case 'f':
501 case 'F':
502 case 'g':
503 case 'G':
504 if (prec == -1) {
505 prec = DEFPREC;
506 } else if ((ch == 'g' || ch == 'G') && prec == 0) {
507 prec = 1;
508 }
509
510 if (flags & LONGDBL) {
511 _double = (double) va_arg(ap, long double);
512 } else {
513 _double = va_arg(ap, double);
514 }
515
516 /* do this before tricky precision changes */
517 if (isinf(_double)) {
518 if (_double < 0)
519 sign = '-';
520 if (ch == 'E' || ch == 'F' || ch == 'G')
521 cp = "INF";
522 else
523 cp = "inf";
524 size = 3;
525 break;
526 }
527 if (isnan(_double)) {
528 if (ch == 'E' || ch == 'F' || ch == 'G')
529 cp = "NAN";
530 else
531 cp = "nan";
532 size = 3;
533 break;
534 }
535 if (fp->_flags & __SAFE) {
536 if (ch == 'E' || ch == 'F' || ch == 'G')
537 cp = "UNK";
538 else
539 cp = "unk";
540 size = 3;
541 break;
542 }
543
544 flags |= FPT;
545 if (dtoaresult)
546 __freedtoa(dtoaresult);
547 cp = dtoaresult = cvt(_double, prec, flags, &softsign,
548 &expt, ch, &ndig);
549 if (ch == 'g' || ch == 'G') {
550 if (expt <= -4 || expt > prec)
551 ch = (ch == 'g') ? 'e' : 'E';
552 else
553 ch = 'g';
554 }
555 if (ch == 'e' || ch == 'E') {
556 --expt;
557 expsize = exponent(expstr, expt, ch);
558 size = expsize + ndig;
559 if (ndig > 1 || flags & ALT)
560 ++size;
561 } else if (ch == 'f' || ch == 'F') {
562 if (expt > 0) {
563 size = expt;
564 if (prec || flags & ALT)
565 size += prec + 1;
566 } else /* "0.X" */
567 size = prec + 2;
568 } else if (expt >= ndig) { /* fixed g fmt */
569 size = expt;
570 if (flags & ALT)
571 ++size;
572 } else
573 size = ndig + (expt > 0 ?
574 1 : 2 - expt);
575
576 if (softsign)
577 sign = '-';
578 break;
579 #endif /* NO_FLOATING_POINT */
580 case 'n':
581 if (flags & MAXINT)
582 *va_arg(ap, intmax_t *) = ret;
583 else if (flags & PTRINT)
584 *va_arg(ap, ptrdiff_t *) = ret;
585 else if (flags & SIZEINT)
586 *va_arg(ap, ssize_t *) = ret; /* XXX */
587 else if (flags & QUADINT)
588 *va_arg(ap, quad_t *) = ret;
589 else if (flags & LONGINT)
590 *va_arg(ap, long *) = ret;
591 else if (flags & SHORTINT)
592 *va_arg(ap, short *) = ret;
593 else
594 *va_arg(ap, int *) = ret;
595 continue; /* no output */
596 case 'O':
597 flags |= LONGINT;
598 /*FALLTHROUGH*/
599 case 'o':
600 _uintmax = UARG();
601 base = OCT;
602 goto nosign;
603 case 'p':
604 /*
605 * ``The argument shall be a pointer to void. The
606 * value of the pointer is converted to a sequence
607 * of printable characters, in an implementation-
608 * defined manner.''
609 * -- ANSI X3J11
610 */
611 /* NOSTRICT */
612 _uintmax = (u_long)va_arg(ap, void *);
613 base = HEX;
614 xdigs = "0123456789abcdef";
615 flags |= HEXPREFIX;
616 ch = 'x';
617 goto nosign;
618 case 's':
619 if ((cp = va_arg(ap, char *)) == NULL)
620 cp = "(null)";
621 if (prec >= 0) {
622 /*
623 * can't use strlen; can only look for the
624 * NUL in the first `prec' characters, and
625 * strlen() will go further.
626 */
627 for (n = 0; n < prec && cp[n]; n++)
628 continue;
629 size = n;
630 } else {
631 size_t len = strlen(cp);
632
633 if (len > INT_MAX)
634 goto overflow;
635 size = len;
636 }
637 sign = '\0';
638 break;
639 case 'U':
640 flags |= LONGINT;
641 /*FALLTHROUGH*/
642 case 'u':
643 _uintmax = UARG();
644 base = DEC;
645 goto nosign;
646 case 'X':
647 xdigs = "0123456789ABCDEF";
648 goto hex;
649 case 'x':
650 xdigs = "0123456789abcdef";
651 hex: _uintmax = UARG();
652 base = HEX;
653 /* leading 0x/X only if non-zero */
654 if (flags & ALT && _uintmax != 0)
655 flags |= HEXPREFIX;
656
657 /* unsigned conversions */
658 nosign: sign = '\0';
659 /*
660 * ``... diouXx conversions ... if a precision is
661 * specified, the 0 flag will be ignored.''
662 * -- ANSI X3J11
663 */
664 number: if ((dprec = prec) >= 0)
665 flags &= ~ZEROPAD;
666
667 /*
668 * ``The result of converting a zero value with an
669 * explicit precision of zero is no characters.''
670 * -- ANSI X3J11
671 */
672 bp = buf + BUF;
673 if (_uintmax != 0 || prec != 0) {
674 /*
675 * Unsigned mod is hard, and unsigned mod
676 * by a constant is easier than that by
677 * a variable; hence this switch.
678 */
679 switch (base) {
680 case OCT:
681 do {
682 *--bp = to_char(_uintmax & 7);
683 _uintmax >>= 3;
684 } while (_uintmax);
685 /* handle octal leading 0 */
686 if (flags & ALT && *bp != '0')
687 *--bp = '0';
688 break;
689
690 case DEC:
691 /* many numbers are 1 digit */
692 while (_uintmax >= 10) {
693 *--bp = to_char(_uintmax % 10);
694 _uintmax /= 10;
695 }
696 *--bp = to_char(_uintmax);
697 break;
698
699 case HEX:
700 do {
701 *--bp = xdigs[(size_t)
702 (_uintmax & 15)];
703 _uintmax >>= 4;
704 } while (_uintmax);
705 break;
706
707 default:
708 cp = "bug in vfprintf: bad base";
709 size = strlen(cp);
710 goto skipsize;
711 }
712 }
713 cp = bp;
714 size = buf + BUF - bp;
715 skipsize:
716 break;
717 default: /* "%?" prints ?, unless ? is NUL */
718 if (ch == '\0')
719 goto done;
720 /* pretend it was %c with argument ch */
721 *buf = ch;
722 cp = buf;
723 size = 1;
724 sign = '\0';
725 break;
726 }
727
728 /*
729 * All reasonable formats wind up here. At this point, `cp'
730 * points to a string which (if not flags&LADJUST) should be
731 * padded out to `width' places. If flags&ZEROPAD, it should
732 * first be prefixed by any sign or other prefix; otherwise,
733 * it should be blank padded before the prefix is emitted.
734 * After any left-hand padding and prefixing, emit zeroes
735 * required by a decimal [diouxX] precision, then print the
736 * string proper, then emit zeroes required by any leftover
737 * floating precision; finally, if LADJUST, pad with blanks.
738 *
739 * Compute actual size, so we know how much to pad.
740 * size excludes decimal prec; realsz includes it.
741 */
742 realsz = dprec > size ? dprec : size;
743 if (sign)
744 realsz++;
745 else if (flags & HEXPREFIX)
746 realsz+= 2;
747
748 /* right-adjusting blank padding */
749 if ((flags & (LADJUST|ZEROPAD)) == 0)
750 PAD(width - realsz, blanks);
751
752 /* prefix */
753 if (sign) {
754 PRINT(&sign, 1);
755 } else if (flags & HEXPREFIX) {
756 ox[0] = '0';
757 ox[1] = ch;
758 PRINT(ox, 2);
759 }
760
761 /* right-adjusting zero padding */
762 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
763 PAD(width - realsz, zeroes);
764
765 /* leading zeroes from decimal precision */
766 PAD(dprec - size, zeroes);
767
768 /* the string or number proper */
769 #ifndef NO_FLOATING_POINT
770 if ((flags & FPT) == 0) {
771 PRINT(cp, size);
772 } else { /* glue together f_p fragments */
773 if (ch >= 'f') { /* 'f' or 'g' */
774 if (decimal_point == NULL)
775 decimal_point =
776 localeconv()->decimal_point;
777 if (_double == 0) {
778 /* kludge for __dtoa irregularity */
779 PRINT("0", 1);
780 if (expt < ndig || (flags & ALT) != 0) {
781 PRINT(decimal_point, 1);
782 PAD(ndig - 1, zeroes);
783 }
784 } else if (expt <= 0) {
785 PRINT("0", 1);
786 PRINT(decimal_point, 1);
787 PAD(-expt, zeroes);
788 PRINT(cp, ndig);
789 } else if (expt >= ndig) {
790 PRINT(cp, ndig);
791 PAD(expt - ndig, zeroes);
792 if (flags & ALT)
793 PRINT(".", 1);
794 } else {
795 PRINT(cp, expt);
796 cp += expt;
797 PRINT(".", 1);
798 PRINT(cp, ndig-expt);
799 }
800 } else { /* 'e' or 'E' */
801 if (ndig > 1 || flags & ALT) {
802 ox[0] = *cp++;
803 ox[1] = '.';
804 PRINT(ox, 2);
805 if (_double) {
806 PRINT(cp, ndig-1);
807 } else /* 0.[0..] */
808 /* __dtoa irregularity */
809 PAD(ndig - 1, zeroes);
810 } else /* XeYYY */
811 PRINT(cp, 1);
812 PRINT(expstr, expsize);
813 }
814 }
815 #else
816 PRINT(cp, size);
817 #endif
818 /* left-adjusting padding (always blank) */
819 if (flags & LADJUST)
820 PAD(width - realsz, blanks);
821
822 /* finally, adjust ret */
823 n = width > realsz ? width : realsz;
824 if (n > INT_MAX - ret)
825 goto overflow;
826 ret += n;
827
828 FLUSH(); /* copy out the I/O vectors */
829 }
830 done:
831 FLUSH();
832 error:
833 if (__sferror(fp))
834 ret = -1;
835 goto finish;
836
837 overflow:
838 errno = EOVERFLOW;
839 ret = -1;
840
841 finish:
842 #ifndef NO_FLOATING_POINT
843 if (dtoaresult)
844 __freedtoa(dtoaresult);
845 #endif
846 return (ret);
847 }
848
849 #ifndef NO_FLOATING_POINT
850
851 static char *
852 cvt(value, ndigits, flags, sign, decpt, ch, length)
853 double value;
854 int ndigits, flags, *decpt, ch, *length;
855 char *sign;
856 {
857 int mode, dsgn;
858 char *digits, *bp, *rve;
859
860 _DIAGASSERT(decpt != NULL);
861 _DIAGASSERT(length != NULL);
862 _DIAGASSERT(sign != NULL);
863
864 if (ch == 'f') {
865 mode = 3; /* ndigits after the decimal point */
866 } else {
867 /* To obtain ndigits after the decimal point for the 'e'
868 * and 'E' formats, round to ndigits + 1 significant
869 * figures.
870 */
871 if (ch == 'e' || ch == 'E') {
872 ndigits++;
873 }
874 mode = 2; /* ndigits significant digits */
875 }
876
877 digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
878 if (dsgn) {
879 value = -value;
880 *sign = '-';
881 } else
882 *sign = '\000';
883 if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */
884 bp = digits + ndigits;
885 if (ch == 'f') {
886 if (*digits == '0' && value)
887 *decpt = -ndigits + 1;
888 bp += *decpt;
889 }
890 if (value == 0) /* kludge for __dtoa irregularity */
891 rve = bp;
892 while (rve < bp)
893 *rve++ = '0';
894 }
895 *length = rve - digits;
896 return (digits);
897 }
898
899 static int
900 exponent(p0, expon, fmtch)
901 char *p0;
902 int expon, fmtch;
903 {
904 char *p, *t;
905 char expbuf[MAXEXP];
906
907 _DIAGASSERT(p0 != NULL);
908
909 p = p0;
910 *p++ = fmtch;
911 if (expon < 0) {
912 expon = -expon;
913 *p++ = '-';
914 }
915 else
916 *p++ = '+';
917 t = expbuf + MAXEXP;
918 if (expon > 9) {
919 do {
920 *--t = to_char(expon % 10);
921 } while ((expon /= 10) > 9);
922 *--t = to_char(expon);
923 for (; t < expbuf + MAXEXP; *p++ = *t++);
924 }
925 else {
926 *p++ = '0';
927 *p++ = to_char(expon);
928 }
929 return (p - p0);
930 }
931 #endif /* NO_FLOATING_POINT */
932