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