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