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