|
|
1.1 root 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: #ifndef lint
8: static char *sccsid = "@(#)printf.c 7.4 (Berkeley) 3/9/87";
9: /* The pwb version this is based on */
10: static char *printf_id = "@(#) printf.c:2.2 6/5/79";
11: #endif not lint
12:
13: #include <varargs.h>
14:
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: #define MAXOCT 11 /* Maximum octal digits in a long */
24: #define MAXINT 32767 /* largest normal length positive integer */
25: #define BIG 1000000000 /* largest power of 10 less than an unsigned long */
26: #define MAXDIGS 10 /* number of digits in BIG */
27:
28: static int width, sign, fill;
29:
30: char *_p_dconv();
31:
32: /* VARARGS */
33: ex_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: ex_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: ex_putchar('0');
185: ex_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: ex_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: ex_putchar(cfill);
343:
344: /* emit the string itself */
345: while (--alen >= 0)
346: ex_putchar(*s++);
347:
348: /* emit trailing pad characters */
349: if (sign)
350: while (--npad >= 0)
351: ex_putchar(cfill);
352: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.