xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 34235)
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*34235Sbostic static char sccsid[] = "@(#)vfprintf.c	5.3 (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 
22*34235Sbostic #define	GETARG(r) \
23*34235Sbostic 	r = argsize&LONGINT ? va_arg(argp, long) : \
24*34235Sbostic 	    argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
25*34235Sbostic 
26*34235Sbostic #define	DEFPREC		6			/* default precision */
27*34235Sbostic #define	MAXBUF		1024
2834233Sbostic #define	PUTC(ch, fd)	{ ++cnt; putc(ch, fd); }
2934233Sbostic #define	todigit(ch)	((ch) - '0')
30*34235Sbostic #define	tochar(ch)	((ch) + '0')
3134226Sbostic 
32*34235Sbostic #define	LONGINT		0x01
33*34235Sbostic #define	LONGDBL		0x02
34*34235Sbostic #define	SHORTINT	0x04
35*34235Sbostic 
36*34235Sbostic x_doprnt(fmt, argp, fp)
3734233Sbostic 	register char *fmt;
3834233Sbostic 	va_list argp;
39*34235Sbostic 	register FILE *fp;
4034226Sbostic {
4134233Sbostic 	register u_long reg_ulong;
4234233Sbostic 	register long reg_long;
4334233Sbostic 	register int base;
44*34235Sbostic 	register char *digs, *bp, *t, padc;
45*34235Sbostic 	double _double;
46*34235Sbostic 	char argsize, printsign, buf[MAXBUF], *fcvt();
47*34235Sbostic 	int alternate, cnt, decpt, n, ladjust, width, prec, sign, size;
4834226Sbostic 
4934233Sbostic 	for (cnt = 0; *fmt; ++fmt) {
5034233Sbostic 		if (*fmt != '%') {
51*34235Sbostic 			PUTC(*fmt, fp);
5234233Sbostic 			continue;
5334226Sbostic 		}
5434226Sbostic 
55*34235Sbostic 		alternate = ladjust = width = 0;
5634233Sbostic 		prec = -1;
5734233Sbostic 		padc = ' ';
58*34235Sbostic 		argsize = printsign = '\0';
5934226Sbostic 
6034233Sbostic flags:		switch (*++fmt) {
6134233Sbostic 		case '#':
6234233Sbostic 			alternate = 1;
6334233Sbostic 			goto flags;
6434233Sbostic 		case '%':			/* "%#%" prints as "%" */
65*34235Sbostic 			PUTC('%', fp);
6634233Sbostic 			continue;
6734233Sbostic 		case '*':
68*34235Sbostic 			/*
69*34235Sbostic 			 * ``A negative field width argument is taken as a
70*34235Sbostic 			 * - flag followed by a  positive field width.''
71*34235Sbostic 			 *	-- ANSI X3J11
72*34235Sbostic 			 * They don't exclude field widths read from args.
73*34235Sbostic 			 */
74*34235Sbostic 			if ((width = va_arg(argp, int)) >= 0)
75*34235Sbostic 				goto flags;
76*34235Sbostic 			width = -width;
77*34235Sbostic 			/*FALLTHROUGH*/
78*34235Sbostic 		case '-':
79*34235Sbostic 			ladjust = 1;
8034233Sbostic 			goto flags;
8134233Sbostic 		case '+':
8234233Sbostic 			printsign = '+';
8334233Sbostic 			goto flags;
8434233Sbostic 		case '.':
85*34235Sbostic 			if (*++fmt == '*')
86*34235Sbostic 				prec = va_arg(argp, int);
87*34235Sbostic 			else if (isdigit(*fmt)) {
88*34235Sbostic 				prec = 0;
8934233Sbostic 				do {
9034233Sbostic 					prec = 10 * prec + todigit(*fmt);
9134233Sbostic 				} while isdigit(*++fmt);
9234233Sbostic 				--fmt;
9334226Sbostic 			}
94*34235Sbostic 			else {
95*34235Sbostic 				prec = 0;
96*34235Sbostic 				--fmt;
97*34235Sbostic 				goto flags;
98*34235Sbostic 			}
99*34235Sbostic 			if (prec < 0)
100*34235Sbostic 				prec = -1;
10134233Sbostic 			goto flags;
10234233Sbostic 		case '0':
10334233Sbostic 			padc = '0';
104*34235Sbostic 			/*FALLTHROUGH*/
10534233Sbostic 		case '1': case '2': case '3': case '4':
10634233Sbostic 		case '5': case '6': case '7': case '8': case '9':
10734233Sbostic 			do {
108*34235Sbostic 				width = 10 * width + todigit(*fmt);
10934233Sbostic 			} while isdigit(*++fmt);
11034233Sbostic 			--fmt;
111*34235Sbostic 		case 'L':
112*34235Sbostic 			argsize |= LONGDBL;
113*34235Sbostic 			goto flags;
114*34235Sbostic 		case 'h':
115*34235Sbostic 			argsize |= SHORTINT;
116*34235Sbostic 			goto flags;
11734233Sbostic 		case 'l':
118*34235Sbostic 			argsize |= LONGINT;
11934233Sbostic 			goto flags;
12034226Sbostic 		}
12134226Sbostic 
12234233Sbostic 		digs = "0123456789abcdef";
12334226Sbostic 
12434233Sbostic 		switch (*fmt) {
12534226Sbostic 		case 'c':
126*34235Sbostic 			PUTC(va_arg(argp, int), fp);
12734226Sbostic 			break;
128*34235Sbostic 		case 'f':
129*34235Sbostic 			if (prec == -1)
130*34235Sbostic 				prec = DEFPREC;
131*34235Sbostic 			_double = va_arg(argp, double);
132*34235Sbostic 			t = fcvt(_double, prec + 1, &decpt, &sign);
133*34235Sbostic 			if (sign)
134*34235Sbostic 				printsign = '-';
135*34235Sbostic 			bp = buf;
136*34235Sbostic 			if (decpt >= 0)
137*34235Sbostic 				for (;;) {
138*34235Sbostic 					*bp++ = *t ? *t++ : '0';
139*34235Sbostic 					if (!--decpt)
140*34235Sbostic 						break;
141*34235Sbostic 				}
142*34235Sbostic 			if (alternate || prec > 0)
143*34235Sbostic 				*bp++ = '.';
144*34235Sbostic 			while (decpt++) {
145*34235Sbostic 				*bp++ = *t ? *t++ : '0';
146*34235Sbostic 				--prec;
147*34235Sbostic 			}
148*34235Sbostic 			while (prec--)
149*34235Sbostic 				*bp++ = *t ? *t++ : '0';
150*34235Sbostic 			size = bp - buf;
151*34235Sbostic 			if (size < width && !ladjust)
152*34235Sbostic 				do {
153*34235Sbostic 					PUTC(padc, fp);
154*34235Sbostic 				} while (--width > size);
155*34235Sbostic 			for (t = buf; t < bp; ++t)
156*34235Sbostic 				PUTC(*t, fp);
157*34235Sbostic 			for (; width > size; --width)
158*34235Sbostic 				PUTC(padc, fp);
159*34235Sbostic 			break;
16034226Sbostic 		case 'd':
161*34235Sbostic 		case 'i':
162*34235Sbostic 			GETARG(reg_long);
16334233Sbostic 			if (reg_long < 0) {
16434233Sbostic 				reg_ulong = -reg_long;
16534233Sbostic 				printsign = '-';
16634233Sbostic 			}
16734233Sbostic 			else {
16834233Sbostic 				reg_ulong = reg_long;
16934233Sbostic 			}
17034233Sbostic 			if (printsign)
171*34235Sbostic 				PUTC(printsign, fp);
17234226Sbostic 			base = 10;
173*34235Sbostic 			goto num1;
174*34235Sbostic 		case 'n':
175*34235Sbostic 			*(va_arg(argp, int *)) = cnt;
176*34235Sbostic 			break;
17734226Sbostic 		case 'o':
178*34235Sbostic 			GETARG(reg_ulong);
17934226Sbostic 			base = 8;
180*34235Sbostic 			if (!reg_ulong || !alternate)
181*34235Sbostic 				goto num1;
182*34235Sbostic 			bp = buf + sizeof(buf) - 1;
183*34235Sbostic 			do {
184*34235Sbostic 				*bp-- = digs[reg_ulong % base];
185*34235Sbostic 				reg_ulong /= base;
186*34235Sbostic 			} while(reg_ulong);
187*34235Sbostic 			size = &buf[sizeof(buf) - 1] - bp;
188*34235Sbostic 			if (size < --width && !ladjust)
189*34235Sbostic 				do {
190*34235Sbostic 					PUTC(padc, fp);
191*34235Sbostic 				} while (--width > size);
192*34235Sbostic 			PUTC('0', fp);
193*34235Sbostic 			goto num3;
194*34235Sbostic 			break;
195*34235Sbostic 		case 'p':
19634226Sbostic 		case 's':
197*34235Sbostic 			if (!(bp = va_arg(argp, char *)))
198*34235Sbostic 				bp = "(null)";
199*34235Sbostic 			if (width > 0 && !ladjust) {
20034233Sbostic 				char *savep;
20134226Sbostic 
202*34235Sbostic 				savep = bp;
203*34235Sbostic 				for (n = 0; *bp && (prec < 0 || n < prec);
204*34235Sbostic 				    n++, bp++);
205*34235Sbostic 				bp = savep;
206*34235Sbostic 				while (n++ < width)
207*34235Sbostic 					PUTC(' ', fp);
20834233Sbostic 			}
209*34235Sbostic 			for (n = 0; *bp; ++bp) {
210*34235Sbostic 				if (++n > prec && prec >= 0)
21134226Sbostic 					break;
212*34235Sbostic 				PUTC(*bp, fp);
21334233Sbostic 			}
214*34235Sbostic 			if (n < width && ladjust)
21534233Sbostic 				do {
216*34235Sbostic 					PUTC(' ', fp);
217*34235Sbostic 				} while (++n < width);
21834226Sbostic 			break;
21934226Sbostic 		case 'u':
220*34235Sbostic 			GETARG(reg_ulong);
22134226Sbostic 			base = 10;
222*34235Sbostic 			goto num1;
22334226Sbostic 		case 'X':
22434226Sbostic 			digs = "0123456789ABCDEF";
22534233Sbostic 			/*FALLTHROUGH*/
22634226Sbostic 		case 'x':
227*34235Sbostic 			GETARG(reg_ulong);
22834233Sbostic 			if (alternate && reg_ulong) {
229*34235Sbostic 				PUTC('0', fp);
230*34235Sbostic 				PUTC(*fmt, fp);
23134233Sbostic 			}
23234226Sbostic 			base = 16;
233*34235Sbostic num1:			bp = buf + sizeof(buf) - 1;
23434233Sbostic 			do {
235*34235Sbostic 				*bp-- = digs[reg_ulong % base];
23634233Sbostic 				reg_ulong /= base;
23734233Sbostic 			} while(reg_ulong);
238*34235Sbostic 			size = &buf[sizeof(buf) - 1] - bp;
239*34235Sbostic 			for (; size < prec; *bp-- = '0', ++size);
240*34235Sbostic 			if (size < width && !ladjust)
241*34235Sbostic 				do {
242*34235Sbostic 					PUTC(padc, fp);
243*34235Sbostic 				} while (--width > size);
244*34235Sbostic num3:			while (++bp != &buf[MAXBUF])
245*34235Sbostic 				PUTC(*bp, fp);
246*34235Sbostic 			for (; width > size; --width)
247*34235Sbostic 				PUTC(padc, fp);
24834226Sbostic 			break;
24934233Sbostic 		case '\0':		/* "%?" prints ?, unless ? is NULL */
250*34235Sbostic 			return(ferror(fp) ? -1 : cnt);
25134226Sbostic 		default:
252*34235Sbostic 			PUTC(*fmt, fp);
25334226Sbostic 		}
25434226Sbostic 	}
255*34235Sbostic 	return(ferror(fp) ? -1 : cnt);
25634226Sbostic }
257*34235Sbostic 
258