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