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 fa325e9b 2020-01-10 cross 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
30 fa325e9b 2020-01-10 cross 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
31 fa325e9b 2020-01-10 cross 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
32 fa325e9b 2020-01-10 cross 1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
33 fa325e9b 2020-01-10 cross 1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
34 fa325e9b 2020-01-10 cross 1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
35 fa325e9b 2020-01-10 cross 1e60, 1e61, 1e62, 1e63, 1e64, 1e65, 1e66, 1e67, 1e68, 1e69,
36 fa325e9b 2020-01-10 cross 1e70, 1e71, 1e72, 1e73, 1e74, 1e75, 1e76, 1e77, 1e78, 1e79,
37 fa325e9b 2020-01-10 cross 1e80, 1e81, 1e82, 1e83, 1e84, 1e85, 1e86, 1e87, 1e88, 1e89,
38 fa325e9b 2020-01-10 cross 1e90, 1e91, 1e92, 1e93, 1e94, 1e95, 1e96, 1e97, 1e98, 1e99,
39 fa325e9b 2020-01-10 cross 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
40 fa325e9b 2020-01-10 cross 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
41 fa325e9b 2020-01-10 cross 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
42 fa325e9b 2020-01-10 cross 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
43 fa325e9b 2020-01-10 cross 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
44 fa325e9b 2020-01-10 cross 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 91c13e54 2004-02-29 devnull neg = 1;
58 91c13e54 2004-02-29 devnull n = -n;
59 5400bd23 2009-07-28 russcox }
60 f8955f18 2006-05-22 devnull
61 f8955f18 2006-05-22 devnull if(n < npows10)
62 91c13e54 2004-02-29 devnull d = pows10[n];
63 91c13e54 2004-02-29 devnull else{
64 f8955f18 2006-05-22 devnull d = pows10[npows10-1];
65 91c13e54 2004-02-29 devnull for(;;){
66 f8955f18 2006-05-22 devnull n -= npows10 - 1;
67 f8955f18 2006-05-22 devnull if(n < npows10){
68 91c13e54 2004-02-29 devnull d *= pows10[n];
69 91c13e54 2004-02-29 devnull break;
70 91c13e54 2004-02-29 devnull }
71 f8955f18 2006-05-22 devnull d *= pows10[npows10 - 1];
72 91c13e54 2004-02-29 devnull }
73 91c13e54 2004-02-29 devnull }
74 f8955f18 2006-05-22 devnull if(neg)
75 91c13e54 2004-02-29 devnull return 1./d;
76 91c13e54 2004-02-29 devnull return d;
77 91c13e54 2004-02-29 devnull }
78 91c13e54 2004-02-29 devnull
79 f8955f18 2006-05-22 devnull /*
80 f8955f18 2006-05-22 devnull * add 1 to the decimal integer string a of length n.
81 f8955f18 2006-05-22 devnull * if 99999 overflows into 10000, return 1 to tell caller
82 f8955f18 2006-05-22 devnull * to move the virtual decimal point.
83 f8955f18 2006-05-22 devnull */
84 91c13e54 2004-02-29 devnull static int
85 f8955f18 2006-05-22 devnull xadd1(char *a, int n)
86 91c13e54 2004-02-29 devnull {
87 91c13e54 2004-02-29 devnull char *b;
88 91c13e54 2004-02-29 devnull int c;
89 91c13e54 2004-02-29 devnull
90 f8955f18 2006-05-22 devnull if(n < 0 || n > NSIGNIF)
91 91c13e54 2004-02-29 devnull return 0;
92 f8955f18 2006-05-22 devnull for(b = a+n-1; b >= a; b--) {
93 f8955f18 2006-05-22 devnull c = *b + 1;
94 91c13e54 2004-02-29 devnull if(c <= '9') {
95 91c13e54 2004-02-29 devnull *b = c;
96 91c13e54 2004-02-29 devnull return 0;
97 91c13e54 2004-02-29 devnull }
98 91c13e54 2004-02-29 devnull *b = '0';
99 91c13e54 2004-02-29 devnull }
100 f8955f18 2006-05-22 devnull /*
101 f8955f18 2006-05-22 devnull * need to overflow adding digit.
102 f8955f18 2006-05-22 devnull * shift number down and insert 1 at beginning.
103 f8955f18 2006-05-22 devnull * decimal is known to be 0s or we wouldn't
104 f8955f18 2006-05-22 devnull * have gotten this far. (e.g., 99999+1 => 00000)
105 f8955f18 2006-05-22 devnull */
106 f8955f18 2006-05-22 devnull a[0] = '1';
107 91c13e54 2004-02-29 devnull return 1;
108 91c13e54 2004-02-29 devnull }
109 91c13e54 2004-02-29 devnull
110 f8955f18 2006-05-22 devnull /*
111 f8955f18 2006-05-22 devnull * subtract 1 from the decimal integer string a.
112 f8955f18 2006-05-22 devnull * if 10000 underflows into 09999, make it 99999
113 fa325e9b 2020-01-10 cross * and return 1 to tell caller to move the virtual
114 f8955f18 2006-05-22 devnull * decimal point. this way, xsub1 is inverse of xadd1.
115 f8955f18 2006-05-22 devnull */
116 91c13e54 2004-02-29 devnull static int
117 f8955f18 2006-05-22 devnull xsub1(char *a, int n)
118 91c13e54 2004-02-29 devnull {
119 91c13e54 2004-02-29 devnull char *b;
120 91c13e54 2004-02-29 devnull int c;
121 91c13e54 2004-02-29 devnull
122 f8955f18 2006-05-22 devnull if(n < 0 || n > NSIGNIF)
123 f8955f18 2006-05-22 devnull return 0;
124 f8955f18 2006-05-22 devnull for(b = a+n-1; b >= a; b--) {
125 f8955f18 2006-05-22 devnull c = *b - 1;
126 91c13e54 2004-02-29 devnull if(c >= '0') {
127 f8955f18 2006-05-22 devnull if(c == '0' && b == a) {
128 f8955f18 2006-05-22 devnull /*
129 f8955f18 2006-05-22 devnull * just zeroed the top digit; shift everyone up.
130 f8955f18 2006-05-22 devnull * decimal is known to be 9s or we wouldn't
131 f8955f18 2006-05-22 devnull * have gotten this far. (e.g., 10000-1 => 09999)
132 f8955f18 2006-05-22 devnull */
133 f8955f18 2006-05-22 devnull *b = '9';
134 f8955f18 2006-05-22 devnull return 1;
135 f8955f18 2006-05-22 devnull }
136 91c13e54 2004-02-29 devnull *b = c;
137 91c13e54 2004-02-29 devnull return 0;
138 91c13e54 2004-02-29 devnull }
139 91c13e54 2004-02-29 devnull *b = '9';
140 91c13e54 2004-02-29 devnull }
141 f8955f18 2006-05-22 devnull /*
142 f8955f18 2006-05-22 devnull * can't get here. the number a is always normalized
143 f8955f18 2006-05-22 devnull * so that it has a nonzero first digit.
144 f8955f18 2006-05-22 devnull */
145 f8955f18 2006-05-22 devnull abort();
146 91c13e54 2004-02-29 devnull }
147 91c13e54 2004-02-29 devnull
148 f8955f18 2006-05-22 devnull /*
149 f8955f18 2006-05-22 devnull * format exponent like sprintf(p, "e%+02d", e)
150 f8955f18 2006-05-22 devnull */
151 91c13e54 2004-02-29 devnull static void
152 f8955f18 2006-05-22 devnull xfmtexp(char *p, int e, int ucase)
153 91c13e54 2004-02-29 devnull {
154 f8955f18 2006-05-22 devnull char se[9];
155 f8955f18 2006-05-22 devnull int i;
156 91c13e54 2004-02-29 devnull
157 f8955f18 2006-05-22 devnull *p++ = ucase ? 'E' : 'e';
158 f8955f18 2006-05-22 devnull if(e < 0) {
159 f8955f18 2006-05-22 devnull *p++ = '-';
160 f8955f18 2006-05-22 devnull e = -e;
161 f8955f18 2006-05-22 devnull } else
162 f8955f18 2006-05-22 devnull *p++ = '+';
163 f8955f18 2006-05-22 devnull i = 0;
164 f8955f18 2006-05-22 devnull while(e) {
165 f8955f18 2006-05-22 devnull se[i++] = e % 10 + '0';
166 f8955f18 2006-05-22 devnull e /= 10;
167 91c13e54 2004-02-29 devnull }
168 f8955f18 2006-05-22 devnull while(i < 2)
169 f8955f18 2006-05-22 devnull se[i++] = '0';
170 f8955f18 2006-05-22 devnull while(i > 0)
171 f8955f18 2006-05-22 devnull *p++ = se[--i];
172 f8955f18 2006-05-22 devnull *p++ = '\0';
173 f8955f18 2006-05-22 devnull }
174 f8955f18 2006-05-22 devnull
175 f8955f18 2006-05-22 devnull /*
176 f8955f18 2006-05-22 devnull * compute decimal integer m, exp such that:
177 f8955f18 2006-05-22 devnull * f = m*10^exp
178 f8955f18 2006-05-22 devnull * m is as short as possible with losing exactness
179 f8955f18 2006-05-22 devnull * assumes special cases (NaN, +Inf, -Inf) have been handled.
180 f8955f18 2006-05-22 devnull */
181 f8955f18 2006-05-22 devnull static void
182 f8955f18 2006-05-22 devnull xdtoa(double f, char *s, int *exp, int *neg, int *ns)
183 f8955f18 2006-05-22 devnull {
184 f8955f18 2006-05-22 devnull int c, d, e2, e, ee, i, ndigit, oerrno;
185 f8955f18 2006-05-22 devnull char tmp[NSIGNIF+10];
186 f8955f18 2006-05-22 devnull double g;
187 f8955f18 2006-05-22 devnull
188 f8955f18 2006-05-22 devnull oerrno = errno; /* in case strtod smashes errno */
189 f8955f18 2006-05-22 devnull
190 f8955f18 2006-05-22 devnull /*
191 f8955f18 2006-05-22 devnull * make f non-negative.
192 f8955f18 2006-05-22 devnull */
193 f8955f18 2006-05-22 devnull *neg = 0;
194 91c13e54 2004-02-29 devnull if(f < 0) {
195 91c13e54 2004-02-29 devnull f = -f;
196 f8955f18 2006-05-22 devnull *neg = 1;
197 91c13e54 2004-02-29 devnull }
198 91c13e54 2004-02-29 devnull
199 91c13e54 2004-02-29 devnull /*
200 f8955f18 2006-05-22 devnull * must handle zero specially.
201 91c13e54 2004-02-29 devnull */
202 f8955f18 2006-05-22 devnull if(f == 0){
203 f8955f18 2006-05-22 devnull *exp = 0;
204 f8955f18 2006-05-22 devnull s[0] = '0';
205 f8955f18 2006-05-22 devnull s[1] = '\0';
206 f8955f18 2006-05-22 devnull *ns = 1;
207 f8955f18 2006-05-22 devnull return;
208 91c13e54 2004-02-29 devnull }
209 fa325e9b 2020-01-10 cross
210 91c13e54 2004-02-29 devnull /*
211 f8955f18 2006-05-22 devnull * find g,e such that f = g*10^e.
212 f8955f18 2006-05-22 devnull * guess 10-exponent using 2-exponent, then fine tune.
213 91c13e54 2004-02-29 devnull */
214 f8955f18 2006-05-22 devnull frexp(f, &e2);
215 f8955f18 2006-05-22 devnull e = (int)(e2 * .301029995664);
216 f8955f18 2006-05-22 devnull g = f * pow10(-e);
217 f8955f18 2006-05-22 devnull while(g < 1) {
218 f8955f18 2006-05-22 devnull e--;
219 f8955f18 2006-05-22 devnull g = f * pow10(-e);
220 91c13e54 2004-02-29 devnull }
221 f8955f18 2006-05-22 devnull while(g >= 10) {
222 f8955f18 2006-05-22 devnull e++;
223 f8955f18 2006-05-22 devnull g = f * pow10(-e);
224 f8955f18 2006-05-22 devnull }
225 91c13e54 2004-02-29 devnull
226 91c13e54 2004-02-29 devnull /*
227 f8955f18 2006-05-22 devnull * convert NSIGNIF digits as a first approximation.
228 91c13e54 2004-02-29 devnull */
229 f8955f18 2006-05-22 devnull for(i=0; i<NSIGNIF; i++) {
230 f8955f18 2006-05-22 devnull d = (int)g;
231 f8955f18 2006-05-22 devnull s[i] = d+'0';
232 f8955f18 2006-05-22 devnull g = (g-d) * 10;
233 f8955f18 2006-05-22 devnull }
234 f8955f18 2006-05-22 devnull s[i] = 0;
235 f8955f18 2006-05-22 devnull
236 f8955f18 2006-05-22 devnull /*
237 f8955f18 2006-05-22 devnull * adjust e because s is 314159... not 3.14159...
238 f8955f18 2006-05-22 devnull */
239 f8955f18 2006-05-22 devnull e -= NSIGNIF-1;
240 f8955f18 2006-05-22 devnull xfmtexp(s+NSIGNIF, e, 0);
241 f8955f18 2006-05-22 devnull
242 f8955f18 2006-05-22 devnull /*
243 f8955f18 2006-05-22 devnull * adjust conversion until strtod(s) == f exactly.
244 f8955f18 2006-05-22 devnull */
245 f8955f18 2006-05-22 devnull for(i=0; i<10; i++) {
246 d17b0403 2009-07-29 rsc g = fmtstrtod(s, nil);
247 91c13e54 2004-02-29 devnull if(f > g) {
248 f8955f18 2006-05-22 devnull if(xadd1(s, NSIGNIF)) {
249 f8955f18 2006-05-22 devnull /* gained a digit */
250 91c13e54 2004-02-29 devnull e--;
251 f8955f18 2006-05-22 devnull xfmtexp(s+NSIGNIF, e, 0);
252 f8955f18 2006-05-22 devnull }
253 91c13e54 2004-02-29 devnull continue;
254 91c13e54 2004-02-29 devnull }
255 91c13e54 2004-02-29 devnull if(f < g) {
256 f8955f18 2006-05-22 devnull if(xsub1(s, NSIGNIF)) {
257 f8955f18 2006-05-22 devnull /* lost a digit */
258 91c13e54 2004-02-29 devnull e++;
259 f8955f18 2006-05-22 devnull xfmtexp(s+NSIGNIF, e, 0);
260 f8955f18 2006-05-22 devnull }
261 91c13e54 2004-02-29 devnull continue;
262 91c13e54 2004-02-29 devnull }
263 91c13e54 2004-02-29 devnull break;
264 91c13e54 2004-02-29 devnull }
265 91c13e54 2004-02-29 devnull
266 91c13e54 2004-02-29 devnull /*
267 f8955f18 2006-05-22 devnull * play with the decimal to try to simplify.
268 91c13e54 2004-02-29 devnull */
269 91c13e54 2004-02-29 devnull
270 91c13e54 2004-02-29 devnull /*
271 f8955f18 2006-05-22 devnull * bump last few digits up to 9 if we can
272 91c13e54 2004-02-29 devnull */
273 f8955f18 2006-05-22 devnull for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
274 f8955f18 2006-05-22 devnull c = s[i];
275 f8955f18 2006-05-22 devnull if(c != '9') {
276 f8955f18 2006-05-22 devnull s[i] = '9';
277 d17b0403 2009-07-29 rsc g = fmtstrtod(s, nil);
278 f8955f18 2006-05-22 devnull if(g != f) {
279 f8955f18 2006-05-22 devnull s[i] = c;
280 f8955f18 2006-05-22 devnull break;
281 f8955f18 2006-05-22 devnull }
282 91c13e54 2004-02-29 devnull }
283 91c13e54 2004-02-29 devnull }
284 91c13e54 2004-02-29 devnull
285 91c13e54 2004-02-29 devnull /*
286 f8955f18 2006-05-22 devnull * add 1 in hopes of turning 9s to 0s
287 91c13e54 2004-02-29 devnull */
288 f8955f18 2006-05-22 devnull if(s[NSIGNIF-1] == '9') {
289 f8955f18 2006-05-22 devnull strcpy(tmp, s);
290 f8955f18 2006-05-22 devnull ee = e;
291 f8955f18 2006-05-22 devnull if(xadd1(tmp, NSIGNIF)) {
292 f8955f18 2006-05-22 devnull ee--;
293 f8955f18 2006-05-22 devnull xfmtexp(tmp+NSIGNIF, ee, 0);
294 f8955f18 2006-05-22 devnull }
295 d17b0403 2009-07-29 rsc g = fmtstrtod(tmp, nil);
296 f8955f18 2006-05-22 devnull if(g == f) {
297 f8955f18 2006-05-22 devnull strcpy(s, tmp);
298 f8955f18 2006-05-22 devnull e = ee;
299 f8955f18 2006-05-22 devnull }
300 91c13e54 2004-02-29 devnull }
301 fa325e9b 2020-01-10 cross
302 91c13e54 2004-02-29 devnull /*
303 f8955f18 2006-05-22 devnull * bump last few digits down to 0 as we can.
304 91c13e54 2004-02-29 devnull */
305 f8955f18 2006-05-22 devnull for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
306 f8955f18 2006-05-22 devnull c = s[i];
307 f8955f18 2006-05-22 devnull if(c != '0') {
308 f8955f18 2006-05-22 devnull s[i] = '0';
309 d17b0403 2009-07-29 rsc g = fmtstrtod(s, nil);
310 f8955f18 2006-05-22 devnull if(g != f) {
311 f8955f18 2006-05-22 devnull s[i] = c;
312 f8955f18 2006-05-22 devnull break;
313 f8955f18 2006-05-22 devnull }
314 f8955f18 2006-05-22 devnull }
315 91c13e54 2004-02-29 devnull }
316 91c13e54 2004-02-29 devnull
317 91c13e54 2004-02-29 devnull /*
318 f8955f18 2006-05-22 devnull * remove trailing zeros.
319 91c13e54 2004-02-29 devnull */
320 f8955f18 2006-05-22 devnull ndigit = NSIGNIF;
321 f8955f18 2006-05-22 devnull while(ndigit > 1 && s[ndigit-1] == '0'){
322 f8955f18 2006-05-22 devnull e++;
323 f8955f18 2006-05-22 devnull --ndigit;
324 f8955f18 2006-05-22 devnull }
325 f8955f18 2006-05-22 devnull s[ndigit] = 0;
326 f8955f18 2006-05-22 devnull *exp = e;
327 f8955f18 2006-05-22 devnull *ns = ndigit;
328 f8955f18 2006-05-22 devnull errno = oerrno;
329 f8955f18 2006-05-22 devnull }
330 f8955f18 2006-05-22 devnull
331 f8955f18 2006-05-22 devnull #ifdef PLAN9PORT
332 f8955f18 2006-05-22 devnull static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
333 f8955f18 2006-05-22 devnull #else
334 f8955f18 2006-05-22 devnull static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
335 f8955f18 2006-05-22 devnull #endif
336 f8955f18 2006-05-22 devnull
337 f8955f18 2006-05-22 devnull int
338 f8955f18 2006-05-22 devnull __efgfmt(Fmt *fmt)
339 f8955f18 2006-05-22 devnull {
340 f8955f18 2006-05-22 devnull char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
341 f8955f18 2006-05-22 devnull double f;
342 f8955f18 2006-05-22 devnull int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
343 f8955f18 2006-05-22 devnull int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
344 f8955f18 2006-05-22 devnull Rune r, *rs, *rt;
345 fa325e9b 2020-01-10 cross
346 56b2179d 2006-06-26 devnull if(fmt->flags&FmtLong)
347 66cf8a39 2006-06-26 devnull f = va_arg(fmt->args, long double);
348 66cf8a39 2006-06-26 devnull else
349 66cf8a39 2006-06-26 devnull f = va_arg(fmt->args, double);
350 fa325e9b 2020-01-10 cross
351 fa325e9b 2020-01-10 cross /*
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 fa325e9b 2020-01-10 cross
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 fa325e9b 2020-01-10 cross /*
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 fa325e9b 2020-01-10 cross
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 fa325e9b 2020-01-10 cross }
541 f8955f18 2006-05-22 devnull sufwid = 0;
542 f8955f18 2006-05-22 devnull break;
543 91c13e54 2004-02-29 devnull }
544 fa325e9b 2020-01-10 cross
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 }