xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 57154)
146076Sbostic /*-
246076Sbostic  * Copyright (c) 1990 The Regents of the University of California.
334233Sbostic  * All rights reserved.
434226Sbostic  *
546076Sbostic  * This code is derived from software contributed to Berkeley by
646076Sbostic  * Chris Torek.
746076Sbostic  *
842631Sbostic  * %sccs.include.redist.c%
934226Sbostic  */
1034226Sbostic 
1134233Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*57154Sbostic static char sccsid[] = "@(#)vfprintf.c	5.50 (Berkeley) 12/16/92";
1334233Sbostic #endif /* LIBC_SCCS and not lint */
1434233Sbostic 
1546076Sbostic /*
1646076Sbostic  * Actual printf innards.
1746076Sbostic  *
1846076Sbostic  * This code is large and complicated...
1946076Sbostic  */
2046076Sbostic 
2134261Sbostic #include <sys/types.h>
22*57154Sbostic 
2346076Sbostic #include <stdio.h>
24*57154Sbostic #include <stdlib.h>
2546076Sbostic #include <string.h>
26*57154Sbostic 
2746076Sbostic #if __STDC__
2846076Sbostic #include <stdarg.h>
2946076Sbostic #else
3034233Sbostic #include <varargs.h>
3146076Sbostic #endif
32*57154Sbostic 
3346076Sbostic #include "local.h"
3446076Sbostic #include "fvwrite.h"
3534226Sbostic 
3650438Sbostic /* Define FLOATING_POINT to get floating point. */
3746076Sbostic #define	FLOATING_POINT
3834226Sbostic 
3946076Sbostic /*
4046076Sbostic  * Flush out all the vectors defined by the given uio,
4146076Sbostic  * then reset it so that it can be reused.
4246076Sbostic  */
4346180Storek static int
4446076Sbostic __sprint(fp, uio)
4546076Sbostic 	FILE *fp;
4646076Sbostic 	register struct __suio *uio;
4746076Sbostic {
4846076Sbostic 	register int err;
4946076Sbostic 
5046076Sbostic 	if (uio->uio_resid == 0) {
5146076Sbostic 		uio->uio_iovcnt = 0;
5246076Sbostic 		return (0);
5346076Sbostic 	}
5446076Sbostic 	err = __sfvwrite(fp, uio);
5546076Sbostic 	uio->uio_resid = 0;
5646076Sbostic 	uio->uio_iovcnt = 0;
5746076Sbostic 	return (err);
5846076Sbostic }
5946076Sbostic 
6046076Sbostic /*
6146076Sbostic  * Helper function for `fprintf to unbuffered unix file': creates a
6246076Sbostic  * temporary buffer.  We only work on write-only files; this avoids
6346076Sbostic  * worries about ungetc buffers and so forth.
6446076Sbostic  */
6546180Storek static int
6646076Sbostic __sbprintf(fp, fmt, ap)
6746076Sbostic 	register FILE *fp;
6846180Storek 	const char *fmt;
6946076Sbostic 	va_list ap;
7046076Sbostic {
7146076Sbostic 	int ret;
7246076Sbostic 	FILE fake;
7346076Sbostic 	unsigned char buf[BUFSIZ];
7446076Sbostic 
7546076Sbostic 	/* copy the important variables */
7646076Sbostic 	fake._flags = fp->_flags & ~__SNBF;
7746076Sbostic 	fake._file = fp->_file;
7846076Sbostic 	fake._cookie = fp->_cookie;
7946076Sbostic 	fake._write = fp->_write;
8046076Sbostic 
8146076Sbostic 	/* set up the buffer */
8246076Sbostic 	fake._bf._base = fake._p = buf;
8346076Sbostic 	fake._bf._size = fake._w = sizeof(buf);
8446076Sbostic 	fake._lbfsize = 0;	/* not actually used, but Just In Case */
8546076Sbostic 
8646076Sbostic 	/* do the work, then copy any error status */
8746076Sbostic 	ret = vfprintf(&fake, fmt, ap);
8846076Sbostic 	if (ret >= 0 && fflush(&fake))
8946076Sbostic 		ret = EOF;
9046076Sbostic 	if (fake._flags & __SERR)
9146076Sbostic 		fp->_flags |= __SERR;
9246076Sbostic 	return (ret);
9346076Sbostic }
9446076Sbostic 
9546076Sbostic 
9646076Sbostic #ifdef FLOATING_POINT
97*57154Sbostic #include <math.h>
9846180Storek #include "floatio.h"
9946076Sbostic 
10034328Sbostic #define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
10146076Sbostic #define	DEFPREC		6
10234328Sbostic 
103*57154Sbostic static char *cvt __P((double, int, int, char *, int *, int, int *));
104*57154Sbostic static int exponent __P((char *, int, int));
10534236Sbostic 
10646076Sbostic #else /* no FLOATING_POINT */
10734235Sbostic 
10846076Sbostic #define	BUF		40
10934331Sbostic 
11046076Sbostic #endif /* FLOATING_POINT */
11134318Sbostic 
11246076Sbostic 
11346076Sbostic /*
11446076Sbostic  * Macros for converting digits to letters and vice versa
11546076Sbostic  */
11646076Sbostic #define	to_digit(c)	((c) - '0')
11746076Sbostic #define is_digit(c)	((unsigned)to_digit(c) <= 9)
11846076Sbostic #define	to_char(n)	((n) + '0')
11946076Sbostic 
12046076Sbostic /*
12146076Sbostic  * Flags used during conversion.
12246076Sbostic  */
12353810Sbostic #define	ALT		0x001		/* alternate form */
12453810Sbostic #define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
12553810Sbostic #define	LADJUST		0x004		/* left adjustment */
12653810Sbostic #define	LONGDBL		0x008		/* long double; unimplemented */
12753810Sbostic #define	LONGINT		0x010		/* long integer */
12853810Sbostic #define	QUADINT		0x020		/* quad integer */
12953810Sbostic #define	SHORTINT	0x040		/* short integer */
13053810Sbostic #define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
131*57154Sbostic #define FPT		0x100		/* Floating point number */
13246180Storek int
13346076Sbostic vfprintf(fp, fmt0, ap)
13446076Sbostic 	FILE *fp;
13546180Storek 	const char *fmt0;
13646076Sbostic 	va_list ap;
13734226Sbostic {
13846076Sbostic 	register char *fmt;	/* format string */
13934427Sbostic 	register int ch;	/* character from fmt */
14046076Sbostic 	register int n;		/* handy integer (short term usage) */
14146076Sbostic 	register char *cp;	/* handy char pointer (short term usage) */
14246076Sbostic 	register struct __siov *iovp;/* for PRINT macro */
14346076Sbostic 	register int flags;	/* flags as above */
14446076Sbostic 	int ret;		/* return value accumulator */
14546076Sbostic 	int width;		/* width from format (%8d), or 0 */
14646076Sbostic 	int prec;		/* precision from format (%.3d), or -1 */
14746076Sbostic 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
14846076Sbostic #ifdef FLOATING_POINT
14946076Sbostic 	char softsign;		/* temporary negative sign for floats */
15034427Sbostic 	double _double;		/* double precision arguments %[eEfgG] */
151*57154Sbostic 	int expt;		/* integer value of exponent */
152*57154Sbostic 	int expsize;		/* character count for expstr */
153*57154Sbostic 	int ndig;		/* actual number of digits returned by cvt */
154*57154Sbostic 	char expstr[7];		/* buffer for exponent string */
15546076Sbostic #endif
15653810Sbostic 	u_quad_t _uquad;	/* integer arguments %[diouxX] */
15746076Sbostic 	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
15846076Sbostic 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
15934624Sbostic 	int fieldsz;		/* field size expanded by sign, etc */
16046076Sbostic 	int realsz;		/* field size expanded by dprec */
16134427Sbostic 	int size;		/* size of converted field or string */
16246076Sbostic 	char *xdigs;		/* digits for [xX] conversion */
16346076Sbostic #define NIOV 8
16446076Sbostic 	struct __suio uio;	/* output information: summary */
16546076Sbostic 	struct __siov iov[NIOV];/* ... and individual io vectors */
16634427Sbostic 	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
16746076Sbostic 	char ox[2];		/* space for 0x hex-prefix */
16834226Sbostic 
16946076Sbostic 	/*
17053810Sbostic 	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
17153810Sbostic 	 * fields occur frequently, increase PADSIZE and make the initialisers
17253810Sbostic 	 * below longer.
17346076Sbostic 	 */
17446076Sbostic #define	PADSIZE	16		/* pad chunk size */
17546076Sbostic 	static char blanks[PADSIZE] =
17646076Sbostic 	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
17746076Sbostic 	static char zeroes[PADSIZE] =
17846076Sbostic 	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
17946076Sbostic 
18046076Sbostic 	/*
18146076Sbostic 	 * BEWARE, these `goto error' on error, and PAD uses `n'.
18246076Sbostic 	 */
18346076Sbostic #define	PRINT(ptr, len) { \
18446076Sbostic 	iovp->iov_base = (ptr); \
18546076Sbostic 	iovp->iov_len = (len); \
18646076Sbostic 	uio.uio_resid += (len); \
18746076Sbostic 	iovp++; \
18846076Sbostic 	if (++uio.uio_iovcnt >= NIOV) { \
18946076Sbostic 		if (__sprint(fp, &uio)) \
19046076Sbostic 			goto error; \
19146076Sbostic 		iovp = iov; \
19246076Sbostic 	} \
19346076Sbostic }
19446076Sbostic #define	PAD(howmany, with) { \
19546076Sbostic 	if ((n = (howmany)) > 0) { \
19646076Sbostic 		while (n > PADSIZE) { \
19746076Sbostic 			PRINT(with, PADSIZE); \
19846076Sbostic 			n -= PADSIZE; \
19946076Sbostic 		} \
20046076Sbostic 		PRINT(with, n); \
20146076Sbostic 	} \
20246076Sbostic }
20346076Sbostic #define	FLUSH() { \
20446076Sbostic 	if (uio.uio_resid && __sprint(fp, &uio)) \
20546076Sbostic 		goto error; \
20646076Sbostic 	uio.uio_iovcnt = 0; \
20746076Sbostic 	iovp = iov; \
20846076Sbostic }
20946076Sbostic 
21046076Sbostic 	/*
21146076Sbostic 	 * To extend shorts properly, we need both signed and unsigned
21246076Sbostic 	 * argument extraction methods.
21346076Sbostic 	 */
21446076Sbostic #define	SARG() \
21553810Sbostic 	(flags&QUADINT ? va_arg(ap, quad_t) : \
21653810Sbostic 	    flags&LONGINT ? va_arg(ap, long) : \
21746076Sbostic 	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
21846076Sbostic 	    (long)va_arg(ap, int))
21946076Sbostic #define	UARG() \
22053810Sbostic 	(flags&QUADINT ? va_arg(ap, u_quad_t) : \
22153810Sbostic 	    flags&LONGINT ? va_arg(ap, u_long) : \
22246076Sbostic 	    flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
22346076Sbostic 	    (u_long)va_arg(ap, u_int))
22446076Sbostic 
22546076Sbostic 	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
22646076Sbostic 	if (cantwrite(fp))
22734428Sbostic 		return (EOF);
22834428Sbostic 
22946076Sbostic 	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
23046076Sbostic 	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
23146076Sbostic 	    fp->_file >= 0)
23246076Sbostic 		return (__sbprintf(fp, fmt0, ap));
23346076Sbostic 
23446076Sbostic 	fmt = (char *)fmt0;
23546076Sbostic 	uio.uio_iov = iovp = iov;
23646076Sbostic 	uio.uio_resid = 0;
23746076Sbostic 	uio.uio_iovcnt = 0;
23846076Sbostic 	ret = 0;
23946076Sbostic 
24046076Sbostic 	/*
24146076Sbostic 	 * Scan the format for conversions (`%' character).
24246076Sbostic 	 */
24346076Sbostic 	for (;;) {
24446076Sbostic 		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
24546076Sbostic 			/* void */;
24646076Sbostic 		if ((n = fmt - cp) != 0) {
24746076Sbostic 			PRINT(cp, n);
24846076Sbostic 			ret += n;
24946076Sbostic 		}
25046076Sbostic 		if (ch == '\0')
25146076Sbostic 			goto done;
25246076Sbostic 		fmt++;		/* skip over '%' */
25346076Sbostic 
25446076Sbostic 		flags = 0;
25546076Sbostic 		dprec = 0;
25646076Sbostic 		width = 0;
25734233Sbostic 		prec = -1;
25834318Sbostic 		sign = '\0';
25934226Sbostic 
26046076Sbostic rflag:		ch = *fmt++;
26146076Sbostic reswitch:	switch (ch) {
26234318Sbostic 		case ' ':
26334669Sbostic 			/*
26434669Sbostic 			 * ``If the space and + flags both appear, the space
26534669Sbostic 			 * flag will be ignored.''
26634669Sbostic 			 *	-- ANSI X3J11
26734669Sbostic 			 */
26834669Sbostic 			if (!sign)
26934669Sbostic 				sign = ' ';
27034318Sbostic 			goto rflag;
27134233Sbostic 		case '#':
27234318Sbostic 			flags |= ALT;
27334318Sbostic 			goto rflag;
27434233Sbostic 		case '*':
27534235Sbostic 			/*
27634235Sbostic 			 * ``A negative field width argument is taken as a
27746076Sbostic 			 * - flag followed by a positive field width.''
27834235Sbostic 			 *	-- ANSI X3J11
27934235Sbostic 			 * They don't exclude field widths read from args.
28034235Sbostic 			 */
28146076Sbostic 			if ((width = va_arg(ap, int)) >= 0)
28234318Sbostic 				goto rflag;
28334235Sbostic 			width = -width;
28434427Sbostic 			/* FALLTHROUGH */
28534235Sbostic 		case '-':
28634318Sbostic 			flags |= LADJUST;
28734318Sbostic 			goto rflag;
28834233Sbostic 		case '+':
28934314Sbostic 			sign = '+';
29034318Sbostic 			goto rflag;
29134233Sbostic 		case '.':
29246076Sbostic 			if ((ch = *fmt++) == '*') {
29346076Sbostic 				n = va_arg(ap, int);
29446076Sbostic 				prec = n < 0 ? -1 : n;
29546076Sbostic 				goto rflag;
29634226Sbostic 			}
29746076Sbostic 			n = 0;
29846076Sbostic 			while (is_digit(ch)) {
29946076Sbostic 				n = 10 * n + to_digit(ch);
30046076Sbostic 				ch = *fmt++;
30146076Sbostic 			}
30234318Sbostic 			prec = n < 0 ? -1 : n;
30346076Sbostic 			goto reswitch;
30434233Sbostic 		case '0':
30534427Sbostic 			/*
30634427Sbostic 			 * ``Note that 0 is taken as a flag, not as the
30734427Sbostic 			 * beginning of a field width.''
30834427Sbostic 			 *	-- ANSI X3J11
30934427Sbostic 			 */
31034427Sbostic 			flags |= ZEROPAD;
31134427Sbostic 			goto rflag;
31234233Sbostic 		case '1': case '2': case '3': case '4':
31334233Sbostic 		case '5': case '6': case '7': case '8': case '9':
31434318Sbostic 			n = 0;
31534233Sbostic 			do {
31646076Sbostic 				n = 10 * n + to_digit(ch);
31746076Sbostic 				ch = *fmt++;
31846076Sbostic 			} while (is_digit(ch));
31934318Sbostic 			width = n;
32046076Sbostic 			goto reswitch;
32146076Sbostic #ifdef FLOATING_POINT
32234235Sbostic 		case 'L':
32334329Sbostic 			flags |= LONGDBL;
32434318Sbostic 			goto rflag;
32546076Sbostic #endif
32634235Sbostic 		case 'h':
32734318Sbostic 			flags |= SHORTINT;
32834318Sbostic 			goto rflag;
32934233Sbostic 		case 'l':
33034318Sbostic 			flags |= LONGINT;
33134318Sbostic 			goto rflag;
33253810Sbostic 		case 'q':
33353810Sbostic 			flags |= QUADINT;
33453810Sbostic 			goto rflag;
33534314Sbostic 		case 'c':
33646076Sbostic 			*(cp = buf) = va_arg(ap, int);
33734314Sbostic 			size = 1;
33834427Sbostic 			sign = '\0';
33946076Sbostic 			break;
34034624Sbostic 		case 'D':
34134624Sbostic 			flags |= LONGINT;
34234624Sbostic 			/*FALLTHROUGH*/
34334314Sbostic 		case 'd':
34434318Sbostic 		case 'i':
34553810Sbostic 			_uquad = SARG();
34653810Sbostic 			if ((quad_t)_uquad < 0) {
34753810Sbostic 				_uquad = -_uquad;
34834314Sbostic 				sign = '-';
34934241Sbostic 			}
35046076Sbostic 			base = DEC;
35134327Sbostic 			goto number;
35246076Sbostic #ifdef FLOATING_POINT
353*57154Sbostic 		case 'e':		/* anomalous precision */
35434236Sbostic 		case 'E':
355*57154Sbostic 			prec = (prec == -1) ?
356*57154Sbostic 				DEFPREC + 1 : prec + 1;
357*57154Sbostic 			/* FALLTHROUGH */
358*57154Sbostic 			goto fp_begin;
359*57154Sbostic 		case 'f':		/* always print trailing zeroes */
360*57154Sbostic 			if (prec != 0)
361*57154Sbostic 				flags |= ALT;
36234261Sbostic 		case 'g':
36334243Sbostic 		case 'G':
364*57154Sbostic 			if (prec == -1)
365*57154Sbostic 				prec = DEFPREC;
366*57154Sbostic fp_begin:		_double = va_arg(ap, double);
36746126Storek 			/* do this before tricky precision changes */
36847607Sbostic 			if (isinf(_double)) {
36947607Sbostic 				if (_double < 0)
37047607Sbostic 					sign = '-';
37147607Sbostic 				cp = "Inf";
37247607Sbostic 				size = 3;
37346126Storek 				break;
37446126Storek 			}
37547607Sbostic 			if (isnan(_double)) {
37647607Sbostic 				cp = "NaN";
37747607Sbostic 				size = 3;
37847607Sbostic 				break;
37947607Sbostic 			}
380*57154Sbostic 			flags |= FPT;
381*57154Sbostic 			cp = cvt(_double, prec, flags, &softsign,
382*57154Sbostic 				&expt, ch, &ndig);
383*57154Sbostic 			if (ch == 'g' || ch == 'G') {
384*57154Sbostic 				if (expt <= -4 || expt > prec)
385*57154Sbostic 					ch = (ch == 'g') ? 'e' : 'E';
386*57154Sbostic 				else
387*57154Sbostic 					ch = 'g';
388*57154Sbostic 			}
389*57154Sbostic 			if (ch <= 'e') {	/* 'e' or 'E' fmt */
390*57154Sbostic 				--expt;
391*57154Sbostic 				expsize = exponent(expstr, expt, ch);
392*57154Sbostic 				size = expsize + ndig;
393*57154Sbostic 				if (ndig > 1 || flags & ALT)
394*57154Sbostic 					++size;
395*57154Sbostic 			} else if (ch == 'f') {		/* f fmt */
396*57154Sbostic 				if (expt > 0) {
397*57154Sbostic 					size = expt;
398*57154Sbostic 					if (prec || flags & ALT)
399*57154Sbostic 						size += prec + 1;
400*57154Sbostic 				} else	/* "0.X" */
401*57154Sbostic 					size = prec + 2;
402*57154Sbostic 			} else if (expt >= ndig) {	/* fixed g fmt */
403*57154Sbostic 				size = expt;
404*57154Sbostic 				if (flags & ALT)
405*57154Sbostic 					++size;
406*57154Sbostic 			} else
407*57154Sbostic 				size = ndig + (expt > 0 ?
408*57154Sbostic 					1 : 2 - expt);
409*57154Sbostic 
41034669Sbostic 			if (softsign)
41134669Sbostic 				sign = '-';
41246076Sbostic 			break;
41346076Sbostic #endif /* FLOATING_POINT */
41434235Sbostic 		case 'n':
41553810Sbostic 			if (flags & QUADINT)
41653810Sbostic 				*va_arg(ap, quad_t *) = ret;
41753810Sbostic 			else if (flags & LONGINT)
41846076Sbostic 				*va_arg(ap, long *) = ret;
41934427Sbostic 			else if (flags & SHORTINT)
42046076Sbostic 				*va_arg(ap, short *) = ret;
42134318Sbostic 			else
42246076Sbostic 				*va_arg(ap, int *) = ret;
42346076Sbostic 			continue;	/* no output */
42434624Sbostic 		case 'O':
42534624Sbostic 			flags |= LONGINT;
42634624Sbostic 			/*FALLTHROUGH*/
42734226Sbostic 		case 'o':
42853810Sbostic 			_uquad = UARG();
42946076Sbostic 			base = OCT;
43034327Sbostic 			goto nosign;
43134235Sbostic 		case 'p':
43234320Sbostic 			/*
43334321Sbostic 			 * ``The argument shall be a pointer to void.  The
43434321Sbostic 			 * value of the pointer is converted to a sequence
43534321Sbostic 			 * of printable characters, in an implementation-
43634321Sbostic 			 * defined manner.''
43734321Sbostic 			 *	-- ANSI X3J11
43834320Sbostic 			 */
43934427Sbostic 			/* NOSTRICT */
44053810Sbostic 			_uquad = (u_quad_t)va_arg(ap, void *);
44146076Sbostic 			base = HEX;
44246076Sbostic 			xdigs = "0123456789abcdef";
44346076Sbostic 			flags |= HEXPREFIX;
44446076Sbostic 			ch = 'x';
44534327Sbostic 			goto nosign;
44634226Sbostic 		case 's':
44746076Sbostic 			if ((cp = va_arg(ap, char *)) == NULL)
44846076Sbostic 				cp = "(null)";
44934321Sbostic 			if (prec >= 0) {
45034321Sbostic 				/*
45134321Sbostic 				 * can't use strlen; can only look for the
45234321Sbostic 				 * NUL in the first `prec' characters, and
45334321Sbostic 				 * strlen() will go further.
45434321Sbostic 				 */
45546076Sbostic 				char *p = memchr(cp, 0, prec);
45634321Sbostic 
45746076Sbostic 				if (p != NULL) {
45846076Sbostic 					size = p - cp;
45934321Sbostic 					if (size > prec)
46034321Sbostic 						size = prec;
46134427Sbostic 				} else
46234321Sbostic 					size = prec;
46334427Sbostic 			} else
46446076Sbostic 				size = strlen(cp);
46534427Sbostic 			sign = '\0';
46646076Sbostic 			break;
46734624Sbostic 		case 'U':
46834624Sbostic 			flags |= LONGINT;
46934624Sbostic 			/*FALLTHROUGH*/
47034226Sbostic 		case 'u':
47153810Sbostic 			_uquad = UARG();
47246076Sbostic 			base = DEC;
47334327Sbostic 			goto nosign;
47434226Sbostic 		case 'X':
47546076Sbostic 			xdigs = "0123456789ABCDEF";
47646076Sbostic 			goto hex;
47734226Sbostic 		case 'x':
47846076Sbostic 			xdigs = "0123456789abcdef";
47953810Sbostic hex:			_uquad = UARG();
48046076Sbostic 			base = HEX;
48134326Sbostic 			/* leading 0x/X only if non-zero */
48253810Sbostic 			if (flags & ALT && _uquad != 0)
48334427Sbostic 				flags |= HEXPREFIX;
48434327Sbostic 
48534327Sbostic 			/* unsigned conversions */
48634427Sbostic nosign:			sign = '\0';
48734326Sbostic 			/*
48834330Sbostic 			 * ``... diouXx conversions ... if a precision is
48934330Sbostic 			 * specified, the 0 flag will be ignored.''
49034330Sbostic 			 *	-- ANSI X3J11
49134330Sbostic 			 */
49234427Sbostic number:			if ((dprec = prec) >= 0)
49334427Sbostic 				flags &= ~ZEROPAD;
49434427Sbostic 
49534330Sbostic 			/*
49634326Sbostic 			 * ``The result of converting a zero value with an
49734326Sbostic 			 * explicit precision of zero is no characters.''
49834326Sbostic 			 *	-- ANSI X3J11
49934326Sbostic 			 */
50046076Sbostic 			cp = buf + BUF;
50153810Sbostic 			if (_uquad != 0 || prec != 0) {
50246076Sbostic 				/*
50353810Sbostic 				 * Unsigned mod is hard, and unsigned mod
50446076Sbostic 				 * by a constant is easier than that by
50546076Sbostic 				 * a variable; hence this switch.
50646076Sbostic 				 */
50746076Sbostic 				switch (base) {
50846076Sbostic 				case OCT:
50946076Sbostic 					do {
51053810Sbostic 						*--cp = to_char(_uquad & 7);
51153810Sbostic 						_uquad >>= 3;
51253810Sbostic 					} while (_uquad);
51346076Sbostic 					/* handle octal leading 0 */
51446076Sbostic 					if (flags & ALT && *cp != '0')
51546076Sbostic 						*--cp = '0';
51646076Sbostic 					break;
51734327Sbostic 
51846076Sbostic 				case DEC:
51946076Sbostic 					/* many numbers are 1 digit */
52053810Sbostic 					while (_uquad >= 10) {
52153810Sbostic 						*--cp = to_char(_uquad % 10);
52253810Sbostic 						_uquad /= 10;
52346076Sbostic 					}
52453810Sbostic 					*--cp = to_char(_uquad);
52546076Sbostic 					break;
52634327Sbostic 
52746076Sbostic 				case HEX:
52846076Sbostic 					do {
52953810Sbostic 						*--cp = xdigs[_uquad & 15];
53053810Sbostic 						_uquad >>= 4;
53153810Sbostic 					} while (_uquad);
53246076Sbostic 					break;
53334327Sbostic 
53446076Sbostic 				default:
53546076Sbostic 					cp = "bug in vfprintf: bad base";
53646180Storek 					size = strlen(cp);
53746076Sbostic 					goto skipsize;
53846076Sbostic 				}
53934327Sbostic 			}
54046076Sbostic 			size = buf + BUF - cp;
54146076Sbostic 		skipsize:
54234226Sbostic 			break;
54346076Sbostic 		default:	/* "%?" prints ?, unless ? is NUL */
54446076Sbostic 			if (ch == '\0')
54546076Sbostic 				goto done;
54646076Sbostic 			/* pretend it was %c with argument ch */
54746076Sbostic 			cp = buf;
54846076Sbostic 			*cp = ch;
54946076Sbostic 			size = 1;
55046076Sbostic 			sign = '\0';
55146076Sbostic 			break;
55234226Sbostic 		}
55346076Sbostic 
55446076Sbostic 		/*
555*57154Sbostic 		 * All reasonable formats wind up here.  At this point, `cp'
556*57154Sbostic 		 * points to a string which (if not flags&LADJUST) should be
557*57154Sbostic 		 * padded out to `width' places.  If flags&ZEROPAD, it should
558*57154Sbostic 		 * first be prefixed by any sign or other prefix; otherwise,
559*57154Sbostic 		 * it should be blank padded before the prefix is emitted.
560*57154Sbostic 		 * After any left-hand padding and prefixing, emit zeroes
561*57154Sbostic 		 * required by a decimal [diouxX] precision, then print the
562*57154Sbostic 		 * string proper, then emit zeroes required by any leftover
563*57154Sbostic 		 * floating precision; finally, if LADJUST, pad with blanks.
564*57154Sbostic 		 *
565*57154Sbostic 		 * Compute actual size, so we know how much to pad.
566*57154Sbostic 		 * fieldsz excludes decimal prec; realsz includes it.
56746076Sbostic 		 */
56846076Sbostic 		fieldsz = size;
56946076Sbostic 		if (sign)
57046076Sbostic 			fieldsz++;
57146076Sbostic 		else if (flags & HEXPREFIX)
57246076Sbostic 			fieldsz += 2;
57346076Sbostic 		realsz = dprec > fieldsz ? dprec : fieldsz;
57446076Sbostic 
57546076Sbostic 		/* right-adjusting blank padding */
57646076Sbostic 		if ((flags & (LADJUST|ZEROPAD)) == 0)
57746076Sbostic 			PAD(width - realsz, blanks);
57846076Sbostic 
57946076Sbostic 		/* prefix */
58046076Sbostic 		if (sign) {
58146076Sbostic 			PRINT(&sign, 1);
58246076Sbostic 		} else if (flags & HEXPREFIX) {
58346076Sbostic 			ox[0] = '0';
58446076Sbostic 			ox[1] = ch;
58546076Sbostic 			PRINT(ox, 2);
58646076Sbostic 		}
58746076Sbostic 
58846076Sbostic 		/* right-adjusting zero padding */
58946076Sbostic 		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
59046076Sbostic 			PAD(width - realsz, zeroes);
59146076Sbostic 
59246076Sbostic 		/* leading zeroes from decimal precision */
59346076Sbostic 		PAD(dprec - fieldsz, zeroes);
59446076Sbostic 
59546076Sbostic 		/* the string or number proper */
596*57154Sbostic #ifdef FLOATING_POINT
597*57154Sbostic 		if ((flags & FPT) == 0) {
598*57154Sbostic 			PRINT(cp, size);
599*57154Sbostic 		} else {	/* glue together f_p fragments */
600*57154Sbostic 			if (ch >= 'f') {	/* 'f' or 'g' */
601*57154Sbostic 				if (_double == 0) {
602*57154Sbostic 				/* kludge for __dtoa irregularity */
603*57154Sbostic 					if (prec == 0 ||
604*57154Sbostic 					    (flags & ALT) == 0) {
605*57154Sbostic 						PRINT("0", 1);
606*57154Sbostic 					} else {
607*57154Sbostic 						PRINT("0.", 2);
608*57154Sbostic 						PAD(ndig - 1, zeroes);
609*57154Sbostic 					}
610*57154Sbostic 				} else if (expt <= 0) {
611*57154Sbostic 					PRINT("0.", 2);
612*57154Sbostic 					PAD(-expt, zeroes);
613*57154Sbostic 					PRINT(cp, ndig);
614*57154Sbostic 				} else if (expt >= ndig) {
615*57154Sbostic 					PRINT(cp, ndig);
616*57154Sbostic 					PAD(expt - ndig, zeroes);
617*57154Sbostic 					if (flags & ALT)
618*57154Sbostic 						PRINT(".", 1);
619*57154Sbostic 				} else {
620*57154Sbostic 					PRINT(cp, expt);
621*57154Sbostic 					cp += expt;
622*57154Sbostic 					PRINT(".", 1);
623*57154Sbostic 					PRINT(cp, ndig-expt);
624*57154Sbostic 				}
625*57154Sbostic 			} else {	/* 'e' or 'E' */
626*57154Sbostic 				if (ndig > 1 || flags & ALT) {
627*57154Sbostic 					ox[0] = *cp++;
628*57154Sbostic 					ox[1] = '.';
629*57154Sbostic 					PRINT(ox, 2);
630*57154Sbostic 					if (_double || flags & ALT == 0) {
631*57154Sbostic 						PRINT(cp, ndig-1);
632*57154Sbostic 					} else	/* 0.[0..] */
633*57154Sbostic 						/* __dtoa irregularity */
634*57154Sbostic 						PAD(ndig - 1, zeroes);
635*57154Sbostic 				} else	/* XeYYY */
636*57154Sbostic 					PRINT(cp, 1);
637*57154Sbostic 				PRINT(expstr, expsize);
638*57154Sbostic 			}
639*57154Sbostic 		}
640*57154Sbostic #else
64146076Sbostic 		PRINT(cp, size);
64246076Sbostic #endif
64346076Sbostic 		/* left-adjusting padding (always blank) */
64446076Sbostic 		if (flags & LADJUST)
64546076Sbostic 			PAD(width - realsz, blanks);
64646076Sbostic 
64746076Sbostic 		/* finally, adjust ret */
64846076Sbostic 		ret += width > realsz ? width : realsz;
64946076Sbostic 
65046076Sbostic 		FLUSH();	/* copy out the I/O vectors */
65134226Sbostic 	}
65246076Sbostic done:
65346076Sbostic 	FLUSH();
65446076Sbostic error:
65546076Sbostic 	return (__sferror(fp) ? EOF : ret);
65634427Sbostic 	/* NOTREACHED */
65734226Sbostic }
65834242Sbostic 
65946076Sbostic #ifdef FLOATING_POINT
66046180Storek 
661*57154Sbostic extern char *__dtoa __P((double, int, int, int *, int *, char **));
66246076Sbostic 
663*57154Sbostic static char *
664*57154Sbostic cvt(value, ndigits, flags, sign, decpt, ch, length)
665*57154Sbostic 	double value;
666*57154Sbostic 	int ndigits, flags, *decpt, ch, *length;
667*57154Sbostic 	char *sign;
66834242Sbostic {
669*57154Sbostic 	int mode, dsgn;
670*57154Sbostic 	char *digits, *bp, *rve;
67134242Sbostic 
672*57154Sbostic 	if (ch == 'f')
673*57154Sbostic 		mode = 3;
674*57154Sbostic 	else {
675*57154Sbostic 		mode = 2;
676*57154Sbostic 	}
677*57154Sbostic 	if (value < 0) {
678*57154Sbostic 		value = -value;
679*57154Sbostic 		*sign = '-';
68046076Sbostic 	} else
681*57154Sbostic 		*sign = '\000';
682*57154Sbostic 	digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve);
683*57154Sbostic 	if (flags & ALT) {	/* Print trailing zeros */
684*57154Sbostic 		bp = digits + ndigits;
685*57154Sbostic 		if (ch == 'f') {
686*57154Sbostic 			if (*digits == '0' && value)
687*57154Sbostic 				*decpt = -ndigits + 1;
688*57154Sbostic 			bp += *decpt;
68934624Sbostic 		}
690*57154Sbostic 		if (value == 0)	/* kludge for __dtoa irregularity */
691*57154Sbostic 			rve = bp;
692*57154Sbostic 		while (rve < bp)
693*57154Sbostic 			*rve++ = '0';
69434624Sbostic 	}
695*57154Sbostic 	*length = rve - digits;
696*57154Sbostic 	return (digits);
69734624Sbostic }
69834248Sbostic 
699*57154Sbostic static int
700*57154Sbostic exponent(p0, exp, fmtch)
701*57154Sbostic 	char *p0;
702*57154Sbostic 	int exp, fmtch;
70334624Sbostic {
704*57154Sbostic 	register char *p, *t;
70534624Sbostic 	char expbuf[MAXEXP];
70634248Sbostic 
707*57154Sbostic 	p = p0;
70834624Sbostic 	*p++ = fmtch;
70934624Sbostic 	if (exp < 0) {
71034624Sbostic 		exp = -exp;
71134624Sbostic 		*p++ = '-';
71234242Sbostic 	}
71334624Sbostic 	else
71434624Sbostic 		*p++ = '+';
71534624Sbostic 	t = expbuf + MAXEXP;
71634624Sbostic 	if (exp > 9) {
71734624Sbostic 		do {
71846076Sbostic 			*--t = to_char(exp % 10);
71934624Sbostic 		} while ((exp /= 10) > 9);
72046076Sbostic 		*--t = to_char(exp);
72134624Sbostic 		for (; t < expbuf + MAXEXP; *p++ = *t++);
72234624Sbostic 	}
72334624Sbostic 	else {
72434624Sbostic 		*p++ = '0';
72546076Sbostic 		*p++ = to_char(exp);
72634624Sbostic 	}
727*57154Sbostic 	return (p - p0);
72834242Sbostic }
72946076Sbostic #endif /* FLOATING_POINT */
730