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: src/lib/libc/stdio/xprintf_float.c,v 1.1 2005/12/16 18:56:38 phk Exp $
34 */
35
36#include <namespace.h>
37#include "xlocale_private.h"
38#include <stdio.h>
39#include <wchar.h>
40#include <assert.h>
41#include <locale.h>
42#include <limits.h>
43
44#define	dtoa		__dtoa
45#define	freedtoa	__freedtoa
46
47#include <float.h>
48#include <math.h>
49#include "gdtoa.h"
50#include "floatio.h"
51#include "printf.h"
52#include "xprintf_private.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
83extern const char *__fix_nogrouping(const char *str);
84
85#define	to_char(n)	((n) + '0')
86
87static int
88exponent(char *p0, int expo, int fmtch)
89{
90	char *p, *t;
91	char expbuf[MAXEXPDIG];
92
93	p = p0;
94	*p++ = fmtch;
95	if (expo < 0) {
96		expo = -expo;
97		*p++ = '-';
98	}
99	else
100		*p++ = '+';
101	t = expbuf + MAXEXPDIG;
102	if (expo > 9) {
103		do {
104			*--t = to_char(expo % 10);
105		} while ((expo /= 10) > 9);
106		*--t = to_char(expo);
107		for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
108			;
109	}
110	else {
111		/*
112		 * Exponents for decimal floating point conversions
113		 * (%[eEgG]) must be at least two characters long,
114		 * whereas exponents for hexadecimal conversions can
115		 * be only one character long.
116		 */
117		if (fmtch == 'e' || fmtch == 'E')
118			*p++ = '0';
119		*p++ = to_char(expo);
120	}
121	return (p - p0);
122}
123
124/* 'f' ---------------------------------------------------------------*/
125
126__private_extern__ int
127__printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt)
128{
129	assert (n > 0);
130#ifdef VECTORS
131	if (pi->is_vec)
132		argt[0] = PA_VECTOR;
133	else {
134#endif /* VECTORS */
135	argt[0] = PA_DOUBLE;
136	if (pi->is_long_double)
137		argt[0] |= PA_FLAG_LONG_DOUBLE;
138#ifdef VECTORS
139	}
140#endif /* VECTORS */
141	return (1);
142}
143
144/*
145 * We can decompose the printed representation of floating
146 * point numbers into several parts, some of which may be empty:
147 *
148 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
149 *    A       B     ---C---      D       E   F
150 *
151 * A:	'sign' holds this value if present; '\0' otherwise
152 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
153 * C:	cp points to the string MMMNNN.  Leading and trailing
154 *	zeros are not in the string and must be added.
155 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
156 * F:	at least two digits for decimal, at least one digit for hex
157 */
158
159__private_extern__ int
160__printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
161{
162	int prec;		/* precision from format; <0 for N/A */
163	char *dtoaresult;	/* buffer allocated by dtoa */
164	char expchar;		/* exponent character: [eEpP\0] */
165	char *cp;
166	int expt;		/* integer value of exponent */
167	int signflag;		/* true if float is negative */
168	char *dtoaend;		/* pointer to end of converted digits */
169	char sign;		/* sign prefix (' ', '+', '-', or \0) */
170	int size;		/* size of converted field or string */
171	int ndig;		/* actual number of digits returned by dtoa */
172	int expsize;		/* character count for expstr */
173	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
174	int nseps;		/* number of group separators with ' */
175	int nrepeats;		/* number of repeats of the last group */
176	const char *grouping;	/* locale specific numeric grouping rules */
177	int lead;		/* sig figs before decimal or group sep */
178	long double ld;
179	double d;
180	int realsz;		/* field size expanded by dprec, sign, etc */
181	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
182	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
183	int prsize;             /* max size of printed field */
184	int ret;		/* return value accumulator */
185	const char *decimal_point;	/* locale specific decimal point */
186	int decimal_point_len;	/* length of locale specific decimal point */
187	int n2;			/* XXX: for PRINTANDPAD */
188	const char *thousands_sep;	/* locale specific thousands separator */
189	int thousands_sep_len;	/* length of locale specific thousands separator */
190	char buf[BUF];		/* buffer with space for digits of uintmax_t */
191	const char *xdigs;
192	int flag;
193
194#ifdef VECTORS
195	if (pi->is_vec) return __xprintf_vector(io, pi, arg);
196#endif /* VECTORS */
197
198	prec = pi->prec;
199	ox[1] = '\0';
200	sign = pi->signchar;
201	flag = 0;
202	ret = 0;
203
204	thousands_sep = localeconv_l(pi->loc)->thousands_sep;
205	thousands_sep_len = strlen(thousands_sep);
206	grouping = NULL;
207	if (pi->group)
208		grouping = __fix_nogrouping(localeconv_l(pi->loc)->grouping);
209	decimal_point = localeconv_l(pi->loc)->decimal_point;
210	decimal_point_len = strlen(decimal_point);
211	dprec = -1;
212
213	switch(pi->spec) {
214	case 'a':
215	case 'A':
216		if (pi->spec == 'a') {
217			ox[1] = 'x';
218			xdigs = __lowercase_hex;
219			expchar = 'p';
220		} else {
221			ox[1] = 'X';
222			xdigs = __uppercase_hex;
223			expchar = 'P';
224		}
225		if (prec >= 0)
226			prec++;
227		if (pi->is_long_double) {
228			ld = *((long double *)arg[0]);
229			dtoaresult = cp =
230			    __hldtoa(ld, xdigs, prec,
231			    &expt, &signflag, &dtoaend);
232		} else {
233			d = *((double *)arg[0]);
234			dtoaresult = cp =
235			    __hdtoa(d, xdigs, prec,
236			    &expt, &signflag, &dtoaend);
237		}
238		if (prec < 0)
239			prec = dtoaend - cp;
240		if (expt == INT_MAX)
241			ox[1] = '\0';
242		goto fp_common;
243	case 'e':
244	case 'E':
245		expchar = pi->spec;
246		if (prec < 0)	/* account for digit before decpt */
247			prec = DEFPREC + 1;
248		else
249			prec++;
250		break;
251	case 'f':
252	case 'F':
253		expchar = '\0';
254		break;
255	case 'g':
256	case 'G':
257		expchar = pi->spec - ('g' - 'e');
258		if (prec == 0)
259			prec = 1;
260		break;
261	default:
262		assert(pi->spec == 'f');
263	}
264
265	if (prec < 0)
266		prec = DEFPREC;
267	if (pi->is_long_double) {
268		ld = *((long double *)arg[0]);
269		dtoaresult = cp =
270		    __ldtoa(&ld, expchar ? 2 : 3, prec,
271		    &expt, &signflag, &dtoaend);
272	} else {
273		d = *((double *)arg[0]);
274		dtoaresult = cp =
275		    dtoa(d, expchar ? 2 : 3, prec,
276		    &expt, &signflag, &dtoaend);
277		if (expt == 9999)
278			expt = INT_MAX;
279	}
280fp_common:
281	if (signflag)
282		sign = '-';
283	if (expt == INT_MAX) {	/* inf or nan */
284		if (*cp == 'N') {
285			cp = (pi->spec >= 'a') ? "nan" : "NAN";
286			sign = '\0';
287		} else
288			cp = (pi->spec >= 'a') ? "inf" : "INF";
289		size = 3;
290		flag = 1;
291		goto here;
292	}
293	ndig = dtoaend - cp;
294	if (pi->spec == 'g' || pi->spec == 'G') {
295		if (expt > -4 && expt <= prec) {
296			/* Make %[gG] smell like %[fF] */
297			expchar = '\0';
298			if (pi->alt)
299				prec -= expt;
300			else
301				prec = ndig - expt;
302			if (prec < 0)
303				prec = 0;
304		} else {
305			/*
306			 * Make %[gG] smell like %[eE], but
307			 * trim trailing zeroes if no # flag.
308			 */
309			if (!pi->alt)
310				prec = ndig;
311		}
312	}
313	if (expchar) {
314		expsize = exponent(expstr, expt - 1, expchar);
315		size = expsize + prec;
316		if (prec > 1 || pi->alt)
317			++size;
318	} else {
319		/* space for digits before decimal point */
320		if (expt > 0)
321			size = expt;
322		else	/* "0" */
323			size = 1;
324		/* space for decimal pt and following digits */
325		if (prec || pi->alt)
326			size += prec + 1;
327		if (grouping && expt > 0) {
328			/* space for thousands' grouping */
329			nseps = nrepeats = 0;
330			lead = expt;
331			while (*grouping != CHAR_MAX) {
332				if (lead <= *grouping)
333					break;
334				lead -= *grouping;
335				if (*(grouping+1)) {
336					nseps++;
337					grouping++;
338				} else
339					nrepeats++;
340			}
341			size += nseps + nrepeats;
342		} else
343			lead = expt;
344	}
345
346here:
347	/*
348	 * All reasonable formats wind up here.  At this point, `cp'
349	 * points to a string which (if not flags&LADJUST) should be
350	 * padded out to `width' places.  If flags&ZEROPAD, it should
351	 * first be prefixed by any sign or other prefix; otherwise,
352	 * it should be blank padded before the prefix is emitted.
353	 * After any left-hand padding and prefixing, emit zeroes
354	 * required by a decimal [diouxX] precision, then print the
355	 * string proper, then emit zeroes required by any leftover
356	 * floating precision; finally, if LADJUST, pad with blanks.
357	 *
358	 * Compute actual size, so we know how much to pad.
359	 * size excludes decimal prec; realsz includes it.
360	 */
361	realsz = dprec > size ? dprec : size;
362	if (sign)
363		realsz++;
364	if (ox[1])
365		realsz += 2;
366
367	prsize = pi->width > realsz ? pi->width : realsz;
368
369	/* right-adjusting blank padding */
370	if (pi->pad != '0' && pi->left == 0)
371		ret += __printf_pad(io, pi->width - realsz, 0);
372
373	/* prefix */
374	if (sign)
375		ret += __printf_puts(io, &sign, 1);
376
377	if (ox[1]) {	/* ox[1] is either x, X, or \0 */
378		ox[0] = '0';
379		ret += __printf_puts(io, ox, 2);
380	}
381
382	/* right-adjusting zero padding */
383	if (pi->pad == '0' && pi->left == 0)
384		ret += __printf_pad(io, pi->width - realsz, 1);
385
386	/* leading zeroes from decimal precision */
387	ret += __printf_pad(io, dprec - size, 1);
388
389	if (flag)
390		ret += __printf_puts(io, cp, size);
391	else {
392		/* glue together f_p fragments */
393		if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
394			if (expt <= 0) {
395				ret += __printf_puts(io, "0", 1);
396				if (prec || pi->alt)
397					ret += __printf_puts(io, decimal_point, decimal_point_len);
398				ret += __printf_pad(io, -expt, 1);
399				/* already handled initial 0's */
400				prec += expt;
401			} else {
402				PRINTANDPAD(cp, dtoaend, lead, 1);
403				cp += lead;
404				if (grouping) {
405					while (nseps>0 || nrepeats>0) {
406						if (nrepeats > 0)
407							nrepeats--;
408						else {
409							grouping--;
410							nseps--;
411						}
412						ret += __printf_puts(io, thousands_sep, thousands_sep_len);
413						PRINTANDPAD(cp,dtoaend,
414						    *grouping, 1);
415						cp += *grouping;
416					}
417					if (cp > dtoaend)
418						cp = dtoaend;
419				}
420				if (prec || pi->alt)
421					ret += __printf_puts(io, decimal_point, decimal_point_len);
422			}
423			PRINTANDPAD(cp, dtoaend, prec, 1);
424		} else {	/* %[eE] or sufficiently long %[gG] */
425			if (prec > 1 || pi->alt) {
426				buf[0] = *cp++;
427				memcpy(buf + 1, decimal_point, decimal_point_len);
428				ret += __printf_puts(io, buf, decimal_point_len + 1);
429				ret += __printf_puts(io, cp, ndig-1);
430				ret += __printf_pad(io, prec - ndig, 1);
431			} else	/* XeYYY */
432				ret += __printf_puts(io, cp, 1);
433			ret += __printf_puts(io, expstr, expsize);
434		}
435	}
436	/* left-adjusting padding (always blank) */
437	if (pi->left)
438		ret += __printf_pad(io, pi->width - realsz, 0);
439
440	__printf_flush(io);
441	if (dtoaresult != NULL)
442		freedtoa(dtoaresult);
443
444	return (ret);
445}
446