Initial import of binutils 2.22 on the new vendor branch
[dragonfly.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: 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 <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 "un-namespace.h"
49 #include "gdtoa.h"
50 #include "floatio.h"
51 #include "printf.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         } else {
95                 *p++ = '+';
96         }
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         } else {
106                 /*
107                  * Exponents for decimal floating point conversions
108                  * (%[eEgG]) must be at least two characters long,
109                  * whereas exponents for hexadecimal conversions can
110                  * be only one character long.
111                  */
112                 if (fmtch == 'e' || fmtch == 'E')
113                         *p++ = '0';
114                 *p++ = to_char(expo);
115         }
116         return (p - p0);
117 }
118
119 /* 'f' ---------------------------------------------------------------*/
120
121 int
122 __printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt)
123 {
124         assert (n > 0);
125         argt[0] = PA_DOUBLE;
126         if (pi->is_long_double)
127                 argt[0] |= PA_FLAG_LONG_DOUBLE;
128         return (1);
129 }
130
131 /*
132  * We can decompose the printed representation of floating
133  * point numbers into several parts, some of which may be empty:
134  *
135  * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
136  *    A       B     ---C---      D       E   F
137  *
138  * A:   'sign' holds this value if present; '\0' otherwise
139  * B:   ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
140  * C:   cp points to the string MMMNNN.  Leading and trailing
141  *      zeroes are not in the string and must be added.
142  * D:   expchar holds this character; '\0' if no exponent, e.g. %f
143  * F:   at least two digits for decimal, at least one digit for hex
144  */
145
146 int
147 __printf_render_float(struct __printf_io *io, const struct printf_info *pi,
148                       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                 }
270                 size = 3;
271                 flag = 1;
272                 goto here;
273         }
274         ndig = dtoaend - cp;
275         if (pi->spec == 'g' || pi->spec == 'G') {
276                 if (expt > -4 && expt <= prec) {
277                         /* Make %[gG] smell like %[fF] */
278                         expchar = '\0';
279                         if (pi->alt)
280                                 prec -= expt;
281                         else
282                                 prec = ndig - expt;
283                         if (prec < 0)
284                                 prec = 0;
285                 } else {
286                         /*
287                          * Make %[gG] smell like %[eE], but
288                          * trim trailing zeroes if no # flag.
289                          */
290                         if (!pi->alt)
291                                 prec = ndig;
292                 }
293         }
294         if (expchar) {
295                 expsize = exponent(expstr, expt - 1, expchar);
296                 size = expsize + prec;
297                 if (prec > 1 || pi->alt)
298                         ++size;
299         } else {
300                 /* space for digits before decimal point */
301                 if (expt > 0)
302                         size = expt;
303                 else    /* "0" */
304                         size = 1;
305                 /* space for decimal pt and following digits */
306                 if (prec || pi->alt)
307                         size += prec + 1;
308                 if (grouping && expt > 0) {
309                         /* space for thousands' grouping */
310                         nseps = nrepeats = 0;
311                         lead = expt;
312                         while (*grouping != CHAR_MAX) {
313                                 if (lead <= *grouping)
314                                         break;
315                                 lead -= *grouping;
316                                 if (*(grouping+1)) {
317                                         nseps++;
318                                         grouping++;
319                                 } else {
320                                         nrepeats++;
321                                 }
322                         }
323                         size += nseps + nrepeats;
324                 } else {
325                         lead = expt;
326                 }
327         }
328
329 here:
330         /*
331          * All reasonable formats wind up here.  At this point, `cp'
332          * points to a string which (if not flags&LADJUST) should be
333          * padded out to `width' places.  If flags&ZEROPAD, it should
334          * first be prefixed by any sign or other prefix; otherwise,
335          * it should be blank padded before the prefix is emitted.
336          * After any left-hand padding and prefixing, emit zeroes
337          * required by a decimal [diouxX] precision, then print the
338          * string proper, then emit zeroes required by any leftover
339          * floating precision; finally, if LADJUST, pad with blanks.
340          *
341          * Compute actual size, so we know how much to pad.
342          * size excludes decimal prec; realsz includes it.
343          */
344         realsz = dprec > size ? dprec : size;
345         if (sign)
346                 realsz++;
347         if (ox[1])
348                 realsz += 2;
349
350         prsize = pi->width > realsz ? pi->width : realsz;
351
352         /* right-adjusting blank padding */
353         if (pi->pad != '0' && pi->left == 0)
354                 ret += __printf_pad(io, pi->width - realsz, 0);
355
356         /* prefix */
357         if (sign)
358                 ret += __printf_puts(io, &sign, 1);
359
360         if (ox[1]) {    /* ox[1] is either x, X, or \0 */
361                 ox[0] = '0';
362                 ret += __printf_puts(io, ox, 2);
363         }
364
365         /* right-adjusting zero padding */
366         if (pi->pad == '0' && pi->left == 0)
367                 ret += __printf_pad(io, pi->width - realsz, 1);
368
369         /* leading zeroes from decimal precision */
370         ret += __printf_pad(io, dprec - size, 1);
371
372         if (flag) {
373                 ret += __printf_puts(io, cp, size);
374         } else {
375                 /* glue together f_p fragments */
376                 if (!expchar) { /* %[fF] or sufficiently short %[gG] */
377                         if (expt <= 0) {
378                                 ret += __printf_puts(io, "0", 1);
379                                 if (prec || pi->alt)
380                                         ret += __printf_puts(io, decimal_point, 1);
381                                 ret += __printf_pad(io, -expt, 1);
382                                 /* already handled initial 0's */
383                                 prec += expt;
384                         } else {
385                                 PRINTANDPAD(cp, dtoaend, lead, 1);
386                                 cp += lead;
387                                 if (grouping) {
388                                         while (nseps>0 || nrepeats>0) {
389                                                 if (nrepeats > 0) {
390                                                         nrepeats--;
391                                                 } else {
392                                                         grouping--;
393                                                         nseps--;
394                                                 }
395                                                 ret += __printf_puts(io, &thousands_sep, 1);
396                                                 PRINTANDPAD(cp,dtoaend,
397                                                     *grouping, 1);
398                                                 cp += *grouping;
399                                         }
400                                         if (cp > dtoaend)
401                                                 cp = dtoaend;
402                                 }
403                                 if (prec || pi->alt)
404                                         ret += __printf_puts(io, decimal_point,1);
405                         }
406                         PRINTANDPAD(cp, dtoaend, prec, 1);
407                 } else {        /* %[eE] or sufficiently long %[gG] */
408                         if (prec > 1 || pi->alt) {
409                                 buf[0] = *cp++;
410                                 buf[1] = *decimal_point;
411                                 ret += __printf_puts(io, buf, 2);
412                                 ret += __printf_puts(io, cp, ndig-1);
413                                 ret += __printf_pad(io, prec - ndig, 1);
414                         } else {        /* XeYYY */
415                                 ret += __printf_puts(io, cp, 1);
416                         }
417                         ret += __printf_puts(io, expstr, expsize);
418                 }
419         }
420         /* left-adjusting padding (always blank) */
421         if (pi->left)
422                 ret += __printf_pad(io, pi->width - realsz, 0);
423
424         __printf_flush(io);
425         if (dtoaresult != NULL)
426                 freedtoa(dtoaresult);
427
428         return (ret);
429 }