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