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
85static int
86exponent(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
124int
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
149int
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	}
261fp_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
327here:
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