1/*	$OpenBSD: vfprintf.c,v 1.71 2016/01/04 15:47:47 schwarze Exp $	*/
2/*-
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Chris Torek.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * Actual printf innards.
36 *
37 * This code is large and complicated...
38 */
39
40#include <sys/types.h>
41#include <sys/mman.h>
42
43#include <errno.h>
44#include <langinfo.h>
45#include <limits.h>
46#include <stdarg.h>
47#include <stddef.h>
48#include <stdio.h>
49#include <stdint.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53#include <wchar.h>
54
55#include "local.h"
56#include "fvwrite.h"
57
58union arg {
59	int			intarg;
60	unsigned int		uintarg;
61	long			longarg;
62	unsigned long		ulongarg;
63	long long		longlongarg;
64	unsigned long long	ulonglongarg;
65	ptrdiff_t		ptrdiffarg;
66	size_t			sizearg;
67	ssize_t			ssizearg;
68	intmax_t		intmaxarg;
69	uintmax_t		uintmaxarg;
70	void			*pvoidarg;
71	char			*pchararg;
72	signed char		*pschararg;
73	short			*pshortarg;
74	int			*pintarg;
75	long			*plongarg;
76	long long		*plonglongarg;
77	ptrdiff_t		*pptrdiffarg;
78	ssize_t			*pssizearg;
79	intmax_t		*pintmaxarg;
80#ifdef FLOATING_POINT
81	double			doublearg;
82	long double		longdoublearg;
83#endif
84#ifdef PRINTF_WIDE_CHAR
85	wint_t			wintarg;
86	wchar_t			*pwchararg;
87#endif
88};
89
90static int __find_arguments(const char *fmt0, va_list ap, union arg **argtable,
91    size_t *argtablesiz);
92static int __grow_type_table(unsigned char **typetable, int *tablesize);
93
94/*
95 * Flush out all the vectors defined by the given uio,
96 * then reset it so that it can be reused.
97 */
98static int
99__sprint(FILE *fp, struct __suio *uio)
100{
101	int err;
102
103	if (uio->uio_resid == 0) {
104		uio->uio_iovcnt = 0;
105		return (0);
106	}
107	err = __sfvwrite(fp, uio);
108	uio->uio_resid = 0;
109	uio->uio_iovcnt = 0;
110	return (err);
111}
112
113/*
114 * Helper function for `fprintf to unbuffered unix file': creates a
115 * temporary buffer.  We only work on write-only files; this avoids
116 * worries about ungetc buffers and so forth.
117 */
118static int
119__sbprintf(FILE *fp, const char *fmt, va_list ap)
120{
121	int ret;
122	FILE fake;
123	struct __sfileext fakeext;
124	unsigned char buf[BUFSIZ];
125
126	_FILEEXT_SETUP(&fake, &fakeext);
127	/* copy the important variables */
128	fake._flags = fp->_flags & ~__SNBF;
129	fake._file = fp->_file;
130	fake._cookie = fp->_cookie;
131	fake._write = fp->_write;
132
133	/* set up the buffer */
134	fake._bf._base = fake._p = buf;
135	fake._bf._size = fake._w = sizeof(buf);
136	fake._lbfsize = 0;	/* not actually used, but Just In Case */
137
138	/* do the work, then copy any error status */
139	ret = __vfprintf(&fake, fmt, ap);
140	if (ret >= 0 && __sflush(&fake))
141		ret = EOF;
142	if (fake._flags & __SERR)
143		fp->_flags |= __SERR;
144	return (ret);
145}
146
147#ifdef PRINTF_WIDE_CHAR
148/*
149 * Convert a wide character string argument for the %ls format to a multibyte
150 * string representation. If not -1, prec specifies the maximum number of
151 * bytes to output, and also means that we can't assume that the wide char
152 * string is null-terminated.
153 */
154static char *
155__wcsconv(wchar_t *wcsarg, int prec)
156{
157	mbstate_t mbs;
158	char buf[MB_LEN_MAX];
159	wchar_t *p;
160	char *convbuf;
161	size_t clen, nbytes;
162
163	/* Allocate space for the maximum number of bytes we could output. */
164	if (prec < 0) {
165		memset(&mbs, 0, sizeof(mbs));
166		p = wcsarg;
167		nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
168		if (nbytes == (size_t)-1)
169			return (NULL);
170	} else {
171		/*
172		 * Optimisation: if the output precision is small enough,
173		 * just allocate enough memory for the maximum instead of
174		 * scanning the string.
175		 */
176		if (prec < 128)
177			nbytes = prec;
178		else {
179			nbytes = 0;
180			p = wcsarg;
181			memset(&mbs, 0, sizeof(mbs));
182			for (;;) {
183				clen = wcrtomb(buf, *p++, &mbs);
184				if (clen == 0 || clen == (size_t)-1 ||
185				    nbytes + clen > (size_t)prec)
186					break;
187				nbytes += clen;
188			}
189			if (clen == (size_t)-1)
190				return (NULL);
191		}
192	}
193	if ((convbuf = malloc(nbytes + 1)) == NULL)
194		return (NULL);
195
196	/* Fill the output buffer. */
197	p = wcsarg;
198	memset(&mbs, 0, sizeof(mbs));
199	if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
200	    nbytes, &mbs)) == (size_t)-1) {
201		free(convbuf);
202		return (NULL);
203	}
204	convbuf[nbytes] = '\0';
205	return (convbuf);
206}
207#endif
208
209#ifdef FLOATING_POINT
210#include <float.h>
211#include <locale.h>
212#include <math.h>
213#include "floatio.h"
214#include "gdtoa.h"
215
216#define	DEFPREC		6
217
218static int exponent(char *, int, int);
219#endif /* FLOATING_POINT */
220
221/*
222 * The size of the buffer we use as scratch space for integer
223 * conversions, among other things.  Technically, we would need the
224 * most space for base 10 conversions with thousands' grouping
225 * characters between each pair of digits.  100 bytes is a
226 * conservative overestimate even for a 128-bit uintmax_t.
227 */
228#define BUF	100
229
230#define STATIC_ARG_TBL_SIZE 8	/* Size of static argument table. */
231
232
233/*
234 * Macros for converting digits to letters and vice versa
235 */
236#define	to_digit(c)	((c) - '0')
237#define is_digit(c)	((unsigned)to_digit(c) <= 9)
238#define	to_char(n)	((n) + '0')
239
240/*
241 * Flags used during conversion.
242 */
243#define	ALT		0x0001		/* alternate form */
244#define	LADJUST		0x0004		/* left adjustment */
245#define	LONGDBL		0x0008		/* long double */
246#define	LONGINT		0x0010		/* long integer */
247#define	LLONGINT	0x0020		/* long long integer */
248#define	SHORTINT	0x0040		/* short integer */
249#define	ZEROPAD		0x0080		/* zero (as opposed to blank) pad */
250#define FPT		0x0100		/* Floating point number */
251#define PTRINT		0x0200		/* (unsigned) ptrdiff_t */
252#define SIZEINT		0x0400		/* (signed) size_t */
253#define CHARINT		0x0800		/* 8 bit integer */
254#define MAXINT		0x1000		/* largest integer size (intmax_t) */
255
256int
257vfprintf(FILE *fp, const char *fmt0, __va_list ap)
258{
259	int ret;
260
261	FLOCKFILE(fp);
262	ret = __vfprintf(fp, fmt0, ap);
263	FUNLOCKFILE(fp);
264	return (ret);
265}
266DEF_STRONG(vfprintf);
267
268int
269__vfprintf(FILE *fp, const char *fmt0, __va_list ap)
270{
271	char *fmt;		/* format string */
272	int ch;			/* character from fmt */
273	int n, n2;		/* handy integers (short term usage) */
274	char *cp;		/* handy char pointer (short term usage) */
275	struct __siov *iovp;	/* for PRINT macro */
276	int flags;		/* flags as above */
277	int ret;		/* return value accumulator */
278	int width;		/* width from format (%8d), or 0 */
279	int prec;		/* precision from format; <0 for N/A */
280	char sign;		/* sign prefix (' ', '+', '-', or \0) */
281	wchar_t wc;
282	mbstate_t ps;
283#ifdef FLOATING_POINT
284	/*
285	 * We can decompose the printed representation of floating
286	 * point numbers into several parts, some of which may be empty:
287	 *
288	 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
289	 *    A       B     ---C---      D       E   F
290	 *
291	 * A:	'sign' holds this value if present; '\0' otherwise
292	 * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
293	 * C:	cp points to the string MMMNNN.  Leading and trailing
294	 *	zeros are not in the string and must be added.
295	 * D:	expchar holds this character; '\0' if no exponent, e.g. %f
296	 * F:	at least two digits for decimal, at least one digit for hex
297	 */
298	char *decimal_point = NULL;
299	int signflag;		/* true if float is negative */
300	union {			/* floating point arguments %[aAeEfFgG] */
301		double dbl;
302		long double ldbl;
303	} fparg;
304	int expt;		/* integer value of exponent */
305	char expchar;		/* exponent character: [eEpP\0] */
306	char *dtoaend;		/* pointer to end of converted digits */
307	int expsize;		/* character count for expstr */
308	int lead;		/* sig figs before decimal or group sep */
309	int ndig;		/* actual number of digits returned by dtoa */
310	char expstr[MAXEXPDIG+2];	/* buffer for exponent string: e+ZZZ */
311	char *dtoaresult = NULL;
312#endif
313
314	uintmax_t _umax;	/* integer arguments %[diouxX] */
315	enum { OCT, DEC, HEX } base;	/* base for %[diouxX] conversion */
316	int dprec;		/* a copy of prec if %[diouxX], 0 otherwise */
317	int realsz;		/* field size expanded by dprec */
318	int size;		/* size of converted field or string */
319	const char *xdigs;	/* digits for %[xX] conversion */
320#define NIOV 8
321	struct __suio uio;	/* output information: summary */
322	struct __siov iov[NIOV];/* ... and individual io vectors */
323	char buf[BUF];		/* buffer with space for digits of uintmax_t */
324	char ox[2];		/* space for 0x; ox[1] is either x, X, or \0 */
325	union arg *argtable;	/* args, built due to positional arg */
326	union arg statargtable[STATIC_ARG_TBL_SIZE];
327	size_t argtablesiz;
328	int nextarg;		/* 1-based argument index */
329	va_list orgap;		/* original argument pointer */
330#ifdef PRINTF_WIDE_CHAR
331	char *convbuf;		/* buffer for wide to multi-byte conversion */
332#endif
333
334	/*
335	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
336	 * fields occur frequently, increase PADSIZE and make the initialisers
337	 * below longer.
338	 */
339#define	PADSIZE	16		/* pad chunk size */
340	static char blanks[PADSIZE] =
341	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
342	static char zeroes[PADSIZE] =
343	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
344
345	static const char xdigs_lower[16] = "0123456789abcdef";
346	static const char xdigs_upper[16] = "0123456789ABCDEF";
347
348	/*
349	 * BEWARE, these `goto error' on error, and PAD uses `n'.
350	 */
351#define	PRINT(ptr, len) do { \
352	iovp->iov_base = (ptr); \
353	iovp->iov_len = (len); \
354	uio.uio_resid += (len); \
355	iovp++; \
356	if (++uio.uio_iovcnt >= NIOV) { \
357		if (__sprint(fp, &uio)) \
358			goto error; \
359		iovp = iov; \
360	} \
361} while (0)
362#define	PAD(howmany, with) do { \
363	if ((n = (howmany)) > 0) { \
364		while (n > PADSIZE) { \
365			PRINT(with, PADSIZE); \
366			n -= PADSIZE; \
367		} \
368		PRINT(with, n); \
369	} \
370} while (0)
371#define	PRINTANDPAD(p, ep, len, with) do {	\
372	n2 = (ep) - (p);       			\
373	if (n2 > (len))				\
374		n2 = (len);			\
375	if (n2 > 0)				\
376		PRINT((p), n2);			\
377	PAD((len) - (n2 > 0 ? n2 : 0), (with));	\
378} while(0)
379#define	FLUSH() do { \
380	if (uio.uio_resid && __sprint(fp, &uio)) \
381		goto error; \
382	uio.uio_iovcnt = 0; \
383	iovp = iov; \
384} while (0)
385
386	/*
387	 * To extend shorts properly, we need both signed and unsigned
388	 * argument extraction methods.
389	 */
390#define	SARG() \
391	((intmax_t)(flags&MAXINT ? GETARG(intmax_t) : \
392	    flags&LLONGINT ? GETARG(long long) : \
393	    flags&LONGINT ? GETARG(long) : \
394	    flags&PTRINT ? GETARG(ptrdiff_t) : \
395	    flags&SIZEINT ? GETARG(ssize_t) : \
396	    flags&SHORTINT ? (short)GETARG(int) : \
397	    flags&CHARINT ? (signed char)GETARG(int) : \
398	    GETARG(int)))
399#define	UARG() \
400	((uintmax_t)(flags&MAXINT ? GETARG(uintmax_t) : \
401	    flags&LLONGINT ? GETARG(unsigned long long) : \
402	    flags&LONGINT ? GETARG(unsigned long) : \
403	    flags&PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */ \
404	    flags&SIZEINT ? GETARG(size_t) : \
405	    flags&SHORTINT ? (unsigned short)GETARG(int) : \
406	    flags&CHARINT ? (unsigned char)GETARG(int) : \
407	    GETARG(unsigned int)))
408
409	/*
410	 * Append a digit to a value and check for overflow.
411	 */
412#define APPEND_DIGIT(val, dig) do { \
413	if ((val) > INT_MAX / 10) \
414		goto overflow; \
415	(val) *= 10; \
416	if ((val) > INT_MAX - to_digit((dig))) \
417		goto overflow; \
418	(val) += to_digit((dig)); \
419} while (0)
420
421	 /*
422	  * Get * arguments, including the form *nn$.  Preserve the nextarg
423	  * that the argument can be gotten once the type is determined.
424	  */
425#define GETASTER(val) \
426	n2 = 0; \
427	cp = fmt; \
428	while (is_digit(*cp)) { \
429		APPEND_DIGIT(n2, *cp); \
430		cp++; \
431	} \
432	if (*cp == '$') { \
433		int hold = nextarg; \
434		if (argtable == NULL) { \
435			argtable = statargtable; \
436			if (__find_arguments(fmt0, orgap, &argtable, \
437			    &argtablesiz) == -1) { \
438				ret = -1; \
439				goto error; \
440			} \
441		} \
442		nextarg = n2; \
443		val = GETARG(int); \
444		nextarg = hold; \
445		fmt = ++cp; \
446	} else { \
447		val = GETARG(int); \
448	}
449
450/*
451* Get the argument indexed by nextarg.   If the argument table is
452* built, use it to get the argument.  If its not, get the next
453* argument (and arguments must be gotten sequentially).
454*/
455#define GETARG(type) \
456	((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
457		(nextarg++, va_arg(ap, type)))
458
459	_SET_ORIENTATION(fp, -1);
460	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
461	if (cantwrite(fp)) {
462		errno = EBADF;
463		return (EOF);
464	}
465
466	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
467	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
468	    fp->_file >= 0)
469		return (__sbprintf(fp, fmt0, ap));
470
471	fmt = (char *)fmt0;
472	argtable = NULL;
473	nextarg = 1;
474	va_copy(orgap, ap);
475	uio.uio_iov = iovp = iov;
476	uio.uio_resid = 0;
477	uio.uio_iovcnt = 0;
478	ret = 0;
479#ifdef PRINTF_WIDE_CHAR
480	convbuf = NULL;
481#endif
482
483	memset(&ps, 0, sizeof(ps));
484	/*
485	 * Scan the format for conversions (`%' character).
486	 */
487	for (;;) {
488		cp = fmt;
489		while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
490			fmt += n;
491			if (wc == '%') {
492				fmt--;
493				break;
494			}
495		}
496		if (n < 0) {
497			ret = -1;
498			goto error;
499		}
500		if (fmt != cp) {
501			ptrdiff_t m = fmt - cp;
502			if (m < 0 || m > INT_MAX - ret)
503				goto overflow;
504			PRINT(cp, m);
505			ret += m;
506		}
507		if (n == 0)
508			goto done;
509		fmt++;		/* skip over '%' */
510
511		flags = 0;
512		dprec = 0;
513		width = 0;
514		prec = -1;
515		sign = '\0';
516		ox[1] = '\0';
517
518rflag:		ch = *fmt++;
519reswitch:	switch (ch) {
520		case ' ':
521			/*
522			 * ``If the space and + flags both appear, the space
523			 * flag will be ignored.''
524			 *	-- ANSI X3J11
525			 */
526			if (!sign)
527				sign = ' ';
528			goto rflag;
529		case '#':
530			flags |= ALT;
531			goto rflag;
532		case '\'':
533			/* grouping not implemented */
534			goto rflag;
535		case '*':
536			/*
537			 * ``A negative field width argument is taken as a
538			 * - flag followed by a positive field width.''
539			 *	-- ANSI X3J11
540			 * They don't exclude field widths read from args.
541			 */
542			GETASTER(width);
543			if (width >= 0)
544				goto rflag;
545			if (width == INT_MIN)
546				goto overflow;
547			width = -width;
548			/* FALLTHROUGH */
549		case '-':
550			flags |= LADJUST;
551			goto rflag;
552		case '+':
553			sign = '+';
554			goto rflag;
555		case '.':
556			if ((ch = *fmt++) == '*') {
557				GETASTER(n);
558				prec = n < 0 ? -1 : n;
559				goto rflag;
560			}
561			n = 0;
562			while (is_digit(ch)) {
563				APPEND_DIGIT(n, ch);
564				ch = *fmt++;
565			}
566			if (ch == '$') {
567				nextarg = n;
568				if (argtable == NULL) {
569					argtable = statargtable;
570					if (__find_arguments(fmt0, orgap,
571					    &argtable, &argtablesiz) == -1) {
572						ret = -1;
573						goto error;
574					}
575				}
576				goto rflag;
577			}
578			prec = n;
579			goto reswitch;
580		case '0':
581			/*
582			 * ``Note that 0 is taken as a flag, not as the
583			 * beginning of a field width.''
584			 *	-- ANSI X3J11
585			 */
586			flags |= ZEROPAD;
587			goto rflag;
588		case '1': case '2': case '3': case '4':
589		case '5': case '6': case '7': case '8': case '9':
590			n = 0;
591			do {
592				APPEND_DIGIT(n, ch);
593				ch = *fmt++;
594			} while (is_digit(ch));
595			if (ch == '$') {
596				nextarg = n;
597				if (argtable == NULL) {
598					argtable = statargtable;
599					if (__find_arguments(fmt0, orgap,
600					    &argtable, &argtablesiz) == -1) {
601						ret = -1;
602						goto error;
603					}
604				}
605				goto rflag;
606			}
607			width = n;
608			goto reswitch;
609#ifdef FLOATING_POINT
610		case 'L':
611			flags |= LONGDBL;
612			goto rflag;
613#endif
614		case 'h':
615			if (*fmt == 'h') {
616				fmt++;
617				flags |= CHARINT;
618			} else {
619				flags |= SHORTINT;
620			}
621			goto rflag;
622		case 'j':
623			flags |= MAXINT;
624			goto rflag;
625		case 'l':
626			if (*fmt == 'l') {
627				fmt++;
628				flags |= LLONGINT;
629			} else {
630				flags |= LONGINT;
631			}
632			goto rflag;
633		case 'q':
634			flags |= LLONGINT;
635			goto rflag;
636		case 't':
637			flags |= PTRINT;
638			goto rflag;
639		case 'z':
640			flags |= SIZEINT;
641			goto rflag;
642		case 'c':
643#ifdef PRINTF_WIDE_CHAR
644			if (flags & LONGINT) {
645				mbstate_t mbs;
646				size_t mbseqlen;
647
648				memset(&mbs, 0, sizeof(mbs));
649				mbseqlen = wcrtomb(buf,
650				    (wchar_t)GETARG(wint_t), &mbs);
651				if (mbseqlen == (size_t)-1) {
652					ret = -1;
653					goto error;
654				}
655				cp = buf;
656				size = (int)mbseqlen;
657			} else {
658#endif
659				*(cp = buf) = GETARG(int);
660				size = 1;
661#ifdef PRINTF_WIDE_CHAR
662			}
663#endif
664			sign = '\0';
665			break;
666		case 'D':
667			flags |= LONGINT;
668			/*FALLTHROUGH*/
669		case 'd':
670		case 'i':
671			_umax = SARG();
672			if ((intmax_t)_umax < 0) {
673				_umax = -_umax;
674				sign = '-';
675			}
676			base = DEC;
677			goto number;
678#ifdef FLOATING_POINT
679		case 'a':
680		case 'A':
681			if (ch == 'a') {
682				ox[1] = 'x';
683				xdigs = xdigs_lower;
684				expchar = 'p';
685			} else {
686				ox[1] = 'X';
687				xdigs = xdigs_upper;
688				expchar = 'P';
689			}
690			if (prec >= 0)
691				prec++;
692			if (dtoaresult)
693				__freedtoa(dtoaresult);
694			if (flags & LONGDBL) {
695				fparg.ldbl = GETARG(long double);
696				dtoaresult = cp =
697				    __hldtoa(fparg.ldbl, xdigs, prec,
698				    &expt, &signflag, &dtoaend);
699				if (dtoaresult == NULL) {
700					errno = ENOMEM;
701					goto error;
702				}
703			} else {
704				fparg.dbl = GETARG(double);
705				dtoaresult = cp =
706				    __hdtoa(fparg.dbl, xdigs, prec,
707				    &expt, &signflag, &dtoaend);
708				if (dtoaresult == NULL) {
709					errno = ENOMEM;
710					goto error;
711				}
712			}
713			if (prec < 0)
714				prec = dtoaend - cp;
715			if (expt == INT_MAX)
716				ox[1] = '\0';
717			goto fp_common;
718		case 'e':
719		case 'E':
720			expchar = ch;
721			if (prec < 0)	/* account for digit before decpt */
722				prec = DEFPREC + 1;
723			else
724				prec++;
725			goto fp_begin;
726		case 'f':
727		case 'F':
728			expchar = '\0';
729			goto fp_begin;
730		case 'g':
731		case 'G':
732			expchar = ch - ('g' - 'e');
733 			if (prec == 0)
734 				prec = 1;
735fp_begin:
736			if (prec < 0)
737				prec = DEFPREC;
738			if (dtoaresult)
739				__freedtoa(dtoaresult);
740			if (flags & LONGDBL) {
741				fparg.ldbl = GETARG(long double);
742				dtoaresult = cp =
743				    __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
744				    &expt, &signflag, &dtoaend);
745				if (dtoaresult == NULL) {
746					errno = ENOMEM;
747					goto error;
748				}
749			} else {
750				fparg.dbl = GETARG(double);
751				dtoaresult = cp =
752				    __dtoa(fparg.dbl, expchar ? 2 : 3, prec,
753				    &expt, &signflag, &dtoaend);
754				if (dtoaresult == NULL) {
755					errno = ENOMEM;
756					goto error;
757				}
758				if (expt == 9999)
759					expt = INT_MAX;
760 			}
761fp_common:
762			if (signflag)
763				sign = '-';
764			if (expt == INT_MAX) {	/* inf or nan */
765				if (*cp == 'N')
766					cp = (ch >= 'a') ? "nan" : "NAN";
767				else
768					cp = (ch >= 'a') ? "inf" : "INF";
769 				size = 3;
770				flags &= ~ZEROPAD;
771 				break;
772 			}
773			flags |= FPT;
774			ndig = dtoaend - cp;
775 			if (ch == 'g' || ch == 'G') {
776				if (expt > -4 && expt <= prec) {
777					/* Make %[gG] smell like %[fF] */
778					expchar = '\0';
779					if (flags & ALT)
780						prec -= expt;
781					else
782						prec = ndig - expt;
783					if (prec < 0)
784						prec = 0;
785				} else {
786					/*
787					 * Make %[gG] smell like %[eE], but
788					 * trim trailing zeroes if no # flag.
789					 */
790					if (!(flags & ALT))
791						prec = ndig;
792				}
793 			}
794			if (expchar) {
795				expsize = exponent(expstr, expt - 1, expchar);
796				size = expsize + prec;
797				if (prec > 1 || flags & ALT)
798 					++size;
799			} else {
800				/* space for digits before decimal point */
801				if (expt > 0)
802					size = expt;
803				else	/* "0" */
804					size = 1;
805				/* space for decimal pt and following digits */
806				if (prec || flags & ALT)
807					size += prec + 1;
808				lead = expt;
809			}
810			break;
811#endif /* FLOATING_POINT */
812#ifndef NO_PRINTF_PERCENT_N
813		case 'n':
814			if (flags & LLONGINT)
815				*GETARG(long long *) = ret;
816			else if (flags & LONGINT)
817				*GETARG(long *) = ret;
818			else if (flags & SHORTINT)
819				*GETARG(short *) = ret;
820			else if (flags & CHARINT)
821				*GETARG(signed char *) = ret;
822			else if (flags & PTRINT)
823				*GETARG(ptrdiff_t *) = ret;
824			else if (flags & SIZEINT)
825				*GETARG(ssize_t *) = ret;
826			else if (flags & MAXINT)
827				*GETARG(intmax_t *) = ret;
828			else
829				*GETARG(int *) = ret;
830			continue;	/* no output */
831#endif /* NO_PRINTF_PERCENT_N */
832		case 'O':
833			flags |= LONGINT;
834			/*FALLTHROUGH*/
835		case 'o':
836			_umax = UARG();
837			base = OCT;
838			goto nosign;
839		case 'p':
840			/*
841			 * ``The argument shall be a pointer to void.  The
842			 * value of the pointer is converted to a sequence
843			 * of printable characters, in an implementation-
844			 * defined manner.''
845			 *	-- ANSI X3J11
846			 */
847			_umax = (u_long)GETARG(void *);
848			base = HEX;
849			xdigs = xdigs_lower;
850			ox[1] = 'x';
851			goto nosign;
852		case 's':
853#ifdef PRINTF_WIDE_CHAR
854			if (flags & LONGINT) {
855				wchar_t *wcp;
856
857				free(convbuf);
858				convbuf = NULL;
859				if ((wcp = GETARG(wchar_t *)) == NULL) {
860					cp = "(null)";
861				} else {
862					convbuf = __wcsconv(wcp, prec);
863					if (convbuf == NULL) {
864						ret = -1;
865						goto error;
866					}
867					cp = convbuf;
868				}
869			} else
870#endif /* PRINTF_WIDE_CHAR */
871			if ((cp = GETARG(char *)) == NULL)
872				cp = "(null)";
873			if (prec >= 0) {
874				/*
875				 * can't use strlen; can only look for the
876				 * NUL in the first `prec' characters, and
877				 * strlen() will go further.
878				 */
879				char *p = memchr(cp, 0, prec);
880
881				size = p ? (p - cp) : prec;
882			} else {
883				size_t len;
884
885				if ((len = strlen(cp)) > INT_MAX)
886					goto overflow;
887				size = (int)len;
888			}
889			sign = '\0';
890			break;
891		case 'U':
892			flags |= LONGINT;
893			/*FALLTHROUGH*/
894		case 'u':
895			_umax = UARG();
896			base = DEC;
897			goto nosign;
898		case 'X':
899			xdigs = xdigs_upper;
900			goto hex;
901		case 'x':
902			xdigs = xdigs_lower;
903hex:			_umax = UARG();
904			base = HEX;
905			/* leading 0x/X only if non-zero */
906			if (flags & ALT && _umax != 0)
907				ox[1] = ch;
908
909			/* unsigned conversions */
910nosign:			sign = '\0';
911			/*
912			 * ``... diouXx conversions ... if a precision is
913			 * specified, the 0 flag will be ignored.''
914			 *	-- ANSI X3J11
915			 */
916number:			if ((dprec = prec) >= 0)
917				flags &= ~ZEROPAD;
918
919			/*
920			 * ``The result of converting a zero value with an
921			 * explicit precision of zero is no characters.''
922			 *	-- ANSI X3J11
923			 */
924			cp = buf + BUF;
925			if (_umax != 0 || prec != 0) {
926				/*
927				 * Unsigned mod is hard, and unsigned mod
928				 * by a constant is easier than that by
929				 * a variable; hence this switch.
930				 */
931				switch (base) {
932				case OCT:
933					do {
934						*--cp = to_char(_umax & 7);
935						_umax >>= 3;
936					} while (_umax);
937					/* handle octal leading 0 */
938					if (flags & ALT && *cp != '0')
939						*--cp = '0';
940					break;
941
942				case DEC:
943					/* many numbers are 1 digit */
944					while (_umax >= 10) {
945						*--cp = to_char(_umax % 10);
946						_umax /= 10;
947					}
948					*--cp = to_char(_umax);
949					break;
950
951				case HEX:
952					do {
953						*--cp = xdigs[_umax & 15];
954						_umax >>= 4;
955					} while (_umax);
956					break;
957
958				default:
959					cp = "bug in vfprintf: bad base";
960					size = strlen(cp);
961					goto skipsize;
962				}
963			}
964			size = buf + BUF - cp;
965			if (size > BUF)	/* should never happen */
966				abort();
967		skipsize:
968			break;
969		default:	/* "%?" prints ?, unless ? is NUL */
970			if (ch == '\0')
971				goto done;
972			/* pretend it was %c with argument ch */
973			cp = buf;
974			*cp = ch;
975			size = 1;
976			sign = '\0';
977			break;
978		}
979
980		/*
981		 * All reasonable formats wind up here.  At this point, `cp'
982		 * points to a string which (if not flags&LADJUST) should be
983		 * padded out to `width' places.  If flags&ZEROPAD, it should
984		 * first be prefixed by any sign or other prefix; otherwise,
985		 * it should be blank padded before the prefix is emitted.
986		 * After any left-hand padding and prefixing, emit zeroes
987		 * required by a decimal %[diouxX] precision, then print the
988		 * string proper, then emit zeroes required by any leftover
989		 * floating precision; finally, if LADJUST, pad with blanks.
990		 *
991		 * Compute actual size, so we know how much to pad.
992		 * size excludes decimal prec; realsz includes it.
993		 */
994		realsz = dprec > size ? dprec : size;
995		if (sign)
996			realsz++;
997		if (ox[1])
998			realsz+= 2;
999
1000		/* right-adjusting blank padding */
1001		if ((flags & (LADJUST|ZEROPAD)) == 0)
1002			PAD(width - realsz, blanks);
1003
1004		/* prefix */
1005		if (sign)
1006			PRINT(&sign, 1);
1007		if (ox[1]) {	/* ox[1] is either x, X, or \0 */
1008			ox[0] = '0';
1009			PRINT(ox, 2);
1010		}
1011
1012		/* right-adjusting zero padding */
1013		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1014			PAD(width - realsz, zeroes);
1015
1016		/* leading zeroes from decimal precision */
1017		PAD(dprec - size, zeroes);
1018
1019		/* the string or number proper */
1020#ifdef FLOATING_POINT
1021		if ((flags & FPT) == 0) {
1022			PRINT(cp, size);
1023		} else {	/* glue together f_p fragments */
1024			if (decimal_point == NULL)
1025				decimal_point = nl_langinfo(RADIXCHAR);
1026			if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
1027				if (expt <= 0) {
1028					PRINT(zeroes, 1);
1029					if (prec || flags & ALT)
1030						PRINT(decimal_point, 1);
1031					PAD(-expt, zeroes);
1032					/* already handled initial 0's */
1033					prec += expt;
1034 				} else {
1035					PRINTANDPAD(cp, dtoaend, lead, zeroes);
1036					cp += lead;
1037					if (prec || flags & ALT)
1038						PRINT(decimal_point, 1);
1039				}
1040				PRINTANDPAD(cp, dtoaend, prec, zeroes);
1041			} else {	/* %[eE] or sufficiently long %[gG] */
1042				if (prec > 1 || flags & ALT) {
1043					buf[0] = *cp++;
1044					buf[1] = *decimal_point;
1045					PRINT(buf, 2);
1046					PRINT(cp, ndig-1);
1047					PAD(prec - ndig, zeroes);
1048				} else { /* XeYYY */
1049					PRINT(cp, 1);
1050				}
1051				PRINT(expstr, expsize);
1052			}
1053		}
1054#else
1055		PRINT(cp, size);
1056#endif
1057		/* left-adjusting padding (always blank) */
1058		if (flags & LADJUST)
1059			PAD(width - realsz, blanks);
1060
1061		/* finally, adjust ret */
1062		if (width < realsz)
1063			width = realsz;
1064		if (width > INT_MAX - ret)
1065			goto overflow;
1066		ret += width;
1067
1068		FLUSH();	/* copy out the I/O vectors */
1069	}
1070done:
1071	FLUSH();
1072error:
1073	va_end(orgap);
1074	if (__sferror(fp))
1075		ret = -1;
1076	goto finish;
1077
1078overflow:
1079	errno = ENOMEM;
1080	ret = -1;
1081
1082finish:
1083#ifdef PRINTF_WIDE_CHAR
1084	free(convbuf);
1085#endif
1086#ifdef FLOATING_POINT
1087	if (dtoaresult)
1088		__freedtoa(dtoaresult);
1089#endif
1090	if (argtable != NULL && argtable != statargtable) {
1091		munmap(argtable, argtablesiz);
1092		argtable = NULL;
1093	}
1094	return (ret);
1095}
1096
1097/*
1098 * Type ids for argument type table.
1099 */
1100#define T_UNUSED	0
1101#define T_SHORT		1
1102#define T_U_SHORT	2
1103#define TP_SHORT	3
1104#define T_INT		4
1105#define T_U_INT		5
1106#define TP_INT		6
1107#define T_LONG		7
1108#define T_U_LONG	8
1109#define TP_LONG		9
1110#define T_LLONG		10
1111#define T_U_LLONG	11
1112#define TP_LLONG	12
1113#define T_DOUBLE	13
1114#define T_LONG_DOUBLE	14
1115#define TP_CHAR		15
1116#define TP_VOID		16
1117#define T_PTRINT	17
1118#define TP_PTRINT	18
1119#define T_SIZEINT	19
1120#define T_SSIZEINT	20
1121#define TP_SSIZEINT	21
1122#define T_MAXINT	22
1123#define T_MAXUINT	23
1124#define TP_MAXINT	24
1125#define T_CHAR		25
1126#define T_U_CHAR	26
1127#define T_WINT		27
1128#define TP_WCHAR	28
1129
1130/*
1131 * Find all arguments when a positional parameter is encountered.  Returns a
1132 * table, indexed by argument number, of pointers to each arguments.  The
1133 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
1134 * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
1135 * used since we are attempting to make snprintf thread safe, and alloca is
1136 * problematic since we have nested functions..)
1137 */
1138static int
1139__find_arguments(const char *fmt0, va_list ap, union arg **argtable,
1140    size_t *argtablesiz)
1141{
1142	char *fmt;		/* format string */
1143	int ch;			/* character from fmt */
1144	int n, n2;		/* handy integer (short term usage) */
1145	char *cp;		/* handy char pointer (short term usage) */
1146	int flags;		/* flags as above */
1147	unsigned char *typetable; /* table of types */
1148	unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
1149	int tablesize;		/* current size of type table */
1150	int tablemax;		/* largest used index in table */
1151	int nextarg;		/* 1-based argument index */
1152	int ret = 0;		/* return value */
1153	wchar_t wc;
1154	mbstate_t ps;
1155
1156	/*
1157	 * Add an argument type to the table, expanding if necessary.
1158	 */
1159#define ADDTYPE(type) \
1160	((nextarg >= tablesize) ? \
1161		__grow_type_table(&typetable, &tablesize) : 0, \
1162	(nextarg > tablemax) ? tablemax = nextarg : 0, \
1163	typetable[nextarg++] = type)
1164
1165#define	ADDSARG() \
1166        ((flags&MAXINT) ? ADDTYPE(T_MAXINT) : \
1167	    ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
1168	    ((flags&SIZEINT) ? ADDTYPE(T_SSIZEINT) : \
1169	    ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
1170	    ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
1171	    ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : \
1172	    ((flags&CHARINT) ? ADDTYPE(T_CHAR) : ADDTYPE(T_INT))))))))
1173
1174#define	ADDUARG() \
1175        ((flags&MAXINT) ? ADDTYPE(T_MAXUINT) : \
1176	    ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
1177	    ((flags&SIZEINT) ? ADDTYPE(T_SIZEINT) : \
1178	    ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
1179	    ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
1180	    ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : \
1181	    ((flags&CHARINT) ? ADDTYPE(T_U_CHAR) : ADDTYPE(T_U_INT))))))))
1182
1183	/*
1184	 * Add * arguments to the type array.
1185	 */
1186#define ADDASTER() \
1187	n2 = 0; \
1188	cp = fmt; \
1189	while (is_digit(*cp)) { \
1190		APPEND_DIGIT(n2, *cp); \
1191		cp++; \
1192	} \
1193	if (*cp == '$') { \
1194		int hold = nextarg; \
1195		nextarg = n2; \
1196		ADDTYPE(T_INT); \
1197		nextarg = hold; \
1198		fmt = ++cp; \
1199	} else { \
1200		ADDTYPE(T_INT); \
1201	}
1202	fmt = (char *)fmt0;
1203	typetable = stattypetable;
1204	tablesize = STATIC_ARG_TBL_SIZE;
1205	tablemax = 0;
1206	nextarg = 1;
1207	memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
1208	memset(&ps, 0, sizeof(ps));
1209
1210	/*
1211	 * Scan the format for conversions (`%' character).
1212	 */
1213	for (;;) {
1214		cp = fmt;
1215		while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
1216			fmt += n;
1217			if (wc == '%') {
1218				fmt--;
1219				break;
1220			}
1221		}
1222		if (n < 0)
1223			return (-1);
1224		if (n == 0)
1225			goto done;
1226		fmt++;		/* skip over '%' */
1227
1228		flags = 0;
1229
1230rflag:		ch = *fmt++;
1231reswitch:	switch (ch) {
1232		case ' ':
1233		case '#':
1234		case '\'':
1235			goto rflag;
1236		case '*':
1237			ADDASTER();
1238			goto rflag;
1239		case '-':
1240		case '+':
1241			goto rflag;
1242		case '.':
1243			if ((ch = *fmt++) == '*') {
1244				ADDASTER();
1245				goto rflag;
1246			}
1247			while (is_digit(ch)) {
1248				ch = *fmt++;
1249			}
1250			goto reswitch;
1251		case '0':
1252			goto rflag;
1253		case '1': case '2': case '3': case '4':
1254		case '5': case '6': case '7': case '8': case '9':
1255			n = 0;
1256			do {
1257				APPEND_DIGIT(n ,ch);
1258				ch = *fmt++;
1259			} while (is_digit(ch));
1260			if (ch == '$') {
1261				nextarg = n;
1262				goto rflag;
1263			}
1264			goto reswitch;
1265#ifdef FLOATING_POINT
1266		case 'L':
1267			flags |= LONGDBL;
1268			goto rflag;
1269#endif
1270		case 'h':
1271			if (*fmt == 'h') {
1272				fmt++;
1273				flags |= CHARINT;
1274			} else {
1275				flags |= SHORTINT;
1276			}
1277			goto rflag;
1278		case 'j':
1279			flags |= MAXINT;
1280			goto rflag;
1281		case 'l':
1282			if (*fmt == 'l') {
1283				fmt++;
1284				flags |= LLONGINT;
1285			} else {
1286				flags |= LONGINT;
1287			}
1288			goto rflag;
1289		case 'q':
1290			flags |= LLONGINT;
1291			goto rflag;
1292		case 't':
1293			flags |= PTRINT;
1294			goto rflag;
1295		case 'z':
1296			flags |= SIZEINT;
1297			goto rflag;
1298		case 'c':
1299#ifdef PRINTF_WIDE_CHAR
1300			if (flags & LONGINT)
1301				ADDTYPE(T_WINT);
1302			else
1303#endif
1304				ADDTYPE(T_INT);
1305			break;
1306		case 'D':
1307			flags |= LONGINT;
1308			/*FALLTHROUGH*/
1309		case 'd':
1310		case 'i':
1311			ADDSARG();
1312			break;
1313#ifdef FLOATING_POINT
1314		case 'a':
1315		case 'A':
1316		case 'e':
1317		case 'E':
1318		case 'f':
1319		case 'F':
1320		case 'g':
1321		case 'G':
1322			if (flags & LONGDBL)
1323				ADDTYPE(T_LONG_DOUBLE);
1324			else
1325				ADDTYPE(T_DOUBLE);
1326			break;
1327#endif /* FLOATING_POINT */
1328#ifndef NO_PRINTF_PERCENT_N
1329		case 'n':
1330			if (flags & LLONGINT)
1331				ADDTYPE(TP_LLONG);
1332			else if (flags & LONGINT)
1333				ADDTYPE(TP_LONG);
1334			else if (flags & SHORTINT)
1335				ADDTYPE(TP_SHORT);
1336			else if (flags & PTRINT)
1337				ADDTYPE(TP_PTRINT);
1338			else if (flags & SIZEINT)
1339				ADDTYPE(TP_SSIZEINT);
1340			else if (flags & MAXINT)
1341				ADDTYPE(TP_MAXINT);
1342			else
1343				ADDTYPE(TP_INT);
1344			continue;	/* no output */
1345#endif /* NO_PRINTF_PERCENT_N */
1346		case 'O':
1347			flags |= LONGINT;
1348			/*FALLTHROUGH*/
1349		case 'o':
1350			ADDUARG();
1351			break;
1352		case 'p':
1353			ADDTYPE(TP_VOID);
1354			break;
1355		case 's':
1356#ifdef PRINTF_WIDE_CHAR
1357			if (flags & LONGINT)
1358				ADDTYPE(TP_WCHAR);
1359			else
1360#endif
1361				ADDTYPE(TP_CHAR);
1362			break;
1363		case 'U':
1364			flags |= LONGINT;
1365			/*FALLTHROUGH*/
1366		case 'u':
1367		case 'X':
1368		case 'x':
1369			ADDUARG();
1370			break;
1371		default:	/* "%?" prints ?, unless ? is NUL */
1372			if (ch == '\0')
1373				goto done;
1374			break;
1375		}
1376	}
1377done:
1378	/*
1379	 * Build the argument table.
1380	 */
1381	if (tablemax >= STATIC_ARG_TBL_SIZE) {
1382		*argtablesiz = sizeof(union arg) * (tablemax + 1);
1383		*argtable = mmap(NULL, *argtablesiz,
1384		    PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);
1385		if (*argtable == MAP_FAILED)
1386			return (-1);
1387	}
1388
1389#if 0
1390	/* XXX is this required? */
1391	(*argtable)[0].intarg = 0;
1392#endif
1393	for (n = 1; n <= tablemax; n++) {
1394		switch (typetable[n]) {
1395		case T_UNUSED:
1396		case T_CHAR:
1397		case T_U_CHAR:
1398		case T_SHORT:
1399		case T_U_SHORT:
1400		case T_INT:
1401			(*argtable)[n].intarg = va_arg(ap, int);
1402			break;
1403		case TP_SHORT:
1404			(*argtable)[n].pshortarg = va_arg(ap, short *);
1405			break;
1406		case T_U_INT:
1407			(*argtable)[n].uintarg = va_arg(ap, unsigned int);
1408			break;
1409		case TP_INT:
1410			(*argtable)[n].pintarg = va_arg(ap, int *);
1411			break;
1412		case T_LONG:
1413			(*argtable)[n].longarg = va_arg(ap, long);
1414			break;
1415		case T_U_LONG:
1416			(*argtable)[n].ulongarg = va_arg(ap, unsigned long);
1417			break;
1418		case TP_LONG:
1419			(*argtable)[n].plongarg = va_arg(ap, long *);
1420			break;
1421		case T_LLONG:
1422			(*argtable)[n].longlongarg = va_arg(ap, long long);
1423			break;
1424		case T_U_LLONG:
1425			(*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
1426			break;
1427		case TP_LLONG:
1428			(*argtable)[n].plonglongarg = va_arg(ap, long long *);
1429			break;
1430#ifdef FLOATING_POINT
1431		case T_DOUBLE:
1432			(*argtable)[n].doublearg = va_arg(ap, double);
1433			break;
1434		case T_LONG_DOUBLE:
1435			(*argtable)[n].longdoublearg = va_arg(ap, long double);
1436			break;
1437#endif
1438		case TP_CHAR:
1439			(*argtable)[n].pchararg = va_arg(ap, char *);
1440			break;
1441		case TP_VOID:
1442			(*argtable)[n].pvoidarg = va_arg(ap, void *);
1443			break;
1444		case T_PTRINT:
1445			(*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
1446			break;
1447		case TP_PTRINT:
1448			(*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *);
1449			break;
1450		case T_SIZEINT:
1451			(*argtable)[n].sizearg = va_arg(ap, size_t);
1452			break;
1453		case T_SSIZEINT:
1454			(*argtable)[n].ssizearg = va_arg(ap, ssize_t);
1455			break;
1456		case TP_SSIZEINT:
1457			(*argtable)[n].pssizearg = va_arg(ap, ssize_t *);
1458			break;
1459		case T_MAXINT:
1460			(*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
1461			break;
1462		case T_MAXUINT:
1463			(*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t);
1464			break;
1465		case TP_MAXINT:
1466			(*argtable)[n].pintmaxarg = va_arg(ap, intmax_t *);
1467			break;
1468#ifdef PRINTF_WIDE_CHAR
1469		case T_WINT:
1470			(*argtable)[n].wintarg = va_arg(ap, wint_t);
1471			break;
1472		case TP_WCHAR:
1473			(*argtable)[n].pwchararg = va_arg(ap, wchar_t *);
1474			break;
1475#endif
1476		}
1477	}
1478	goto finish;
1479
1480overflow:
1481	errno = ENOMEM;
1482	ret = -1;
1483
1484finish:
1485	if (typetable != NULL && typetable != stattypetable) {
1486		munmap(typetable, *argtablesiz);
1487		typetable = NULL;
1488	}
1489	return (ret);
1490}
1491
1492/*
1493 * Increase the size of the type table.
1494 */
1495static int
1496__grow_type_table(unsigned char **typetable, int *tablesize)
1497{
1498	unsigned char *oldtable = *typetable;
1499	int newsize = *tablesize * 2;
1500
1501	if (newsize < getpagesize())
1502		newsize = getpagesize();
1503
1504	if (*tablesize == STATIC_ARG_TBL_SIZE) {
1505		*typetable = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
1506		    MAP_ANON|MAP_PRIVATE, -1, 0);
1507		if (*typetable == MAP_FAILED)
1508			return (-1);
1509		bcopy(oldtable, *typetable, *tablesize);
1510	} else {
1511		unsigned char *new = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
1512		    MAP_ANON|MAP_PRIVATE, -1, 0);
1513		if (new == MAP_FAILED)
1514			return (-1);
1515		memmove(new, *typetable, *tablesize);
1516		munmap(*typetable, *tablesize);
1517		*typetable = new;
1518	}
1519	memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize));
1520
1521	*tablesize = newsize;
1522	return (0);
1523}
1524
1525
1526#ifdef FLOATING_POINT
1527static int
1528exponent(char *p0, int exp, int fmtch)
1529{
1530	char *p, *t;
1531	char expbuf[MAXEXPDIG];
1532
1533	p = p0;
1534	*p++ = fmtch;
1535	if (exp < 0) {
1536		exp = -exp;
1537		*p++ = '-';
1538	} else
1539		*p++ = '+';
1540	t = expbuf + MAXEXPDIG;
1541	if (exp > 9) {
1542		do {
1543			*--t = to_char(exp % 10);
1544		} while ((exp /= 10) > 9);
1545		*--t = to_char(exp);
1546		for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
1547			/* nothing */;
1548	} else {
1549		/*
1550		 * Exponents for decimal floating point conversions
1551		 * (%[eEgG]) must be at least two characters long,
1552		 * whereas exponents for hexadecimal conversions can
1553		 * be only one character long.
1554		 */
1555		if (fmtch == 'e' || fmtch == 'E')
1556			*p++ = '0';
1557		*p++ = to_char(exp);
1558	}
1559	return (p - p0);
1560}
1561#endif /* FLOATING_POINT */
1562