1/*	$OpenBSD: vfprintf.c,v 1.67 2014/12/21 00:23:30 daniel 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				else
759					cp = (ch >= 'a') ? "inf" : "INF";
760 				size = 3;
761				flags &= ~ZEROPAD;
762 				break;
763 			}
764			flags |= FPT;
765			ndig = dtoaend - cp;
766 			if (ch == 'g' || ch == 'G') {
767				if (expt > -4 && expt <= prec) {
768					/* Make %[gG] smell like %[fF] */
769					expchar = '\0';
770					if (flags & ALT)
771						prec -= expt;
772					else
773						prec = ndig - expt;
774					if (prec < 0)
775						prec = 0;
776				} else {
777					/*
778					 * Make %[gG] smell like %[eE], but
779					 * trim trailing zeroes if no # flag.
780					 */
781					if (!(flags & ALT))
782						prec = ndig;
783				}
784 			}
785			if (expchar) {
786				expsize = exponent(expstr, expt - 1, expchar);
787				size = expsize + prec;
788				if (prec > 1 || flags & ALT)
789 					++size;
790			} else {
791				/* space for digits before decimal point */
792				if (expt > 0)
793					size = expt;
794				else	/* "0" */
795					size = 1;
796				/* space for decimal pt and following digits */
797				if (prec || flags & ALT)
798					size += prec + 1;
799				lead = expt;
800			}
801			break;
802#endif /* FLOATING_POINT */
803#ifndef NO_PRINTF_PERCENT_N
804		case 'n':
805			if (flags & LLONGINT)
806				*GETARG(long long *) = ret;
807			else if (flags & LONGINT)
808				*GETARG(long *) = ret;
809			else if (flags & SHORTINT)
810				*GETARG(short *) = ret;
811			else if (flags & CHARINT)
812				*GETARG(signed char *) = ret;
813			else if (flags & PTRINT)
814				*GETARG(ptrdiff_t *) = ret;
815			else if (flags & SIZEINT)
816				*GETARG(ssize_t *) = ret;
817			else if (flags & MAXINT)
818				*GETARG(intmax_t *) = ret;
819			else
820				*GETARG(int *) = ret;
821			continue;	/* no output */
822#endif /* NO_PRINTF_PERCENT_N */
823		case 'O':
824			flags |= LONGINT;
825			/*FALLTHROUGH*/
826		case 'o':
827			_umax = UARG();
828			base = OCT;
829			goto nosign;
830		case 'p':
831			/*
832			 * ``The argument shall be a pointer to void.  The
833			 * value of the pointer is converted to a sequence
834			 * of printable characters, in an implementation-
835			 * defined manner.''
836			 *	-- ANSI X3J11
837			 */
838			/* NOSTRICT */
839			_umax = (u_long)GETARG(void *);
840			base = HEX;
841			xdigs = xdigs_lower;
842			ox[1] = 'x';
843			goto nosign;
844		case 's':
845#ifdef PRINTF_WIDE_CHAR
846			if (flags & LONGINT) {
847				wchar_t *wcp;
848
849				if (convbuf != NULL) {
850					free(convbuf);
851					convbuf = NULL;
852				}
853				if ((wcp = GETARG(wchar_t *)) == NULL) {
854					cp = "(null)";
855				} else {
856					convbuf = __wcsconv(wcp, prec);
857					if (convbuf == NULL) {
858						fp->_flags = __SERR;
859						goto error;
860					}
861					cp = convbuf;
862				}
863			} else
864#endif /* PRINTF_WIDE_CHAR */
865			if ((cp = GETARG(char *)) == NULL)
866				cp = "(null)";
867			if (prec >= 0) {
868				/*
869				 * can't use strlen; can only look for the
870				 * NUL in the first `prec' characters, and
871				 * strlen() will go further.
872				 */
873				char *p = memchr(cp, 0, prec);
874
875				size = p ? (p - cp) : prec;
876			} else {
877				size_t len;
878
879				if ((len = strlen(cp)) > INT_MAX)
880					goto overflow;
881				size = (int)len;
882			}
883			sign = '\0';
884			break;
885		case 'U':
886			flags |= LONGINT;
887			/*FALLTHROUGH*/
888		case 'u':
889			_umax = UARG();
890			base = DEC;
891			goto nosign;
892		case 'X':
893			xdigs = xdigs_upper;
894			goto hex;
895		case 'x':
896			xdigs = xdigs_lower;
897hex:			_umax = UARG();
898			base = HEX;
899			/* leading 0x/X only if non-zero */
900			if (flags & ALT && _umax != 0)
901				ox[1] = ch;
902
903			/* unsigned conversions */
904nosign:			sign = '\0';
905			/*
906			 * ``... diouXx conversions ... if a precision is
907			 * specified, the 0 flag will be ignored.''
908			 *	-- ANSI X3J11
909			 */
910number:			if ((dprec = prec) >= 0)
911				flags &= ~ZEROPAD;
912
913			/*
914			 * ``The result of converting a zero value with an
915			 * explicit precision of zero is no characters.''
916			 *	-- ANSI X3J11
917			 */
918			cp = buf + BUF;
919			if (_umax != 0 || prec != 0) {
920				/*
921				 * Unsigned mod is hard, and unsigned mod
922				 * by a constant is easier than that by
923				 * a variable; hence this switch.
924				 */
925				switch (base) {
926				case OCT:
927					do {
928						*--cp = to_char(_umax & 7);
929						_umax >>= 3;
930					} while (_umax);
931					/* handle octal leading 0 */
932					if (flags & ALT && *cp != '0')
933						*--cp = '0';
934					break;
935
936				case DEC:
937					/* many numbers are 1 digit */
938					while (_umax >= 10) {
939						*--cp = to_char(_umax % 10);
940						_umax /= 10;
941					}
942					*--cp = to_char(_umax);
943					break;
944
945				case HEX:
946					do {
947						*--cp = xdigs[_umax & 15];
948						_umax >>= 4;
949					} while (_umax);
950					break;
951
952				default:
953					cp = "bug in vfprintf: bad base";
954					size = strlen(cp);
955					goto skipsize;
956				}
957			}
958			size = buf + BUF - cp;
959			if (size > BUF)	/* should never happen */
960				abort();
961		skipsize:
962			break;
963		default:	/* "%?" prints ?, unless ? is NUL */
964			if (ch == '\0')
965				goto done;
966			/* pretend it was %c with argument ch */
967			cp = buf;
968			*cp = ch;
969			size = 1;
970			sign = '\0';
971			break;
972		}
973
974		/*
975		 * All reasonable formats wind up here.  At this point, `cp'
976		 * points to a string which (if not flags&LADJUST) should be
977		 * padded out to `width' places.  If flags&ZEROPAD, it should
978		 * first be prefixed by any sign or other prefix; otherwise,
979		 * it should be blank padded before the prefix is emitted.
980		 * After any left-hand padding and prefixing, emit zeroes
981		 * required by a decimal %[diouxX] precision, then print the
982		 * string proper, then emit zeroes required by any leftover
983		 * floating precision; finally, if LADJUST, pad with blanks.
984		 *
985		 * Compute actual size, so we know how much to pad.
986		 * size excludes decimal prec; realsz includes it.
987		 */
988		realsz = dprec > size ? dprec : size;
989		if (sign)
990			realsz++;
991		if (ox[1])
992			realsz+= 2;
993
994		/* right-adjusting blank padding */
995		if ((flags & (LADJUST|ZEROPAD)) == 0)
996			PAD(width - realsz, blanks);
997
998		/* prefix */
999		if (sign)
1000			PRINT(&sign, 1);
1001		if (ox[1]) {	/* ox[1] is either x, X, or \0 */
1002			ox[0] = '0';
1003			PRINT(ox, 2);
1004		}
1005
1006		/* right-adjusting zero padding */
1007		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
1008			PAD(width - realsz, zeroes);
1009
1010		/* leading zeroes from decimal precision */
1011		PAD(dprec - size, zeroes);
1012
1013		/* the string or number proper */
1014#ifdef FLOATING_POINT
1015		if ((flags & FPT) == 0) {
1016			PRINT(cp, size);
1017		} else {	/* glue together f_p fragments */
1018			if (decimal_point == NULL)
1019				decimal_point = nl_langinfo(RADIXCHAR);
1020			if (!expchar) {	/* %[fF] or sufficiently short %[gG] */
1021				if (expt <= 0) {
1022					PRINT(zeroes, 1);
1023					if (prec || flags & ALT)
1024						PRINT(decimal_point, 1);
1025					PAD(-expt, zeroes);
1026					/* already handled initial 0's */
1027					prec += expt;
1028 				} else {
1029					PRINTANDPAD(cp, dtoaend, lead, zeroes);
1030					cp += lead;
1031					if (prec || flags & ALT)
1032						PRINT(decimal_point, 1);
1033				}
1034				PRINTANDPAD(cp, dtoaend, prec, zeroes);
1035			} else {	/* %[eE] or sufficiently long %[gG] */
1036				if (prec > 1 || flags & ALT) {
1037					buf[0] = *cp++;
1038					buf[1] = *decimal_point;
1039					PRINT(buf, 2);
1040					PRINT(cp, ndig-1);
1041					PAD(prec - ndig, zeroes);
1042				} else { /* XeYYY */
1043					PRINT(cp, 1);
1044				}
1045				PRINT(expstr, expsize);
1046			}
1047		}
1048#else
1049		PRINT(cp, size);
1050#endif
1051		/* left-adjusting padding (always blank) */
1052		if (flags & LADJUST)
1053			PAD(width - realsz, blanks);
1054
1055		/* finally, adjust ret */
1056		if (width < realsz)
1057			width = realsz;
1058		if (width > INT_MAX - ret)
1059			goto overflow;
1060		ret += width;
1061
1062		FLUSH();	/* copy out the I/O vectors */
1063	}
1064done:
1065	FLUSH();
1066error:
1067	va_end(orgap);
1068	if (__sferror(fp))
1069		ret = -1;
1070	goto finish;
1071
1072overflow:
1073	errno = ENOMEM;
1074	ret = -1;
1075
1076finish:
1077#ifdef PRINTF_WIDE_CHAR
1078	if (convbuf)
1079		free(convbuf);
1080#endif
1081#ifdef FLOATING_POINT
1082	if (dtoaresult)
1083		__freedtoa(dtoaresult);
1084#endif
1085	if (argtable != NULL && argtable != statargtable) {
1086		munmap(argtable, argtablesiz);
1087		argtable = NULL;
1088	}
1089	return (ret);
1090}
1091
1092/*
1093 * Type ids for argument type table.
1094 */
1095#define T_UNUSED	0
1096#define T_SHORT		1
1097#define T_U_SHORT	2
1098#define TP_SHORT	3
1099#define T_INT		4
1100#define T_U_INT		5
1101#define TP_INT		6
1102#define T_LONG		7
1103#define T_U_LONG	8
1104#define TP_LONG		9
1105#define T_LLONG		10
1106#define T_U_LLONG	11
1107#define TP_LLONG	12
1108#define T_DOUBLE	13
1109#define T_LONG_DOUBLE	14
1110#define TP_CHAR		15
1111#define TP_VOID		16
1112#define T_PTRINT	17
1113#define TP_PTRINT	18
1114#define T_SIZEINT	19
1115#define T_SSIZEINT	20
1116#define TP_SSIZEINT	21
1117#define T_MAXINT	22
1118#define T_MAXUINT	23
1119#define TP_MAXINT	24
1120#define T_CHAR		25
1121#define T_U_CHAR	26
1122#define T_WINT		27
1123#define TP_WCHAR	28
1124
1125/*
1126 * Find all arguments when a positional parameter is encountered.  Returns a
1127 * table, indexed by argument number, of pointers to each arguments.  The
1128 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
1129 * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
1130 * used since we are attempting to make snprintf thread safe, and alloca is
1131 * problematic since we have nested functions..)
1132 */
1133static int
1134__find_arguments(const char *fmt0, va_list ap, union arg **argtable,
1135    size_t *argtablesiz)
1136{
1137	char *fmt;		/* format string */
1138	int ch;			/* character from fmt */
1139	int n, n2;		/* handy integer (short term usage) */
1140	char *cp;		/* handy char pointer (short term usage) */
1141	int flags;		/* flags as above */
1142	unsigned char *typetable; /* table of types */
1143	unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
1144	int tablesize;		/* current size of type table */
1145	int tablemax;		/* largest used index in table */
1146	int nextarg;		/* 1-based argument index */
1147	int ret = 0;		/* return value */
1148	wchar_t wc;
1149	mbstate_t ps;
1150
1151	/*
1152	 * Add an argument type to the table, expanding if necessary.
1153	 */
1154#define ADDTYPE(type) \
1155	((nextarg >= tablesize) ? \
1156		__grow_type_table(&typetable, &tablesize) : 0, \
1157	(nextarg > tablemax) ? tablemax = nextarg : 0, \
1158	typetable[nextarg++] = type)
1159
1160#define	ADDSARG() \
1161        ((flags&MAXINT) ? ADDTYPE(T_MAXINT) : \
1162	    ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
1163	    ((flags&SIZEINT) ? ADDTYPE(T_SSIZEINT) : \
1164	    ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
1165	    ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
1166	    ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : \
1167	    ((flags&CHARINT) ? ADDTYPE(T_CHAR) : ADDTYPE(T_INT))))))))
1168
1169#define	ADDUARG() \
1170        ((flags&MAXINT) ? ADDTYPE(T_MAXUINT) : \
1171	    ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
1172	    ((flags&SIZEINT) ? ADDTYPE(T_SIZEINT) : \
1173	    ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
1174	    ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
1175	    ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : \
1176	    ((flags&CHARINT) ? ADDTYPE(T_U_CHAR) : ADDTYPE(T_U_INT))))))))
1177
1178	/*
1179	 * Add * arguments to the type array.
1180	 */
1181#define ADDASTER() \
1182	n2 = 0; \
1183	cp = fmt; \
1184	while (is_digit(*cp)) { \
1185		APPEND_DIGIT(n2, *cp); \
1186		cp++; \
1187	} \
1188	if (*cp == '$') { \
1189		int hold = nextarg; \
1190		nextarg = n2; \
1191		ADDTYPE(T_INT); \
1192		nextarg = hold; \
1193		fmt = ++cp; \
1194	} else { \
1195		ADDTYPE(T_INT); \
1196	}
1197	fmt = (char *)fmt0;
1198	typetable = stattypetable;
1199	tablesize = STATIC_ARG_TBL_SIZE;
1200	tablemax = 0;
1201	nextarg = 1;
1202	memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
1203	memset(&ps, 0, sizeof(ps));
1204
1205	/*
1206	 * Scan the format for conversions (`%' character).
1207	 */
1208	for (;;) {
1209		cp = fmt;
1210		while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
1211			fmt += n;
1212			if (wc == '%') {
1213				fmt--;
1214				break;
1215			}
1216		}
1217		if (n <= 0)
1218			goto done;
1219		fmt++;		/* skip over '%' */
1220
1221		flags = 0;
1222
1223rflag:		ch = *fmt++;
1224reswitch:	switch (ch) {
1225		case ' ':
1226		case '#':
1227		case '\'':
1228			goto rflag;
1229		case '*':
1230			ADDASTER();
1231			goto rflag;
1232		case '-':
1233		case '+':
1234			goto rflag;
1235		case '.':
1236			if ((ch = *fmt++) == '*') {
1237				ADDASTER();
1238				goto rflag;
1239			}
1240			while (is_digit(ch)) {
1241				ch = *fmt++;
1242			}
1243			goto reswitch;
1244		case '0':
1245			goto rflag;
1246		case '1': case '2': case '3': case '4':
1247		case '5': case '6': case '7': case '8': case '9':
1248			n = 0;
1249			do {
1250				APPEND_DIGIT(n ,ch);
1251				ch = *fmt++;
1252			} while (is_digit(ch));
1253			if (ch == '$') {
1254				nextarg = n;
1255				goto rflag;
1256			}
1257			goto reswitch;
1258#ifdef FLOATING_POINT
1259		case 'L':
1260			flags |= LONGDBL;
1261			goto rflag;
1262#endif
1263		case 'h':
1264			if (*fmt == 'h') {
1265				fmt++;
1266				flags |= CHARINT;
1267			} else {
1268				flags |= SHORTINT;
1269			}
1270			goto rflag;
1271		case 'j':
1272			flags |= MAXINT;
1273			goto rflag;
1274		case 'l':
1275			if (*fmt == 'l') {
1276				fmt++;
1277				flags |= LLONGINT;
1278			} else {
1279				flags |= LONGINT;
1280			}
1281			goto rflag;
1282		case 'q':
1283			flags |= LLONGINT;
1284			goto rflag;
1285		case 't':
1286			flags |= PTRINT;
1287			goto rflag;
1288		case 'z':
1289			flags |= SIZEINT;
1290			goto rflag;
1291		case 'c':
1292#ifdef PRINTF_WIDE_CHAR
1293			if (flags & LONGINT)
1294				ADDTYPE(T_WINT);
1295			else
1296#endif
1297				ADDTYPE(T_INT);
1298			break;
1299		case 'D':
1300			flags |= LONGINT;
1301			/*FALLTHROUGH*/
1302		case 'd':
1303		case 'i':
1304			ADDSARG();
1305			break;
1306#ifdef FLOATING_POINT
1307		case 'a':
1308		case 'A':
1309		case 'e':
1310		case 'E':
1311		case 'f':
1312		case 'F':
1313		case 'g':
1314		case 'G':
1315			if (flags & LONGDBL)
1316				ADDTYPE(T_LONG_DOUBLE);
1317			else
1318				ADDTYPE(T_DOUBLE);
1319			break;
1320#endif /* FLOATING_POINT */
1321#ifndef NO_PRINTF_PERCENT_N
1322		case 'n':
1323			if (flags & LLONGINT)
1324				ADDTYPE(TP_LLONG);
1325			else if (flags & LONGINT)
1326				ADDTYPE(TP_LONG);
1327			else if (flags & SHORTINT)
1328				ADDTYPE(TP_SHORT);
1329			else if (flags & PTRINT)
1330				ADDTYPE(TP_PTRINT);
1331			else if (flags & SIZEINT)
1332				ADDTYPE(TP_SSIZEINT);
1333			else if (flags & MAXINT)
1334				ADDTYPE(TP_MAXINT);
1335			else
1336				ADDTYPE(TP_INT);
1337			continue;	/* no output */
1338#endif /* NO_PRINTF_PERCENT_N */
1339		case 'O':
1340			flags |= LONGINT;
1341			/*FALLTHROUGH*/
1342		case 'o':
1343			ADDUARG();
1344			break;
1345		case 'p':
1346			ADDTYPE(TP_VOID);
1347			break;
1348		case 's':
1349#ifdef PRINTF_WIDE_CHAR
1350			if (flags & LONGINT)
1351				ADDTYPE(TP_WCHAR);
1352			else
1353#endif
1354				ADDTYPE(TP_CHAR);
1355			break;
1356		case 'U':
1357			flags |= LONGINT;
1358			/*FALLTHROUGH*/
1359		case 'u':
1360		case 'X':
1361		case 'x':
1362			ADDUARG();
1363			break;
1364		default:	/* "%?" prints ?, unless ? is NUL */
1365			if (ch == '\0')
1366				goto done;
1367			break;
1368		}
1369	}
1370done:
1371	/*
1372	 * Build the argument table.
1373	 */
1374	if (tablemax >= STATIC_ARG_TBL_SIZE) {
1375		*argtablesiz = sizeof(union arg) * (tablemax + 1);
1376		*argtable = mmap(NULL, *argtablesiz,
1377		    PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);
1378		if (*argtable == MAP_FAILED)
1379			return (-1);
1380	}
1381
1382#if 0
1383	/* XXX is this required? */
1384	(*argtable)[0].intarg = 0;
1385#endif
1386	for (n = 1; n <= tablemax; n++) {
1387		switch (typetable[n]) {
1388		case T_UNUSED:
1389		case T_CHAR:
1390		case T_U_CHAR:
1391		case T_SHORT:
1392		case T_U_SHORT:
1393		case T_INT:
1394			(*argtable)[n].intarg = va_arg(ap, int);
1395			break;
1396		case TP_SHORT:
1397			(*argtable)[n].pshortarg = va_arg(ap, short *);
1398			break;
1399		case T_U_INT:
1400			(*argtable)[n].uintarg = va_arg(ap, unsigned int);
1401			break;
1402		case TP_INT:
1403			(*argtable)[n].pintarg = va_arg(ap, int *);
1404			break;
1405		case T_LONG:
1406			(*argtable)[n].longarg = va_arg(ap, long);
1407			break;
1408		case T_U_LONG:
1409			(*argtable)[n].ulongarg = va_arg(ap, unsigned long);
1410			break;
1411		case TP_LONG:
1412			(*argtable)[n].plongarg = va_arg(ap, long *);
1413			break;
1414		case T_LLONG:
1415			(*argtable)[n].longlongarg = va_arg(ap, long long);
1416			break;
1417		case T_U_LLONG:
1418			(*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
1419			break;
1420		case TP_LLONG:
1421			(*argtable)[n].plonglongarg = va_arg(ap, long long *);
1422			break;
1423#ifdef FLOATING_POINT
1424		case T_DOUBLE:
1425			(*argtable)[n].doublearg = va_arg(ap, double);
1426			break;
1427		case T_LONG_DOUBLE:
1428			(*argtable)[n].longdoublearg = va_arg(ap, long double);
1429			break;
1430#endif
1431		case TP_CHAR:
1432			(*argtable)[n].pchararg = va_arg(ap, char *);
1433			break;
1434		case TP_VOID:
1435			(*argtable)[n].pvoidarg = va_arg(ap, void *);
1436			break;
1437		case T_PTRINT:
1438			(*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
1439			break;
1440		case TP_PTRINT:
1441			(*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *);
1442			break;
1443		case T_SIZEINT:
1444			(*argtable)[n].sizearg = va_arg(ap, size_t);
1445			break;
1446		case T_SSIZEINT:
1447			(*argtable)[n].ssizearg = va_arg(ap, ssize_t);
1448			break;
1449		case TP_SSIZEINT:
1450			(*argtable)[n].pssizearg = va_arg(ap, ssize_t *);
1451			break;
1452		case T_MAXINT:
1453			(*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
1454			break;
1455		case T_MAXUINT:
1456			(*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t);
1457			break;
1458		case TP_MAXINT:
1459			(*argtable)[n].pintmaxarg = va_arg(ap, intmax_t *);
1460			break;
1461#ifdef PRINTF_WIDE_CHAR
1462		case T_WINT:
1463			(*argtable)[n].wintarg = va_arg(ap, wint_t);
1464			break;
1465		case TP_WCHAR:
1466			(*argtable)[n].pwchararg = va_arg(ap, wchar_t *);
1467			break;
1468#endif
1469		}
1470	}
1471	goto finish;
1472
1473overflow:
1474	errno = ENOMEM;
1475	ret = -1;
1476
1477finish:
1478	if (typetable != NULL && typetable != stattypetable) {
1479		munmap(typetable, *argtablesiz);
1480		typetable = NULL;
1481	}
1482	return (ret);
1483}
1484
1485/*
1486 * Increase the size of the type table.
1487 */
1488static int
1489__grow_type_table(unsigned char **typetable, int *tablesize)
1490{
1491	unsigned char *oldtable = *typetable;
1492	int newsize = *tablesize * 2;
1493
1494	if (newsize < getpagesize())
1495		newsize = getpagesize();
1496
1497	if (*tablesize == STATIC_ARG_TBL_SIZE) {
1498		*typetable = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
1499		    MAP_ANON|MAP_PRIVATE, -1, 0);
1500		if (*typetable == MAP_FAILED)
1501			return (-1);
1502		bcopy(oldtable, *typetable, *tablesize);
1503	} else {
1504		unsigned char *new = mmap(NULL, newsize, PROT_WRITE|PROT_READ,
1505		    MAP_ANON|MAP_PRIVATE, -1, 0);
1506		if (new == MAP_FAILED)
1507			return (-1);
1508		memmove(new, *typetable, *tablesize);
1509		munmap(*typetable, *tablesize);
1510		*typetable = new;
1511	}
1512	memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize));
1513
1514	*tablesize = newsize;
1515	return (0);
1516}
1517
1518
1519#ifdef FLOATING_POINT
1520static int
1521exponent(char *p0, int exp, int fmtch)
1522{
1523	char *p, *t;
1524	char expbuf[MAXEXPDIG];
1525
1526	p = p0;
1527	*p++ = fmtch;
1528	if (exp < 0) {
1529		exp = -exp;
1530		*p++ = '-';
1531	} else
1532		*p++ = '+';
1533	t = expbuf + MAXEXPDIG;
1534	if (exp > 9) {
1535		do {
1536			*--t = to_char(exp % 10);
1537		} while ((exp /= 10) > 9);
1538		*--t = to_char(exp);
1539		for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
1540			/* nothing */;
1541	} else {
1542		/*
1543		 * Exponents for decimal floating point conversions
1544		 * (%[eEgG]) must be at least two characters long,
1545		 * whereas exponents for hexadecimal conversions can
1546		 * be only one character long.
1547		 */
1548		if (fmtch == 'e' || fmtch == 'E')
1549			*p++ = '0';
1550		*p++ = to_char(exp);
1551	}
1552	return (p - p0);
1553}
1554#endif /* FLOATING_POINT */
1555