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(FILE *fp, char *format, va_list ap) 24 { 25 char fmt[BUFSIZ]; /* format specifier */ 26 register char *fmtp; 27 register char *cp; 28 int count = 0; 29 30 /* 31 * Iterate over characters in the format string, picking up arguments 32 * when format specifiers are found. 33 */ 34 35 for (cp = format; *cp; cp++) { 36 if (*cp != '%') { 37 putc(*cp, fp); /* ordinary character */ 38 count++; 39 } else { 40 41 /* 42 * Format specifiers are handled one at a time, since we can only 43 * deal with arguments one at a time. Try to determine the end of 44 * the format specifier. We do not attempt to fully parse format 45 * strings, since we are ging to let fprintf() do the hard work. 46 * In regular expression notation, we recognize: 47 * 48 * %-?0?([0-9]+|\*)?\.?([0-9]+|\*)?l?[a-z] 49 * 50 * which includes some combinations that do not make sense. 51 */ 52 53 fmtp = fmt; 54 *fmtp++ = *cp++; 55 if (*cp == '-') /* left-adjusted field? */ 56 *fmtp++ = *cp++; 57 if (*cp == '0') /* zero-padded field? */ 58 *fmtp++ = *cp++; 59 if (*cp == '*') { /* dynamic field witdh */ 60 sprintf(fmtp, "%d", va_arg(ap, int)); 61 fmtp += strlen(fmtp); 62 cp++; 63 } else { 64 while (isdigit(*cp)) /* hard-coded field width */ 65 *fmtp++ = *cp++; 66 } 67 if (*cp == '.') /* width/precision separator */ 68 *fmtp++ = *cp++; 69 if (*cp == '*') { /* dynamic precision */ 70 sprintf(fmtp, "%d", va_arg(ap, int)); 71 fmtp += strlen(fmtp); 72 cp++; 73 } else { 74 while (isdigit(*cp)) /* hard-coded precision */ 75 *fmtp++ = *cp++; 76 } 77 if (*cp == 'l') /* long whatever */ 78 *fmtp++ = *cp++; 79 if (*cp == 0) /* premature end, punt */ 80 break; 81 *fmtp++ = *cp; /* type (checked below) */ 82 *fmtp = 0; 83 84 /* Execute the format string - let fprintf() do the hard work. */ 85 86 switch (fmtp[-1]) { 87 case 's': /* string-valued argument */ 88 count += fprintf(fp, fmt, va_arg(ap, char *)); 89 break; 90 case 'c': /* integral-valued argument */ 91 case 'd': 92 case 'u': 93 case 'o': 94 case 'x': 95 if (fmtp[-2] == 'l') 96 count += fprintf(fp, fmt, va_arg(ap, long)); 97 else 98 count += fprintf(fp, fmt, va_arg(ap, int)); 99 break; 100 case 'e': /* float-valued argument */ 101 case 'f': 102 case 'g': 103 count += fprintf(fp, fmt, va_arg(ap, double)); 104 break; 105 default: /* anything else */ 106 putc(fmtp[-1], fp); 107 count++; 108 break; 109 } 110 } 111 } 112 return (count); 113 } 114 115 /* vprintf - print variable-length argument list to stdout */ 116 117 vprintf(char *format, va_list ap) 118 { 119 return (vfprintf(stdout, format, ap)); 120 } 121