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