144743Smarkm /*
244743Smarkm  * vfprintf() and vprintf() clones. They will produce unexpected results
344743Smarkm  * when excessive dynamic ("*") field widths are specified. To be used for
444743Smarkm  * testing purposes only.
544743Smarkm  *
644743Smarkm  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
744743Smarkm  */
844743Smarkm
944743Smarkm#ifndef lint
1044743Smarkmstatic char sccsid[] = "@(#) vfprintf.c 1.2 94/03/23 17:44:46";
1144743Smarkm#endif
1244743Smarkm
1344743Smarkm#include <stdio.h>
1444743Smarkm#include <ctype.h>
1544743Smarkm#ifdef __STDC__
1644743Smarkm#include <stdarg.h>
1744743Smarkm#else
1844743Smarkm#include <varargs.h>
1944743Smarkm#endif
2044743Smarkm
2144743Smarkm/* vfprintf - print variable-length argument list to stream */
2244743Smarkm
2344743Smarkmint     vfprintf(fp, format, ap)
2444743SmarkmFILE   *fp;
2544743Smarkmchar   *format;
2644743Smarkmva_list ap;
2744743Smarkm{
2844743Smarkm    char    fmt[BUFSIZ];		/* format specifier */
2944743Smarkm    register char *fmtp;
3044743Smarkm    register char *cp;
3144743Smarkm    int     count = 0;
3244743Smarkm
3344743Smarkm    /*
3444743Smarkm     * Iterate over characters in the format string, picking up arguments
3544743Smarkm     * when format specifiers are found.
3644743Smarkm     */
3744743Smarkm
3844743Smarkm    for (cp = format; *cp; cp++) {
3944743Smarkm	if (*cp != '%') {
4044743Smarkm	    putc(*cp, fp);			/* ordinary character */
4144743Smarkm	    count++;
4244743Smarkm	} else {
4344743Smarkm
4444743Smarkm	    /*
4544743Smarkm	     * Format specifiers are handled one at a time, since we can only
4644743Smarkm	     * deal with arguments one at a time. Try to determine the end of
4744743Smarkm	     * the format specifier. We do not attempt to fully parse format
4844743Smarkm	     * strings, since we are ging to let fprintf() do the hard work.
4944743Smarkm	     * In regular expression notation, we recognize:
5044743Smarkm	     *
5144743Smarkm	     * %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-z]
5244743Smarkm	     *
5344743Smarkm	     * which includes some combinations that do not make sense.
5444743Smarkm	     */
5544743Smarkm
5644743Smarkm	    fmtp = fmt;
5744743Smarkm	    *fmtp++ = *cp++;
5844743Smarkm	    if (*cp == '-')			/* left-adjusted field? */
5944743Smarkm		*fmtp++ = *cp++;
6044743Smarkm	    if (*cp == '0')			/* zero-padded field? */
6144743Smarkm		*fmtp++ = *cp++;
6244743Smarkm	    if (*cp == '*') {			/* dynamic field witdh */
6344743Smarkm		sprintf(fmtp, "%d", va_arg(ap, int));
6444743Smarkm		fmtp += strlen(fmtp);
6544743Smarkm		cp++;
6644743Smarkm	    } else {
6744743Smarkm		while (isdigit(*cp))		/* hard-coded field width */
6844743Smarkm		    *fmtp++ = *cp++;
6944743Smarkm	    }
7044743Smarkm	    if (*cp == '.')			/* width/precision separator */
7144743Smarkm		*fmtp++ = *cp++;
7244743Smarkm	    if (*cp == '*') {			/* dynamic precision */
7344743Smarkm		sprintf(fmtp, "%d", va_arg(ap, int));
7444743Smarkm		fmtp += strlen(fmtp);
7544743Smarkm		cp++;
7644743Smarkm	    } else {
7744743Smarkm		while (isdigit(*cp))		/* hard-coded precision */
7844743Smarkm		    *fmtp++ = *cp++;
7944743Smarkm	    }
8044743Smarkm	    if (*cp == 'l')			/* long whatever */
8144743Smarkm		*fmtp++ = *cp++;
8244743Smarkm	    if (*cp == 0)			/* premature end, punt */
8344743Smarkm		break;
8444743Smarkm	    *fmtp++ = *cp;			/* type (checked below) */
8544743Smarkm	    *fmtp = 0;
8644743Smarkm
8744743Smarkm	    /* Execute the format string - let fprintf() do the hard work. */
8844743Smarkm
8944743Smarkm	    switch (fmtp[-1]) {
9044743Smarkm	    case 's':				/* string-valued argument */
9144743Smarkm		count += fprintf(fp, fmt, va_arg(ap, char *));
9244743Smarkm		break;
9344743Smarkm	    case 'c':				/* integral-valued argument */
9444743Smarkm	    case 'd':
9544743Smarkm	    case 'u':
9644743Smarkm	    case 'o':
9744743Smarkm	    case 'x':
9844743Smarkm		if (fmtp[-2] == 'l')
9944743Smarkm		    count += fprintf(fp, fmt, va_arg(ap, long));
10044743Smarkm		else
10144743Smarkm		    count += fprintf(fp, fmt, va_arg(ap, int));
10244743Smarkm		break;
10344743Smarkm	    case 'e':				/* float-valued argument */
10444743Smarkm	    case 'f':
10544743Smarkm	    case 'g':
10644743Smarkm		count += fprintf(fp, fmt, va_arg(ap, double));
10744743Smarkm		break;
10844743Smarkm	    default:				/* anything else */
10944743Smarkm		putc(fmtp[-1], fp);
11044743Smarkm		count++;
11144743Smarkm		break;
11244743Smarkm	    }
11344743Smarkm	}
11444743Smarkm    }
11544743Smarkm    return (count);
11644743Smarkm}
11744743Smarkm
11844743Smarkm/* vprintf - print variable-length argument list to stdout */
11944743Smarkm
12044743Smarkmvprintf(format, ap)
12144743Smarkmchar   *format;
12244743Smarkmva_list ap;
12344743Smarkm{
12444743Smarkm    return (vfprintf(stdout, format, ap));
12544743Smarkm}
126