Commit Diff


commit - 3f1a2197698858e42a9176ca6e8cd57f6ea8eb30
commit + a76c0fd4a9a9a9a64893db614dd146a5819a6e0c
blob - a7e57997b0605e27b48caf0e87f4f51f856694ac
blob + 90b86c10068fd08a13699fa684267759b6071860
--- src/lib9/fmt/fltfmt.c
+++ src/lib9/fmt/fltfmt.c
@@ -25,6 +25,7 @@
 
 enum
 {
+	FDIGIT	= 30,
 	FDEFLT	= 6,
 	NSIGNIF	= 17
 };
@@ -129,67 +130,47 @@ xsub(char *a, int n, int v)
 }
 
 static void
-xaddexp(char *p, int e)
+xdtoa(Fmt *fmt, char *s2, double f)
 {
-	char se[9];
-	int i;
+	char s1[NSIGNIF+10];
+	double g, h;
+	int e, d, i, n;
+	int c1, c2, c3, c4, ucase, sign, chr, prec;
 
-	*p++ = 'e';
-	if(e < 0) {
-		*p++ = '-';
-		e = -e;
+	prec = FDEFLT;
+	if(fmt->flags & FmtPrec)
+		prec = fmt->prec;
+	if(prec > FDIGIT)
+		prec = FDIGIT;
+	if(isNaN(f)) {
+		strcpy(s2, "NaN");
+		return;
 	}
-	i = 0;
-	while(e) {
-		se[i++] = e % 10 + '0';
-		e /= 10;
+	if(isInf(f, 1)) {
+		strcpy(s2, "+Inf");
+		return;
 	}
-	if(i == 0) {
-		*p++ = '0';
-	} else {
-		while(i > 0)
-			*p++ = se[--i];
+	if(isInf(f, -1)) {
+		strcpy(s2, "-Inf");
+		return;
 	}
-	*p++ = '\0';
-}
-
-static char*
-xdodtoa(char *s1, double f, int chr, int prec, int *decpt, int *rsign)
-{
-	char s2[NSIGNIF+10];
-	double g, h;
-	int e, d, i;
-	int c2, sign, oerr;
-
-	if(chr == 'F')
-		chr = 'f';
-	if(prec > NSIGNIF)
-		prec = NSIGNIF;
-	if(prec < 0)
-		prec = 0;
-	if(__isNaN(f)) {
-		*decpt = 9999;
-		*rsign = 0;
-		strcpy(s1, "nan");
-		return &s1[3];
-	}
 	sign = 0;
 	if(f < 0) {
 		f = -f;
 		sign++;
 	}
-	*rsign = sign;
-	if(__isInf(f, 1) || __isInf(f, -1)) {
-		*decpt = 9999;
-		strcpy(s1, "inf");
-		return &s1[3];
+	ucase = 0;
+	chr = fmt->r;
+	if(isupper(chr)) {
+		ucase = 1;
+		chr = tolower(chr);
 	}
 
 	e = 0;
 	g = f;
 	if(g != 0) {
 		frexp(f, &e);
-		e = (int)(e * .301029995664);
+		e = e * .301029995664;
 		if(e >= -150 && e <= +150) {
 			d = 0;
 			h = f;
@@ -213,7 +194,7 @@ xdodtoa(char *s1, double f, int chr, int prec, int *de
 	 * back to get accuracy.
 	 */
 	for(i=0; i<NSIGNIF; i++) {
-		d = (int)g;
+		d = g;
 		s1[i] = d + '0';
 		g = (g - d) * 10;
 	}
@@ -225,21 +206,20 @@ xdodtoa(char *s1, double f, int chr, int prec, int *de
 	c2 = prec + 1;
 	if(chr == 'f')
 		c2 += e;
-	oerr = errno;
 	if(c2 >= NSIGNIF-2) {
 		strcpy(s2, s1);
 		d = e;
 		s1[NSIGNIF-2] = '0';
 		s1[NSIGNIF-1] = '0';
-		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
-		g = fmtstrtod(s1, nil);
+		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
+		g = strtod(s1, nil);
 		if(g == f)
 			goto found;
 		if(xadd(s1, NSIGNIF-3, 1)) {
 			e++;
-			xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
+			sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
 		}
-		g = fmtstrtod(s1, nil);
+		g = strtod(s1, nil);
 		if(g == f)
 			goto found;
 		strcpy(s1, s2);
@@ -249,9 +229,9 @@ xdodtoa(char *s1, double f, int chr, int prec, int *de
 	/*
 	 * convert back so s1 gets exact answer
 	 */
-	for(d = 0; d < 10; d++) {
-		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
-		g = fmtstrtod(s1, nil);
+	for(;;) {
+		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
+		g = strtod(s1, nil);
 		if(f > g) {
 			if(xadd(s1, NSIGNIF-1, 1))
 				e--;
@@ -266,180 +246,18 @@ xdodtoa(char *s1, double f, int chr, int prec, int *de
 	}
 
 found:
-	errno = oerr;
-
 	/*
 	 * sign
 	 */
 	d = 0;
 	i = 0;
-
-	/*
-	 * round & adjust 'f' digits
-	 */
-	c2 = prec + 1;
-	if(chr == 'f'){
-		if(xadd(s1, c2+e, 5))
-			e++;
-		c2 += e;
-		if(c2 < 0){
-			c2 = 0;
-			e = -prec - 1;
-		}
-	}else{
-		if(xadd(s1, c2, 5))
-			e++;
-	}
-	if(c2 > NSIGNIF){
-		c2 = NSIGNIF;
-	}
-
-	*decpt = e + 1;
-
-	/*
-	 * terminate the converted digits
-	 */
-	s1[c2] = '\0';
-	return &s1[c2];
-}
-
-/*
- * this function works like the standard dtoa, if you want it.
- */
-#if 0
-static char*
-__dtoa(double f, int mode, int ndigits, int *decpt, int *rsign, char **rve)
-{
-	static char s2[NSIGNIF + 10];
-	char *es;
-	int chr, prec;
-
-	switch(mode) {
-	/* like 'e' */
-	case 2:
-	case 4:
-	case 6:
-	case 8:
-		chr = 'e';
-		break;
-	/* like 'g' */
-	case 0:
-	case 1:
-	default:
-		chr = 'g';
-		break;
-	/* like 'f' */
-	case 3:
-	case 5:
-	case 7:
-	case 9:
-		chr = 'f';
-		break;
-	}
-
-	if(chr != 'f' && ndigits){
-		ndigits--;
-	}
-	prec = ndigits;
-	if(prec > NSIGNIF)
-		prec = NSIGNIF;
-	if(ndigits == 0)
-		prec = NSIGNIF;
-	es = xdodtoa(s2, f, chr, prec, decpt, rsign);
-
-	/*
-	 * strip trailing 0
-	 */
-	for(; es > s2 + 1; es--){
-		if(es[-1] != '0'){
-			break;
-		}
-	}
-	*es = '\0';
-	if(rve != NULL)
-		*rve = es;
-	return s2;
-}
-#endif
-
-static int
-fmtzdotpad(Fmt *f, int n, int pt)
-{
-	char *t, *s;
-	int i;
-	Rune *rt, *rs;
-
-	if(f->runes){
-		rt = (Rune*)f->to;
-		rs = (Rune*)f->stop;
-		for(i = 0; i < n; i++){
-			if(i == pt){
-				FMTRCHAR(f, rt, rs, '.');
-			}
-			FMTRCHAR(f, rt, rs, '0');
-		}
-		f->nfmt += rt - (Rune*)f->to;
-		f->to = rt;
-	}else{
-		t = (char*)f->to;
-		s = (char*)f->stop;
-		for(i = 0; i < n; i++){
-			if(i == pt){
-				FMTCHAR(f, t, s, '.');
-			}
-			FMTCHAR(f, t, s, '0');
-		}
-		f->nfmt += t - (char *)f->to;
-		f->to = t;
-	}
-	return 0;
-}
-
-int
-__efgfmt(Fmt *fmt)
-{
-	double f;
-	char s1[NSIGNIF+10];
-	int e, d, n;
-	int c1, c2, c3, c4, ucase, sign, chr, prec, fl;
-
-	f = va_arg(fmt->args, double);
-	prec = FDEFLT;
-	fl = fmt->flags;
-	fmt->flags = 0;
-	if(fl & FmtPrec)
-		prec = fmt->prec;
-	chr = fmt->r;
-	ucase = 0;
-	if(chr == 'E'){
-		chr = 'e';
-		ucase = 1;
-	}else if(chr == 'F'){
-		chr = 'f';
-		ucase = 1;
-	}else if(chr == 'G'){
-		chr = 'g';
-		ucase = 1;
-	}
-	if(prec > 0 && chr == 'g')
-		prec--;
-	if(prec < 0)
-		prec = 0;
+	if(sign)
+		s2[d++] = '-';
+	else if(fmt->flags & FmtSign)
+		s2[d++] = '+';
+	else if(fmt->flags & FmtSpace)
+		s2[d++] = ' ';
 
-	xdodtoa(s1, f, chr, prec, &e, &sign);
-	e--;
-	if(*s1 == 'i' || *s1 == 'n'){
-		if(ucase){
-			if(*s1 == 'i'){
-				strcpy(s1, "INF");
-			}else{
-				strcpy(s1, "NAN");
-			}
-		}
-		fmt->flags = fl & (FmtWidth|FmtLeft);
-		return __fmtcpy(fmt, (const void*)s1, 3, 3);
-	}
-
 	/*
 	 * copy into final place
 	 * c1 digits of leading '0'
@@ -453,22 +271,27 @@ __efgfmt(Fmt *fmt)
 	c4 = prec;
 	switch(chr) {
 	default:
-		chr = 'e';
+		if(xadd(s1, c2, 5))
+			e++;
 		break;
 	case 'g':
 		/*
 		 * decide on 'e' of 'f' style convers
 		 */
-		if(e >= -4 && e <= prec) {
-			c1 = -e;
+		if(xadd(s1, c2, 5))
+			e++;
+		if(e >= -5 && e <= prec) {
+			c1 = -e - 1;
 			c4 = prec - e;
-			chr = 'h';	/* flag for 'f' style */
+			chr = 'h';	// flag for 'f' style
 		}
 		break;
 	case 'f':
+		if(xadd(s1, c2+e, 5))
+			e++;
 		c1 = -e;
 		if(c1 > prec)
-			c1 = prec + 1;
+			c1 = c2;
 		c2 += e;
 		break;
 	}
@@ -486,126 +309,116 @@ __efgfmt(Fmt *fmt)
 	}
 
 	/*
-	 * trim trailing zeros for %g
-	 */
-	if(!(fl & FmtSharp)
-	&& (chr == 'g' || chr == 'h')){
-		if(c4 >= c3){
-			c4 -= c3;
-			c3 = 0;
-		}else{
-			c3 -= c4;
-			c4 = 0;
-		}
-		while(c4 && c2 > 1 && s1[c2 - 1] == '0'){
-			c4--;
-			c2--;
-		}
-	}
-
-	/*
-	 * calculate the total length
-	 */
-	n = c1 + c2 + c3;
-	if(sign || (fl & (FmtSign|FmtSpace)))
-		n++;
-	if(c4 || (fl & FmtSharp)){
-		n++;
-	}
-	if(chr == 'e' || chr == 'g'){
-		n += 4;
-		if(e >= 100)
-			n++;
-	}
-
-	/*
-	 * pad to width if right justified
-	 */
-	if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){
-		if(fl & FmtZero){
-			c1 += fmt->width - n;
-		}else{
-			if(__fmtpad(fmt, fmt->width - n) < 0){
-				return -1;
-			}
-		}
-	}
-
-	/*
-	 * sign
-	 */
-	d = 0;
-	if(sign)
-		d = '-';
-	else if(fl & FmtSign)
-		d = '+';
-	else if(fl & FmtSpace)
-		d = ' ';
-	if(d && fmtrune(fmt, d) < 0){
-		return -1;
-	}
-
-	/*
 	 * copy digits
 	 */
-	c4 = c1 + c2 + c3 - c4;
-	if(c1 > 0){
-		if(fmtzdotpad(fmt, c1, c4) < 0){
-			return -1;
-		}
-		c4 -= c1;
+	while(c1 > 0) {
+		if(c1+c2+c3 == c4)
+			s2[d++] = '.';
+		s2[d++] = '0';
+		c1--;
 	}
-	d = 0;
-	if(c4 >= 0 && c4 < c2){
-		if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0)
-			return -1;
-		d = c4;
-		c2 -= c4;
-		c4 = -1;
+	while(c2 > 0) {
+		if(c2+c3 == c4)
+			s2[d++] = '.';
+		s2[d++] = s1[i++];
+		c2--;
 	}
-	if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){
-		return -1;
+	while(c3 > 0) {
+		if(c3 == c4)
+			s2[d++] = '.';
+		s2[d++] = '0';
+		c3--;
 	}
-	c4 -= c2;
-	if(c3 > 0){
-		if(fmtzdotpad(fmt, c3, c4) < 0){
-			return -1;
-		}
-		c4 -= c3;
-	}
 
 	/*
 	 * strip trailing '0' on g conv
 	 */
-	if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){
-		return -1;
+	if(fmt->flags & FmtSharp) {
+		if(0 == c4)
+			s2[d++] = '.';
+	} else
+	if(chr == 'g' || chr == 'h') {
+		for(n=d-1; n>=0; n--)
+			if(s2[n] != '0')
+				break;
+		for(i=n; i>=0; i--)
+			if(s2[i] == '.') {
+				d = n;
+				if(i != n)
+					d++;
+				break;
+			}
 	}
 	if(chr == 'e' || chr == 'g') {
-		d = 0;
 		if(ucase)
-			s1[d++] = 'E';
+			s2[d++] = 'E';
 		else
-			s1[d++] = 'e';
+			s2[d++] = 'e';
 		c1 = e;
 		if(c1 < 0) {
-			s1[d++] = '-';
+			s2[d++] = '-';
 			c1 = -c1;
 		} else
-			s1[d++] = '+';
+			s2[d++] = '+';
 		if(c1 >= 100) {
-			s1[d++] = c1/100 + '0';
+			s2[d++] = c1/100 + '0';
 			c1 = c1%100;
 		}
-		s1[d++] = c1/10 + '0';
-		s1[d++] = c1%10 + '0';
-		if(__fmtcpy(fmt, s1, d, d) < 0){
-			return -1;
-		}
+		s2[d++] = c1/10 + '0';
+		s2[d++] = c1%10 + '0';
 	}
-	if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){
-		if(__fmtpad(fmt, fmt->width - n) < 0){
-			return -1;
+	s2[d] = 0;
+}
+
+static int
+fmtzdotpad(Fmt *f, int n, int pt)
+{
+	char *t, *s;
+	int i;
+	Rune *rt, *rs;
+
+	if(f->runes){
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(i = 0; i < n; i++){
+			if(i == pt){
+				FMTRCHAR(f, rt, rs, '.');
+			}
+			FMTRCHAR(f, rt, rs, '0');
 		}
+		f->nfmt += rt - (Rune*)f->to;
+		f->to = rt;
+	}else{
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(i = 0; i < n; i++){
+			if(i == pt){
+				FMTCHAR(f, t, s, '.');
+			}
+			FMTCHAR(f, t, s, '0');
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
 	}
 	return 0;
 }
+
+static int
+floatfmt(Fmt *fmt, double f)
+{
+	char s[FDIGIT+10];
+
+	xdtoa(fmt, s, f);
+	fmt->flags &= FmtWidth|FmtLeft;
+	__fmtcpy(fmt, s, strlen(s), strlen(s));
+	return 0;
+}
+
+int
+__efgfmt(Fmt *f)
+{
+	double d;
+
+	d = va_arg(f->args, double);
+	return floatfmt(f, d);
+}