pci: don't do sanity check for missing pci bus, the check can misfire.
[minix.git] / commands / simple / printf.c
blob4e797b6efbefb15a22d4780c94919a762a312f23
1 #if ever
2 static char sccsid[] = "@(#)printf.c (U of Maryland) FLB 6-Jan-1987";
3 static char RCSid[] = "@(#)$Header$";
4 #endif
6 /*
7 * Printf - Duplicate the C library routine of the same name, but from
8 * the shell command level.
10 * Fred Blonder <fred@Mimsy.umd.edu>
12 * To Compile:
13 % cc -s -O printf.c -o printf
15 * $Log$
16 * Revision 1.1 2005/04/21 14:55:31 beng
17 * Initial revision
19 * Revision 1.1.1.1 2005/04/20 13:33:30 beng
20 * Initial import of minix 2.0.4
22 * Revision 1.4 87/01/29 20:52:30 fred
23 * Re-installed backslash-notation conversion for string & char arguments.
25 * Revision 1.3 87/01/29 20:44:23 fred
26 * Converted to portable algorithm.
27 * Added Roman format for integers.
28 * 29-Jan-87 FLB
30 * Revision 1.2 87/01/09 19:10:57 fred
31 * Fixed bug in argument-count error-checking.
32 * Changed backslash escapes within strings to correspond to ANSII C
33 * draft standard. (9-Jan-87 FLB)
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #define EX_OK 0
41 #define EX_USAGE 1
43 int ctrl(char *s);
45 #define atoi(a) strtoul((a), NULL, 0)
47 /****************************************************************************/
49 int main(int argc, char *argv[])
51 register char *cp, *conv_spec, **argp, **ep;
52 char *ctor(int x);
54 if (argc < 2) {
55 fprintf(stderr,
56 "printf: Usage: printf <format-string> [ arg1 . . . ]\n");
57 exit(EX_USAGE);
60 argp = &argv[2]; /* Point at first arg (if any) beyond format string. */
61 ep = &argv[argc]; /* Point beyond last arg. */
63 ctrl(argv[1]); /* Change backslash notation to control chars in fmt string. */
65 /* Scan format string for conversion specifications, and do appropriate
66 conversion on the corresponding argument. */
67 for (cp = argv[1]; *cp; cp++) {
68 register int dynamic_count;
70 /* Look for next conversion spec. */
71 while (*cp && *cp != '%') {
72 putchar(*cp++);
75 if (!*cp) /* End of format string */
76 break;
78 dynamic_count = 0; /* Begin counting dynamic field width specs. */
79 conv_spec = cp++; /* Remember where this conversion begins. */
81 for (;*cp; cp++) { /* Scan until conversion character. */
82 char conv_buf[BUFSIZ]; /* Save conversion string here. */
83 register int conv_len; /* Length of ``conv_buf''. */
85 switch (*cp) { /* Field-width spec.: Keep scanning. */
86 case '.': case '0': case '1': case '2': case '3':
87 case '4': case '5': case '6': case '7': case '8':
88 case '9':
89 continue;
91 case '*': /* Dynamic field-width spec */
92 dynamic_count++;
93 continue;
95 case 's': /* String */
96 if (&argp[dynamic_count] >= ep) {
97 fprintf(stderr,
98 "printf: Not enough args for format.\n"
100 exit(EX_USAGE);
103 (void) strncpy(conv_buf, conv_spec,
104 conv_len = cp - conv_spec + 1);
105 conv_buf[conv_len] = '\0';
107 switch (dynamic_count) {
108 case 0:
109 ctrl(*argp);
110 printf(conv_buf, *argp++);
111 break;
113 case 1:
115 register int a1;
117 a1 = atoi(*argp++);
118 ctrl(*argp);
119 printf(conv_buf, a1, *argp++);
121 break;
123 case 2:
125 register int a1, a2;
127 a1 = atoi(*argp++);
128 a2 = atoi(*argp++);
129 ctrl(*argp);
130 printf(conv_buf, a1, a2, *argp++);
132 break;
135 goto out;
137 case 'c': /* Char */
138 if (&argp[dynamic_count] >= ep) {
139 fprintf(stderr,
140 "printf: Not enough args for format.\n"
142 exit(EX_USAGE);
145 (void) strncpy(conv_buf, conv_spec,
146 conv_len = cp - conv_spec + 1);
147 conv_buf[conv_len] = '\0';
149 switch (dynamic_count) {
150 case 0:
151 ctrl(*argp);
152 printf(conv_buf, **argp++);
153 break;
155 case 1:
157 register int a1;
159 a1 = atoi(*argp++);
160 ctrl(*argp);
161 printf(conv_buf, a1, **argp++);
163 break;
165 case 2:
167 register int a1, a2;
169 a1 = atoi(*argp++);
170 a2 = atoi(*argp++);
171 ctrl(*argp);
172 printf(conv_buf, a1, a2, **argp++);
174 break;
176 goto out;
178 case 'd': /* Integer */
179 case 'o':
180 case 'x':
181 case 'X':
182 case 'u':
183 if (&argp[dynamic_count] >= ep) {
184 fprintf(stderr,
185 "printf: Not enough args for format.\n"
187 exit(EX_USAGE);
190 (void) strncpy(conv_buf, conv_spec,
191 conv_len = cp - conv_spec + 1);
192 conv_buf[conv_len] = '\0';
194 switch (dynamic_count) {
195 case 0:
196 printf(conv_buf, atoi(*argp++));
197 break;
199 case 1:
201 register int a1;
203 a1 = atoi(*argp++);
204 printf(conv_buf, a1, atoi(*argp++));
206 break;
208 case 2:
210 register int a1, a2;
212 a1 = atoi(*argp++);
213 a2 = atoi(*argp++);
214 printf(conv_buf, a1, a2, atoi(*argp++));
216 break;
219 goto out;
221 case 'f': /* Real */
222 case 'e':
223 case 'g':
224 if (&argp[dynamic_count] >= ep) {
225 fprintf(stderr,
226 "printf: Not enough args for format.\n"
228 exit(EX_USAGE);
231 (void) strncpy(conv_buf, conv_spec,
232 conv_len = cp - conv_spec + 1);
233 conv_buf[conv_len] = '\0';
235 switch (dynamic_count) {
236 case 0:
237 printf(conv_buf, atof(*argp++));
238 break;
240 case 1:
242 register int a1;
244 a1 = atoi(*argp++);
245 printf(conv_buf, a1, atof(*argp++));
247 break;
249 case 2:
251 register int a1, a2;
253 a1 = atoi(*argp++);
254 a2 = atoi(*argp++);
255 printf(conv_buf, a1, a2, atof(*argp++));
257 break;
260 goto out;
262 case 'r': /* Roman (Well, why not?) */
263 if (&argp[dynamic_count] >= ep) {
264 fprintf(stderr,
265 "printf: Not enough args for format.\n"
267 exit(EX_USAGE);
270 (void) strncpy(conv_buf, conv_spec,
271 conv_len = cp - conv_spec + 1);
272 conv_buf[conv_len] = '\0';
273 conv_buf[conv_len - 1] = 's';
275 switch (dynamic_count) {
276 case 0:
277 printf(conv_buf,
278 ctor(atoi(*argp++)));
279 break;
281 case 1:
283 register int a1;
285 a1 = atoi(*argp++);
286 printf(conv_buf, a1,
287 ctor(atoi(*argp++)));
289 break;
291 case 2:
293 register int a1, a2;
295 a1 = atoi(*argp++);
296 a2 = atoi(*argp++);
297 printf(conv_buf, a1, a2,
298 ctor(atoi(*argp++)));
300 break;
303 goto out;
305 case '%': /* Boring */
306 putchar('%');
307 break;
309 default: /* Probably an error, but let user
310 have his way. */
311 continue;
314 out: ;
317 exit(EX_OK);
320 /****************************************************************************/
322 /* Convert backslash notation to control characters, in place. */
324 int ctrl(char *s)
326 register char *op;
327 static int val;
329 for (op = s; *s; s++)
330 if (*s == '\\')
331 switch (*++s) {
332 case '\0': /* End-of-string: user goofed */
333 goto out;
335 case '\\': /* Backslash */
336 *op++ = '\\';
337 break;
339 case 'n': /* newline */
340 *op++ = '\n';
341 break;
343 case 't': /* horizontal tab */
344 *op++ = '\t';
345 break;
347 case 'r': /* carriage-return */
348 *op++ = '\r';
349 break;
351 case 'f': /* form-feed */
352 *op++ = '\f';
353 break;
355 case 'b': /* backspace */
356 *op++ = '\b';
357 break;
359 case 'v': /* vertical tab */
360 *op++ = '\13';
361 break;
363 case 'a': /* WARNING! DANGER! DANGER! DANGER! */
364 *op++ = '\7';
365 break;
367 case '0': case '1': case '2': case '3':
368 case '4': case '5': case '6': case '7':
369 { /* octal constant */
370 register int digits;
372 val = 0;
373 (void) sscanf(s, "%3o", &val);
374 *op++ = val;
375 for (digits = 3; s[1] &&
376 strchr("01234567", s[1])
377 && --digits > 0;
378 s++);
380 break;
382 case 'x': /* hex constant */
383 case 'X':
384 s++;
386 register int digits;
388 val = 0;
389 (void) sscanf(s, "%3x", &val);
390 *op++ = val;
391 for (digits = 3; *s && s[1] &&
392 strchr("0123456789abcdefABCDEF",
393 s[1])
394 && --digits > 0;
395 s++);
397 break;
400 else
401 *op++ = *s;
403 out:
405 *op = '\0';
408 /****************************************************************************/
410 /* Convert integer to Roman Numerals. (Have have you survived without it?) */
412 struct roman {
413 unsigned r_mag;
414 char r_units, r_fives;
415 } roman[] = {
416 { 1000, 'M', '\0', },
417 { 100, 'C', 'D', },
418 { 10, 'X', 'L', },
419 { 1, 'I', 'V', },
422 char *ctor(int x)
424 register struct roman *mp;
425 static char buf[BUFSIZ];
426 register char *cp = buf;
428 /* I've never actually seen a roman numeral with a minus-sign.
429 Probably ought to print out some appropriate latin phrase instead. */
430 if (x < 0) {
431 *cp++ = '-';
432 x = -x;
435 for (mp = roman; x; mp++) {
436 register unsigned units;
438 units = x / mp->r_mag;
439 x = x % mp->r_mag;
441 if (cp > &buf[BUFSIZ-2])
442 return "???";
444 if (units == 9 && mp > roman) { /* Do inverse notation: Eg: ``IX''. */
445 *cp++ = mp->r_units;
446 *cp++ = mp[-1].r_units;
448 else if (units == 4 && mp->r_fives) {
449 /* Inverse notation for half-decades: Eg: ``IV'' */
450 *cp++ = mp->r_units;
451 *cp++ = mp->r_fives;
453 else { /* Additive notation */
454 if (units >= 5 && mp->r_fives) {
455 *cp++ = mp->r_fives;
456 units -= 5;
458 while (units--) {
459 *cp++ = mp->r_units;
460 if (cp > &buf[BUFSIZ-5])
461 return "???";
466 *cp = '\0';
468 return buf;
471 /****************************************************************************/