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