]> git.saurik.com Git - apple/libc.git/blame - stdio/FreeBSD/xprintf_float.c
Libc-997.1.1.tar.gz
[apple/libc.git] / stdio / FreeBSD / xprintf_float.c
CommitLineData
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
83extern const char *__fix_nogrouping(const char *str);
84
85#define to_char(n) ((n) + '0')
86
87static int
88exponent(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 }
280fp_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
346here:
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}