]>
Commit | Line | Data |
---|---|---|
6465356a A |
1 | /*- |
2 | * Copyright (c) 2005 Poul-Henning Kamp | |
3 | * Copyright (c) 1990, 1993 | |
4 | * The Regents of the University of California. All rights reserved. | |
5 | * | |
6 | * This code is derived from software contributed to Berkeley by | |
7 | * Chris Torek. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * 3. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | * $FreeBSD: src/lib/libc/stdio/xprintf_float.c,v 1.1 2005/12/16 18:56:38 phk Exp $ | |
34 | */ | |
35 | ||
36 | #include <namespace.h> | |
37 | #include "xlocale_private.h" | |
38 | #include <stdio.h> | |
39 | #include <wchar.h> | |
40 | #include <assert.h> | |
41 | #include <locale.h> | |
42 | #include <limits.h> | |
43 | ||
44 | #define dtoa __dtoa | |
45 | #define freedtoa __freedtoa | |
46 | ||
47 | #include <float.h> | |
48 | #include <math.h> | |
49 | #include "gdtoa.h" | |
50 | #include "floatio.h" | |
51 | #include "printf.h" | |
52 | #include "xprintf_private.h" | |
53 | #include <un-namespace.h> | |
54 | ||
55 | /* | |
56 | * The size of the buffer we use as scratch space for integer | |
57 | * conversions, among other things. Technically, we would need the | |
58 | * most space for base 10 conversions with thousands' grouping | |
59 | * characters between each pair of digits. 100 bytes is a | |
60 | * conservative overestimate even for a 128-bit uintmax_t. | |
61 | */ | |
62 | #define BUF 100 | |
63 | ||
64 | #define DEFPREC 6 /* Default FP precision */ | |
65 | ||
66 | ||
67 | /* various globals ---------------------------------------------------*/ | |
68 | ||
69 | ||
70 | /* padding function---------------------------------------------------*/ | |
71 | ||
72 | #define PRINTANDPAD(p, ep, len, with) do { \ | |
73 | n2 = (ep) - (p); \ | |
74 | if (n2 > (len)) \ | |
75 | n2 = (len); \ | |
76 | if (n2 > 0) \ | |
77 | ret += __printf_puts(io, (p), n2); \ | |
78 | ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with)); \ | |
79 | } while(0) | |
80 | ||
81 | /* misc --------------------------------------------------------------*/ | |
82 | ||
83 | extern const char *__fix_nogrouping(const char *str); | |
84 | ||
85 | #define to_char(n) ((n) + '0') | |
86 | ||
87 | static int | |
88 | exponent(char *p0, int expo, int fmtch) | |
89 | { | |
90 | char *p, *t; | |
91 | char expbuf[MAXEXPDIG]; | |
92 | ||
93 | p = p0; | |
94 | *p++ = fmtch; | |
95 | if (expo < 0) { | |
96 | expo = -expo; | |
97 | *p++ = '-'; | |
98 | } | |
99 | else | |
100 | *p++ = '+'; | |
101 | t = expbuf + MAXEXPDIG; | |
102 | if (expo > 9) { | |
103 | do { | |
104 | *--t = to_char(expo % 10); | |
105 | } while ((expo /= 10) > 9); | |
106 | *--t = to_char(expo); | |
107 | for (; t < expbuf + MAXEXPDIG; *p++ = *t++) | |
108 | ; | |
109 | } | |
110 | else { | |
111 | /* | |
112 | * Exponents for decimal floating point conversions | |
113 | * (%[eEgG]) must be at least two characters long, | |
114 | * whereas exponents for hexadecimal conversions can | |
115 | * be only one character long. | |
116 | */ | |
117 | if (fmtch == 'e' || fmtch == 'E') | |
118 | *p++ = '0'; | |
119 | *p++ = to_char(expo); | |
120 | } | |
121 | return (p - p0); | |
122 | } | |
123 | ||
124 | /* 'f' ---------------------------------------------------------------*/ | |
125 | ||
126 | __private_extern__ int | |
127 | __printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt) | |
128 | { | |
129 | assert (n > 0); | |
130 | #ifdef VECTORS | |
131 | if (pi->is_vec) | |
132 | argt[0] = PA_VECTOR; | |
133 | else { | |
134 | #endif /* VECTORS */ | |
135 | argt[0] = PA_DOUBLE; | |
136 | if (pi->is_long_double) | |
137 | argt[0] |= PA_FLAG_LONG_DOUBLE; | |
138 | #ifdef VECTORS | |
139 | } | |
140 | #endif /* VECTORS */ | |
141 | return (1); | |
142 | } | |
143 | ||
144 | /* | |
145 | * We can decompose the printed representation of floating | |
146 | * point numbers into several parts, some of which may be empty: | |
147 | * | |
148 | * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ | |
149 | * A B ---C--- D E F | |
150 | * | |
151 | * A: 'sign' holds this value if present; '\0' otherwise | |
152 | * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal | |
153 | * C: cp points to the string MMMNNN. Leading and trailing | |
154 | * zeros are not in the string and must be added. | |
155 | * D: expchar holds this character; '\0' if no exponent, e.g. %f | |
156 | * F: at least two digits for decimal, at least one digit for hex | |
157 | */ | |
158 | ||
159 | __private_extern__ int | |
160 | __printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) | |
161 | { | |
162 | int prec; /* precision from format; <0 for N/A */ | |
163 | char *dtoaresult; /* buffer allocated by dtoa */ | |
164 | char expchar; /* exponent character: [eEpP\0] */ | |
165 | char *cp; | |
166 | int expt; /* integer value of exponent */ | |
167 | int signflag; /* true if float is negative */ | |
168 | char *dtoaend; /* pointer to end of converted digits */ | |
169 | char sign; /* sign prefix (' ', '+', '-', or \0) */ | |
170 | int size; /* size of converted field or string */ | |
171 | int ndig; /* actual number of digits returned by dtoa */ | |
172 | int expsize; /* character count for expstr */ | |
173 | char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ | |
174 | int nseps; /* number of group separators with ' */ | |
175 | int nrepeats; /* number of repeats of the last group */ | |
176 | const char *grouping; /* locale specific numeric grouping rules */ | |
177 | int lead; /* sig figs before decimal or group sep */ | |
178 | long double ld; | |
179 | double d; | |
180 | int realsz; /* field size expanded by dprec, sign, etc */ | |
181 | int dprec; /* a copy of prec if [diouxX], 0 otherwise */ | |
182 | char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ | |
183 | int prsize; /* max size of printed field */ | |
184 | int ret; /* return value accumulator */ | |
185 | const char *decimal_point; /* locale specific decimal point */ | |
186 | int decimal_point_len; /* length of locale specific decimal point */ | |
187 | int n2; /* XXX: for PRINTANDPAD */ | |
188 | const char *thousands_sep; /* locale specific thousands separator */ | |
189 | int thousands_sep_len; /* length of locale specific thousands separator */ | |
190 | char buf[BUF]; /* buffer with space for digits of uintmax_t */ | |
191 | const char *xdigs; | |
192 | int flag; | |
193 | ||
194 | #ifdef VECTORS | |
195 | if (pi->is_vec) return __xprintf_vector(io, pi, arg); | |
196 | #endif /* VECTORS */ | |
197 | ||
198 | prec = pi->prec; | |
199 | ox[1] = '\0'; | |
200 | sign = pi->signchar; | |
201 | flag = 0; | |
202 | ret = 0; | |
203 | ||
204 | thousands_sep = localeconv_l(pi->loc)->thousands_sep; | |
205 | thousands_sep_len = strlen(thousands_sep); | |
206 | grouping = NULL; | |
207 | if (pi->group) | |
208 | grouping = __fix_nogrouping(localeconv_l(pi->loc)->grouping); | |
209 | decimal_point = localeconv_l(pi->loc)->decimal_point; | |
210 | decimal_point_len = strlen(decimal_point); | |
211 | dprec = -1; | |
212 | ||
213 | switch(pi->spec) { | |
214 | case 'a': | |
215 | case 'A': | |
216 | if (pi->spec == 'a') { | |
217 | ox[1] = 'x'; | |
218 | xdigs = __lowercase_hex; | |
219 | expchar = 'p'; | |
220 | } else { | |
221 | ox[1] = 'X'; | |
222 | xdigs = __uppercase_hex; | |
223 | expchar = 'P'; | |
224 | } | |
225 | if (prec >= 0) | |
226 | prec++; | |
227 | if (pi->is_long_double) { | |
228 | ld = *((long double *)arg[0]); | |
229 | dtoaresult = cp = | |
230 | __hldtoa(ld, xdigs, prec, | |
231 | &expt, &signflag, &dtoaend); | |
232 | } else { | |
233 | d = *((double *)arg[0]); | |
234 | dtoaresult = cp = | |
235 | __hdtoa(d, xdigs, prec, | |
236 | &expt, &signflag, &dtoaend); | |
237 | } | |
238 | if (prec < 0) | |
239 | prec = dtoaend - cp; | |
240 | if (expt == INT_MAX) | |
241 | ox[1] = '\0'; | |
242 | goto fp_common; | |
243 | case 'e': | |
244 | case 'E': | |
245 | expchar = pi->spec; | |
246 | if (prec < 0) /* account for digit before decpt */ | |
247 | prec = DEFPREC + 1; | |
248 | else | |
249 | prec++; | |
250 | break; | |
251 | case 'f': | |
252 | case 'F': | |
253 | expchar = '\0'; | |
254 | break; | |
255 | case 'g': | |
256 | case 'G': | |
257 | expchar = pi->spec - ('g' - 'e'); | |
258 | if (prec == 0) | |
259 | prec = 1; | |
260 | break; | |
261 | default: | |
262 | assert(pi->spec == 'f'); | |
263 | } | |
264 | ||
265 | if (prec < 0) | |
266 | prec = DEFPREC; | |
267 | if (pi->is_long_double) { | |
268 | ld = *((long double *)arg[0]); | |
269 | dtoaresult = cp = | |
270 | __ldtoa(&ld, expchar ? 2 : 3, prec, | |
271 | &expt, &signflag, &dtoaend); | |
272 | } else { | |
273 | d = *((double *)arg[0]); | |
274 | dtoaresult = cp = | |
275 | dtoa(d, expchar ? 2 : 3, prec, | |
276 | &expt, &signflag, &dtoaend); | |
277 | if (expt == 9999) | |
278 | expt = INT_MAX; | |
279 | } | |
280 | fp_common: | |
281 | if (signflag) | |
282 | sign = '-'; | |
283 | if (expt == INT_MAX) { /* inf or nan */ | |
284 | if (*cp == 'N') { | |
285 | cp = (pi->spec >= 'a') ? "nan" : "NAN"; | |
286 | sign = '\0'; | |
287 | } else | |
288 | cp = (pi->spec >= 'a') ? "inf" : "INF"; | |
289 | size = 3; | |
290 | flag = 1; | |
291 | goto here; | |
292 | } | |
293 | ndig = dtoaend - cp; | |
294 | if (pi->spec == 'g' || pi->spec == 'G') { | |
295 | if (expt > -4 && expt <= prec) { | |
296 | /* Make %[gG] smell like %[fF] */ | |
297 | expchar = '\0'; | |
298 | if (pi->alt) | |
299 | prec -= expt; | |
300 | else | |
301 | prec = ndig - expt; | |
302 | if (prec < 0) | |
303 | prec = 0; | |
304 | } else { | |
305 | /* | |
306 | * Make %[gG] smell like %[eE], but | |
307 | * trim trailing zeroes if no # flag. | |
308 | */ | |
309 | if (!pi->alt) | |
310 | prec = ndig; | |
311 | } | |
312 | } | |
313 | if (expchar) { | |
314 | expsize = exponent(expstr, expt - 1, expchar); | |
315 | size = expsize + prec; | |
316 | if (prec > 1 || pi->alt) | |
317 | ++size; | |
318 | } else { | |
319 | /* space for digits before decimal point */ | |
320 | if (expt > 0) | |
321 | size = expt; | |
322 | else /* "0" */ | |
323 | size = 1; | |
324 | /* space for decimal pt and following digits */ | |
325 | if (prec || pi->alt) | |
326 | size += prec + 1; | |
327 | if (grouping && expt > 0) { | |
328 | /* space for thousands' grouping */ | |
329 | nseps = nrepeats = 0; | |
330 | lead = expt; | |
331 | while (*grouping != CHAR_MAX) { | |
332 | if (lead <= *grouping) | |
333 | break; | |
334 | lead -= *grouping; | |
335 | if (*(grouping+1)) { | |
336 | nseps++; | |
337 | grouping++; | |
338 | } else | |
339 | nrepeats++; | |
340 | } | |
341 | size += nseps + nrepeats; | |
342 | } else | |
343 | lead = expt; | |
344 | } | |
345 | ||
346 | here: | |
347 | /* | |
348 | * All reasonable formats wind up here. At this point, `cp' | |
349 | * points to a string which (if not flags&LADJUST) should be | |
350 | * padded out to `width' places. If flags&ZEROPAD, it should | |
351 | * first be prefixed by any sign or other prefix; otherwise, | |
352 | * it should be blank padded before the prefix is emitted. | |
353 | * After any left-hand padding and prefixing, emit zeroes | |
354 | * required by a decimal [diouxX] precision, then print the | |
355 | * string proper, then emit zeroes required by any leftover | |
356 | * floating precision; finally, if LADJUST, pad with blanks. | |
357 | * | |
358 | * Compute actual size, so we know how much to pad. | |
359 | * size excludes decimal prec; realsz includes it. | |
360 | */ | |
361 | realsz = dprec > size ? dprec : size; | |
362 | if (sign) | |
363 | realsz++; | |
364 | if (ox[1]) | |
365 | realsz += 2; | |
366 | ||
367 | prsize = pi->width > realsz ? pi->width : realsz; | |
368 | ||
369 | /* right-adjusting blank padding */ | |
370 | if (pi->pad != '0' && pi->left == 0) | |
371 | ret += __printf_pad(io, pi->width - realsz, 0); | |
372 | ||
373 | /* prefix */ | |
374 | if (sign) | |
375 | ret += __printf_puts(io, &sign, 1); | |
376 | ||
377 | if (ox[1]) { /* ox[1] is either x, X, or \0 */ | |
378 | ox[0] = '0'; | |
379 | ret += __printf_puts(io, ox, 2); | |
380 | } | |
381 | ||
382 | /* right-adjusting zero padding */ | |
383 | if (pi->pad == '0' && pi->left == 0) | |
384 | ret += __printf_pad(io, pi->width - realsz, 1); | |
385 | ||
386 | /* leading zeroes from decimal precision */ | |
387 | ret += __printf_pad(io, dprec - size, 1); | |
388 | ||
389 | if (flag) | |
390 | ret += __printf_puts(io, cp, size); | |
391 | else { | |
392 | /* glue together f_p fragments */ | |
393 | if (!expchar) { /* %[fF] or sufficiently short %[gG] */ | |
394 | if (expt <= 0) { | |
395 | ret += __printf_puts(io, "0", 1); | |
396 | if (prec || pi->alt) | |
397 | ret += __printf_puts(io, decimal_point, decimal_point_len); | |
398 | ret += __printf_pad(io, -expt, 1); | |
399 | /* already handled initial 0's */ | |
400 | prec += expt; | |
401 | } else { | |
402 | PRINTANDPAD(cp, dtoaend, lead, 1); | |
403 | cp += lead; | |
404 | if (grouping) { | |
405 | while (nseps>0 || nrepeats>0) { | |
406 | if (nrepeats > 0) | |
407 | nrepeats--; | |
408 | else { | |
409 | grouping--; | |
410 | nseps--; | |
411 | } | |
412 | ret += __printf_puts(io, thousands_sep, thousands_sep_len); | |
413 | PRINTANDPAD(cp,dtoaend, | |
414 | *grouping, 1); | |
415 | cp += *grouping; | |
416 | } | |
417 | if (cp > dtoaend) | |
418 | cp = dtoaend; | |
419 | } | |
420 | if (prec || pi->alt) | |
421 | ret += __printf_puts(io, decimal_point, decimal_point_len); | |
422 | } | |
423 | PRINTANDPAD(cp, dtoaend, prec, 1); | |
424 | } else { /* %[eE] or sufficiently long %[gG] */ | |
425 | if (prec > 1 || pi->alt) { | |
426 | buf[0] = *cp++; | |
427 | memcpy(buf + 1, decimal_point, decimal_point_len); | |
428 | ret += __printf_puts(io, buf, decimal_point_len + 1); | |
429 | ret += __printf_puts(io, cp, ndig-1); | |
430 | ret += __printf_pad(io, prec - ndig, 1); | |
431 | } else /* XeYYY */ | |
432 | ret += __printf_puts(io, cp, 1); | |
433 | ret += __printf_puts(io, expstr, expsize); | |
434 | } | |
435 | } | |
436 | /* left-adjusting padding (always blank) */ | |
437 | if (pi->left) | |
438 | ret += __printf_pad(io, pi->width - realsz, 0); | |
439 | ||
440 | __printf_flush(io); | |
441 | if (dtoaresult != NULL) | |
442 | freedtoa(dtoaresult); | |
443 | ||
444 | return (ret); | |
445 | } |