Although this code is in contrib/ there is no active upstream. Reviewed by: brooks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D36047
121 lines
3.1 KiB
C
121 lines
3.1 KiB
C
/*
|
|
* vfprintf() and vprintf() clones. They will produce unexpected results
|
|
* when excessive dynamic ("*") field widths are specified. To be used for
|
|
* testing purposes only.
|
|
*
|
|
* Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#) vfprintf.c 1.2 94/03/23 17:44:46";
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#ifdef __STDC__
|
|
#include <stdarg.h>
|
|
#else
|
|
#include <varargs.h>
|
|
#endif
|
|
|
|
/* vfprintf - print variable-length argument list to stream */
|
|
|
|
int vfprintf(FILE *fp, char *format, va_list ap)
|
|
{
|
|
char fmt[BUFSIZ]; /* format specifier */
|
|
register char *fmtp;
|
|
register char *cp;
|
|
int count = 0;
|
|
|
|
/*
|
|
* Iterate over characters in the format string, picking up arguments
|
|
* when format specifiers are found.
|
|
*/
|
|
|
|
for (cp = format; *cp; cp++) {
|
|
if (*cp != '%') {
|
|
putc(*cp, fp); /* ordinary character */
|
|
count++;
|
|
} else {
|
|
|
|
/*
|
|
* Format specifiers are handled one at a time, since we can only
|
|
* deal with arguments one at a time. Try to determine the end of
|
|
* the format specifier. We do not attempt to fully parse format
|
|
* strings, since we are ging to let fprintf() do the hard work.
|
|
* In regular expression notation, we recognize:
|
|
*
|
|
* %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-z]
|
|
*
|
|
* which includes some combinations that do not make sense.
|
|
*/
|
|
|
|
fmtp = fmt;
|
|
*fmtp++ = *cp++;
|
|
if (*cp == '-') /* left-adjusted field? */
|
|
*fmtp++ = *cp++;
|
|
if (*cp == '0') /* zero-padded field? */
|
|
*fmtp++ = *cp++;
|
|
if (*cp == '*') { /* dynamic field witdh */
|
|
sprintf(fmtp, "%d", va_arg(ap, int));
|
|
fmtp += strlen(fmtp);
|
|
cp++;
|
|
} else {
|
|
while (isdigit(*cp)) /* hard-coded field width */
|
|
*fmtp++ = *cp++;
|
|
}
|
|
if (*cp == '.') /* width/precision separator */
|
|
*fmtp++ = *cp++;
|
|
if (*cp == '*') { /* dynamic precision */
|
|
sprintf(fmtp, "%d", va_arg(ap, int));
|
|
fmtp += strlen(fmtp);
|
|
cp++;
|
|
} else {
|
|
while (isdigit(*cp)) /* hard-coded precision */
|
|
*fmtp++ = *cp++;
|
|
}
|
|
if (*cp == 'l') /* long whatever */
|
|
*fmtp++ = *cp++;
|
|
if (*cp == 0) /* premature end, punt */
|
|
break;
|
|
*fmtp++ = *cp; /* type (checked below) */
|
|
*fmtp = 0;
|
|
|
|
/* Execute the format string - let fprintf() do the hard work. */
|
|
|
|
switch (fmtp[-1]) {
|
|
case 's': /* string-valued argument */
|
|
count += fprintf(fp, fmt, va_arg(ap, char *));
|
|
break;
|
|
case 'c': /* integral-valued argument */
|
|
case 'd':
|
|
case 'u':
|
|
case 'o':
|
|
case 'x':
|
|
if (fmtp[-2] == 'l')
|
|
count += fprintf(fp, fmt, va_arg(ap, long));
|
|
else
|
|
count += fprintf(fp, fmt, va_arg(ap, int));
|
|
break;
|
|
case 'e': /* float-valued argument */
|
|
case 'f':
|
|
case 'g':
|
|
count += fprintf(fp, fmt, va_arg(ap, double));
|
|
break;
|
|
default: /* anything else */
|
|
putc(fmtp[-1], fp);
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return (count);
|
|
}
|
|
|
|
/* vprintf - print variable-length argument list to stdout */
|
|
|
|
vprintf(char *format, va_list ap)
|
|
{
|
|
return (vfprintf(stdout, format, ap));
|
|
}
|