vfprintf.c revision 165742
165942Sgibbs/*-
265942Sgibbs * Copyright (c) 1990, 1993
365942Sgibbs *	The Regents of the University of California.  All rights reserved.
465942Sgibbs *
565942Sgibbs * This code is derived from software contributed to Berkeley by
665942Sgibbs * Chris Torek.
765942Sgibbs *
865942Sgibbs * Redistribution and use in source and binary forms, with or without
965942Sgibbs * modification, are permitted provided that the following conditions
1065942Sgibbs * are met:
1165942Sgibbs * 1. Redistributions of source code must retain the above copyright
1265942Sgibbs *    notice, this list of conditions and the following disclaimer.
1365942Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1465942Sgibbs *    notice, this list of conditions and the following disclaimer in the
1565942Sgibbs *    documentation and/or other materials provided with the distribution.
1665942Sgibbs * 3. All advertising materials mentioning features or use of this software
1765942Sgibbs *    must display the following acknowledgement:
1865942Sgibbs *	This product includes software developed by the University of
1965942Sgibbs *	California, Berkeley and its contributors.
2065942Sgibbs * 4. Neither the name of the University nor the names of its contributors
2165942Sgibbs *    may be used to endorse or promote products derived from this software
2265942Sgibbs *    without specific prior written permission.
2365942Sgibbs *
2465942Sgibbs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2565942Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2665942Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2765942Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2865942Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2965942Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3065942Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3165942Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3265942Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3365942Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3465942Sgibbs * SUCH DAMAGE.
3565942Sgibbs */
3665942Sgibbs
3765942Sgibbs#if defined(LIBC_SCCS) && !defined(lint)
3865942Sgibbsstatic char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
3965942Sgibbs#endif /* LIBC_SCCS and not lint */
4065942Sgibbs#include <sys/cdefs.h>
4165942Sgibbs__FBSDID("$FreeBSD: head/lib/libc/stdio/vfprintf.c 165742 2007-01-03 04:57:58Z das $");
4265942Sgibbs
4365942Sgibbs/*
4465942Sgibbs * Actual printf innards.
4565942Sgibbs *
4665942Sgibbs * This code is large and complicated...
4765942Sgibbs */
4865942Sgibbs
4965942Sgibbs#include "namespace.h"
5065942Sgibbs#include <sys/types.h>
5165942Sgibbs
5265942Sgibbs#include <ctype.h>
5365942Sgibbs#include <limits.h>
5465942Sgibbs#include <locale.h>
5565942Sgibbs#include <stddef.h>
5665942Sgibbs#include <stdint.h>
5765942Sgibbs#include <stdio.h>
5865942Sgibbs#include <stdlib.h>
5965942Sgibbs#include <string.h>
6065942Sgibbs#include <wchar.h>
6165942Sgibbs#include <printf.h>
6265942Sgibbs
6365942Sgibbs#include <stdarg.h>
6465942Sgibbs#include "un-namespace.h"
6565942Sgibbs
6665942Sgibbs#include "libc_private.h"
6765942Sgibbs#include "local.h"
6865942Sgibbs#include "fvwrite.h"
6965942Sgibbs
7065942Sgibbsunion arg {
7166269Sgibbs	int	intarg;
7265942Sgibbs	u_int	uintarg;
7365942Sgibbs	long	longarg;
7465942Sgibbs	u_long	ulongarg;
7565942Sgibbs	long long longlongarg;
7665942Sgibbs	unsigned long long ulonglongarg;
7766269Sgibbs	ptrdiff_t ptrdiffarg;
7866269Sgibbs	size_t	sizearg;
7965942Sgibbs	intmax_t intmaxarg;
8065942Sgibbs	uintmax_t uintmaxarg;
8165942Sgibbs	void	*pvoidarg;
8266269Sgibbs	char	*pchararg;
8365942Sgibbs	signed char *pschararg;
8465942Sgibbs	short	*pshortarg;
8565942Sgibbs	int	*pintarg;
8665942Sgibbs	long	*plongarg;
8765942Sgibbs	long long *plonglongarg;
8866269Sgibbs	ptrdiff_t *pptrdiffarg;
8965942Sgibbs	size_t	*psizearg;
9065942Sgibbs	intmax_t *pintmaxarg;
9165942Sgibbs#ifndef NO_FLOATING_POINT
9265942Sgibbs	double	doublearg;
9365942Sgibbs	long double longdoublearg;
9465942Sgibbs#endif
9565942Sgibbs	wint_t	wintarg;
9665942Sgibbs	wchar_t	*pwchararg;
9765942Sgibbs};
9865942Sgibbs
9965942Sgibbs/*
10065942Sgibbs * Type ids for argument type table.
10165942Sgibbs */
10265942Sgibbsenum typeid {
10365942Sgibbs	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
10465942Sgibbs	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
10565942Sgibbs	T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,
10665942Sgibbs	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
10765942Sgibbs	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
10865942Sgibbs};
10965942Sgibbs
11065942Sgibbsstatic int	__sprint(FILE *, struct __suio *);
11165942Sgibbsstatic int	__sbprintf(FILE *, const char *, va_list) __printflike(2, 0);
11265942Sgibbsstatic char	*__ujtoa(uintmax_t, char *, int, int, const char *, int, char,
11365942Sgibbs		    const char *);
11465942Sgibbsstatic char	*__ultoa(u_long, char *, int, int, const char *, int, char,
11565942Sgibbs		    const char *);
11665942Sgibbsstatic char	*__wcsconv(wchar_t *, int);
11765942Sgibbsstatic void	__find_arguments(const char *, va_list, union arg **);
11865942Sgibbsstatic void	__grow_type_table(int, enum typeid **, int *);
11965942Sgibbs
12065942Sgibbs/*
12165942Sgibbs * Flush out all the vectors defined by the given uio,
12265942Sgibbs * then reset it so that it can be reused.
12365942Sgibbs */
12465942Sgibbsstatic int
12565942Sgibbs__sprint(FILE *fp, struct __suio *uio)
12665942Sgibbs{
12765942Sgibbs	int err;
12865942Sgibbs
12965942Sgibbs	if (uio->uio_resid == 0) {
13065942Sgibbs		uio->uio_iovcnt = 0;
13165942Sgibbs		return (0);
13265942Sgibbs	}
13365942Sgibbs	err = __sfvwrite(fp, uio);
13465942Sgibbs	uio->uio_resid = 0;
13565942Sgibbs	uio->uio_iovcnt = 0;
13665942Sgibbs	return (err);
13765942Sgibbs}
13865942Sgibbs
13965942Sgibbs/*
14065942Sgibbs * Helper function for `fprintf to unbuffered unix file': creates a
14166647Sgibbs * temporary buffer.  We only work on write-only files; this avoids
14265942Sgibbs * worries about ungetc buffers and so forth.
14365942Sgibbs */
14465942Sgibbsstatic int
14565942Sgibbs__sbprintf(FILE *fp, const char *fmt, va_list ap)
14665942Sgibbs{
14765942Sgibbs	int ret;
14866104Sgibbs	FILE fake;
14966104Sgibbs	unsigned char buf[BUFSIZ];
15066647Sgibbs
15165942Sgibbs	/* copy the important variables */
15265942Sgibbs	fake._flags = fp->_flags & ~__SNBF;
15365942Sgibbs	fake._file = fp->_file;
15465942Sgibbs	fake._cookie = fp->_cookie;
15565942Sgibbs	fake._write = fp->_write;
15665942Sgibbs	fake._extra = fp->_extra;
15765942Sgibbs
15865942Sgibbs	/* set up the buffer */
15965942Sgibbs	fake._bf._base = fake._p = buf;
16065942Sgibbs	fake._bf._size = fake._w = sizeof(buf);
16165942Sgibbs	fake._lbfsize = 0;	/* not actually used, but Just In Case */
16265942Sgibbs
16365942Sgibbs	/* do the work, then copy any error status */
16465942Sgibbs	ret = __vfprintf(&fake, fmt, ap);
16565942Sgibbs	if (ret >= 0 && __fflush(&fake))
16665942Sgibbs		ret = EOF;
16765942Sgibbs	if (fake._flags & __SERR)
16865942Sgibbs		fp->_flags |= __SERR;
16965942Sgibbs	return (ret);
17065942Sgibbs}
17165942Sgibbs
17265942Sgibbs/*
17365942Sgibbs * Macros for converting digits to letters and vice versa
17465942Sgibbs */
17565942Sgibbs#define	to_digit(c)	((c) - '0')
17665942Sgibbs#define is_digit(c)	((unsigned)to_digit(c) <= 9)
17765942Sgibbs#define	to_char(n)	((n) + '0')
17865942Sgibbs
17965942Sgibbs/*
18065942Sgibbs * Convert an unsigned long to ASCII for printf purposes, returning
18166104Sgibbs * a pointer to the first character of the string representation.
18266647Sgibbs * Octal numbers can be forced to have a leading zero; hex numbers
18365942Sgibbs * use the given digits.
18465942Sgibbs */
18565942Sgibbsstatic char *
18665942Sgibbs__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs,
18765942Sgibbs	int needgrp, char thousep, const char *grp)
18865942Sgibbs{
18965942Sgibbs	char *cp = endp;
19065942Sgibbs	long sval;
19165942Sgibbs	int ndig;
19265942Sgibbs
19365942Sgibbs	/*
19465942Sgibbs	 * Handle the three cases separately, in the hope of getting
19565942Sgibbs	 * better/faster code.
19665942Sgibbs	 */
19765942Sgibbs	switch (base) {
19865942Sgibbs	case 10:
19965942Sgibbs		if (val < 10) {	/* many numbers are 1 digit */
20065942Sgibbs			*--cp = to_char(val);
20165942Sgibbs			return (cp);
20265942Sgibbs		}
20365942Sgibbs		ndig = 0;
20465942Sgibbs		/*
20565942Sgibbs		 * On many machines, unsigned arithmetic is harder than
20665942Sgibbs		 * signed arithmetic, so we do at most one unsigned mod and
20765942Sgibbs		 * divide; this is sufficient to reduce the range of
20865942Sgibbs		 * the incoming value to where signed arithmetic works.
20965942Sgibbs		 */
21065942Sgibbs		if (val > LONG_MAX) {
21165942Sgibbs			*--cp = to_char(val % 10);
21265942Sgibbs			ndig++;
21365942Sgibbs			sval = val / 10;
21465942Sgibbs		} else
21565942Sgibbs			sval = val;
21665942Sgibbs		do {
21765942Sgibbs			*--cp = to_char(sval % 10);
21865942Sgibbs			ndig++;
21965942Sgibbs			/*
22065942Sgibbs			 * If (*grp == CHAR_MAX) then no more grouping
22165942Sgibbs			 * should be performed.
22265942Sgibbs			 */
22365942Sgibbs			if (needgrp && ndig == *grp && *grp != CHAR_MAX
22465942Sgibbs					&& sval > 9) {
22565942Sgibbs				*--cp = thousep;
22665942Sgibbs				ndig = 0;
22765942Sgibbs				/*
22865942Sgibbs				 * If (*(grp+1) == '\0') then we have to
22965942Sgibbs				 * use *grp character (last grouping rule)
23065942Sgibbs				 * for all next cases
23165942Sgibbs				 */
23265942Sgibbs				if (*(grp+1) != '\0')
23365942Sgibbs					grp++;
23465942Sgibbs			}
23565942Sgibbs			sval /= 10;
23665942Sgibbs		} while (sval != 0);
23765942Sgibbs		break;
23865942Sgibbs
23965942Sgibbs	case 8:
24065942Sgibbs		do {
24165942Sgibbs			*--cp = to_char(val & 7);
24265942Sgibbs			val >>= 3;
24365942Sgibbs		} while (val);
24465942Sgibbs		if (octzero && *cp != '0')
24565942Sgibbs			*--cp = '0';
24665942Sgibbs		break;
24765942Sgibbs
24865942Sgibbs	case 16:
24965942Sgibbs		do {
25065942Sgibbs			*--cp = xdigs[val & 15];
25165942Sgibbs			val >>= 4;
25265942Sgibbs		} while (val);
25365942Sgibbs		break;
25465942Sgibbs
25565942Sgibbs	default:			/* oops */
25665942Sgibbs		abort();
25765942Sgibbs	}
25865942Sgibbs	return (cp);
25965942Sgibbs}
26065942Sgibbs
26165942Sgibbs/* Identical to __ultoa, but for intmax_t. */
26265942Sgibbsstatic char *
26365942Sgibbs__ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs,
26465942Sgibbs	int needgrp, char thousep, const char *grp)
26565942Sgibbs{
26665942Sgibbs	char *cp = endp;
26765942Sgibbs	intmax_t sval;
26865942Sgibbs	int ndig;
26965942Sgibbs
27065942Sgibbs	/* quick test for small values; __ultoa is typically much faster */
27165942Sgibbs	/* (perhaps instead we should run until small, then call __ultoa?) */
27265942Sgibbs	if (val <= ULONG_MAX)
27365942Sgibbs		return (__ultoa((u_long)val, endp, base, octzero, xdigs,
27465942Sgibbs		    needgrp, thousep, grp));
27565942Sgibbs	switch (base) {
27665942Sgibbs	case 10:
27765942Sgibbs		if (val < 10) {
27865942Sgibbs			*--cp = to_char(val % 10);
27965942Sgibbs			return (cp);
28065942Sgibbs		}
28165942Sgibbs		ndig = 0;
28265942Sgibbs		if (val > INTMAX_MAX) {
28365942Sgibbs			*--cp = to_char(val % 10);
28465942Sgibbs			ndig++;
28565942Sgibbs			sval = val / 10;
28665942Sgibbs		} else
28765942Sgibbs			sval = val;
28865942Sgibbs		do {
28965942Sgibbs			*--cp = to_char(sval % 10);
29065942Sgibbs			ndig++;
29165942Sgibbs			/*
29265942Sgibbs			 * If (*grp == CHAR_MAX) then no more grouping
29365942Sgibbs			 * should be performed.
29465942Sgibbs			 */
29565942Sgibbs			if (needgrp && *grp != CHAR_MAX && ndig == *grp
29665942Sgibbs					&& sval > 9) {
29765942Sgibbs				*--cp = thousep;
29865942Sgibbs				ndig = 0;
29965942Sgibbs				/*
30065942Sgibbs				 * If (*(grp+1) == '\0') then we have to
30165942Sgibbs				 * use *grp character (last grouping rule)
30265942Sgibbs				 * for all next cases
30365942Sgibbs				 */
30465942Sgibbs				if (*(grp+1) != '\0')
30565942Sgibbs					grp++;
30665942Sgibbs			}
30765942Sgibbs			sval /= 10;
30865942Sgibbs		} while (sval != 0);
30965942Sgibbs		break;
31065942Sgibbs
31165942Sgibbs	case 8:
31265942Sgibbs		do {
31365942Sgibbs			*--cp = to_char(val & 7);
31465942Sgibbs			val >>= 3;
31565942Sgibbs		} while (val);
31665942Sgibbs		if (octzero && *cp != '0')
31765942Sgibbs			*--cp = '0';
31865942Sgibbs		break;
31965942Sgibbs
32065942Sgibbs	case 16:
32165942Sgibbs		do {
32265942Sgibbs			*--cp = xdigs[val & 15];
32365942Sgibbs			val >>= 4;
32465942Sgibbs		} while (val);
32565942Sgibbs		break;
32665942Sgibbs
32765942Sgibbs	default:
32865942Sgibbs		abort();
32965942Sgibbs	}
33065942Sgibbs	return (cp);
33165942Sgibbs}
33265942Sgibbs
33365942Sgibbs/*
33465942Sgibbs * Convert a wide character string argument for the %ls format to a multibyte
33565942Sgibbs * string representation. If not -1, prec specifies the maximum number of
33665942Sgibbs * bytes to output, and also means that we can't assume that the wide char.
33765942Sgibbs * string ends is null-terminated.
33865942Sgibbs */
33965942Sgibbsstatic char *
34065942Sgibbs__wcsconv(wchar_t *wcsarg, int prec)
34165942Sgibbs{
34265942Sgibbs	static const mbstate_t initial;
34365942Sgibbs	mbstate_t mbs;
34465942Sgibbs	char buf[MB_LEN_MAX];
34565942Sgibbs	wchar_t *p;
34665942Sgibbs	char *convbuf;
34765942Sgibbs	size_t clen, nbytes;
34865942Sgibbs
34965942Sgibbs	/* Allocate space for the maximum number of bytes we could output. */
35065942Sgibbs	if (prec < 0) {
35165942Sgibbs		p = wcsarg;
35265942Sgibbs		mbs = initial;
35365942Sgibbs		nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
35465942Sgibbs		if (nbytes == (size_t)-1)
35565942Sgibbs			return (NULL);
35665942Sgibbs	} else {
35765942Sgibbs		/*
35865942Sgibbs		 * Optimisation: if the output precision is small enough,
35965942Sgibbs		 * just allocate enough memory for the maximum instead of
36065942Sgibbs		 * scanning the string.
36165942Sgibbs		 */
36265942Sgibbs		if (prec < 128)
36365942Sgibbs			nbytes = prec;
36465942Sgibbs		else {
36565942Sgibbs			nbytes = 0;
36665942Sgibbs			p = wcsarg;
36765942Sgibbs			mbs = initial;
36865942Sgibbs			for (;;) {
36965942Sgibbs				clen = wcrtomb(buf, *p++, &mbs);
37065942Sgibbs				if (clen == 0 || clen == (size_t)-1 ||
37165942Sgibbs				    nbytes + clen > prec)
37265942Sgibbs					break;
37365942Sgibbs				nbytes += clen;
37465942Sgibbs			}
37565942Sgibbs		}
37665942Sgibbs	}
37765942Sgibbs	if ((convbuf = malloc(nbytes + 1)) == NULL)
37865942Sgibbs		return (NULL);
37965942Sgibbs
38065942Sgibbs	/* Fill the output buffer. */
38165942Sgibbs	p = wcsarg;
38265942Sgibbs	mbs = initial;
38365942Sgibbs	if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
38465942Sgibbs	    nbytes, &mbs)) == (size_t)-1) {
38565942Sgibbs		free(convbuf);
38665942Sgibbs		return (NULL);
38765942Sgibbs	}
38865942Sgibbs	convbuf[nbytes] = '\0';
38965942Sgibbs	return (convbuf);
39065942Sgibbs}
39165942Sgibbs
39265942Sgibbs/*
39365942Sgibbs * MT-safe version
39465942Sgibbs */
39565942Sgibbsint
39665942Sgibbsvfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
39765942Sgibbs
39865942Sgibbs{
39965942Sgibbs	int ret;
40065942Sgibbs
40165942Sgibbs	FLOCKFILE(fp);
40265942Sgibbs	ret = __vfprintf(fp, fmt0, ap);
40365942Sgibbs	FUNLOCKFILE(fp);
40465942Sgibbs	return (ret);
40565942Sgibbs}
40665942Sgibbs
40765942Sgibbs#ifndef NO_FLOATING_POINT
40865942Sgibbs
40965942Sgibbs#define	dtoa		__dtoa
41065942Sgibbs#define	freedtoa	__freedtoa
41165942Sgibbs
41265942Sgibbs#include <float.h>
41365942Sgibbs#include <math.h>
41465942Sgibbs#include "floatio.h"
41565942Sgibbs#include "gdtoa.h"
41665942Sgibbs
41765942Sgibbs#define	DEFPREC		6
41865942Sgibbs
41965942Sgibbsstatic int exponent(char *, int, int);
42065942Sgibbs
42165942Sgibbs#endif /* !NO_FLOATING_POINT */
42265942Sgibbs
42365942Sgibbs/*
42465942Sgibbs * The size of the buffer we use as scratch space for integer
42565942Sgibbs * conversions, among other things.  Technically, we would need the
42665942Sgibbs * most space for base 10 conversions with thousands' grouping
42765942Sgibbs * characters between each pair of digits.  100 bytes is a
42865942Sgibbs * conservative overestimate even for a 128-bit uintmax_t.
42965942Sgibbs */
43065942Sgibbs#define	BUF	100
43165942Sgibbs
43265942Sgibbs#define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
43365942Sgibbs
43465942Sgibbs/*
43565942Sgibbs * Flags used during conversion.
43665942Sgibbs */
43765942Sgibbs#define	ALT		0x001		/* alternate form */
43865942Sgibbs#define	LADJUST		0x004		/* left adjustment */
43965942Sgibbs#define	LONGDBL		0x008		/* long double */
44065942Sgibbs#define	LONGINT		0x010		/* long integer */
44165942Sgibbs#define	LLONGINT	0x020		/* long long integer */
44266510Sgibbs#define	SHORTINT	0x040		/* short integer */
44365942Sgibbs#define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
44465942Sgibbs#define	FPT		0x100		/* Floating point number */
44565942Sgibbs#define	GROUPING	0x200		/* use grouping ("'" flag) */
44665942Sgibbs					/* C99 additional size modifiers: */
44765942Sgibbs#define	SIZET		0x400		/* size_t */
44865942Sgibbs#define	PTRDIFFT	0x800		/* ptrdiff_t */
44965942Sgibbs#define	INTMAXT		0x1000		/* intmax_t */
45065942Sgibbs#define	CHARINT		0x2000		/* print char using int format */
45165942Sgibbs
45265942Sgibbs/*
45365942Sgibbs * Non-MT-safe version
45465942Sgibbs */
45565942Sgibbsint
45665942Sgibbs__vfprintf(FILE *fp, const char *fmt0, va_list ap)
45765942Sgibbs{
45865942Sgibbs	char *fmt;		/* format string */
45965942Sgibbs	int ch;			/* character from fmt */
46065942Sgibbs	int n, n2;		/* handy integer (short term usage) */
46165942Sgibbs	char *cp;		/* handy char pointer (short term usage) */
46265942Sgibbs	struct __siov *iovp;	/* for PRINT macro */
46365942Sgibbs	int flags;		/* flags as above */
46465942Sgibbs	int ret;		/* return value accumulator */
46565942Sgibbs	int width;		/* width from format (%8d), or 0 */
46665942Sgibbs	int prec;		/* precision from format; <0 for N/A */
46765942Sgibbs	char sign;		/* sign prefix (' ', '+', '-', or \0) */
46865942Sgibbs	char thousands_sep;	/* locale specific thousands separator */
46965942Sgibbs	const char *grouping;	/* locale specific numeric grouping rules */
47065942Sgibbs
47165942Sgibbs	if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
47265942Sgibbs		__use_xprintf = 1;
47365942Sgibbs	if (__use_xprintf > 0)
47465942Sgibbs		return (__xvprintf(fp, fmt0, ap));
47565942Sgibbs
47665942Sgibbs#ifndef NO_FLOATING_POINT
47765942Sgibbs	/*
47865942Sgibbs	 * We can decompose the printed representation of floating
47965942Sgibbs	 * point numbers into several parts, some of which may be empty:
48065942Sgibbs	 *
48165942Sgibbs	 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
48265942Sgibbs	 *    A       B     ---C---      D       E   F
48365942Sgibbs	 *
48465942Sgibbs	 * A:	'sign' holds this value if present; '\0' otherwise
48565942Sgibbs	 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
48665942Sgibbs	 * C:	cp points to the string MMMNNN.  Leading and trailing
48765942Sgibbs	 *	zeros are not in the string and must be added.
48865942Sgibbs	 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
48965942Sgibbs	 * F:	at least two digits for decimal, at least one digit for hex
49065942Sgibbs	 */
49165942Sgibbs	char *decimal_point;	/* locale specific decimal point */
49265942Sgibbs	int signflag;		/* true if float is negative */
49365942Sgibbs	union {			/* floating point arguments %[aAeEfFgG] */
49465942Sgibbs		double dbl;
49565942Sgibbs		long double ldbl;
49665942Sgibbs	} fparg;
49765942Sgibbs	int expt;		/* integer value of exponent */
49865942Sgibbs	char expchar;		/* exponent character: [eEpP\0] */
49965942Sgibbs	char *dtoaend;		/* pointer to end of converted digits */
50065942Sgibbs	int expsize;		/* character count for expstr */
50165942Sgibbs	int lead;		/* sig figs before decimal or group sep */
50265942Sgibbs	int ndig;		/* actual number of digits returned by dtoa */
50365942Sgibbs	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
50465942Sgibbs	char *dtoaresult;	/* buffer allocated by dtoa */
50565942Sgibbs	int nseps;		/* number of group separators with ' */
50665942Sgibbs	int nrepeats;		/* number of repeats of the last group */
50765942Sgibbs#endif
50865942Sgibbs	u_long	ulval;		/* integer arguments %[diouxX] */
50965942Sgibbs	uintmax_t ujval;	/* %j, %ll, %q, %t, %z integers */
51065942Sgibbs	int base;		/* base for [diouxX] conversion */
51165942Sgibbs	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
51265942Sgibbs	int realsz;		/* field size expanded by dprec, sign, etc */
51365942Sgibbs	int size;		/* size of converted field or string */
51465942Sgibbs	int prsize;             /* max size of printed field */
51565942Sgibbs	const char *xdigs;     	/* digits for %[xX] conversion */
51665942Sgibbs#define NIOV 8
51765942Sgibbs	struct __suio uio;	/* output information: summary */
51865942Sgibbs	struct __siov iov[NIOV];/* ... and individual io vectors */
51965942Sgibbs	char buf[BUF];		/* buffer with space for digits of uintmax_t */
52065942Sgibbs	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
52165942Sgibbs	union arg *argtable;    /* args, built due to positional arg */
52265942Sgibbs	union arg statargtable [STATIC_ARG_TBL_SIZE];
52365942Sgibbs	int nextarg;            /* 1-based argument index */
52465942Sgibbs	va_list orgap;          /* original argument pointer */
52565942Sgibbs	char *convbuf;		/* wide to multibyte conversion result */
52665942Sgibbs
52765942Sgibbs	/*
52865942Sgibbs	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
52965942Sgibbs	 * fields occur frequently, increase PADSIZE and make the initialisers
53065942Sgibbs	 * below longer.
53165942Sgibbs	 */
53265942Sgibbs#define	PADSIZE	16		/* pad chunk size */
53365942Sgibbs	static char blanks[PADSIZE] =
53465942Sgibbs	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
53565942Sgibbs	static char zeroes[PADSIZE] =
53665942Sgibbs	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
53765942Sgibbs
53865942Sgibbs	static const char xdigs_lower[16] = "0123456789abcdef";
53965942Sgibbs	static const char xdigs_upper[16] = "0123456789ABCDEF";
54065942Sgibbs
54165942Sgibbs	/*
54265942Sgibbs	 * BEWARE, these `goto error' on error, and PAD uses `n'.
54365942Sgibbs	 */
54465942Sgibbs#define	PRINT(ptr, len) { \
54565942Sgibbs	iovp->iov_base = (ptr); \
54665942Sgibbs	iovp->iov_len = (len); \
54765942Sgibbs	uio.uio_resid += (len); \
54865942Sgibbs	iovp++; \
54965942Sgibbs	if (++uio.uio_iovcnt >= NIOV) { \
55065942Sgibbs		if (__sprint(fp, &uio)) \
55165942Sgibbs			goto error; \
55265942Sgibbs		iovp = iov; \
55365942Sgibbs	} \
55465942Sgibbs}
55565942Sgibbs#define	PAD(howmany, with) { \
55665942Sgibbs	if ((n = (howmany)) > 0) { \
55765942Sgibbs		while (n > PADSIZE) { \
55865942Sgibbs			PRINT(with, PADSIZE); \
55965942Sgibbs			n -= PADSIZE; \
56065942Sgibbs		} \
56165942Sgibbs		PRINT(with, n); \
56265942Sgibbs	} \
56365942Sgibbs}
56465942Sgibbs#define	PRINTANDPAD(p, ep, len, with) do {	\
56565942Sgibbs	n2 = (ep) - (p);       			\
56665942Sgibbs	if (n2 > (len))				\
56765942Sgibbs		n2 = (len);			\
56865942Sgibbs	if (n2 > 0)				\
56965942Sgibbs		PRINT((p), n2);			\
57065942Sgibbs	PAD((len) - (n2 > 0 ? n2 : 0), (with));	\
57165942Sgibbs} while(0)
57265942Sgibbs#define	FLUSH() { \
57365942Sgibbs	if (uio.uio_resid && __sprint(fp, &uio)) \
57465942Sgibbs		goto error; \
57565942Sgibbs	uio.uio_iovcnt = 0; \
57665942Sgibbs	iovp = iov; \
57765942Sgibbs}
57865942Sgibbs
57965942Sgibbs	/*
58065942Sgibbs	 * Get the argument indexed by nextarg.   If the argument table is
58165942Sgibbs	 * built, use it to get the argument.  If its not, get the next
58265942Sgibbs	 * argument (and arguments must be gotten sequentially).
58365942Sgibbs	 */
58465942Sgibbs#define GETARG(type) \
58565942Sgibbs	((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
58665942Sgibbs	    (nextarg++, va_arg(ap, type)))
58765942Sgibbs
58865942Sgibbs	/*
58965942Sgibbs	 * To extend shorts properly, we need both signed and unsigned
59065942Sgibbs	 * argument extraction methods.
59165942Sgibbs	 */
59265942Sgibbs#define	SARG() \
59365942Sgibbs	(flags&LONGINT ? GETARG(long) : \
59465942Sgibbs	    flags&SHORTINT ? (long)(short)GETARG(int) : \
59565942Sgibbs	    flags&CHARINT ? (long)(signed char)GETARG(int) : \
59665942Sgibbs	    (long)GETARG(int))
59765942Sgibbs#define	UARG() \
59865942Sgibbs	(flags&LONGINT ? GETARG(u_long) : \
59965942Sgibbs	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
60065942Sgibbs	    flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
60165942Sgibbs	    (u_long)GETARG(u_int))
60265942Sgibbs#define	INTMAX_SIZE	(INTMAXT|SIZET|PTRDIFFT|LLONGINT)
60365942Sgibbs#define SJARG() \
60465942Sgibbs	(flags&INTMAXT ? GETARG(intmax_t) : \
60565942Sgibbs	    flags&SIZET ? (intmax_t)GETARG(size_t) : \
60665942Sgibbs	    flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
60765942Sgibbs	    (intmax_t)GETARG(long long))
60865942Sgibbs#define	UJARG() \
60965942Sgibbs	(flags&INTMAXT ? GETARG(uintmax_t) : \
61065942Sgibbs	    flags&SIZET ? (uintmax_t)GETARG(size_t) : \
61165942Sgibbs	    flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
61265942Sgibbs	    (uintmax_t)GETARG(unsigned long long))
61365942Sgibbs
61465942Sgibbs	/*
61565942Sgibbs	 * Get * arguments, including the form *nn$.  Preserve the nextarg
61665942Sgibbs	 * that the argument can be gotten once the type is determined.
61765942Sgibbs	 */
61865942Sgibbs#define GETASTER(val) \
61965942Sgibbs	n2 = 0; \
62065942Sgibbs	cp = fmt; \
62165942Sgibbs	while (is_digit(*cp)) { \
62265942Sgibbs		n2 = 10 * n2 + to_digit(*cp); \
62365942Sgibbs		cp++; \
62465942Sgibbs	} \
62565942Sgibbs	if (*cp == '$') { \
62665942Sgibbs		int hold = nextarg; \
62765942Sgibbs		if (argtable == NULL) { \
62865942Sgibbs			argtable = statargtable; \
62965942Sgibbs			__find_arguments (fmt0, orgap, &argtable); \
63065942Sgibbs		} \
63165942Sgibbs		nextarg = n2; \
63265942Sgibbs		val = GETARG (int); \
63365942Sgibbs		nextarg = hold; \
63465942Sgibbs		fmt = ++cp; \
63565942Sgibbs	} else { \
63665942Sgibbs		val = GETARG (int); \
63765942Sgibbs	}
63865942Sgibbs
63965942Sgibbs
64065942Sgibbs	thousands_sep = '\0';
64165942Sgibbs	grouping = NULL;
64265942Sgibbs	convbuf = NULL;
64365942Sgibbs#ifndef NO_FLOATING_POINT
64465942Sgibbs	dtoaresult = NULL;
64565942Sgibbs	decimal_point = localeconv()->decimal_point;
64665942Sgibbs#endif
64765942Sgibbs	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
64865942Sgibbs	if (prepwrite(fp) != 0)
64965942Sgibbs		return (EOF);
65065942Sgibbs
65165942Sgibbs	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
65265942Sgibbs	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
65365942Sgibbs	    fp->_file >= 0)
65465942Sgibbs		return (__sbprintf(fp, fmt0, ap));
65565942Sgibbs
65665942Sgibbs	fmt = (char *)fmt0;
65765942Sgibbs	argtable = NULL;
65865942Sgibbs	nextarg = 1;
65965942Sgibbs	va_copy(orgap, ap);
66065942Sgibbs	uio.uio_iov = iovp = iov;
66165942Sgibbs	uio.uio_resid = 0;
66265942Sgibbs	uio.uio_iovcnt = 0;
66365942Sgibbs	ret = 0;
66465942Sgibbs
66565942Sgibbs	/*
66665942Sgibbs	 * Scan the format for conversions (`%' character).
66765942Sgibbs	 */
66865942Sgibbs	for (;;) {
66965942Sgibbs		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
67065942Sgibbs			/* void */;
67165942Sgibbs		if ((n = fmt - cp) != 0) {
67265942Sgibbs			if ((unsigned)ret + n > INT_MAX) {
67365942Sgibbs				ret = EOF;
67465942Sgibbs				goto error;
67565942Sgibbs			}
67665942Sgibbs			PRINT(cp, n);
67765942Sgibbs			ret += n;
67865942Sgibbs		}
67965942Sgibbs		if (ch == '\0')
68065942Sgibbs			goto done;
68165942Sgibbs		fmt++;		/* skip over '%' */
68265942Sgibbs
68365942Sgibbs		flags = 0;
68465942Sgibbs		dprec = 0;
68565942Sgibbs		width = 0;
68665942Sgibbs		prec = -1;
68765942Sgibbs		sign = '\0';
68865942Sgibbs		ox[1] = '\0';
68965942Sgibbs
69065942Sgibbsrflag:		ch = *fmt++;
69165942Sgibbsreswitch:	switch (ch) {
69265942Sgibbs		case ' ':
69365942Sgibbs			/*-
69465942Sgibbs			 * ``If the space and + flags both appear, the space
69565942Sgibbs			 * flag will be ignored.''
69665942Sgibbs			 *	-- ANSI X3J11
69765942Sgibbs			 */
69865942Sgibbs			if (!sign)
69965942Sgibbs				sign = ' ';
70065942Sgibbs			goto rflag;
70165942Sgibbs		case '#':
70265942Sgibbs			flags |= ALT;
70365942Sgibbs			goto rflag;
70465942Sgibbs		case '*':
70565942Sgibbs			/*-
70665942Sgibbs			 * ``A negative field width argument is taken as a
70765942Sgibbs			 * - flag followed by a positive field width.''
70865942Sgibbs			 *	-- ANSI X3J11
70965942Sgibbs			 * They don't exclude field widths read from args.
71065942Sgibbs			 */
71165942Sgibbs			GETASTER (width);
71265942Sgibbs			if (width >= 0)
71365942Sgibbs				goto rflag;
71465942Sgibbs			width = -width;
71565942Sgibbs			/* FALLTHROUGH */
71665942Sgibbs		case '-':
71765942Sgibbs			flags |= LADJUST;
71865942Sgibbs			goto rflag;
71965942Sgibbs		case '+':
72065942Sgibbs			sign = '+';
72165942Sgibbs			goto rflag;
72265942Sgibbs		case '\'':
72365942Sgibbs			flags |= GROUPING;
72465942Sgibbs			thousands_sep = *(localeconv()->thousands_sep);
72565942Sgibbs			grouping = localeconv()->grouping;
72665942Sgibbs			goto rflag;
72765942Sgibbs		case '.':
72865942Sgibbs			if ((ch = *fmt++) == '*') {
72965942Sgibbs				GETASTER (prec);
73065942Sgibbs				goto rflag;
73165942Sgibbs			}
73265942Sgibbs			prec = 0;
73365942Sgibbs			while (is_digit(ch)) {
73465942Sgibbs				prec = 10 * prec + to_digit(ch);
73565942Sgibbs				ch = *fmt++;
73665942Sgibbs			}
73765942Sgibbs			goto reswitch;
73865942Sgibbs		case '0':
73965942Sgibbs			/*-
74065942Sgibbs			 * ``Note that 0 is taken as a flag, not as the
74165942Sgibbs			 * beginning of a field width.''
74265942Sgibbs			 *	-- ANSI X3J11
74365942Sgibbs			 */
74465942Sgibbs			flags |= ZEROPAD;
74565942Sgibbs			goto rflag;
74665942Sgibbs		case '1': case '2': case '3': case '4':
74765942Sgibbs		case '5': case '6': case '7': case '8': case '9':
74865942Sgibbs			n = 0;
74965942Sgibbs			do {
75065942Sgibbs				n = 10 * n + to_digit(ch);
75165942Sgibbs				ch = *fmt++;
75265942Sgibbs			} while (is_digit(ch));
75365942Sgibbs			if (ch == '$') {
75465942Sgibbs				nextarg = n;
75565942Sgibbs				if (argtable == NULL) {
75665942Sgibbs					argtable = statargtable;
75765942Sgibbs					__find_arguments (fmt0, orgap,
75865942Sgibbs					    &argtable);
75965942Sgibbs				}
76065942Sgibbs				goto rflag;
76165942Sgibbs			}
76265942Sgibbs			width = n;
76365942Sgibbs			goto reswitch;
76465942Sgibbs#ifndef NO_FLOATING_POINT
76565942Sgibbs		case 'L':
76665942Sgibbs			flags |= LONGDBL;
76765942Sgibbs			goto rflag;
76865942Sgibbs#endif
76965942Sgibbs		case 'h':
77065942Sgibbs			if (flags & SHORTINT) {
77165942Sgibbs				flags &= ~SHORTINT;
77265942Sgibbs				flags |= CHARINT;
77365942Sgibbs			} else
77465942Sgibbs				flags |= SHORTINT;
77565942Sgibbs			goto rflag;
77665942Sgibbs		case 'j':
77765942Sgibbs			flags |= INTMAXT;
77865942Sgibbs			goto rflag;
77965942Sgibbs		case 'l':
78065942Sgibbs			if (flags & LONGINT) {
78165942Sgibbs				flags &= ~LONGINT;
78265942Sgibbs				flags |= LLONGINT;
78365942Sgibbs			} else
78465942Sgibbs				flags |= LONGINT;
78565942Sgibbs			goto rflag;
78665942Sgibbs		case 'q':
78765942Sgibbs			flags |= LLONGINT;	/* not necessarily */
78865942Sgibbs			goto rflag;
78965942Sgibbs		case 't':
79065942Sgibbs			flags |= PTRDIFFT;
79165942Sgibbs			goto rflag;
79265942Sgibbs		case 'z':
79365942Sgibbs			flags |= SIZET;
79465942Sgibbs			goto rflag;
79565942Sgibbs		case 'C':
79665942Sgibbs			flags |= LONGINT;
79765942Sgibbs			/*FALLTHROUGH*/
79865942Sgibbs		case 'c':
79965942Sgibbs			if (flags & LONGINT) {
80065942Sgibbs				static const mbstate_t initial;
80165942Sgibbs				mbstate_t mbs;
80265942Sgibbs				size_t mbseqlen;
80365942Sgibbs
80465942Sgibbs				mbs = initial;
80565942Sgibbs				mbseqlen = wcrtomb(cp = buf,
80665942Sgibbs				    (wchar_t)GETARG(wint_t), &mbs);
80765942Sgibbs				if (mbseqlen == (size_t)-1) {
80865942Sgibbs					fp->_flags |= __SERR;
80965942Sgibbs					goto error;
81065942Sgibbs				}
81165942Sgibbs				size = (int)mbseqlen;
81265942Sgibbs			} else {
81365942Sgibbs				*(cp = buf) = GETARG(int);
81465942Sgibbs				size = 1;
81565942Sgibbs			}
81665942Sgibbs			sign = '\0';
81765942Sgibbs			break;
81865942Sgibbs		case 'D':
81965942Sgibbs			flags |= LONGINT;
82065942Sgibbs			/*FALLTHROUGH*/
82165942Sgibbs		case 'd':
82265942Sgibbs		case 'i':
82365942Sgibbs			if (flags & INTMAX_SIZE) {
82465942Sgibbs				ujval = SJARG();
82565942Sgibbs				if ((intmax_t)ujval < 0) {
82665942Sgibbs					ujval = -ujval;
82765942Sgibbs					sign = '-';
82865942Sgibbs				}
82965942Sgibbs			} else {
83065942Sgibbs				ulval = SARG();
83165942Sgibbs				if ((long)ulval < 0) {
83265942Sgibbs					ulval = -ulval;
83365942Sgibbs					sign = '-';
83465942Sgibbs				}
83565942Sgibbs			}
83665942Sgibbs			base = 10;
83765942Sgibbs			goto number;
83865942Sgibbs#ifndef NO_FLOATING_POINT
83965942Sgibbs		case 'a':
84065942Sgibbs		case 'A':
84165942Sgibbs			if (ch == 'a') {
84265942Sgibbs				ox[1] = 'x';
84365942Sgibbs				xdigs = xdigs_lower;
84465942Sgibbs				expchar = 'p';
84565942Sgibbs			} else {
84665942Sgibbs				ox[1] = 'X';
84765942Sgibbs				xdigs = xdigs_upper;
84865942Sgibbs				expchar = 'P';
84965942Sgibbs			}
85065942Sgibbs			if (prec >= 0)
85165942Sgibbs				prec++;
85265942Sgibbs			if (dtoaresult != NULL)
85365942Sgibbs				freedtoa(dtoaresult);
85465942Sgibbs			if (flags & LONGDBL) {
85565942Sgibbs				fparg.ldbl = GETARG(long double);
85665942Sgibbs				dtoaresult = cp =
85765942Sgibbs				    __hldtoa(fparg.ldbl, xdigs, prec,
85865942Sgibbs				    &expt, &signflag, &dtoaend);
85965942Sgibbs			} else {
86065942Sgibbs				fparg.dbl = GETARG(double);
86165942Sgibbs				dtoaresult = cp =
86265942Sgibbs				    __hdtoa(fparg.dbl, xdigs, prec,
86365942Sgibbs				    &expt, &signflag, &dtoaend);
86465942Sgibbs			}
86565942Sgibbs			if (prec < 0)
86665942Sgibbs				prec = dtoaend - cp;
86765942Sgibbs			if (expt == INT_MAX)
86865942Sgibbs				ox[1] = '\0';
86965942Sgibbs			goto fp_common;
87065942Sgibbs		case 'e':
87165942Sgibbs		case 'E':
87265942Sgibbs			expchar = ch;
87365942Sgibbs			if (prec < 0)	/* account for digit before decpt */
87465942Sgibbs				prec = DEFPREC + 1;
87565942Sgibbs			else
87665942Sgibbs				prec++;
87765942Sgibbs			goto fp_begin;
87865942Sgibbs		case 'f':
87965942Sgibbs		case 'F':
88065942Sgibbs			expchar = '\0';
88165942Sgibbs			goto fp_begin;
88265942Sgibbs		case 'g':
88365942Sgibbs		case 'G':
88465942Sgibbs			expchar = ch - ('g' - 'e');
88565942Sgibbs			if (prec == 0)
88665942Sgibbs				prec = 1;
88765942Sgibbsfp_begin:
88865942Sgibbs			if (prec < 0)
88965942Sgibbs				prec = DEFPREC;
89065942Sgibbs			if (dtoaresult != NULL)
89165942Sgibbs				freedtoa(dtoaresult);
89265942Sgibbs			if (flags & LONGDBL) {
89365942Sgibbs				fparg.ldbl = GETARG(long double);
89465942Sgibbs				dtoaresult = cp =
89565942Sgibbs				    __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
89665942Sgibbs				    &expt, &signflag, &dtoaend);
89765942Sgibbs			} else {
89865942Sgibbs				fparg.dbl = GETARG(double);
89965942Sgibbs				dtoaresult = cp =
90065942Sgibbs				    dtoa(fparg.dbl, expchar ? 2 : 3, prec,
90165942Sgibbs				    &expt, &signflag, &dtoaend);
90265942Sgibbs				if (expt == 9999)
90365942Sgibbs					expt = INT_MAX;
90465942Sgibbs			}
90565942Sgibbsfp_common:
90665942Sgibbs			if (signflag)
90765942Sgibbs				sign = '-';
90865942Sgibbs			if (expt == INT_MAX) {	/* inf or nan */
90965942Sgibbs				if (*cp == 'N') {
91065942Sgibbs					cp = (ch >= 'a') ? "nan" : "NAN";
91165942Sgibbs					sign = '\0';
91265942Sgibbs				} else
91365942Sgibbs					cp = (ch >= 'a') ? "inf" : "INF";
91465942Sgibbs				size = 3;
91565942Sgibbs				break;
91665942Sgibbs			}
91765942Sgibbs			flags |= FPT;
91865942Sgibbs			ndig = dtoaend - cp;
91965942Sgibbs			if (ch == 'g' || ch == 'G') {
92065942Sgibbs				if (expt > -4 && expt <= prec) {
92165942Sgibbs					/* Make %[gG] smell like %[fF] */
92265942Sgibbs					expchar = '\0';
92365942Sgibbs					if (flags & ALT)
92465942Sgibbs						prec -= expt;
92565942Sgibbs					else
92665942Sgibbs						prec = ndig - expt;
92765942Sgibbs					if (prec < 0)
92865942Sgibbs						prec = 0;
92965942Sgibbs				} else {
93065942Sgibbs					/*
93165942Sgibbs					 * Make %[gG] smell like %[eE], but
93265942Sgibbs					 * trim trailing zeroes if no # flag.
93365942Sgibbs					 */
93465942Sgibbs					if (!(flags & ALT))
93565942Sgibbs						prec = ndig;
93665942Sgibbs				}
93765942Sgibbs			}
93865942Sgibbs			if (expchar) {
93965942Sgibbs				expsize = exponent(expstr, expt - 1, expchar);
94065942Sgibbs				size = expsize + prec;
94165942Sgibbs				if (prec > 1 || flags & ALT)
94265942Sgibbs					++size;
94365942Sgibbs			} else {
94465942Sgibbs				/* space for digits before decimal point */
94565942Sgibbs				if (expt > 0)
94665942Sgibbs					size = expt;
94765942Sgibbs				else	/* "0" */
94865942Sgibbs					size = 1;
94965942Sgibbs				/* space for decimal pt and following digits */
95065942Sgibbs				if (prec || flags & ALT)
95165942Sgibbs					size += prec + 1;
95265942Sgibbs				if (grouping && expt > 0) {
95365942Sgibbs					/* space for thousands' grouping */
95465942Sgibbs					nseps = nrepeats = 0;
95565942Sgibbs					lead = expt;
95665942Sgibbs					while (*grouping != CHAR_MAX) {
95765942Sgibbs						if (lead <= *grouping)
95865942Sgibbs							break;
95965942Sgibbs						lead -= *grouping;
96065942Sgibbs						if (*(grouping+1)) {
96165942Sgibbs							nseps++;
96265942Sgibbs							grouping++;
96365942Sgibbs						} else
96465942Sgibbs							nrepeats++;
96565942Sgibbs					}
96665942Sgibbs					size += nseps + nrepeats;
96765942Sgibbs				} else
96865942Sgibbs					lead = expt;
96965942Sgibbs			}
97065942Sgibbs			break;
97165942Sgibbs#endif /* !NO_FLOATING_POINT */
97265942Sgibbs		case 'n':
97365942Sgibbs			/*
97465942Sgibbs			 * Assignment-like behavior is specified if the
97565942Sgibbs			 * value overflows or is otherwise unrepresentable.
97665942Sgibbs			 * C99 says to use `signed char' for %hhn conversions.
97765942Sgibbs			 */
97865942Sgibbs			if (flags & LLONGINT)
97965942Sgibbs				*GETARG(long long *) = ret;
98065942Sgibbs			else if (flags & SIZET)
98165942Sgibbs				*GETARG(ssize_t *) = (ssize_t)ret;
98265942Sgibbs			else if (flags & PTRDIFFT)
98365942Sgibbs				*GETARG(ptrdiff_t *) = ret;
98465942Sgibbs			else if (flags & INTMAXT)
98565942Sgibbs				*GETARG(intmax_t *) = ret;
98665942Sgibbs			else if (flags & LONGINT)
98765942Sgibbs				*GETARG(long *) = ret;
98865942Sgibbs			else if (flags & SHORTINT)
98965942Sgibbs				*GETARG(short *) = ret;
99065942Sgibbs			else if (flags & CHARINT)
99165942Sgibbs				*GETARG(signed char *) = ret;
99265942Sgibbs			else
99365942Sgibbs				*GETARG(int *) = ret;
99465942Sgibbs			continue;	/* no output */
99565942Sgibbs		case 'O':
99665942Sgibbs			flags |= LONGINT;
99765942Sgibbs			/*FALLTHROUGH*/
99865942Sgibbs		case 'o':
99965942Sgibbs			if (flags & INTMAX_SIZE)
100065942Sgibbs				ujval = UJARG();
100165942Sgibbs			else
100265942Sgibbs				ulval = UARG();
100365942Sgibbs			base = 8;
100465942Sgibbs			goto nosign;
100565942Sgibbs		case 'p':
100665942Sgibbs			/*-
100765942Sgibbs			 * ``The argument shall be a pointer to void.  The
100865942Sgibbs			 * value of the pointer is converted to a sequence
100965942Sgibbs			 * of printable characters, in an implementation-
101065942Sgibbs			 * defined manner.''
101165942Sgibbs			 *	-- ANSI X3J11
101265942Sgibbs			 */
101365942Sgibbs			ujval = (uintmax_t)(uintptr_t)GETARG(void *);
101465942Sgibbs			base = 16;
101565942Sgibbs			xdigs = xdigs_lower;
101665942Sgibbs			flags = flags | INTMAXT;
101765942Sgibbs			ox[1] = 'x';
101865942Sgibbs			goto nosign;
101965942Sgibbs		case 'S':
102065942Sgibbs			flags |= LONGINT;
102165942Sgibbs			/*FALLTHROUGH*/
102265942Sgibbs		case 's':
102365942Sgibbs			if (flags & LONGINT) {
102465942Sgibbs				wchar_t *wcp;
102565942Sgibbs
102665942Sgibbs				if (convbuf != NULL)
102765942Sgibbs					free(convbuf);
102865942Sgibbs				if ((wcp = GETARG(wchar_t *)) == NULL)
102965942Sgibbs					cp = "(null)";
103065942Sgibbs				else {
103165942Sgibbs					convbuf = __wcsconv(wcp, prec);
103265942Sgibbs					if (convbuf == NULL) {
103365942Sgibbs						fp->_flags |= __SERR;
103465942Sgibbs						goto error;
103565942Sgibbs					}
103665942Sgibbs					cp = convbuf;
103765942Sgibbs				}
103865942Sgibbs			} else if ((cp = GETARG(char *)) == NULL)
103965942Sgibbs				cp = "(null)";
104065942Sgibbs			if (prec >= 0) {
104165942Sgibbs				/*
104265942Sgibbs				 * can't use strlen; can only look for the
104365942Sgibbs				 * NUL in the first `prec' characters, and
104465942Sgibbs				 * strlen() will go further.
104565942Sgibbs				 */
104665942Sgibbs				char *p = memchr(cp, 0, (size_t)prec);
104765942Sgibbs
104865942Sgibbs				if (p != NULL) {
104965942Sgibbs					size = p - cp;
105065942Sgibbs					if (size > prec)
105165942Sgibbs						size = prec;
105265942Sgibbs				} else
105365942Sgibbs					size = prec;
105465942Sgibbs			} else
105565942Sgibbs				size = strlen(cp);
105665942Sgibbs			sign = '\0';
105765942Sgibbs			break;
105865942Sgibbs		case 'U':
105965942Sgibbs			flags |= LONGINT;
106065942Sgibbs			/*FALLTHROUGH*/
106165942Sgibbs		case 'u':
106265942Sgibbs			if (flags & INTMAX_SIZE)
106365942Sgibbs				ujval = UJARG();
106465942Sgibbs			else
106565942Sgibbs				ulval = UARG();
106665942Sgibbs			base = 10;
106765942Sgibbs			goto nosign;
106865942Sgibbs		case 'X':
106965942Sgibbs			xdigs = xdigs_upper;
107065942Sgibbs			goto hex;
107165942Sgibbs		case 'x':
107265942Sgibbs			xdigs = xdigs_lower;
107365942Sgibbshex:
107465942Sgibbs			if (flags & INTMAX_SIZE)
107565942Sgibbs				ujval = UJARG();
107666647Sgibbs			else
107765942Sgibbs				ulval = UARG();
107866647Sgibbs			base = 16;
107965942Sgibbs			/* leading 0x/X only if non-zero */
108065942Sgibbs			if (flags & ALT &&
108165942Sgibbs			    (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
108265942Sgibbs				ox[1] = ch;
108365942Sgibbs
108465942Sgibbs			flags &= ~GROUPING;
108565942Sgibbs			/* unsigned conversions */
108665942Sgibbsnosign:			sign = '\0';
108765942Sgibbs			/*-
108865942Sgibbs			 * ``... diouXx conversions ... if a precision is
108965942Sgibbs			 * specified, the 0 flag will be ignored.''
109065942Sgibbs			 *	-- ANSI X3J11
109165942Sgibbs			 */
109265942Sgibbsnumber:			if ((dprec = prec) >= 0)
109365942Sgibbs				flags &= ~ZEROPAD;
109465942Sgibbs
109565942Sgibbs			/*-
109665942Sgibbs			 * ``The result of converting a zero value with an
109765942Sgibbs			 * explicit precision of zero is no characters.''
109865942Sgibbs			 *	-- ANSI X3J11
109965942Sgibbs			 *
110065942Sgibbs			 * ``The C Standard is clear enough as is.  The call
110165942Sgibbs			 * printf("%#.0o", 0) should print 0.''
110265942Sgibbs			 *	-- Defect Report #151
110365942Sgibbs			 */
110465942Sgibbs			cp = buf + BUF;
110565942Sgibbs			if (flags & INTMAX_SIZE) {
110665942Sgibbs				if (ujval != 0 || prec != 0 ||
110765942Sgibbs				    (flags & ALT && base == 8))
110865942Sgibbs					cp = __ujtoa(ujval, cp, base,
110965942Sgibbs					    flags & ALT, xdigs,
111065942Sgibbs					    flags & GROUPING, thousands_sep,
111165942Sgibbs					    grouping);
111265942Sgibbs			} else {
111365942Sgibbs				if (ulval != 0 || prec != 0 ||
111465942Sgibbs				    (flags & ALT && base == 8))
111565942Sgibbs					cp = __ultoa(ulval, cp, base,
111665942Sgibbs					    flags & ALT, xdigs,
111765942Sgibbs					    flags & GROUPING, thousands_sep,
111865942Sgibbs					    grouping);
111965942Sgibbs			}
112065942Sgibbs			size = buf + BUF - cp;
112165942Sgibbs			if (size > BUF)	/* should never happen */
112265942Sgibbs				abort();
112365942Sgibbs			break;
112465942Sgibbs		default:	/* "%?" prints ?, unless ? is NUL */
112565942Sgibbs			if (ch == '\0')
112665942Sgibbs				goto done;
112765942Sgibbs			/* pretend it was %c with argument ch */
112865942Sgibbs			cp = buf;
112965942Sgibbs			*cp = ch;
113065942Sgibbs			size = 1;
113165942Sgibbs			sign = '\0';
113265942Sgibbs			break;
113365942Sgibbs		}
113465942Sgibbs
113565942Sgibbs		/*
113665942Sgibbs		 * All reasonable formats wind up here.  At this point, `cp'
113765942Sgibbs		 * points to a string which (if not flags&LADJUST) should be
113865942Sgibbs		 * padded out to `width' places.  If flags&ZEROPAD, it should
113965942Sgibbs		 * first be prefixed by any sign or other prefix; otherwise,
114065942Sgibbs		 * it should be blank padded before the prefix is emitted.
114165942Sgibbs		 * After any left-hand padding and prefixing, emit zeroes
114265942Sgibbs		 * required by a decimal [diouxX] precision, then print the
114365942Sgibbs		 * string proper, then emit zeroes required by any leftover
114465942Sgibbs		 * floating precision; finally, if LADJUST, pad with blanks.
114566647Sgibbs		 *
114665942Sgibbs		 * Compute actual size, so we know how much to pad.
114766647Sgibbs		 * size excludes decimal prec; realsz includes it.
114865942Sgibbs		 */
114965942Sgibbs		realsz = dprec > size ? dprec : size;
115065942Sgibbs		if (sign)
115165942Sgibbs			realsz++;
115265942Sgibbs		if (ox[1])
115365942Sgibbs			realsz += 2;
115465942Sgibbs
115565942Sgibbs		prsize = width > realsz ? width : realsz;
115665942Sgibbs		if ((unsigned)ret + prsize > INT_MAX) {
115765942Sgibbs			ret = EOF;
115865942Sgibbs			goto error;
115965942Sgibbs		}
116065942Sgibbs
116165942Sgibbs		/* right-adjusting blank padding */
116265942Sgibbs		if ((flags & (LADJUST|ZEROPAD)) == 0)
116365942Sgibbs			PAD(width - realsz, blanks);
116465942Sgibbs
116565942Sgibbs		/* prefix */
116665942Sgibbs		if (sign)
116765942Sgibbs			PRINT(&sign, 1);
116865942Sgibbs
116965942Sgibbs		if (ox[1]) {	/* ox[1] is either x, X, or \0 */
117065942Sgibbs			ox[0] = '0';
117165942Sgibbs			PRINT(ox, 2);
117265942Sgibbs		}
117365942Sgibbs
117465942Sgibbs		/* right-adjusting zero padding */
117565942Sgibbs		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
117665942Sgibbs			PAD(width - realsz, zeroes);
117765942Sgibbs
117865942Sgibbs		/* leading zeroes from decimal precision */
117965942Sgibbs		PAD(dprec - size, zeroes);
118065942Sgibbs
118166647Sgibbs		/* the string or number proper */
118265942Sgibbs#ifndef NO_FLOATING_POINT
118365942Sgibbs		if ((flags & FPT) == 0) {
118465942Sgibbs			PRINT(cp, size);
118565942Sgibbs		} else {	/* glue together f_p fragments */
118665942Sgibbs			if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
118765942Sgibbs				if (expt <= 0) {
118865942Sgibbs					PRINT(zeroes, 1);
118965942Sgibbs					if (prec || flags & ALT)
119065942Sgibbs						PRINT(decimal_point, 1);
119165942Sgibbs					PAD(-expt, zeroes);
119265942Sgibbs					/* already handled initial 0's */
119365942Sgibbs					prec += expt;
119465942Sgibbs				} else {
119565942Sgibbs					PRINTANDPAD(cp, dtoaend, lead, zeroes);
119665942Sgibbs					cp += lead;
119765942Sgibbs					if (grouping) {
119865942Sgibbs						while (nseps>0 || nrepeats>0) {
119965942Sgibbs							if (nrepeats > 0)
120065942Sgibbs								nrepeats--;
120165942Sgibbs							else {
120265942Sgibbs								grouping--;
120365942Sgibbs								nseps--;
120465942Sgibbs							}
120565942Sgibbs							PRINT(&thousands_sep,
120665942Sgibbs							    1);
120765942Sgibbs							PRINTANDPAD(cp,dtoaend,
120865942Sgibbs							    *grouping, zeroes);
120965942Sgibbs							cp += *grouping;
121065942Sgibbs						}
121165942Sgibbs						if (cp > dtoaend)
121265942Sgibbs							cp = dtoaend;
121365942Sgibbs					}
121465942Sgibbs					if (prec || flags & ALT)
121565942Sgibbs						PRINT(decimal_point,1);
121665942Sgibbs				}
121765942Sgibbs				PRINTANDPAD(cp, dtoaend, prec, zeroes);
121865942Sgibbs			} else {	/* %[eE] or sufficiently long %[gG] */
121965942Sgibbs				if (prec > 1 || flags & ALT) {
122065942Sgibbs					buf[0] = *cp++;
122165942Sgibbs					buf[1] = *decimal_point;
122265942Sgibbs					PRINT(buf, 2);
122365942Sgibbs					PRINT(cp, ndig-1);
122465942Sgibbs					PAD(prec - ndig, zeroes);
122565942Sgibbs				} else	/* XeYYY */
122665942Sgibbs					PRINT(cp, 1);
122765942Sgibbs				PRINT(expstr, expsize);
122865942Sgibbs			}
122965942Sgibbs		}
123065942Sgibbs#else
123165942Sgibbs		PRINT(cp, size);
123265942Sgibbs#endif
123365942Sgibbs		/* left-adjusting padding (always blank) */
123465942Sgibbs		if (flags & LADJUST)
123565942Sgibbs			PAD(width - realsz, blanks);
123665942Sgibbs
123765942Sgibbs		/* finally, adjust ret */
123865942Sgibbs		ret += prsize;
123965942Sgibbs
124065942Sgibbs		FLUSH();	/* copy out the I/O vectors */
124165942Sgibbs	}
124265942Sgibbsdone:
124365942Sgibbs	FLUSH();
124465942Sgibbserror:
124565942Sgibbs	va_end(orgap);
124665942Sgibbs#ifndef NO_FLOATING_POINT
124765942Sgibbs	if (dtoaresult != NULL)
124865942Sgibbs		freedtoa(dtoaresult);
124965942Sgibbs#endif
125065942Sgibbs	if (convbuf != NULL)
125165942Sgibbs		free(convbuf);
125265942Sgibbs	if (__sferror(fp))
125366647Sgibbs		ret = EOF;
125466647Sgibbs	if ((argtable != NULL) && (argtable != statargtable))
125565942Sgibbs		free (argtable);
125665942Sgibbs	return (ret);
125766647Sgibbs	/* NOTREACHED */
125865942Sgibbs}
125966647Sgibbs
126066647Sgibbs/*
126165942Sgibbs * Find all arguments when a positional parameter is encountered.  Returns a
126265942Sgibbs * table, indexed by argument number, of pointers to each arguments.  The
126365942Sgibbs * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
126465942Sgibbs * It will be replaces with a malloc-ed one if it overflows.
126565942Sgibbs */
126665942Sgibbsstatic void
126765942Sgibbs__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
126865942Sgibbs{
126965942Sgibbs	char *fmt;		/* format string */
127065942Sgibbs	int ch;			/* character from fmt */
127165942Sgibbs	int n, n2;		/* handy integer (short term usage) */
127265942Sgibbs	char *cp;		/* handy char pointer (short term usage) */
127365942Sgibbs	int flags;		/* flags as above */
127465942Sgibbs	int width;		/* width from format (%8d), or 0 */
127565942Sgibbs	enum typeid *typetable; /* table of types */
127665942Sgibbs	enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
127765942Sgibbs	int tablesize;		/* current size of type table */
127865942Sgibbs	int tablemax;		/* largest used index in table */
127965942Sgibbs	int nextarg;		/* 1-based argument index */
128065942Sgibbs
128165942Sgibbs	/*
128265942Sgibbs	 * Add an argument type to the table, expanding if necessary.
128365942Sgibbs	 */
128465942Sgibbs#define ADDTYPE(type) \
128565942Sgibbs	((nextarg >= tablesize) ? \
128665942Sgibbs		__grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \
128765942Sgibbs	(nextarg > tablemax) ? tablemax = nextarg : 0, \
128865942Sgibbs	typetable[nextarg++] = type)
128965942Sgibbs
129065942Sgibbs#define	ADDSARG() \
129165942Sgibbs	((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
129265942Sgibbs		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
129365942Sgibbs		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
129465942Sgibbs		((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
129565942Sgibbs		((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
129665942Sgibbs
129765942Sgibbs#define	ADDUARG() \
129865942Sgibbs	((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
129965942Sgibbs		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
130065942Sgibbs		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
130165942Sgibbs		((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
130265942Sgibbs		((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
130365942Sgibbs
130465942Sgibbs	/*
130565942Sgibbs	 * Add * arguments to the type array.
130665942Sgibbs	 */
130765942Sgibbs#define ADDASTER() \
130865942Sgibbs	n2 = 0; \
130965942Sgibbs	cp = fmt; \
131065942Sgibbs	while (is_digit(*cp)) { \
131165942Sgibbs		n2 = 10 * n2 + to_digit(*cp); \
131265942Sgibbs		cp++; \
131365942Sgibbs	} \
131465942Sgibbs	if (*cp == '$') { \
131565942Sgibbs		int hold = nextarg; \
131665942Sgibbs		nextarg = n2; \
131765942Sgibbs		ADDTYPE (T_INT); \
131865942Sgibbs		nextarg = hold; \
131965942Sgibbs		fmt = ++cp; \
132065942Sgibbs	} else { \
132165942Sgibbs		ADDTYPE (T_INT); \
132265942Sgibbs	}
132365942Sgibbs	fmt = (char *)fmt0;
132465942Sgibbs	typetable = stattypetable;
132565942Sgibbs	tablesize = STATIC_ARG_TBL_SIZE;
132665942Sgibbs	tablemax = 0;
132765942Sgibbs	nextarg = 1;
132865942Sgibbs	for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
132965942Sgibbs		typetable[n] = T_UNUSED;
133065942Sgibbs
133165942Sgibbs	/*
133265942Sgibbs	 * Scan the format for conversions (`%' character).
133365942Sgibbs	 */
133465942Sgibbs	for (;;) {
133565942Sgibbs		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
133665942Sgibbs			/* void */;
133765942Sgibbs		if (ch == '\0')
133865942Sgibbs			goto done;
133965942Sgibbs		fmt++;		/* skip over '%' */
134065942Sgibbs
134165942Sgibbs		flags = 0;
134265942Sgibbs		width = 0;
134365942Sgibbs
134465942Sgibbsrflag:		ch = *fmt++;
134565942Sgibbsreswitch:	switch (ch) {
134665942Sgibbs		case ' ':
134765942Sgibbs		case '#':
134865942Sgibbs			goto rflag;
134965942Sgibbs		case '*':
135065942Sgibbs			ADDASTER ();
135165942Sgibbs			goto rflag;
135265942Sgibbs		case '-':
135365942Sgibbs		case '+':
135465942Sgibbs		case '\'':
135565942Sgibbs			goto rflag;
135665942Sgibbs		case '.':
135765942Sgibbs			if ((ch = *fmt++) == '*') {
135865942Sgibbs				ADDASTER ();
135965942Sgibbs				goto rflag;
136065942Sgibbs			}
136165942Sgibbs			while (is_digit(ch)) {
136265942Sgibbs				ch = *fmt++;
136365942Sgibbs			}
136465942Sgibbs			goto reswitch;
136565942Sgibbs		case '0':
136665942Sgibbs			goto rflag;
136765942Sgibbs		case '1': case '2': case '3': case '4':
136865942Sgibbs		case '5': case '6': case '7': case '8': case '9':
136965942Sgibbs			n = 0;
137065942Sgibbs			do {
137165942Sgibbs				n = 10 * n + to_digit(ch);
137265942Sgibbs				ch = *fmt++;
137365942Sgibbs			} while (is_digit(ch));
137465942Sgibbs			if (ch == '$') {
137565942Sgibbs				nextarg = n;
137665942Sgibbs				goto rflag;
137765942Sgibbs			}
137865942Sgibbs			width = n;
137965942Sgibbs			goto reswitch;
138065942Sgibbs#ifndef NO_FLOATING_POINT
138165942Sgibbs		case 'L':
138265942Sgibbs			flags |= LONGDBL;
138365942Sgibbs			goto rflag;
138465942Sgibbs#endif
138565942Sgibbs		case 'h':
138665942Sgibbs			if (flags & SHORTINT) {
138765942Sgibbs				flags &= ~SHORTINT;
138865942Sgibbs				flags |= CHARINT;
138965942Sgibbs			} else
139065942Sgibbs				flags |= SHORTINT;
139165942Sgibbs			goto rflag;
139265942Sgibbs		case 'j':
139365942Sgibbs			flags |= INTMAXT;
139465942Sgibbs			goto rflag;
139565942Sgibbs		case 'l':
139665942Sgibbs			if (flags & LONGINT) {
139765942Sgibbs				flags &= ~LONGINT;
139865942Sgibbs				flags |= LLONGINT;
139965942Sgibbs			} else
140065942Sgibbs				flags |= LONGINT;
140165942Sgibbs			goto rflag;
140265942Sgibbs		case 'q':
140365942Sgibbs			flags |= LLONGINT;	/* not necessarily */
140465942Sgibbs			goto rflag;
140565942Sgibbs		case 't':
140665942Sgibbs			flags |= PTRDIFFT;
140765942Sgibbs			goto rflag;
140865942Sgibbs		case 'z':
140965942Sgibbs			flags |= SIZET;
141065942Sgibbs			goto rflag;
141165942Sgibbs		case 'C':
141265942Sgibbs			flags |= LONGINT;
141365942Sgibbs			/*FALLTHROUGH*/
141465942Sgibbs		case 'c':
141565942Sgibbs			if (flags & LONGINT)
141665942Sgibbs				ADDTYPE(T_WINT);
141765942Sgibbs			else
141865942Sgibbs				ADDTYPE(T_INT);
141965942Sgibbs			break;
142065942Sgibbs		case 'D':
142165942Sgibbs			flags |= LONGINT;
142265942Sgibbs			/*FALLTHROUGH*/
142365942Sgibbs		case 'd':
142465942Sgibbs		case 'i':
142565942Sgibbs			ADDSARG();
142665942Sgibbs			break;
142765942Sgibbs#ifndef NO_FLOATING_POINT
142865942Sgibbs		case 'a':
142965942Sgibbs		case 'A':
143065942Sgibbs		case 'e':
143165942Sgibbs		case 'E':
143265942Sgibbs		case 'f':
143365942Sgibbs		case 'g':
143465942Sgibbs		case 'G':
143565942Sgibbs			if (flags & LONGDBL)
143665942Sgibbs				ADDTYPE(T_LONG_DOUBLE);
143765942Sgibbs			else
143865942Sgibbs				ADDTYPE(T_DOUBLE);
143965942Sgibbs			break;
144065942Sgibbs#endif /* !NO_FLOATING_POINT */
144165942Sgibbs		case 'n':
144265942Sgibbs			if (flags & INTMAXT)
144365942Sgibbs				ADDTYPE(TP_INTMAXT);
144465942Sgibbs			else if (flags & PTRDIFFT)
144565942Sgibbs				ADDTYPE(TP_PTRDIFFT);
144665942Sgibbs			else if (flags & SIZET)
144765942Sgibbs				ADDTYPE(TP_SIZET);
144865942Sgibbs			else if (flags & LLONGINT)
144965942Sgibbs				ADDTYPE(TP_LLONG);
145065942Sgibbs			else if (flags & LONGINT)
145165942Sgibbs				ADDTYPE(TP_LONG);
145265942Sgibbs			else if (flags & SHORTINT)
145365942Sgibbs				ADDTYPE(TP_SHORT);
145465942Sgibbs			else if (flags & CHARINT)
145565942Sgibbs				ADDTYPE(TP_SCHAR);
145665942Sgibbs			else
145765942Sgibbs				ADDTYPE(TP_INT);
145865942Sgibbs			continue;	/* no output */
145965942Sgibbs		case 'O':
146065942Sgibbs			flags |= LONGINT;
146165942Sgibbs			/*FALLTHROUGH*/
146265942Sgibbs		case 'o':
146365942Sgibbs			ADDUARG();
146465942Sgibbs			break;
146565942Sgibbs		case 'p':
146665942Sgibbs			ADDTYPE(TP_VOID);
146765942Sgibbs			break;
146865942Sgibbs		case 'S':
146965942Sgibbs			flags |= LONGINT;
147065942Sgibbs			/*FALLTHROUGH*/
147165942Sgibbs		case 's':
147265942Sgibbs			if (flags & LONGINT)
147365942Sgibbs				ADDTYPE(TP_WCHAR);
147465942Sgibbs			else
147565942Sgibbs				ADDTYPE(TP_CHAR);
147665942Sgibbs			break;
147765942Sgibbs		case 'U':
147865942Sgibbs			flags |= LONGINT;
147965942Sgibbs			/*FALLTHROUGH*/
148065942Sgibbs		case 'u':
148165942Sgibbs		case 'X':
148265942Sgibbs		case 'x':
148365942Sgibbs			ADDUARG();
148465942Sgibbs			break;
148565942Sgibbs		default:	/* "%?" prints ?, unless ? is NUL */
148665942Sgibbs			if (ch == '\0')
148765942Sgibbs				goto done;
148865942Sgibbs			break;
148965942Sgibbs		}
149065942Sgibbs	}
149165942Sgibbsdone:
149265942Sgibbs	/*
149365942Sgibbs	 * Build the argument table.
149465942Sgibbs	 */
149565942Sgibbs	if (tablemax >= STATIC_ARG_TBL_SIZE) {
149665942Sgibbs		*argtable = (union arg *)
149765942Sgibbs		    malloc (sizeof (union arg) * (tablemax + 1));
149865942Sgibbs	}
149965942Sgibbs
150065942Sgibbs	(*argtable) [0].intarg = 0;
150165942Sgibbs	for (n = 1; n <= tablemax; n++) {
150265942Sgibbs		switch (typetable [n]) {
150365942Sgibbs		    case T_UNUSED: /* whoops! */
150465942Sgibbs			(*argtable) [n].intarg = va_arg (ap, int);
150565942Sgibbs			break;
150665942Sgibbs		    case TP_SCHAR:
150765942Sgibbs			(*argtable) [n].pschararg = va_arg (ap, signed char *);
150865942Sgibbs			break;
150965942Sgibbs		    case TP_SHORT:
151065942Sgibbs			(*argtable) [n].pshortarg = va_arg (ap, short *);
151165942Sgibbs			break;
151265942Sgibbs		    case T_INT:
151365942Sgibbs			(*argtable) [n].intarg = va_arg (ap, int);
151465942Sgibbs			break;
151565942Sgibbs		    case T_U_INT:
151665942Sgibbs			(*argtable) [n].uintarg = va_arg (ap, unsigned int);
151765942Sgibbs			break;
151865942Sgibbs		    case TP_INT:
151965942Sgibbs			(*argtable) [n].pintarg = va_arg (ap, int *);
152065942Sgibbs			break;
152165942Sgibbs		    case T_LONG:
152265942Sgibbs			(*argtable) [n].longarg = va_arg (ap, long);
152365942Sgibbs			break;
152465942Sgibbs		    case T_U_LONG:
152565942Sgibbs			(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
152665942Sgibbs			break;
152765942Sgibbs		    case TP_LONG:
152865942Sgibbs			(*argtable) [n].plongarg = va_arg (ap, long *);
152965942Sgibbs			break;
153065942Sgibbs		    case T_LLONG:
153165942Sgibbs			(*argtable) [n].longlongarg = va_arg (ap, long long);
153265942Sgibbs			break;
153365942Sgibbs		    case T_U_LLONG:
153465942Sgibbs			(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
153565942Sgibbs			break;
153665942Sgibbs		    case TP_LLONG:
153765942Sgibbs			(*argtable) [n].plonglongarg = va_arg (ap, long long *);
153865942Sgibbs			break;
153965942Sgibbs		    case T_PTRDIFFT:
154065942Sgibbs			(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
154165942Sgibbs			break;
154265942Sgibbs		    case TP_PTRDIFFT:
154365942Sgibbs			(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
154465942Sgibbs			break;
154565942Sgibbs		    case T_SIZET:
154665942Sgibbs			(*argtable) [n].sizearg = va_arg (ap, size_t);
154765942Sgibbs			break;
154865942Sgibbs		    case TP_SIZET:
154965942Sgibbs			(*argtable) [n].psizearg = va_arg (ap, size_t *);
155065942Sgibbs			break;
155165942Sgibbs		    case T_INTMAXT:
155265942Sgibbs			(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
155365942Sgibbs			break;
155465942Sgibbs		    case T_UINTMAXT:
155565942Sgibbs			(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
155665942Sgibbs			break;
155765942Sgibbs		    case TP_INTMAXT:
155865942Sgibbs			(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
155965942Sgibbs			break;
156065942Sgibbs		    case T_DOUBLE:
156165942Sgibbs#ifndef NO_FLOATING_POINT
156265942Sgibbs			(*argtable) [n].doublearg = va_arg (ap, double);
156365942Sgibbs#endif
156465942Sgibbs			break;
156565942Sgibbs		    case T_LONG_DOUBLE:
156665942Sgibbs#ifndef NO_FLOATING_POINT
156765942Sgibbs			(*argtable) [n].longdoublearg = va_arg (ap, long double);
156865942Sgibbs#endif
156965942Sgibbs			break;
157065942Sgibbs		    case TP_CHAR:
157165942Sgibbs			(*argtable) [n].pchararg = va_arg (ap, char *);
157265942Sgibbs			break;
157365942Sgibbs		    case TP_VOID:
157465942Sgibbs			(*argtable) [n].pvoidarg = va_arg (ap, void *);
157565942Sgibbs			break;
157665942Sgibbs		    case T_WINT:
157765942Sgibbs			(*argtable) [n].wintarg = va_arg (ap, wint_t);
157865942Sgibbs			break;
157965942Sgibbs		    case TP_WCHAR:
158065942Sgibbs			(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
158165942Sgibbs			break;
158265942Sgibbs		}
158365942Sgibbs	}
158465942Sgibbs
158565942Sgibbs	if ((typetable != NULL) && (typetable != stattypetable))
158665942Sgibbs		free (typetable);
158765942Sgibbs}
158865942Sgibbs
158965942Sgibbs/*
159065942Sgibbs * Increase the size of the type table.
159165942Sgibbs */
159265942Sgibbsstatic void
159365942Sgibbs__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
159465942Sgibbs{
159565942Sgibbs	enum typeid *const oldtable = *typetable;
159665942Sgibbs	const int oldsize = *tablesize;
159765942Sgibbs	enum typeid *newtable;
159865942Sgibbs	int n, newsize = oldsize * 2;
159965942Sgibbs
160065942Sgibbs	if (newsize < nextarg + 1)
160165942Sgibbs		newsize = nextarg + 1;
160265942Sgibbs	if (oldsize == STATIC_ARG_TBL_SIZE) {
160365942Sgibbs		if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
160465942Sgibbs			abort();			/* XXX handle better */
160565942Sgibbs		bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
160665942Sgibbs	} else {
160765942Sgibbs		newtable = reallocf(oldtable, newsize * sizeof(enum typeid));
160865942Sgibbs		if (newtable == NULL)
160965942Sgibbs			abort();			/* XXX handle better */
161065942Sgibbs	}
161165942Sgibbs	for (n = oldsize; n < newsize; n++)
161265942Sgibbs		newtable[n] = T_UNUSED;
161365942Sgibbs
161465942Sgibbs	*typetable = newtable;
161565942Sgibbs	*tablesize = newsize;
161665942Sgibbs}
161765942Sgibbs
161865942Sgibbs
161965942Sgibbs#ifndef NO_FLOATING_POINT
162065942Sgibbs
162165942Sgibbsstatic int
162265942Sgibbsexponent(char *p0, int exp, int fmtch)
162365942Sgibbs{
162465942Sgibbs	char *p, *t;
162565942Sgibbs	char expbuf[MAXEXPDIG];
162665942Sgibbs
162765942Sgibbs	p = p0;
162865942Sgibbs	*p++ = fmtch;
162965942Sgibbs	if (exp < 0) {
163065942Sgibbs		exp = -exp;
163165942Sgibbs		*p++ = '-';
163265942Sgibbs	}
163365942Sgibbs	else
163465942Sgibbs		*p++ = '+';
163565942Sgibbs	t = expbuf + MAXEXPDIG;
163665942Sgibbs	if (exp > 9) {
163765942Sgibbs		do {
163865942Sgibbs			*--t = to_char(exp % 10);
163965942Sgibbs		} while ((exp /= 10) > 9);
164065942Sgibbs		*--t = to_char(exp);
164165942Sgibbs		for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
164265942Sgibbs	}
164365942Sgibbs	else {
164465942Sgibbs		/*
164565942Sgibbs		 * Exponents for decimal floating point conversions
164665942Sgibbs		 * (%[eEgG]) must be at least two characters long,
164765942Sgibbs		 * whereas exponents for hexadecimal conversions can
164865942Sgibbs		 * be only one character long.
164965942Sgibbs		 */
165065942Sgibbs		if (fmtch == 'e' || fmtch == 'E')
165165942Sgibbs			*p++ = '0';
165265942Sgibbs		*p++ = to_char(exp);
165365942Sgibbs	}
165465942Sgibbs	return (p - p0);
165565942Sgibbs}
165665942Sgibbs#endif /* !NO_FLOATING_POINT */
165765942Sgibbs