Blame


1 85231fd8 2006-05-21 devnull /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2 91c13e54 2004-02-29 devnull #include <stdio.h>
3 91c13e54 2004-02-29 devnull #include <math.h>
4 91c13e54 2004-02-29 devnull #include <float.h>
5 91c13e54 2004-02-29 devnull #include <string.h>
6 91c13e54 2004-02-29 devnull #include <stdlib.h>
7 91c13e54 2004-02-29 devnull #include <errno.h>
8 91c13e54 2004-02-29 devnull #include <stdarg.h>
9 e5aa96ac 2004-12-26 devnull #include <fmt.h>
10 f8955f18 2006-05-22 devnull #include <assert.h>
11 e5aa96ac 2004-12-26 devnull #include "plan9.h"
12 91c13e54 2004-02-29 devnull #include "fmt.h"
13 91c13e54 2004-02-29 devnull #include "fmtdef.h"
14 f8955f18 2006-05-22 devnull #include "nan.h"
15 91c13e54 2004-02-29 devnull
16 91c13e54 2004-02-29 devnull enum
17 91c13e54 2004-02-29 devnull {
18 a76c0fd4 2004-12-26 devnull FDIGIT = 30,
19 91c13e54 2004-02-29 devnull FDEFLT = 6,
20 91c13e54 2004-02-29 devnull NSIGNIF = 17
21 91c13e54 2004-02-29 devnull };
22 91c13e54 2004-02-29 devnull
23 91c13e54 2004-02-29 devnull /*
24 91c13e54 2004-02-29 devnull * first few powers of 10, enough for about 1/2 of the
25 91c13e54 2004-02-29 devnull * total space for doubles.
26 91c13e54 2004-02-29 devnull */
27 91c13e54 2004-02-29 devnull static double pows10[] =
28 91c13e54 2004-02-29 devnull {
29 91c13e54 2004-02-29 devnull 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
30 91c13e54 2004-02-29 devnull 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
31 91c13e54 2004-02-29 devnull 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
32 91c13e54 2004-02-29 devnull 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
33 91c13e54 2004-02-29 devnull 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
34 91c13e54 2004-02-29 devnull 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
35 91c13e54 2004-02-29 devnull 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
36 91c13e54 2004-02-29 devnull 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
37 91c13e54 2004-02-29 devnull 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
38 91c13e54 2004-02-29 devnull 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
39 91c13e54 2004-02-29 devnull 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
40 91c13e54 2004-02-29 devnull 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
41 91c13e54 2004-02-29 devnull 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
42 91c13e54 2004-02-29 devnull 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
43 91c13e54 2004-02-29 devnull 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
44 91c13e54 2004-02-29 devnull 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
45 91c13e54 2004-02-29 devnull };
46 f8955f18 2006-05-22 devnull #define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
47 f8955f18 2006-05-22 devnull #define pow10(x) fmtpow10(x)
48 4645c5d7 2004-12-29 devnull
49 91c13e54 2004-02-29 devnull static double
50 91c13e54 2004-02-29 devnull pow10(int n)
51 91c13e54 2004-02-29 devnull {
52 91c13e54 2004-02-29 devnull double d;
53 91c13e54 2004-02-29 devnull int neg;
54 91c13e54 2004-02-29 devnull
55 91c13e54 2004-02-29 devnull neg = 0;
56 91c13e54 2004-02-29 devnull if(n < 0){
57 f8955f18 2006-05-22 devnull if(n < DBL_MIN_10_EXP)
58 91c13e54 2004-02-29 devnull return 0.;
59 91c13e54 2004-02-29 devnull neg = 1;
60 91c13e54 2004-02-29 devnull n = -n;
61 f8955f18 2006-05-22 devnull }else if(n > DBL_MAX_10_EXP)
62 91c13e54 2004-02-29 devnull return HUGE_VAL;
63 f8955f18 2006-05-22 devnull
64 f8955f18 2006-05-22 devnull if(n < npows10)
65 91c13e54 2004-02-29 devnull d = pows10[n];
66 91c13e54 2004-02-29 devnull else{
67 f8955f18 2006-05-22 devnull d = pows10[npows10-1];
68 91c13e54 2004-02-29 devnull for(;;){
69 f8955f18 2006-05-22 devnull n -= npows10 - 1;
70 f8955f18 2006-05-22 devnull if(n < npows10){
71 91c13e54 2004-02-29 devnull d *= pows10[n];
72 91c13e54 2004-02-29 devnull break;
73 91c13e54 2004-02-29 devnull }
74 f8955f18 2006-05-22 devnull d *= pows10[npows10 - 1];
75 91c13e54 2004-02-29 devnull }
76 91c13e54 2004-02-29 devnull }
77 f8955f18 2006-05-22 devnull if(neg)
78 91c13e54 2004-02-29 devnull return 1./d;
79 91c13e54 2004-02-29 devnull return d;
80 91c13e54 2004-02-29 devnull }
81 91c13e54 2004-02-29 devnull
82 f8955f18 2006-05-22 devnull /*
83 f8955f18 2006-05-22 devnull * add 1 to the decimal integer string a of length n.
84 f8955f18 2006-05-22 devnull * if 99999 overflows into 10000, return 1 to tell caller
85 f8955f18 2006-05-22 devnull * to move the virtual decimal point.
86 f8955f18 2006-05-22 devnull */
87 91c13e54 2004-02-29 devnull static int
88 f8955f18 2006-05-22 devnull xadd1(char *a, int n)
89 91c13e54 2004-02-29 devnull {
90 91c13e54 2004-02-29 devnull char *b;
91 91c13e54 2004-02-29 devnull int c;
92 91c13e54 2004-02-29 devnull
93 f8955f18 2006-05-22 devnull if(n < 0 || n > NSIGNIF)
94 91c13e54 2004-02-29 devnull return 0;
95 f8955f18 2006-05-22 devnull for(b = a+n-1; b >= a; b--) {
96 f8955f18 2006-05-22 devnull c = *b + 1;
97 91c13e54 2004-02-29 devnull if(c <= '9') {
98 91c13e54 2004-02-29 devnull *b = c;
99 91c13e54 2004-02-29 devnull return 0;
100 91c13e54 2004-02-29 devnull }
101 91c13e54 2004-02-29 devnull *b = '0';
102 91c13e54 2004-02-29 devnull }
103 f8955f18 2006-05-22 devnull /*
104 f8955f18 2006-05-22 devnull * need to overflow adding digit.
105 f8955f18 2006-05-22 devnull * shift number down and insert 1 at beginning.
106 f8955f18 2006-05-22 devnull * decimal is known to be 0s or we wouldn't
107 f8955f18 2006-05-22 devnull * have gotten this far. (e.g., 99999+1 => 00000)
108 f8955f18 2006-05-22 devnull */
109 f8955f18 2006-05-22 devnull a[0] = '1';
110 91c13e54 2004-02-29 devnull return 1;
111 91c13e54 2004-02-29 devnull }
112 91c13e54 2004-02-29 devnull
113 f8955f18 2006-05-22 devnull /*
114 f8955f18 2006-05-22 devnull * subtract 1 from the decimal integer string a.
115 f8955f18 2006-05-22 devnull * if 10000 underflows into 09999, make it 99999
116 f8955f18 2006-05-22 devnull * and return 1 to tell caller to move the virtual
117 f8955f18 2006-05-22 devnull * decimal point. this way, xsub1 is inverse of xadd1.
118 f8955f18 2006-05-22 devnull */
119 91c13e54 2004-02-29 devnull static int
120 f8955f18 2006-05-22 devnull xsub1(char *a, int n)
121 91c13e54 2004-02-29 devnull {
122 91c13e54 2004-02-29 devnull char *b;
123 91c13e54 2004-02-29 devnull int c;
124 91c13e54 2004-02-29 devnull
125 f8955f18 2006-05-22 devnull if(n < 0 || n > NSIGNIF)
126 f8955f18 2006-05-22 devnull return 0;
127 f8955f18 2006-05-22 devnull for(b = a+n-1; b >= a; b--) {
128 f8955f18 2006-05-22 devnull c = *b - 1;
129 91c13e54 2004-02-29 devnull if(c >= '0') {
130 f8955f18 2006-05-22 devnull if(c == '0' && b == a) {
131 f8955f18 2006-05-22 devnull /*
132 f8955f18 2006-05-22 devnull * just zeroed the top digit; shift everyone up.
133 f8955f18 2006-05-22 devnull * decimal is known to be 9s or we wouldn't
134 f8955f18 2006-05-22 devnull * have gotten this far. (e.g., 10000-1 => 09999)
135 f8955f18 2006-05-22 devnull */
136 f8955f18 2006-05-22 devnull *b = '9';
137 f8955f18 2006-05-22 devnull return 1;
138 f8955f18 2006-05-22 devnull }
139 91c13e54 2004-02-29 devnull *b = c;
140 91c13e54 2004-02-29 devnull return 0;
141 91c13e54 2004-02-29 devnull }
142 91c13e54 2004-02-29 devnull *b = '9';
143 91c13e54 2004-02-29 devnull }
144 f8955f18 2006-05-22 devnull /*
145 f8955f18 2006-05-22 devnull * can't get here. the number a is always normalized
146 f8955f18 2006-05-22 devnull * so that it has a nonzero first digit.
147 f8955f18 2006-05-22 devnull */
148 f8955f18 2006-05-22 devnull abort();
149 91c13e54 2004-02-29 devnull }
150 91c13e54 2004-02-29 devnull
151 f8955f18 2006-05-22 devnull /*
152 f8955f18 2006-05-22 devnull * format exponent like sprintf(p, "e%+02d", e)
153 f8955f18 2006-05-22 devnull */
154 91c13e54 2004-02-29 devnull static void
155 f8955f18 2006-05-22 devnull xfmtexp(char *p, int e, int ucase)
156 91c13e54 2004-02-29 devnull {
157 f8955f18 2006-05-22 devnull char se[9];
158 f8955f18 2006-05-22 devnull int i;
159 91c13e54 2004-02-29 devnull
160 f8955f18 2006-05-22 devnull *p++ = ucase ? 'E' : 'e';
161 f8955f18 2006-05-22 devnull if(e < 0) {
162 f8955f18 2006-05-22 devnull *p++ = '-';
163 f8955f18 2006-05-22 devnull e = -e;
164 f8955f18 2006-05-22 devnull } else
165 f8955f18 2006-05-22 devnull *p++ = '+';
166 f8955f18 2006-05-22 devnull i = 0;
167 f8955f18 2006-05-22 devnull while(e) {
168 f8955f18 2006-05-22 devnull se[i++] = e % 10 + '0';
169 f8955f18 2006-05-22 devnull e /= 10;
170 91c13e54 2004-02-29 devnull }
171 f8955f18 2006-05-22 devnull while(i < 2)
172 f8955f18 2006-05-22 devnull se[i++] = '0';
173 f8955f18 2006-05-22 devnull while(i > 0)
174 f8955f18 2006-05-22 devnull *p++ = se[--i];
175 f8955f18 2006-05-22 devnull *p++ = '\0';
176 f8955f18 2006-05-22 devnull }
177 f8955f18 2006-05-22 devnull
178 f8955f18 2006-05-22 devnull /*
179 f8955f18 2006-05-22 devnull * compute decimal integer m, exp such that:
180 f8955f18 2006-05-22 devnull * f = m*10^exp
181 f8955f18 2006-05-22 devnull * m is as short as possible with losing exactness
182 f8955f18 2006-05-22 devnull * assumes special cases (NaN, +Inf, -Inf) have been handled.
183 f8955f18 2006-05-22 devnull */
184 f8955f18 2006-05-22 devnull static void
185 f8955f18 2006-05-22 devnull xdtoa(double f, char *s, int *exp, int *neg, int *ns)
186 f8955f18 2006-05-22 devnull {
187 f8955f18 2006-05-22 devnull int c, d, e2, e, ee, i, ndigit, oerrno;
188 f8955f18 2006-05-22 devnull char tmp[NSIGNIF+10];
189 f8955f18 2006-05-22 devnull double g;
190 f8955f18 2006-05-22 devnull
191 f8955f18 2006-05-22 devnull oerrno = errno; /* in case strtod smashes errno */
192 f8955f18 2006-05-22 devnull
193 f8955f18 2006-05-22 devnull /*
194 f8955f18 2006-05-22 devnull * make f non-negative.
195 f8955f18 2006-05-22 devnull */
196 f8955f18 2006-05-22 devnull *neg = 0;
197 91c13e54 2004-02-29 devnull if(f < 0) {
198 91c13e54 2004-02-29 devnull f = -f;
199 f8955f18 2006-05-22 devnull *neg = 1;
200 91c13e54 2004-02-29 devnull }
201 91c13e54 2004-02-29 devnull
202 91c13e54 2004-02-29 devnull /*
203 f8955f18 2006-05-22 devnull * must handle zero specially.
204 91c13e54 2004-02-29 devnull */
205 f8955f18 2006-05-22 devnull if(f == 0){
206 f8955f18 2006-05-22 devnull *exp = 0;
207 f8955f18 2006-05-22 devnull s[0] = '0';
208 f8955f18 2006-05-22 devnull s[1] = '\0';
209 f8955f18 2006-05-22 devnull *ns = 1;
210 f8955f18 2006-05-22 devnull return;
211 91c13e54 2004-02-29 devnull }
212 f8955f18 2006-05-22 devnull
213 91c13e54 2004-02-29 devnull /*
214 f8955f18 2006-05-22 devnull * find g,e such that f = g*10^e.
215 f8955f18 2006-05-22 devnull * guess 10-exponent using 2-exponent, then fine tune.
216 91c13e54 2004-02-29 devnull */
217 f8955f18 2006-05-22 devnull frexp(f, &e2);
218 f8955f18 2006-05-22 devnull e = (int)(e2 * .301029995664);
219 f8955f18 2006-05-22 devnull g = f * pow10(-e);
220 f8955f18 2006-05-22 devnull while(g < 1) {
221 f8955f18 2006-05-22 devnull e--;
222 f8955f18 2006-05-22 devnull g = f * pow10(-e);
223 91c13e54 2004-02-29 devnull }
224 f8955f18 2006-05-22 devnull while(g >= 10) {
225 f8955f18 2006-05-22 devnull e++;
226 f8955f18 2006-05-22 devnull g = f * pow10(-e);
227 f8955f18 2006-05-22 devnull }
228 91c13e54 2004-02-29 devnull
229 91c13e54 2004-02-29 devnull /*
230 f8955f18 2006-05-22 devnull * convert NSIGNIF digits as a first approximation.
231 91c13e54 2004-02-29 devnull */
232 f8955f18 2006-05-22 devnull for(i=0; i<NSIGNIF; i++) {
233 f8955f18 2006-05-22 devnull d = (int)g;
234 f8955f18 2006-05-22 devnull s[i] = d+'0';
235 f8955f18 2006-05-22 devnull g = (g-d) * 10;
236 f8955f18 2006-05-22 devnull }
237 f8955f18 2006-05-22 devnull s[i] = 0;
238 f8955f18 2006-05-22 devnull
239 f8955f18 2006-05-22 devnull /*
240 f8955f18 2006-05-22 devnull * adjust e because s is 314159... not 3.14159...
241 f8955f18 2006-05-22 devnull */
242 f8955f18 2006-05-22 devnull e -= NSIGNIF-1;
243 f8955f18 2006-05-22 devnull xfmtexp(s+NSIGNIF, e, 0);
244 f8955f18 2006-05-22 devnull
245 f8955f18 2006-05-22 devnull /*
246 f8955f18 2006-05-22 devnull * adjust conversion until strtod(s) == f exactly.
247 f8955f18 2006-05-22 devnull */
248 f8955f18 2006-05-22 devnull for(i=0; i<10; i++) {
249 f8955f18 2006-05-22 devnull g = strtod(s, nil);
250 91c13e54 2004-02-29 devnull if(f > g) {
251 f8955f18 2006-05-22 devnull if(xadd1(s, NSIGNIF)) {
252 f8955f18 2006-05-22 devnull /* gained a digit */
253 91c13e54 2004-02-29 devnull e--;
254 f8955f18 2006-05-22 devnull xfmtexp(s+NSIGNIF, e, 0);
255 f8955f18 2006-05-22 devnull }
256 91c13e54 2004-02-29 devnull continue;
257 91c13e54 2004-02-29 devnull }
258 91c13e54 2004-02-29 devnull if(f < g) {
259 f8955f18 2006-05-22 devnull if(xsub1(s, NSIGNIF)) {
260 f8955f18 2006-05-22 devnull /* lost a digit */
261 91c13e54 2004-02-29 devnull e++;
262 f8955f18 2006-05-22 devnull xfmtexp(s+NSIGNIF, e, 0);
263 f8955f18 2006-05-22 devnull }
264 91c13e54 2004-02-29 devnull continue;
265 91c13e54 2004-02-29 devnull }
266 91c13e54 2004-02-29 devnull break;
267 91c13e54 2004-02-29 devnull }
268 91c13e54 2004-02-29 devnull
269 91c13e54 2004-02-29 devnull /*
270 f8955f18 2006-05-22 devnull * play with the decimal to try to simplify.
271 91c13e54 2004-02-29 devnull */
272 91c13e54 2004-02-29 devnull
273 91c13e54 2004-02-29 devnull /*
274 f8955f18 2006-05-22 devnull * bump last few digits up to 9 if we can
275 91c13e54 2004-02-29 devnull */
276 f8955f18 2006-05-22 devnull for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
277 f8955f18 2006-05-22 devnull c = s[i];
278 f8955f18 2006-05-22 devnull if(c != '9') {
279 f8955f18 2006-05-22 devnull s[i] = '9';
280 f8955f18 2006-05-22 devnull g = strtod(s, nil);
281 f8955f18 2006-05-22 devnull if(g != f) {
282 f8955f18 2006-05-22 devnull s[i] = c;
283 f8955f18 2006-05-22 devnull break;
284 f8955f18 2006-05-22 devnull }
285 91c13e54 2004-02-29 devnull }
286 91c13e54 2004-02-29 devnull }
287 91c13e54 2004-02-29 devnull
288 91c13e54 2004-02-29 devnull /*
289 f8955f18 2006-05-22 devnull * add 1 in hopes of turning 9s to 0s
290 91c13e54 2004-02-29 devnull */
291 f8955f18 2006-05-22 devnull if(s[NSIGNIF-1] == '9') {
292 f8955f18 2006-05-22 devnull strcpy(tmp, s);
293 f8955f18 2006-05-22 devnull ee = e;
294 f8955f18 2006-05-22 devnull if(xadd1(tmp, NSIGNIF)) {
295 f8955f18 2006-05-22 devnull ee--;
296 f8955f18 2006-05-22 devnull xfmtexp(tmp+NSIGNIF, ee, 0);
297 f8955f18 2006-05-22 devnull }
298 f8955f18 2006-05-22 devnull g = strtod(tmp, nil);
299 f8955f18 2006-05-22 devnull if(g == f) {
300 f8955f18 2006-05-22 devnull strcpy(s, tmp);
301 f8955f18 2006-05-22 devnull e = ee;
302 f8955f18 2006-05-22 devnull }
303 91c13e54 2004-02-29 devnull }
304 f8955f18 2006-05-22 devnull
305 91c13e54 2004-02-29 devnull /*
306 f8955f18 2006-05-22 devnull * bump last few digits down to 0 as we can.
307 91c13e54 2004-02-29 devnull */
308 f8955f18 2006-05-22 devnull for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
309 f8955f18 2006-05-22 devnull c = s[i];
310 f8955f18 2006-05-22 devnull if(c != '0') {
311 f8955f18 2006-05-22 devnull s[i] = '0';
312 f8955f18 2006-05-22 devnull g = strtod(s, nil);
313 f8955f18 2006-05-22 devnull if(g != f) {
314 f8955f18 2006-05-22 devnull s[i] = c;
315 f8955f18 2006-05-22 devnull break;
316 f8955f18 2006-05-22 devnull }
317 f8955f18 2006-05-22 devnull }
318 91c13e54 2004-02-29 devnull }
319 91c13e54 2004-02-29 devnull
320 91c13e54 2004-02-29 devnull /*
321 f8955f18 2006-05-22 devnull * remove trailing zeros.
322 91c13e54 2004-02-29 devnull */
323 f8955f18 2006-05-22 devnull ndigit = NSIGNIF;
324 f8955f18 2006-05-22 devnull while(ndigit > 1 && s[ndigit-1] == '0'){
325 f8955f18 2006-05-22 devnull e++;
326 f8955f18 2006-05-22 devnull --ndigit;
327 f8955f18 2006-05-22 devnull }
328 f8955f18 2006-05-22 devnull s[ndigit] = 0;
329 f8955f18 2006-05-22 devnull *exp = e;
330 f8955f18 2006-05-22 devnull *ns = ndigit;
331 f8955f18 2006-05-22 devnull errno = oerrno;
332 f8955f18 2006-05-22 devnull }
333 f8955f18 2006-05-22 devnull
334 f8955f18 2006-05-22 devnull #ifdef PLAN9PORT
335 f8955f18 2006-05-22 devnull static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
336 f8955f18 2006-05-22 devnull #else
337 f8955f18 2006-05-22 devnull static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
338 f8955f18 2006-05-22 devnull #endif
339 f8955f18 2006-05-22 devnull
340 f8955f18 2006-05-22 devnull int
341 f8955f18 2006-05-22 devnull __efgfmt(Fmt *fmt)
342 f8955f18 2006-05-22 devnull {
343 f8955f18 2006-05-22 devnull char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
344 f8955f18 2006-05-22 devnull double f;
345 f8955f18 2006-05-22 devnull int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
346 f8955f18 2006-05-22 devnull int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
347 f8955f18 2006-05-22 devnull Rune r, *rs, *rt;
348 f8955f18 2006-05-22 devnull
349 f8955f18 2006-05-22 devnull f = va_arg(fmt->args, double);
350 f8955f18 2006-05-22 devnull
351 f8955f18 2006-05-22 devnull /*
352 f8955f18 2006-05-22 devnull * extract formatting flags
353 f8955f18 2006-05-22 devnull */
354 f8955f18 2006-05-22 devnull fl = fmt->flags;
355 f8955f18 2006-05-22 devnull fmt->flags = 0;
356 f8955f18 2006-05-22 devnull prec = FDEFLT;
357 f8955f18 2006-05-22 devnull if(fl & FmtPrec)
358 f8955f18 2006-05-22 devnull prec = fmt->prec;
359 f8955f18 2006-05-22 devnull chr = fmt->r;
360 f8955f18 2006-05-22 devnull ucase = 0;
361 f8955f18 2006-05-22 devnull switch(chr) {
362 f8955f18 2006-05-22 devnull case 'A':
363 f8955f18 2006-05-22 devnull case 'E':
364 f8955f18 2006-05-22 devnull case 'F':
365 f8955f18 2006-05-22 devnull case 'G':
366 f8955f18 2006-05-22 devnull chr += 'a'-'A';
367 f8955f18 2006-05-22 devnull ucase = 1;
368 f8955f18 2006-05-22 devnull break;
369 f8955f18 2006-05-22 devnull }
370 f8955f18 2006-05-22 devnull
371 f8955f18 2006-05-22 devnull /*
372 f8955f18 2006-05-22 devnull * pick off special numbers.
373 f8955f18 2006-05-22 devnull */
374 f8955f18 2006-05-22 devnull if(__isNaN(f)) {
375 f8955f18 2006-05-22 devnull s = special[0+ucase];
376 f8955f18 2006-05-22 devnull special:
377 f8955f18 2006-05-22 devnull fmt->flags = fl & (FmtWidth|FmtLeft);
378 f8955f18 2006-05-22 devnull return __fmtcpy(fmt, s, strlen(s), strlen(s));
379 f8955f18 2006-05-22 devnull }
380 f8955f18 2006-05-22 devnull if(__isInf(f, 1)) {
381 f8955f18 2006-05-22 devnull s = special[2+ucase];
382 f8955f18 2006-05-22 devnull goto special;
383 f8955f18 2006-05-22 devnull }
384 f8955f18 2006-05-22 devnull if(__isInf(f, -1)) {
385 f8955f18 2006-05-22 devnull s = special[4+ucase];
386 f8955f18 2006-05-22 devnull goto special;
387 f8955f18 2006-05-22 devnull }
388 f8955f18 2006-05-22 devnull
389 f8955f18 2006-05-22 devnull /*
390 f8955f18 2006-05-22 devnull * get exact representation.
391 f8955f18 2006-05-22 devnull */
392 f8955f18 2006-05-22 devnull digits = buf;
393 f8955f18 2006-05-22 devnull xdtoa(f, digits, &exp, &neg, &ndigits);
394 f8955f18 2006-05-22 devnull
395 f8955f18 2006-05-22 devnull /*
396 f8955f18 2006-05-22 devnull * get locale's decimal point.
397 f8955f18 2006-05-22 devnull */
398 f8955f18 2006-05-22 devnull dot = fmt->decimal;
399 f8955f18 2006-05-22 devnull if(dot == nil)
400 f8955f18 2006-05-22 devnull dot = ".";
401 f8955f18 2006-05-22 devnull dotwid = utflen(dot);
402 f8955f18 2006-05-22 devnull
403 f8955f18 2006-05-22 devnull /*
404 f8955f18 2006-05-22 devnull * now the formatting fun begins.
405 f8955f18 2006-05-22 devnull * compute parameters for actual fmt:
406 f8955f18 2006-05-22 devnull *
407 f8955f18 2006-05-22 devnull * pad: number of spaces to insert before/after field.
408 f8955f18 2006-05-22 devnull * z1: number of zeros to insert before digits
409 f8955f18 2006-05-22 devnull * z2: number of zeros to insert after digits
410 f8955f18 2006-05-22 devnull * point: number of digits to print before decimal point
411 f8955f18 2006-05-22 devnull * ndigits: number of digits to use from digits[]
412 f8955f18 2006-05-22 devnull * suf: trailing suffix, like "e-5"
413 f8955f18 2006-05-22 devnull */
414 f8955f18 2006-05-22 devnull realchr = chr;
415 f8955f18 2006-05-22 devnull switch(chr){
416 f8955f18 2006-05-22 devnull case 'g':
417 f8955f18 2006-05-22 devnull /*
418 f8955f18 2006-05-22 devnull * convert to at most prec significant digits. (prec=0 means 1)
419 f8955f18 2006-05-22 devnull */
420 f8955f18 2006-05-22 devnull if(prec == 0)
421 f8955f18 2006-05-22 devnull prec = 1;
422 f8955f18 2006-05-22 devnull if(ndigits > prec) {
423 f8955f18 2006-05-22 devnull if(digits[prec] >= '5' && xadd1(digits, prec))
424 f8955f18 2006-05-22 devnull exp++;
425 f8955f18 2006-05-22 devnull exp += ndigits-prec;
426 f8955f18 2006-05-22 devnull ndigits = prec;
427 f8955f18 2006-05-22 devnull }
428 f8955f18 2006-05-22 devnull
429 f8955f18 2006-05-22 devnull /*
430 f8955f18 2006-05-22 devnull * extra rules for %g (implemented below):
431 f8955f18 2006-05-22 devnull * trailing zeros removed after decimal unless FmtSharp.
432 f8955f18 2006-05-22 devnull * decimal point only if digit follows.
433 f8955f18 2006-05-22 devnull */
434 f8955f18 2006-05-22 devnull
435 f8955f18 2006-05-22 devnull /* fall through to %e */
436 f8955f18 2006-05-22 devnull default:
437 f8955f18 2006-05-22 devnull case 'e':
438 f8955f18 2006-05-22 devnull /*
439 f8955f18 2006-05-22 devnull * one significant digit before decimal, no leading zeros.
440 f8955f18 2006-05-22 devnull */
441 f8955f18 2006-05-22 devnull point = 1;
442 f8955f18 2006-05-22 devnull z1 = 0;
443 f8955f18 2006-05-22 devnull
444 f8955f18 2006-05-22 devnull /*
445 f8955f18 2006-05-22 devnull * decimal point is after ndigits digits right now.
446 f8955f18 2006-05-22 devnull * slide to be after first.
447 f8955f18 2006-05-22 devnull */
448 f8955f18 2006-05-22 devnull e = exp + (ndigits-1);
449 f8955f18 2006-05-22 devnull
450 f8955f18 2006-05-22 devnull /*
451 f8955f18 2006-05-22 devnull * if this is %g, check exponent and convert prec
452 f8955f18 2006-05-22 devnull */
453 f8955f18 2006-05-22 devnull if(realchr == 'g') {
454 f8955f18 2006-05-22 devnull if(-4 <= e && e < prec)
455 f8955f18 2006-05-22 devnull goto casef;
456 f8955f18 2006-05-22 devnull prec--; /* one digit before decimal; rest after */
457 f8955f18 2006-05-22 devnull }
458 f8955f18 2006-05-22 devnull
459 f8955f18 2006-05-22 devnull /*
460 f8955f18 2006-05-22 devnull * compute trailing zero padding or truncate digits.
461 f8955f18 2006-05-22 devnull */
462 f8955f18 2006-05-22 devnull if(1+prec >= ndigits)
463 f8955f18 2006-05-22 devnull z2 = 1+prec - ndigits;
464 f8955f18 2006-05-22 devnull else {
465 f8955f18 2006-05-22 devnull /*
466 f8955f18 2006-05-22 devnull * truncate digits
467 f8955f18 2006-05-22 devnull */
468 f8955f18 2006-05-22 devnull assert(realchr != 'g');
469 f8955f18 2006-05-22 devnull newndigits = 1+prec;
470 f8955f18 2006-05-22 devnull if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
471 f8955f18 2006-05-22 devnull /*
472 f8955f18 2006-05-22 devnull * had 999e4, now have 100e5
473 f8955f18 2006-05-22 devnull */
474 f8955f18 2006-05-22 devnull e++;
475 a76c0fd4 2004-12-26 devnull }
476 f8955f18 2006-05-22 devnull ndigits = newndigits;
477 f8955f18 2006-05-22 devnull z2 = 0;
478 f8955f18 2006-05-22 devnull }
479 f8955f18 2006-05-22 devnull xfmtexp(suf, e, ucase);
480 f8955f18 2006-05-22 devnull sufwid = strlen(suf);
481 f8955f18 2006-05-22 devnull break;
482 f8955f18 2006-05-22 devnull
483 f8955f18 2006-05-22 devnull casef:
484 f8955f18 2006-05-22 devnull case 'f':
485 f8955f18 2006-05-22 devnull /*
486 f8955f18 2006-05-22 devnull * determine where digits go with respect to decimal point
487 f8955f18 2006-05-22 devnull */
488 f8955f18 2006-05-22 devnull if(ndigits+exp > 0) {
489 f8955f18 2006-05-22 devnull point = ndigits+exp;
490 f8955f18 2006-05-22 devnull z1 = 0;
491 f8955f18 2006-05-22 devnull } else {
492 f8955f18 2006-05-22 devnull point = 1;
493 f8955f18 2006-05-22 devnull z1 = 1 + -(ndigits+exp);
494 f8955f18 2006-05-22 devnull }
495 f8955f18 2006-05-22 devnull
496 f8955f18 2006-05-22 devnull /*
497 f8955f18 2006-05-22 devnull * %g specifies prec = number of significant digits
498 f8955f18 2006-05-22 devnull * convert to number of digits after decimal point
499 f8955f18 2006-05-22 devnull */
500 f8955f18 2006-05-22 devnull if(realchr == 'g')
501 f8955f18 2006-05-22 devnull prec += z1 - point;
502 f8955f18 2006-05-22 devnull
503 f8955f18 2006-05-22 devnull /*
504 f8955f18 2006-05-22 devnull * compute trailing zero padding or truncate digits.
505 f8955f18 2006-05-22 devnull */
506 f8955f18 2006-05-22 devnull if(point+prec >= z1+ndigits)
507 f8955f18 2006-05-22 devnull z2 = point+prec - (z1+ndigits);
508 f8955f18 2006-05-22 devnull else {
509 f8955f18 2006-05-22 devnull /*
510 f8955f18 2006-05-22 devnull * truncate digits
511 f8955f18 2006-05-22 devnull */
512 f8955f18 2006-05-22 devnull assert(realchr != 'g');
513 f8955f18 2006-05-22 devnull newndigits = point+prec - z1;
514 f8955f18 2006-05-22 devnull if(newndigits < 0) {
515 f8955f18 2006-05-22 devnull z1 += newndigits;
516 f8955f18 2006-05-22 devnull newndigits = 0;
517 f8955f18 2006-05-22 devnull } else if(newndigits == 0) {
518 f8955f18 2006-05-22 devnull /* perhaps round up */
519 f8955f18 2006-05-22 devnull if(digits[0] >= '5'){
520 f8955f18 2006-05-22 devnull digits[0] = '1';
521 f8955f18 2006-05-22 devnull newndigits = 1;
522 f8955f18 2006-05-22 devnull goto newdigit;
523 f8955f18 2006-05-22 devnull }
524 f8955f18 2006-05-22 devnull } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
525 f8955f18 2006-05-22 devnull /*
526 f8955f18 2006-05-22 devnull * digits was 999, is now 100; make it 1000
527 f8955f18 2006-05-22 devnull */
528 f8955f18 2006-05-22 devnull digits[newndigits++] = '0';
529 f8955f18 2006-05-22 devnull newdigit:
530 f8955f18 2006-05-22 devnull /*
531 f8955f18 2006-05-22 devnull * account for new digit
532 f8955f18 2006-05-22 devnull */
533 f8955f18 2006-05-22 devnull if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/
534 f8955f18 2006-05-22 devnull z1--;
535 f8955f18 2006-05-22 devnull else /* 9.99 => 10.00 */
536 f8955f18 2006-05-22 devnull point++;
537 f8955f18 2006-05-22 devnull }
538 f8955f18 2006-05-22 devnull z2 = 0;
539 f8955f18 2006-05-22 devnull ndigits = newndigits;
540 f8955f18 2006-05-22 devnull }
541 f8955f18 2006-05-22 devnull sufwid = 0;
542 f8955f18 2006-05-22 devnull break;
543 91c13e54 2004-02-29 devnull }
544 f8955f18 2006-05-22 devnull
545 f8955f18 2006-05-22 devnull /*
546 f8955f18 2006-05-22 devnull * if %g is given without FmtSharp, remove trailing zeros.
547 f8955f18 2006-05-22 devnull * must do after truncation, so that e.g. print %.3g 1.001
548 f8955f18 2006-05-22 devnull * produces 1, not 1.00. sorry, but them's the rules.
549 f8955f18 2006-05-22 devnull */
550 f8955f18 2006-05-22 devnull if(realchr == 'g' && !(fl & FmtSharp)) {
551 f8955f18 2006-05-22 devnull if(z1+ndigits+z2 >= point) {
552 f8955f18 2006-05-22 devnull if(z1+ndigits < point)
553 f8955f18 2006-05-22 devnull z2 = point - (z1+ndigits);
554 f8955f18 2006-05-22 devnull else{
555 f8955f18 2006-05-22 devnull z2 = 0;
556 f8955f18 2006-05-22 devnull while(z1+ndigits > point && digits[ndigits-1] == '0')
557 f8955f18 2006-05-22 devnull ndigits--;
558 f8955f18 2006-05-22 devnull }
559 91c13e54 2004-02-29 devnull }
560 91c13e54 2004-02-29 devnull }
561 a76c0fd4 2004-12-26 devnull
562 f8955f18 2006-05-22 devnull /*
563 f8955f18 2006-05-22 devnull * compute width of all digits and decimal point and suffix if any
564 f8955f18 2006-05-22 devnull */
565 f8955f18 2006-05-22 devnull wid = z1+ndigits+z2;
566 f8955f18 2006-05-22 devnull if(wid > point)
567 f8955f18 2006-05-22 devnull wid += dotwid;
568 f8955f18 2006-05-22 devnull else if(wid == point){
569 f8955f18 2006-05-22 devnull if(fl & FmtSharp)
570 f8955f18 2006-05-22 devnull wid += dotwid;
571 f8955f18 2006-05-22 devnull else
572 f8955f18 2006-05-22 devnull point++; /* do not print any decimal point */
573 f8955f18 2006-05-22 devnull }
574 f8955f18 2006-05-22 devnull wid += sufwid;
575 a76c0fd4 2004-12-26 devnull
576 f8955f18 2006-05-22 devnull /*
577 f8955f18 2006-05-22 devnull * determine sign
578 f8955f18 2006-05-22 devnull */
579 f8955f18 2006-05-22 devnull sign = 0;
580 f8955f18 2006-05-22 devnull if(neg)
581 f8955f18 2006-05-22 devnull sign = '-';
582 f8955f18 2006-05-22 devnull else if(fl & FmtSign)
583 f8955f18 2006-05-22 devnull sign = '+';
584 f8955f18 2006-05-22 devnull else if(fl & FmtSpace)
585 f8955f18 2006-05-22 devnull sign = ' ';
586 f8955f18 2006-05-22 devnull if(sign)
587 f8955f18 2006-05-22 devnull wid++;
588 a76c0fd4 2004-12-26 devnull
589 f8955f18 2006-05-22 devnull /*
590 f8955f18 2006-05-22 devnull * compute padding
591 f8955f18 2006-05-22 devnull */
592 f8955f18 2006-05-22 devnull pad = 0;
593 f8955f18 2006-05-22 devnull if((fl & FmtWidth) && fmt->width > wid)
594 f8955f18 2006-05-22 devnull pad = fmt->width - wid;
595 f8955f18 2006-05-22 devnull if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
596 f8955f18 2006-05-22 devnull z1 += pad;
597 f8955f18 2006-05-22 devnull point += pad;
598 f8955f18 2006-05-22 devnull pad = 0;
599 f8955f18 2006-05-22 devnull }
600 a76c0fd4 2004-12-26 devnull
601 f8955f18 2006-05-22 devnull /*
602 f8955f18 2006-05-22 devnull * format the actual field. too bad about doing this twice.
603 f8955f18 2006-05-22 devnull */
604 f8955f18 2006-05-22 devnull if(fmt->runes){
605 f8955f18 2006-05-22 devnull if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
606 f8955f18 2006-05-22 devnull return -1;
607 f8955f18 2006-05-22 devnull rt = (Rune*)fmt->to;
608 f8955f18 2006-05-22 devnull rs = (Rune*)fmt->stop;
609 f8955f18 2006-05-22 devnull if(sign)
610 f8955f18 2006-05-22 devnull FMTRCHAR(fmt, rt, rs, sign);
611 f8955f18 2006-05-22 devnull while(z1>0 || ndigits>0 || z2>0) {
612 f8955f18 2006-05-22 devnull if(z1 > 0){
613 f8955f18 2006-05-22 devnull z1--;
614 f8955f18 2006-05-22 devnull c = '0';
615 f8955f18 2006-05-22 devnull }else if(ndigits > 0){
616 f8955f18 2006-05-22 devnull ndigits--;
617 f8955f18 2006-05-22 devnull c = *digits++;
618 d4f27433 2006-05-26 devnull }else{
619 f8955f18 2006-05-22 devnull z2--;
620 f8955f18 2006-05-22 devnull c = '0';
621 f8955f18 2006-05-22 devnull }
622 f8955f18 2006-05-22 devnull FMTRCHAR(fmt, rt, rs, c);
623 f8955f18 2006-05-22 devnull if(--point == 0) {
624 f8955f18 2006-05-22 devnull for(p = dot; *p; ){
625 f8955f18 2006-05-22 devnull p += chartorune(&r, p);
626 f8955f18 2006-05-22 devnull FMTRCHAR(fmt, rt, rs, r);
627 f8955f18 2006-05-22 devnull }
628 f8955f18 2006-05-22 devnull }
629 f8955f18 2006-05-22 devnull }
630 f8955f18 2006-05-22 devnull fmt->nfmt += rt - (Rune*)fmt->to;
631 f8955f18 2006-05-22 devnull fmt->to = rt;
632 f8955f18 2006-05-22 devnull if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
633 f8955f18 2006-05-22 devnull return -1;
634 f8955f18 2006-05-22 devnull if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
635 f8955f18 2006-05-22 devnull return -1;
636 f8955f18 2006-05-22 devnull }else{
637 f8955f18 2006-05-22 devnull if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
638 f8955f18 2006-05-22 devnull return -1;
639 f8955f18 2006-05-22 devnull t = (char*)fmt->to;
640 f8955f18 2006-05-22 devnull s = (char*)fmt->stop;
641 f8955f18 2006-05-22 devnull if(sign)
642 f8955f18 2006-05-22 devnull FMTCHAR(fmt, t, s, sign);
643 f8955f18 2006-05-22 devnull while(z1>0 || ndigits>0 || z2>0) {
644 f8955f18 2006-05-22 devnull if(z1 > 0){
645 f8955f18 2006-05-22 devnull z1--;
646 f8955f18 2006-05-22 devnull c = '0';
647 f8955f18 2006-05-22 devnull }else if(ndigits > 0){
648 f8955f18 2006-05-22 devnull ndigits--;
649 f8955f18 2006-05-22 devnull c = *digits++;
650 403fb41e 2006-05-28 devnull }else{
651 f8955f18 2006-05-22 devnull z2--;
652 f8955f18 2006-05-22 devnull c = '0';
653 f8955f18 2006-05-22 devnull }
654 f8955f18 2006-05-22 devnull FMTCHAR(fmt, t, s, c);
655 f8955f18 2006-05-22 devnull if(--point == 0)
656 f8955f18 2006-05-22 devnull for(p=dot; *p; p++)
657 f8955f18 2006-05-22 devnull FMTCHAR(fmt, t, s, *p);
658 f8955f18 2006-05-22 devnull }
659 f8955f18 2006-05-22 devnull fmt->nfmt += t - (char*)fmt->to;
660 f8955f18 2006-05-22 devnull fmt->to = t;
661 f8955f18 2006-05-22 devnull if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
662 f8955f18 2006-05-22 devnull return -1;
663 f8955f18 2006-05-22 devnull if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
664 f8955f18 2006-05-22 devnull return -1;
665 f8955f18 2006-05-22 devnull }
666 f8955f18 2006-05-22 devnull return 0;
667 a76c0fd4 2004-12-26 devnull }
668 f8955f18 2006-05-22 devnull