Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
105 7u83 1
/*
2
 * Copyright (c) 1980 Regents of the University of California.
3
 * All rights reserved.  The Berkeley software License Agreement
4
 * specifies the terms and conditions for redistribution.
5
 */
6
 
7
#if	!defined(lint) && defined(DOSCCS)
8
static char *sccsid = "@(#)printf.c	7.3 (Berkeley) 6/7/85";
9
 
10
/* The pwb version this is based on */
11
static char *printf_id = "@(#) printf.c:2.2 6/5/79";
12
#endif
13
 
14
#include "varargs.h"
15
/*
16
 * This version of printf is compatible with the Version 7 C
17
 * printf. The differences are only minor except that this
18
 * printf assumes it is to print through putchar. Version 7
19
 * printf is more general (and is much larger) and includes
20
 * provisions for floating point.
21
 */
22
 
23
 
24
#define MAXOCT	11	/* Maximum octal digits in a long */
25
#define MAXINT	32767	/* largest normal length positive integer */
26
#define BIG	1000000000  /* largest power of 10 less than an unsigned long */
27
#define MAXDIGS	10	/* number of digits in BIG */
28
 
29
static int width, sign, fill;
30
 
31
char *_p_dconv();
32
 
33
printf(va_alist)
34
	va_dcl
35
{
36
	va_list ap;
37
	register char *fmt;
38
	char fcode;
39
	int prec;
40
	int length,mask1,nbits,n;
41
	long int mask2, num;
42
	register char *bptr;
43
	char *ptr;
44
	char buf[134];
45
 
46
	va_start(ap);
47
	fmt = va_arg(ap,char *);
48
	for (;;) {
49
		/* process format string first */
50
		while ((fcode = *fmt++)!='%') {
51
			/* ordinary (non-%) character */
52
			if (fcode=='\0')
53
				return;
54
			putchar(fcode);
55
		}
56
		/* length modifier: -1 for h, 1 for l, 0 for none */
57
		length = 0;
58
		/* check for a leading - sign */
59
		sign = 0;
60
		if (*fmt == '-') {
61
			sign++;
62
			fmt++;
63
		}
64
		/* a '0' may follow the - sign */
65
		/* this is the requested fill character */
66
		fill = 1;
67
		if (*fmt == '0') {
68
			fill--;
69
			fmt++;
70
		}
71
 
72
		/* Now comes a digit string which may be a '*' */
73
		if (*fmt == '*') {
74
			width = va_arg(ap, int);
75
			if (width < 0) {
76
				width = -width;
77
				sign = !sign;
78
			}
79
			fmt++;
80
		}
81
		else {
82
			width = 0;
83
			while (*fmt>='0' && *fmt<='9')
84
				width = width * 10 + (*fmt++ - '0');
85
		}
86
 
87
		/* maybe a decimal point followed by more digits (or '*') */
88
		if (*fmt=='.') {
89
			if (*++fmt == '*') {
90
				prec = va_arg(ap, int);
91
				fmt++;
92
			}
93
			else {
94
				prec = 0;
95
				while (*fmt>='0' && *fmt<='9')
96
					prec = prec * 10 + (*fmt++ - '0');
97
			}
98
		}
99
		else
100
			prec = -1;
101
 
102
		/*
103
		 * At this point, "sign" is nonzero if there was
104
		 * a sign, "fill" is 0 if there was a leading
105
		 * zero and 1 otherwise, "width" and "prec"
106
		 * contain numbers corresponding to the digit
107
		 * strings before and after the decimal point,
108
		 * respectively, and "fmt" addresses the next
109
		 * character after the whole mess. If there was
110
		 * no decimal point, "prec" will be -1.
111
		 */
112
		switch (*fmt) {
113
			case 'L':
114
			case 'l':
115
				length = 2;
116
				/* no break!! */
117
			case 'h':
118
			case 'H':
119
				length--;
120
				fmt++;
121
				break;
122
		}
123
 
124
		/*
125
		 * At exit from the following switch, we will
126
		 * emit the characters starting at "bptr" and
127
		 * ending at "ptr"-1, unless fcode is '\0'.
128
		 */
129
		switch (fcode = *fmt++) {
130
			/* process characters and strings first */
131
			case 'c':
132
				buf[0] = va_arg(ap, int);
133
				ptr = bptr = &buf[0];
134
				if (buf[0] != '\0')
135
					ptr++;
136
				break;
137
			case 's':
138
				bptr = va_arg(ap,char *);
139
				if (bptr==0)
140
					bptr = "(null pointer)";
141
				if (prec < 0)
142
					prec = MAXINT;
143
				for (n=0; *bptr++ && n < prec; n++) ;
144
				ptr = --bptr;
145
				bptr -= n;
146
				break;
147
			case 'O':
148
				length = 1;
149
				fcode = 'o';
150
				/* no break */
151
			case 'o':
152
			case 'X':
153
			case 'x':
154
				if (length > 0)
155
					num = va_arg(ap,long);
156
				else
157
					num = (unsigned)va_arg(ap,int);
158
				if (fcode=='o') {
159
					mask1 = 0x7;
160
					mask2 = 0x1fffffffL;
161
					nbits = 3;
162
				}
163
				else {
164
					mask1 = 0xf;
165
					mask2 = 0x0fffffffL;
166
					nbits = 4;
167
				}
168
				n = (num!=0);
169
				bptr = buf + MAXOCT + 3;
170
				/* shift and mask for speed */
171
				do
172
				    if (((int) num & mask1) < 10)
173
					*--bptr = ((int) num & mask1) + 060;
174
				    else
175
					*--bptr = ((int) num & mask1) + 0127;
176
				while (num = (num >> nbits) & mask2);
177
 
178
				if (fcode=='o') {
179
					if (n)
180
						*--bptr = '0';
181
				}
182
				else
183
					if (!sign && fill <= 0) {
184
						putchar('0');
185
						putchar(fcode);
186
						width -= 2;
187
					}
188
					else {
189
						*--bptr = fcode;
190
						*--bptr = '0';
191
					}
192
				ptr = buf + MAXOCT + 3;
193
				break;
194
			case 'D':
195
			case 'U':
196
			case 'I':
197
				length = 1;
198
				fcode = fcode + 'a' - 'A';
199
				/* no break */
200
			case 'd':
201
			case 'i':
202
			case 'u':
203
				if (length > 0)
204
					num = va_arg(ap,long);
205
				else {
206
					n = va_arg(ap,int);
207
					if (fcode=='u')
208
						num = (unsigned) n;
209
					else
210
						num = (long) n;
211
				}
212
				if (n = (fcode != 'u' && num < 0))
213
					num = -num;
214
				/* now convert to digits */
215
				bptr = _p_dconv(num, buf);
216
				if (n)
217
					*--bptr = '-';
218
				if (fill == 0)
219
					fill = -1;
220
				ptr = buf + MAXDIGS + 1;
221
				break;
222
			default:
223
				/* not a control character, 
224
				 * print it.
225
				 */
226
				ptr = bptr = &fcode;
227
				ptr++;
228
				break;
229
			}
230
			if (fcode != '\0')
231
				_p_emit(bptr,ptr);
232
	}
233
	va_end(ap);
234
}
235
 
