140ef9009SDavid du Colombier /*
240ef9009SDavid du Colombier * The authors of this software are Rob Pike and Ken Thompson.
340ef9009SDavid du Colombier * Copyright (c) 2002 by Lucent Technologies.
440ef9009SDavid du Colombier * Permission to use, copy, modify, and distribute this software for any
540ef9009SDavid du Colombier * purpose without fee is hereby granted, provided that this entire notice
640ef9009SDavid du Colombier * is included in all copies of any software which is or includes a copy
740ef9009SDavid du Colombier * or modification of this software and in all copies of the supporting
840ef9009SDavid du Colombier * documentation for such software.
940ef9009SDavid du Colombier * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
1040ef9009SDavid du Colombier * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
1140ef9009SDavid du Colombier * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
1240ef9009SDavid du Colombier * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
1340ef9009SDavid du Colombier */
1440ef9009SDavid du Colombier #include <stdio.h>
1540ef9009SDavid du Colombier #include <math.h>
1640ef9009SDavid du Colombier #include <float.h>
1740ef9009SDavid du Colombier #include <string.h>
1840ef9009SDavid du Colombier #include <stdlib.h>
1940ef9009SDavid du Colombier #include <errno.h>
2040ef9009SDavid du Colombier #include <stdarg.h>
2140ef9009SDavid du Colombier #include "fmt.h"
2240ef9009SDavid du Colombier #include "fmtdef.h"
2340ef9009SDavid du Colombier #include "nan.h"
2440ef9009SDavid du Colombier
2540ef9009SDavid du Colombier enum
2640ef9009SDavid du Colombier {
2740ef9009SDavid du Colombier FDEFLT = 6,
2840ef9009SDavid du Colombier NSIGNIF = 17
2940ef9009SDavid du Colombier };
3040ef9009SDavid du Colombier
3140ef9009SDavid du Colombier /*
3240ef9009SDavid du Colombier * first few powers of 10, enough for about 1/2 of the
3340ef9009SDavid du Colombier * total space for doubles.
3440ef9009SDavid du Colombier */
3540ef9009SDavid du Colombier static double pows10[] =
3640ef9009SDavid du Colombier {
3740ef9009SDavid du Colombier 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
3840ef9009SDavid du Colombier 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
3940ef9009SDavid du Colombier 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
4040ef9009SDavid du Colombier 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
4140ef9009SDavid du Colombier 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
4240ef9009SDavid du Colombier 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
4340ef9009SDavid du Colombier 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
4440ef9009SDavid du Colombier 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
4540ef9009SDavid du Colombier 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
4640ef9009SDavid du Colombier 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
4740ef9009SDavid du Colombier 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
4840ef9009SDavid du Colombier 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
4940ef9009SDavid du Colombier 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
5040ef9009SDavid du Colombier 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
5140ef9009SDavid du Colombier 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
5240ef9009SDavid du Colombier 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
5340ef9009SDavid du Colombier };
5440ef9009SDavid du Colombier
5540ef9009SDavid du Colombier static double
pow10(int n)5640ef9009SDavid du Colombier pow10(int n)
5740ef9009SDavid du Colombier {
5840ef9009SDavid du Colombier double d;
5940ef9009SDavid du Colombier int neg;
6040ef9009SDavid du Colombier
6140ef9009SDavid du Colombier neg = 0;
6240ef9009SDavid du Colombier if(n < 0){
6340ef9009SDavid du Colombier if(n < DBL_MIN_10_EXP){
6440ef9009SDavid du Colombier return 0.;
6540ef9009SDavid du Colombier }
6640ef9009SDavid du Colombier neg = 1;
6740ef9009SDavid du Colombier n = -n;
6840ef9009SDavid du Colombier }else if(n > DBL_MAX_10_EXP){
6940ef9009SDavid du Colombier return HUGE_VAL;
7040ef9009SDavid du Colombier }
7140ef9009SDavid du Colombier if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
7240ef9009SDavid du Colombier d = pows10[n];
7340ef9009SDavid du Colombier else{
7440ef9009SDavid du Colombier d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
7540ef9009SDavid du Colombier for(;;){
7640ef9009SDavid du Colombier n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
7740ef9009SDavid du Colombier if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
7840ef9009SDavid du Colombier d *= pows10[n];
7940ef9009SDavid du Colombier break;
8040ef9009SDavid du Colombier }
8140ef9009SDavid du Colombier d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
8240ef9009SDavid du Colombier }
8340ef9009SDavid du Colombier }
8440ef9009SDavid du Colombier if(neg){
8540ef9009SDavid du Colombier return 1./d;
8640ef9009SDavid du Colombier }
8740ef9009SDavid du Colombier return d;
8840ef9009SDavid du Colombier }
8940ef9009SDavid du Colombier
9040ef9009SDavid du Colombier static int
xadd(char * a,int n,int v)9140ef9009SDavid du Colombier xadd(char *a, int n, int v)
9240ef9009SDavid du Colombier {
9340ef9009SDavid du Colombier char *b;
9440ef9009SDavid du Colombier int c;
9540ef9009SDavid du Colombier
9640ef9009SDavid du Colombier if(n < 0 || n >= NSIGNIF)
9740ef9009SDavid du Colombier return 0;
9840ef9009SDavid du Colombier for(b = a+n; b >= a; b--) {
9940ef9009SDavid du Colombier c = *b + v;
10040ef9009SDavid du Colombier if(c <= '9') {
10140ef9009SDavid du Colombier *b = c;
10240ef9009SDavid du Colombier return 0;
10340ef9009SDavid du Colombier }
10440ef9009SDavid du Colombier *b = '0';
10540ef9009SDavid du Colombier v = 1;
10640ef9009SDavid du Colombier }
10740ef9009SDavid du Colombier *a = '1'; /* overflow adding */
10840ef9009SDavid du Colombier return 1;
10940ef9009SDavid du Colombier }
11040ef9009SDavid du Colombier
11140ef9009SDavid du Colombier static int
xsub(char * a,int n,int v)11240ef9009SDavid du Colombier xsub(char *a, int n, int v)
11340ef9009SDavid du Colombier {
11440ef9009SDavid du Colombier char *b;
11540ef9009SDavid du Colombier int c;
11640ef9009SDavid du Colombier
11740ef9009SDavid du Colombier for(b = a+n; b >= a; b--) {
11840ef9009SDavid du Colombier c = *b - v;
11940ef9009SDavid du Colombier if(c >= '0') {
12040ef9009SDavid du Colombier *b = c;
12140ef9009SDavid du Colombier return 0;
12240ef9009SDavid du Colombier }
12340ef9009SDavid du Colombier *b = '9';
12440ef9009SDavid du Colombier v = 1;
12540ef9009SDavid du Colombier }
12640ef9009SDavid du Colombier *a = '9'; /* underflow subtracting */
12740ef9009SDavid du Colombier return 1;
12840ef9009SDavid du Colombier }
12940ef9009SDavid du Colombier
13040ef9009SDavid du Colombier static void
xaddexp(char * p,int e)13140ef9009SDavid du Colombier xaddexp(char *p, int e)
13240ef9009SDavid du Colombier {
13340ef9009SDavid du Colombier char se[9];
13440ef9009SDavid du Colombier int i;
13540ef9009SDavid du Colombier
13640ef9009SDavid du Colombier *p++ = 'e';
13740ef9009SDavid du Colombier if(e < 0) {
13840ef9009SDavid du Colombier *p++ = '-';
13940ef9009SDavid du Colombier e = -e;
14040ef9009SDavid du Colombier }
14140ef9009SDavid du Colombier i = 0;
14240ef9009SDavid du Colombier while(e) {
14340ef9009SDavid du Colombier se[i++] = e % 10 + '0';
14440ef9009SDavid du Colombier e /= 10;
14540ef9009SDavid du Colombier }
14640ef9009SDavid du Colombier if(i == 0) {
14740ef9009SDavid du Colombier *p++ = '0';
14840ef9009SDavid du Colombier } else {
14940ef9009SDavid du Colombier while(i > 0)
15040ef9009SDavid du Colombier *p++ = se[--i];
15140ef9009SDavid du Colombier }
152*781103c4SDavid du Colombier *p = '\0';
15340ef9009SDavid du Colombier }
15440ef9009SDavid du Colombier
15540ef9009SDavid du Colombier static char*
xdodtoa(char * s1,double f,int chr,int prec,int * decpt,int * rsign)15640ef9009SDavid du Colombier xdodtoa(char *s1, double f, int chr, int prec, int *decpt, int *rsign)
15740ef9009SDavid du Colombier {
15840ef9009SDavid du Colombier char s2[NSIGNIF+10];
15940ef9009SDavid du Colombier double g, h;
16040ef9009SDavid du Colombier int e, d, i;
16140ef9009SDavid du Colombier int c2, sign, oerr;
16240ef9009SDavid du Colombier
16340ef9009SDavid du Colombier if(chr == 'F')
16440ef9009SDavid du Colombier chr = 'f';
16540ef9009SDavid du Colombier if(prec > NSIGNIF)
16640ef9009SDavid du Colombier prec = NSIGNIF;
16740ef9009SDavid du Colombier if(prec < 0)
16840ef9009SDavid du Colombier prec = 0;
16940ef9009SDavid du Colombier if(__isNaN(f)) {
17040ef9009SDavid du Colombier *decpt = 9999;
17140ef9009SDavid du Colombier *rsign = 0;
17240ef9009SDavid du Colombier strcpy(s1, "nan");
17340ef9009SDavid du Colombier return &s1[3];
17440ef9009SDavid du Colombier }
17540ef9009SDavid du Colombier sign = 0;
17640ef9009SDavid du Colombier if(f < 0) {
17740ef9009SDavid du Colombier f = -f;
17840ef9009SDavid du Colombier sign++;
17940ef9009SDavid du Colombier }
18040ef9009SDavid du Colombier *rsign = sign;
18140ef9009SDavid du Colombier if(__isInf(f, 1) || __isInf(f, -1)) {
18240ef9009SDavid du Colombier *decpt = 9999;
18340ef9009SDavid du Colombier strcpy(s1, "inf");
18440ef9009SDavid du Colombier return &s1[3];
18540ef9009SDavid du Colombier }
18640ef9009SDavid du Colombier
18740ef9009SDavid du Colombier e = 0;
18840ef9009SDavid du Colombier g = f;
18940ef9009SDavid du Colombier if(g != 0) {
19040ef9009SDavid du Colombier frexp(f, &e);
19140ef9009SDavid du Colombier e = (int)(e * .301029995664);
19240ef9009SDavid du Colombier if(e >= -150 && e <= +150) {
19340ef9009SDavid du Colombier d = 0;
19440ef9009SDavid du Colombier h = f;
19540ef9009SDavid du Colombier } else {
19640ef9009SDavid du Colombier d = e/2;
19740ef9009SDavid du Colombier h = f * pow10(-d);
19840ef9009SDavid du Colombier }
19940ef9009SDavid du Colombier g = h * pow10(d-e);
20040ef9009SDavid du Colombier while(g < 1) {
20140ef9009SDavid du Colombier e--;
20240ef9009SDavid du Colombier g = h * pow10(d-e);
20340ef9009SDavid du Colombier }
20440ef9009SDavid du Colombier while(g >= 10) {
20540ef9009SDavid du Colombier e++;
20640ef9009SDavid du Colombier g = h * pow10(d-e);
20740ef9009SDavid du Colombier }
20840ef9009SDavid du Colombier }
20940ef9009SDavid du Colombier
21040ef9009SDavid du Colombier /*
21140ef9009SDavid du Colombier * convert NSIGNIF digits and convert
21240ef9009SDavid du Colombier * back to get accuracy.
21340ef9009SDavid du Colombier */
21440ef9009SDavid du Colombier for(i=0; i<NSIGNIF; i++) {
21540ef9009SDavid du Colombier d = (int)g;
21640ef9009SDavid du Colombier s1[i] = d + '0';
21740ef9009SDavid du Colombier g = (g - d) * 10;
21840ef9009SDavid du Colombier }
21940ef9009SDavid du Colombier s1[i] = 0;
22040ef9009SDavid du Colombier
22140ef9009SDavid du Colombier /*
22240ef9009SDavid du Colombier * try decimal rounding to eliminate 9s
22340ef9009SDavid du Colombier */
22440ef9009SDavid du Colombier c2 = prec + 1;
22540ef9009SDavid du Colombier if(chr == 'f')
22640ef9009SDavid du Colombier c2 += e;
22740ef9009SDavid du Colombier oerr = errno;
22840ef9009SDavid du Colombier if(c2 >= NSIGNIF-2) {
22940ef9009SDavid du Colombier strcpy(s2, s1);
23040ef9009SDavid du Colombier d = e;
23140ef9009SDavid du Colombier s1[NSIGNIF-2] = '0';
23240ef9009SDavid du Colombier s1[NSIGNIF-1] = '0';
23340ef9009SDavid du Colombier xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
23440ef9009SDavid du Colombier g = fmtstrtod(s1, nil);
23540ef9009SDavid du Colombier if(g == f)
23640ef9009SDavid du Colombier goto found;
23740ef9009SDavid du Colombier if(xadd(s1, NSIGNIF-3, 1)) {
23840ef9009SDavid du Colombier e++;
23940ef9009SDavid du Colombier xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
24040ef9009SDavid du Colombier }
24140ef9009SDavid du Colombier g = fmtstrtod(s1, nil);
24240ef9009SDavid du Colombier if(g == f)
24340ef9009SDavid du Colombier goto found;
24440ef9009SDavid du Colombier strcpy(s1, s2);
24540ef9009SDavid du Colombier e = d;
24640ef9009SDavid du Colombier }
24740ef9009SDavid du Colombier
24840ef9009SDavid du Colombier /*
24940ef9009SDavid du Colombier * convert back so s1 gets exact answer
25040ef9009SDavid du Colombier */
25140ef9009SDavid du Colombier for(d = 0; d < 10; d++) {
25240ef9009SDavid du Colombier xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
25340ef9009SDavid du Colombier g = fmtstrtod(s1, nil);
25440ef9009SDavid du Colombier if(f > g) {
25540ef9009SDavid du Colombier if(xadd(s1, NSIGNIF-1, 1))
25640ef9009SDavid du Colombier e--;
25740ef9009SDavid du Colombier continue;
25840ef9009SDavid du Colombier }
25940ef9009SDavid du Colombier if(f < g) {
26040ef9009SDavid du Colombier if(xsub(s1, NSIGNIF-1, 1))
26140ef9009SDavid du Colombier e++;
26240ef9009SDavid du Colombier continue;
26340ef9009SDavid du Colombier }
26440ef9009SDavid du Colombier break;
26540ef9009SDavid du Colombier }
26640ef9009SDavid du Colombier
26740ef9009SDavid du Colombier found:
26840ef9009SDavid du Colombier errno = oerr;
26940ef9009SDavid du Colombier
27040ef9009SDavid du Colombier /*
27140ef9009SDavid du Colombier * round & adjust 'f' digits
27240ef9009SDavid du Colombier */
27340ef9009SDavid du Colombier c2 = prec + 1;
27440ef9009SDavid du Colombier if(chr == 'f'){
27540ef9009SDavid du Colombier if(xadd(s1, c2+e, 5))
27640ef9009SDavid du Colombier e++;
27740ef9009SDavid du Colombier c2 += e;
27840ef9009SDavid du Colombier if(c2 < 0){
27940ef9009SDavid du Colombier c2 = 0;
28040ef9009SDavid du Colombier e = -prec - 1;
28140ef9009SDavid du Colombier }
28240ef9009SDavid du Colombier }else{
28340ef9009SDavid du Colombier if(xadd(s1, c2, 5))
28440ef9009SDavid du Colombier e++;
28540ef9009SDavid du Colombier }
28640ef9009SDavid du Colombier if(c2 > NSIGNIF){
28740ef9009SDavid du Colombier c2 = NSIGNIF;
28840ef9009SDavid du Colombier }
28940ef9009SDavid du Colombier
29040ef9009SDavid du Colombier *decpt = e + 1;
29140ef9009SDavid du Colombier
29240ef9009SDavid du Colombier /*
29340ef9009SDavid du Colombier * terminate the converted digits
29440ef9009SDavid du Colombier */
29540ef9009SDavid du Colombier s1[c2] = '\0';
29640ef9009SDavid du Colombier return &s1[c2];
29740ef9009SDavid du Colombier }
29840ef9009SDavid du Colombier
29940ef9009SDavid du Colombier /*
30040ef9009SDavid du Colombier * this function works like the standard dtoa, if you want it.
30140ef9009SDavid du Colombier */
30240ef9009SDavid du Colombier #if 0
30340ef9009SDavid du Colombier static char*
30440ef9009SDavid du Colombier __dtoa(double f, int mode, int ndigits, int *decpt, int *rsign, char **rve)
30540ef9009SDavid du Colombier {
30640ef9009SDavid du Colombier static char s2[NSIGNIF + 10];
30740ef9009SDavid du Colombier char *es;
30840ef9009SDavid du Colombier int chr, prec;
30940ef9009SDavid du Colombier
31040ef9009SDavid du Colombier switch(mode) {
31140ef9009SDavid du Colombier /* like 'e' */
31240ef9009SDavid du Colombier case 2:
31340ef9009SDavid du Colombier case 4:
31440ef9009SDavid du Colombier case 6:
31540ef9009SDavid du Colombier case 8:
31640ef9009SDavid du Colombier chr = 'e';
31740ef9009SDavid du Colombier break;
31840ef9009SDavid du Colombier /* like 'g' */
31940ef9009SDavid du Colombier case 0:
32040ef9009SDavid du Colombier case 1:
32140ef9009SDavid du Colombier default:
32240ef9009SDavid du Colombier chr = 'g';
32340ef9009SDavid du Colombier break;
32440ef9009SDavid du Colombier /* like 'f' */
32540ef9009SDavid du Colombier case 3:
32640ef9009SDavid du Colombier case 5:
32740ef9009SDavid du Colombier case 7:
32840ef9009SDavid du Colombier case 9:
32940ef9009SDavid du Colombier chr = 'f';
33040ef9009SDavid du Colombier break;
33140ef9009SDavid du Colombier }
33240ef9009SDavid du Colombier
33340ef9009SDavid du Colombier if(chr != 'f' && ndigits){
33440ef9009SDavid du Colombier ndigits--;
33540ef9009SDavid du Colombier }
33640ef9009SDavid du Colombier prec = ndigits;
33740ef9009SDavid du Colombier if(prec > NSIGNIF)
33840ef9009SDavid du Colombier prec = NSIGNIF;
33940ef9009SDavid du Colombier if(ndigits == 0)
34040ef9009SDavid du Colombier prec = NSIGNIF;
34140ef9009SDavid du Colombier es = xdodtoa(s2, f, chr, prec, decpt, rsign);
34240ef9009SDavid du Colombier
34340ef9009SDavid du Colombier /*
34440ef9009SDavid du Colombier * strip trailing 0
34540ef9009SDavid du Colombier */
34640ef9009SDavid du Colombier for(; es > s2 + 1; es--){
34740ef9009SDavid du Colombier if(es[-1] != '0'){
34840ef9009SDavid du Colombier break;
34940ef9009SDavid du Colombier }
35040ef9009SDavid du Colombier }
35140ef9009SDavid du Colombier *es = '\0';
35240ef9009SDavid du Colombier if(rve != NULL)
35340ef9009SDavid du Colombier *rve = es;
35440ef9009SDavid du Colombier return s2;
35540ef9009SDavid du Colombier }
35640ef9009SDavid du Colombier #endif
35740ef9009SDavid du Colombier
35840ef9009SDavid du Colombier static int
fmtzdotpad(Fmt * f,int n,int pt)35940ef9009SDavid du Colombier fmtzdotpad(Fmt *f, int n, int pt)
36040ef9009SDavid du Colombier {
36140ef9009SDavid du Colombier char *t, *s;
36240ef9009SDavid du Colombier int i;
36340ef9009SDavid du Colombier Rune *rt, *rs;
36440ef9009SDavid du Colombier
36540ef9009SDavid du Colombier if(f->runes){
36640ef9009SDavid du Colombier rt = (Rune*)f->to;
36740ef9009SDavid du Colombier rs = (Rune*)f->stop;
36840ef9009SDavid du Colombier for(i = 0; i < n; i++){
36940ef9009SDavid du Colombier if(i == pt){
37040ef9009SDavid du Colombier FMTRCHAR(f, rt, rs, '.');
37140ef9009SDavid du Colombier }
37240ef9009SDavid du Colombier FMTRCHAR(f, rt, rs, '0');
37340ef9009SDavid du Colombier }
37440ef9009SDavid du Colombier f->nfmt += rt - (Rune*)f->to;
37540ef9009SDavid du Colombier f->to = rt;
37640ef9009SDavid du Colombier }else{
37740ef9009SDavid du Colombier t = (char*)f->to;
37840ef9009SDavid du Colombier s = (char*)f->stop;
37940ef9009SDavid du Colombier for(i = 0; i < n; i++){
38040ef9009SDavid du Colombier if(i == pt){
38140ef9009SDavid du Colombier FMTCHAR(f, t, s, '.');
38240ef9009SDavid du Colombier }
38340ef9009SDavid du Colombier FMTCHAR(f, t, s, '0');
38440ef9009SDavid du Colombier }
38540ef9009SDavid du Colombier f->nfmt += t - (char *)f->to;
38640ef9009SDavid du Colombier f->to = t;
38740ef9009SDavid du Colombier }
38840ef9009SDavid du Colombier return 0;
38940ef9009SDavid du Colombier }
39040ef9009SDavid du Colombier
39140ef9009SDavid du Colombier int
__efgfmt(Fmt * fmt)39240ef9009SDavid du Colombier __efgfmt(Fmt *fmt)
39340ef9009SDavid du Colombier {
39440ef9009SDavid du Colombier double f;
39540ef9009SDavid du Colombier char s1[NSIGNIF+10];
39640ef9009SDavid du Colombier int e, d, n;
39740ef9009SDavid du Colombier int c1, c2, c3, c4, ucase, sign, chr, prec, fl;
39840ef9009SDavid du Colombier
39940ef9009SDavid du Colombier f = va_arg(fmt->args, double);
40040ef9009SDavid du Colombier prec = FDEFLT;
40140ef9009SDavid du Colombier fl = fmt->flags;
40240ef9009SDavid du Colombier fmt->flags = 0;
40340ef9009SDavid du Colombier if(fl & FmtPrec)
40440ef9009SDavid du Colombier prec = fmt->prec;
40540ef9009SDavid du Colombier chr = fmt->r;
40640ef9009SDavid du Colombier ucase = 0;
40740ef9009SDavid du Colombier if(chr == 'E'){
40840ef9009SDavid du Colombier chr = 'e';
40940ef9009SDavid du Colombier ucase = 1;
41040ef9009SDavid du Colombier }else if(chr == 'F'){
41140ef9009SDavid du Colombier chr = 'f';
41240ef9009SDavid du Colombier ucase = 1;
41340ef9009SDavid du Colombier }else if(chr == 'G'){
41440ef9009SDavid du Colombier chr = 'g';
41540ef9009SDavid du Colombier ucase = 1;
41640ef9009SDavid du Colombier }
41740ef9009SDavid du Colombier if(prec > 0 && chr == 'g')
41840ef9009SDavid du Colombier prec--;
41940ef9009SDavid du Colombier if(prec < 0)
42040ef9009SDavid du Colombier prec = 0;
42140ef9009SDavid du Colombier
42240ef9009SDavid du Colombier xdodtoa(s1, f, chr, prec, &e, &sign);
42340ef9009SDavid du Colombier e--;
42440ef9009SDavid du Colombier if(*s1 == 'i' || *s1 == 'n'){
42540ef9009SDavid du Colombier if(ucase){
42640ef9009SDavid du Colombier if(*s1 == 'i'){
42740ef9009SDavid du Colombier strcpy(s1, "INF");
42840ef9009SDavid du Colombier }else{
42940ef9009SDavid du Colombier strcpy(s1, "NAN");
43040ef9009SDavid du Colombier }
43140ef9009SDavid du Colombier }
43240ef9009SDavid du Colombier fmt->flags = fl & (FmtWidth|FmtLeft);
43340ef9009SDavid du Colombier return __fmtcpy(fmt, (const void*)s1, 3, 3);
43440ef9009SDavid du Colombier }
43540ef9009SDavid du Colombier
43640ef9009SDavid du Colombier /*
43740ef9009SDavid du Colombier * copy into final place
43840ef9009SDavid du Colombier * c1 digits of leading '0'
43940ef9009SDavid du Colombier * c2 digits from conversion
44040ef9009SDavid du Colombier * c3 digits of trailing '0'
44140ef9009SDavid du Colombier * c4 digits after '.'
44240ef9009SDavid du Colombier */
44340ef9009SDavid du Colombier c1 = 0;
44440ef9009SDavid du Colombier c2 = prec + 1;
44540ef9009SDavid du Colombier c3 = 0;
44640ef9009SDavid du Colombier c4 = prec;
44740ef9009SDavid du Colombier switch(chr) {
44840ef9009SDavid du Colombier default:
44940ef9009SDavid du Colombier chr = 'e';
45040ef9009SDavid du Colombier break;
45140ef9009SDavid du Colombier case 'g':
45240ef9009SDavid du Colombier /*
45340ef9009SDavid du Colombier * decide on 'e' of 'f' style convers
45440ef9009SDavid du Colombier */
45540ef9009SDavid du Colombier if(e >= -4 && e <= prec) {
45640ef9009SDavid du Colombier c1 = -e;
45740ef9009SDavid du Colombier c4 = prec - e;
45840ef9009SDavid du Colombier chr = 'h'; /* flag for 'f' style */
45940ef9009SDavid du Colombier }
46040ef9009SDavid du Colombier break;
46140ef9009SDavid du Colombier case 'f':
46240ef9009SDavid du Colombier c1 = -e;
46340ef9009SDavid du Colombier if(c1 > prec)
46440ef9009SDavid du Colombier c1 = prec + 1;
46540ef9009SDavid du Colombier c2 += e;
46640ef9009SDavid du Colombier break;
46740ef9009SDavid du Colombier }
46840ef9009SDavid du Colombier
46940ef9009SDavid du Colombier /*
47040ef9009SDavid du Colombier * clean up c1 c2 and c3
47140ef9009SDavid du Colombier */
47240ef9009SDavid du Colombier if(c1 < 0)
47340ef9009SDavid du Colombier c1 = 0;
47440ef9009SDavid du Colombier if(c2 < 0)
47540ef9009SDavid du Colombier c2 = 0;
47640ef9009SDavid du Colombier if(c2 > NSIGNIF) {
47740ef9009SDavid du Colombier c3 = c2-NSIGNIF;
47840ef9009SDavid du Colombier c2 = NSIGNIF;
47940ef9009SDavid du Colombier }
48040ef9009SDavid du Colombier
48140ef9009SDavid du Colombier /*
48240ef9009SDavid du Colombier * trim trailing zeros for %g
48340ef9009SDavid du Colombier */
48440ef9009SDavid du Colombier if(!(fl & FmtSharp)
48540ef9009SDavid du Colombier && (chr == 'g' || chr == 'h')){
48640ef9009SDavid du Colombier if(c4 >= c3){
48740ef9009SDavid du Colombier c4 -= c3;
48840ef9009SDavid du Colombier c3 = 0;
48940ef9009SDavid du Colombier }else{
49040ef9009SDavid du Colombier c3 -= c4;
49140ef9009SDavid du Colombier c4 = 0;
49240ef9009SDavid du Colombier }
49340ef9009SDavid du Colombier while(c4 && c2 > 1 && s1[c2 - 1] == '0'){
49440ef9009SDavid du Colombier c4--;
49540ef9009SDavid du Colombier c2--;
49640ef9009SDavid du Colombier }
49740ef9009SDavid du Colombier }
49840ef9009SDavid du Colombier
49940ef9009SDavid du Colombier /*
50040ef9009SDavid du Colombier * calculate the total length
50140ef9009SDavid du Colombier */
50240ef9009SDavid du Colombier n = c1 + c2 + c3;
50340ef9009SDavid du Colombier if(sign || (fl & (FmtSign|FmtSpace)))
50440ef9009SDavid du Colombier n++;
50540ef9009SDavid du Colombier if(c4 || (fl & FmtSharp)){
50640ef9009SDavid du Colombier n++;
50740ef9009SDavid du Colombier }
50840ef9009SDavid du Colombier if(chr == 'e' || chr == 'g'){
50940ef9009SDavid du Colombier n += 4;
51040ef9009SDavid du Colombier if(e >= 100)
51140ef9009SDavid du Colombier n++;
51240ef9009SDavid du Colombier }
51340ef9009SDavid du Colombier
51440ef9009SDavid du Colombier /*
51540ef9009SDavid du Colombier * pad to width if right justified
51640ef9009SDavid du Colombier */
51740ef9009SDavid du Colombier if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){
51840ef9009SDavid du Colombier if(fl & FmtZero){
51940ef9009SDavid du Colombier c1 += fmt->width - n;
52040ef9009SDavid du Colombier }else{
52140ef9009SDavid du Colombier if(__fmtpad(fmt, fmt->width - n) < 0){
52240ef9009SDavid du Colombier return -1;
52340ef9009SDavid du Colombier }
52440ef9009SDavid du Colombier }
52540ef9009SDavid du Colombier }
52640ef9009SDavid du Colombier
52740ef9009SDavid du Colombier /*
52840ef9009SDavid du Colombier * sign
52940ef9009SDavid du Colombier */
53040ef9009SDavid du Colombier d = 0;
53140ef9009SDavid du Colombier if(sign)
53240ef9009SDavid du Colombier d = '-';
53340ef9009SDavid du Colombier else if(fl & FmtSign)
53440ef9009SDavid du Colombier d = '+';
53540ef9009SDavid du Colombier else if(fl & FmtSpace)
53640ef9009SDavid du Colombier d = ' ';
53740ef9009SDavid du Colombier if(d && fmtrune(fmt, d) < 0){
53840ef9009SDavid du Colombier return -1;
53940ef9009SDavid du Colombier }
54040ef9009SDavid du Colombier
54140ef9009SDavid du Colombier /*
54240ef9009SDavid du Colombier * copy digits
54340ef9009SDavid du Colombier */
54440ef9009SDavid du Colombier c4 = c1 + c2 + c3 - c4;
54540ef9009SDavid du Colombier if(c1 > 0){
54640ef9009SDavid du Colombier if(fmtzdotpad(fmt, c1, c4) < 0){
54740ef9009SDavid du Colombier return -1;
54840ef9009SDavid du Colombier }
54940ef9009SDavid du Colombier c4 -= c1;
55040ef9009SDavid du Colombier }
55140ef9009SDavid du Colombier d = 0;
55240ef9009SDavid du Colombier if(c4 >= 0 && c4 < c2){
55340ef9009SDavid du Colombier if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0)
55440ef9009SDavid du Colombier return -1;
55540ef9009SDavid du Colombier d = c4;
55640ef9009SDavid du Colombier c2 -= c4;
55740ef9009SDavid du Colombier c4 = -1;
55840ef9009SDavid du Colombier }
55940ef9009SDavid du Colombier if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){
56040ef9009SDavid du Colombier return -1;
56140ef9009SDavid du Colombier }
56240ef9009SDavid du Colombier c4 -= c2;
56340ef9009SDavid du Colombier if(c3 > 0){
56440ef9009SDavid du Colombier if(fmtzdotpad(fmt, c3, c4) < 0){
56540ef9009SDavid du Colombier return -1;
56640ef9009SDavid du Colombier }
56740ef9009SDavid du Colombier c4 -= c3;
56840ef9009SDavid du Colombier }
56940ef9009SDavid du Colombier
57040ef9009SDavid du Colombier /*
57140ef9009SDavid du Colombier * strip trailing '0' on g conv
57240ef9009SDavid du Colombier */
57340ef9009SDavid du Colombier if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){
57440ef9009SDavid du Colombier return -1;
57540ef9009SDavid du Colombier }
57640ef9009SDavid du Colombier if(chr == 'e' || chr == 'g') {
57740ef9009SDavid du Colombier d = 0;
57840ef9009SDavid du Colombier if(ucase)
57940ef9009SDavid du Colombier s1[d++] = 'E';
58040ef9009SDavid du Colombier else
58140ef9009SDavid du Colombier s1[d++] = 'e';
58240ef9009SDavid du Colombier c1 = e;
58340ef9009SDavid du Colombier if(c1 < 0) {
58440ef9009SDavid du Colombier s1[d++] = '-';
58540ef9009SDavid du Colombier c1 = -c1;
58640ef9009SDavid du Colombier } else
58740ef9009SDavid du Colombier s1[d++] = '+';
58840ef9009SDavid du Colombier if(c1 >= 100) {
58940ef9009SDavid du Colombier s1[d++] = c1/100 + '0';
59040ef9009SDavid du Colombier c1 = c1%100;
59140ef9009SDavid du Colombier }
59240ef9009SDavid du Colombier s1[d++] = c1/10 + '0';
59340ef9009SDavid du Colombier s1[d++] = c1%10 + '0';
59440ef9009SDavid du Colombier if(__fmtcpy(fmt, s1, d, d) < 0){
59540ef9009SDavid du Colombier return -1;
59640ef9009SDavid du Colombier }
59740ef9009SDavid du Colombier }
59840ef9009SDavid du Colombier if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){
59940ef9009SDavid du Colombier if(__fmtpad(fmt, fmt->width - n) < 0){
60040ef9009SDavid du Colombier return -1;
60140ef9009SDavid du Colombier }
60240ef9009SDavid du Colombier }
60340ef9009SDavid du Colombier return 0;
60440ef9009SDavid du Colombier }
605