xref: /csrg-svn/lib/libc/stdio/vfprintf.c (revision 34226)
1*34226Sbostic From stevesu@copper.UUCP Wed Mar 25 23:35:32 1987
2*34226Sbostic Path: seismo!ut-sally!husc6!bacchus!mit-eddie!genrad!decvax!tektronix!teklds!copper!stevesu
3*34226Sbostic From: stevesu@copper.TEK.COM (Steve Summit)
4*34226Sbostic Newsgroups: net.sources
5*34226Sbostic Subject: Public Domain _doprnt in C
6*34226Sbostic Message-ID: <938@copper.TEK.COM>
7*34226Sbostic Date: 26 Mar 87 04:35:32 GMT
8*34226Sbostic Reply-To: stevesu@copper.UUCP (Steve Summit)
9*34226Sbostic Distribution: world
10*34226Sbostic Organization: Tektronix, Inc., Beaverton, OR.
11*34226Sbostic Lines: 420
12*34226Sbostic 
13*34226Sbostic Mark Pulver is looking for a C version of _doprnt, so I thought
14*34226Sbostic I'd pass mine along.  I wrote this from the ground up; it is
15*34226Sbostic absolutely underived from anything proprietary.
16*34226Sbostic 
17*34226Sbostic This version is not complete, and has the following two key
18*34226Sbostic omissions:
19*34226Sbostic 
20*34226Sbostic 	It doesn't do floating point (%f, %e, or %g).
21*34226Sbostic 
22*34226Sbostic 	It will handle %ld (%lx, etc.) incorrectly on machines
23*34226Sbostic 	where sizeof(long) != sizeof(int).
24*34226Sbostic 
25*34226Sbostic It also does not implement the %# stuff which appeared in the 4.2
26*34226Sbostic documentation but which I haven't seen in any implementation yet.
27*34226Sbostic 
28*34226Sbostic I believe it handles everything else correctly, although I have
29*34226Sbostic not tested it exhaustively.
30*34226Sbostic 
31*34226Sbostic There are two "fun" additions: %b is binary, and %r is roman.
32*34226Sbostic 
33*34226Sbostic You are free to use this code as you wish, but please leave the
34*34226Sbostic identification comment intact.  I can offer no support for this
35*34226Sbostic code, although if I ever implement floating point or pdp11
36*34226Sbostic support (I'm acutely embarrassed to admit making the typical VAX
37*34226Sbostic int/long equivalence assumption) I'll try to remember to post
38*34226Sbostic those additions.
39*34226Sbostic 
40*34226Sbostic                                            Steve Summit
41*34226Sbostic                                            stevesu@copper.tek.com
42*34226Sbostic 
43*34226Sbostic --------------------- cut here for doprnt.c ---------------------
44*34226Sbostic /*
45*34226Sbostic  *  Common code for printf et al.
46*34226Sbostic  *
47*34226Sbostic  *  The calling routine typically takes a variable number of arguments,
48*34226Sbostic  *  and passes the address of the first one.  This implementation
49*34226Sbostic  *  assumes a straightforward, stack implementation, aligned to the
50*34226Sbostic  *  machine's wordsize.  Increasing addresses are assumed to point to
51*34226Sbostic  *  successive arguments (left-to-right), as is the case for a machine
52*34226Sbostic  *  with a downward-growing stack with arguments pushed right-to-left.
53*34226Sbostic  *
54*34226Sbostic  *  To write, for example, fprintf() using this routine, the code
55*34226Sbostic  *
56*34226Sbostic  *	fprintf(fd, format, args)
57*34226Sbostic  *	FILE *fd;
58*34226Sbostic  *	char *format;
59*34226Sbostic  *	{
60*34226Sbostic  *	_doprnt(format, &args, fd);
61*34226Sbostic  *	}
62*34226Sbostic  *
63*34226Sbostic  *  would suffice.  (This example does not handle the fprintf's "return
64*34226Sbostic  *  value" correctly, but who looks at the return value of fprintf
65*34226Sbostic  *  anyway?)
66*34226Sbostic  *
67*34226Sbostic  *  This version implements the following printf features:
68*34226Sbostic  *
69*34226Sbostic  *	%d	decimal conversion
70*34226Sbostic  *	%u	unsigned conversion
71*34226Sbostic  *	%x	hexadecimal conversion
72*34226Sbostic  *	%X	hexadecimal conversion with capital letters
73*34226Sbostic  *	%o	octal conversion
74*34226Sbostic  *	%c	character
75*34226Sbostic  *	%s	string
76*34226Sbostic  *	%m.n	field width, precision
77*34226Sbostic  *	%-m.n	left adjustment
78*34226Sbostic  *	%0m.n	zero-padding
79*34226Sbostic  *	%*.*	width and precision taken from arguments
80*34226Sbostic  *
81*34226Sbostic  *  This version does not implement %f, %e, or %g.  It accepts, but
82*34226Sbostic  *  ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
83*34226Sbostic  *  work correctly on machines for which sizeof(long) != sizeof(int).
84*34226Sbostic  *  It does not even parse %D, %O, or %U; you should be using %ld, %o and
85*34226Sbostic  *  %lu if you mean long conversion.
86*34226Sbostic  *
87*34226Sbostic  *  This version implements the following nonstandard features:
88*34226Sbostic  *
89*34226Sbostic  *	%b	binary conversion
90*34226Sbostic  *	%r	roman numeral conversion
91*34226Sbostic  *	%R	roman numeral conversion with capital letters
92*34226Sbostic  *
93*34226Sbostic  *  As mentioned, this version does not return any reasonable value.
94*34226Sbostic  *
95*34226Sbostic  *  Permission is granted to use, modify, or propagate this code as
96*34226Sbostic  *  long as this notice is incorporated.
97*34226Sbostic  *
98*34226Sbostic  *  Steve Summit 3/25/87
99*34226Sbostic  */
100*34226Sbostic 
101*34226Sbostic #include <stdio.h>
102*34226Sbostic 
103*34226Sbostic #define TRUE 1
104*34226Sbostic #define FALSE 0
105*34226Sbostic 
106*34226Sbostic #define ROMAN
107*34226Sbostic 
108*34226Sbostic #define isdigit(d) ((d) >= '0' && (d) <= '9')
109*34226Sbostic #define Ctod(c) ((c) - '0')
110*34226Sbostic 
111*34226Sbostic #define MAXBUF (sizeof(long int) * 8)		 /* enough for binary */
112*34226Sbostic 
113*34226Sbostic #ifdef ROMAN
114*34226Sbostic static tack();
115*34226Sbostic static doit();
116*34226Sbostic #endif
117*34226Sbostic 
118*34226Sbostic _doprnt(fmt, argp, fd)
119*34226Sbostic register char *fmt;
120*34226Sbostic register int *argp;
121*34226Sbostic FILE *fd;
122*34226Sbostic {
123*34226Sbostic register char *p;
124*34226Sbostic char *p2;
125*34226Sbostic int size;
126*34226Sbostic int length;
127*34226Sbostic int prec;
128*34226Sbostic int ladjust;
129*34226Sbostic char padc;
130*34226Sbostic int n;
131*34226Sbostic unsigned int u;
132*34226Sbostic int base;
133*34226Sbostic char buf[MAXBUF];
134*34226Sbostic int negflag;
135*34226Sbostic char *digs;
136*34226Sbostic #ifdef ROMAN
137*34226Sbostic char *rdigs;
138*34226Sbostic int d;
139*34226Sbostic #endif
140*34226Sbostic 
141*34226Sbostic while(*fmt != '\0')
142*34226Sbostic 	{
143*34226Sbostic 	if(*fmt != '%')
144*34226Sbostic 		{
145*34226Sbostic 		putc(*fmt++, fd);
146*34226Sbostic 		continue;
147*34226Sbostic 		}
148*34226Sbostic 
149*34226Sbostic 	fmt++;
150*34226Sbostic 
151*34226Sbostic 	if(*fmt == 'l')
152*34226Sbostic 		fmt++;	     /* need to use it if sizeof(int) < sizeof(long) */
153*34226Sbostic 
154*34226Sbostic 	length = 0;
155*34226Sbostic 	prec = -1;
156*34226Sbostic 	ladjust = FALSE;
157*34226Sbostic 	padc = ' ';
158*34226Sbostic 
159*34226Sbostic 	if(*fmt == '-')
160*34226Sbostic 		{
161*34226Sbostic 		ladjust = TRUE;
162*34226Sbostic 		fmt++;
163*34226Sbostic 		}
164*34226Sbostic 
165*34226Sbostic 	if(*fmt == '0')
166*34226Sbostic 		{
167*34226Sbostic 		padc = '0';
168*34226Sbostic 		fmt++;
169*34226Sbostic 		}
170*34226Sbostic 
171*34226Sbostic 	if(isdigit(*fmt))
172*34226Sbostic 		{
173*34226Sbostic 		while(isdigit(*fmt))
174*34226Sbostic 			length = 10 * length + Ctod(*fmt++);
175*34226Sbostic 		}
176*34226Sbostic 	else if(*fmt == '*')
177*34226Sbostic 		{
178*34226Sbostic 		length = *argp++;
179*34226Sbostic 		fmt++;
180*34226Sbostic 		if(length < 0)
181*34226Sbostic 			{
182*34226Sbostic 			ladjust = !ladjust;
183*34226Sbostic 			length = -length;
184*34226Sbostic 			}
185*34226Sbostic 		}
186*34226Sbostic 
187*34226Sbostic 	if(*fmt == '.')
188*34226Sbostic 		{
189*34226Sbostic 		fmt++;
190*34226Sbostic 		if(isdigit(*fmt))
191*34226Sbostic 			{
192*34226Sbostic 			prec = 0;
193*34226Sbostic 			while(isdigit(*fmt))
194*34226Sbostic 				prec = 10 * prec + Ctod(*fmt++);
195*34226Sbostic 			}
196*34226Sbostic 		else if(*fmt == '*')
197*34226Sbostic 			{
198*34226Sbostic 			prec = *argp++;
199*34226Sbostic 			fmt++;
200*34226Sbostic 			}
201*34226Sbostic 		}
202*34226Sbostic 
203*34226Sbostic 	negflag = FALSE;
204*34226Sbostic 	digs = "0123456789abcdef";
205*34226Sbostic #ifdef ROMAN
206*34226Sbostic 	rdigs = "  mdclxvi";
207*34226Sbostic #endif
208*34226Sbostic 
209*34226Sbostic 	switch(*fmt)
210*34226Sbostic 		{
211*34226Sbostic 		case 'b':
212*34226Sbostic 		case 'B':
213*34226Sbostic 			u = *argp++;
214*34226Sbostic 			base = 2;
215*34226Sbostic 			goto donum;
216*34226Sbostic 
217*34226Sbostic 		case 'c':
218*34226Sbostic 			putc(*argp++, fd);
219*34226Sbostic 			break;
220*34226Sbostic 
221*34226Sbostic 		case 'd':
222*34226Sbostic 		case 'D':
223*34226Sbostic 			n = *argp++;
224*34226Sbostic 
225*34226Sbostic 			if(n >= 0)
226*34226Sbostic 				u = n;
227*34226Sbostic 			else	{
228*34226Sbostic 				u = -n;
229*34226Sbostic 				negflag = TRUE;
230*34226Sbostic 				}
231*34226Sbostic 
232*34226Sbostic 			base = 10;
233*34226Sbostic 
234*34226Sbostic 			goto donum;
235*34226Sbostic 
236*34226Sbostic 		case 'o':
237*34226Sbostic 		case 'O':
238*34226Sbostic 			u = *argp++;
239*34226Sbostic 			base = 8;
240*34226Sbostic 			goto donum;
241*34226Sbostic #ifdef ROMAN
242*34226Sbostic 		case 'R':
243*34226Sbostic 			rdigs = "  MDCLXVI";
244*34226Sbostic 		case 'r':
245*34226Sbostic 			n = *argp++;
246*34226Sbostic 			p2 = &buf[MAXBUF - 1];
247*34226Sbostic 
248*34226Sbostic 			d = n % 10;
249*34226Sbostic 			tack(d, &rdigs[6], &p2);
250*34226Sbostic 			n = n / 10;
251*34226Sbostic 
252*34226Sbostic 			d = n % 10;
253*34226Sbostic 			tack(d, &rdigs[4], &p2);
254*34226Sbostic 			n = n / 10;
255*34226Sbostic 
256*34226Sbostic 			d = n % 10;
257*34226Sbostic 			tack(d, &rdigs[2], &p2);
258*34226Sbostic 			n /= 10;
259*34226Sbostic 
260*34226Sbostic 			d = n % 10;
261*34226Sbostic 			tack(d, rdigs, &p2);
262*34226Sbostic 
263*34226Sbostic 			p = p2;
264*34226Sbostic 
265*34226Sbostic 			goto putpad;
266*34226Sbostic #endif
267*34226Sbostic 		case 's':
268*34226Sbostic 			p = (char *)(*argp++);
269*34226Sbostic 
270*34226Sbostic 			if(p == NULL)
271*34226Sbostic 				p = "(NULL)";
272*34226Sbostic 
273*34226Sbostic 			if(length > 0 && !ladjust)
274*34226Sbostic 				{
275*34226Sbostic 				n = 0;
276*34226Sbostic 				p2 = p;
277*34226Sbostic 
278*34226Sbostic 				for(; *p != '\0' &&
279*34226Sbostic 						(prec == -1 || n < prec); p++)
280*34226Sbostic 					n++;
281*34226Sbostic 
282*34226Sbostic 				p = p2;
283*34226Sbostic 
284*34226Sbostic 				while(n < length)
285*34226Sbostic 					{
286*34226Sbostic 					putc(' ', fd);
287*34226Sbostic 					n++;
288*34226Sbostic 					}
289*34226Sbostic 				}
290*34226Sbostic 
291*34226Sbostic 			n = 0;
292*34226Sbostic 
293*34226Sbostic 			while(*p != '\0')
294*34226Sbostic 				{
295*34226Sbostic 				if(++n > prec && prec != -1)
296*34226Sbostic 					break;
297*34226Sbostic 
298*34226Sbostic 				putc(*p++, fd);
299*34226Sbostic 				}
300*34226Sbostic 
301*34226Sbostic 			if(n < length && ladjust)
302*34226Sbostic 				{
303*34226Sbostic 				while(n < length)
304*34226Sbostic 					{
305*34226Sbostic 					putc(' ', fd);
306*34226Sbostic 					n++;
307*34226Sbostic 					}
308*34226Sbostic 				}
309*34226Sbostic 
310*34226Sbostic 			break;
311*34226Sbostic 
312*34226Sbostic 		case 'u':
313*34226Sbostic 		case 'U':
314*34226Sbostic 			u = *argp++;
315*34226Sbostic 			base = 10;
316*34226Sbostic 			goto donum;
317*34226Sbostic 
318*34226Sbostic 		case 'X':
319*34226Sbostic 			digs = "0123456789ABCDEF";
320*34226Sbostic 		case 'x':
321*34226Sbostic 			u = *argp++;
322*34226Sbostic 			base = 16;
323*34226Sbostic 
324*34226Sbostic donum:			p = &buf[MAXBUF - 1];
325*34226Sbostic 
326*34226Sbostic 			do	{
327*34226Sbostic 				*p-- = digs[u % base];
328*34226Sbostic 				u /= base;
329*34226Sbostic 				} while(u != 0);
330*34226Sbostic 
331*34226Sbostic 			if(negflag)
332*34226Sbostic 				putc('-', fd);
333*34226Sbostic putpad:
334*34226Sbostic 			size = &buf[MAXBUF - 1] - p;
335*34226Sbostic 
336*34226Sbostic 			if(size < length && !ladjust)
337*34226Sbostic 				{
338*34226Sbostic 				while(length > size)
339*34226Sbostic 					{
340*34226Sbostic 					putc(padc, fd);
341*34226Sbostic 					length--;
342*34226Sbostic 					}
343*34226Sbostic 				}
344*34226Sbostic 
345*34226Sbostic 			while(++p != &buf[MAXBUF])
346*34226Sbostic 				putc(*p, fd);
347*34226Sbostic 
348*34226Sbostic 			if(size < length)	/* must be ladjust */
349*34226Sbostic 				{
350*34226Sbostic 				while(length > size)
351*34226Sbostic 					{
352*34226Sbostic 					putc(padc, fd);
353*34226Sbostic 					length--;
354*34226Sbostic 					}
355*34226Sbostic 				}
356*34226Sbostic 
357*34226Sbostic 			break;
358*34226Sbostic 
359*34226Sbostic 		case '\0':
360*34226Sbostic 			fmt--;
361*34226Sbostic 			break;
362*34226Sbostic 
363*34226Sbostic 		default:
364*34226Sbostic 			putc(*fmt, fd);
365*34226Sbostic 		}
366*34226Sbostic 	fmt++;
367*34226Sbostic 	}
368*34226Sbostic }
369*34226Sbostic 
370*34226Sbostic #ifdef ROMAN
371*34226Sbostic 
372*34226Sbostic static
373*34226Sbostic tack(d, digs, p)
374*34226Sbostic int d;
375*34226Sbostic char *digs;
376*34226Sbostic char **p;
377*34226Sbostic {
378*34226Sbostic if(d == 0) return;
379*34226Sbostic if(d >= 1 && d <= 3)
380*34226Sbostic 	{
381*34226Sbostic 	doit(d, digs[2], p);
382*34226Sbostic 	return;
383*34226Sbostic 	}
384*34226Sbostic 
385*34226Sbostic if(d == 4 || d == 5)
386*34226Sbostic 	{
387*34226Sbostic 	**p = digs[1];
388*34226Sbostic 	(*p)--;
389*34226Sbostic 	}
390*34226Sbostic 
391*34226Sbostic if(d == 4)
392*34226Sbostic 	{
393*34226Sbostic 	**p = digs[2];
394*34226Sbostic 	(*p)--;
395*34226Sbostic 	return;
396*34226Sbostic 	}
397*34226Sbostic 
398*34226Sbostic if(d == 5) return;
399*34226Sbostic 
400*34226Sbostic if(d >= 6 && d <= 8)
401*34226Sbostic 	{
402*34226Sbostic 	doit(d - 5, digs[2], p);
403*34226Sbostic 	**p = digs[1];
404*34226Sbostic 	(*p)--;
405*34226Sbostic 	return;
406*34226Sbostic 	}
407*34226Sbostic 
408*34226Sbostic /* d == 9 */
409*34226Sbostic 
410*34226Sbostic **p = digs[0];
411*34226Sbostic (*p)--;
412*34226Sbostic **p = digs[2];
413*34226Sbostic (*p)--;
414*34226Sbostic return;
415*34226Sbostic }
416*34226Sbostic 
417*34226Sbostic static
418*34226Sbostic doit(d, one, p)
419*34226Sbostic int d;
420*34226Sbostic char one;
421*34226Sbostic char **p;
422*34226Sbostic {
423*34226Sbostic int i;
424*34226Sbostic 
425*34226Sbostic for(i = 0; i < d; i++)
426*34226Sbostic 	{
427*34226Sbostic 	**p = one;
428*34226Sbostic 	(*p)--;
429*34226Sbostic 	}
430*34226Sbostic }
431*34226Sbostic 
432*34226Sbostic #endif
433