xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 34241)
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*34241Sbostic static char sccsid[] = "@(#)vfprintf.c	5.5 (Berkeley) 05/09/88";
1534233Sbostic #endif /* LIBC_SCCS and not lint */
1634233Sbostic 
1734233Sbostic #include <sys/param.h>
1834233Sbostic #include <varargs.h>
1934226Sbostic #include <stdio.h>
2034233Sbostic #include <ctype.h>
2134226Sbostic 
22*34241Sbostic #define	MAXBUF		120			/* should hold any number */
2334235Sbostic #define	DEFPREC		6			/* default precision */
2434226Sbostic 
2534236Sbostic #define	PUTC(ch, fd)	{++cnt; putc(ch, fd);}
2634236Sbostic 
2734235Sbostic #define	LONGINT		0x01
2834235Sbostic #define	LONGDBL		0x02
2934235Sbostic #define	SHORTINT	0x04
30*34241Sbostic #define	GETARG(r) \
31*34241Sbostic 	r = argsize&LONGINT ? va_arg(argp, long) : \
32*34241Sbostic 	    argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
3334235Sbostic 
3434235Sbostic x_doprnt(fmt, argp, fp)
3534233Sbostic 	register char *fmt;
3634233Sbostic 	va_list argp;
3734235Sbostic 	register FILE *fp;
3834226Sbostic {
3934233Sbostic 	register u_long reg_ulong;
4034233Sbostic 	register long reg_long;
4134233Sbostic 	register int base;
4234235Sbostic 	register char *digs, *bp, *t, padc;
4334235Sbostic 	double _double;
4434236Sbostic 	char argsize, printsign, buf[MAXBUF], *ecvt(), *fcvt();
4534235Sbostic 	int alternate, cnt, decpt, n, ladjust, width, prec, sign, size;
4634226Sbostic 
4734233Sbostic 	for (cnt = 0; *fmt; ++fmt) {
4834233Sbostic 		if (*fmt != '%') {
4934235Sbostic 			PUTC(*fmt, fp);
5034233Sbostic 			continue;
5134226Sbostic 		}
5234226Sbostic 
5334235Sbostic 		alternate = ladjust = width = 0;
5434233Sbostic 		prec = -1;
5534233Sbostic 		padc = ' ';
5634235Sbostic 		argsize = printsign = '\0';
5734226Sbostic 
5834233Sbostic flags:		switch (*++fmt) {
5934233Sbostic 		case '#':
6034233Sbostic 			alternate = 1;
6134233Sbostic 			goto flags;
6234233Sbostic 		case '%':			/* "%#%" prints as "%" */
6334235Sbostic 			PUTC('%', fp);
6434233Sbostic 			continue;
6534233Sbostic 		case '*':
6634235Sbostic 			/*
6734235Sbostic 			 * ``A negative field width argument is taken as a
6834235Sbostic 			 * - flag followed by a  positive field width.''
6934235Sbostic 			 *	-- ANSI X3J11
7034235Sbostic 			 * They don't exclude field widths read from args.
7134235Sbostic 			 */
7234235Sbostic 			if ((width = va_arg(argp, int)) >= 0)
7334235Sbostic 				goto flags;
7434235Sbostic 			width = -width;
7534235Sbostic 			/*FALLTHROUGH*/
7634235Sbostic 		case '-':
7734235Sbostic 			ladjust = 1;
7834233Sbostic 			goto flags;
7934233Sbostic 		case '+':
8034233Sbostic 			printsign = '+';
8134233Sbostic 			goto flags;
8234233Sbostic 		case '.':
8334235Sbostic 			if (*++fmt == '*')
8434235Sbostic 				prec = va_arg(argp, int);
8534235Sbostic 			else if (isdigit(*fmt)) {
8634235Sbostic 				prec = 0;
8734233Sbostic 				do {
8834236Sbostic 					prec = 10 * prec + *fmt - '0';
8934233Sbostic 				} while isdigit(*++fmt);
9034233Sbostic 				--fmt;
9134226Sbostic 			}
9234235Sbostic 			else {
9334235Sbostic 				prec = 0;
9434235Sbostic 				--fmt;
9534235Sbostic 				goto flags;
9634235Sbostic 			}
9734235Sbostic 			if (prec < 0)
9834235Sbostic 				prec = -1;
9934233Sbostic 			goto flags;
10034233Sbostic 		case '0':
10134233Sbostic 			padc = '0';
10234235Sbostic 			/*FALLTHROUGH*/
10334233Sbostic 		case '1': case '2': case '3': case '4':
10434233Sbostic 		case '5': case '6': case '7': case '8': case '9':
10534233Sbostic 			do {
10634236Sbostic 				width = 10 * width + *fmt - '0';
10734233Sbostic 			} while isdigit(*++fmt);
10834233Sbostic 			--fmt;
10934235Sbostic 		case 'L':
11034235Sbostic 			argsize |= LONGDBL;
11134235Sbostic 			goto flags;
11234235Sbostic 		case 'h':
11334235Sbostic 			argsize |= SHORTINT;
11434235Sbostic 			goto flags;
11534233Sbostic 		case 'l':
11634235Sbostic 			argsize |= LONGINT;
11734233Sbostic 			goto flags;
11834226Sbostic 		}
11934226Sbostic 
12034233Sbostic 		digs = "0123456789abcdef";
12134226Sbostic 
12234233Sbostic 		switch (*fmt) {
12334226Sbostic 		case 'c':
12434235Sbostic 			PUTC(va_arg(argp, int), fp);
12534226Sbostic 			break;
126*34241Sbostic 		case 'd':
127*34241Sbostic 		case 'i':
128*34241Sbostic 			GETARG(reg_long);
129*34241Sbostic 			if (reg_long < 0) {
130*34241Sbostic 				reg_ulong = -reg_long;
131*34241Sbostic 				printsign = '-';
132*34241Sbostic 			}
133*34241Sbostic 			else {
134*34241Sbostic 				reg_ulong = reg_long;
135*34241Sbostic 			}
136*34241Sbostic 			if (printsign)
137*34241Sbostic 				PUTC(printsign, fp);
138*34241Sbostic 			base = 10;
139*34241Sbostic 			goto num1;
14034236Sbostic 		case 'E':
14134236Sbostic 		case 'e':
14234236Sbostic 			if (prec == -1)
14334236Sbostic 				prec = DEFPREC;
14434236Sbostic 			_double = va_arg(argp, double);
145*34241Sbostic 			t = fcvt(_double, prec + 1, &decpt, &sign);
146*34241Sbostic gise:			bp = buf;
14734236Sbostic 			*bp++ = *t ? *t++ : '0';
14834236Sbostic 			if (alternate || prec > 0)
14934236Sbostic 				*bp++ = '.';
15034236Sbostic 			while (prec--)
15134236Sbostic 				*bp++ = *t ? *t++ : '0';
15234236Sbostic 			*bp++ = *fmt;
153*34241Sbostic 			if (decpt > 0 || !_double) {
154*34241Sbostic 				*bp++ = '+';
155*34241Sbostic 				--decpt;
156*34241Sbostic 			}
157*34241Sbostic 			else {
158*34241Sbostic 				*bp++ = '-';
159*34241Sbostic 				decpt = -decpt + 1;
160*34241Sbostic 			}
161*34241Sbostic 			/* exponents <= 99 in ANSI X3J11 */
162*34241Sbostic 			*bp++ = (int)(decpt / 10) + '0';
163*34241Sbostic 			*bp++ = (int)(decpt % 10) + '0';
16434236Sbostic 			goto pbuf;
16534235Sbostic 		case 'f':
16634235Sbostic 			if (prec == -1)
16734235Sbostic 				prec = DEFPREC;
16834235Sbostic 			_double = va_arg(argp, double);
16934235Sbostic 			t = fcvt(_double, prec + 1, &decpt, &sign);
170*34241Sbostic gisf:			bp = buf;
17134235Sbostic 			if (decpt >= 0)
17234235Sbostic 				for (;;) {
17334235Sbostic 					*bp++ = *t ? *t++ : '0';
17434235Sbostic 					if (!--decpt)
17534235Sbostic 						break;
17634235Sbostic 				}
177*34241Sbostic 			if (alternate || prec > 0) {
178*34241Sbostic 				if (decpt < 0)
179*34241Sbostic 					*bp++ = '0';
18034235Sbostic 				*bp++ = '.';
181*34241Sbostic 			}
18234235Sbostic 			while (decpt++) {
183*34241Sbostic 				*bp++ = '0';
18434235Sbostic 				--prec;
18534235Sbostic 			}
18634235Sbostic 			while (prec--)
18734235Sbostic 				*bp++ = *t ? *t++ : '0';
18834236Sbostic pbuf:			size = bp - buf;
18934236Sbostic 			if (sign || printsign)
19034236Sbostic 				PUTC(sign ? '-' : printsign, fp);
19134235Sbostic 			if (size < width && !ladjust)
19234235Sbostic 				do {
19334235Sbostic 					PUTC(padc, fp);
19434235Sbostic 				} while (--width > size);
19534235Sbostic 			for (t = buf; t < bp; ++t)
19634235Sbostic 				PUTC(*t, fp);
19734235Sbostic 			for (; width > size; --width)
19834235Sbostic 				PUTC(padc, fp);
19934235Sbostic 			break;
200*34241Sbostic 		case 'G':
201*34241Sbostic 		case 'g': {
202*34241Sbostic 			int gotoe;
203*34241Sbostic 
204*34241Sbostic 			if (prec == -1)
205*34241Sbostic 				prec = DEFPREC;
206*34241Sbostic 			_double = va_arg(argp, double);
207*34241Sbostic 			t = fcvt(_double, prec + 1, &decpt, &sign);
208*34241Sbostic 			gotoe = decpt > prec;
209*34241Sbostic 			if (!alternate) {
210*34241Sbostic 				for (bp = t + prec + decpt; prec &&
211*34241Sbostic 				    *--bp == '0'; --prec);
21234233Sbostic 			}
213*34241Sbostic 			if (gotoe || decpt < -3) {
214*34241Sbostic 				*fmt -= 2;
215*34241Sbostic 				goto gise;
21634233Sbostic 			}
217*34241Sbostic 			--*fmt;
218*34241Sbostic 			goto gisf;
219*34241Sbostic 		}
22034235Sbostic 		case 'n':
22134235Sbostic 			*(va_arg(argp, int *)) = cnt;
22234235Sbostic 			break;
22334226Sbostic 		case 'o':
22434235Sbostic 			GETARG(reg_ulong);
22534226Sbostic 			base = 8;
22634235Sbostic 			if (!reg_ulong || !alternate)
22734235Sbostic 				goto num1;
22834235Sbostic 			bp = buf + sizeof(buf) - 1;
22934235Sbostic 			do {
23034235Sbostic 				*bp-- = digs[reg_ulong % base];
23134235Sbostic 				reg_ulong /= base;
23234235Sbostic 			} while(reg_ulong);
23334235Sbostic 			size = &buf[sizeof(buf) - 1] - bp;
23434235Sbostic 			if (size < --width && !ladjust)
23534235Sbostic 				do {
23634235Sbostic 					PUTC(padc, fp);
23734235Sbostic 				} while (--width > size);
23834235Sbostic 			PUTC('0', fp);
23934236Sbostic 			goto num2;
24034235Sbostic 			break;
24134235Sbostic 		case 'p':
24234226Sbostic 		case 's':
24334235Sbostic 			if (!(bp = va_arg(argp, char *)))
24434235Sbostic 				bp = "(null)";
24534235Sbostic 			if (width > 0 && !ladjust) {
24634233Sbostic 				char *savep;
24734226Sbostic 
24834235Sbostic 				savep = bp;
24934235Sbostic 				for (n = 0; *bp && (prec < 0 || n < prec);
25034235Sbostic 				    n++, bp++);
25134235Sbostic 				bp = savep;
25234235Sbostic 				while (n++ < width)
25334235Sbostic 					PUTC(' ', fp);
25434233Sbostic 			}
25534235Sbostic 			for (n = 0; *bp; ++bp) {
25634235Sbostic 				if (++n > prec && prec >= 0)
25734226Sbostic 					break;
25834235Sbostic 				PUTC(*bp, fp);
25934233Sbostic 			}
26034235Sbostic 			if (n < width && ladjust)
26134233Sbostic 				do {
26234235Sbostic 					PUTC(' ', fp);
26334235Sbostic 				} while (++n < width);
26434226Sbostic 			break;
26534226Sbostic 		case 'u':
26634235Sbostic 			GETARG(reg_ulong);
26734226Sbostic 			base = 10;
26834235Sbostic 			goto num1;
26934226Sbostic 		case 'X':
27034226Sbostic 			digs = "0123456789ABCDEF";
27134233Sbostic 			/*FALLTHROUGH*/
27234226Sbostic 		case 'x':
27334235Sbostic 			GETARG(reg_ulong);
27434233Sbostic 			if (alternate && reg_ulong) {
27534235Sbostic 				PUTC('0', fp);
27634235Sbostic 				PUTC(*fmt, fp);
27734233Sbostic 			}
27834226Sbostic 			base = 16;
27934235Sbostic num1:			bp = buf + sizeof(buf) - 1;
28034233Sbostic 			do {
28134235Sbostic 				*bp-- = digs[reg_ulong % base];
28234233Sbostic 				reg_ulong /= base;
28334233Sbostic 			} while(reg_ulong);
28434235Sbostic 			size = &buf[sizeof(buf) - 1] - bp;
28534235Sbostic 			for (; size < prec; *bp-- = '0', ++size);
28634235Sbostic 			if (size < width && !ladjust)
28734235Sbostic 				do {
28834235Sbostic 					PUTC(padc, fp);
28934235Sbostic 				} while (--width > size);
29034236Sbostic num2:			while (++bp != &buf[MAXBUF])
29134235Sbostic 				PUTC(*bp, fp);
29234235Sbostic 			for (; width > size; --width)
29334235Sbostic 				PUTC(padc, fp);
29434226Sbostic 			break;
29534233Sbostic 		case '\0':		/* "%?" prints ?, unless ? is NULL */
29634235Sbostic 			return(ferror(fp) ? -1 : cnt);
29734226Sbostic 		default:
29834235Sbostic 			PUTC(*fmt, fp);
29934226Sbostic 		}
30034226Sbostic 	}
30134235Sbostic 	return(ferror(fp) ? -1 : cnt);
30234226Sbostic }
303