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