|
|
1.1 root 1: /*
2: * pANS stdio -- vfprintf
3: */
4: #include "iolib.h"
5: #include <stdarg.h>
6: #include <math.h>
7: #include <stdlib.h>
8: #include <string.h>
9: /*
10: * Leading flags
11: */
12: #define SPACE 1 /* ' ' prepend space if no sign printed */
13: #define ALT 2 /* '#' use alternate conversion */
14: #define SIGN 4 /* '+' prepend sign, even if positive */
15: #define LEFT 8 /* '-' left-justify */
16: #define ZPAD 16 /* '0' zero-pad */
17: /*
18: * Trailing flags
19: */
20: #define SHORT 32 /* 'h' convert a short integer */
21: #define LONG 64 /* 'l' convert a long integer */
22: #define LDBL 128 /* 'L' convert a long double */
23: #define PTR 256 /* convert a void * (%p) */
24:
25: static int lflag[] = { /* leading flags */
26: 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
27: 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
28: 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
29: 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
30: SPACE, 0, 0, ALT, 0, 0, 0, 0, /* sp ! " # $ % & ' */
31: 0, 0, 0, SIGN, 0, LEFT, 0, 0, /* ( ) * + , - . / */
32: ZPAD, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
33: 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
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 [ \ ] ^ _ */
38: 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
39: 0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
40: 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
41: 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
42:
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,
55: 0, 0, 0, 0, 0, 0, 0, 0,
56: 0, 0, 0, 0, 0, 0, 0, 0,
57: 0, 0, 0, 0, 0, 0, 0, 0,
58: 0, 0, 0, 0, 0, 0, 0, 0,
59: };
60:
61: static int tflag[] = { /* trailing flags */
62: 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
63: 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
64: 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
65: 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
66: 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
67: 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
68: 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
69: 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
70: 0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
71: 0, 0, 0, 0, LDBL, 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 [ \ ] ^ _ */
74: 0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
75: SHORT, 0, 0, 0, LONG, 0, 0, 0, /* h i j k l m n o */
76: 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
77: 0, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
78:
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,
91: 0, 0, 0, 0, 0, 0, 0, 0,
92: 0, 0, 0, 0, 0, 0, 0, 0,
93: 0, 0, 0, 0, 0, 0, 0, 0,
94: 0, 0, 0, 0, 0, 0, 0, 0,
95: };
96:
97: static int ocvt_E(FILE *, va_list *, int, int, int);
98: static int ocvt_G(FILE *, va_list *, int, int, int);
99: static int ocvt_X(FILE *, va_list *, int, int, int);
100: static int ocvt_c(FILE *, va_list *, int, int, int);
101: static int ocvt_d(FILE *, va_list *, int, int, int);
102: static int ocvt_e(FILE *, va_list *, int, int, int);
103: static int ocvt_f(FILE *, va_list *, int, int, int);
104: static int ocvt_g(FILE *, va_list *, int, int, int);
105: static int ocvt_n(FILE *, va_list *, int, int, int);
106: static int ocvt_o(FILE *, va_list *, int, int, int);
107: static int ocvt_p(FILE *, va_list *, int, int, int);
108: static int ocvt_s(FILE *, va_list *, int, int, int);
109: static int ocvt_u(FILE *, va_list *, int, int, int);
110: static int ocvt_x(FILE *, va_list *, int, int, int);
111:
112: static int(*ocvt[])(FILE *, va_list *, int, int, int) = {
113: 0, 0, 0, 0, 0, 0, 0, 0, /* ^@ ^A ^B ^C ^D ^E ^F ^G */
114: 0, 0, 0, 0, 0, 0, 0, 0, /* ^H ^I ^J ^K ^L ^M ^N ^O */
115: 0, 0, 0, 0, 0, 0, 0, 0, /* ^P ^Q ^R ^S ^T ^U ^V ^W */
116: 0, 0, 0, 0, 0, 0, 0, 0, /* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */
117: 0, 0, 0, 0, 0, 0, 0, 0, /* sp ! " # $ % & ' */
118: 0, 0, 0, 0, 0, 0, 0, 0, /* ( ) * + , - . / */
119: 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
120: 0, 0, 0, 0, 0, 0, 0, 0, /* 8 9 : ; < = > ? */
121: 0, 0, 0, 0, 0, ocvt_E, 0, ocvt_G, /* @ A B C D E F G */
122: 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
123: 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
124: ocvt_X, 0, 0, 0, 0, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
125: 0, 0, 0, ocvt_c, ocvt_d, ocvt_e, ocvt_f, ocvt_g, /* ` a b c d e f g */
126: 0, ocvt_d, 0, 0, 0, 0, ocvt_n, ocvt_o, /* h i j k l m n o */
127: ocvt_p, 0, 0, ocvt_s, 0, ocvt_u, 0, 0, /* p q r s t u v w */
128: ocvt_x, 0, 0, 0, 0, 0, 0, 0, /* x y z { | } ~ ^? */
129:
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,
142: 0, 0, 0, 0, 0, 0, 0, 0,
143: 0, 0, 0, 0, 0, 0, 0, 0,
144: 0, 0, 0, 0, 0, 0, 0, 0,
145: 0, 0, 0, 0, 0, 0, 0, 0,
146: };
147:
148: static int nprint;
149:
150: int
151: vfprintf(FILE *f, const char *s, va_list args)
152: {
153: int flags, width, precision;
154:
155: nprint = 0;
156: while(*s){
157: if(*s != '%'){
158: putc(*s++, f);
159: nprint++;
160: continue;
161: }
162: s++;
163: flags = 0;
164: while(lflag[*s&_IO_CHMASK]) flags |= lflag[*s++&_IO_CHMASK];
165: if(*s == '*'){
166: width = va_arg(args, int);
167: s++;
168: if(width<0){
169: flags |= LEFT;
170: width = -width;
171: }
172: }
173: else{
174: width = 0;
175: while('0'<=*s && *s<='9') width = width*10 + *s++ - '0';
176: }
177: if(*s == '.'){
178: s++;
179: if(*s == '*'){
180: precision = va_arg(args, int);
181: s++;
182: }
183: else{
184: precision = 0;
185: while('0'<=*s && *s<='9') precision = precision*10 + *s++ - '0';
186: }
187: }
188: else
189: precision = -1;
190: while(tflag[*s&_IO_CHMASK]) flags |= tflag[*s++&_IO_CHMASK];
191: if(ocvt[*s]) nprint += (*ocvt[*s++])(f, &args, flags, width, precision);
192: else if(*s){
193: putc(*s++, f);
194: nprint++;
195: }
196: }
197: return ferror(f)? -1: nprint; /* previous errors */
198: /* will be re-reported */
199: }
200:
201: static int
202: ocvt_c(FILE *f, va_list *args, int flags, int width, int precision)
203: {
204: #pragma ref precision
205: int i;
206:
207: if(!(flags&LEFT)) for(i=1; i<width; i++) putc(' ', f);
208: putc((unsigned char)va_arg(*args, int), f);
209: if(flags&LEFT) for(i=1; i<width; i++) putc(' ', f);
210: return width<1 ? 1 : width;
211: }
212:
213: static int
214: ocvt_s(FILE *f, va_list *args, int flags, int width, int precision)
215: {
216: int i, n = 0;
217: char *s;
218:
219: s = va_arg(*args, char *);
220: if(!(flags&LEFT)){
221: if(precision >= 0)
222: for(i=0; i!=precision && s[i]; i++);
223: else
224: for(i=0; s[i]; i++);
225: for(; i<width; i++){
226: putc(' ', f);
227: n++;
228: }
229: }
230: if(precision >= 0){
231: for(i=0; i!=precision && *s; i++){
232: putc(*s++, f);
233: n++;
234: }
235: } else{
236: for(i=0;*s;i++){
237: putc(*s++, f);
238: n++;
239: }
240: }
241: if(flags&LEFT){
242: for(; i<width; i++){
243: putc(' ', f);
244: n++;
245: }
246: }
247: return n;
248: }
249:
250: static int
251: ocvt_n(FILE *f, va_list *args, int flags, int width, int precision)
252: {
253: #pragma ref f
254: #pragma ref width
255: #pragma ref precision
256: if(flags&SHORT)
257: *va_arg(*args, short *) = nprint;
258: else if(flags&LONG)
259: *va_arg(*args, long *) = nprint;
260: else
261: *va_arg(*args, int *) = nprint;
262: return 0;
263: }
264:
265: /*
266: * Generic fixed-point conversion
267: * f is the output FILE *;
268: * args is the va_list * from which to get the number;
269: * flags, width and precision are the results of printf-cracking;
270: * radix is the number base to print in;
271: * alphabet is the set of digits to use;
272: * prefix is the prefix to print before non-zero numbers when
273: * using ``alternate form.''
274: */
275: static int
276: ocvt_fixed(FILE *f, va_list *args, int flags, int width, int precision,
277: int radix, int sgned, char alphabet[], char *prefix)
278: {
279: char digits[128]; /* no reasonable machine will ever overflow this */
280: char *sign;
281: char *dp;
282: long snum;
283: unsigned long num;
284: int c, nout, npad, nlzero;
285:
286: if(sgned){
287: if(flags&PTR) snum = (long)va_arg(*args, void *);
288: else if(flags&SHORT) snum = va_arg(*args, short);
289: else if(flags&LONG) snum = va_arg(*args, long);
290: else snum = va_arg(*args, int);
291: if(snum < 0){
292: sign = "-";
293: num = -snum;
294: } else{
295: if(flags&SIGN) sign = "+";
296: else if(flags&SPACE) sign = " ";
297: else sign = "";
298: num = snum;
299: }
300: } else {
301: sign = "";
302: if(flags&PTR) num = (long)va_arg(*args, void *);
303: else if(flags&SHORT) num = va_arg(*args, unsigned short);
304: else if(flags&LONG) num = va_arg(*args, unsigned long);
305: else num = va_arg(*args, unsigned int);
306: }
307: if(num == 0) prefix = "";
308: dp = digits;
309: do{
310: *dp++ = alphabet[num%radix];
311: num /= radix;
312: }while(num);
313: if(precision==0 && dp-digits==1 && dp[-1]=='0')
314: dp--;
315: nlzero = precision-(dp-digits);
316: if(nlzero < 0) nlzero = 0;
317: if(flags&ALT){
318: if(radix == 8) if(dp[-1]=='0' || nlzero) prefix = "";
319: }
320: else prefix = "";
321: nout = dp-digits+nlzero+strlen(prefix)+strlen(sign);
322: npad = width-nout;
323: if(npad < 0) npad = 0;
324: nout += npad;
325: if(!(flags&LEFT)){
326: if(flags&ZPAD && precision <= 0){
327: /* for sgi, we get a loop if we invoke puts here */
328: while(c = *sign++)
329: putc(c, f);
330: while(c = *prefix++)
331: putc(c, f);
332: while(npad){
333: putc('0', f);
334: --npad;
335: }
336: } else{
337: while(npad){
338: putc(' ', f);
339: --npad;
340: }
341: while(c = *sign++)
342: putc(c, f);
343: while(c = *prefix++)
344: putc(c, f);
345: }
346: while(nlzero){
347: putc('0', f);
348: --nlzero;
349: }
350: while(dp!=digits) putc(*--dp, f);
351: }
352: else{
353: while(c = *sign++)
354: putc(c, f);
355: while(c = *prefix++)
356: putc(c, f);
357: while(nlzero){
358: putc('0', f);
359: --nlzero;
360: }
361: while(dp != digits) putc(*--dp, f);
362: while(npad){
363: putc(' ', f);
364: --npad;
365: }
366: }
367: return nout;
368: }
369:
370: static int
371: ocvt_X(FILE *f, va_list *args, int flags, int width, int precision)
372: {
373: return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789ABCDEF", "0X");
374: }
375:
376: static int
377: ocvt_d(FILE *f, va_list *args, int flags, int width, int precision)
378: {
379: return ocvt_fixed(f, args, flags, width, precision, 10, 1, "0123456789", "");
380: }
381:
382: static int
383: ocvt_o(FILE *f, va_list *args, int flags, int width, int precision)
384: {
385: return ocvt_fixed(f, args, flags, width, precision, 8, 0, "01234567", "0");
386: }
387:
388: static int
389: ocvt_p(FILE *f, va_list *args, int flags, int width, int precision)
390: {
391: return ocvt_fixed(f, args, flags|PTR|ALT, width, precision, 16, 0,
392: "0123456789ABCDEF", "0X");
393: }
394:
395: static int
396: ocvt_u(FILE *f, va_list *args, int flags, int width, int precision)
397: {
398: return ocvt_fixed(f, args, flags, width, precision, 10, 0, "0123456789", "");
399: }
400:
401: static int
402: ocvt_x(FILE *f, va_list *args, int flags, int width, int precision)
403: {
404: return ocvt_fixed(f, args, flags, width, precision, 16, 0, "0123456789abcdef", "0x");
405: }
406:
407: static int ocvt_flt(FILE *, va_list *, int, int, int, char);
408:
409: static int
410: ocvt_E(FILE *f, va_list *args, int flags, int width, int precision)
411: {
412: return ocvt_flt(f, args, flags, width, precision, 'E');
413: }
414:
415: static int
416: ocvt_G(FILE *f, va_list *args, int flags, int width, int precision)
417: {
418: return ocvt_flt(f, args, flags, width, precision, 'G');
419: }
420:
421: static int
422: ocvt_e(FILE *f, va_list *args, int flags, int width, int precision)
423: {
424: return ocvt_flt(f, args, flags, width, precision, 'e');
425: }
426:
427: static int
428: ocvt_f(FILE *f, va_list *args, int flags, int width, int precision)
429: {
430: return ocvt_flt(f, args, flags, width, precision, 'f');
431: }
432:
433: static int
434: ocvt_g(FILE *f, va_list *args, int flags, int width, int precision)
435: {
436: return ocvt_flt(f, args, flags, width, precision, 'g');
437: }
438:
439: static int
440: ocvt_flt(FILE *f, va_list *args, int flags, int width, int precision, char afmt)
441: {
442: extern char *_dtoa(double, int, int, int*, int*, char **);
443: int echr;
444: char *digits, *edigits;
445: int exponent;
446: char fmt;
447: int sign;
448: int ndig;
449: int nout, i;
450: char ebuf[20]; /* no sensible machine will overflow this */
451: char *eptr;
452: double d;
453:
454: echr = 'e';
455: fmt = afmt;
456: d = va_arg(*args, double);
457: if(precision < 0) precision = 6;
458: switch(fmt){
459: case 'f':
460: digits = _dtoa(d, 3, precision, &exponent, &sign, &edigits);
461: break;
462: case 'E':
463: echr = 'E';
464: fmt = 'e';
465: /* fall through */
466: case 'e':
467: digits = _dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
468: break;
469: case 'G':
470: echr = 'E';
471: /* fall through */
472: case 'g':
473: if (precision > 0)
474: digits = _dtoa(d, 2, precision, &exponent, &sign, &edigits);
475: else {
476: digits = _dtoa(d, 0, precision, &exponent, &sign, &edigits);
477: precision = edigits - digits;
478: if (exponent > precision && exponent <= precision + 4)
479: precision = exponent;
480: }
481: if(exponent >= -3 && exponent <= precision){
482: fmt = 'f';
483: precision -= exponent;
484: }else{
485: fmt = 'e';
486: --precision;
487: }
488: break;
489: }
490: if (exponent == 9999) {
491: /* Infinity or Nan */
492: precision = 0;
493: exponent = edigits - digits;
494: fmt = 'f';
495: }
496: ndig = edigits-digits;
497: if((afmt=='g' || afmt=='G') && !(flags&ALT)){ /* knock off trailing zeros */
498: if(fmt == 'f'){
499: if(precision+exponent > ndig) {
500: precision = ndig - exponent;
501: if(precision < 0)
502: precision = 0;
503: }
504: }
505: else{
506: if(precision > ndig-1) precision = ndig-1;
507: }
508: }
509: nout = precision; /* digits after decimal point */
510: if(precision!=0 || flags&ALT) nout++; /* decimal point */
511: if(fmt=='f' && exponent>0) nout += exponent; /* digits before decimal point */
512: else nout++; /* there's always at least one */
513: if(sign || flags&(SPACE|SIGN)) nout++; /* sign */
514: if(fmt != 'f'){ /* exponent */
515: eptr = ebuf;
516: for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
517: *eptr++ = '0' + i%10;
518: while(eptr<ebuf+2) *eptr++ = '0';
519: nout += eptr-ebuf+2; /* e+99 */
520: }
521: if(!(flags&ZPAD) && !(flags&LEFT))
522: while(nout < width){
523: putc(' ', f);
524: nout++;
525: }
526: if(sign) putc('-', f);
527: else if(flags&SIGN) putc('+', f);
528: else if(flags&SPACE) putc(' ', f);
529: if(flags&ZPAD)
530: while(nout < width){
531: putc('0', f);
532: nout++;
533: }
534: if(fmt == 'f'){
535: for(i=0; i<exponent; i++) putc(i<ndig?digits[i]:'0', f);
536: if(i == 0) putc('0', f);
537: if(precision>0 || flags&ALT) putc('.', f);
538: for(i=0; i!=precision; i++)
539: putc(0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0', f);
540: }
541: else{
542: putc(digits[0], f);
543: if(precision>0 || flags&ALT) putc('.', f);
544: for(i=0; i!=precision; i++) putc(i<ndig-1?digits[i+1]:'0', f);
545: }
546: if(fmt != 'f'){
547: putc(echr, f);
548: putc(exponent<=0?'-':'+', f);
549: while(eptr>ebuf) putc(*--eptr, f);
550: }
551: while(nout < width){
552: putc(' ', f);
553: nout++;
554: }
555: return nout;
556: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.