|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that: (1) source distributions retain this entire copyright
7: * notice and comment, and (2) distributions including binaries display
8: * the following acknowledgement: ``This product includes software
9: * developed by the University of California, Berkeley and its contributors''
10: * in the documentation or other materials provided with the distribution
11: * and in all advertising materials mentioning features or use of this
12: * software. Neither the name of the University nor the names of its
13: * contributors may be used to endorse or promote products derived
14: * from this software without specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)printf.c 5.9 (Berkeley) 6/1/90";
28: #endif /* not lint */
29:
30: #include <sys/types.h>
31: #include <stdio.h>
32:
33: #define PF(f, func) { \
34: if (fieldwidth) \
35: if (precision) \
36: (void)printf(f, fieldwidth, precision, func); \
37: else \
38: (void)printf(f, fieldwidth, func); \
39: else if (precision) \
40: (void)printf(f, precision, func); \
41: else \
42: (void)printf(f, func); \
43: }
44:
45: char **gargv;
46:
47: main(argc, argv)
48: int argc;
49: char **argv;
50: {
51: static char *skip1, *skip2;
52: register char *format, *fmt, *start;
53: register int end, fieldwidth, precision;
54: char convch, nextch, *getstr(), *index(), *mklong();
55: double getdouble();
56: long getlong();
57:
58: if (argc < 2) {
59: fprintf(stderr, "usage: printf format [arg ...]\n");
60: exit(1);
61: }
62:
63: /*
64: * Basic algorithm is to scan the format string for conversion
65: * specifications -- once one is found, find out if the field
66: * width or precision is a '*'; if it is, gather up value. Note,
67: * format strings are reused as necessary to use up the provided
68: * arguments, arguments of zero/null string are provided to use
69: * up the format string.
70: */
71: skip1 = "#-+ 0";
72: skip2 = "*0123456789";
73:
74: escape(fmt = format = *++argv); /* backslash interpretation */
75: gargv = ++argv;
76: for (;;) {
77: end = 0;
78: /* find next format specification */
79: next: for (start = fmt;; ++fmt) {
80: if (!*fmt) {
81: /* avoid infinite loop */
82: if (end == 1) {
83: fprintf(stderr,
84: "printf: missing format character.\n");
85: exit(1);
86: }
87: end = 1;
88: if (fmt > start)
89: (void)printf("%s", start);
90: if (!*gargv)
91: exit(0);
92: fmt = format;
93: goto next;
94: }
95: /* %% prints a % */
96: if (*fmt == '%') {
97: if (*++fmt != '%')
98: break;
99: *fmt++ = '\0';
100: (void)printf("%s", start);
101: goto next;
102: }
103: }
104:
105: /* skip to field width */
106: for (; index(skip1, *fmt); ++fmt);
107: fieldwidth = *fmt == '*' ? getint() : 0;
108:
109: /* skip to possible '.', get following precision */
110: for (; index(skip2, *fmt); ++fmt);
111: if (*fmt == '.')
112: ++fmt;
113: precision = *fmt == '*' ? getint() : 0;
114:
115: /* skip to conversion char */
116: for (; index(skip2, *fmt); ++fmt);
117: if (!*fmt) {
118: fprintf(stderr, "printf: missing format character.\n");
119: exit(1);
120: }
121:
122: convch = *fmt;
123: nextch = *++fmt;
124: *fmt = '\0';
125: switch(convch) {
126: case 'c': {
127: char p = getchr();
128: PF(start, p);
129: break;
130: }
131: case 's': {
132: char *p = getstr();
133: PF(start, p);
134: break;
135: }
136: case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
137: char *f = mklong(start, convch);
138: long p = getlong();
139: PF(f, p);
140: break;
141: }
142: case 'e': case 'E': case 'f': case 'g': case 'G': {
143: double p = getdouble();
144: PF(start, p);
145: break;
146: }
147: default:
148: fprintf(stderr, "printf: illegal format character.\n");
149: exit(1);
150: }
151: *fmt = nextch;
152: }
153: /* NOTREACHED */
154: }
155:
156: char *
157: mklong(str, ch)
158: char *str, ch;
159: {
160: int len;
161: char *copy, *malloc();
162:
163: len = strlen(str) + 2;
164: if (!(copy = malloc((u_int)len))) { /* never freed; XXX */
165: fprintf(stderr, "printf: out of memory.\n");
166: exit(1);
167: }
168: bcopy(str, copy, len - 3);
169: copy[len - 3] = 'l';
170: copy[len - 2] = ch;
171: copy[len - 1] = '\0';
172: return(copy);
173: }
174:
175: escape(fmt)
176: register char *fmt;
177: {
178: register char *store;
179: register int value, c;
180:
181: for (store = fmt; c = *fmt; ++fmt, ++store) {
182: if (c != '\\') {
183: *store = c;
184: continue;
185: }
186: switch (*++fmt) {
187: case '\0': /* EOS, user error */
188: *store = '\\';
189: *++store = '\0';
190: return;
191: case '\\': /* backslash */
192: case '\'': /* single quote */
193: *store = *fmt;
194: break;
195: case 'a': /* bell/alert */
196: *store = '\7';
197: break;
198: case 'b': /* backspace */
199: *store = '\b';
200: break;
201: case 'f': /* form-feed */
202: *store = '\f';
203: break;
204: case 'n': /* newline */
205: *store = '\n';
206: break;
207: case 'r': /* carriage-return */
208: *store = '\r';
209: break;
210: case 't': /* horizontal tab */
211: *store = '\t';
212: break;
213: case 'v': /* vertical tab */
214: *store = '\13';
215: break;
216: /* octal constant */
217: case '0': case '1': case '2': case '3':
218: case '4': case '5': case '6': case '7':
219: for (c = 3, value = 0;
220: c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
221: value <<= 3;
222: value += *fmt - '0';
223: }
224: --fmt;
225: *store = value;
226: break;
227: default:
228: *store = *fmt;
229: break;
230: }
231: }
232: *store = '\0';
233: }
234:
235: getchr()
236: {
237: if (!*gargv)
238: return((int)'\0');
239: return((int)**gargv++);
240: }
241:
242: char *
243: getstr()
244: {
245: if (!*gargv)
246: return("");
247: return(*gargv++);
248: }
249:
250: static char *number = "+-.0123456789";
251: getint()
252: {
253: if (!*gargv)
254: return(0);
255: if (index(number, **gargv))
256: return(atoi(*gargv++));
257: return(asciicode());
258: }
259:
260: long
261: getlong()
262: {
263: long atol();
264:
265: if (!*gargv)
266: return((long)0);
267: if (index(number, **gargv))
268: return(strtol(*gargv++, (char **)NULL, 0));
269: return((long)asciicode());
270: }
271:
272: double
273: getdouble()
274: {
275: double atof();
276:
277: if (!*gargv)
278: return((double)0);
279: if (index(number, **gargv))
280: return(atof(*gargv++));
281: return((double)asciicode());
282: }
283:
284: asciicode()
285: {
286: register char ch;
287:
288: ch = **gargv;
289: if (ch == '\'' || ch == '"')
290: ch = (*gargv)[1];
291: ++gargv;
292: return(ch);
293: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.