1 #include "lib9.h"
2 #include "mathi.h"
3 extern char *dtoa(double, int, int, int *, int *, char **);
4 extern void freedtoa(char*);
5 extern int _fmtcpy(Fmt*, void*, int, int);
6
7 enum
8 {
9 NONE = -1000,
10 FDIGIT = 20,
11 FDEFLT = 6,
12 NSIGNIF = 17
13 };
14
15 int
gfltconv(Fmt * f)16 gfltconv(Fmt *f)
17 {
18 int flags = f->flags;
19 int precision;
20 int fmt = f->r;
21 double d;
22 int echr, exponent, sign, ndig, nout, i;
23 char *digits, *edigits, ebuf[32], *eptr;
24 char out[64], *pout;
25
26 d = va_arg(f->args, double);
27 echr = 'e';
28 precision = FDEFLT;
29 if(f->flags & FmtPrec)
30 precision = f->prec;
31 if(precision > FDIGIT)
32 precision = FDIGIT;
33 switch(fmt){
34 case 'f':
35 digits = dtoa(d, 3, precision, &exponent, &sign, &edigits);
36 break;
37 case 0x00c9: /* L'É' */
38 case 'E':
39 echr = 'E';
40 fmt = 'e';
41 /* fall through */
42 case 'e':
43 digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
44 break;
45 case 'G':
46 echr = 'E';
47 /* fall through */
48 default:
49 case 'g':
50 if((flags&(FmtWidth|FmtPrec)) == 0){
51 g_fmt(out, d, echr);
52 f->flags &= FmtWidth|FmtLeft;
53 return _fmtcpy(f, out, strlen(out), strlen(out));
54 }
55 if (precision > 0)
56 digits = dtoa(d, 2, precision, &exponent, &sign, &edigits);
57 else {
58 digits = dtoa(d, 0, precision, &exponent, &sign, &edigits);
59 precision = edigits - digits;
60 if (exponent > precision && exponent <= precision + 4)
61 precision = exponent;
62 }
63 if(exponent >= -3 && exponent <= precision){
64 fmt = 'f';
65 precision -= exponent;
66 }else{
67 fmt = 'e';
68 --precision;
69 }
70 break;
71 }
72 if (exponent == 9999) {
73 /* Infinity or Nan */
74 precision = 0;
75 exponent = edigits - digits;
76 fmt = 'f';
77 }
78 ndig = edigits-digits;
79 if((f->r=='g' || f->r=='G') && !(flags&FmtSharp)){ /* knock off trailing zeros */
80 if(fmt == 'f'){
81 if(precision+exponent > ndig) {
82 precision = ndig - exponent;
83 if(precision < 0)
84 precision = 0;
85 }
86 }
87 else{
88 if(precision > ndig-1) precision = ndig-1;
89 }
90 }
91 eptr = ebuf;
92 if(fmt != 'f'){ /* exponent */
93 for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
94 *eptr++ = '0' + i%10;
95 while(eptr<ebuf+2) *eptr++ = '0';
96 }
97 pout = out;
98 if(sign) *pout++ = '-';
99 else if(flags&FmtSign) *pout++ = '+';
100 else if(flags&FmtSpace) *pout++ = ' ';
101 if(fmt == 'f'){
102 for(i=0; i<exponent; i++) *pout++ = i<ndig?digits[i]:'0';
103 if(i == 0) *pout++ = '0';
104 if(precision>0 || flags&FmtSharp) *pout++ = '.';
105 for(i=0; i!=precision; i++)
106 *pout++ = 0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0';
107 }
108 else{
109 *pout++ = digits[0];
110 if(precision>0 || flags&FmtSharp) *pout++ = '.';
111 for(i=0; i!=precision; i++) *pout++ = i<ndig-1?digits[i+1]:'0';
112 }
113 if(fmt != 'f'){
114 *pout++ = echr;
115 *pout++ = exponent<=0?'-':'+';
116 while(eptr>ebuf) *pout++ = *--eptr;
117 }
118 *pout = 0;
119 freedtoa(digits);
120 f->flags &= FmtWidth|FmtLeft;
121 nout = pout-out;
122 return _fmtcpy(f, out, nout, nout);
123 }
124