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