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(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
117vprintf(char *format, va_list ap)
118{
119    return (vfprintf(stdout, format, ap));
120}
121