Upgrade awk(1). 1/2
[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 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                 }
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                         }
322                         size += nseps + nrepeats;
323                 } else {
324                         lead = expt;
325                 }
326         }
327
328 here:
329         /*
330          * All reasonable formats wind up here.  At this point, `cp'
331          * points to a string which (if not flags&LADJUST) should be
332          * padded out to `width' places.  If flags&ZEROPAD, it should
333          * first be prefixed by any sign or other prefix; otherwise,
334          * it should be blank padded before the prefix is emitted.
335          * After any left-hand padding and prefixing, emit zeroes
336          * required by a decimal [diouxX] precision, then print the
337          * string proper, then emit zeroes required by any leftover
338          * floating precision; finally, if LADJUST, pad with blanks.
339          *
340          * Compute actual size, so we know how much to pad.
341          * size excludes decimal prec; realsz includes it.
342          */
343         realsz = dprec > size ? dprec : size;
344         if (sign)
345                 realsz++;
346         if (ox[1])
347                 realsz += 2;
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                         }
414                         ret += __printf_puts(io, expstr, expsize);
415                 }
416         }
417         /* left-adjusting padding (always blank) */
418         if (pi->left)
419                 ret += __printf_pad(io, pi->width - realsz, 0);
420
421         __printf_flush(io);
422         if (dtoaresult != NULL)
423                 freedtoa(dtoaresult);
424
425         return (ret);
426 }