strings.h -> string.h
[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
802c33fc 25static char sccsid[] = "@(#)printf.c 5.8 (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 % */
8a6a6c83
KB
94 if (*fmt == '%') {
95 if (*++fmt != '%')
96 break;
97 *fmt++ = '\0';
98 (void)printf("%s", start);
99 goto next;
100 }
6b8cdffd
KB
101 }
102
103 /* skip to field width */
104 for (; index(skip1, *fmt); ++fmt);
62216505
KB
105 fieldwidth = *fmt == '*' ? getint() : 0;
106
107 /* skip to possible '.', get following precision */
6b8cdffd
KB
108 for (; index(skip2, *fmt); ++fmt);
109 if (*fmt == '.')
110 ++fmt;
62216505
KB
111 precision = *fmt == '*' ? getint() : 0;
112
6b8cdffd
KB
113 /* skip to conversion char */
114 for (; index(skip2, *fmt); ++fmt);
115 if (!*fmt) {
116 fprintf(stderr, "printf: missing format character.\n");
5d351dd2 117 exit(1);
6b8cdffd
KB
118 }
119
120 convch = *fmt;
121 nextch = *++fmt;
122 *fmt = '\0';
123 switch(convch) {
124 case 'c': {
125 char p = getchr();
126 PF(start, p);
127 break;
128 }
129 case 's': {
130 char *p = getstr();
131 PF(start, p);
132 break;
133 }
a0486b62 134 case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
6b8cdffd
KB
135 char *f = mklong(start, convch);
136 long p = getlong();
137 PF(f, p);
138 break;
139 }
140 case 'e': case 'E': case 'f': case 'g': case 'G': {
141 double p = getdouble();
142 PF(start, p);
143 break;
144 }
145 default:
146 fprintf(stderr, "printf: illegal format character.\n");
5d351dd2 147 exit(1);
6b8cdffd
KB
148 }
149 *fmt = nextch;
150 }
151 /* NOTREACHED */
152}
153
154char *
155mklong(str, ch)
156 char *str, ch;
157{
158 int len;
159 char *copy, *malloc();
160
161 len = strlen(str) + 2;
162 if (!(copy = malloc((u_int)len))) { /* never freed; XXX */
163 fprintf(stderr, "printf: out of memory.\n");
5d351dd2 164 exit(1);
6b8cdffd
KB
165 }
166 bcopy(str, copy, len - 3);
167 copy[len - 3] = 'l';
168 copy[len - 2] = ch;
169 copy[len - 1] = '\0';
170 return(copy);
171}
172
173escape(fmt)
174 register char *fmt;
175{
176 register char *store;
177 register int value, c;
178
179 for (store = fmt; c = *fmt; ++fmt, ++store) {
180 if (c != '\\') {
181 *store = c;
182 continue;
183 }
184 switch (*++fmt) {
185 case '\0': /* EOS, user error */
186 *store = '\\';
187 *++store = '\0';
188 return;
189 case '\\': /* backslash */
93e4ef47
KB
190 case '\'': /* single quote */
191 *store = *fmt;
6b8cdffd
KB
192 break;
193 case 'a': /* bell/alert */
194 *store = '\7';
195 break;
196 case 'b': /* backspace */
197 *store = '\b';
198 break;
199 case 'f': /* form-feed */
200 *store = '\f';
201 break;
202 case 'n': /* newline */
203 *store = '\n';
204 break;
205 case 'r': /* carriage-return */
206 *store = '\r';
207 break;
208 case 't': /* horizontal tab */
209 *store = '\t';
210 break;
211 case 'v': /* vertical tab */
212 *store = '\13';
213 break;
214 /* octal constant */
215 case '0': case '1': case '2': case '3':
216 case '4': case '5': case '6': case '7':
217 for (c = 3, value = 0;
218 c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
219 value <<= 3;
220 value += *fmt - '0';
221 }
222 --fmt;
223 *store = value;
224 break;
225 default:
226 *store = *fmt;
227 break;
228 }
229 }
230 *store = '\0';
231}
232
233getchr()
234{
235 if (!*gargv)
236 return((int)'\0');
237 return((int)**gargv++);
238}
239
240char *
241getstr()
242{
243 if (!*gargv)
244 return("");
245 return(*gargv++);
246}
247
256c1f3d 248static char *number = "+-.0123456789";
6b8cdffd
KB
249getint()
250{
251 if (!*gargv)
252 return(0);
253 if (index(number, **gargv))
254 return(atoi(*gargv++));
255 return(asciicode());
256}
257
258long
259getlong()
260{
261 long atol();
262
263 if (!*gargv)
264 return((long)0);
265 if (index(number, **gargv))
802c33fc 266 return(strtol(*gargv++, (char **)NULL, 0));
6b8cdffd
KB
267 return((long)asciicode());
268}
269
270double
271getdouble()
272{
273 double atof();
274
275 if (!*gargv)
276 return((double)0);
277 if (index(number, **gargv))
278 return(atof(*gargv++));
279 return((double)asciicode());
280}
281
282asciicode()
283{
284 register char ch;
285
286 ch = **gargv;
287 if (ch == '\'' || ch == '"')
288 ch = (*gargv)[1];
289 ++gargv;
290 return(ch);
291}