1 /*
2 * vfprintf() and vprintf() clones. They will produce unexpected results
3 * when excessive dynamic ("*") field widths are specified. To be used for
4 * testing purposes only.
5 *
6 * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
7 */
8
9 #ifndef lint
10 static char sccsid[] = "@(#) vfprintf.c 1.2 94/03/23 17:44:46";
11 #endif
12
13 #include <stdio.h>
14 #include <ctype.h>
15 #ifdef __STDC__
16 #include <stdarg.h>
17 #else
18 #include <varargs.h>
19 #endif
20
21 /* vfprintf - print variable-length argument list to stream */
22
vfprintf(FILE * fp,char * format,va_list ap)23 int vfprintf(FILE *fp, char *format, va_list ap)
24 {
25 char fmt[BUFSIZ]; /* format specifier */
26 register char *fmtp;
27 register char *cp;
28 int count = 0;
29
30 /*
31 * Iterate over characters in the format string, picking up arguments
32 * when format specifiers are found.
33 */
34
35 for (cp = format; *cp; cp++) {
36 if (*cp != '%') {
37 putc(*cp, fp); /* ordinary character */
38 count++;
39 } else {
40
41 /*
42 * Format specifiers are handled one at a time, since we can only
43 * deal with arguments one at a time. Try to determine the end of
44 * the format specifier. We do not attempt to fully parse format
45 * strings, since we are ging to let fprintf() do the hard work.
46 * In regular expression notation, we recognize:
47 *
48 * %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-z]
49 *
50 * which includes some combinations that do not make sense.
51 */
52
53 fmtp = fmt;
54 *fmtp++ = *cp++;
55 if (*cp == '-') /* left-adjusted field? */
56 *fmtp++ = *cp++;
57 if (*cp == '0') /* zero-padded field? */
58 *fmtp++ = *cp++;
59 if (*cp == '*') { /* dynamic field witdh */
60 sprintf(fmtp, "%d", va_arg(ap, int));
61 fmtp += strlen(fmtp);
62 cp++;
63 } else {
64 while (isdigit(*cp)) /* hard-coded field width */
65 *fmtp++ = *cp++;
66 }
67 if (*cp == '.') /* width/precision separator */
68 *fmtp++ = *cp++;
69 if (*cp == '*') { /* dynamic precision */
70 sprintf(fmtp, "%d", va_arg(ap, int));
71 fmtp += strlen(fmtp);
72 cp++;
73 } else {
74 while (isdigit(*cp)) /* hard-coded precision */
75 *fmtp++ = *cp++;
76 }
77 if (*cp == 'l') /* long whatever */
78 *fmtp++ = *cp++;
79 if (*cp == 0) /* premature end, punt */
80 break;
81 *fmtp++ = *cp; /* type (checked below) */
82 *fmtp = 0;
83
84 /* Execute the format string - let fprintf() do the hard work. */
85
86 switch (fmtp[-1]) {
87 case 's': /* string-valued argument */
88 count += fprintf(fp, fmt, va_arg(ap, char *));
89 break;
90 case 'c': /* integral-valued argument */
91 case 'd':
92 case 'u':
93 case 'o':
94 case 'x':
95 if (fmtp[-2] == 'l')
96 count += fprintf(fp, fmt, va_arg(ap, long));
97 else
98 count += fprintf(fp, fmt, va_arg(ap, int));
99 break;
100 case 'e': /* float-valued argument */
101 case 'f':
102 case 'g':
103 count += fprintf(fp, fmt, va_arg(ap, double));
104 break;
105 default: /* anything else */
106 putc(fmtp[-1], fp);
107 count++;
108 break;
109 }
110 }
111 }
112 return (count);
113 }
114
115 /* vprintf - print variable-length argument list to stdout */
116
vprintf(char * format,va_list ap)117 vprintf(char *format, va_list ap)
118 {
119 return (vfprintf(stdout, format, ap));
120 }
121