xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 34322)
134226Sbostic /*
234233Sbostic  * Copyright (c) 1988 Regents of the University of California.
334233Sbostic  * All rights reserved.
434226Sbostic  *
534233Sbostic  * Redistribution and use in source and binary forms are permitted
634233Sbostic  * provided that this notice is preserved and that due credit is given
734233Sbostic  * to the University of California at Berkeley. The name of the University
834233Sbostic  * may not be used to endorse or promote products derived from this
934233Sbostic  * software without specific prior written permission. This software
1034233Sbostic  * is provided ``as is'' without express or implied warranty.
1134226Sbostic  */
1234226Sbostic 
1334233Sbostic #if defined(LIBC_SCCS) && !defined(lint)
14*34322Sbostic static char sccsid[] = "@(#)vfprintf.c	5.18 (Berkeley) 05/17/88";
1534233Sbostic #endif /* LIBC_SCCS and not lint */
1634233Sbostic 
1734261Sbostic #include <sys/types.h>
1834233Sbostic #include <varargs.h>
1934226Sbostic #include <stdio.h>
2034233Sbostic #include <ctype.h>
2134226Sbostic 
2234319Sbostic /*
2334319Sbostic  * To handle arbitrary floating point precision, the buffer has to hold the
2434319Sbostic  * number, a decimal point, and N precision digits.  We can't just truncate
2534319Sbostic  * at some point is that the lower-level math routines may very well be
2634319Sbostic  * repeatedly returning some small fraction.  A 128 bit fraction can be
2734319Sbostic  * represented in 39 decimal digits.  Guess a max of 40 digits of precision,
2834319Sbostic  * and add one for the decimal point.
2934319Sbostic  */
3034319Sbostic #define	MAXFRAC		39
3134319Sbostic #define	MAXPREC		40
3234319Sbostic #define	MAXDIGIT	(MAXFRAC + MAXPREC + 1)
3334226Sbostic 
3434263Sbostic #define	PUTC(ch)	{++cnt; putc(ch, fp);}
3534236Sbostic 
3634318Sbostic #define	ARG() \
3734318Sbostic 	_ulong = flags&LONGINT ? va_arg(argp, long) : \
3834318Sbostic 	    flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
3934235Sbostic 
4034318Sbostic /* have to deal with the negative buffer count kludge */
4134318Sbostic #define	NEGATIVE_COUNT_KLUDGE
4234318Sbostic 
4334318Sbostic #define	LONGINT		0x01		/* long integer */
4434318Sbostic #define	LONGDBL		0x02		/* long double; unimplemented */
4534318Sbostic #define	SHORTINT	0x04		/* short integer */
4634318Sbostic #define	ALT		0x08		/* alternate form */
4734318Sbostic #define	LADJUST		0x10		/* left adjustment */
4834318Sbostic static int flags;
4934318Sbostic 
5034319Sbostic static char sign, *buf;
5134248Sbostic 
5234235Sbostic x_doprnt(fmt, argp, fp)
5334233Sbostic 	register char *fmt;
5434233Sbostic 	va_list argp;
5534235Sbostic 	register FILE *fp;
5634226Sbostic {
5734314Sbostic 	register int cnt, n;
5834314Sbostic 	register char ch, *t;
5934235Sbostic 	double _double;
6034314Sbostic 	u_long _ulong;
6134318Sbostic 	int base, width, prec, size;
6234319Sbostic 	char padc, *digs, sbuf[MAXDIGIT];
6334226Sbostic 
6434243Sbostic 	digs = "0123456789abcdef";
65*34322Sbostic 	if (!buf)
66*34322Sbostic 		buf = sbuf;
67*34322Sbostic 	for (cnt = 0;; ++fmt) {
6834318Sbostic 		n = fp->_cnt;
6934318Sbostic 		for (t = fp->_ptr; (ch = *fmt) && ch != '%'; ++cnt, ++fmt)
7034318Sbostic 			if (--n < 0
7134318Sbostic #ifdef NEGATIVE_COUNT_KLUDGE
7234318Sbostic 			    && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
7334318Sbostic #endif
7434318Sbostic 			    || ch == '\n' && fp->_flag&_IOLBF) {
7534318Sbostic 				fp->_cnt = n;
7634318Sbostic 				fp->_ptr = t;
7734318Sbostic 				(void)_flsbuf(ch, fp);
7834318Sbostic 				n = fp->_cnt;
7934318Sbostic 				t = fp->_ptr;
8034318Sbostic 			}
8134318Sbostic 			else
8234314Sbostic 				*t++ = ch;
8334318Sbostic 		fp->_cnt = n;
8434318Sbostic 		fp->_ptr = t;
8534318Sbostic 		if (!ch)
8634314Sbostic 			return(cnt);
8734314Sbostic 
8834318Sbostic 		flags = width = 0;
8934233Sbostic 		prec = -1;
9034233Sbostic 		padc = ' ';
9134318Sbostic 		sign = '\0';
9234226Sbostic 
9334318Sbostic rflag:		switch (*++fmt) {
9434318Sbostic 		case ' ':
9534318Sbostic 			sign = ' ';
9634318Sbostic 			goto rflag;
9734233Sbostic 		case '#':
9834318Sbostic 			flags |= ALT;
9934318Sbostic 			goto rflag;
10034233Sbostic 		case '*':
10134235Sbostic 			/*
10234235Sbostic 			 * ``A negative field width argument is taken as a
10334235Sbostic 			 * - flag followed by a  positive field width.''
10434235Sbostic 			 *	-- ANSI X3J11
10534235Sbostic 			 * They don't exclude field widths read from args.
10634235Sbostic 			 */
10734235Sbostic 			if ((width = va_arg(argp, int)) >= 0)
10834318Sbostic 				goto rflag;
10934235Sbostic 			width = -width;
11034235Sbostic 			/*FALLTHROUGH*/
11134235Sbostic 		case '-':
11234318Sbostic 			flags |= LADJUST;
11334318Sbostic 			goto rflag;
11434233Sbostic 		case '+':
11534314Sbostic 			sign = '+';
11634318Sbostic 			goto rflag;
11734233Sbostic 		case '.':
11834235Sbostic 			if (*++fmt == '*')
11934318Sbostic 				n = va_arg(argp, int);
12034318Sbostic 			else if (isascii(*fmt) && isdigit(*fmt)) {
12134318Sbostic 				n = 0;
12234233Sbostic 				do {
12334318Sbostic 					n = 10 * n + *fmt - '0';
12434318Sbostic 				} while (isascii(*++fmt) && isdigit(*fmt));
12534233Sbostic 				--fmt;
12634226Sbostic 			}
12734235Sbostic 			else {
12834318Sbostic 				--fmt;
12934235Sbostic 				prec = 0;
13034318Sbostic 				goto rflag;
13134235Sbostic 			}
13234318Sbostic 			prec = n < 0 ? -1 : n;
13334318Sbostic 			goto rflag;
13434233Sbostic 		case '0':
13534233Sbostic 			padc = '0';
13634235Sbostic 			/*FALLTHROUGH*/
13734233Sbostic 		case '1': case '2': case '3': case '4':
13834233Sbostic 		case '5': case '6': case '7': case '8': case '9':
13934318Sbostic 			n = 0;
14034233Sbostic 			do {
14134318Sbostic 				n = 10 * n + *fmt - '0';
14234318Sbostic 			} while (isascii(*++fmt) && isdigit(*fmt));
14334318Sbostic 			width = n;
14434233Sbostic 			--fmt;
14534319Sbostic 			goto rflag;
14634235Sbostic 		case 'L':
14734318Sbostic 			/*
14834318Sbostic 			 * C doesn't have a long double; use long for now.
14934318Sbostic 			 * flags |= LONGDBL;
15034318Sbostic 			 */
15134318Sbostic 			flags |= LONGINT;
15234318Sbostic 			goto rflag;
15334235Sbostic 		case 'h':
15434318Sbostic 			flags |= SHORTINT;
15534318Sbostic 			goto rflag;
15634233Sbostic 		case 'l':
15734318Sbostic 			flags |= LONGINT;
15834318Sbostic 			goto rflag;
15934314Sbostic 		case 'c':
16034319Sbostic 			buf[0] = va_arg(argp, int);
16134314Sbostic 			size = 1;
16234319Sbostic 			t = buf;
16334314Sbostic 			goto pforw;
16434314Sbostic 		case 'd':
16534318Sbostic 		case 'i':
16634318Sbostic 			ARG();
16734318Sbostic 			if ((long)_ulong < 0) {
16834318Sbostic 				_ulong = -_ulong;
16934314Sbostic 				sign = '-';
17034241Sbostic 			}
17134314Sbostic 			if (sign)
17234314Sbostic 				PUTC(sign);
17334241Sbostic 			base = 10;
17434314Sbostic 			goto num;
17534261Sbostic 		case 'e':
17634236Sbostic 		case 'E':
17734235Sbostic 		case 'f':
17834261Sbostic 		case 'g':
17934243Sbostic 		case 'G':
18034243Sbostic 			_double = va_arg(argp, double);
18134319Sbostic 			size = _cvt(_double, prec, *fmt);
18234319Sbostic 			t = buf;
18334314Sbostic 			goto pforw;
18434235Sbostic 		case 'n':
18534318Sbostic 			if (flags&LONGDBL || flags&LONGINT)
18634318Sbostic 				*va_arg(argp, long *) = cnt;
18734318Sbostic 			else if (flags&SHORTINT)
18834318Sbostic 				*va_arg(argp, short *) = cnt;
18934318Sbostic 			else
19034318Sbostic 				*va_arg(argp, int *) = cnt;
19134235Sbostic 			break;
19234226Sbostic 		case 'o':
19334318Sbostic 			ARG();
19434226Sbostic 			base = 8;
19534314Sbostic 			goto num;
19634235Sbostic 		case 'p':
19734320Sbostic 			/*
19834321Sbostic 			 * ``The argument shall be a pointer to void.  The
19934321Sbostic 			 * value of the pointer is converted to a sequence
20034321Sbostic 			 * of printable characters, in an implementation-
20134321Sbostic 			 * defined manner.''
20234321Sbostic 			 *	-- ANSI X3J11
20334320Sbostic 			 */
20434320Sbostic 			_ulong = (u_long)va_arg(argp, void *);
20534320Sbostic 			base = 16;
20634320Sbostic 			goto num;
20734226Sbostic 		case 's':
20834314Sbostic 			if (!(t = va_arg(argp, char *)))
20934314Sbostic 				t = "(null)";
21034321Sbostic 			if (prec >= 0) {
21134321Sbostic 				/*
21234321Sbostic 				 * can't use strlen; can only look for the
21334321Sbostic 				 * NUL in the first `prec' characters, and
21434321Sbostic 				 * strlen() will go further.
21534321Sbostic 				 */
21634321Sbostic 				char *p, *memchr();
21734321Sbostic 
21834321Sbostic 				if (p = memchr(t, 0, prec)) {
21934321Sbostic 					size = p - t;
22034321Sbostic 					if (size > prec)
22134321Sbostic 						size = prec;
22234321Sbostic 				}
22334321Sbostic 				else
22434321Sbostic 					size = prec;
22534321Sbostic 			}
22634321Sbostic 			else
22734321Sbostic 				size = strlen(t);
22834318Sbostic pforw:			if (!(flags&LADJUST) && width)
22934314Sbostic 				for (n = size; n++ < width;)
23034314Sbostic 					PUTC(padc);
23134314Sbostic 			if (fp->_cnt - (n = size) >= 0) {
23234314Sbostic 				cnt += n;
23334314Sbostic 				fp->_cnt -= n;
23434314Sbostic 				bcopy(t, fp->_ptr, n);
23534314Sbostic 				fp->_ptr += n;
23634233Sbostic 			}
23734314Sbostic 			else for (; n--; ++t)
23834314Sbostic 				PUTC(*t);
23934318Sbostic 			if (flags&LADJUST)
24034314Sbostic 				while (width-- > size)
24134314Sbostic 					PUTC(padc);
24234226Sbostic 			break;
24334226Sbostic 		case 'u':
24434318Sbostic 			ARG();
24534226Sbostic 			base = 10;
24634314Sbostic 			goto num;
24734226Sbostic 		case 'X':
24834226Sbostic 			digs = "0123456789ABCDEF";
24934233Sbostic 			/*FALLTHROUGH*/
25034226Sbostic 		case 'x':
25134318Sbostic 			ARG();
25234314Sbostic 			base = 16;
25334314Sbostic 			/* alternate form for hex; leading 0x/X */
25434318Sbostic 			if (flags&ALT && _ulong) {
25534263Sbostic 				PUTC('0');
25634263Sbostic 				PUTC(*fmt);
25734233Sbostic 			}
25834319Sbostic num:			t = buf + MAXDIGIT - 1;
25934233Sbostic 			do {
26034314Sbostic 				*t-- = digs[_ulong % base];
26134314Sbostic 				_ulong /= base;
26234314Sbostic 			} while(_ulong);
26334314Sbostic 			digs = "0123456789abcdef";
26434319Sbostic 			size = buf + MAXDIGIT - 1 - t;
26534314Sbostic 			if (size >= prec) {
26634314Sbostic 				/* alternate form for octal; leading 0 */
26734318Sbostic 				if (t[1] != '0' && flags&ALT && *fmt == 'o') {
26834314Sbostic 					*t-- = '0';
26934314Sbostic 					++size;
27034314Sbostic 				}
27134314Sbostic 			}
27234314Sbostic 			else
27334314Sbostic 				for (; size < prec; ++size)
27434314Sbostic 					*t-- = '0';
27534318Sbostic 			if (!(flags&LADJUST))
27634314Sbostic 				while (size++ < width)
27734263Sbostic 					PUTC(padc);
27834319Sbostic 			while (++t < buf + MAXDIGIT)
27934314Sbostic 				PUTC(*t);
28034235Sbostic 			for (; width > size; --width)
28134263Sbostic 				PUTC(padc);
28234226Sbostic 			break;
28334233Sbostic 		case '\0':		/* "%?" prints ?, unless ? is NULL */
28434314Sbostic 			return(cnt);
28534226Sbostic 		default:
28634263Sbostic 			PUTC(*fmt);
28734226Sbostic 		}
28834226Sbostic 	}
28934314Sbostic 	/*NOTREACHED*/
29034226Sbostic }
29134242Sbostic 
29234261Sbostic #define	EFORMAT	0x01
29334261Sbostic #define	FFORMAT	0x02
29434261Sbostic #define	GFORMAT	0x04
29534314Sbostic #define	DEFPREC	6
29634261Sbostic 
29734319Sbostic static
29834319Sbostic _cvt(number, prec, fmtch)
29934242Sbostic 	double number;
30034261Sbostic 	register int prec;
30134319Sbostic 	char fmtch;
30234242Sbostic {
30334248Sbostic 	register char *p;
30434261Sbostic 	register int expcnt, format;
30534319Sbostic 	static int maxprec = MAXPREC;
30634248Sbostic 	double fract, integer, tmp, modf();
30734261Sbostic 	int decpt;
30834319Sbostic 	char *endp, *savep, *startp, *malloc();
30934242Sbostic 
31034314Sbostic 	if (prec == -1)
31134242Sbostic 		prec = DEFPREC;
31234242Sbostic 
31334319Sbostic 	/* allocate space for large precision */
31434319Sbostic 	if (prec > maxprec)
31534319Sbostic 		buf = malloc((u_int)((maxprec = prec) + MAXFRAC + 1));
31634319Sbostic 
31734319Sbostic 	startp = buf;
31834314Sbostic 	if (number < 0) {
31934248Sbostic 		*startp++ = '-';
32034248Sbostic 		number = -number;
32134248Sbostic 	}
32234314Sbostic 	else if (sign)
32334318Sbostic 		*startp++ = sign;
32434242Sbostic 
32534261Sbostic 	switch(fmtch) {
32634261Sbostic 	case 'e':
32734261Sbostic 	case 'E':
32834261Sbostic 		format = EFORMAT;
32934261Sbostic 		break;
33034261Sbostic 	case 'f':
33134261Sbostic 		format = FFORMAT;
33234261Sbostic 		break;
33334261Sbostic 	case 'g':
33434261Sbostic 	case 'G':
33534261Sbostic 		format = GFORMAT;
33634261Sbostic 		fmtch -= 2;
33734261Sbostic 	}
33834261Sbostic 
33934248Sbostic 	/*
34034248Sbostic 	 * if the alternate flag is set, or, at least one digit of precision
34134248Sbostic 	 * was requested, add a decimal point, unless it's the g/G format
34234314Sbostic 	 * in which case we require two digits of precision, as it counts
34334248Sbostic 	 * precision differently.
34434248Sbostic 	 */
34534318Sbostic 	decpt = flags&ALT || prec > (format&GFORMAT ? 1 : 0);
34634248Sbostic 
34734248Sbostic 	expcnt = 0;
34834319Sbostic 	p = buf + maxprec + MAXFRAC;
34934319Sbostic 	endp = p + 1;
35034248Sbostic 	fract = modf(number, &integer);
35134248Sbostic 	if (integer) {
35234248Sbostic 		register char *p2;
35334248Sbostic 
35434248Sbostic 		/* get integer part of number; count decimal places */
35534248Sbostic 		for (; integer; ++expcnt) {
35634248Sbostic 			tmp = modf(integer / 10, &integer);
35734248Sbostic 			*p-- = (int)((tmp + .03) * 10) + '0';
35834242Sbostic 		}
35934248Sbostic 
36034248Sbostic 		/* copy, in reverse order, to start of buffer */
36134248Sbostic 		p2 = startp;
36234248Sbostic 		*p2++ = *++p;
36334248Sbostic 
36434248Sbostic 		/*
36534248Sbostic 		 * if the format is g/G, and the resulting exponent will be
36634248Sbostic 		 * greater than the precision, use e/E format.  If e/E format,
36734248Sbostic 		 * put in a decimal point as needed, and decrement precision
36834248Sbostic 		 * count for each digit after the decimal point.
36934248Sbostic 		 */
37034248Sbostic 		if (format&GFORMAT && expcnt - 1 > prec || format&EFORMAT) {
37134248Sbostic 			if (format&GFORMAT) {
37234248Sbostic 				format |= EFORMAT;
37334248Sbostic 
37434248Sbostic 				/* first digit is precision for g/G format */
37534248Sbostic 				if (prec)
37634248Sbostic 					--prec;
37734248Sbostic 			}
37834248Sbostic 			if (decpt)
37934248Sbostic 				*p2++ = '.';
38034248Sbostic 			for (; ++p < endp && prec; --prec, *p2++ = *p);
38134248Sbostic 
38234318Sbostic 			/* precision ran out, round */
38334248Sbostic 			if (p < endp) {
38434248Sbostic 				if (*p > '4') {
38534248Sbostic 					for (savep = p2--;; *p2-- = '0') {
38634248Sbostic 						if (*p2 == '.')
38734248Sbostic 							--p2;
38834248Sbostic 						if (++*p2 <= '9')
38934248Sbostic 							break;
39034248Sbostic 					}
39134248Sbostic 					p2 = savep;
39234248Sbostic 				}
39334248Sbostic 				fract = 0;
39434248Sbostic 			}
39534242Sbostic 		}
39634248Sbostic 		/*
39734314Sbostic 		 * g/G in f format; if out of precision, replace digits with
39834314Sbostic 		 * zeroes, note, have to round first.
39934248Sbostic 		 */
40034248Sbostic 		else if (format&GFORMAT) {
40134248Sbostic 			for (; ++p < endp && prec; --prec, *p2++ = *p);
40234248Sbostic 			/* precision ran out; round and then add zeroes */
40334248Sbostic 			if (p < endp) {
40434248Sbostic 				if (*p > '4') {
40534248Sbostic 					for (savep = p2--; ++*p2 > '9';
40634248Sbostic 					    *p2-- = '0');
40734248Sbostic 					p2 = savep;
40834248Sbostic 				}
40934248Sbostic 				do {
41034248Sbostic 					*p2++ = '0';
41134248Sbostic 				} while (++p < endp);
41234248Sbostic 				fract = 0;
41334248Sbostic 			}
41434248Sbostic 			if (decpt)
41534248Sbostic 				*p2++ = '.';
41634242Sbostic 		}
41734248Sbostic 		/* f format */
41834248Sbostic 		else {
41934248Sbostic 			for (; ++p < endp; *p2++ = *p);
42034248Sbostic 			if (decpt)
42134248Sbostic 				*p2++ = '.';
42234248Sbostic 		}
42334248Sbostic 		p = p2;
42434248Sbostic 	}
42534248Sbostic 	/*
42634318Sbostic 	 * if no fraction, the number was zero, and if no precision, can't
42734318Sbostic 	 * show anything after the decimal point.
42834248Sbostic 	 */
42934248Sbostic 	else if (!fract || !prec) {
43034248Sbostic 		*startp++ = '0';
43134318Sbostic 		if (decpt && !(format&GFORMAT))
43234248Sbostic 			*startp++ = '.';
43334318Sbostic 		*startp = '\0';
43434319Sbostic 		return(startp - buf);
43534248Sbostic 	}
43634248Sbostic 	/*
43734248Sbostic 	 * if the format is g/G, and the resulting exponent will be less than
43834248Sbostic 	 * -4 use e/E format.  If e/E format, compute exponent value.
43934248Sbostic 	 */
44034248Sbostic 	else if (format&GFORMAT && fract < .0001 || format&EFORMAT) {
44134248Sbostic 		format |= EFORMAT;
44234248Sbostic 		if (fract)
44334248Sbostic 			for (p = startp; fract;) {
44434248Sbostic 				fract = modf(fract * 10, &tmp);
44534248Sbostic 				if (!tmp) {
44634248Sbostic 					--expcnt;
44734248Sbostic 					continue;
44834248Sbostic 				}
44934248Sbostic 				*p++ = (int)tmp + '0';
45034248Sbostic 				break;
45134248Sbostic 			}
45234242Sbostic 		else
45334248Sbostic 			*p++ = '0';
45434248Sbostic 
45534248Sbostic 		/* g/G format, decrement precision for first digit */
45634248Sbostic 		if (format&GFORMAT && prec)
45734248Sbostic 			--prec;
45834248Sbostic 
45934248Sbostic 		/* add decimal after first non-zero digit */
46034248Sbostic 		if (decpt)
46134248Sbostic 			*p++ = '.';
46234242Sbostic 	}
46334248Sbostic 	/*
46434248Sbostic 	 * f format or g/G printed as f format; don't worry about decimal
46534248Sbostic 	 * point, if g/G format doesn't need it, will get stripped later.
46634248Sbostic 	 */
46734242Sbostic 	else {
46834248Sbostic 		p = startp;
46934248Sbostic 		*p++ = '0';
47034248Sbostic 		*p++ = '.';
47134248Sbostic 	}
47234248Sbostic 
47334319Sbostic 	/* finish out requested precision */
47434319Sbostic 	while (fract && prec-- > 0) {
47534319Sbostic 		fract = modf(fract * 10, &tmp);
47634319Sbostic 		*p++ = (int)tmp + '0';
47734319Sbostic 	}
47834319Sbostic 	while (prec-- > 0)
47934319Sbostic 		*p++ = '0';
48034248Sbostic 
48134248Sbostic 	/*
48234248Sbostic 	 * if any fractional value left, "round" it back up to the beginning
48334248Sbostic 	 * of the number, fixing the exponent as necessary, and avoiding the
48434248Sbostic 	 * decimal point.
48534248Sbostic 	 */
48634248Sbostic 	if (fract) {
48734248Sbostic 		(void)modf(fract * 10, &tmp);
48834248Sbostic 		if (tmp > 4) {
48934248Sbostic 			for (savep = p--;; *p-- = '0') {
49034248Sbostic 				if (*p == '.')
49134248Sbostic 					--p;
49234248Sbostic 				if (p == startp) {
49334248Sbostic 					*p = '1';
49434248Sbostic 					++expcnt;
49534248Sbostic 					break;
49634248Sbostic 				}
49734248Sbostic 				if (++*p <= '9')
49834248Sbostic 					break;
49934242Sbostic 			}
50034248Sbostic 			p = savep;
50134242Sbostic 		}
50234248Sbostic 	}
50334248Sbostic 
50434248Sbostic 	/*
50534248Sbostic 	 * if a g/G format and not alternate flag, lose trailing zeroes,
50634248Sbostic 	 * if e/E or g/G format, and last char is decimal point, lose it.
50734248Sbostic 	 */
50834318Sbostic 	if (!(flags&ALT)) {
50934248Sbostic 		if (format&GFORMAT)
51034248Sbostic 			for (; p[-1] == '0'; --p);
51134248Sbostic 		if (format&(GFORMAT|EFORMAT) && p[-1] == '.')
51234248Sbostic 			--p;
51334248Sbostic 	}
51434248Sbostic 
51534248Sbostic 	/* if an e/E format, add exponent */
51634248Sbostic 	if (format&EFORMAT) {
51734248Sbostic 		*p++ = fmtch;
51834248Sbostic 		if (--expcnt < 0) {
51934248Sbostic 			expcnt = -expcnt;
52034248Sbostic 			*p++ = '-';
52134242Sbostic 		}
52234248Sbostic 		else
52334248Sbostic 			*p++ = '+';
52434248Sbostic 		*p++ = expcnt / 10 + '0';
52534248Sbostic 		*p++ = expcnt % 10 + '0';
52634242Sbostic 	}
52734319Sbostic 	return(p - buf);
52834242Sbostic }
529