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 | |
---|
23 | int vfprintf(fp, format, ap) |
---|
24 | FILE *fp; |
---|
25 | char *format; |
---|
26 | va_list ap; |
---|
27 | { |
---|
28 | char fmt[BUFSIZ]; /* format specifier */ |
---|
29 | register char *fmtp; |
---|
30 | register char *cp; |
---|
31 | int count = 0; |
---|
32 | |
---|
33 | /* |
---|
34 | * Iterate over characters in the format string, picking up arguments |
---|
35 | * when format specifiers are found. |
---|
36 | */ |
---|
37 | |
---|
38 | for (cp = format; *cp; cp++) { |
---|
39 | if (*cp != '%') { |
---|
40 | putc(*cp, fp); /* ordinary character */ |
---|
41 | count++; |
---|
42 | } else { |
---|
43 | |
---|
44 | /* |
---|
45 | * Format specifiers are handled one at a time, since we can only |
---|
46 | * deal with arguments one at a time. Try to determine the end of |
---|
47 | * the format specifier. We do not attempt to fully parse format |
---|
48 | * strings, since we are ging to let fprintf() do the hard work. |
---|
49 | * In regular expression notation, we recognize: |
---|
50 | * |
---|
51 | * %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-z] |
---|
52 | * |
---|
53 | * which includes some combinations that do not make sense. |
---|
54 | */ |
---|
55 | |
---|
56 | fmtp = fmt; |
---|
57 | *fmtp++ = *cp++; |
---|
58 | if (*cp == '-') /* left-adjusted field? */ |
---|
59 | *fmtp++ = *cp++; |
---|
60 | if (*cp == '0') /* zero-padded field? */ |
---|
61 | *fmtp++ = *cp++; |
---|
62 | if (*cp == '*') { /* dynamic field witdh */ |
---|
63 | sprintf(fmtp, "%d", va_arg(ap, int)); |
---|
64 | fmtp += strlen(fmtp); |
---|
65 | cp++; |
---|
66 | } else { |
---|
67 | while (isdigit(*cp)) /* hard-coded field width */ |
---|
68 | *fmtp++ = *cp++; |
---|
69 | } |
---|
70 | if (*cp == '.') /* width/precision separator */ |
---|
71 | *fmtp++ = *cp++; |
---|
72 | if (*cp == '*') { /* dynamic precision */ |
---|
73 | sprintf(fmtp, "%d", va_arg(ap, int)); |
---|
74 | fmtp += strlen(fmtp); |
---|
75 | cp++; |
---|
76 | } else { |
---|
77 | while (isdigit(*cp)) /* hard-coded precision */ |
---|
78 | *fmtp++ = *cp++; |
---|
79 | } |
---|
80 | if (*cp == 'l') /* long whatever */ |
---|
81 | *fmtp++ = *cp++; |
---|
82 | if (*cp == 0) /* premature end, punt */ |
---|
83 | break; |
---|
84 | *fmtp++ = *cp; /* type (checked below) */ |
---|
85 | *fmtp = 0; |
---|
86 | |
---|
87 | /* Execute the format string - let fprintf() do the hard work. */ |
---|
88 | |
---|
89 | switch (fmtp[-1]) { |
---|
90 | case 's': /* string-valued argument */ |
---|
91 | count += fprintf(fp, fmt, va_arg(ap, char *)); |
---|
92 | break; |
---|
93 | case 'c': /* integral-valued argument */ |
---|
94 | case 'd': |
---|
95 | case 'u': |
---|
96 | case 'o': |
---|
97 | case 'x': |
---|
98 | if (fmtp[-2] == 'l') |
---|
99 | count += fprintf(fp, fmt, va_arg(ap, long)); |
---|
100 | else |
---|
101 | count += fprintf(fp, fmt, va_arg(ap, int)); |
---|
102 | break; |
---|
103 | case 'e': /* float-valued argument */ |
---|
104 | case 'f': |
---|
105 | case 'g': |
---|
106 | count += fprintf(fp, fmt, va_arg(ap, double)); |
---|
107 | break; |
---|
108 | default: /* anything else */ |
---|
109 | putc(fmtp[-1], fp); |
---|
110 | count++; |
---|
111 | break; |
---|
112 | } |
---|
113 | } |
---|
114 | } |
---|
115 | return (count); |
---|
116 | } |
---|
117 | |
---|
118 | /* vprintf - print variable-length argument list to stdout */ |
---|
119 | |
---|
120 | vprintf(format, ap) |
---|
121 | char *format; |
---|
122 | va_list ap; |
---|
123 | { |
---|
124 | return (vfprintf(stdout, format, ap)); |
---|
125 | } |
---|