2 * pANS stdio -- vfprintf
8 #define SPACE 1 /* ' ' prepend space if no sign printed */
9 #define ALT 2 /* '#' use alternate conversion */
10 #define SIGN 4 /* '+' prepend sign, even if positive */
11 #define LEFT 8 /* '-' left-justify */
12 #define ZPAD 16 /* '0' zero-pad */
16 #define SHORT 32 /* 'h' convert a short integer */
17 #define LONG 64 /* 'l' convert a long integer */
18 #define LDBL 128 /* 'L' convert a long double */
19 #define PTR 256 /* convert a void * (%p) */
21 static int lflag[] = { /* leading flags */
22 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
23 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
24 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
25 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
26 SPACE, 0, 0, ALT, 0, 0, 0, 0, /* sp ! " # $ % & ' */
27 0, 0, 0, SIGN, 0, LEFT, 0, 0, /* ( ) * + , - . / */
28 ZPAD, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
29 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
30 0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
31 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
32 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
33 0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
34 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
35 0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
36 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
37 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
39 0, 0, 0, 0, 0, 0, 0, 0,
40 0, 0, 0, 0, 0, 0, 0, 0,
41 0, 0, 0, 0, 0, 0, 0, 0,
42 0, 0, 0, 0, 0, 0, 0, 0,
43 0, 0, 0, 0, 0, 0, 0, 0,
44 0, 0, 0, 0, 0, 0, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0,
46 0, 0, 0, 0, 0, 0, 0, 0,
47 0, 0, 0, 0, 0, 0, 0, 0,
48 0, 0, 0, 0, 0, 0, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0,
52 0, 0, 0, 0, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0,
57 static int tflag[] = { /* trailing flags */
58 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
59 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
60 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
61 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
62 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
63 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
64 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
65 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
66 0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
67 0, 0, 0, 0, LDBL, 0, 0, 0, /* H I J K L M N O */
68 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
69 0, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
70 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
71 SHORT, 0, 0, 0, LONG, 0, 0, 0, /* h i j k l m n o */
72 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
73 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
75 0, 0, 0, 0, 0, 0, 0, 0,
76 0, 0, 0, 0, 0, 0, 0, 0,
77 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0,
79 0, 0, 0, 0, 0, 0, 0, 0,
80 0, 0, 0, 0, 0, 0, 0, 0,
81 0, 0, 0, 0, 0, 0, 0, 0,
82 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0,
93 static int ocvt_E(FILE *, va_list *, int, int, int);
94 static int ocvt_G(FILE *, va_list *, int, int, int);
95 static int ocvt_X(FILE *, va_list *, int, int, int);
96 static int ocvt_c(FILE *, va_list *, int, int, int);
97 static int ocvt_d(FILE *, va_list *, int, int, int);
98 static int ocvt_e(FILE *, va_list *, int, int, int);
99 static int ocvt_f(FILE *, va_list *, int, int, int);
100 static int ocvt_g(FILE *, va_list *, int, int, int);
101 static int ocvt_n(FILE *, va_list *, int, int, int);
102 static int ocvt_o(FILE *, va_list *, int, int, int);
103 static int ocvt_p(FILE *, va_list *, int, int, int);
104 static int ocvt_s(FILE *, va_list *, int, int, int);
105 static int ocvt_u(FILE *, va_list *, int, int, int);
106 static int ocvt_x(FILE *, va_list *, int, int, int);
108 static int(*ocvt[])(FILE *, va_list *, int, int, int) = {
109 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
110 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
111 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
112 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
113 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
114 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
115 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
116 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
117 0, 0, 0, 0, 0, ocvt_E, 0, ocvt_G, /* @ A B C D E F G */
118 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
119 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
120 ocvt_X, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
121 0, 0, 0, ocvt_c, ocvt_d, ocvt_e, ocvt_f, ocvt_g, /* ` a b c d e f g */
122 0, ocvt_d, 0, 0, 0, 0, ocvt_n, ocvt_o, /* h i j k l m n o */
123 ocvt_p, 0, 0, ocvt_s, 0, ocvt_u, 0, 0, /* p q r s t u v w */
124 ocvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
126 0, 0, 0, 0, 0, 0, 0, 0,
127 0, 0, 0, 0, 0, 0, 0, 0,
128 0, 0, 0, 0, 0, 0, 0, 0,
129 0, 0, 0, 0, 0, 0, 0, 0,
130 0, 0, 0, 0, 0, 0, 0, 0,
131 0, 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0, 0,
135 0, 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 0, 0, 0, 0, 0,
137 0, 0, 0, 0, 0, 0, 0, 0,
138 0, 0, 0, 0, 0, 0, 0, 0,
139 0, 0, 0, 0, 0, 0, 0, 0,
140 0, 0, 0, 0, 0, 0, 0, 0,
141 0, 0, 0, 0, 0, 0, 0, 0,
149 vfprintf(FILE *f, const char *s, va_list args)
151 int flags, width, precision;
164 while(lflag[*s&_IO_CHMASK]) flags |= lflag[*s++&_IO_CHMASK];
166 width = va_arg(args, int);
175 while('0'<=*s && *s<='9') width = width*10 + *s++ - '0';
180 precision = va_arg(args, int);
185 while('0'<=*s && *s<='9') precision = precision*10 + *s++ - '0';
190 while(tflag[*s&_IO_CHMASK]) flags |= tflag[*s++&_IO_CHMASK];
191 if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
201 if((f->flags&STRING) && f->wp==f->rp && f->wp>f->buf){
211 ocvt_c(FILE *f, va_list *args, int flags, int width, int precision)
213 #pragma ref precision
216 if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
217 putc((unsigned char)va_arg(*args, int), f);
218 if(flags&LEFT) for(i=1; i<width; i++) putc(' ', f);
219 return width<1 ? 1 : width;
223 ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
228 s = va_arg(*args, char *);
231 for(i=0; i!=precision && s[i]; i++);
240 for(i=0; i!=precision && *s; i++){
260 ocvt_n(FILE *f, va_list *args, int flags, int width, int precision)
264 #pragma ref precision
266 *va_arg(*args, short *) = nprint;
268 *va_arg(*args, long *) = nprint;
270 *va_arg(*args, int *) = nprint;
275 * Generic fixed-point conversion
276 * f is the output FILE *;
277 * args is the va_list * from which to get the number;
278 * flags, width and precision are the results of printf-cracking;
279 * radix is the number base to print in;
280 * alphabet is the set of digits to use;
281 * prefix is the prefix to print before non-zero numbers when
282 * using ``alternate form.''
285 ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
286 int radix, int sgned, char alphabet[], char *prefix)
288 char digits[128]; /* no reasonable machine will ever overflow this */
293 int nout, npad, nlzero;
296 if(flags&PTR) snum = (long)va_arg(*args, void *);
297 else if(flags&SHORT) snum = va_arg(*args, short);
298 else if(flags&LONG) snum = va_arg(*args, long);
299 else snum = va_arg(*args, int);
304 if(flags&SIGN) sign = "+";
305 else if(flags&SPACE) sign = " ";
311 if(flags&PTR) num = (long)va_arg(*args, void *);
312 else if(flags&SHORT) num = va_arg(*args, unsigned short);
313 else if(flags&LONG) num = va_arg(*args, unsigned long);
314 else num = va_arg(*args, unsigned int);
316 if(num == 0) prefix = "";
319 *dp++ = alphabet[num%radix];
322 if(precision==0 && dp-digits==1 && dp[-1]=='0')
324 nlzero = precision-(dp-digits);
325 if(nlzero < 0) nlzero = 0;
327 if(radix == 8) if(dp[-1]=='0' || nlzero) prefix = "";
330 nout = dp-digits+nlzero+strlen(prefix)+strlen(sign);
332 if(npad < 0) npad = 0;
335 if(flags&ZPAD && precision <= 0){
354 while(dp!=digits) putc(*--dp, f);
363 while(dp != digits) putc(*--dp, f);
373 ocvt_X(FILE *f, va_list *args, int flags, int width, int precision)
375 return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789ABCDEF", "0X");
379 ocvt_d(FILE *f, va_list *args, int flags, int width, int precision)
381 return ocvt_fixed(f, args, flags, width, precision, 10, 1, "0123456789", "");
385 ocvt_o(FILE *f, va_list *args, int flags, int width, int precision)
387 return ocvt_fixed(f, args, flags, width, precision, 8, 0, "01234567", "0");
391 ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
393 return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
394 "0123456789ABCDEF", "0X");
398 ocvt_u(FILE *f, va_list *args, int flags, int width, int precision)
400 return ocvt_fixed(f, args, flags, width, precision, 10, 0, "0123456789", "");
404 ocvt_x(FILE *f, va_list *args, int flags, int width, int precision)
406 return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789abcdef", "0x");
409 static int ocvt_flt(FILE *, va_list *, int, int, int, char);
412 ocvt_E(FILE *f, va_list *args, int flags, int width, int precision)
414 return ocvt_flt(f, args, flags, width, precision, 'E');
418 ocvt_G(FILE *f, va_list *args, int flags, int width, int precision)
420 return ocvt_flt(f, args, flags, width, precision, 'G');
424 ocvt_e(FILE *f, va_list *args, int flags, int width, int precision)
426 return ocvt_flt(f, args, flags, width, precision, 'e');
430 ocvt_f(FILE *f, va_list *args, int flags, int width, int precision)
432 return ocvt_flt(f, args, flags, width, precision, 'f');
436 ocvt_g(FILE *f, va_list *args, int flags, int width, int precision)
438 return ocvt_flt(f, args, flags, width, precision, 'g');
442 ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
445 char *digits, *edigits;
451 char ebuf[20]; /* no sensible machine will overflow this */
457 d = va_arg(*args, double);
458 if(precision < 0) precision = 6;
461 digits = dtoa(d, 3, precision, &exponent, &sign, &edigits);
468 digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
475 digits = dtoa(d, 2, precision, &exponent, &sign, &edigits);
477 digits = dtoa(d, 0, precision, &exponent, &sign, &edigits);
478 precision = edigits - digits;
479 if (exponent > precision && exponent <= precision + 4)
480 precision = exponent;
482 if(exponent >= -3 && exponent <= precision){
484 precision -= exponent;
491 if (exponent == 9999) {
492 /* Infinity or Nan */
494 exponent = edigits - digits;
497 ndig = edigits-digits;
498 if((afmt=='g' || afmt=='G') && !(flags&ALT)){ /* knock off trailing zeros */
500 if(precision+exponent > ndig) {
501 precision = ndig - exponent;
507 if(precision > ndig-1) precision = ndig-1;
510 nout = precision; /* digits after decimal point */
511 if(precision!=0 || flags&ALT) nout++; /* decimal point */
512 if(fmt=='f' && exponent>0) nout += exponent; /* digits before decimal point */
513 else nout++; /* there's always at least one */
514 if(sign || flags&(SPACE|SIGN)) nout++; /* sign */
515 if(fmt != 'f'){ /* exponent */
517 for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
518 *eptr++ = '0' + i%10;
519 while(eptr<ebuf+2) *eptr++ = '0';
520 nout += eptr-ebuf+2; /* e+99 */
522 if(!(flags&ZPAD) && !(flags&LEFT))
527 if(sign) putc('-', f);
528 else if(flags&SIGN) putc('+', f);
529 else if(flags&SPACE) putc(' ', f);
536 for(i=0; i<exponent; i++) putc(i<ndig?digits[i]:'0', f);
537 if(i == 0) putc('0', f);
538 if(precision>0 || flags&ALT) putc('.', f);
539 for(i=0; i!=precision; i++)
540 putc(0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0', f);
544 if(precision>0 || flags&ALT) putc('.', f);
545 for(i=0; i!=precision; i++) putc(i<ndig-1?digits[i+1]:'0', f);
549 putc(exponent<=0?'-':'+', f);
550 while(eptr>ebuf) putc(*--eptr, f);