| tpick up plan 9 fltfmt changes - plan9port - [fork] Plan 9 from user space | |
| git clone git://src.adamsgaard.dk/plan9port | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| commit a76c0fd4a9a9a9a64893db614dd146a5819a6e0c | |
| parent 3f1a2197698858e42a9176ca6e8cd57f6ea8eb30 | |
| Author: rsc <devnull@localhost> | |
| Date: Sun, 26 Dec 2004 22:36:52 +0000 | |
| pick up plan 9 fltfmt changes | |
| Diffstat: | |
| M src/lib9/fmt/fltfmt.c | 463 +++++++++--------------------… | |
| 1 file changed, 138 insertions(+), 325 deletions(-) | |
| --- | |
| diff --git a/src/lib9/fmt/fltfmt.c b/src/lib9/fmt/fltfmt.c | |
| t@@ -25,6 +25,7 @@ | |
| enum | |
| { | |
| + FDIGIT = 30, | |
| FDEFLT = 6, | |
| NSIGNIF = 17 | |
| }; | |
| t@@ -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; | |
| - } | |
| - i = 0; | |
| - while(e) { | |
| - se[i++] = e % 10 + '0'; | |
| - e /= 10; | |
| + prec = FDEFLT; | |
| + if(fmt->flags & FmtPrec) | |
| + prec = fmt->prec; | |
| + if(prec > FDIGIT) | |
| + prec = FDIGIT; | |
| + if(isNaN(f)) { | |
| + strcpy(s2, "NaN"); | |
| + 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]; | |
| + if(isInf(f, -1)) { | |
| + strcpy(s2, "-Inf"); | |
| + return; | |
| } | |
| 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; | |
| t@@ -213,7 +194,7 @@ xdodtoa(char *s1, double f, int chr, int prec, int *decpt,… | |
| * back to get accuracy. | |
| */ | |
| for(i=0; i<NSIGNIF; i++) { | |
| - d = (int)g; | |
| + d = g; | |
| s1[i] = d + '0'; | |
| g = (g - d) * 10; | |
| } | |
| t@@ -225,21 +206,20 @@ xdodtoa(char *s1, double f, int chr, int prec, int *decp… | |
| 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); | |
| t@@ -249,9 +229,9 @@ xdodtoa(char *s1, double f, int chr, int prec, int *decpt,… | |
| /* | |
| * 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--; | |
| t@@ -266,179 +246,17 @@ xdodtoa(char *s1, double f, int chr, int prec, int *dec… | |
| } | |
| 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; | |
| - | |
| - 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); | |
| - } | |
| + if(sign) | |
| + s2[d++] = '-'; | |
| + else if(fmt->flags & FmtSign) | |
| + s2[d++] = '+'; | |
| + else if(fmt->flags & FmtSpace) | |
| + s2[d++] = ' '; | |
| /* | |
| * copy into final place | |
| t@@ -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; | |
| } | |
| t@@ -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; | |
| - } | |
| - c4 -= c2; | |
| - if(c3 > 0){ | |
| - if(fmtzdotpad(fmt, c3, c4) < 0){ | |
| - return -1; | |
| - } | |
| - c4 -= c3; | |
| + while(c3 > 0) { | |
| + if(c3 == c4) | |
| + s2[d++] = '.'; | |
| + s2[d++] = '0'; | |
| + 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); | |
| +} |