xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 34233)
134226Sbostic /*
2*34233Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*34233Sbostic  * All rights reserved.
434226Sbostic  *
5*34233Sbostic  * Redistribution and use in source and binary forms are permitted
6*34233Sbostic  * provided that this notice is preserved and that due credit is given
7*34233Sbostic  * to the University of California at Berkeley. The name of the University
8*34233Sbostic  * may not be used to endorse or promote products derived from this
9*34233Sbostic  * software without specific prior written permission. This software
10*34233Sbostic  * is provided ``as is'' without express or implied warranty.
1134226Sbostic  *
12*34233Sbostic  * Originally derived from code posted by Steve Summit to USENET,
13*34233Sbostic  * dated 3/25/87
1434226Sbostic  */
1534226Sbostic 
16*34233Sbostic #if defined(LIBC_SCCS) && !defined(lint)
17*34233Sbostic static char sccsid[] = "@(#)vfprintf.c	5.2 (Berkeley) 05/07/88";
18*34233Sbostic #endif /* LIBC_SCCS and not lint */
19*34233Sbostic 
20*34233Sbostic #include <sys/param.h>
21*34233Sbostic #include <varargs.h>
2234226Sbostic #include <stdio.h>
23*34233Sbostic #include <ctype.h>
2434226Sbostic 
25*34233Sbostic #define	MAXBUF		(sizeof(long) * 8)	 /* enough for binary */
26*34233Sbostic #define	PUTC(ch, fd)	{ ++cnt; putc(ch, fd); }
27*34233Sbostic #define	todigit(ch)	((ch) - '0')
2834226Sbostic 
29*34233Sbostic doprnt(fmt, argp, fd)
30*34233Sbostic 	register char *fmt;
31*34233Sbostic 	va_list argp;
32*34233Sbostic 	register FILE *fd;
3334226Sbostic {
34*34233Sbostic 	register u_long reg_ulong;
35*34233Sbostic 	register long reg_long;
36*34233Sbostic 	register int base;
37*34233Sbostic 	register char *digs, *p, padc;
38*34233Sbostic 	char printsign, buf[MAXBUF];
39*34233Sbostic 	int alternate, cnt, n, ladjust, length, setlong, prec, size;
4034226Sbostic 
41*34233Sbostic 	for (cnt = 0; *fmt; ++fmt) {
42*34233Sbostic 		if (*fmt != '%') {
43*34233Sbostic 			PUTC(*fmt, fd);
44*34233Sbostic 			continue;
4534226Sbostic 		}
4634226Sbostic 
47*34233Sbostic 		alternate = ladjust = length = setlong = 0;
48*34233Sbostic 		prec = -1;
49*34233Sbostic 		padc = ' ';
50*34233Sbostic 		printsign = '\0';
5134226Sbostic 
52*34233Sbostic flags:		switch (*++fmt) {
53*34233Sbostic 		case '#':
54*34233Sbostic 			alternate = 1;
55*34233Sbostic 			goto flags;
56*34233Sbostic 		case '%':			/* "%#%" prints as "%" */
57*34233Sbostic 			PUTC('%', fd);
58*34233Sbostic 			continue;
59*34233Sbostic 		case '*':
60*34233Sbostic 			if ((length = va_arg(argp, int)) < 0) {
61*34233Sbostic 				ladjust = !ladjust;
62*34233Sbostic 				length = -length;
6334226Sbostic 			}
64*34233Sbostic 			goto flags;
65*34233Sbostic 		case '+':
66*34233Sbostic 			printsign = '+';
67*34233Sbostic 			goto flags;
68*34233Sbostic 		case '-':
69*34233Sbostic 			ladjust = 1;
70*34233Sbostic 			goto flags;
71*34233Sbostic 		case '.':
72*34233Sbostic 			if (isdigit(*++fmt)) {
73*34233Sbostic 				do {
74*34233Sbostic 					prec = 10 * prec + todigit(*fmt);
75*34233Sbostic 				} while isdigit(*++fmt);
76*34233Sbostic 				--fmt;
7734226Sbostic 			}
78*34233Sbostic 			else if (*fmt == '*')
79*34233Sbostic 				prec = va_arg(argp, int);
80*34233Sbostic 			goto flags;
81*34233Sbostic 		case '0':
82*34233Sbostic 			padc = '0';
83*34233Sbostic 			goto flags;
84*34233Sbostic 		case '1': case '2': case '3': case '4':
85*34233Sbostic 		case '5': case '6': case '7': case '8': case '9':
86*34233Sbostic 			do {
87*34233Sbostic 				length = 10 * length + todigit(*fmt);
88*34233Sbostic 			} while isdigit(*++fmt);
89*34233Sbostic 			--fmt;
90*34233Sbostic 		case 'l':
91*34233Sbostic 			setlong = 1;
92*34233Sbostic 			goto flags;
9334226Sbostic 		}
9434226Sbostic 
95*34233Sbostic 		digs = "0123456789abcdef";
9634226Sbostic 
97*34233Sbostic 		switch (*fmt) {
9834226Sbostic 		case 'c':
99*34233Sbostic 			PUTC(va_arg(argp, int), fd);
10034226Sbostic 			break;
10134226Sbostic 		case 'd':
102*34233Sbostic 			if (setlong)
103*34233Sbostic 				reg_long = va_arg(argp, long);
104*34233Sbostic 			else
105*34233Sbostic 				reg_long = va_arg(argp, int);
106*34233Sbostic 			if (reg_long < 0) {
107*34233Sbostic 				reg_ulong = -reg_long;
108*34233Sbostic 				printsign = '-';
109*34233Sbostic 			}
110*34233Sbostic 			else {
111*34233Sbostic 				reg_ulong = reg_long;
112*34233Sbostic 			}
113*34233Sbostic 			if (printsign)
114*34233Sbostic 				PUTC(printsign, fd);
11534226Sbostic 			base = 10;
11634226Sbostic 			goto donum;
11734226Sbostic 		case 'o':
118*34233Sbostic 			if (setlong)
119*34233Sbostic 				reg_ulong = va_arg(argp, long);
120*34233Sbostic 			else
121*34233Sbostic 				reg_ulong = va_arg(argp, int);
12234226Sbostic 			base = 8;
12334226Sbostic 			goto donum;
12434226Sbostic 		case 's':
125*34233Sbostic 			if (!(p = va_arg(argp, char *)))
126*34233Sbostic 				p = "(null)";
127*34233Sbostic 			if (length > 0 && !ladjust) {
128*34233Sbostic 				char *savep;
12934226Sbostic 
130*34233Sbostic 				savep = p;
131*34233Sbostic 				for (n = 0; *p && (prec == -1 || n < prec);
132*34233Sbostic 				    n++, p++);
133*34233Sbostic 				p = savep;
134*34233Sbostic 				while (n++ < length)
135*34233Sbostic 					PUTC(' ', fd);
136*34233Sbostic 			}
137*34233Sbostic 			for (n = 0; *p; ++p) {
138*34233Sbostic 				if (++n > prec && prec != -1)
13934226Sbostic 					break;
140*34233Sbostic 				PUTC(*p, fd);
141*34233Sbostic 			}
142*34233Sbostic 			if (n < length && ladjust)
143*34233Sbostic 				do {
144*34233Sbostic 					PUTC(' ', fd);
145*34233Sbostic 				} while (++n < length);
14634226Sbostic 			break;
14734226Sbostic 		case 'u':
148*34233Sbostic 			if (setlong)
149*34233Sbostic 				reg_ulong = va_arg(argp, long);
150*34233Sbostic 			else
151*34233Sbostic 				reg_ulong = va_arg(argp, int);
15234226Sbostic 			base = 10;
15334226Sbostic 			goto donum;
15434226Sbostic 		case 'X':
15534226Sbostic 			digs = "0123456789ABCDEF";
156*34233Sbostic 			/*FALLTHROUGH*/
15734226Sbostic 		case 'x':
158*34233Sbostic 			if (setlong)
159*34233Sbostic 				reg_ulong = va_arg(argp, long);
160*34233Sbostic 			else
161*34233Sbostic 				reg_ulong = va_arg(argp, int);
162*34233Sbostic 			if (alternate && reg_ulong) {
163*34233Sbostic 				PUTC('0', fd);
164*34233Sbostic 				PUTC(*fmt, fd);
165*34233Sbostic 			}
16634226Sbostic 			base = 16;
167*34233Sbostic donum:			p = &buf[sizeof(buf) - 1];
168*34233Sbostic 			do {
169*34233Sbostic 				*p-- = digs[reg_ulong % base];
170*34233Sbostic 				reg_ulong /= base;
171*34233Sbostic 			} while(reg_ulong);
172*34233Sbostic 			size = &buf[sizeof(buf) - 1] - p;
173*34233Sbostic 			if (reg_ulong && alternate && *fmt == 'o') {
174*34233Sbostic 				if (size < --length && !ladjust)
175*34233Sbostic 					do {
176*34233Sbostic 						PUTC(padc, fd);
177*34233Sbostic 					} while (--length > size);
178*34233Sbostic 				PUTC('0', fd);
179*34233Sbostic 				while (++p != &buf[MAXBUF])
180*34233Sbostic 					PUTC(*p, fd);
181*34233Sbostic 				if (size < length)	/* must be ladjust */
182*34233Sbostic 					for (; length > size; --length)
183*34233Sbostic 						PUTC(padc, fd);
184*34233Sbostic 			}
185*34233Sbostic 			else {
186*34233Sbostic 				if (size < length && !ladjust)
187*34233Sbostic 					do {
188*34233Sbostic 						PUTC(padc, fd);
189*34233Sbostic 					} while (--length > size);
190*34233Sbostic 				while (++p != &buf[MAXBUF])
191*34233Sbostic 					PUTC(*p, fd);
192*34233Sbostic 				if (size < length)	/* must be ladjust */
193*34233Sbostic 					for (; length > size; --length)
194*34233Sbostic 						PUTC(padc, fd);
195*34233Sbostic 			}
19634226Sbostic 			break;
197*34233Sbostic 		case '\0':		/* "%?" prints ?, unless ? is NULL */
198*34233Sbostic 			return(cnt);
19934226Sbostic 		default:
200*34233Sbostic 			PUTC(*fmt, fd);
20134226Sbostic 		}
20234226Sbostic 	}
203*34233Sbostic 	return(cnt);
20434226Sbostic }
205