xref: /freebsd/contrib/tcp_wrappers/vfprintf.c (revision 7afc53b8dfcc7d5897920ce6cc7e842fbb4ab813)
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 }
126