]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libc/stdio/xprintf_float.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 prsize;             /* max size of printed field */
172         int ret;                /* return value accumulator */
173         char *decimal_point;    /* locale specific decimal point */
174         int n2;                 /* XXX: for PRINTANDPAD */
175         char thousands_sep;     /* locale specific thousands separator */
176         char buf[BUF];          /* buffer with space for digits of uintmax_t */
177         const char *xdigs;
178         int flag;
179
180         prec = pi->prec;
181         ox[1] = '\0';
182         sign = pi->showsign;
183         flag = 0;
184         ret = 0;
185
186         thousands_sep = *(localeconv()->thousands_sep);
187         grouping = NULL;
188         if (pi->alt)
189                 grouping = localeconv()->grouping;
190         decimal_point = localeconv()->decimal_point;
191         dprec = -1;
192
193         switch(pi->spec) {
194         case 'a':
195         case 'A':
196                 if (pi->spec == 'a') {
197                         ox[1] = 'x';
198                         xdigs = __lowercase_hex;
199                         expchar = 'p';
200                 } else {
201                         ox[1] = 'X';
202                         xdigs = __uppercase_hex;
203                         expchar = 'P';
204                 }
205                 if (prec >= 0)
206                         prec++;
207                 if (pi->is_long_double) {
208                         ld = *((long double *)arg[0]);
209                         dtoaresult = cp =
210                             __hldtoa(ld, xdigs, prec,
211                             &expt, &signflag, &dtoaend);
212                 } else {
213                         d = *((double *)arg[0]);
214                         dtoaresult = cp =
215                             __hdtoa(d, xdigs, prec,
216                             &expt, &signflag, &dtoaend);
217                 }
218                 if (prec < 0)
219                         prec = dtoaend - cp;
220                 if (expt == INT_MAX)
221                         ox[1] = '\0';
222                 goto fp_common;
223         case 'e':
224         case 'E':
225                 expchar = pi->spec;
226                 if (prec < 0)   /* account for digit before decpt */
227                         prec = DEFPREC + 1;
228                 else
229                         prec++;
230                 break;
231         case 'f':
232         case 'F':
233                 expchar = '\0';
234                 break;
235         case 'g':
236         case 'G':
237                 expchar = pi->spec - ('g' - 'e');
238                 if (prec == 0)
239                         prec = 1;
240                 break;
241         default:
242                 assert(pi->spec == 'f');
243         }
244
245         if (prec < 0)
246                 prec = DEFPREC;
247         if (pi->is_long_double) {
248                 ld = *((long double *)arg[0]);
249                 dtoaresult = cp =
250                     __ldtoa(&ld, expchar ? 2 : 3, prec,
251                     &expt, &signflag, &dtoaend);
252         } else {
253                 d = *((double *)arg[0]);
254                 dtoaresult = cp =
255                     dtoa(d, expchar ? 2 : 3, prec,
256                     &expt, &signflag, &dtoaend);
257                 if (expt == 9999)
258                         expt = INT_MAX;
259         }
260 fp_common:
261         if (signflag)
262                 sign = '-';
263         if (expt == INT_MAX) {  /* inf or nan */
264                 if (*cp == 'N') {
265                         cp = (pi->spec >= 'a') ? "nan" : "NAN";
266                         sign = '\0';
267                 } else
268                         cp = (pi->spec >= 'a') ? "inf" : "INF";
269                 size = 3;
270                 flag = 1;
271                 goto here;
272         }
273         ndig = dtoaend - cp;
274         if (pi->spec == 'g' || pi->spec == 'G') {
275                 if (expt > -4 && expt <= prec) {
276                         /* Make %[gG] smell like %[fF] */
277                         expchar = '\0';
278                         if (pi->alt)
279                                 prec -= expt;
280                         else
281                                 prec = ndig - expt;
282                         if (prec < 0)
283                                 prec = 0;
284                 } else {
285                         /*
286                          * Make %[gG] smell like %[eE], but
287                          * trim trailing zeroes if no # flag.
288                          */
289                         if (!pi->alt)
290                                 prec = ndig;
291                 }
292         }
293         if (expchar) {
294                 expsize = exponent(expstr, expt - 1, expchar);
295                 size = expsize + prec;
296                 if (prec > 1 || pi->alt)
297                         ++size;
298         } else {
299                 /* space for digits before decimal point */
300                 if (expt > 0)
301                         size = expt;
302                 else    /* "0" */
303                         size = 1;
304                 /* space for decimal pt and following digits */
305                 if (prec || pi->alt)
306                         size += prec + 1;
307                 if (grouping && expt > 0) {
308                         /* space for thousands' grouping */
309                         nseps = nrepeats = 0;
310                         lead = expt;
311                         while (*grouping != CHAR_MAX) {
312                                 if (lead <= *grouping)
313                                         break;
314                                 lead -= *grouping;
315                                 if (*(grouping+1)) {
316                                         nseps++;
317                                         grouping++;
318                                 } else
319                                         nrepeats++;
320                         }
321                         size += nseps + nrepeats;
322                 } else
323                         lead = expt;
324         }
325
326 here:
327         /*
328          * All reasonable formats wind up here.  At this point, `cp'
329          * points to a string which (if not flags&LADJUST) should be
330          * padded out to `width' places.  If flags&ZEROPAD, it should
331          * first be prefixed by any sign or other prefix; otherwise,
332          * it should be blank padded before the prefix is emitted.
333          * After any left-hand padding and prefixing, emit zeroes
334          * required by a decimal [diouxX] precision, then print the
335          * string proper, then emit zeroes required by any leftover
336          * floating precision; finally, if LADJUST, pad with blanks.
337          *
338          * Compute actual size, so we know how much to pad.
339          * size excludes decimal prec; realsz includes it.
340          */
341         realsz = dprec > size ? dprec : size;
342         if (sign)
343                 realsz++;
344         if (ox[1])
345                 realsz += 2;
346
347         prsize = pi->width > realsz ? pi->width : realsz;
348
349         /* right-adjusting blank padding */
350         if (pi->pad != '0' && pi->left == 0)
351                 ret += __printf_pad(io, pi->width - realsz, 0);
352
353         /* prefix */
354         if (sign)
355                 ret += __printf_puts(io, &sign, 1);
356
357         if (ox[1]) {    /* ox[1] is either x, X, or \0 */
358                 ox[0] = '0';
359                 ret += __printf_puts(io, ox, 2);
360         }
361
362         /* right-adjusting zero padding */
363         if (pi->pad == '0' && pi->left == 0)
364                 ret += __printf_pad(io, pi->width - realsz, 1);
365
366         /* leading zeroes from decimal precision */
367         ret += __printf_pad(io, dprec - size, 1);
368
369         if (flag)
370                 ret += __printf_puts(io, cp, size);
371         else {
372                 /* glue together f_p fragments */
373                 if (!expchar) { /* %[fF] or sufficiently short %[gG] */
374                         if (expt <= 0) {
375                                 ret += __printf_puts(io, "0", 1);
376                                 if (prec || pi->alt)
377                                         ret += __printf_puts(io, decimal_point, 1);
378                                 ret += __printf_pad(io, -expt, 1);
379                                 /* already handled initial 0's */
380                                 prec += expt;
381                         } else {
382                                 PRINTANDPAD(cp, dtoaend, lead, 1);
383                                 cp += lead;
384                                 if (grouping) {
385                                         while (nseps>0 || nrepeats>0) {
386                                                 if (nrepeats > 0)
387                                                         nrepeats--;
388                                                 else {
389                                                         grouping--;
390                                                         nseps--;
391                                                 }
392                                                 ret += __printf_puts(io, &thousands_sep, 1);
393                                                 PRINTANDPAD(cp,dtoaend,
394                                                     *grouping, 1);
395                                                 cp += *grouping;
396                                         }
397                                         if (cp > dtoaend)
398                                                 cp = dtoaend;
399                                 }
400                                 if (prec || pi->alt)
401                                         ret += __printf_puts(io, decimal_point,1);
402                         }
403                         PRINTANDPAD(cp, dtoaend, prec, 1);
404                 } else {        /* %[eE] or sufficiently long %[gG] */
405                         if (prec > 1 || pi->alt) {
406                                 buf[0] = *cp++;
407                                 buf[1] = *decimal_point;
408                                 ret += __printf_puts(io, buf, 2);
409                                 ret += __printf_puts(io, cp, ndig-1);
410                                 ret += __printf_pad(io, prec - ndig, 1);
411                         } else  /* XeYYY */
412                                 ret += __printf_puts(io, cp, 1);
413                         ret += __printf_puts(io, expstr, expsize);
414                 }
415         }
416         /* left-adjusting padding (always blank) */
417         if (pi->left)
418                 ret += __printf_pad(io, pi->width - realsz, 0);
419
420         __printf_flush(io);
421         if (dtoaresult != NULL)
422                 freedtoa(dtoaresult);
423
424         return (ret);
425 }