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