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