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
10static 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
23int     vfprintf(fp, format, ap)
24FILE   *fp;
25char   *format;
26va_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
120vprintf(format, ap)
121char   *format;
122va_list ap;
123{
124    return (vfprintf(stdout, format, ap));
125}
126