xref: /freebsd/lib/libc/stdio/xprintf_float.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
175067f4fSPoul-Henning Kamp /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni  *
475067f4fSPoul-Henning Kamp  * Copyright (c) 2005 Poul-Henning Kamp
575067f4fSPoul-Henning Kamp  * Copyright (c) 1990, 1993
675067f4fSPoul-Henning Kamp  *	The Regents of the University of California.  All rights reserved.
775067f4fSPoul-Henning Kamp  *
875067f4fSPoul-Henning Kamp  * This code is derived from software contributed to Berkeley by
975067f4fSPoul-Henning Kamp  * Chris Torek.
1075067f4fSPoul-Henning Kamp  *
1175067f4fSPoul-Henning Kamp  * Redistribution and use in source and binary forms, with or without
1275067f4fSPoul-Henning Kamp  * modification, are permitted provided that the following conditions
1375067f4fSPoul-Henning Kamp  * are met:
1475067f4fSPoul-Henning Kamp  * 1. Redistributions of source code must retain the above copyright
1575067f4fSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer.
1675067f4fSPoul-Henning Kamp  * 2. Redistributions in binary form must reproduce the above copyright
1775067f4fSPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer in the
1875067f4fSPoul-Henning Kamp  *    documentation and/or other materials provided with the distribution.
1975067f4fSPoul-Henning Kamp  * 3. Neither the name of the University nor the names of its contributors
2075067f4fSPoul-Henning Kamp  *    may be used to endorse or promote products derived from this software
2175067f4fSPoul-Henning Kamp  *    without specific prior written permission.
2275067f4fSPoul-Henning Kamp  *
2375067f4fSPoul-Henning Kamp  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2475067f4fSPoul-Henning Kamp  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2575067f4fSPoul-Henning Kamp  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2675067f4fSPoul-Henning Kamp  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2775067f4fSPoul-Henning Kamp  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2875067f4fSPoul-Henning Kamp  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2975067f4fSPoul-Henning Kamp  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3075067f4fSPoul-Henning Kamp  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3175067f4fSPoul-Henning Kamp  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3275067f4fSPoul-Henning Kamp  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3375067f4fSPoul-Henning Kamp  * SUCH DAMAGE.
3475067f4fSPoul-Henning Kamp  */
3575067f4fSPoul-Henning Kamp 
3675067f4fSPoul-Henning Kamp #include <namespace.h>
3775067f4fSPoul-Henning Kamp #include <stdio.h>
3875067f4fSPoul-Henning Kamp #include <wchar.h>
3975067f4fSPoul-Henning Kamp #include <assert.h>
4075067f4fSPoul-Henning Kamp #include <locale.h>
4175067f4fSPoul-Henning Kamp #include <limits.h>
4275067f4fSPoul-Henning Kamp 
4375067f4fSPoul-Henning Kamp #define	dtoa		__dtoa
4475067f4fSPoul-Henning Kamp #define	freedtoa	__freedtoa
4575067f4fSPoul-Henning Kamp 
4675067f4fSPoul-Henning Kamp #include <float.h>
4775067f4fSPoul-Henning Kamp #include <math.h>
4875067f4fSPoul-Henning Kamp #include "gdtoa.h"
4975067f4fSPoul-Henning Kamp #include "floatio.h"
5075067f4fSPoul-Henning Kamp #include "printf.h"
5175067f4fSPoul-Henning Kamp #include <un-namespace.h>
5275067f4fSPoul-Henning Kamp 
5375067f4fSPoul-Henning Kamp /*
5475067f4fSPoul-Henning Kamp  * The size of the buffer we use as scratch space for integer
5575067f4fSPoul-Henning Kamp  * conversions, among other things.  Technically, we would need the
5675067f4fSPoul-Henning Kamp  * most space for base 10 conversions with thousands' grouping
5775067f4fSPoul-Henning Kamp  * characters between each pair of digits.  100 bytes is a
5875067f4fSPoul-Henning Kamp  * conservative overestimate even for a 128-bit uintmax_t.
5975067f4fSPoul-Henning Kamp  */
6075067f4fSPoul-Henning Kamp #define	BUF	100
6175067f4fSPoul-Henning Kamp 
6275067f4fSPoul-Henning Kamp #define	DEFPREC		6	/* Default FP precision */
6375067f4fSPoul-Henning Kamp 
6475067f4fSPoul-Henning Kamp 
6575067f4fSPoul-Henning Kamp /* various globals ---------------------------------------------------*/
6675067f4fSPoul-Henning Kamp 
6775067f4fSPoul-Henning Kamp 
6875067f4fSPoul-Henning Kamp /* padding function---------------------------------------------------*/
6975067f4fSPoul-Henning Kamp 
7075067f4fSPoul-Henning Kamp #define	PRINTANDPAD(p, ep, len, with) do {		\
7175067f4fSPoul-Henning Kamp 	n2 = (ep) - (p);       				\
7275067f4fSPoul-Henning Kamp 	if (n2 > (len))					\
7375067f4fSPoul-Henning Kamp 		n2 = (len);				\
7475067f4fSPoul-Henning Kamp 	if (n2 > 0)					\
7575067f4fSPoul-Henning Kamp 		ret += __printf_puts(io, (p), n2);		\
7675067f4fSPoul-Henning Kamp 	ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with));	\
7775067f4fSPoul-Henning Kamp } while(0)
7875067f4fSPoul-Henning Kamp 
7975067f4fSPoul-Henning Kamp /* misc --------------------------------------------------------------*/
8075067f4fSPoul-Henning Kamp 
8175067f4fSPoul-Henning Kamp #define	to_char(n)	((n) + '0')
8275067f4fSPoul-Henning Kamp 
8375067f4fSPoul-Henning Kamp static int
exponent(char * p0,int expo,int fmtch)8475067f4fSPoul-Henning Kamp exponent(char *p0, int expo, int fmtch)
8575067f4fSPoul-Henning Kamp {
8675067f4fSPoul-Henning Kamp 	char *p, *t;
8775067f4fSPoul-Henning Kamp 	char expbuf[MAXEXPDIG];
8875067f4fSPoul-Henning Kamp 
8975067f4fSPoul-Henning Kamp 	p = p0;
9075067f4fSPoul-Henning Kamp 	*p++ = fmtch;
9175067f4fSPoul-Henning Kamp 	if (expo < 0) {
9275067f4fSPoul-Henning Kamp 		expo = -expo;
9375067f4fSPoul-Henning Kamp 		*p++ = '-';
9475067f4fSPoul-Henning Kamp 	}
9575067f4fSPoul-Henning Kamp 	else
9675067f4fSPoul-Henning Kamp 		*p++ = '+';
9775067f4fSPoul-Henning Kamp 	t = expbuf + MAXEXPDIG;
9875067f4fSPoul-Henning Kamp 	if (expo > 9) {
9975067f4fSPoul-Henning Kamp 		do {
10075067f4fSPoul-Henning Kamp 			*--t = to_char(expo % 10);
10175067f4fSPoul-Henning Kamp 		} while ((expo /= 10) > 9);
10275067f4fSPoul-Henning Kamp 		*--t = to_char(expo);
10375067f4fSPoul-Henning Kamp 		for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
10475067f4fSPoul-Henning Kamp 			;
10575067f4fSPoul-Henning Kamp 	}
10675067f4fSPoul-Henning Kamp 	else {
10775067f4fSPoul-Henning Kamp 		/*
10875067f4fSPoul-Henning Kamp 		 * Exponents for decimal floating point conversions
10975067f4fSPoul-Henning Kamp 		 * (%[eEgG]) must be at least two characters long,
11075067f4fSPoul-Henning Kamp 		 * whereas exponents for hexadecimal conversions can
11175067f4fSPoul-Henning Kamp 		 * be only one character long.
11275067f4fSPoul-Henning Kamp 		 */
11375067f4fSPoul-Henning Kamp 		if (fmtch == 'e' || fmtch == 'E')
11475067f4fSPoul-Henning Kamp 			*p++ = '0';
11575067f4fSPoul-Henning Kamp 		*p++ = to_char(expo);
11675067f4fSPoul-Henning Kamp 	}
11775067f4fSPoul-Henning Kamp 	return (p - p0);
11875067f4fSPoul-Henning Kamp }
11975067f4fSPoul-Henning Kamp 
12075067f4fSPoul-Henning Kamp /* 'f' ---------------------------------------------------------------*/
12175067f4fSPoul-Henning Kamp 
12275067f4fSPoul-Henning Kamp int
__printf_arginfo_float(const struct printf_info * pi,size_t n,int * argt)12375067f4fSPoul-Henning Kamp __printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt)
12475067f4fSPoul-Henning Kamp {
12575067f4fSPoul-Henning Kamp 	assert (n > 0);
12675067f4fSPoul-Henning Kamp 	argt[0] = PA_DOUBLE;
12775067f4fSPoul-Henning Kamp 	if (pi->is_long_double)
12875067f4fSPoul-Henning Kamp 		argt[0] |= PA_FLAG_LONG_DOUBLE;
12975067f4fSPoul-Henning Kamp 	return (1);
13075067f4fSPoul-Henning Kamp }
13175067f4fSPoul-Henning Kamp 
13275067f4fSPoul-Henning Kamp /*
13375067f4fSPoul-Henning Kamp  * We can decompose the printed representation of floating
13475067f4fSPoul-Henning Kamp  * point numbers into several parts, some of which may be empty:
13575067f4fSPoul-Henning Kamp  *
13675067f4fSPoul-Henning Kamp  * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
13775067f4fSPoul-Henning Kamp  *    A       B     ---C---      D       E   F
13875067f4fSPoul-Henning Kamp  *
13975067f4fSPoul-Henning Kamp  * A:	'sign' holds this value if present; '\0' otherwise
14075067f4fSPoul-Henning Kamp  * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
14175067f4fSPoul-Henning Kamp  * C:	cp points to the string MMMNNN.  Leading and trailing
14275067f4fSPoul-Henning Kamp  *	zeros are not in the string and must be added.
14375067f4fSPoul-Henning Kamp  * D:	expchar holds this character; '\0' if no exponent, e.g. %f
14475067f4fSPoul-Henning Kamp  * F:	at least two digits for decimal, at least one digit for hex
14575067f4fSPoul-Henning Kamp  */
14675067f4fSPoul-Henning Kamp 
14775067f4fSPoul-Henning Kamp int
__printf_render_float(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)14875067f4fSPoul-Henning Kamp __printf_render_float(struct __printf_io *io, const struct printf_info *pi, const void *const *arg)
14975067f4fSPoul-Henning Kamp {
15075067f4fSPoul-Henning Kamp 	int prec;		/* precision from format; <0 for N/A */
15175067f4fSPoul-Henning Kamp 	char *dtoaresult;	/* buffer allocated by dtoa */
15275067f4fSPoul-Henning Kamp 	char expchar;		/* exponent character: [eEpP\0] */
15375067f4fSPoul-Henning Kamp 	char *cp;
15475067f4fSPoul-Henning Kamp 	int expt;		/* integer value of exponent */
15575067f4fSPoul-Henning Kamp 	int signflag;		/* true if float is negative */
15675067f4fSPoul-Henning Kamp 	char *dtoaend;		/* pointer to end of converted digits */
15775067f4fSPoul-Henning Kamp 	char sign;		/* sign prefix (' ', '+', '-', or \0) */
15875067f4fSPoul-Henning Kamp 	int size;		/* size of converted field or string */
15975067f4fSPoul-Henning Kamp 	int ndig;		/* actual number of digits returned by dtoa */
16075067f4fSPoul-Henning Kamp 	int expsize;		/* character count for expstr */
16175067f4fSPoul-Henning Kamp 	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
16275067f4fSPoul-Henning Kamp 	int nseps;		/* number of group separators with ' */
16375067f4fSPoul-Henning Kamp 	int nrepeats;		/* number of repeats of the last group */
16475067f4fSPoul-Henning Kamp 	const char *grouping;	/* locale specific numeric grouping rules */
16575067f4fSPoul-Henning Kamp 	int lead;		/* sig figs before decimal or group sep */
16675067f4fSPoul-Henning Kamp 	long double ld;
16775067f4fSPoul-Henning Kamp 	double d;
16875067f4fSPoul-Henning Kamp 	int realsz;		/* field size expanded by dprec, sign, etc */
16975067f4fSPoul-Henning Kamp 	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
17075067f4fSPoul-Henning Kamp 	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
17175067f4fSPoul-Henning Kamp 	int ret;		/* return value accumulator */
17275067f4fSPoul-Henning Kamp 	char *decimal_point;	/* locale specific decimal point */
17375067f4fSPoul-Henning Kamp 	int n2;			/* XXX: for PRINTANDPAD */
17475067f4fSPoul-Henning Kamp 	char thousands_sep;	/* locale specific thousands separator */
17575067f4fSPoul-Henning Kamp 	char buf[BUF];		/* buffer with space for digits of uintmax_t */
17675067f4fSPoul-Henning Kamp 	const char *xdigs;
17775067f4fSPoul-Henning Kamp 	int flag;
17875067f4fSPoul-Henning Kamp 
17975067f4fSPoul-Henning Kamp 	prec = pi->prec;
18075067f4fSPoul-Henning Kamp 	ox[1] = '\0';
18175067f4fSPoul-Henning Kamp 	sign = pi->showsign;
18275067f4fSPoul-Henning Kamp 	flag = 0;
18375067f4fSPoul-Henning Kamp 	ret = 0;
18475067f4fSPoul-Henning Kamp 
18575067f4fSPoul-Henning Kamp 	thousands_sep = *(localeconv()->thousands_sep);
18675067f4fSPoul-Henning Kamp 	grouping = NULL;
18775067f4fSPoul-Henning Kamp 	if (pi->alt)
18875067f4fSPoul-Henning Kamp 		grouping = localeconv()->grouping;
18975067f4fSPoul-Henning Kamp 	decimal_point = localeconv()->decimal_point;
19075067f4fSPoul-Henning Kamp 	dprec = -1;
19175067f4fSPoul-Henning Kamp 
19275067f4fSPoul-Henning Kamp 	switch(pi->spec) {
19375067f4fSPoul-Henning Kamp 	case 'a':
19475067f4fSPoul-Henning Kamp 	case 'A':
19575067f4fSPoul-Henning Kamp 		if (pi->spec == 'a') {
19675067f4fSPoul-Henning Kamp 			ox[1] = 'x';
19775067f4fSPoul-Henning Kamp 			xdigs = __lowercase_hex;
19875067f4fSPoul-Henning Kamp 			expchar = 'p';
19975067f4fSPoul-Henning Kamp 		} else {
20075067f4fSPoul-Henning Kamp 			ox[1] = 'X';
20175067f4fSPoul-Henning Kamp 			xdigs = __uppercase_hex;
20275067f4fSPoul-Henning Kamp 			expchar = 'P';
20375067f4fSPoul-Henning Kamp 		}
20475067f4fSPoul-Henning Kamp 		if (prec >= 0)
20575067f4fSPoul-Henning Kamp 			prec++;
20675067f4fSPoul-Henning Kamp 		if (pi->is_long_double) {
20775067f4fSPoul-Henning Kamp 			ld = *((long double *)arg[0]);
20875067f4fSPoul-Henning Kamp 			dtoaresult = cp =
20975067f4fSPoul-Henning Kamp 			    __hldtoa(ld, xdigs, prec,
21075067f4fSPoul-Henning Kamp 			    &expt, &signflag, &dtoaend);
21175067f4fSPoul-Henning Kamp 		} else {
21275067f4fSPoul-Henning Kamp 			d = *((double *)arg[0]);
21375067f4fSPoul-Henning Kamp 			dtoaresult = cp =
21475067f4fSPoul-Henning Kamp 			    __hdtoa(d, xdigs, prec,
21575067f4fSPoul-Henning Kamp 			    &expt, &signflag, &dtoaend);
21675067f4fSPoul-Henning Kamp 		}
21775067f4fSPoul-Henning Kamp 		if (prec < 0)
21875067f4fSPoul-Henning Kamp 			prec = dtoaend - cp;
21975067f4fSPoul-Henning Kamp 		if (expt == INT_MAX)
22075067f4fSPoul-Henning Kamp 			ox[1] = '\0';
22175067f4fSPoul-Henning Kamp 		goto fp_common;
22275067f4fSPoul-Henning Kamp 	case 'e':
22375067f4fSPoul-Henning Kamp 	case 'E':
22475067f4fSPoul-Henning Kamp 		expchar = pi->spec;
22575067f4fSPoul-Henning Kamp 		if (prec < 0)	/* account for digit before decpt */
22675067f4fSPoul-Henning Kamp 			prec = DEFPREC + 1;
22775067f4fSPoul-Henning Kamp 		else
22875067f4fSPoul-Henning Kamp 			prec++;
22975067f4fSPoul-Henning Kamp 		break;
23075067f4fSPoul-Henning Kamp 	case 'f':
23175067f4fSPoul-Henning Kamp 	case 'F':
23275067f4fSPoul-Henning Kamp 		expchar = '\0';
23375067f4fSPoul-Henning Kamp 		break;
23475067f4fSPoul-Henning Kamp 	case 'g':
23575067f4fSPoul-Henning Kamp 	case 'G':
23675067f4fSPoul-Henning Kamp 		expchar = pi->spec - ('g' - 'e');
23775067f4fSPoul-Henning Kamp 		if (prec == 0)
23875067f4fSPoul-Henning Kamp 			prec = 1;
23975067f4fSPoul-Henning Kamp 		break;
24075067f4fSPoul-Henning Kamp 	default:
24175067f4fSPoul-Henning Kamp 		assert(pi->spec == 'f');
24275067f4fSPoul-Henning Kamp 	}
24375067f4fSPoul-Henning Kamp 
24475067f4fSPoul-Henning Kamp 	if (prec < 0)
24575067f4fSPoul-Henning Kamp 		prec = DEFPREC;
24675067f4fSPoul-Henning Kamp 	if (pi->is_long_double) {
24775067f4fSPoul-Henning Kamp 		ld = *((long double *)arg[0]);
24875067f4fSPoul-Henning Kamp 		dtoaresult = cp =
24975067f4fSPoul-Henning Kamp 		    __ldtoa(&ld, expchar ? 2 : 3, prec,
25075067f4fSPoul-Henning Kamp 		    &expt, &signflag, &dtoaend);
25175067f4fSPoul-Henning Kamp 	} else {
25275067f4fSPoul-Henning Kamp 		d = *((double *)arg[0]);
25375067f4fSPoul-Henning Kamp 		dtoaresult = cp =
25475067f4fSPoul-Henning Kamp 		    dtoa(d, expchar ? 2 : 3, prec,
25575067f4fSPoul-Henning Kamp 		    &expt, &signflag, &dtoaend);
25675067f4fSPoul-Henning Kamp 		if (expt == 9999)
25775067f4fSPoul-Henning Kamp 			expt = INT_MAX;
25875067f4fSPoul-Henning Kamp 	}
25975067f4fSPoul-Henning Kamp fp_common:
26075067f4fSPoul-Henning Kamp 	if (signflag)
26175067f4fSPoul-Henning Kamp 		sign = '-';
26275067f4fSPoul-Henning Kamp 	if (expt == INT_MAX) {	/* inf or nan */
26375067f4fSPoul-Henning Kamp 		if (*cp == 'N') {
26475067f4fSPoul-Henning Kamp 			cp = (pi->spec >= 'a') ? "nan" : "NAN";
26575067f4fSPoul-Henning Kamp 			sign = '\0';
26675067f4fSPoul-Henning Kamp 		} else
26775067f4fSPoul-Henning Kamp 			cp = (pi->spec >= 'a') ? "inf" : "INF";
26875067f4fSPoul-Henning Kamp 		size = 3;
26975067f4fSPoul-Henning Kamp 		flag = 1;
27075067f4fSPoul-Henning Kamp 		goto here;
27175067f4fSPoul-Henning Kamp 	}
27275067f4fSPoul-Henning Kamp 	ndig = dtoaend - cp;
27375067f4fSPoul-Henning Kamp 	if (pi->spec == 'g' || pi->spec == 'G') {
27475067f4fSPoul-Henning Kamp 		if (expt > -4 && expt <= prec) {
27575067f4fSPoul-Henning Kamp 			/* Make %[gG] smell like %[fF] */
27675067f4fSPoul-Henning Kamp 			expchar = '\0';
27775067f4fSPoul-Henning Kamp 			if (pi->alt)
27875067f4fSPoul-Henning Kamp 				prec -= expt;
27975067f4fSPoul-Henning Kamp 			else
28075067f4fSPoul-Henning Kamp 				prec = ndig - expt;
28175067f4fSPoul-Henning Kamp 			if (prec < 0)
28275067f4fSPoul-Henning Kamp 				prec = 0;
28375067f4fSPoul-Henning Kamp 		} else {
28475067f4fSPoul-Henning Kamp 			/*
28575067f4fSPoul-Henning Kamp 			 * Make %[gG] smell like %[eE], but
28675067f4fSPoul-Henning Kamp 			 * trim trailing zeroes if no # flag.
28775067f4fSPoul-Henning Kamp 			 */
28875067f4fSPoul-Henning Kamp 			if (!pi->alt)
28975067f4fSPoul-Henning Kamp 				prec = ndig;
29075067f4fSPoul-Henning Kamp 		}
29175067f4fSPoul-Henning Kamp 	}
29275067f4fSPoul-Henning Kamp 	if (expchar) {
29375067f4fSPoul-Henning Kamp 		expsize = exponent(expstr, expt - 1, expchar);
29475067f4fSPoul-Henning Kamp 		size = expsize + prec;
29575067f4fSPoul-Henning Kamp 		if (prec > 1 || pi->alt)
29675067f4fSPoul-Henning Kamp 			++size;
29775067f4fSPoul-Henning Kamp 	} else {
29875067f4fSPoul-Henning Kamp 		/* space for digits before decimal point */
29975067f4fSPoul-Henning Kamp 		if (expt > 0)
30075067f4fSPoul-Henning Kamp 			size = expt;
30175067f4fSPoul-Henning Kamp 		else	/* "0" */
30275067f4fSPoul-Henning Kamp 			size = 1;
30375067f4fSPoul-Henning Kamp 		/* space for decimal pt and following digits */
30475067f4fSPoul-Henning Kamp 		if (prec || pi->alt)
30575067f4fSPoul-Henning Kamp 			size += prec + 1;
30675067f4fSPoul-Henning Kamp 		if (grouping && expt > 0) {
30775067f4fSPoul-Henning Kamp 			/* space for thousands' grouping */
30875067f4fSPoul-Henning Kamp 			nseps = nrepeats = 0;
30975067f4fSPoul-Henning Kamp 			lead = expt;
31075067f4fSPoul-Henning Kamp 			while (*grouping != CHAR_MAX) {
31175067f4fSPoul-Henning Kamp 				if (lead <= *grouping)
31275067f4fSPoul-Henning Kamp 					break;
31375067f4fSPoul-Henning Kamp 				lead -= *grouping;
31475067f4fSPoul-Henning Kamp 				if (*(grouping+1)) {
31575067f4fSPoul-Henning Kamp 					nseps++;
31675067f4fSPoul-Henning Kamp 					grouping++;
31775067f4fSPoul-Henning Kamp 				} else
31875067f4fSPoul-Henning Kamp 					nrepeats++;
31975067f4fSPoul-Henning Kamp 			}
32075067f4fSPoul-Henning Kamp 			size += nseps + nrepeats;
32175067f4fSPoul-Henning Kamp 		} else
32275067f4fSPoul-Henning Kamp 			lead = expt;
32375067f4fSPoul-Henning Kamp 	}
32475067f4fSPoul-Henning Kamp 
32575067f4fSPoul-Henning Kamp here:
32675067f4fSPoul-Henning Kamp 	/*
32775067f4fSPoul-Henning Kamp 	 * All reasonable formats wind up here.  At this point, `cp'
32875067f4fSPoul-Henning Kamp 	 * points to a string which (if not flags&LADJUST) should be
32975067f4fSPoul-Henning Kamp 	 * padded out to `width' places.  If flags&ZEROPAD, it should
33075067f4fSPoul-Henning Kamp 	 * first be prefixed by any sign or other prefix; otherwise,
33175067f4fSPoul-Henning Kamp 	 * it should be blank padded before the prefix is emitted.
33275067f4fSPoul-Henning Kamp 	 * After any left-hand padding and prefixing, emit zeroes
33375067f4fSPoul-Henning Kamp 	 * required by a decimal [diouxX] precision, then print the
33475067f4fSPoul-Henning Kamp 	 * string proper, then emit zeroes required by any leftover
33575067f4fSPoul-Henning Kamp 	 * floating precision; finally, if LADJUST, pad with blanks.
33675067f4fSPoul-Henning Kamp 	 *
33775067f4fSPoul-Henning Kamp 	 * Compute actual size, so we know how much to pad.
33875067f4fSPoul-Henning Kamp 	 * size excludes decimal prec; realsz includes it.
33975067f4fSPoul-Henning Kamp 	 */
34075067f4fSPoul-Henning Kamp 	realsz = dprec > size ? dprec : size;
34175067f4fSPoul-Henning Kamp 	if (sign)
34275067f4fSPoul-Henning Kamp 		realsz++;
34375067f4fSPoul-Henning Kamp 	if (ox[1])
34475067f4fSPoul-Henning Kamp 		realsz += 2;
34575067f4fSPoul-Henning Kamp 
34675067f4fSPoul-Henning Kamp 	/* right-adjusting blank padding */
34775067f4fSPoul-Henning Kamp 	if (pi->pad != '0' && pi->left == 0)
34875067f4fSPoul-Henning Kamp 		ret += __printf_pad(io, pi->width - realsz, 0);
34975067f4fSPoul-Henning Kamp 
35075067f4fSPoul-Henning Kamp 	/* prefix */
35175067f4fSPoul-Henning Kamp 	if (sign)
35275067f4fSPoul-Henning Kamp 		ret += __printf_puts(io, &sign, 1);
35375067f4fSPoul-Henning Kamp 
35475067f4fSPoul-Henning Kamp 	if (ox[1]) {	/* ox[1] is either x, X, or \0 */
35575067f4fSPoul-Henning Kamp 		ox[0] = '0';
35675067f4fSPoul-Henning Kamp 		ret += __printf_puts(io, ox, 2);
35775067f4fSPoul-Henning Kamp 	}
35875067f4fSPoul-Henning Kamp 
35975067f4fSPoul-Henning Kamp 	/* right-adjusting zero padding */
36075067f4fSPoul-Henning Kamp 	if (pi->pad == '0' && pi->left == 0)
36175067f4fSPoul-Henning Kamp 		ret += __printf_pad(io, pi->width - realsz, 1);
36275067f4fSPoul-Henning Kamp 
36375067f4fSPoul-Henning Kamp 	/* leading zeroes from decimal precision */
36475067f4fSPoul-Henning Kamp 	ret += __printf_pad(io, dprec - size, 1);
36575067f4fSPoul-Henning Kamp 
36675067f4fSPoul-Henning Kamp 	if (flag)
36775067f4fSPoul-Henning Kamp 		ret += __printf_puts(io, cp, size);
36875067f4fSPoul-Henning Kamp 	else {
36975067f4fSPoul-Henning Kamp 		/* glue together f_p fragments */
37075067f4fSPoul-Henning Kamp 		if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
37175067f4fSPoul-Henning Kamp 			if (expt <= 0) {
37275067f4fSPoul-Henning Kamp 				ret += __printf_puts(io, "0", 1);
37375067f4fSPoul-Henning Kamp 				if (prec || pi->alt)
37475067f4fSPoul-Henning Kamp 					ret += __printf_puts(io, decimal_point, 1);
37575067f4fSPoul-Henning Kamp 				ret += __printf_pad(io, -expt, 1);
37675067f4fSPoul-Henning Kamp 				/* already handled initial 0's */
37775067f4fSPoul-Henning Kamp 				prec += expt;
37875067f4fSPoul-Henning Kamp 			} else {
37975067f4fSPoul-Henning Kamp 				PRINTANDPAD(cp, dtoaend, lead, 1);
38075067f4fSPoul-Henning Kamp 				cp += lead;
38175067f4fSPoul-Henning Kamp 				if (grouping) {
38275067f4fSPoul-Henning Kamp 					while (nseps>0 || nrepeats>0) {
38375067f4fSPoul-Henning Kamp 						if (nrepeats > 0)
38475067f4fSPoul-Henning Kamp 							nrepeats--;
38575067f4fSPoul-Henning Kamp 						else {
38675067f4fSPoul-Henning Kamp 							grouping--;
38775067f4fSPoul-Henning Kamp 							nseps--;
38875067f4fSPoul-Henning Kamp 						}
38975067f4fSPoul-Henning Kamp 						ret += __printf_puts(io, &thousands_sep, 1);
39075067f4fSPoul-Henning Kamp 						PRINTANDPAD(cp,dtoaend,
39175067f4fSPoul-Henning Kamp 						    *grouping, 1);
39275067f4fSPoul-Henning Kamp 						cp += *grouping;
39375067f4fSPoul-Henning Kamp 					}
39475067f4fSPoul-Henning Kamp 					if (cp > dtoaend)
39575067f4fSPoul-Henning Kamp 						cp = dtoaend;
39675067f4fSPoul-Henning Kamp 				}
39775067f4fSPoul-Henning Kamp 				if (prec || pi->alt)
39875067f4fSPoul-Henning Kamp 					ret += __printf_puts(io, decimal_point,1);
39975067f4fSPoul-Henning Kamp 			}
40075067f4fSPoul-Henning Kamp 			PRINTANDPAD(cp, dtoaend, prec, 1);
40175067f4fSPoul-Henning Kamp 		} else {	/* %[eE] or sufficiently long %[gG] */
40275067f4fSPoul-Henning Kamp 			if (prec > 1 || pi->alt) {
40375067f4fSPoul-Henning Kamp 				buf[0] = *cp++;
40475067f4fSPoul-Henning Kamp 				buf[1] = *decimal_point;
40575067f4fSPoul-Henning Kamp 				ret += __printf_puts(io, buf, 2);
40675067f4fSPoul-Henning Kamp 				ret += __printf_puts(io, cp, ndig-1);
40775067f4fSPoul-Henning Kamp 				ret += __printf_pad(io, prec - ndig, 1);
40875067f4fSPoul-Henning Kamp 			} else	/* XeYYY */
40975067f4fSPoul-Henning Kamp 				ret += __printf_puts(io, cp, 1);
41075067f4fSPoul-Henning Kamp 			ret += __printf_puts(io, expstr, expsize);
41175067f4fSPoul-Henning Kamp 		}
41275067f4fSPoul-Henning Kamp 	}
41375067f4fSPoul-Henning Kamp 	/* left-adjusting padding (always blank) */
41475067f4fSPoul-Henning Kamp 	if (pi->left)
41575067f4fSPoul-Henning Kamp 		ret += __printf_pad(io, pi->width - realsz, 0);
41675067f4fSPoul-Henning Kamp 
41775067f4fSPoul-Henning Kamp 	__printf_flush(io);
41875067f4fSPoul-Henning Kamp 	if (dtoaresult != NULL)
41975067f4fSPoul-Henning Kamp 		freedtoa(dtoaresult);
42075067f4fSPoul-Henning Kamp 
42175067f4fSPoul-Henning Kamp 	return (ret);
42275067f4fSPoul-Henning Kamp }
423