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
exponent(char * p0,int expo,int fmtch)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
__printf_arginfo_float(const struct printf_info * pi,size_t n,int * argt)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
__printf_render_float(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)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 }
425