xprintf_float.c revision 331722
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: stable/11/lib/libc/stdio/xprintf_float.c 331722 2018-03-29 02:50:57Z eadler $
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
83static int
84exponent(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
122int
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
147int
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	}
259fp_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
325here:
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