xref: /inferno-os/libmath/gfltconv.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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