xref: /dragonfly/lib/libc/stdio/xprintf_float.c (revision cf515c3a)
1*e0f95098SPeter Avalos /*-
2*e0f95098SPeter Avalos  * Copyright (c) 2005 Poul-Henning Kamp
3*e0f95098SPeter Avalos  * Copyright (c) 1990, 1993
4*e0f95098SPeter Avalos  *	The Regents of the University of California.  All rights reserved.
5*e0f95098SPeter Avalos  *
6*e0f95098SPeter Avalos  * This code is derived from software contributed to Berkeley by
7*e0f95098SPeter Avalos  * Chris Torek.
8*e0f95098SPeter Avalos  *
9*e0f95098SPeter Avalos  * Redistribution and use in source and binary forms, with or without
10*e0f95098SPeter Avalos  * modification, are permitted provided that the following conditions
11*e0f95098SPeter Avalos  * are met:
12*e0f95098SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
13*e0f95098SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
14*e0f95098SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
15*e0f95098SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
16*e0f95098SPeter Avalos  *    documentation and/or other materials provided with the distribution.
17*e0f95098SPeter Avalos  * 3. Neither the name of the University nor the names of its contributors
18*e0f95098SPeter Avalos  *    may be used to endorse or promote products derived from this software
19*e0f95098SPeter Avalos  *    without specific prior written permission.
20*e0f95098SPeter Avalos  *
21*e0f95098SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22*e0f95098SPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23*e0f95098SPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24*e0f95098SPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25*e0f95098SPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26*e0f95098SPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27*e0f95098SPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28*e0f95098SPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29*e0f95098SPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30*e0f95098SPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*e0f95098SPeter Avalos  * SUCH DAMAGE.
32*e0f95098SPeter Avalos  *
33*e0f95098SPeter Avalos  * $FreeBSD: src/lib/libc/stdio/xprintf_float.c,v 1.1 2005/12/16 18:56:38 phk Exp $
34*e0f95098SPeter Avalos  */
35*e0f95098SPeter Avalos 
36*e0f95098SPeter Avalos #include "namespace.h"
37*e0f95098SPeter Avalos #include <stdio.h>
38*e0f95098SPeter Avalos #include <wchar.h>
39*e0f95098SPeter Avalos #include <assert.h>
40*e0f95098SPeter Avalos #include <locale.h>
41*e0f95098SPeter Avalos #include <limits.h>
42*e0f95098SPeter Avalos 
43*e0f95098SPeter Avalos #define	dtoa		__dtoa
44*e0f95098SPeter Avalos #define	freedtoa	__freedtoa
45*e0f95098SPeter Avalos 
46*e0f95098SPeter Avalos #include <float.h>
47*e0f95098SPeter Avalos #include <math.h>
48*e0f95098SPeter Avalos #include "un-namespace.h"
49*e0f95098SPeter Avalos #include "gdtoa.h"
50*e0f95098SPeter Avalos #include "floatio.h"
51*e0f95098SPeter Avalos #include "printf.h"
52*e0f95098SPeter Avalos 
53*e0f95098SPeter Avalos /*
54*e0f95098SPeter Avalos  * The size of the buffer we use as scratch space for integer
55*e0f95098SPeter Avalos  * conversions, among other things.  Technically, we would need the
56*e0f95098SPeter Avalos  * most space for base 10 conversions with thousands' grouping
57*e0f95098SPeter Avalos  * characters between each pair of digits.  100 bytes is a
58*e0f95098SPeter Avalos  * conservative overestimate even for a 128-bit uintmax_t.
59*e0f95098SPeter Avalos  */
60*e0f95098SPeter Avalos #define	BUF	100
61*e0f95098SPeter Avalos 
62*e0f95098SPeter Avalos #define	DEFPREC		6	/* Default FP precision */
63*e0f95098SPeter Avalos 
64*e0f95098SPeter Avalos 
65*e0f95098SPeter Avalos /* various globals ---------------------------------------------------*/
66*e0f95098SPeter Avalos 
67*e0f95098SPeter Avalos 
68*e0f95098SPeter Avalos /* padding function---------------------------------------------------*/
69*e0f95098SPeter Avalos 
70*e0f95098SPeter Avalos #define	PRINTANDPAD(p, ep, len, with) do {		\
71*e0f95098SPeter Avalos 	n2 = (ep) - (p);       				\
72*e0f95098SPeter Avalos 	if (n2 > (len))					\
73*e0f95098SPeter Avalos 		n2 = (len);				\
74*e0f95098SPeter Avalos 	if (n2 > 0)					\
75*e0f95098SPeter Avalos 		ret += __printf_puts(io, (p), n2);		\
76*e0f95098SPeter Avalos 	ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with));	\
77*e0f95098SPeter Avalos } while(0)
78*e0f95098SPeter Avalos 
79*e0f95098SPeter Avalos /* misc --------------------------------------------------------------*/
80*e0f95098SPeter Avalos 
81*e0f95098SPeter Avalos #define	to_char(n)	((n) + '0')
82*e0f95098SPeter Avalos 
83*e0f95098SPeter Avalos static int
exponent(char * p0,int expo,int fmtch)84*e0f95098SPeter Avalos exponent(char *p0, int expo, int fmtch)
85*e0f95098SPeter Avalos {
86*e0f95098SPeter Avalos 	char *p, *t;
87*e0f95098SPeter Avalos 	char expbuf[MAXEXPDIG];
88*e0f95098SPeter Avalos 
89*e0f95098SPeter Avalos 	p = p0;
90*e0f95098SPeter Avalos 	*p++ = fmtch;
91*e0f95098SPeter Avalos 	if (expo < 0) {
92*e0f95098SPeter Avalos 		expo = -expo;
93*e0f95098SPeter Avalos 		*p++ = '-';
94*e0f95098SPeter Avalos 	} else {
95*e0f95098SPeter Avalos 		*p++ = '+';
96*e0f95098SPeter Avalos 	}
97*e0f95098SPeter Avalos 	t = expbuf + MAXEXPDIG;
98*e0f95098SPeter Avalos 	if (expo > 9) {
99*e0f95098SPeter Avalos 		do {
100*e0f95098SPeter Avalos 			*--t = to_char(expo % 10);
101*e0f95098SPeter Avalos 		} while ((expo /= 10) > 9);
102*e0f95098SPeter Avalos 		*--t = to_char(expo);
103*e0f95098SPeter Avalos 		for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
104*e0f95098SPeter Avalos 			;
105*e0f95098SPeter Avalos 	} else {
106*e0f95098SPeter Avalos 		/*
107*e0f95098SPeter Avalos 		 * Exponents for decimal floating point conversions
108*e0f95098SPeter Avalos 		 * (%[eEgG]) must be at least two characters long,
109*e0f95098SPeter Avalos 		 * whereas exponents for hexadecimal conversions can
110*e0f95098SPeter Avalos 		 * be only one character long.
111*e0f95098SPeter Avalos 		 */
112*e0f95098SPeter Avalos 		if (fmtch == 'e' || fmtch == 'E')
113*e0f95098SPeter Avalos 			*p++ = '0';
114*e0f95098SPeter Avalos 		*p++ = to_char(expo);
115*e0f95098SPeter Avalos 	}
116*e0f95098SPeter Avalos 	return (p - p0);
117*e0f95098SPeter Avalos }
118*e0f95098SPeter Avalos 
119*e0f95098SPeter Avalos /* 'f' ---------------------------------------------------------------*/
120*e0f95098SPeter Avalos 
121*e0f95098SPeter Avalos int
__printf_arginfo_float(const struct printf_info * pi,size_t n,int * argt)122*e0f95098SPeter Avalos __printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt)
123*e0f95098SPeter Avalos {
124*e0f95098SPeter Avalos 	assert (n > 0);
125*e0f95098SPeter Avalos 	argt[0] = PA_DOUBLE;
126*e0f95098SPeter Avalos 	if (pi->is_long_double)
127*e0f95098SPeter Avalos 		argt[0] |= PA_FLAG_LONG_DOUBLE;
128*e0f95098SPeter Avalos 	return (1);
129*e0f95098SPeter Avalos }
130*e0f95098SPeter Avalos 
131*e0f95098SPeter Avalos /*
132*e0f95098SPeter Avalos  * We can decompose the printed representation of floating
133*e0f95098SPeter Avalos  * point numbers into several parts, some of which may be empty:
134*e0f95098SPeter Avalos  *
135*e0f95098SPeter Avalos  * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
136*e0f95098SPeter Avalos  *    A       B     ---C---      D       E   F
137*e0f95098SPeter Avalos  *
138*e0f95098SPeter Avalos  * A:	'sign' holds this value if present; '\0' otherwise
139*e0f95098SPeter Avalos  * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
140*e0f95098SPeter Avalos  * C:	cp points to the string MMMNNN.  Leading and trailing
141*e0f95098SPeter Avalos  *	zeroes are not in the string and must be added.
142*e0f95098SPeter Avalos  * D:	expchar holds this character; '\0' if no exponent, e.g. %f
143*e0f95098SPeter Avalos  * F:	at least two digits for decimal, at least one digit for hex
144*e0f95098SPeter Avalos  */
145*e0f95098SPeter Avalos 
146*e0f95098SPeter Avalos int
__printf_render_float(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)147*e0f95098SPeter Avalos __printf_render_float(struct __printf_io *io, const struct printf_info *pi,
148*e0f95098SPeter Avalos 		      const void *const *arg)
149*e0f95098SPeter Avalos {
150*e0f95098SPeter Avalos 	int prec;		/* precision from format; <0 for N/A */
151*e0f95098SPeter Avalos 	char *dtoaresult;	/* buffer allocated by dtoa */
152*e0f95098SPeter Avalos 	char expchar;		/* exponent character: [eEpP\0] */
153*e0f95098SPeter Avalos 	char *cp;
154*e0f95098SPeter Avalos 	int expt;		/* integer value of exponent */
155*e0f95098SPeter Avalos 	int signflag;		/* true if float is negative */
156*e0f95098SPeter Avalos 	char *dtoaend;		/* pointer to end of converted digits */
157*e0f95098SPeter Avalos 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
158*e0f95098SPeter Avalos 	int size;		/* size of converted field or string */
159*e0f95098SPeter Avalos 	int ndig;		/* actual number of digits returned by dtoa */
160*e0f95098SPeter Avalos 	int expsize;		/* character count for expstr */
161*e0f95098SPeter Avalos 	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
162*e0f95098SPeter Avalos 	int nseps;		/* number of group separators with ' */
163*e0f95098SPeter Avalos 	int nrepeats;		/* number of repeats of the last group */
164*e0f95098SPeter Avalos 	const char *grouping;	/* locale specific numeric grouping rules */
165*e0f95098SPeter Avalos 	int lead;		/* sig figs before decimal or group sep */
166*e0f95098SPeter Avalos 	long double ld;
167*e0f95098SPeter Avalos 	double d;
168*e0f95098SPeter Avalos 	int realsz;		/* field size expanded by dprec, sign, etc */
169*e0f95098SPeter Avalos 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
170*e0f95098SPeter Avalos 	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
171*e0f95098SPeter Avalos 	int ret;		/* return value accumulator */
172*e0f95098SPeter Avalos 	char *decimal_point;	/* locale specific decimal point */
173*e0f95098SPeter Avalos 	int n2;			/* XXX: for PRINTANDPAD */
174*e0f95098SPeter Avalos 	char thousands_sep;	/* locale specific thousands separator */
175*e0f95098SPeter Avalos 	char buf[BUF];		/* buffer with space for digits of uintmax_t */
176*e0f95098SPeter Avalos 	const char *xdigs;
177*e0f95098SPeter Avalos 	int flag;
178*e0f95098SPeter Avalos 
179*e0f95098SPeter Avalos 	prec = pi->prec;
180*e0f95098SPeter Avalos 	ox[1] = '\0';
181*e0f95098SPeter Avalos 	sign = pi->showsign;
182*e0f95098SPeter Avalos 	flag = 0;
183*e0f95098SPeter Avalos 	ret = 0;
184*e0f95098SPeter Avalos 
185*e0f95098SPeter Avalos 	thousands_sep = *(localeconv()->thousands_sep);
186*e0f95098SPeter Avalos 	grouping = NULL;
187*e0f95098SPeter Avalos 	if (pi->alt)
188*e0f95098SPeter Avalos 		grouping = localeconv()->grouping;
189*e0f95098SPeter Avalos 	decimal_point = localeconv()->decimal_point;
190*e0f95098SPeter Avalos 	dprec = -1;
191*e0f95098SPeter Avalos 
192*e0f95098SPeter Avalos 	switch(pi->spec) {
193*e0f95098SPeter Avalos 	case 'a':
194*e0f95098SPeter Avalos 	case 'A':
195*e0f95098SPeter Avalos 		if (pi->spec == 'a') {
196*e0f95098SPeter Avalos 			ox[1] = 'x';
197*e0f95098SPeter Avalos 			xdigs = __lowercase_hex;
198*e0f95098SPeter Avalos 			expchar = 'p';
199*e0f95098SPeter Avalos 		} else {
200*e0f95098SPeter Avalos 			ox[1] = 'X';
201*e0f95098SPeter Avalos 			xdigs = __uppercase_hex;
202*e0f95098SPeter Avalos 			expchar = 'P';
203*e0f95098SPeter Avalos 		}
204*e0f95098SPeter Avalos 		if (prec >= 0)
205*e0f95098SPeter Avalos 			prec++;
206*e0f95098SPeter Avalos 		if (pi->is_long_double) {
207*e0f95098SPeter Avalos 			ld = *((long double *)arg[0]);
208*e0f95098SPeter Avalos 			dtoaresult = cp =
209*e0f95098SPeter Avalos 			    __hldtoa(ld, xdigs, prec,
210*e0f95098SPeter Avalos 			    &expt, &signflag, &dtoaend);
211*e0f95098SPeter Avalos 		} else {
212*e0f95098SPeter Avalos 			d = *((double *)arg[0]);
213*e0f95098SPeter Avalos 			dtoaresult = cp =
214*e0f95098SPeter Avalos 			    __hdtoa(d, xdigs, prec,
215*e0f95098SPeter Avalos 			    &expt, &signflag, &dtoaend);
216*e0f95098SPeter Avalos 		}
217*e0f95098SPeter Avalos 		if (prec < 0)
218*e0f95098SPeter Avalos 			prec = dtoaend - cp;
219*e0f95098SPeter Avalos 		if (expt == INT_MAX)
220*e0f95098SPeter Avalos 			ox[1] = '\0';
221*e0f95098SPeter Avalos 		goto fp_common;
222*e0f95098SPeter Avalos 	case 'e':
223*e0f95098SPeter Avalos 	case 'E':
224*e0f95098SPeter Avalos 		expchar = pi->spec;
225*e0f95098SPeter Avalos 		if (prec < 0)	/* account for digit before decpt */
226*e0f95098SPeter Avalos 			prec = DEFPREC + 1;
227*e0f95098SPeter Avalos 		else
228*e0f95098SPeter Avalos 			prec++;
229*e0f95098SPeter Avalos 		break;
230*e0f95098SPeter Avalos 	case 'f':
231*e0f95098SPeter Avalos 	case 'F':
232*e0f95098SPeter Avalos 		expchar = '\0';
233*e0f95098SPeter Avalos 		break;
234*e0f95098SPeter Avalos 	case 'g':
235*e0f95098SPeter Avalos 	case 'G':
236*e0f95098SPeter Avalos 		expchar = pi->spec - ('g' - 'e');
237*e0f95098SPeter Avalos 		if (prec == 0)
238*e0f95098SPeter Avalos 			prec = 1;
239*e0f95098SPeter Avalos 		break;
240*e0f95098SPeter Avalos 	default:
241*e0f95098SPeter Avalos 		assert(pi->spec == 'f');
242*e0f95098SPeter Avalos 	}
243*e0f95098SPeter Avalos 
244*e0f95098SPeter Avalos 	if (prec < 0)
245*e0f95098SPeter Avalos 		prec = DEFPREC;
246*e0f95098SPeter Avalos 	if (pi->is_long_double) {
247*e0f95098SPeter Avalos 		ld = *((long double *)arg[0]);
248*e0f95098SPeter Avalos 		dtoaresult = cp =
249*e0f95098SPeter Avalos 		    __ldtoa(&ld, expchar ? 2 : 3, prec,
250*e0f95098SPeter Avalos 		    &expt, &signflag, &dtoaend);
251*e0f95098SPeter Avalos 	} else {
252*e0f95098SPeter Avalos 		d = *((double *)arg[0]);
253*e0f95098SPeter Avalos 		dtoaresult = cp =
254*e0f95098SPeter Avalos 		    dtoa(d, expchar ? 2 : 3, prec,
255*e0f95098SPeter Avalos 		    &expt, &signflag, &dtoaend);
256*e0f95098SPeter Avalos 		if (expt == 9999)
257*e0f95098SPeter Avalos 			expt = INT_MAX;
258*e0f95098SPeter Avalos 	}
259*e0f95098SPeter Avalos fp_common:
260*e0f95098SPeter Avalos 	if (signflag)
261*e0f95098SPeter Avalos 		sign = '-';
262*e0f95098SPeter Avalos 	if (expt == INT_MAX) {	/* inf or nan */
263*e0f95098SPeter Avalos 		if (*cp == 'N') {
264*e0f95098SPeter Avalos 			cp = (pi->spec >= 'a') ? "nan" : "NAN";
265*e0f95098SPeter Avalos 			sign = '\0';
266*e0f95098SPeter Avalos 		} else {
267*e0f95098SPeter Avalos 			cp = (pi->spec >= 'a') ? "inf" : "INF";
268*e0f95098SPeter Avalos 		}
269*e0f95098SPeter Avalos 		size = 3;
270*e0f95098SPeter Avalos 		flag = 1;
271*e0f95098SPeter Avalos 		goto here;
272*e0f95098SPeter Avalos 	}
273*e0f95098SPeter Avalos 	ndig = dtoaend - cp;
274*e0f95098SPeter Avalos 	if (pi->spec == 'g' || pi->spec == 'G') {
275*e0f95098SPeter Avalos 		if (expt > -4 && expt <= prec) {
276*e0f95098SPeter Avalos 			/* Make %[gG] smell like %[fF] */
277*e0f95098SPeter Avalos 			expchar = '\0';
278*e0f95098SPeter Avalos 			if (pi->alt)
279*e0f95098SPeter Avalos 				prec -= expt;
280*e0f95098SPeter Avalos 			else
281*e0f95098SPeter Avalos 				prec = ndig - expt;
282*e0f95098SPeter Avalos 			if (prec < 0)
283*e0f95098SPeter Avalos 				prec = 0;
284*e0f95098SPeter Avalos 		} else {
285*e0f95098SPeter Avalos 			/*
286*e0f95098SPeter Avalos 			 * Make %[gG] smell like %[eE], but
287*e0f95098SPeter Avalos 			 * trim trailing zeroes if no # flag.
288*e0f95098SPeter Avalos 			 */
289*e0f95098SPeter Avalos 			if (!pi->alt)
290*e0f95098SPeter Avalos 				prec = ndig;
291*e0f95098SPeter Avalos 		}
292*e0f95098SPeter Avalos 	}
293*e0f95098SPeter Avalos 	if (expchar) {
294*e0f95098SPeter Avalos 		expsize = exponent(expstr, expt - 1, expchar);
295*e0f95098SPeter Avalos 		size = expsize + prec;
296*e0f95098SPeter Avalos 		if (prec > 1 || pi->alt)
297*e0f95098SPeter Avalos 			++size;
298*e0f95098SPeter Avalos 	} else {
299*e0f95098SPeter Avalos 		/* space for digits before decimal point */
300*e0f95098SPeter Avalos 		if (expt > 0)
301*e0f95098SPeter Avalos 			size = expt;
302*e0f95098SPeter Avalos 		else	/* "0" */
303*e0f95098SPeter Avalos 			size = 1;
304*e0f95098SPeter Avalos 		/* space for decimal pt and following digits */
305*e0f95098SPeter Avalos 		if (prec || pi->alt)
306*e0f95098SPeter Avalos 			size += prec + 1;
307*e0f95098SPeter Avalos 		if (grouping && expt > 0) {
308*e0f95098SPeter Avalos 			/* space for thousands' grouping */
309*e0f95098SPeter Avalos 			nseps = nrepeats = 0;
310*e0f95098SPeter Avalos 			lead = expt;
311*e0f95098SPeter Avalos 			while (*grouping != CHAR_MAX) {
312*e0f95098SPeter Avalos 				if (lead <= *grouping)
313*e0f95098SPeter Avalos 					break;
314*e0f95098SPeter Avalos 				lead -= *grouping;
315*e0f95098SPeter Avalos 				if (*(grouping+1)) {
316*e0f95098SPeter Avalos 					nseps++;
317*e0f95098SPeter Avalos 					grouping++;
318*e0f95098SPeter Avalos 				} else {
319*e0f95098SPeter Avalos 					nrepeats++;
320*e0f95098SPeter Avalos 				}
321*e0f95098SPeter Avalos 			}
322*e0f95098SPeter Avalos 			size += nseps + nrepeats;
323*e0f95098SPeter Avalos 		} else {
324*e0f95098SPeter Avalos 			lead = expt;
325*e0f95098SPeter Avalos 		}
326*e0f95098SPeter Avalos 	}
327*e0f95098SPeter Avalos 
328*e0f95098SPeter Avalos here:
329*e0f95098SPeter Avalos 	/*
330*e0f95098SPeter Avalos 	 * All reasonable formats wind up here.  At this point, `cp'
331*e0f95098SPeter Avalos 	 * points to a string which (if not flags&LADJUST) should be
332*e0f95098SPeter Avalos 	 * padded out to `width' places.  If flags&ZEROPAD, it should
333*e0f95098SPeter Avalos 	 * first be prefixed by any sign or other prefix; otherwise,
334*e0f95098SPeter Avalos 	 * it should be blank padded before the prefix is emitted.
335*e0f95098SPeter Avalos 	 * After any left-hand padding and prefixing, emit zeroes
336*e0f95098SPeter Avalos 	 * required by a decimal [diouxX] precision, then print the
337*e0f95098SPeter Avalos 	 * string proper, then emit zeroes required by any leftover
338*e0f95098SPeter Avalos 	 * floating precision; finally, if LADJUST, pad with blanks.
339*e0f95098SPeter Avalos 	 *
340*e0f95098SPeter Avalos 	 * Compute actual size, so we know how much to pad.
341*e0f95098SPeter Avalos 	 * size excludes decimal prec; realsz includes it.
342*e0f95098SPeter Avalos 	 */
343*e0f95098SPeter Avalos 	realsz = dprec > size ? dprec : size;
344*e0f95098SPeter Avalos 	if (sign)
345*e0f95098SPeter Avalos 		realsz++;
346*e0f95098SPeter Avalos 	if (ox[1])
347*e0f95098SPeter Avalos 		realsz += 2;
348*e0f95098SPeter Avalos 
349*e0f95098SPeter Avalos 	/* right-adjusting blank padding */
350*e0f95098SPeter Avalos 	if (pi->pad != '0' && pi->left == 0)
351*e0f95098SPeter Avalos 		ret += __printf_pad(io, pi->width - realsz, 0);
352*e0f95098SPeter Avalos 
353*e0f95098SPeter Avalos 	/* prefix */
354*e0f95098SPeter Avalos 	if (sign)
355*e0f95098SPeter Avalos 		ret += __printf_puts(io, &sign, 1);
356*e0f95098SPeter Avalos 
357*e0f95098SPeter Avalos 	if (ox[1]) {	/* ox[1] is either x, X, or \0 */
358*e0f95098SPeter Avalos 		ox[0] = '0';
359*e0f95098SPeter Avalos 		ret += __printf_puts(io, ox, 2);
360*e0f95098SPeter Avalos 	}
361*e0f95098SPeter Avalos 
362*e0f95098SPeter Avalos 	/* right-adjusting zero padding */
363*e0f95098SPeter Avalos 	if (pi->pad == '0' && pi->left == 0)
364*e0f95098SPeter Avalos 		ret += __printf_pad(io, pi->width - realsz, 1);
365*e0f95098SPeter Avalos 
366*e0f95098SPeter Avalos 	/* leading zeroes from decimal precision */
367*e0f95098SPeter Avalos 	ret += __printf_pad(io, dprec - size, 1);
368*e0f95098SPeter Avalos 
369*e0f95098SPeter Avalos 	if (flag) {
370*e0f95098SPeter Avalos 		ret += __printf_puts(io, cp, size);
371*e0f95098SPeter Avalos 	} else {
372*e0f95098SPeter Avalos 		/* glue together f_p fragments */
373*e0f95098SPeter Avalos 		if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
374*e0f95098SPeter Avalos 			if (expt <= 0) {
375*e0f95098SPeter Avalos 				ret += __printf_puts(io, "0", 1);
376*e0f95098SPeter Avalos 				if (prec || pi->alt)
377*e0f95098SPeter Avalos 					ret += __printf_puts(io, decimal_point, 1);
378*e0f95098SPeter Avalos 				ret += __printf_pad(io, -expt, 1);
379*e0f95098SPeter Avalos 				/* already handled initial 0's */
380*e0f95098SPeter Avalos 				prec += expt;
381*e0f95098SPeter Avalos 			} else {
382*e0f95098SPeter Avalos 				PRINTANDPAD(cp, dtoaend, lead, 1);
383*e0f95098SPeter Avalos 				cp += lead;
384*e0f95098SPeter Avalos 				if (grouping) {
385*e0f95098SPeter Avalos 					while (nseps>0 || nrepeats>0) {
386*e0f95098SPeter Avalos 						if (nrepeats > 0) {
387*e0f95098SPeter Avalos 							nrepeats--;
388*e0f95098SPeter Avalos 						} else {
389*e0f95098SPeter Avalos 							grouping--;
390*e0f95098SPeter Avalos 							nseps--;
391*e0f95098SPeter Avalos 						}
392*e0f95098SPeter Avalos 						ret += __printf_puts(io, &thousands_sep, 1);
393*e0f95098SPeter Avalos 						PRINTANDPAD(cp,dtoaend,
394*e0f95098SPeter Avalos 						    *grouping, 1);
395*e0f95098SPeter Avalos 						cp += *grouping;
396*e0f95098SPeter Avalos 					}
397*e0f95098SPeter Avalos 					if (cp > dtoaend)
398*e0f95098SPeter Avalos 						cp = dtoaend;
399*e0f95098SPeter Avalos 				}
400*e0f95098SPeter Avalos 				if (prec || pi->alt)
401*e0f95098SPeter Avalos 					ret += __printf_puts(io, decimal_point,1);
402*e0f95098SPeter Avalos 			}
403*e0f95098SPeter Avalos 			PRINTANDPAD(cp, dtoaend, prec, 1);
404*e0f95098SPeter Avalos 		} else {	/* %[eE] or sufficiently long %[gG] */
405*e0f95098SPeter Avalos 			if (prec > 1 || pi->alt) {
406*e0f95098SPeter Avalos 				buf[0] = *cp++;
407*e0f95098SPeter Avalos 				buf[1] = *decimal_point;
408*e0f95098SPeter Avalos 				ret += __printf_puts(io, buf, 2);
409*e0f95098SPeter Avalos 				ret += __printf_puts(io, cp, ndig-1);
410*e0f95098SPeter Avalos 				ret += __printf_pad(io, prec - ndig, 1);
411*e0f95098SPeter Avalos 			} else {	/* XeYYY */
412*e0f95098SPeter Avalos 				ret += __printf_puts(io, cp, 1);
413*e0f95098SPeter Avalos 			}
414*e0f95098SPeter Avalos 			ret += __printf_puts(io, expstr, expsize);
415*e0f95098SPeter Avalos 		}
416*e0f95098SPeter Avalos 	}
417*e0f95098SPeter Avalos 	/* left-adjusting padding (always blank) */
418*e0f95098SPeter Avalos 	if (pi->left)
419*e0f95098SPeter Avalos 		ret += __printf_pad(io, pi->width - realsz, 0);
420*e0f95098SPeter Avalos 
421*e0f95098SPeter Avalos 	__printf_flush(io);
422*e0f95098SPeter Avalos 	if (dtoaresult != NULL)
423*e0f95098SPeter Avalos 		freedtoa(dtoaresult);
424*e0f95098SPeter Avalos 
425*e0f95098SPeter Avalos 	return (ret);
426*e0f95098SPeter Avalos }
427