summaryrefslogtreecommitdiff
path: root/vfprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'vfprintf.c')
-rw-r--r--vfprintf.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/vfprintf.c b/vfprintf.c
new file mode 100644
index 0000000..d6f37d5
--- /dev/null
+++ b/vfprintf.c
@@ -0,0 +1,125 @@
+ /*
+ * 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(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));
+}