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