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