vfprintf.c revision 178287
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1990, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Chris Torek.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 4. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
311573Srgrimes */
321573Srgrimes
331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
341573Srgrimesstatic char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
351573Srgrimes#endif /* LIBC_SCCS and not lint */
3692986Sobrien#include <sys/cdefs.h>
3792986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdio/vfprintf.c 178287 2008-04-17 22:17:54Z jhb $");
381573Srgrimes
391573Srgrimes/*
401573Srgrimes * Actual printf innards.
411573Srgrimes *
421573Srgrimes * This code is large and complicated...
431573Srgrimes */
441573Srgrimes
4571579Sdeischen#include "namespace.h"
461573Srgrimes#include <sys/types.h>
471573Srgrimes
4887113Sfenner#include <ctype.h>
491573Srgrimes#include <limits.h>
5087490Sphantom#include <locale.h>
5187113Sfenner#include <stddef.h>
5287113Sfenner#include <stdint.h>
531573Srgrimes#include <stdio.h>
541573Srgrimes#include <stdlib.h>
551573Srgrimes#include <string.h>
56103633Stjr#include <wchar.h>
57153486Sphk#include <printf.h>
581573Srgrimes
591573Srgrimes#include <stdarg.h>
6071579Sdeischen#include "un-namespace.h"
611573Srgrimes
6271579Sdeischen#include "libc_private.h"
631573Srgrimes#include "local.h"
641573Srgrimes#include "fvwrite.h"
651573Srgrimes
6684922Sdfrunion arg {
6784962Sbde	int	intarg;
6884962Sbde	u_int	uintarg;
6984962Sbde	long	longarg;
7084962Sbde	u_long	ulongarg;
7187113Sfenner	long long longlongarg;
7287113Sfenner	unsigned long long ulonglongarg;
7387113Sfenner	ptrdiff_t ptrdiffarg;
7487113Sfenner	size_t	sizearg;
7587113Sfenner	intmax_t intmaxarg;
7687113Sfenner	uintmax_t uintmaxarg;
7784962Sbde	void	*pvoidarg;
7884962Sbde	char	*pchararg;
7987113Sfenner	signed char *pschararg;
8084962Sbde	short	*pshortarg;
8184962Sbde	int	*pintarg;
8284962Sbde	long	*plongarg;
8387113Sfenner	long long *plonglongarg;
8487113Sfenner	ptrdiff_t *pptrdiffarg;
8587113Sfenner	size_t	*psizearg;
8687113Sfenner	intmax_t *pintmaxarg;
87128819Sdas#ifndef NO_FLOATING_POINT
8884962Sbde	double	doublearg;
8984962Sbde	long double longdoublearg;
9084922Sdfr#endif
91103633Stjr	wint_t	wintarg;
92103633Stjr	wchar_t	*pwchararg;
9384922Sdfr};
9484922Sdfr
9587113Sfenner/*
9687113Sfenner * Type ids for argument type table.
9787113Sfenner */
9887113Sfennerenum typeid {
9987113Sfenner	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
10087113Sfenner	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
10187113Sfenner	T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET,
10287113Sfenner	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
103103633Stjr	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
10487113Sfenner};
10587113Sfenner
10692905Sobrienstatic int	__sprint(FILE *, struct __suio *);
10792941Sobrienstatic int	__sbprintf(FILE *, const char *, va_list) __printflike(2, 0);
108113146Sdasstatic char	*__ujtoa(uintmax_t, char *, int, int, const char *, int, char,
10992941Sobrien		    const char *);
110113146Sdasstatic char	*__ultoa(u_long, char *, int, int, const char *, int, char,
11192941Sobrien		    const char *);
112103633Stjrstatic char	*__wcsconv(wchar_t *, int);
11392905Sobrienstatic void	__find_arguments(const char *, va_list, union arg **);
11492905Sobrienstatic void	__grow_type_table(int, enum typeid **, int *);
11516586Sjraynard
1161573Srgrimes/*
1171573Srgrimes * Flush out all the vectors defined by the given uio,
1181573Srgrimes * then reset it so that it can be reused.
1191573Srgrimes */
1201573Srgrimesstatic int
12171579Sdeischen__sprint(FILE *fp, struct __suio *uio)
1221573Srgrimes{
12371579Sdeischen	int err;
1241573Srgrimes
1251573Srgrimes	if (uio->uio_resid == 0) {
1261573Srgrimes		uio->uio_iovcnt = 0;
1271573Srgrimes		return (0);
1281573Srgrimes	}
1291573Srgrimes	err = __sfvwrite(fp, uio);
1301573Srgrimes	uio->uio_resid = 0;
1311573Srgrimes	uio->uio_iovcnt = 0;
1321573Srgrimes	return (err);
1331573Srgrimes}
1341573Srgrimes
1351573Srgrimes/*
1361573Srgrimes * Helper function for `fprintf to unbuffered unix file': creates a
1371573Srgrimes * temporary buffer.  We only work on write-only files; this avoids
1381573Srgrimes * worries about ungetc buffers and so forth.
1391573Srgrimes */
1401573Srgrimesstatic int
14171579Sdeischen__sbprintf(FILE *fp, const char *fmt, va_list ap)
1421573Srgrimes{
1431573Srgrimes	int ret;
1441573Srgrimes	FILE fake;
1451573Srgrimes	unsigned char buf[BUFSIZ];
1461573Srgrimes
1471573Srgrimes	/* copy the important variables */
1481573Srgrimes	fake._flags = fp->_flags & ~__SNBF;
1491573Srgrimes	fake._file = fp->_file;
1501573Srgrimes	fake._cookie = fp->_cookie;
1511573Srgrimes	fake._write = fp->_write;
152178287Sjhb	fake._orientation = fp->_orientation;
153178287Sjhb	fake._mbstate = fp->_mbstate;
1541573Srgrimes
1551573Srgrimes	/* set up the buffer */
1561573Srgrimes	fake._bf._base = fake._p = buf;
1571573Srgrimes	fake._bf._size = fake._w = sizeof(buf);
1581573Srgrimes	fake._lbfsize = 0;	/* not actually used, but Just In Case */
1591573Srgrimes
1601573Srgrimes	/* do the work, then copy any error status */
16171579Sdeischen	ret = __vfprintf(&fake, fmt, ap);
16271579Sdeischen	if (ret >= 0 && __fflush(&fake))
1631573Srgrimes		ret = EOF;
1641573Srgrimes	if (fake._flags & __SERR)
1651573Srgrimes		fp->_flags |= __SERR;
1661573Srgrimes	return (ret);
1671573Srgrimes}
1681573Srgrimes
1691573Srgrimes/*
1701573Srgrimes * Macros for converting digits to letters and vice versa
1711573Srgrimes */
1721573Srgrimes#define	to_digit(c)	((c) - '0')
1731573Srgrimes#define is_digit(c)	((unsigned)to_digit(c) <= 9)
1741573Srgrimes#define	to_char(n)	((n) + '0')
1751573Srgrimes
1761573Srgrimes/*
1771573Srgrimes * Convert an unsigned long to ASCII for printf purposes, returning
1781573Srgrimes * a pointer to the first character of the string representation.
1791573Srgrimes * Octal numbers can be forced to have a leading zero; hex numbers
1801573Srgrimes * use the given digits.
1811573Srgrimes */
1821573Srgrimesstatic char *
183113146Sdas__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs,
18487815Sphantom	int needgrp, char thousep, const char *grp)
1851573Srgrimes{
18692889Sobrien	char *cp = endp;
18792889Sobrien	long sval;
18887113Sfenner	int ndig;
1891573Srgrimes
1901573Srgrimes	/*
1911573Srgrimes	 * Handle the three cases separately, in the hope of getting
1921573Srgrimes	 * better/faster code.
1931573Srgrimes	 */
1941573Srgrimes	switch (base) {
1951573Srgrimes	case 10:
1961573Srgrimes		if (val < 10) {	/* many numbers are 1 digit */
1971573Srgrimes			*--cp = to_char(val);
1981573Srgrimes			return (cp);
1991573Srgrimes		}
20087113Sfenner		ndig = 0;
2011573Srgrimes		/*
2021573Srgrimes		 * On many machines, unsigned arithmetic is harder than
2031573Srgrimes		 * signed arithmetic, so we do at most one unsigned mod and
2041573Srgrimes		 * divide; this is sufficient to reduce the range of
2051573Srgrimes		 * the incoming value to where signed arithmetic works.
2061573Srgrimes		 */
2071573Srgrimes		if (val > LONG_MAX) {
2081573Srgrimes			*--cp = to_char(val % 10);
20987113Sfenner			ndig++;
2101573Srgrimes			sval = val / 10;
2111573Srgrimes		} else
2121573Srgrimes			sval = val;
2131573Srgrimes		do {
2141573Srgrimes			*--cp = to_char(sval % 10);
21587815Sphantom			ndig++;
21687815Sphantom			/*
21787815Sphantom			 * If (*grp == CHAR_MAX) then no more grouping
21887815Sphantom			 * should be performed.
21987815Sphantom			 */
22087818Sphantom			if (needgrp && ndig == *grp && *grp != CHAR_MAX
22187818Sphantom					&& sval > 9) {
22287815Sphantom				*--cp = thousep;
22387113Sfenner				ndig = 0;
22487815Sphantom				/*
22587815Sphantom				 * If (*(grp+1) == '\0') then we have to
22687815Sphantom				 * use *grp character (last grouping rule)
22787815Sphantom				 * for all next cases
22887815Sphantom				 */
22988057Sphantom				if (*(grp+1) != '\0')
23088057Sphantom					grp++;
23187113Sfenner			}
2321573Srgrimes			sval /= 10;
2331573Srgrimes		} while (sval != 0);
2341573Srgrimes		break;
2351573Srgrimes
2361573Srgrimes	case 8:
2371573Srgrimes		do {
2381573Srgrimes			*--cp = to_char(val & 7);
2391573Srgrimes			val >>= 3;
2401573Srgrimes		} while (val);
2411573Srgrimes		if (octzero && *cp != '0')
2421573Srgrimes			*--cp = '0';
2431573Srgrimes		break;
2441573Srgrimes
2451573Srgrimes	case 16:
2461573Srgrimes		do {
2471573Srgrimes			*--cp = xdigs[val & 15];
2481573Srgrimes			val >>= 4;
2491573Srgrimes		} while (val);
2501573Srgrimes		break;
2511573Srgrimes
2521573Srgrimes	default:			/* oops */
2531573Srgrimes		abort();
2541573Srgrimes	}
2551573Srgrimes	return (cp);
2561573Srgrimes}
2571573Srgrimes
25887113Sfenner/* Identical to __ultoa, but for intmax_t. */
2591573Srgrimesstatic char *
260113146Sdas__ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs,
26187815Sphantom	int needgrp, char thousep, const char *grp)
2621573Srgrimes{
26371579Sdeischen	char *cp = endp;
26487113Sfenner	intmax_t sval;
26587113Sfenner	int ndig;
2661573Srgrimes
2671573Srgrimes	/* quick test for small values; __ultoa is typically much faster */
2681573Srgrimes	/* (perhaps instead we should run until small, then call __ultoa?) */
2691573Srgrimes	if (val <= ULONG_MAX)
27087113Sfenner		return (__ultoa((u_long)val, endp, base, octzero, xdigs,
27187815Sphantom		    needgrp, thousep, grp));
2721573Srgrimes	switch (base) {
2731573Srgrimes	case 10:
2741573Srgrimes		if (val < 10) {
2751573Srgrimes			*--cp = to_char(val % 10);
2761573Srgrimes			return (cp);
2771573Srgrimes		}
27887113Sfenner		ndig = 0;
27987113Sfenner		if (val > INTMAX_MAX) {
2801573Srgrimes			*--cp = to_char(val % 10);
28187113Sfenner			ndig++;
2821573Srgrimes			sval = val / 10;
2831573Srgrimes		} else
2841573Srgrimes			sval = val;
2851573Srgrimes		do {
2861573Srgrimes			*--cp = to_char(sval % 10);
28787815Sphantom			ndig++;
28887815Sphantom			/*
28987815Sphantom			 * If (*grp == CHAR_MAX) then no more grouping
29087815Sphantom			 * should be performed.
29187815Sphantom			 */
29287818Sphantom			if (needgrp && *grp != CHAR_MAX && ndig == *grp
29387818Sphantom					&& sval > 9) {
29487815Sphantom				*--cp = thousep;
29587113Sfenner				ndig = 0;
29687815Sphantom				/*
29787815Sphantom				 * If (*(grp+1) == '\0') then we have to
29887815Sphantom				 * use *grp character (last grouping rule)
29987815Sphantom				 * for all next cases
30087815Sphantom				 */
30188057Sphantom				if (*(grp+1) != '\0')
30288057Sphantom					grp++;
30388057Sphantom			}
3041573Srgrimes			sval /= 10;
3051573Srgrimes		} while (sval != 0);
3061573Srgrimes		break;
3071573Srgrimes
3081573Srgrimes	case 8:
3091573Srgrimes		do {
3101573Srgrimes			*--cp = to_char(val & 7);
3111573Srgrimes			val >>= 3;
3121573Srgrimes		} while (val);
3131573Srgrimes		if (octzero && *cp != '0')
3141573Srgrimes			*--cp = '0';
3151573Srgrimes		break;
3161573Srgrimes
3171573Srgrimes	case 16:
3181573Srgrimes		do {
3191573Srgrimes			*--cp = xdigs[val & 15];
3201573Srgrimes			val >>= 4;
3211573Srgrimes		} while (val);
3221573Srgrimes		break;
3231573Srgrimes
3241573Srgrimes	default:
3251573Srgrimes		abort();
3261573Srgrimes	}
3271573Srgrimes	return (cp);
3281573Srgrimes}
3291573Srgrimes
33071579Sdeischen/*
331103633Stjr * Convert a wide character string argument for the %ls format to a multibyte
332148363Stjr * string representation. If not -1, prec specifies the maximum number of
333148363Stjr * bytes to output, and also means that we can't assume that the wide char.
334148363Stjr * string ends is null-terminated.
335103633Stjr */
336103633Stjrstatic char *
337103633Stjr__wcsconv(wchar_t *wcsarg, int prec)
338103633Stjr{
339128002Stjr	static const mbstate_t initial;
340128002Stjr	mbstate_t mbs;
341103633Stjr	char buf[MB_LEN_MAX];
342103633Stjr	wchar_t *p;
343148363Stjr	char *convbuf;
344103633Stjr	size_t clen, nbytes;
345103633Stjr
346148363Stjr	/* Allocate space for the maximum number of bytes we could output. */
347148363Stjr	if (prec < 0) {
348103633Stjr		p = wcsarg;
349128002Stjr		mbs = initial;
350128002Stjr		nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
351103633Stjr		if (nbytes == (size_t)-1)
352103633Stjr			return (NULL);
353148363Stjr	} else {
354148363Stjr		/*
355148363Stjr		 * Optimisation: if the output precision is small enough,
356148363Stjr		 * just allocate enough memory for the maximum instead of
357148363Stjr		 * scanning the string.
358148363Stjr		 */
359148363Stjr		if (prec < 128)
360148363Stjr			nbytes = prec;
361148363Stjr		else {
362148363Stjr			nbytes = 0;
363148363Stjr			p = wcsarg;
364148363Stjr			mbs = initial;
365148363Stjr			for (;;) {
366148363Stjr				clen = wcrtomb(buf, *p++, &mbs);
367148363Stjr				if (clen == 0 || clen == (size_t)-1 ||
368148363Stjr				    nbytes + clen > prec)
369148363Stjr					break;
370148363Stjr				nbytes += clen;
371148363Stjr			}
372148363Stjr		}
373103633Stjr	}
374103633Stjr	if ((convbuf = malloc(nbytes + 1)) == NULL)
375103633Stjr		return (NULL);
376103633Stjr
377148363Stjr	/* Fill the output buffer. */
378103633Stjr	p = wcsarg;
379128002Stjr	mbs = initial;
380148363Stjr	if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
381148363Stjr	    nbytes, &mbs)) == (size_t)-1) {
382113196Sache		free(convbuf);
383113196Sache		return (NULL);
384113196Sache	}
385148363Stjr	convbuf[nbytes] = '\0';
386103633Stjr	return (convbuf);
387103633Stjr}
388103633Stjr
389103633Stjr/*
39071579Sdeischen * MT-safe version
39171579Sdeischen */
39271579Sdeischenint
393103012Stjrvfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
394101914Srobert
39571579Sdeischen{
39671579Sdeischen	int ret;
39771579Sdeischen
39871579Sdeischen	FLOCKFILE(fp);
39971579Sdeischen	ret = __vfprintf(fp, fmt0, ap);
40071579Sdeischen	FUNLOCKFILE(fp);
40171579Sdeischen	return (ret);
40271579Sdeischen}
40371579Sdeischen
404128819Sdas#ifndef NO_FLOATING_POINT
405113146Sdas
406113146Sdas#define	dtoa		__dtoa
407113146Sdas#define	freedtoa	__freedtoa
408113146Sdas
409113146Sdas#include <float.h>
4101573Srgrimes#include <math.h>
4111573Srgrimes#include "floatio.h"
412113146Sdas#include "gdtoa.h"
4131573Srgrimes
4141573Srgrimes#define	DEFPREC		6
4151573Srgrimes
41692905Sobrienstatic int exponent(char *, int, int);
4171573Srgrimes
418128819Sdas#endif /* !NO_FLOATING_POINT */
4191573Srgrimes
420113142Sdas/*
421113142Sdas * The size of the buffer we use as scratch space for integer
422113142Sdas * conversions, among other things.  Technically, we would need the
423113142Sdas * most space for base 10 conversions with thousands' grouping
424113142Sdas * characters between each pair of digits.  100 bytes is a
425113142Sdas * conservative overestimate even for a 128-bit uintmax_t.
426113142Sdas */
427113142Sdas#define	BUF	100
4281573Srgrimes
42921674Sjkh#define STATIC_ARG_TBL_SIZE 8           /* Size of static argument table. */
4301573Srgrimes
4311573Srgrimes/*
4321573Srgrimes * Flags used during conversion.
4331573Srgrimes */
4341573Srgrimes#define	ALT		0x001		/* alternate form */
4351573Srgrimes#define	LADJUST		0x004		/* left adjustment */
43631871Sbde#define	LONGDBL		0x008		/* long double */
4371573Srgrimes#define	LONGINT		0x010		/* long integer */
43887113Sfenner#define	LLONGINT	0x020		/* long long integer */
4391573Srgrimes#define	SHORTINT	0x040		/* short integer */
4401573Srgrimes#define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
44188057Sphantom#define	FPT		0x100		/* Floating point number */
44287815Sphantom#define	GROUPING	0x200		/* use grouping ("'" flag) */
44387113Sfenner					/* C99 additional size modifiers: */
44487815Sphantom#define	SIZET		0x400		/* size_t */
44587815Sphantom#define	PTRDIFFT	0x800		/* ptrdiff_t */
44687815Sphantom#define	INTMAXT		0x1000		/* intmax_t */
44787815Sphantom#define	CHARINT		0x2000		/* print char using int format */
44887113Sfenner
44971579Sdeischen/*
45071579Sdeischen * Non-MT-safe version
45171579Sdeischen */
4521573Srgrimesint
45371579Sdeischen__vfprintf(FILE *fp, const char *fmt0, va_list ap)
4541573Srgrimes{
45571579Sdeischen	char *fmt;		/* format string */
45671579Sdeischen	int ch;			/* character from fmt */
45771579Sdeischen	int n, n2;		/* handy integer (short term usage) */
45871579Sdeischen	char *cp;		/* handy char pointer (short term usage) */
45971579Sdeischen	struct __siov *iovp;	/* for PRINT macro */
46071579Sdeischen	int flags;		/* flags as above */
4611573Srgrimes	int ret;		/* return value accumulator */
4621573Srgrimes	int width;		/* width from format (%8d), or 0 */
463113146Sdas	int prec;		/* precision from format; <0 for N/A */
4641573Srgrimes	char sign;		/* sign prefix (' ', '+', '-', or \0) */
46587815Sphantom	char thousands_sep;	/* locale specific thousands separator */
46687815Sphantom	const char *grouping;	/* locale specific numeric grouping rules */
467153486Sphk
468153486Sphk	if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
469153486Sphk		__use_xprintf = 1;
470153486Sphk	if (__use_xprintf > 0)
471153486Sphk		return (__xvprintf(fp, fmt0, ap));
472153486Sphk
473128819Sdas#ifndef NO_FLOATING_POINT
474113146Sdas	/*
475113146Sdas	 * We can decompose the printed representation of floating
476113146Sdas	 * point numbers into several parts, some of which may be empty:
477113146Sdas	 *
478113146Sdas	 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
479113146Sdas	 *    A       B     ---C---      D       E   F
480113146Sdas	 *
481113146Sdas	 * A:	'sign' holds this value if present; '\0' otherwise
482113146Sdas	 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
483113146Sdas	 * C:	cp points to the string MMMNNN.  Leading and trailing
484113146Sdas	 *	zeros are not in the string and must be added.
485113146Sdas	 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
486113146Sdas	 * F:	at least two digits for decimal, at least one digit for hex
487113146Sdas	 */
48887490Sphantom	char *decimal_point;	/* locale specific decimal point */
489113146Sdas	int signflag;		/* true if float is negative */
490113146Sdas	union {			/* floating point arguments %[aAeEfFgG] */
491113146Sdas		double dbl;
492113146Sdas		long double ldbl;
493113146Sdas	} fparg;
4941573Srgrimes	int expt;		/* integer value of exponent */
495113146Sdas	char expchar;		/* exponent character: [eEpP\0] */
496113146Sdas	char *dtoaend;		/* pointer to end of converted digits */
4971573Srgrimes	int expsize;		/* character count for expstr */
498113146Sdas	int lead;		/* sig figs before decimal or group sep */
499113146Sdas	int ndig;		/* actual number of digits returned by dtoa */
500113146Sdas	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
50172523Stegge	char *dtoaresult;	/* buffer allocated by dtoa */
502113146Sdas	int nseps;		/* number of group separators with ' */
503113146Sdas	int nrepeats;		/* number of repeats of the last group */
5041573Srgrimes#endif
5051573Srgrimes	u_long	ulval;		/* integer arguments %[diouxX] */
50687113Sfenner	uintmax_t ujval;	/* %j, %ll, %q, %t, %z integers */
5071573Srgrimes	int base;		/* base for [diouxX] conversion */
5081573Srgrimes	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
50914727Sfenner	int realsz;		/* field size expanded by dprec, sign, etc */
5101573Srgrimes	int size;		/* size of converted field or string */
51131983Sache	int prsize;             /* max size of printed field */
512113146Sdas	const char *xdigs;     	/* digits for %[xX] conversion */
5131573Srgrimes#define NIOV 8
5141573Srgrimes	struct __suio uio;	/* output information: summary */
5151573Srgrimes	struct __siov iov[NIOV];/* ... and individual io vectors */
516113142Sdas	char buf[BUF];		/* buffer with space for digits of uintmax_t */
517113146Sdas	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
518103399Stjr	union arg *argtable;    /* args, built due to positional arg */
519103399Stjr	union arg statargtable [STATIC_ARG_TBL_SIZE];
520103399Stjr	int nextarg;            /* 1-based argument index */
521103399Stjr	va_list orgap;          /* original argument pointer */
522103633Stjr	char *convbuf;		/* wide to multibyte conversion result */
5231573Srgrimes
5241573Srgrimes	/*
5251573Srgrimes	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
5261573Srgrimes	 * fields occur frequently, increase PADSIZE and make the initialisers
5271573Srgrimes	 * below longer.
5281573Srgrimes	 */
5291573Srgrimes#define	PADSIZE	16		/* pad chunk size */
5301573Srgrimes	static char blanks[PADSIZE] =
5311573Srgrimes	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
5321573Srgrimes	static char zeroes[PADSIZE] =
5331573Srgrimes	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
5341573Srgrimes
535165742Sdas	static const char xdigs_lower[16] = "0123456789abcdef";
536165742Sdas	static const char xdigs_upper[16] = "0123456789ABCDEF";
537113146Sdas
5381573Srgrimes	/*
5391573Srgrimes	 * BEWARE, these `goto error' on error, and PAD uses `n'.
5401573Srgrimes	 */
5411573Srgrimes#define	PRINT(ptr, len) { \
5421573Srgrimes	iovp->iov_base = (ptr); \
5431573Srgrimes	iovp->iov_len = (len); \
5441573Srgrimes	uio.uio_resid += (len); \
5451573Srgrimes	iovp++; \
5461573Srgrimes	if (++uio.uio_iovcnt >= NIOV) { \
5471573Srgrimes		if (__sprint(fp, &uio)) \
5481573Srgrimes			goto error; \
5491573Srgrimes		iovp = iov; \
5501573Srgrimes	} \
5511573Srgrimes}
5521573Srgrimes#define	PAD(howmany, with) { \
5531573Srgrimes	if ((n = (howmany)) > 0) { \
5541573Srgrimes		while (n > PADSIZE) { \
5551573Srgrimes			PRINT(with, PADSIZE); \
5561573Srgrimes			n -= PADSIZE; \
5571573Srgrimes		} \
5581573Srgrimes		PRINT(with, n); \
5591573Srgrimes	} \
5601573Srgrimes}
561113191Sdas#define	PRINTANDPAD(p, ep, len, with) do {	\
562113191Sdas	n2 = (ep) - (p);       			\
563113191Sdas	if (n2 > (len))				\
564113191Sdas		n2 = (len);			\
565113191Sdas	if (n2 > 0)				\
566113191Sdas		PRINT((p), n2);			\
567113191Sdas	PAD((len) - (n2 > 0 ? n2 : 0), (with));	\
568113191Sdas} while(0)
5691573Srgrimes#define	FLUSH() { \
5701573Srgrimes	if (uio.uio_resid && __sprint(fp, &uio)) \
5711573Srgrimes		goto error; \
5721573Srgrimes	uio.uio_iovcnt = 0; \
5731573Srgrimes	iovp = iov; \
5741573Srgrimes}
5751573Srgrimes
576103399Stjr	/*
577103399Stjr	 * Get the argument indexed by nextarg.   If the argument table is
578103399Stjr	 * built, use it to get the argument.  If its not, get the next
579103399Stjr	 * argument (and arguments must be gotten sequentially).
580103399Stjr	 */
58121674Sjkh#define GETARG(type) \
582103399Stjr	((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
583103399Stjr	    (nextarg++, va_arg(ap, type)))
58421674Sjkh
5851573Srgrimes	/*
5861573Srgrimes	 * To extend shorts properly, we need both signed and unsigned
5871573Srgrimes	 * argument extraction methods.
5881573Srgrimes	 */
5891573Srgrimes#define	SARG() \
59021674Sjkh	(flags&LONGINT ? GETARG(long) : \
59121674Sjkh	    flags&SHORTINT ? (long)(short)GETARG(int) : \
59287113Sfenner	    flags&CHARINT ? (long)(signed char)GETARG(int) : \
59321674Sjkh	    (long)GETARG(int))
5941573Srgrimes#define	UARG() \
59521674Sjkh	(flags&LONGINT ? GETARG(u_long) : \
59621674Sjkh	    flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
59787113Sfenner	    flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
59821674Sjkh	    (u_long)GETARG(u_int))
59987113Sfenner#define	INTMAX_SIZE	(INTMAXT|SIZET|PTRDIFFT|LLONGINT)
60087113Sfenner#define SJARG() \
60187113Sfenner	(flags&INTMAXT ? GETARG(intmax_t) : \
60287113Sfenner	    flags&SIZET ? (intmax_t)GETARG(size_t) : \
60387113Sfenner	    flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
60487113Sfenner	    (intmax_t)GETARG(long long))
60587113Sfenner#define	UJARG() \
60687113Sfenner	(flags&INTMAXT ? GETARG(uintmax_t) : \
60787113Sfenner	    flags&SIZET ? (uintmax_t)GETARG(size_t) : \
60887113Sfenner	    flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
60987113Sfenner	    (uintmax_t)GETARG(unsigned long long))
6101573Srgrimes
611103399Stjr	/*
612103399Stjr	 * Get * arguments, including the form *nn$.  Preserve the nextarg
613103399Stjr	 * that the argument can be gotten once the type is determined.
614103399Stjr	 */
61521674Sjkh#define GETASTER(val) \
616103399Stjr	n2 = 0; \
617103399Stjr	cp = fmt; \
618103399Stjr	while (is_digit(*cp)) { \
619103399Stjr		n2 = 10 * n2 + to_digit(*cp); \
620103399Stjr		cp++; \
621103399Stjr	} \
622103399Stjr	if (*cp == '$') { \
623103399Stjr		int hold = nextarg; \
624103399Stjr		if (argtable == NULL) { \
625103399Stjr			argtable = statargtable; \
626103399Stjr			__find_arguments (fmt0, orgap, &argtable); \
627103399Stjr		} \
628103399Stjr		nextarg = n2; \
62921674Sjkh		val = GETARG (int); \
630103399Stjr		nextarg = hold; \
631103399Stjr		fmt = ++cp; \
632103399Stjr	} else { \
633103399Stjr		val = GETARG (int); \
634103399Stjr	}
63587815Sphantom
63688057Sphantom
63787815Sphantom	thousands_sep = '\0';
63887815Sphantom	grouping = NULL;
639103633Stjr	convbuf = NULL;
640128819Sdas#ifndef NO_FLOATING_POINT
64172523Stegge	dtoaresult = NULL;
64287113Sfenner	decimal_point = localeconv()->decimal_point;
64372523Stegge#endif
6441573Srgrimes	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
645130231Sdas	if (prepwrite(fp) != 0)
6461573Srgrimes		return (EOF);
6471573Srgrimes
6481573Srgrimes	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
6491573Srgrimes	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
65071579Sdeischen	    fp->_file >= 0)
6511573Srgrimes		return (__sbprintf(fp, fmt0, ap));
6521573Srgrimes
6531573Srgrimes	fmt = (char *)fmt0;
654103399Stjr	argtable = NULL;
655103399Stjr	nextarg = 1;
656103876Stjr	va_copy(orgap, ap);
6571573Srgrimes	uio.uio_iov = iovp = iov;
6581573Srgrimes	uio.uio_resid = 0;
6591573Srgrimes	uio.uio_iovcnt = 0;
6601573Srgrimes	ret = 0;
6611573Srgrimes
6621573Srgrimes	/*
6631573Srgrimes	 * Scan the format for conversions (`%' character).
6641573Srgrimes	 */
6651573Srgrimes	for (;;) {
6661573Srgrimes		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
6671573Srgrimes			/* void */;
6681573Srgrimes		if ((n = fmt - cp) != 0) {
66932253Sache			if ((unsigned)ret + n > INT_MAX) {
67031983Sache				ret = EOF;
67131983Sache				goto error;
67231983Sache			}
6731573Srgrimes			PRINT(cp, n);
6741573Srgrimes			ret += n;
6751573Srgrimes		}
6761573Srgrimes		if (ch == '\0')
6771573Srgrimes			goto done;
6781573Srgrimes		fmt++;		/* skip over '%' */
6791573Srgrimes
6801573Srgrimes		flags = 0;
6811573Srgrimes		dprec = 0;
6821573Srgrimes		width = 0;
6831573Srgrimes		prec = -1;
6841573Srgrimes		sign = '\0';
685113146Sdas		ox[1] = '\0';
6861573Srgrimes
6871573Srgrimesrflag:		ch = *fmt++;
6881573Srgrimesreswitch:	switch (ch) {
6891573Srgrimes		case ' ':
69088057Sphantom			/*-
6911573Srgrimes			 * ``If the space and + flags both appear, the space
6921573Srgrimes			 * flag will be ignored.''
6931573Srgrimes			 *	-- ANSI X3J11
6941573Srgrimes			 */
6951573Srgrimes			if (!sign)
6961573Srgrimes				sign = ' ';
6971573Srgrimes			goto rflag;
6981573Srgrimes		case '#':
6991573Srgrimes			flags |= ALT;
7001573Srgrimes			goto rflag;
7011573Srgrimes		case '*':
70288057Sphantom			/*-
7031573Srgrimes			 * ``A negative field width argument is taken as a
7041573Srgrimes			 * - flag followed by a positive field width.''
7051573Srgrimes			 *	-- ANSI X3J11
7061573Srgrimes			 * They don't exclude field widths read from args.
7071573Srgrimes			 */
70821674Sjkh			GETASTER (width);
70921674Sjkh			if (width >= 0)
7101573Srgrimes				goto rflag;
7111573Srgrimes			width = -width;
7121573Srgrimes			/* FALLTHROUGH */
7131573Srgrimes		case '-':
7141573Srgrimes			flags |= LADJUST;
7151573Srgrimes			goto rflag;
7161573Srgrimes		case '+':
7171573Srgrimes			sign = '+';
7181573Srgrimes			goto rflag;
71987113Sfenner		case '\'':
72087815Sphantom			flags |= GROUPING;
72187815Sphantom			thousands_sep = *(localeconv()->thousands_sep);
72287815Sphantom			grouping = localeconv()->grouping;
72387113Sfenner			goto rflag;
7241573Srgrimes		case '.':
7251573Srgrimes			if ((ch = *fmt++) == '*') {
726113191Sdas				GETASTER (prec);
7271573Srgrimes				goto rflag;
7281573Srgrimes			}
729113191Sdas			prec = 0;
7301573Srgrimes			while (is_digit(ch)) {
731113191Sdas				prec = 10 * prec + to_digit(ch);
7321573Srgrimes				ch = *fmt++;
7331573Srgrimes			}
7341573Srgrimes			goto reswitch;
7351573Srgrimes		case '0':
73688057Sphantom			/*-
7371573Srgrimes			 * ``Note that 0 is taken as a flag, not as the
7381573Srgrimes			 * beginning of a field width.''
7391573Srgrimes			 *	-- ANSI X3J11
7401573Srgrimes			 */
7411573Srgrimes			flags |= ZEROPAD;
7421573Srgrimes			goto rflag;
7431573Srgrimes		case '1': case '2': case '3': case '4':
7441573Srgrimes		case '5': case '6': case '7': case '8': case '9':
7451573Srgrimes			n = 0;
7461573Srgrimes			do {
7471573Srgrimes				n = 10 * n + to_digit(ch);
7481573Srgrimes				ch = *fmt++;
7491573Srgrimes			} while (is_digit(ch));
75021674Sjkh			if (ch == '$') {
75121674Sjkh				nextarg = n;
752103399Stjr				if (argtable == NULL) {
753103399Stjr					argtable = statargtable;
754103399Stjr					__find_arguments (fmt0, orgap,
755103399Stjr					    &argtable);
75621674Sjkh				}
75721674Sjkh				goto rflag;
758103399Stjr			}
7591573Srgrimes			width = n;
7601573Srgrimes			goto reswitch;
761128819Sdas#ifndef NO_FLOATING_POINT
7621573Srgrimes		case 'L':
7631573Srgrimes			flags |= LONGDBL;
7641573Srgrimes			goto rflag;
7651573Srgrimes#endif
7661573Srgrimes		case 'h':
76787113Sfenner			if (flags & SHORTINT) {
76887113Sfenner				flags &= ~SHORTINT;
76987113Sfenner				flags |= CHARINT;
77087113Sfenner			} else
77187113Sfenner				flags |= SHORTINT;
7721573Srgrimes			goto rflag;
77387113Sfenner		case 'j':
77487113Sfenner			flags |= INTMAXT;
77587113Sfenner			goto rflag;
7761573Srgrimes		case 'l':
77787113Sfenner			if (flags & LONGINT) {
77887113Sfenner				flags &= ~LONGINT;
77987113Sfenner				flags |= LLONGINT;
78087113Sfenner			} else
78144674Sdfr				flags |= LONGINT;
7821573Srgrimes			goto rflag;
7831573Srgrimes		case 'q':
78487113Sfenner			flags |= LLONGINT;	/* not necessarily */
7851573Srgrimes			goto rflag;
78687113Sfenner		case 't':
78787113Sfenner			flags |= PTRDIFFT;
78887113Sfenner			goto rflag;
78987113Sfenner		case 'z':
79087113Sfenner			flags |= SIZET;
79187113Sfenner			goto rflag;
792105204Stjr		case 'C':
793105204Stjr			flags |= LONGINT;
794105204Stjr			/*FALLTHROUGH*/
7951573Srgrimes		case 'c':
796103633Stjr			if (flags & LONGINT) {
797128002Stjr				static const mbstate_t initial;
798128002Stjr				mbstate_t mbs;
799103633Stjr				size_t mbseqlen;
800103633Stjr
801128002Stjr				mbs = initial;
802103633Stjr				mbseqlen = wcrtomb(cp = buf,
803128002Stjr				    (wchar_t)GETARG(wint_t), &mbs);
804105234Stjr				if (mbseqlen == (size_t)-1) {
805105234Stjr					fp->_flags |= __SERR;
806103633Stjr					goto error;
807105234Stjr				}
808103633Stjr				size = (int)mbseqlen;
809103633Stjr			} else {
810103633Stjr				*(cp = buf) = GETARG(int);
811103633Stjr				size = 1;
812103633Stjr			}
8131573Srgrimes			sign = '\0';
8141573Srgrimes			break;
8151573Srgrimes		case 'D':
8161573Srgrimes			flags |= LONGINT;
8171573Srgrimes			/*FALLTHROUGH*/
8181573Srgrimes		case 'd':
8191573Srgrimes		case 'i':
82087113Sfenner			if (flags & INTMAX_SIZE) {
82187113Sfenner				ujval = SJARG();
82287113Sfenner				if ((intmax_t)ujval < 0) {
82387113Sfenner					ujval = -ujval;
8241573Srgrimes					sign = '-';
8251573Srgrimes				}
8261573Srgrimes			} else {
8271573Srgrimes				ulval = SARG();
8281573Srgrimes				if ((long)ulval < 0) {
8291573Srgrimes					ulval = -ulval;
8301573Srgrimes					sign = '-';
8311573Srgrimes				}
8321573Srgrimes			}
8331573Srgrimes			base = 10;
8341573Srgrimes			goto number;
835128819Sdas#ifndef NO_FLOATING_POINT
83687113Sfenner		case 'a':
83787113Sfenner		case 'A':
838113146Sdas			if (ch == 'a') {
839113146Sdas				ox[1] = 'x';
840113146Sdas				xdigs = xdigs_lower;
841113146Sdas				expchar = 'p';
842113146Sdas			} else {
843113146Sdas				ox[1] = 'X';
844113146Sdas				xdigs = xdigs_upper;
845113146Sdas				expchar = 'P';
846113146Sdas			}
847124657Sdas			if (prec >= 0)
848124657Sdas				prec++;
849124657Sdas			if (dtoaresult != NULL)
850124657Sdas				freedtoa(dtoaresult);
851113146Sdas			if (flags & LONGDBL) {
852124657Sdas				fparg.ldbl = GETARG(long double);
853113146Sdas				dtoaresult = cp =
854113146Sdas				    __hldtoa(fparg.ldbl, xdigs, prec,
855113146Sdas				    &expt, &signflag, &dtoaend);
856113146Sdas			} else {
857113146Sdas				fparg.dbl = GETARG(double);
858113146Sdas				dtoaresult = cp =
859113146Sdas				    __hdtoa(fparg.dbl, xdigs, prec,
860113146Sdas				    &expt, &signflag, &dtoaend);
861113146Sdas			}
862124657Sdas			if (prec < 0)
863124657Sdas				prec = dtoaend - cp;
864124657Sdas			if (expt == INT_MAX)
865124657Sdas				ox[1] = '\0';
866124657Sdas			goto fp_common;
8677033Sbde		case 'e':
8681573Srgrimes		case 'E':
869113146Sdas			expchar = ch;
870113146Sdas			if (prec < 0)	/* account for digit before decpt */
871113146Sdas				prec = DEFPREC + 1;
872113146Sdas			else
873113146Sdas				prec++;
874113146Sdas			goto fp_begin;
8757033Sbde		case 'f':
87687113Sfenner		case 'F':
877113146Sdas			expchar = '\0';
8787033Sbde			goto fp_begin;
8791573Srgrimes		case 'g':
8801573Srgrimes		case 'G':
881113146Sdas			expchar = ch - ('g' - 'e');
8827033Sbde			if (prec == 0)
8837033Sbde				prec = 1;
884113146Sdasfp_begin:
885113146Sdas			if (prec < 0)
8861573Srgrimes				prec = DEFPREC;
887113146Sdas			if (dtoaresult != NULL)
888113146Sdas				freedtoa(dtoaresult);
889113146Sdas			if (flags & LONGDBL) {
890113146Sdas				fparg.ldbl = GETARG(long double);
891113146Sdas				dtoaresult = cp =
892113146Sdas				    __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
893113146Sdas				    &expt, &signflag, &dtoaend);
894113146Sdas			} else {
895113146Sdas				fparg.dbl = GETARG(double);
896113146Sdas				dtoaresult = cp =
897113146Sdas				    dtoa(fparg.dbl, expchar ? 2 : 3, prec,
898113146Sdas				    &expt, &signflag, &dtoaend);
899113146Sdas				if (expt == 9999)
900113146Sdas					expt = INT_MAX;
9011573Srgrimes			}
902124657Sdasfp_common:
903113146Sdas			if (signflag)
904113146Sdas				sign = '-';
905113146Sdas			if (expt == INT_MAX) {	/* inf or nan */
906113146Sdas				if (*cp == 'N') {
907113146Sdas					cp = (ch >= 'a') ? "nan" : "NAN";
908113146Sdas					sign = '\0';
909113146Sdas				} else
910113146Sdas					cp = (ch >= 'a') ? "inf" : "INF";
9111573Srgrimes				size = 3;
912169355Sdas				flags &= ~ZEROPAD;
9131573Srgrimes				break;
9141573Srgrimes			}
9151573Srgrimes			flags |= FPT;
916113146Sdas			ndig = dtoaend - cp;
9171573Srgrimes			if (ch == 'g' || ch == 'G') {
918113146Sdas				if (expt > -4 && expt <= prec) {
919113146Sdas					/* Make %[gG] smell like %[fF] */
920113146Sdas					expchar = '\0';
921113146Sdas					if (flags & ALT)
922113146Sdas						prec -= expt;
923113146Sdas					else
924113146Sdas						prec = ndig - expt;
925113146Sdas					if (prec < 0)
926113146Sdas						prec = 0;
927113723Sdas				} else {
928113723Sdas					/*
929113723Sdas					 * Make %[gG] smell like %[eE], but
930113723Sdas					 * trim trailing zeroes if no # flag.
931113723Sdas					 */
932113723Sdas					if (!(flags & ALT))
933113723Sdas						prec = ndig;
934113146Sdas				}
9358870Srgrimes			}
936113146Sdas			if (expchar) {
937113146Sdas				expsize = exponent(expstr, expt - 1, expchar);
938113146Sdas				size = expsize + prec;
939113191Sdas				if (prec > 1 || flags & ALT)
9401573Srgrimes					++size;
941113146Sdas			} else {
942113468Sdas				/* space for digits before decimal point */
943113468Sdas				if (expt > 0)
9441573Srgrimes					size = expt;
945113468Sdas				else	/* "0" */
946113468Sdas					size = 1;
947113468Sdas				/* space for decimal pt and following digits */
948113468Sdas				if (prec || flags & ALT)
949113468Sdas					size += prec + 1;
950113146Sdas				if (grouping && expt > 0) {
951113146Sdas					/* space for thousands' grouping */
952113146Sdas					nseps = nrepeats = 0;
953113146Sdas					lead = expt;
954113146Sdas					while (*grouping != CHAR_MAX) {
955113146Sdas						if (lead <= *grouping)
956113146Sdas							break;
957113146Sdas						lead -= *grouping;
958113146Sdas						if (*(grouping+1)) {
959113146Sdas							nseps++;
960113146Sdas							grouping++;
961113146Sdas						} else
962113146Sdas							nrepeats++;
963113146Sdas					}
964113146Sdas					size += nseps + nrepeats;
965113146Sdas				} else
966113194Sdas					lead = expt;
967113146Sdas			}
9681573Srgrimes			break;
969128819Sdas#endif /* !NO_FLOATING_POINT */
9701573Srgrimes		case 'n':
97187113Sfenner			/*
97287113Sfenner			 * Assignment-like behavior is specified if the
97387113Sfenner			 * value overflows or is otherwise unrepresentable.
97487113Sfenner			 * C99 says to use `signed char' for %hhn conversions.
97587113Sfenner			 */
97687113Sfenner			if (flags & LLONGINT)
97787113Sfenner				*GETARG(long long *) = ret;
97887113Sfenner			else if (flags & SIZET)
97987113Sfenner				*GETARG(ssize_t *) = (ssize_t)ret;
98087113Sfenner			else if (flags & PTRDIFFT)
98187113Sfenner				*GETARG(ptrdiff_t *) = ret;
98287113Sfenner			else if (flags & INTMAXT)
98387113Sfenner				*GETARG(intmax_t *) = ret;
9841573Srgrimes			else if (flags & LONGINT)
98531980Sache				*GETARG(long *) = ret;
9861573Srgrimes			else if (flags & SHORTINT)
98731980Sache				*GETARG(short *) = ret;
98887113Sfenner			else if (flags & CHARINT)
98987113Sfenner				*GETARG(signed char *) = ret;
9901573Srgrimes			else
99131980Sache				*GETARG(int *) = ret;
9921573Srgrimes			continue;	/* no output */
9931573Srgrimes		case 'O':
9941573Srgrimes			flags |= LONGINT;
9951573Srgrimes			/*FALLTHROUGH*/
9961573Srgrimes		case 'o':
99787113Sfenner			if (flags & INTMAX_SIZE)
99887113Sfenner				ujval = UJARG();
9991573Srgrimes			else
10001573Srgrimes				ulval = UARG();
10011573Srgrimes			base = 8;
10021573Srgrimes			goto nosign;
10031573Srgrimes		case 'p':
100488057Sphantom			/*-
10051573Srgrimes			 * ``The argument shall be a pointer to void.  The
10061573Srgrimes			 * value of the pointer is converted to a sequence
10071573Srgrimes			 * of printable characters, in an implementation-
10081573Srgrimes			 * defined manner.''
10091573Srgrimes			 *	-- ANSI X3J11
10101573Srgrimes			 */
101187113Sfenner			ujval = (uintmax_t)(uintptr_t)GETARG(void *);
10121573Srgrimes			base = 16;
1013113146Sdas			xdigs = xdigs_lower;
1014113146Sdas			flags = flags | INTMAXT;
1015113146Sdas			ox[1] = 'x';
10161573Srgrimes			goto nosign;
1017105204Stjr		case 'S':
1018105204Stjr			flags |= LONGINT;
1019105204Stjr			/*FALLTHROUGH*/
10201573Srgrimes		case 's':
1021103633Stjr			if (flags & LONGINT) {
1022103633Stjr				wchar_t *wcp;
1023103633Stjr
1024103633Stjr				if (convbuf != NULL)
1025103633Stjr					free(convbuf);
1026103633Stjr				if ((wcp = GETARG(wchar_t *)) == NULL)
1027103633Stjr					cp = "(null)";
1028103633Stjr				else {
1029103633Stjr					convbuf = __wcsconv(wcp, prec);
1030105234Stjr					if (convbuf == NULL) {
1031105234Stjr						fp->_flags |= __SERR;
1032103633Stjr						goto error;
1033105234Stjr					}
1034103633Stjr					cp = convbuf;
1035103633Stjr				}
1036103633Stjr			} else if ((cp = GETARG(char *)) == NULL)
10371573Srgrimes				cp = "(null)";
10381573Srgrimes			if (prec >= 0) {
10391573Srgrimes				/*
10401573Srgrimes				 * can't use strlen; can only look for the
10411573Srgrimes				 * NUL in the first `prec' characters, and
10421573Srgrimes				 * strlen() will go further.
10431573Srgrimes				 */
104416586Sjraynard				char *p = memchr(cp, 0, (size_t)prec);
10451573Srgrimes
10461573Srgrimes				if (p != NULL) {
10471573Srgrimes					size = p - cp;
10481573Srgrimes					if (size > prec)
10491573Srgrimes						size = prec;
10501573Srgrimes				} else
10511573Srgrimes					size = prec;
10521573Srgrimes			} else
10531573Srgrimes				size = strlen(cp);
10541573Srgrimes			sign = '\0';
10551573Srgrimes			break;
10561573Srgrimes		case 'U':
10571573Srgrimes			flags |= LONGINT;
10581573Srgrimes			/*FALLTHROUGH*/
10591573Srgrimes		case 'u':
106087113Sfenner			if (flags & INTMAX_SIZE)
106187113Sfenner				ujval = UJARG();
10621573Srgrimes			else
10631573Srgrimes				ulval = UARG();
10641573Srgrimes			base = 10;
10651573Srgrimes			goto nosign;
10661573Srgrimes		case 'X':
1067113146Sdas			xdigs = xdigs_upper;
10681573Srgrimes			goto hex;
10691573Srgrimes		case 'x':
1070113146Sdas			xdigs = xdigs_lower;
107187113Sfennerhex:
107287113Sfenner			if (flags & INTMAX_SIZE)
107387113Sfenner				ujval = UJARG();
10741573Srgrimes			else
10751573Srgrimes				ulval = UARG();
10761573Srgrimes			base = 16;
10771573Srgrimes			/* leading 0x/X only if non-zero */
10781573Srgrimes			if (flags & ALT &&
107987113Sfenner			    (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
1080113146Sdas				ox[1] = ch;
10811573Srgrimes
108287815Sphantom			flags &= ~GROUPING;
10831573Srgrimes			/* unsigned conversions */
10841573Srgrimesnosign:			sign = '\0';
108588057Sphantom			/*-
10861573Srgrimes			 * ``... diouXx conversions ... if a precision is
10871573Srgrimes			 * specified, the 0 flag will be ignored.''
10881573Srgrimes			 *	-- ANSI X3J11
10891573Srgrimes			 */
10901573Srgrimesnumber:			if ((dprec = prec) >= 0)
10911573Srgrimes				flags &= ~ZEROPAD;
10921573Srgrimes
109388057Sphantom			/*-
10941573Srgrimes			 * ``The result of converting a zero value with an
10951573Srgrimes			 * explicit precision of zero is no characters.''
10961573Srgrimes			 *	-- ANSI X3J11
1097145172Sdas			 *
1098145172Sdas			 * ``The C Standard is clear enough as is.  The call
1099145172Sdas			 * printf("%#.0o", 0) should print 0.''
1100145172Sdas			 *	-- Defect Report #151
11011573Srgrimes			 */
11021573Srgrimes			cp = buf + BUF;
110387113Sfenner			if (flags & INTMAX_SIZE) {
1104145172Sdas				if (ujval != 0 || prec != 0 ||
1105145172Sdas				    (flags & ALT && base == 8))
110687113Sfenner					cp = __ujtoa(ujval, cp, base,
110787815Sphantom					    flags & ALT, xdigs,
110887815Sphantom					    flags & GROUPING, thousands_sep,
110987815Sphantom					    grouping);
11101573Srgrimes			} else {
1111145172Sdas				if (ulval != 0 || prec != 0 ||
1112145172Sdas				    (flags & ALT && base == 8))
11131573Srgrimes					cp = __ultoa(ulval, cp, base,
111487815Sphantom					    flags & ALT, xdigs,
111587815Sphantom					    flags & GROUPING, thousands_sep,
111687815Sphantom					    grouping);
11171573Srgrimes			}
11181573Srgrimes			size = buf + BUF - cp;
1119113142Sdas			if (size > BUF)	/* should never happen */
1120113142Sdas				abort();
11211573Srgrimes			break;
11221573Srgrimes		default:	/* "%?" prints ?, unless ? is NUL */
11231573Srgrimes			if (ch == '\0')
11241573Srgrimes				goto done;
11251573Srgrimes			/* pretend it was %c with argument ch */
11261573Srgrimes			cp = buf;
11271573Srgrimes			*cp = ch;
11281573Srgrimes			size = 1;
11291573Srgrimes			sign = '\0';
11301573Srgrimes			break;
11311573Srgrimes		}
11321573Srgrimes
11331573Srgrimes		/*
11341573Srgrimes		 * All reasonable formats wind up here.  At this point, `cp'
11351573Srgrimes		 * points to a string which (if not flags&LADJUST) should be
11361573Srgrimes		 * padded out to `width' places.  If flags&ZEROPAD, it should
11371573Srgrimes		 * first be prefixed by any sign or other prefix; otherwise,
11381573Srgrimes		 * it should be blank padded before the prefix is emitted.
11391573Srgrimes		 * After any left-hand padding and prefixing, emit zeroes
11401573Srgrimes		 * required by a decimal [diouxX] precision, then print the
11411573Srgrimes		 * string proper, then emit zeroes required by any leftover
11421573Srgrimes		 * floating precision; finally, if LADJUST, pad with blanks.
11431573Srgrimes		 *
11441573Srgrimes		 * Compute actual size, so we know how much to pad.
114514727Sfenner		 * size excludes decimal prec; realsz includes it.
11461573Srgrimes		 */
114714727Sfenner		realsz = dprec > size ? dprec : size;
11481573Srgrimes		if (sign)
114914727Sfenner			realsz++;
1150124657Sdas		if (ox[1])
115114727Sfenner			realsz += 2;
11521573Srgrimes
115331983Sache		prsize = width > realsz ? width : realsz;
115432253Sache		if ((unsigned)ret + prsize > INT_MAX) {
115531983Sache			ret = EOF;
115631983Sache			goto error;
115731983Sache		}
115831983Sache
11591573Srgrimes		/* right-adjusting blank padding */
11601573Srgrimes		if ((flags & (LADJUST|ZEROPAD)) == 0)
11611573Srgrimes			PAD(width - realsz, blanks);
11621573Srgrimes
11631573Srgrimes		/* prefix */
1164124657Sdas		if (sign)
11651573Srgrimes			PRINT(&sign, 1);
1166124657Sdas
1167124657Sdas		if (ox[1]) {	/* ox[1] is either x, X, or \0 */
11681573Srgrimes			ox[0] = '0';
11691573Srgrimes			PRINT(ox, 2);
11701573Srgrimes		}
11711573Srgrimes
11721573Srgrimes		/* right-adjusting zero padding */
11731573Srgrimes		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
11741573Srgrimes			PAD(width - realsz, zeroes);
11751573Srgrimes
11761573Srgrimes		/* leading zeroes from decimal precision */
117714727Sfenner		PAD(dprec - size, zeroes);
11781573Srgrimes
11791573Srgrimes		/* the string or number proper */
1180128819Sdas#ifndef NO_FLOATING_POINT
11811573Srgrimes		if ((flags & FPT) == 0) {
11821573Srgrimes			PRINT(cp, size);
11831573Srgrimes		} else {	/* glue together f_p fragments */
1184113146Sdas			if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
1185113146Sdas				if (expt <= 0) {
1186113468Sdas					PRINT(zeroes, 1);
1187113468Sdas					if (prec || flags & ALT)
1188113468Sdas						PRINT(decimal_point, 1);
11891573Srgrimes					PAD(-expt, zeroes);
1190113191Sdas					/* already handled initial 0's */
1191113191Sdas					prec += expt;
11921573Srgrimes				} else {
1193113191Sdas					PRINTANDPAD(cp, dtoaend, lead, zeroes);
1194113146Sdas					cp += lead;
1195113146Sdas					if (grouping) {
1196113146Sdas						while (nseps>0 || nrepeats>0) {
1197113146Sdas							if (nrepeats > 0)
1198113146Sdas								nrepeats--;
1199113146Sdas							else {
1200113146Sdas								grouping--;
1201113146Sdas								nseps--;
1202113146Sdas							}
1203113146Sdas							PRINT(&thousands_sep,
1204113146Sdas							    1);
1205113191Sdas							PRINTANDPAD(cp,dtoaend,
1206113191Sdas							    *grouping, zeroes);
1207113146Sdas							cp += *grouping;
1208113146Sdas						}
1209113191Sdas						if (cp > dtoaend)
1210113191Sdas							cp = dtoaend;
1211113146Sdas					}
1212113146Sdas					if (prec || flags & ALT)
1213113146Sdas						PRINT(decimal_point,1);
12141573Srgrimes				}
1215113191Sdas				PRINTANDPAD(cp, dtoaend, prec, zeroes);
1216113146Sdas			} else {	/* %[eE] or sufficiently long %[gG] */
1217113191Sdas				if (prec > 1 || flags & ALT) {
1218113146Sdas					buf[0] = *cp++;
1219113146Sdas					buf[1] = *decimal_point;
1220113146Sdas					PRINT(buf, 2);
1221113146Sdas					PRINT(cp, ndig-1);
1222113146Sdas					PAD(prec - ndig, zeroes);
12231573Srgrimes				} else	/* XeYYY */
12241573Srgrimes					PRINT(cp, 1);
12251573Srgrimes				PRINT(expstr, expsize);
12261573Srgrimes			}
12271573Srgrimes		}
12281573Srgrimes#else
12291573Srgrimes		PRINT(cp, size);
12301573Srgrimes#endif
12311573Srgrimes		/* left-adjusting padding (always blank) */
12321573Srgrimes		if (flags & LADJUST)
12331573Srgrimes			PAD(width - realsz, blanks);
12341573Srgrimes
12351573Srgrimes		/* finally, adjust ret */
123631983Sache		ret += prsize;
12371573Srgrimes
12381573Srgrimes		FLUSH();	/* copy out the I/O vectors */
12391573Srgrimes	}
12401573Srgrimesdone:
12411573Srgrimes	FLUSH();
12421573Srgrimeserror:
1243134332Sdes	va_end(orgap);
1244128819Sdas#ifndef NO_FLOATING_POINT
124572523Stegge	if (dtoaresult != NULL)
1246113146Sdas		freedtoa(dtoaresult);
124772523Stegge#endif
1248103633Stjr	if (convbuf != NULL)
1249103633Stjr		free(convbuf);
125013545Sjulian	if (__sferror(fp))
125113545Sjulian		ret = EOF;
1252103399Stjr	if ((argtable != NULL) && (argtable != statargtable))
1253103399Stjr		free (argtable);
125413545Sjulian	return (ret);
12551573Srgrimes	/* NOTREACHED */
12561573Srgrimes}
12571573Srgrimes
125821674Sjkh/*
125921674Sjkh * Find all arguments when a positional parameter is encountered.  Returns a
126021674Sjkh * table, indexed by argument number, of pointers to each arguments.  The
126121674Sjkh * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
126270725Sarchie * It will be replaces with a malloc-ed one if it overflows.
126321674Sjkh */
126421674Sjkhstatic void
126584962Sbde__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
126621674Sjkh{
126771579Sdeischen	char *fmt;		/* format string */
126871579Sdeischen	int ch;			/* character from fmt */
126971579Sdeischen	int n, n2;		/* handy integer (short term usage) */
127071579Sdeischen	char *cp;		/* handy char pointer (short term usage) */
127171579Sdeischen	int flags;		/* flags as above */
127221674Sjkh	int width;		/* width from format (%8d), or 0 */
127387113Sfenner	enum typeid *typetable; /* table of types */
127487113Sfenner	enum typeid stattypetable [STATIC_ARG_TBL_SIZE];
127521674Sjkh	int tablesize;		/* current size of type table */
127621674Sjkh	int tablemax;		/* largest used index in table */
127721674Sjkh	int nextarg;		/* 1-based argument index */
127821674Sjkh
127921674Sjkh	/*
128021674Sjkh	 * Add an argument type to the table, expanding if necessary.
128121674Sjkh	 */
128221674Sjkh#define ADDTYPE(type) \
128321674Sjkh	((nextarg >= tablesize) ? \
1284130242Sstefanf		__grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \
128570725Sarchie	(nextarg > tablemax) ? tablemax = nextarg : 0, \
128670725Sarchie	typetable[nextarg++] = type)
128721674Sjkh
128821674Sjkh#define	ADDSARG() \
128987113Sfenner	((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \
129087113Sfenner		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
129187113Sfenner		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
129287113Sfenner		((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
129387113Sfenner		((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT))))))
129421674Sjkh
129521674Sjkh#define	ADDUARG() \
129687113Sfenner	((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \
129787113Sfenner		((flags&SIZET) ? ADDTYPE(T_SIZET) : \
129887113Sfenner		((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \
129987113Sfenner		((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
130087113Sfenner		((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT))))))
130121674Sjkh
130221674Sjkh	/*
130321674Sjkh	 * Add * arguments to the type array.
130421674Sjkh	 */
130521674Sjkh#define ADDASTER() \
130621674Sjkh	n2 = 0; \
130721674Sjkh	cp = fmt; \
130821674Sjkh	while (is_digit(*cp)) { \
130921674Sjkh		n2 = 10 * n2 + to_digit(*cp); \
131021674Sjkh		cp++; \
131121674Sjkh	} \
131221674Sjkh	if (*cp == '$') { \
131321674Sjkh		int hold = nextarg; \
131421674Sjkh		nextarg = n2; \
131521674Sjkh		ADDTYPE (T_INT); \
131621674Sjkh		nextarg = hold; \
131721674Sjkh		fmt = ++cp; \
131821674Sjkh	} else { \
131921674Sjkh		ADDTYPE (T_INT); \
132021674Sjkh	}
132121674Sjkh	fmt = (char *)fmt0;
132221674Sjkh	typetable = stattypetable;
132321674Sjkh	tablesize = STATIC_ARG_TBL_SIZE;
132421674Sjkh	tablemax = 0;
132521674Sjkh	nextarg = 1;
1326128550Stjr	for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
1327128550Stjr		typetable[n] = T_UNUSED;
132821674Sjkh
132921674Sjkh	/*
133021674Sjkh	 * Scan the format for conversions (`%' character).
133121674Sjkh	 */
133221674Sjkh	for (;;) {
133321674Sjkh		for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
133421674Sjkh			/* void */;
133521674Sjkh		if (ch == '\0')
133621674Sjkh			goto done;
133721674Sjkh		fmt++;		/* skip over '%' */
133821674Sjkh
133921674Sjkh		flags = 0;
134021674Sjkh		width = 0;
134121674Sjkh
134221674Sjkhrflag:		ch = *fmt++;
134321674Sjkhreswitch:	switch (ch) {
134421674Sjkh		case ' ':
134521674Sjkh		case '#':
134621674Sjkh			goto rflag;
134721674Sjkh		case '*':
134821674Sjkh			ADDASTER ();
134921674Sjkh			goto rflag;
135021674Sjkh		case '-':
135121674Sjkh		case '+':
135287113Sfenner		case '\'':
135321674Sjkh			goto rflag;
135421674Sjkh		case '.':
135521674Sjkh			if ((ch = *fmt++) == '*') {
135621674Sjkh				ADDASTER ();
135721674Sjkh				goto rflag;
135821674Sjkh			}
135921674Sjkh			while (is_digit(ch)) {
136021674Sjkh				ch = *fmt++;
136121674Sjkh			}
136221674Sjkh			goto reswitch;
136321674Sjkh		case '0':
136421674Sjkh			goto rflag;
136521674Sjkh		case '1': case '2': case '3': case '4':
136621674Sjkh		case '5': case '6': case '7': case '8': case '9':
136721674Sjkh			n = 0;
136821674Sjkh			do {
136921674Sjkh				n = 10 * n + to_digit(ch);
137021674Sjkh				ch = *fmt++;
137121674Sjkh			} while (is_digit(ch));
137221674Sjkh			if (ch == '$') {
137321674Sjkh				nextarg = n;
137421674Sjkh				goto rflag;
137521674Sjkh			}
137621674Sjkh			width = n;
137721674Sjkh			goto reswitch;
1378128819Sdas#ifndef NO_FLOATING_POINT
137921674Sjkh		case 'L':
138021674Sjkh			flags |= LONGDBL;
138121674Sjkh			goto rflag;
138221674Sjkh#endif
138321674Sjkh		case 'h':
138487113Sfenner			if (flags & SHORTINT) {
138587113Sfenner				flags &= ~SHORTINT;
138687113Sfenner				flags |= CHARINT;
138787113Sfenner			} else
138887113Sfenner				flags |= SHORTINT;
138921674Sjkh			goto rflag;
139087113Sfenner		case 'j':
139187113Sfenner			flags |= INTMAXT;
139287113Sfenner			goto rflag;
139321674Sjkh		case 'l':
139487113Sfenner			if (flags & LONGINT) {
139587113Sfenner				flags &= ~LONGINT;
139687113Sfenner				flags |= LLONGINT;
139787113Sfenner			} else
139844674Sdfr				flags |= LONGINT;
139921674Sjkh			goto rflag;
140021674Sjkh		case 'q':
140187113Sfenner			flags |= LLONGINT;	/* not necessarily */
140221674Sjkh			goto rflag;
140387113Sfenner		case 't':
140487113Sfenner			flags |= PTRDIFFT;
140587113Sfenner			goto rflag;
140687113Sfenner		case 'z':
140787113Sfenner			flags |= SIZET;
140887113Sfenner			goto rflag;
1409105204Stjr		case 'C':
1410105204Stjr			flags |= LONGINT;
1411105204Stjr			/*FALLTHROUGH*/
141221674Sjkh		case 'c':
1413103633Stjr			if (flags & LONGINT)
1414103633Stjr				ADDTYPE(T_WINT);
1415103633Stjr			else
1416103633Stjr				ADDTYPE(T_INT);
141721674Sjkh			break;
141821674Sjkh		case 'D':
141921674Sjkh			flags |= LONGINT;
142021674Sjkh			/*FALLTHROUGH*/
142121674Sjkh		case 'd':
142221674Sjkh		case 'i':
142387113Sfenner			ADDSARG();
142421674Sjkh			break;
1425128819Sdas#ifndef NO_FLOATING_POINT
142687113Sfenner		case 'a':
142787113Sfenner		case 'A':
142821674Sjkh		case 'e':
142921674Sjkh		case 'E':
143021674Sjkh		case 'f':
143121674Sjkh		case 'g':
143221674Sjkh		case 'G':
143321674Sjkh			if (flags & LONGDBL)
143421674Sjkh				ADDTYPE(T_LONG_DOUBLE);
143521674Sjkh			else
143621674Sjkh				ADDTYPE(T_DOUBLE);
143721674Sjkh			break;
1438128819Sdas#endif /* !NO_FLOATING_POINT */
143921674Sjkh		case 'n':
144087113Sfenner			if (flags & INTMAXT)
144187113Sfenner				ADDTYPE(TP_INTMAXT);
144287113Sfenner			else if (flags & PTRDIFFT)
144387113Sfenner				ADDTYPE(TP_PTRDIFFT);
144487113Sfenner			else if (flags & SIZET)
144587113Sfenner				ADDTYPE(TP_SIZET);
144687113Sfenner			else if (flags & LLONGINT)
144787113Sfenner				ADDTYPE(TP_LLONG);
144821674Sjkh			else if (flags & LONGINT)
144921674Sjkh				ADDTYPE(TP_LONG);
145021674Sjkh			else if (flags & SHORTINT)
145121674Sjkh				ADDTYPE(TP_SHORT);
145287113Sfenner			else if (flags & CHARINT)
145387113Sfenner				ADDTYPE(TP_SCHAR);
145421674Sjkh			else
145521674Sjkh				ADDTYPE(TP_INT);
145621674Sjkh			continue;	/* no output */
145721674Sjkh		case 'O':
145821674Sjkh			flags |= LONGINT;
145921674Sjkh			/*FALLTHROUGH*/
146021674Sjkh		case 'o':
146187113Sfenner			ADDUARG();
146221674Sjkh			break;
146321674Sjkh		case 'p':
146421674Sjkh			ADDTYPE(TP_VOID);
146521674Sjkh			break;
1466105204Stjr		case 'S':
1467105204Stjr			flags |= LONGINT;
1468105204Stjr			/*FALLTHROUGH*/
146921674Sjkh		case 's':
1470103633Stjr			if (flags & LONGINT)
1471103633Stjr				ADDTYPE(TP_WCHAR);
1472103633Stjr			else
1473103633Stjr				ADDTYPE(TP_CHAR);
147421674Sjkh			break;
147521674Sjkh		case 'U':
147621674Sjkh			flags |= LONGINT;
147721674Sjkh			/*FALLTHROUGH*/
147821674Sjkh		case 'u':
147921674Sjkh		case 'X':
148021674Sjkh		case 'x':
148187113Sfenner			ADDUARG();
148221674Sjkh			break;
148321674Sjkh		default:	/* "%?" prints ?, unless ? is NUL */
148421674Sjkh			if (ch == '\0')
148521674Sjkh				goto done;
148621674Sjkh			break;
148721674Sjkh		}
148821674Sjkh	}
148921674Sjkhdone:
149021674Sjkh	/*
149121674Sjkh	 * Build the argument table.
149221674Sjkh	 */
149321674Sjkh	if (tablemax >= STATIC_ARG_TBL_SIZE) {
149484922Sdfr		*argtable = (union arg *)
149584922Sdfr		    malloc (sizeof (union arg) * (tablemax + 1));
149621674Sjkh	}
14971573Srgrimes
149884922Sdfr	(*argtable) [0].intarg = 0;
149921674Sjkh	for (n = 1; n <= tablemax; n++) {
150021674Sjkh		switch (typetable [n]) {
150187113Sfenner		    case T_UNUSED: /* whoops! */
150284922Sdfr			(*argtable) [n].intarg = va_arg (ap, int);
150321674Sjkh			break;
150487113Sfenner		    case TP_SCHAR:
150587113Sfenner			(*argtable) [n].pschararg = va_arg (ap, signed char *);
150621674Sjkh			break;
150721674Sjkh		    case TP_SHORT:
150884922Sdfr			(*argtable) [n].pshortarg = va_arg (ap, short *);
150921674Sjkh			break;
151021674Sjkh		    case T_INT:
151184922Sdfr			(*argtable) [n].intarg = va_arg (ap, int);
151221674Sjkh			break;
151321674Sjkh		    case T_U_INT:
151484922Sdfr			(*argtable) [n].uintarg = va_arg (ap, unsigned int);
151521674Sjkh			break;
151621674Sjkh		    case TP_INT:
151784922Sdfr			(*argtable) [n].pintarg = va_arg (ap, int *);
151821674Sjkh			break;
151921674Sjkh		    case T_LONG:
152084922Sdfr			(*argtable) [n].longarg = va_arg (ap, long);
152121674Sjkh			break;
152221674Sjkh		    case T_U_LONG:
152384922Sdfr			(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
152421674Sjkh			break;
152521674Sjkh		    case TP_LONG:
152684922Sdfr			(*argtable) [n].plongarg = va_arg (ap, long *);
152721674Sjkh			break;
152887113Sfenner		    case T_LLONG:
152987113Sfenner			(*argtable) [n].longlongarg = va_arg (ap, long long);
153021674Sjkh			break;
153187113Sfenner		    case T_U_LLONG:
153287113Sfenner			(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
153321674Sjkh			break;
153487113Sfenner		    case TP_LLONG:
153587113Sfenner			(*argtable) [n].plonglongarg = va_arg (ap, long long *);
153621674Sjkh			break;
153787113Sfenner		    case T_PTRDIFFT:
153887113Sfenner			(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
153987113Sfenner			break;
154087113Sfenner		    case TP_PTRDIFFT:
154187113Sfenner			(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
154287113Sfenner			break;
154387113Sfenner		    case T_SIZET:
154487113Sfenner			(*argtable) [n].sizearg = va_arg (ap, size_t);
154587113Sfenner			break;
154687113Sfenner		    case TP_SIZET:
1547162523Skan			(*argtable) [n].psizearg = va_arg (ap, size_t *);
154887113Sfenner			break;
154987113Sfenner		    case T_INTMAXT:
155087113Sfenner			(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
155187113Sfenner			break;
155287113Sfenner		    case T_UINTMAXT:
155387113Sfenner			(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
155487113Sfenner			break;
155587113Sfenner		    case TP_INTMAXT:
155687113Sfenner			(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
155787113Sfenner			break;
1558157381Sphk		    case T_DOUBLE:
1559128819Sdas#ifndef NO_FLOATING_POINT
156084922Sdfr			(*argtable) [n].doublearg = va_arg (ap, double);
1561157381Sphk#endif
156221674Sjkh			break;
156321674Sjkh		    case T_LONG_DOUBLE:
1564157381Sphk#ifndef NO_FLOATING_POINT
156584922Sdfr			(*argtable) [n].longdoublearg = va_arg (ap, long double);
1566157381Sphk#endif
156721674Sjkh			break;
156821674Sjkh		    case TP_CHAR:
156984922Sdfr			(*argtable) [n].pchararg = va_arg (ap, char *);
157021674Sjkh			break;
157121674Sjkh		    case TP_VOID:
157284922Sdfr			(*argtable) [n].pvoidarg = va_arg (ap, void *);
157321674Sjkh			break;
1574103633Stjr		    case T_WINT:
1575103633Stjr			(*argtable) [n].wintarg = va_arg (ap, wint_t);
1576103633Stjr			break;
1577103633Stjr		    case TP_WCHAR:
1578103633Stjr			(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
1579103633Stjr			break;
158021674Sjkh		}
158121674Sjkh	}
158221674Sjkh
158321674Sjkh	if ((typetable != NULL) && (typetable != stattypetable))
158421674Sjkh		free (typetable);
158521674Sjkh}
158621674Sjkh
158721674Sjkh/*
158821674Sjkh * Increase the size of the type table.
158921674Sjkh */
159021674Sjkhstatic void
159187113Sfenner__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize)
159221674Sjkh{
159387113Sfenner	enum typeid *const oldtable = *typetable;
159470725Sarchie	const int oldsize = *tablesize;
159587113Sfenner	enum typeid *newtable;
1596128550Stjr	int n, newsize = oldsize * 2;
159721674Sjkh
159870725Sarchie	if (newsize < nextarg + 1)
159970725Sarchie		newsize = nextarg + 1;
160070725Sarchie	if (oldsize == STATIC_ARG_TBL_SIZE) {
1601128550Stjr		if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
160270725Sarchie			abort();			/* XXX handle better */
1603128550Stjr		bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
160421674Sjkh	} else {
1605128550Stjr		newtable = reallocf(oldtable, newsize * sizeof(enum typeid));
1606128550Stjr		if (newtable == NULL)
160770725Sarchie			abort();			/* XXX handle better */
160821674Sjkh	}
1609128550Stjr	for (n = oldsize; n < newsize; n++)
1610128550Stjr		newtable[n] = T_UNUSED;
161121674Sjkh
161270725Sarchie	*typetable = newtable;
161321674Sjkh	*tablesize = newsize;
161421674Sjkh}
161521674Sjkh
161621674Sjkh
1617128819Sdas#ifndef NO_FLOATING_POINT
161821674Sjkh
16191573Srgrimesstatic int
162071579Sdeischenexponent(char *p0, int exp, int fmtch)
16211573Srgrimes{
162271579Sdeischen	char *p, *t;
1623113142Sdas	char expbuf[MAXEXPDIG];
16241573Srgrimes
16251573Srgrimes	p = p0;
16261573Srgrimes	*p++ = fmtch;
16271573Srgrimes	if (exp < 0) {
16281573Srgrimes		exp = -exp;
16291573Srgrimes		*p++ = '-';
16301573Srgrimes	}
16311573Srgrimes	else
16321573Srgrimes		*p++ = '+';
1633113142Sdas	t = expbuf + MAXEXPDIG;
16341573Srgrimes	if (exp > 9) {
16351573Srgrimes		do {
16361573Srgrimes			*--t = to_char(exp % 10);
16371573Srgrimes		} while ((exp /= 10) > 9);
16381573Srgrimes		*--t = to_char(exp);
1639113142Sdas		for (; t < expbuf + MAXEXPDIG; *p++ = *t++);
16401573Srgrimes	}
16411573Srgrimes	else {
1642113146Sdas		/*
1643113146Sdas		 * Exponents for decimal floating point conversions
1644113146Sdas		 * (%[eEgG]) must be at least two characters long,
1645113146Sdas		 * whereas exponents for hexadecimal conversions can
1646113146Sdas		 * be only one character long.
1647113146Sdas		 */
1648113146Sdas		if (fmtch == 'e' || fmtch == 'E')
1649113146Sdas			*p++ = '0';
16501573Srgrimes		*p++ = to_char(exp);
16511573Srgrimes	}
16521573Srgrimes	return (p - p0);
16531573Srgrimes}
1654128819Sdas#endif /* !NO_FLOATING_POINT */
1655