xref: /csrg-svn/usr.bin/printf/printf.c (revision 36725)
1*36725Sbostic /*
2*36725Sbostic  * Copyright (c) 1989 The Regents of the University of California.
3*36725Sbostic  * All rights reserved.
4*36725Sbostic  *
5*36725Sbostic  * Redistribution and use in source and binary forms are permitted
6*36725Sbostic  * provided that the above copyright notice and this paragraph are
7*36725Sbostic  * duplicated in all such forms and that any documentation,
8*36725Sbostic  * advertising materials, and other materials related to such
9*36725Sbostic  * distribution and use acknowledge that the software was developed
10*36725Sbostic  * by the University of California, Berkeley.  The name of the
11*36725Sbostic  * University may not be used to endorse or promote products derived
12*36725Sbostic  * from this software without specific prior written permission.
13*36725Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*36725Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*36725Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*36725Sbostic  */
17*36725Sbostic 
18*36725Sbostic #ifndef lint
19*36725Sbostic char copyright[] =
20*36725Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
21*36725Sbostic  All rights reserved.\n";
22*36725Sbostic #endif /* not lint */
23*36725Sbostic 
24*36725Sbostic #ifndef lint
25*36725Sbostic static char sccsid[] = "@(#)printf.c	5.1 (Berkeley) 02/12/89";
26*36725Sbostic #endif /* not lint */
27*36725Sbostic 
28*36725Sbostic #include <sys/types.h>
29*36725Sbostic #include <stdio.h>
30*36725Sbostic 
31*36725Sbostic #define PF(f, func) { \
32*36725Sbostic 	if (fieldwidth) \
33*36725Sbostic 		if (precision) \
34*36725Sbostic 			cnt += printf(f, fieldwidth, precision, func); \
35*36725Sbostic 		else \
36*36725Sbostic 			cnt += printf(f, fieldwidth, func); \
37*36725Sbostic 	else if (precision) \
38*36725Sbostic 		cnt += printf(f, precision, func); \
39*36725Sbostic 	else \
40*36725Sbostic 		cnt += printf(f, func); \
41*36725Sbostic }
42*36725Sbostic 
43*36725Sbostic char **gargv;
44*36725Sbostic 
45*36725Sbostic main(argc, argv)
46*36725Sbostic 	int argc;
47*36725Sbostic 	char **argv;
48*36725Sbostic {
49*36725Sbostic 	static char *skip1, *skip2;
50*36725Sbostic 	register char *format, *fmt, *start;
51*36725Sbostic 	register int end, cnt, fieldwidth, precision;
52*36725Sbostic 	char convch, nextch, *getstr(), *index(), *mklong();
53*36725Sbostic 	double getdouble();
54*36725Sbostic 	long getlong();
55*36725Sbostic 
56*36725Sbostic 	if (argc < 2) {
57*36725Sbostic 		fprintf(stderr, "usage: printf format [arg ...]\n");
58*36725Sbostic 		exit(0);
59*36725Sbostic 	}
60*36725Sbostic 
61*36725Sbostic 	/*
62*36725Sbostic 	 * Basic algorithm is to scan the format string for conversion
63*36725Sbostic 	 * specifications -- once one is found, find out if the field
64*36725Sbostic 	 * width or precision is a '*'; if it is, gather up value.  Note,
65*36725Sbostic 	 * format strings are reused as necessary to use up the provided
66*36725Sbostic 	 * arguments, arguments of zero/null string are provided to use
67*36725Sbostic 	 * up the format string.
68*36725Sbostic 	 */
69*36725Sbostic 	skip1 = "#-+ 0";
70*36725Sbostic 	skip2 = "*0123456789";
71*36725Sbostic 
72*36725Sbostic 	escape(fmt = format = *++argv);		/* backslash interpretation */
73*36725Sbostic 	gargv = ++argv;
74*36725Sbostic 	for (cnt = 0;;) {
75*36725Sbostic 		end = 0;
76*36725Sbostic 		/* find next format specification */
77*36725Sbostic next:		for (start = fmt;; ++fmt) {
78*36725Sbostic 			if (!*fmt) {
79*36725Sbostic 				/* avoid infinite loop */
80*36725Sbostic 				if (end == 1) {
81*36725Sbostic 					fprintf(stderr,
82*36725Sbostic 					    "printf: missing format character.\n");
83*36725Sbostic 					exit(0);
84*36725Sbostic 				}
85*36725Sbostic 				end = 1;
86*36725Sbostic 				if (fmt > start)
87*36725Sbostic 					cnt += printf("%s", start);
88*36725Sbostic 				if (!*gargv)
89*36725Sbostic 					exit(cnt);
90*36725Sbostic 				fmt = format;
91*36725Sbostic 				goto next;
92*36725Sbostic 			}
93*36725Sbostic 			/* %% prints a % */
94*36725Sbostic 			if (*fmt == '%' && *++fmt != '%')
95*36725Sbostic 				break;
96*36725Sbostic 		}
97*36725Sbostic 
98*36725Sbostic 		/* skip to field width */
99*36725Sbostic 		for (; index(skip1, *fmt); ++fmt);
100*36725Sbostic 		if (*fmt == '*')
101*36725Sbostic 			fieldwidth = getint();
102*36725Sbostic 		/* skip to possible '.' */
103*36725Sbostic 		for (; index(skip2, *fmt); ++fmt);
104*36725Sbostic 		if (*fmt == '.')
105*36725Sbostic 			++fmt;
106*36725Sbostic 		if (*fmt == '*')
107*36725Sbostic 			precision = getint();
108*36725Sbostic 		/* skip to conversion char */
109*36725Sbostic 		for (; index(skip2, *fmt); ++fmt);
110*36725Sbostic 		if (!*fmt) {
111*36725Sbostic 			fprintf(stderr, "printf: missing format character.\n");
112*36725Sbostic 			exit(-1);
113*36725Sbostic 		}
114*36725Sbostic 
115*36725Sbostic 		convch = *fmt;
116*36725Sbostic 		nextch = *++fmt;
117*36725Sbostic 		*fmt = '\0';
118*36725Sbostic 		switch(convch) {
119*36725Sbostic 		case 'c': {
120*36725Sbostic 			char p = getchr();
121*36725Sbostic 			PF(start, p);
122*36725Sbostic 			break;
123*36725Sbostic 		}
124*36725Sbostic 		case 's': {
125*36725Sbostic 			char *p = getstr();
126*36725Sbostic 			PF(start, p);
127*36725Sbostic 			break;
128*36725Sbostic 		}
129*36725Sbostic 		case 'd': case 'o': case 'u': case 'x': case 'X': {
130*36725Sbostic 			char *f = mklong(start, convch);
131*36725Sbostic 			long p = getlong();
132*36725Sbostic 			PF(f, p);
133*36725Sbostic 			break;
134*36725Sbostic 		}
135*36725Sbostic 		case 'e': case 'E': case 'f': case 'g': case 'G': {
136*36725Sbostic 			double p = getdouble();
137*36725Sbostic 			PF(start, p);
138*36725Sbostic 			break;
139*36725Sbostic 		}
140*36725Sbostic 		default:
141*36725Sbostic 			fprintf(stderr, "printf: illegal format character.\n");
142*36725Sbostic 			exit(-1);
143*36725Sbostic 		}
144*36725Sbostic 		*fmt = nextch;
145*36725Sbostic 	}
146*36725Sbostic 	/* NOTREACHED */
147*36725Sbostic }
148*36725Sbostic 
149*36725Sbostic char *
150*36725Sbostic mklong(str, ch)
151*36725Sbostic 	char *str, ch;
152*36725Sbostic {
153*36725Sbostic 	int len;
154*36725Sbostic 	char *copy, *malloc();
155*36725Sbostic 
156*36725Sbostic 	len = strlen(str) + 2;
157*36725Sbostic 	if (!(copy = malloc((u_int)len))) {	/* never freed; XXX */
158*36725Sbostic 		fprintf(stderr, "printf: out of memory.\n");
159*36725Sbostic 		exit(-1);
160*36725Sbostic 	}
161*36725Sbostic 	bcopy(str, copy, len - 3);
162*36725Sbostic 	copy[len - 3] = 'l';
163*36725Sbostic 	copy[len - 2] = ch;
164*36725Sbostic 	copy[len - 1] = '\0';
165*36725Sbostic 	return(copy);
166*36725Sbostic }
167*36725Sbostic 
168*36725Sbostic escape(fmt)
169*36725Sbostic 	register char *fmt;
170*36725Sbostic {
171*36725Sbostic 	register char *store;
172*36725Sbostic 	register int value, c;
173*36725Sbostic 
174*36725Sbostic 	for (store = fmt; c = *fmt; ++fmt, ++store) {
175*36725Sbostic 		if (c != '\\') {
176*36725Sbostic 			*store = c;
177*36725Sbostic 			continue;
178*36725Sbostic 		}
179*36725Sbostic 		switch (*++fmt) {
180*36725Sbostic 		case '\0':		/* EOS, user error */
181*36725Sbostic 			*store = '\\';
182*36725Sbostic 			*++store = '\0';
183*36725Sbostic 			return;
184*36725Sbostic 		case '\\':		/* backslash */
185*36725Sbostic 			*store = '\\';
186*36725Sbostic 			break;
187*36725Sbostic 		case 'a':		/* bell/alert */
188*36725Sbostic 			*store = '\7';
189*36725Sbostic 			break;
190*36725Sbostic 		case 'b':		/* backspace */
191*36725Sbostic 			*store = '\b';
192*36725Sbostic 			break;
193*36725Sbostic 		case 'f':		/* form-feed */
194*36725Sbostic 			*store = '\f';
195*36725Sbostic 			break;
196*36725Sbostic 		case 'n':		/* newline */
197*36725Sbostic 			*store = '\n';
198*36725Sbostic 			break;
199*36725Sbostic 		case 'r':		/* carriage-return */
200*36725Sbostic 			*store = '\r';
201*36725Sbostic 			break;
202*36725Sbostic 		case 't':		/* horizontal tab */
203*36725Sbostic 			*store = '\t';
204*36725Sbostic 			break;
205*36725Sbostic 		case 'v':		/* vertical tab */
206*36725Sbostic 			*store = '\13';
207*36725Sbostic 			break;
208*36725Sbostic 					/* octal constant */
209*36725Sbostic 		case '0': case '1': case '2': case '3':
210*36725Sbostic 		case '4': case '5': case '6': case '7':
211*36725Sbostic 			for (c = 3, value = 0;
212*36725Sbostic 			    c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
213*36725Sbostic 				value <<= 3;
214*36725Sbostic 				value += *fmt - '0';
215*36725Sbostic 			}
216*36725Sbostic 			--fmt;
217*36725Sbostic 			*store = value;
218*36725Sbostic 			break;
219*36725Sbostic 		default:
220*36725Sbostic 			*store = *fmt;
221*36725Sbostic 			break;
222*36725Sbostic 		}
223*36725Sbostic 	}
224*36725Sbostic 	*store = '\0';
225*36725Sbostic }
226*36725Sbostic 
227*36725Sbostic getchr()
228*36725Sbostic {
229*36725Sbostic 	if (!*gargv)
230*36725Sbostic 		return((int)'\0');
231*36725Sbostic 	return((int)**gargv++);
232*36725Sbostic }
233*36725Sbostic 
234*36725Sbostic char *
235*36725Sbostic getstr()
236*36725Sbostic {
237*36725Sbostic 	if (!*gargv)
238*36725Sbostic 		return("");
239*36725Sbostic 	return(*gargv++);
240*36725Sbostic }
241*36725Sbostic 
242*36725Sbostic static char *number = "+-0123456789";
243*36725Sbostic getint()
244*36725Sbostic {
245*36725Sbostic 	if (!*gargv)
246*36725Sbostic 		return(0);
247*36725Sbostic 	if (index(number, **gargv))
248*36725Sbostic 		return(atoi(*gargv++));
249*36725Sbostic 	return(asciicode());
250*36725Sbostic }
251*36725Sbostic 
252*36725Sbostic long
253*36725Sbostic getlong()
254*36725Sbostic {
255*36725Sbostic 	long atol();
256*36725Sbostic 
257*36725Sbostic 	if (!*gargv)
258*36725Sbostic 		return((long)0);
259*36725Sbostic 	if (index(number, **gargv))
260*36725Sbostic 		return(atol(*gargv++));
261*36725Sbostic 	return((long)asciicode());
262*36725Sbostic }
263*36725Sbostic 
264*36725Sbostic double
265*36725Sbostic getdouble()
266*36725Sbostic {
267*36725Sbostic 	double atof();
268*36725Sbostic 
269*36725Sbostic 	if (!*gargv)
270*36725Sbostic 		return((double)0);
271*36725Sbostic 	if (index(number, **gargv))
272*36725Sbostic 		return(atof(*gargv++));
273*36725Sbostic 	return((double)asciicode());
274*36725Sbostic }
275*36725Sbostic 
276*36725Sbostic asciicode()
277*36725Sbostic {
278*36725Sbostic 	register char ch;
279*36725Sbostic 
280*36725Sbostic 	ch = **gargv;
281*36725Sbostic 	if (ch == '\'' || ch == '"')
282*36725Sbostic 		ch = (*gargv)[1];
283*36725Sbostic 	++gargv;
284*36725Sbostic 	return(ch);
285*36725Sbostic }
286