236
/* _p_dconv converts the unsigned long integer "value" to
237
 * printable decimal and places it in "buffer", right-justified.
238
 * The value returned is the address of the first non-zero character,
239
 * or the address of the last character if all are zero.
240
 * The result is NOT null terminated, and is MAXDIGS characters long,
241
 * starting at buffer[1] (to allow for insertion of a sign).
242
 *
243
 * This program assumes it is running on 2's complement machine
244
 * with reasonable overflow treatment.
245
 */
246
char *
247
_p_dconv(value, buffer)
248
	long value;
249
	char *buffer;
250
{
251
	register char *bp;
252
	register int svalue;
253
	int n;
254
	long lval;
255
 
256
	bp = buffer;
257
 
258
	/* zero is a special case */
259
	if (value == 0) {
260
		bp += MAXDIGS;
261
		*bp = '0';
262
		return(bp);
263
	}
264
 
265
	/* develop the leading digit of the value in "n" */
266
	n = 0;
267
	while (value < 0) {
268
		value -= BIG;	/* will eventually underflow */
269
		n++;
270
	}
271
	while ((lval = value - BIG) >= 0) {
272
		value = lval;
273
		n++;
274
	}
275
 
276
	/* stash it in buffer[1] to allow for a sign */
277
	bp[1] = n + '0';
278
	/*
279
	 * Now develop the rest of the digits. Since speed counts here,
280
	 * we do it in two loops. The first gets "value" down until it
281
	 * is no larger than MAXINT. The second one uses integer divides
282
	 * rather than long divides to speed it up.
283
	 */
284
	bp += MAXDIGS + 1;
285
	while (value > MAXINT) {
286
		*--bp = (int)(value % 10) + '0';
287
		value /= 10;
288
	}
289
 
290
	/* cannot lose precision */
291
	svalue = value;
292
	while (svalue > 0) {
293
		*--bp = (svalue % 10) + '0';
294
		svalue /= 10;
295
	}
296
 
297
	/* fill in intermediate zeroes if needed */
298
	if (buffer[1] != '0') {
299
		while (bp > buffer + 2)
300
			*--bp = '0';
301
		--bp;
302
	}
303
	return(bp);
304
}
305
 
306
/*
307
 * This program sends string "s" to putchar. The character after
308
 * the end of "s" is given by "send". This allows the size of the
309
 * field to be computed; it is stored in "alen". "width" contains the
310
 * user specified length. If width<alen, the width will be taken to
311
 * be alen. "sign" is zero if the string is to be right-justified
312
 * in the field, nonzero if it is to be left-justified. "fill" is
313
 * 0 if the string is to be padded with '0', positive if it is to be
314
 * padded with ' ', and negative if an initial '-' should appear before
315
 * any padding in right-justification (to avoid printing "-3" as
316
 * "000-3" where "-0003" was intended).
317
 */
318
_p_emit(s, send)
319
	register char *s;
320
	char *send;
321
{
322
	char cfill;
323
	register int alen;
324
	int npad;
325
 
326
	alen = send - s;
327
	if (alen > width)
328
		width = alen;
329
	cfill = fill>0? ' ': '0';
330
 
331
	/* we may want to print a leading '-' before anything */
332
	if (*s == '-' && fill < 0) {
333
		putchar(*s++);
334
		alen--;
335
		width--;
336
	}
337
	npad = width - alen;
338
 
339
	/* emit any leading pad characters */
340
	if (!sign)
341
		while (--npad >= 0)
342
			putchar(cfill);
343
 
344
	/* emit the string itself */
345
	while (--alen >= 0)
346
		putchar(*s++);
347
 
348
	/* emit trailing pad characters */
349
	if (sign)
350
		while (--npad >= 0)
351
			putchar(cfill);
352
}