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
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
exponent(char * p0,int expo,int fmtch)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
__printf_arginfo_float(const struct printf_info * pi,size_t n,int * argt)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
__printf_render_float(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)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 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 size = 3;
269 flag = 1;
270 goto here;
271 }
272 ndig = dtoaend - cp;
273 if (pi->spec == 'g' || pi->spec == 'G') {
274 if (expt > -4 && expt <= prec) {
275 /* Make %[gG] smell like %[fF] */
276 expchar = '\0';
277 if (pi->alt)
278 prec -= expt;
279 else
280 prec = ndig - expt;
281 if (prec < 0)
282 prec = 0;
283 } else {
284 /*
285 * Make %[gG] smell like %[eE], but
286 * trim trailing zeroes if no # flag.
287 */
288 if (!pi->alt)
289 prec = ndig;
290 }
291 }
292 if (expchar) {
293 expsize = exponent(expstr, expt - 1, expchar);
294 size = expsize + prec;
295 if (prec > 1 || pi->alt)
296 ++size;
297 } else {
298 /* space for digits before decimal point */
299 if (expt > 0)
300 size = expt;
301 else /* "0" */
302 size = 1;
303 /* space for decimal pt and following digits */
304 if (prec || pi->alt)
305 size += prec + 1;
306 if (grouping && expt > 0) {
307 /* space for thousands' grouping */
308 nseps = nrepeats = 0;
309 lead = expt;
310 while (*grouping != CHAR_MAX) {
311 if (lead <= *grouping)
312 break;
313 lead -= *grouping;
314 if (*(grouping+1)) {
315 nseps++;
316 grouping++;
317 } else
318 nrepeats++;
319 }
320 size += nseps + nrepeats;
321 } else
322 lead = expt;
323 }
324
325 here:
326 /*
327 * All reasonable formats wind up here. At this point, `cp'
328 * points to a string which (if not flags&LADJUST) should be
329 * padded out to `width' places. If flags&ZEROPAD, it should
330 * first be prefixed by any sign or other prefix; otherwise,
331 * it should be blank padded before the prefix is emitted.
332 * After any left-hand padding and prefixing, emit zeroes
333 * required by a decimal [diouxX] precision, then print the
334 * string proper, then emit zeroes required by any leftover
335 * floating precision; finally, if LADJUST, pad with blanks.
336 *
337 * Compute actual size, so we know how much to pad.
338 * size excludes decimal prec; realsz includes it.
339 */
340 realsz = dprec > size ? dprec : size;
341 if (sign)
342 realsz++;
343 if (ox[1])
344 realsz += 2;
345
346 /* right-adjusting blank padding */
347 if (pi->pad != '0' && pi->left == 0)
348 ret += __printf_pad(io, pi->width - realsz, 0);
349
350 /* prefix */
351 if (sign)
352 ret += __printf_puts(io, &sign, 1);
353
354 if (ox[1]) { /* ox[1] is either x, X, or \0 */
355 ox[0] = '0';
356 ret += __printf_puts(io, ox, 2);
357 }
358
359 /* right-adjusting zero padding */
360 if (pi->pad == '0' && pi->left == 0)
361 ret += __printf_pad(io, pi->width - realsz, 1);
362
363 /* leading zeroes from decimal precision */
364 ret += __printf_pad(io, dprec - size, 1);
365
366 if (flag)
367 ret += __printf_puts(io, cp, size);
368 else {
369 /* glue together f_p fragments */
370 if (!expchar) { /* %[fF] or sufficiently short %[gG] */
371 if (expt <= 0) {
372 ret += __printf_puts(io, "0", 1);
373 if (prec || pi->alt)
374 ret += __printf_puts(io, decimal_point, 1);
375 ret += __printf_pad(io, -expt, 1);
376 /* already handled initial 0's */
377 prec += expt;
378 } else {
379 PRINTANDPAD(cp, dtoaend, lead, 1);
380 cp += lead;
381 if (grouping) {
382 while (nseps>0 || nrepeats>0) {
383 if (nrepeats > 0)
384 nrepeats--;
385 else {
386 grouping--;
387 nseps--;
388 }
389 ret += __printf_puts(io, &thousands_sep, 1);
390 PRINTANDPAD(cp,dtoaend,
391 *grouping, 1);
392 cp += *grouping;
393 }
394 if (cp > dtoaend)
395 cp = dtoaend;
396 }
397 if (prec || pi->alt)
398 ret += __printf_puts(io, decimal_point,1);
399 }
400 PRINTANDPAD(cp, dtoaend, prec, 1);
401 } else { /* %[eE] or sufficiently long %[gG] */
402 if (prec > 1 || pi->alt) {
403 buf[0] = *cp++;
404 buf[1] = *decimal_point;
405 ret += __printf_puts(io, buf, 2);
406 ret += __printf_puts(io, cp, ndig-1);
407 ret += __printf_pad(io, prec - ndig, 1);
408 } else /* XeYYY */
409 ret += __printf_puts(io, cp, 1);
410 ret += __printf_puts(io, expstr, expsize);
411 }
412 }
413 /* left-adjusting padding (always blank) */
414 if (pi->left)
415 ret += __printf_pad(io, pi->width - realsz, 0);
416
417 __printf_flush(io);
418 if (dtoaresult != NULL)
419 freedtoa(dtoaresult);
420
421 return (ret);
422 }
423