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