xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 34236)
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*34236Sbostic static char sccsid[] = "@(#)vfprintf.c	5.4 (Berkeley) 05/08/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 
2234235Sbostic #define	GETARG(r) \
2334235Sbostic 	r = argsize&LONGINT ? va_arg(argp, long) : \
2434235Sbostic 	    argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
2534235Sbostic 
26*34236Sbostic #define	MAXBUF		1024			/* should hold any number */
27*34236Sbostic #define	MAXEXP		10			/* should hold any exponent */
28*34236Sbostic 
2934235Sbostic #define	DEFPREC		6			/* default precision */
3034226Sbostic 
31*34236Sbostic #define	PUTC(ch, fd)	{++cnt; putc(ch, fd);}
32*34236Sbostic 
3334235Sbostic #define	LONGINT		0x01
3434235Sbostic #define	LONGDBL		0x02
3534235Sbostic #define	SHORTINT	0x04
3634235Sbostic 
3734235Sbostic x_doprnt(fmt, argp, fp)
3834233Sbostic 	register char *fmt;
3934233Sbostic 	va_list argp;
4034235Sbostic 	register FILE *fp;
4134226Sbostic {
4234233Sbostic 	register u_long reg_ulong;
4334233Sbostic 	register long reg_long;
4434233Sbostic 	register int base;
4534235Sbostic 	register char *digs, *bp, *t, padc;
4634235Sbostic 	double _double;
47*34236Sbostic 	char argsize, printsign, buf[MAXBUF], *ecvt(), *fcvt();
4834235Sbostic 	int alternate, cnt, decpt, n, ladjust, width, prec, sign, size;
4934226Sbostic 
5034233Sbostic 	for (cnt = 0; *fmt; ++fmt) {
5134233Sbostic 		if (*fmt != '%') {
5234235Sbostic 			PUTC(*fmt, fp);
5334233Sbostic 			continue;
5434226Sbostic 		}
5534226Sbostic 
5634235Sbostic 		alternate = ladjust = width = 0;
5734233Sbostic 		prec = -1;
5834233Sbostic 		padc = ' ';
5934235Sbostic 		argsize = printsign = '\0';
6034226Sbostic 
6134233Sbostic flags:		switch (*++fmt) {
6234233Sbostic 		case '#':
6334233Sbostic 			alternate = 1;
6434233Sbostic 			goto flags;
6534233Sbostic 		case '%':			/* "%#%" prints as "%" */
6634235Sbostic 			PUTC('%', fp);
6734233Sbostic 			continue;
6834233Sbostic 		case '*':
6934235Sbostic 			/*
7034235Sbostic 			 * ``A negative field width argument is taken as a
7134235Sbostic 			 * - flag followed by a  positive field width.''
7234235Sbostic 			 *	-- ANSI X3J11
7334235Sbostic 			 * They don't exclude field widths read from args.
7434235Sbostic 			 */
7534235Sbostic 			if ((width = va_arg(argp, int)) >= 0)
7634235Sbostic 				goto flags;
7734235Sbostic 			width = -width;
7834235Sbostic 			/*FALLTHROUGH*/
7934235Sbostic 		case '-':
8034235Sbostic 			ladjust = 1;
8134233Sbostic 			goto flags;
8234233Sbostic 		case '+':
8334233Sbostic 			printsign = '+';
8434233Sbostic 			goto flags;
8534233Sbostic 		case '.':
8634235Sbostic 			if (*++fmt == '*')
8734235Sbostic 				prec = va_arg(argp, int);
8834235Sbostic 			else if (isdigit(*fmt)) {
8934235Sbostic 				prec = 0;
9034233Sbostic 				do {
91*34236Sbostic 					prec = 10 * prec + *fmt - '0';
9234233Sbostic 				} while isdigit(*++fmt);
9334233Sbostic 				--fmt;
9434226Sbostic 			}
9534235Sbostic 			else {
9634235Sbostic 				prec = 0;
9734235Sbostic 				--fmt;
9834235Sbostic 				goto flags;
9934235Sbostic 			}
10034235Sbostic 			if (prec < 0)
10134235Sbostic 				prec = -1;
10234233Sbostic 			goto flags;
10334233Sbostic 		case '0':
10434233Sbostic 			padc = '0';
10534235Sbostic 			/*FALLTHROUGH*/
10634233Sbostic 		case '1': case '2': case '3': case '4':
10734233Sbostic 		case '5': case '6': case '7': case '8': case '9':
10834233Sbostic 			do {
109*34236Sbostic 				width = 10 * width + *fmt - '0';
11034233Sbostic 			} while isdigit(*++fmt);
11134233Sbostic 			--fmt;
11234235Sbostic 		case 'L':
11334235Sbostic 			argsize |= LONGDBL;
11434235Sbostic 			goto flags;
11534235Sbostic 		case 'h':
11634235Sbostic 			argsize |= SHORTINT;
11734235Sbostic 			goto flags;
11834233Sbostic 		case 'l':
11934235Sbostic 			argsize |= LONGINT;
12034233Sbostic 			goto flags;
12134226Sbostic 		}
12234226Sbostic 
12334233Sbostic 		digs = "0123456789abcdef";
12434226Sbostic 
12534233Sbostic 		switch (*fmt) {
12634226Sbostic 		case 'c':
12734235Sbostic 			PUTC(va_arg(argp, int), fp);
12834226Sbostic 			break;
129*34236Sbostic 		case 'E':
130*34236Sbostic 		case 'e':
131*34236Sbostic 			if (prec == -1)
132*34236Sbostic 				prec = DEFPREC;
133*34236Sbostic 			_double = va_arg(argp, double);
134*34236Sbostic 			t = ecvt(_double, prec + 1, &decpt, &sign);
135*34236Sbostic 			bp = buf;
136*34236Sbostic 			*bp++ = *t ? *t++ : '0';
137*34236Sbostic 			if (alternate || prec > 0)
138*34236Sbostic 				*bp++ = '.';
139*34236Sbostic 			while (prec--)
140*34236Sbostic 				*bp++ = *t ? *t++ : '0';
141*34236Sbostic 			*bp++ = *fmt;
142*34236Sbostic 			*bp++ = (decpt > 0 || !_double) ? '+' : '-';
143*34236Sbostic 			/* we know exponents <= 99 */
144*34236Sbostic 			--decpt;
145*34236Sbostic 			*bp++ = (int)decpt / 10 + '0';
146*34236Sbostic 			*bp++ = (int)decpt % 10 + '0';
147*34236Sbostic 			goto pbuf;
14834235Sbostic 		case 'f':
14934235Sbostic 			if (prec == -1)
15034235Sbostic 				prec = DEFPREC;
15134235Sbostic 			_double = va_arg(argp, double);
15234235Sbostic 			t = fcvt(_double, prec + 1, &decpt, &sign);
15334235Sbostic 			bp = buf;
15434235Sbostic 			if (decpt >= 0)
15534235Sbostic 				for (;;) {
15634235Sbostic 					*bp++ = *t ? *t++ : '0';
15734235Sbostic 					if (!--decpt)
15834235Sbostic 						break;
15934235Sbostic 				}
16034235Sbostic 			if (alternate || prec > 0)
16134235Sbostic 				*bp++ = '.';
16234235Sbostic 			while (decpt++) {
16334235Sbostic 				*bp++ = *t ? *t++ : '0';
16434235Sbostic 				--prec;
16534235Sbostic 			}
16634235Sbostic 			while (prec--)
16734235Sbostic 				*bp++ = *t ? *t++ : '0';
168*34236Sbostic pbuf:			size = bp - buf;
169*34236Sbostic 			if (sign || printsign)
170*34236Sbostic 				PUTC(sign ? '-' : printsign, fp);
17134235Sbostic 			if (size < width && !ladjust)
17234235Sbostic 				do {
17334235Sbostic 					PUTC(padc, fp);
17434235Sbostic 				} while (--width > size);
17534235Sbostic 			for (t = buf; t < bp; ++t)
17634235Sbostic 				PUTC(*t, fp);
17734235Sbostic 			for (; width > size; --width)
17834235Sbostic 				PUTC(padc, fp);
17934235Sbostic 			break;
18034226Sbostic 		case 'd':
18134235Sbostic 		case 'i':
18234235Sbostic 			GETARG(reg_long);
18334233Sbostic 			if (reg_long < 0) {
18434233Sbostic 				reg_ulong = -reg_long;
18534233Sbostic 				printsign = '-';
18634233Sbostic 			}
18734233Sbostic 			else {
18834233Sbostic 				reg_ulong = reg_long;
18934233Sbostic 			}
19034233Sbostic 			if (printsign)
19134235Sbostic 				PUTC(printsign, fp);
19234226Sbostic 			base = 10;
19334235Sbostic 			goto num1;
19434235Sbostic 		case 'n':
19534235Sbostic 			*(va_arg(argp, int *)) = cnt;
19634235Sbostic 			break;
19734226Sbostic 		case 'o':
19834235Sbostic 			GETARG(reg_ulong);
19934226Sbostic 			base = 8;
20034235Sbostic 			if (!reg_ulong || !alternate)
20134235Sbostic 				goto num1;
20234235Sbostic 			bp = buf + sizeof(buf) - 1;
20334235Sbostic 			do {
20434235Sbostic 				*bp-- = digs[reg_ulong % base];
20534235Sbostic 				reg_ulong /= base;
20634235Sbostic 			} while(reg_ulong);
20734235Sbostic 			size = &buf[sizeof(buf) - 1] - bp;
20834235Sbostic 			if (size < --width && !ladjust)
20934235Sbostic 				do {
21034235Sbostic 					PUTC(padc, fp);
21134235Sbostic 				} while (--width > size);
21234235Sbostic 			PUTC('0', fp);
213*34236Sbostic 			goto num2;
21434235Sbostic 			break;
21534235Sbostic 		case 'p':
21634226Sbostic 		case 's':
21734235Sbostic 			if (!(bp = va_arg(argp, char *)))
21834235Sbostic 				bp = "(null)";
21934235Sbostic 			if (width > 0 && !ladjust) {
22034233Sbostic 				char *savep;
22134226Sbostic 
22234235Sbostic 				savep = bp;
22334235Sbostic 				for (n = 0; *bp && (prec < 0 || n < prec);
22434235Sbostic 				    n++, bp++);
22534235Sbostic 				bp = savep;
22634235Sbostic 				while (n++ < width)
22734235Sbostic 					PUTC(' ', fp);
22834233Sbostic 			}
22934235Sbostic 			for (n = 0; *bp; ++bp) {
23034235Sbostic 				if (++n > prec && prec >= 0)
23134226Sbostic 					break;
23234235Sbostic 				PUTC(*bp, fp);
23334233Sbostic 			}
23434235Sbostic 			if (n < width && ladjust)
23534233Sbostic 				do {
23634235Sbostic 					PUTC(' ', fp);
23734235Sbostic 				} while (++n < width);
23834226Sbostic 			break;
23934226Sbostic 		case 'u':
24034235Sbostic 			GETARG(reg_ulong);
24134226Sbostic 			base = 10;
24234235Sbostic 			goto num1;
24334226Sbostic 		case 'X':
24434226Sbostic 			digs = "0123456789ABCDEF";
24534233Sbostic 			/*FALLTHROUGH*/
24634226Sbostic 		case 'x':
24734235Sbostic 			GETARG(reg_ulong);
24834233Sbostic 			if (alternate && reg_ulong) {
24934235Sbostic 				PUTC('0', fp);
25034235Sbostic 				PUTC(*fmt, fp);
25134233Sbostic 			}
25234226Sbostic 			base = 16;
25334235Sbostic num1:			bp = buf + sizeof(buf) - 1;
25434233Sbostic 			do {
25534235Sbostic 				*bp-- = digs[reg_ulong % base];
25634233Sbostic 				reg_ulong /= base;
25734233Sbostic 			} while(reg_ulong);
25834235Sbostic 			size = &buf[sizeof(buf) - 1] - bp;
25934235Sbostic 			for (; size < prec; *bp-- = '0', ++size);
26034235Sbostic 			if (size < width && !ladjust)
26134235Sbostic 				do {
26234235Sbostic 					PUTC(padc, fp);
26334235Sbostic 				} while (--width > size);
264*34236Sbostic num2:			while (++bp != &buf[MAXBUF])
26534235Sbostic 				PUTC(*bp, fp);
26634235Sbostic 			for (; width > size; --width)
26734235Sbostic 				PUTC(padc, fp);
26834226Sbostic 			break;
26934233Sbostic 		case '\0':		/* "%?" prints ?, unless ? is NULL */
27034235Sbostic 			return(ferror(fp) ? -1 : cnt);
27134226Sbostic 		default:
27234235Sbostic 			PUTC(*fmt, fp);
27334226Sbostic 		}
27434226Sbostic 	}
27534235Sbostic 	return(ferror(fp) ? -1 : cnt);
27634226Sbostic }
277