]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/stdio/xprintf_float.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb, and openmp
[FreeBSD/FreeBSD.git] / lib / libc / stdio / xprintf_float.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2005 Poul-Henning Kamp
5  * Copyright (c) 1990, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Chris Torek.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $FreeBSD$
36  */
37
38 #include <namespace.h>
39 #include <stdio.h>
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 <un-namespace.h>
54
55 /*
56  * The size of the buffer we use as scratch space for integer
57  * conversions, among other things.  Technically, we would need the
58  * most space for base 10 conversions with thousands' grouping
59  * characters between each pair of digits.  100 bytes is a
60  * conservative overestimate even for a 128-bit uintmax_t.
61  */
62 #define BUF     100
63
64 #define DEFPREC         6       /* Default FP precision */
65
66
67 /* various globals ---------------------------------------------------*/
68
69
70 /* padding function---------------------------------------------------*/
71
72 #define PRINTANDPAD(p, ep, len, with) do {              \
73         n2 = (ep) - (p);                                \
74         if (n2 > (len))                                 \
75                 n2 = (len);                             \
76         if (n2 > 0)                                     \
77                 ret += __printf_puts(io, (p), n2);              \
78         ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with));     \
79 } while(0)
80
81 /* misc --------------------------------------------------------------*/
82
83 #define to_char(n)      ((n) + '0')
84
85 static int
86 exponent(char *p0, int expo, int fmtch)
87 {
88         char *p, *t;
89         char expbuf[MAXEXPDIG];
90
91         p = p0;
92         *p++ = fmtch;
93         if (expo < 0) {
94                 expo = -expo;
95                 *p++ = '-';
96         }
97         else
98                 *p++ = '+';
99         t = expbuf + MAXEXPDIG;
100         if (expo > 9) {
101                 do {
102                         *--t = to_char(expo % 10);
103                 } while ((expo /= 10) > 9);
104                 *--t = to_char(expo);
105                 for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
106                         ;
107         }
108         else {
109                 /*
110                  * Exponents for decimal floating point conversions
111                  * (%[eEgG]) must be at least two characters long,
112                  * whereas exponents for hexadecimal conversions can
113                  * be only one character long.
114                  */
115                 if (fmtch == 'e' || fmtch == 'E')
116                         *p++ = '0';
117                 *p++ = to_char(expo);
118         }
119         return (p - p0);
120 }
121
122 /* 'f' ---------------------------------------------------------------*/
123
124 int
125 __printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt)
126 {
127         assert (n > 0);
128         argt[0] = PA_DOUBLE;
129         if (pi->is_long_double)
130                 argt[0] |= PA_FLAG_LONG_DOUBLE;
131         return (1);
132 }
133
134 /*
135  * We can decompose the printed representation of floating
136  * point numbers into several parts, some of which may be empty:
137  *
138  * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
139  *    A       B     ---C---      D       E   F
140  *
141  * A:   'sign' holds this value if present; '\0' otherwise
142  * B:   ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
143  * C:   cp points to the string MMMNNN.  Leading and trailing
144  *      zeros are not in the string and must be added.
145  * D:   expchar holds this character; '\0' if no exponent, e.g. %f
146  * F:   at least two digits for decimal, at least one digit for hex
147  */
148
149 int
150 __printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
151 {
152         int prec;               /* precision from format; <0 for N/A */
153         char *dtoaresult;       /* buffer allocated by dtoa */
154         char expchar;           /* exponent character: [eEpP\0] */
155         char *cp;
156         int expt;               /* integer value of exponent */
157         int signflag;           /* true if float is negative */
158         char *dtoaend;          /* pointer to end of converted digits */
159         char sign;              /* sign prefix (' ', '+', '-', or \0) */
160         int size;               /* size of converted field or string */
161         int ndig;               /* actual number of digits returned by dtoa */
162         int expsize;            /* character count for expstr */
163         char expstr[MAXEXPDIG+2];       /* buffer for exponent string: e+ZZZ */
164         int nseps;              /* number of group separators with ' */
165         int nrepeats;           /* number of repeats of the last group */
166         const char *grouping;   /* locale specific numeric grouping rules */
167         int lead;               /* sig figs before decimal or group sep */
168         long double ld;
169         double d;
170         int realsz;             /* field size expanded by dprec, sign, etc */
171         int dprec;              /* a copy of prec if [diouxX], 0 otherwise */
172         char ox[2];             /* space for 0x; ox[1] is either x, X, or \0 */
173         int ret;                /* return value accumulator */
174         char *decimal_point;    /* locale specific decimal point */
175         int n2;                 /* XXX: for PRINTANDPAD */
176         char thousands_sep;     /* locale specific thousands separator */
177         char buf[BUF];          /* buffer with space for digits of uintmax_t */
178         const char *xdigs;
179         int flag;
180
181         prec = pi->prec;
182         ox[1] = '\0';
183         sign = pi->showsign;
184         flag = 0;
185         ret = 0;
186
187         thousands_sep = *(localeconv()->thousands_sep);
188         grouping = NULL;
189         if (pi->alt)
190                 grouping = localeconv()->grouping;
191         decimal_point = localeconv()->decimal_point;
192         dprec = -1;
193
194         switch(pi->spec) {
195         case 'a':
196         case 'A':
197                 if (pi->spec == 'a') {
198                         ox[1] = 'x';
199                         xdigs = __lowercase_hex;
200                         expchar = 'p';
201                 } else {
202                         ox[1] = 'X';
203                         xdigs = __uppercase_hex;
204                         expchar = 'P';
205                 }
206                 if (prec >= 0)
207                         prec++;
208                 if (pi->is_long_double) {
209                         ld = *((long double *)arg[0]);
210                         dtoaresult = cp =
211                             __hldtoa(ld, xdigs, prec,
212                             &expt, &signflag, &dtoaend);
213                 } else {
214                         d = *((double *)arg[0]);
215                         dtoaresult = cp =
216                             __hdtoa(d, xdigs, prec,
217                             &expt, &signflag, &dtoaend);
218                 }
219                 if (prec < 0)
220                         prec = dtoaend - cp;
221                 if (expt == INT_MAX)
222                         ox[1] = '\0';
223                 goto fp_common;
224         case 'e':
225         case 'E':
226                 expchar = pi->spec;
227                 if (prec < 0)   /* account for digit before decpt */
228                         prec = DEFPREC + 1;
229                 else
230                         prec++;
231                 break;
232         case 'f':
233         case 'F':
234                 expchar = '\0';
235                 break;
236         case 'g':
237         case 'G':
238                 expchar = pi->spec - ('g' - 'e');
239                 if (prec == 0)
240                         prec = 1;
241                 break;
242         default:
243                 assert(pi->spec == 'f');
244         }
245
246         if (prec < 0)
247                 prec = DEFPREC;
248         if (pi->is_long_double) {
249                 ld = *((long double *)arg[0]);
250                 dtoaresult = cp =
251                     __ldtoa(&ld, expchar ? 2 : 3, prec,
252                     &expt, &signflag, &dtoaend);
253         } else {
254                 d = *((double *)arg[0]);
255                 dtoaresult = cp =
256                     dtoa(d, expchar ? 2 : 3, prec,
257                     &expt, &signflag, &dtoaend);
258                 if (expt == 9999)
259                         expt = INT_MAX;
260         }
261 fp_common:
262         if (signflag)
263                 sign = '-';
264         if (expt == INT_MAX) {  /* inf or nan */
265                 if (*cp == 'N') {
266                         cp = (pi->spec >= 'a') ? "nan" : "NAN";
267                         sign = '\0';
268                 } else
269                         cp = (pi->spec >= 'a') ? "inf" : "INF";
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                         size += nseps + nrepeats;
323                 } else
324                         lead = expt;
325         }
326
327 here:
328         /*
329          * All reasonable formats wind up here.  At this point, `cp'
330          * points to a string which (if not flags&LADJUST) should be
331          * padded out to `width' places.  If flags&ZEROPAD, it should
332          * first be prefixed by any sign or other prefix; otherwise,
333          * it should be blank padded before the prefix is emitted.
334          * After any left-hand padding and prefixing, emit zeroes
335          * required by a decimal [diouxX] precision, then print the
336          * string proper, then emit zeroes required by any leftover
337          * floating precision; finally, if LADJUST, pad with blanks.
338          *
339          * Compute actual size, so we know how much to pad.
340          * size excludes decimal prec; realsz includes it.
341          */
342         realsz = dprec > size ? dprec : size;
343         if (sign)
344                 realsz++;
345         if (ox[1])
346                 realsz += 2;
347
348         /* right-adjusting blank padding */
349         if (pi->pad != '0' && pi->left == 0)
350                 ret += __printf_pad(io, pi->width - realsz, 0);
351
352         /* prefix */
353         if (sign)
354                 ret += __printf_puts(io, &sign, 1);
355
356         if (ox[1]) {    /* ox[1] is either x, X, or \0 */
357                 ox[0] = '0';
358                 ret += __printf_puts(io, ox, 2);
359         }
360
361         /* right-adjusting zero padding */
362         if (pi->pad == '0' && pi->left == 0)
363                 ret += __printf_pad(io, pi->width - realsz, 1);
364
365         /* leading zeroes from decimal precision */
366         ret += __printf_pad(io, dprec - size, 1);
367
368         if (flag)
369                 ret += __printf_puts(io, cp, size);
370         else {
371                 /* glue together f_p fragments */
372                 if (!expchar) { /* %[fF] or sufficiently short %[gG] */
373                         if (expt <= 0) {
374                                 ret += __printf_puts(io, "0", 1);
375                                 if (prec || pi->alt)
376                                         ret += __printf_puts(io, decimal_point, 1);
377                                 ret += __printf_pad(io, -expt, 1);
378                                 /* already handled initial 0's */
379                                 prec += expt;
380                         } else {
381                                 PRINTANDPAD(cp, dtoaend, lead, 1);
382                                 cp += lead;
383                                 if (grouping) {
384                                         while (nseps>0 || nrepeats>0) {
385                                                 if (nrepeats > 0)
386                                                         nrepeats--;
387                                                 else {
388                                                         grouping--;
389                                                         nseps--;
390                                                 }
391                                                 ret += __printf_puts(io, &thousands_sep, 1);
392                                                 PRINTANDPAD(cp,dtoaend,
393                                                     *grouping, 1);
394                                                 cp += *grouping;
395                                         }
396                                         if (cp > dtoaend)
397                                                 cp = dtoaend;
398                                 }
399                                 if (prec || pi->alt)
400                                         ret += __printf_puts(io, decimal_point,1);
401                         }
402                         PRINTANDPAD(cp, dtoaend, prec, 1);
403                 } else {        /* %[eE] or sufficiently long %[gG] */
404                         if (prec > 1 || pi->alt) {
405                                 buf[0] = *cp++;
406                                 buf[1] = *decimal_point;
407                                 ret += __printf_puts(io, buf, 2);
408                                 ret += __printf_puts(io, cp, ndig-1);
409                                 ret += __printf_pad(io, prec - ndig, 1);
410                         } else  /* XeYYY */
411                                 ret += __printf_puts(io, cp, 1);
412                         ret += __printf_puts(io, expstr, expsize);
413                 }
414         }
415         /* left-adjusting padding (always blank) */
416         if (pi->left)
417                 ret += __printf_pad(io, pi->width - realsz, 0);
418
419         __printf_flush(io);
420         if (dtoaresult != NULL)
421                 freedtoa(dtoaresult);
422
423         return (ret);
424 }