/* * 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 #include #ifdef __STDC__ #include #else #include #endif /* vfprintf - print variable-length argument list to stream */ int vfprintf(fp, format, ap) 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(format, ap) char *format; va_list ap; { return (vfprintf(stdout, format, ap)); }