xref: /freebsd/lib/libc/stdio/printf-pos.c (revision 97721eb583806b8deebcf708630ba1e54eed6324)
12591efccSDavid Schultz /*-
22591efccSDavid Schultz  * Copyright (c) 1990, 1993
32591efccSDavid Schultz  *	The Regents of the University of California.  All rights reserved.
42591efccSDavid Schultz  *
52591efccSDavid Schultz  * This code is derived from software contributed to Berkeley by
62591efccSDavid Schultz  * Chris Torek.
72591efccSDavid Schultz  *
82591efccSDavid Schultz  * Redistribution and use in source and binary forms, with or without
92591efccSDavid Schultz  * modification, are permitted provided that the following conditions
102591efccSDavid Schultz  * are met:
112591efccSDavid Schultz  * 1. Redistributions of source code must retain the above copyright
122591efccSDavid Schultz  *    notice, this list of conditions and the following disclaimer.
132591efccSDavid Schultz  * 2. Redistributions in binary form must reproduce the above copyright
142591efccSDavid Schultz  *    notice, this list of conditions and the following disclaimer in the
152591efccSDavid Schultz  *    documentation and/or other materials provided with the distribution.
161d8053c5SEd Maste  * 3. Neither the name of the University nor the names of its contributors
172591efccSDavid Schultz  *    may be used to endorse or promote products derived from this software
182591efccSDavid Schultz  *    without specific prior written permission.
192591efccSDavid Schultz  *
202591efccSDavid Schultz  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
212591efccSDavid Schultz  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222591efccSDavid Schultz  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
232591efccSDavid Schultz  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
242591efccSDavid Schultz  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
252591efccSDavid Schultz  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
262591efccSDavid Schultz  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
272591efccSDavid Schultz  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
282591efccSDavid Schultz  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
292591efccSDavid Schultz  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
302591efccSDavid Schultz  * SUCH DAMAGE.
312591efccSDavid Schultz  */
322591efccSDavid Schultz 
332591efccSDavid Schultz #if defined(LIBC_SCCS) && !defined(lint)
342591efccSDavid Schultz static char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
352591efccSDavid Schultz #endif /* LIBC_SCCS and not lint */
362591efccSDavid Schultz #include <sys/cdefs.h>
372591efccSDavid Schultz __FBSDID("$FreeBSD$");
382591efccSDavid Schultz 
392591efccSDavid Schultz /*
402591efccSDavid Schultz  * This is the code responsible for handling positional arguments
412591efccSDavid Schultz  * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
422591efccSDavid Schultz  */
432591efccSDavid Schultz 
442591efccSDavid Schultz #include "namespace.h"
452591efccSDavid Schultz #include <sys/types.h>
462591efccSDavid Schultz 
47130a08a3SRuslan Bukin #include <limits.h>
48e62e5ff9SDavid Schultz #include <stdarg.h>
492591efccSDavid Schultz #include <stddef.h>
502591efccSDavid Schultz #include <stdint.h>
512591efccSDavid Schultz #include <stdio.h>
522591efccSDavid Schultz #include <stdlib.h>
532591efccSDavid Schultz #include <string.h>
542591efccSDavid Schultz #include <wchar.h>
552591efccSDavid Schultz 
562591efccSDavid Schultz #include "un-namespace.h"
572591efccSDavid Schultz #include "printflocal.h"
582591efccSDavid Schultz 
59130a08a3SRuslan Bukin #ifdef	NL_ARGMAX
60130a08a3SRuslan Bukin #define	MAX_POSARG	NL_ARGMAX
61130a08a3SRuslan Bukin #else
62130a08a3SRuslan Bukin #define	MAX_POSARG	65536
63130a08a3SRuslan Bukin #endif
64130a08a3SRuslan Bukin 
652591efccSDavid Schultz /*
662591efccSDavid Schultz  * Type ids for argument type table.
672591efccSDavid Schultz  */
682591efccSDavid Schultz enum typeid {
692591efccSDavid Schultz 	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
702591efccSDavid Schultz 	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
7188f919d6SDavid Schultz 	T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
722591efccSDavid Schultz 	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
732591efccSDavid Schultz 	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
742591efccSDavid Schultz };
752591efccSDavid Schultz 
762591efccSDavid Schultz /* An expandable array of types. */
772591efccSDavid Schultz struct typetable {
782591efccSDavid Schultz 	enum typeid *table; /* table of types */
792591efccSDavid Schultz 	enum typeid stattable[STATIC_ARG_TBL_SIZE];
80130a08a3SRuslan Bukin 	u_int tablesize;	/* current size of type table */
81130a08a3SRuslan Bukin 	u_int tablemax;		/* largest used index in table */
82130a08a3SRuslan Bukin 	u_int nextarg;		/* 1-based argument index */
832591efccSDavid Schultz };
842591efccSDavid Schultz 
85e62e5ff9SDavid Schultz static int	__grow_type_table(struct typetable *);
8607bed96bSDavid Schultz static void	build_arg_table (struct typetable *, va_list, union arg **);
872591efccSDavid Schultz 
882591efccSDavid Schultz /*
892591efccSDavid Schultz  * Initialize a struct typetable.
902591efccSDavid Schultz  */
912591efccSDavid Schultz static inline void
922591efccSDavid Schultz inittypes(struct typetable *types)
932591efccSDavid Schultz {
94130a08a3SRuslan Bukin 	u_int n;
952591efccSDavid Schultz 
962591efccSDavid Schultz 	types->table = types->stattable;
972591efccSDavid Schultz 	types->tablesize = STATIC_ARG_TBL_SIZE;
982591efccSDavid Schultz 	types->tablemax = 0;
992591efccSDavid Schultz 	types->nextarg = 1;
1002591efccSDavid Schultz 	for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
1012591efccSDavid Schultz 		types->table[n] = T_UNUSED;
1022591efccSDavid Schultz }
1032591efccSDavid Schultz 
1042591efccSDavid Schultz /*
1052591efccSDavid Schultz  * struct typetable destructor.
1062591efccSDavid Schultz  */
1072591efccSDavid Schultz static inline void
1082591efccSDavid Schultz freetypes(struct typetable *types)
1092591efccSDavid Schultz {
1102591efccSDavid Schultz 
1112591efccSDavid Schultz 	if (types->table != types->stattable)
1122591efccSDavid Schultz 		free (types->table);
1132591efccSDavid Schultz }
1142591efccSDavid Schultz 
1152591efccSDavid Schultz /*
116e62e5ff9SDavid Schultz  * Ensure that there is space to add a new argument type to the type table.
117e62e5ff9SDavid Schultz  * Expand the table if necessary. Returns 0 on success.
1182591efccSDavid Schultz  */
119e62e5ff9SDavid Schultz static inline int
120e62e5ff9SDavid Schultz _ensurespace(struct typetable *types)
121e62e5ff9SDavid Schultz {
122e62e5ff9SDavid Schultz 
123e62e5ff9SDavid Schultz 	if (types->nextarg >= types->tablesize) {
124e62e5ff9SDavid Schultz 		if (__grow_type_table(types))
125e62e5ff9SDavid Schultz 			return (-1);
126e62e5ff9SDavid Schultz 	}
127e62e5ff9SDavid Schultz 	if (types->nextarg > types->tablemax)
128e62e5ff9SDavid Schultz 		types->tablemax = types->nextarg;
129e62e5ff9SDavid Schultz 	return (0);
130e62e5ff9SDavid Schultz }
131e62e5ff9SDavid Schultz 
132e62e5ff9SDavid Schultz /*
133e62e5ff9SDavid Schultz  * Add an argument type to the table, expanding if necessary.
134e62e5ff9SDavid Schultz  * Returns 0 on success.
135e62e5ff9SDavid Schultz  */
136e62e5ff9SDavid Schultz static inline int
1372591efccSDavid Schultz addtype(struct typetable *types, enum typeid type)
1382591efccSDavid Schultz {
1392591efccSDavid Schultz 
140c4014b50SDavid Schultz 	if (_ensurespace(types))
141c4014b50SDavid Schultz 		return (-1);
1422591efccSDavid Schultz 	types->table[types->nextarg++] = type;
143e62e5ff9SDavid Schultz 	return (0);
1442591efccSDavid Schultz }
1452591efccSDavid Schultz 
146e62e5ff9SDavid Schultz static inline int
1472591efccSDavid Schultz addsarg(struct typetable *types, int flags)
1482591efccSDavid Schultz {
1492591efccSDavid Schultz 
150e62e5ff9SDavid Schultz 	if (_ensurespace(types))
151e62e5ff9SDavid Schultz 		return (-1);
1522591efccSDavid Schultz 	if (flags & INTMAXT)
153e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_INTMAXT;
1542591efccSDavid Schultz 	else if (flags & SIZET)
1550881683bSDavid Schultz 		types->table[types->nextarg++] = T_SSIZET;
1562591efccSDavid Schultz 	else if (flags & PTRDIFFT)
157e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_PTRDIFFT;
1582591efccSDavid Schultz 	else if (flags & LLONGINT)
159e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_LLONG;
1602591efccSDavid Schultz 	else if (flags & LONGINT)
161e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_LONG;
1622591efccSDavid Schultz 	else
163e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_INT;
164e62e5ff9SDavid Schultz 	return (0);
1652591efccSDavid Schultz }
1662591efccSDavid Schultz 
167e62e5ff9SDavid Schultz static inline int
1682591efccSDavid Schultz adduarg(struct typetable *types, int flags)
1692591efccSDavid Schultz {
1702591efccSDavid Schultz 
171e62e5ff9SDavid Schultz 	if (_ensurespace(types))
172e62e5ff9SDavid Schultz 		return (-1);
1732591efccSDavid Schultz 	if (flags & INTMAXT)
174e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_UINTMAXT;
1752591efccSDavid Schultz 	else if (flags & SIZET)
176e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_SIZET;
1772591efccSDavid Schultz 	else if (flags & PTRDIFFT)
1780881683bSDavid Schultz 		types->table[types->nextarg++] = T_SIZET;
1792591efccSDavid Schultz 	else if (flags & LLONGINT)
180e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_U_LLONG;
1812591efccSDavid Schultz 	else if (flags & LONGINT)
182e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_U_LONG;
1832591efccSDavid Schultz 	else
184e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_U_INT;
185e62e5ff9SDavid Schultz 	return (0);
1862591efccSDavid Schultz }
1872591efccSDavid Schultz 
1882591efccSDavid Schultz /*
1892591efccSDavid Schultz  * Add * arguments to the type array.
1902591efccSDavid Schultz  */
191e62e5ff9SDavid Schultz static inline int
1922591efccSDavid Schultz addaster(struct typetable *types, char **fmtp)
1932591efccSDavid Schultz {
1942591efccSDavid Schultz 	char *cp;
195130a08a3SRuslan Bukin 	u_int n2;
1962591efccSDavid Schultz 
1972591efccSDavid Schultz 	n2 = 0;
1982591efccSDavid Schultz 	cp = *fmtp;
1992591efccSDavid Schultz 	while (is_digit(*cp)) {
2002591efccSDavid Schultz 		n2 = 10 * n2 + to_digit(*cp);
2012591efccSDavid Schultz 		cp++;
2022591efccSDavid Schultz 	}
2032591efccSDavid Schultz 	if (*cp == '$') {
204130a08a3SRuslan Bukin 		u_int hold = types->nextarg;
2052591efccSDavid Schultz 		types->nextarg = n2;
206c4014b50SDavid Schultz 		if (addtype(types, T_INT))
207c4014b50SDavid Schultz 			return (-1);
2082591efccSDavid Schultz 		types->nextarg = hold;
2092591efccSDavid Schultz 		*fmtp = ++cp;
2102591efccSDavid Schultz 	} else {
211c4014b50SDavid Schultz 		if (addtype(types, T_INT))
212c4014b50SDavid Schultz 			return (-1);
2132591efccSDavid Schultz 	}
214e62e5ff9SDavid Schultz 	return (0);
2152591efccSDavid Schultz }
2162591efccSDavid Schultz 
217e62e5ff9SDavid Schultz static inline int
2182591efccSDavid Schultz addwaster(struct typetable *types, wchar_t **fmtp)
2192591efccSDavid Schultz {
2202591efccSDavid Schultz 	wchar_t *cp;
221130a08a3SRuslan Bukin 	u_int n2;
2222591efccSDavid Schultz 
2232591efccSDavid Schultz 	n2 = 0;
2242591efccSDavid Schultz 	cp = *fmtp;
2252591efccSDavid Schultz 	while (is_digit(*cp)) {
2262591efccSDavid Schultz 		n2 = 10 * n2 + to_digit(*cp);
2272591efccSDavid Schultz 		cp++;
2282591efccSDavid Schultz 	}
2292591efccSDavid Schultz 	if (*cp == '$') {
230130a08a3SRuslan Bukin 		u_int hold = types->nextarg;
2312591efccSDavid Schultz 		types->nextarg = n2;
232c4014b50SDavid Schultz 		if (addtype(types, T_INT))
233c4014b50SDavid Schultz 			return (-1);
2342591efccSDavid Schultz 		types->nextarg = hold;
2352591efccSDavid Schultz 		*fmtp = ++cp;
2362591efccSDavid Schultz 	} else {
237c4014b50SDavid Schultz 		if (addtype(types, T_INT))
238c4014b50SDavid Schultz 			return (-1);
2392591efccSDavid Schultz 	}
240e62e5ff9SDavid Schultz 	return (0);
2412591efccSDavid Schultz }
2422591efccSDavid Schultz 
2432591efccSDavid Schultz /*
2442591efccSDavid Schultz  * Find all arguments when a positional parameter is encountered.  Returns a
2452591efccSDavid Schultz  * table, indexed by argument number, of pointers to each arguments.  The
2462591efccSDavid Schultz  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
2472591efccSDavid Schultz  * It will be replaces with a malloc-ed one if it overflows.
248e62e5ff9SDavid Schultz  * Returns 0 on success. On failure, returns nonzero and sets errno.
2492591efccSDavid Schultz  */
250e62e5ff9SDavid Schultz int
2512591efccSDavid Schultz __find_arguments (const char *fmt0, va_list ap, union arg **argtable)
2522591efccSDavid Schultz {
2532591efccSDavid Schultz 	char *fmt;		/* format string */
2542591efccSDavid Schultz 	int ch;			/* character from fmt */
255130a08a3SRuslan Bukin 	u_int n;		/* handy integer (short term usage) */
256e62e5ff9SDavid Schultz 	int error;
2572591efccSDavid Schultz 	int flags;		/* flags as above */
2582591efccSDavid Schultz 	struct typetable types;	/* table of types */
2592591efccSDavid Schultz 
2602591efccSDavid Schultz 	fmt = (char *)fmt0;
2612591efccSDavid Schultz 	inittypes(&types);
262e62e5ff9SDavid Schultz 	error = 0;
2632591efccSDavid Schultz 
2642591efccSDavid Schultz 	/*
2652591efccSDavid Schultz 	 * Scan the format for conversions (`%' character).
2662591efccSDavid Schultz 	 */
2672591efccSDavid Schultz 	for (;;) {
2682591efccSDavid Schultz 		while ((ch = *fmt) != '\0' && ch != '%')
2692591efccSDavid Schultz 			fmt++;
2702591efccSDavid Schultz 		if (ch == '\0')
2712591efccSDavid Schultz 			goto done;
2722591efccSDavid Schultz 		fmt++;		/* skip over '%' */
2732591efccSDavid Schultz 
2742591efccSDavid Schultz 		flags = 0;
2752591efccSDavid Schultz 
2762591efccSDavid Schultz rflag:		ch = *fmt++;
2772591efccSDavid Schultz reswitch:	switch (ch) {
2782591efccSDavid Schultz 		case ' ':
2792591efccSDavid Schultz 		case '#':
2802591efccSDavid Schultz 			goto rflag;
2812591efccSDavid Schultz 		case '*':
282e62e5ff9SDavid Schultz 			if ((error = addaster(&types, &fmt)))
283e62e5ff9SDavid Schultz 				goto error;
2842591efccSDavid Schultz 			goto rflag;
2852591efccSDavid Schultz 		case '-':
2862591efccSDavid Schultz 		case '+':
2872591efccSDavid Schultz 		case '\'':
2882591efccSDavid Schultz 			goto rflag;
2892591efccSDavid Schultz 		case '.':
2902591efccSDavid Schultz 			if ((ch = *fmt++) == '*') {
291e62e5ff9SDavid Schultz 				if ((error = addaster(&types, &fmt)))
292e62e5ff9SDavid Schultz 					goto error;
2932591efccSDavid Schultz 				goto rflag;
2942591efccSDavid Schultz 			}
2952591efccSDavid Schultz 			while (is_digit(ch)) {
2962591efccSDavid Schultz 				ch = *fmt++;
2972591efccSDavid Schultz 			}
2982591efccSDavid Schultz 			goto reswitch;
2992591efccSDavid Schultz 		case '0':
3002591efccSDavid Schultz 			goto rflag;
3012591efccSDavid Schultz 		case '1': case '2': case '3': case '4':
3022591efccSDavid Schultz 		case '5': case '6': case '7': case '8': case '9':
3032591efccSDavid Schultz 			n = 0;
3042591efccSDavid Schultz 			do {
3052591efccSDavid Schultz 				n = 10 * n + to_digit(ch);
306130a08a3SRuslan Bukin 				/* Detect overflow */
307130a08a3SRuslan Bukin 				if (n > MAX_POSARG) {
308130a08a3SRuslan Bukin 					error = -1;
309130a08a3SRuslan Bukin 					goto error;
310130a08a3SRuslan Bukin 				}
3112591efccSDavid Schultz 				ch = *fmt++;
3122591efccSDavid Schultz 			} while (is_digit(ch));
3132591efccSDavid Schultz 			if (ch == '$') {
3142591efccSDavid Schultz 				types.nextarg = n;
3152591efccSDavid Schultz 				goto rflag;
3162591efccSDavid Schultz 			}
3172591efccSDavid Schultz 			goto reswitch;
3182591efccSDavid Schultz #ifndef NO_FLOATING_POINT
3192591efccSDavid Schultz 		case 'L':
3202591efccSDavid Schultz 			flags |= LONGDBL;
3212591efccSDavid Schultz 			goto rflag;
3222591efccSDavid Schultz #endif
3232591efccSDavid Schultz 		case 'h':
3242591efccSDavid Schultz 			if (flags & SHORTINT) {
3252591efccSDavid Schultz 				flags &= ~SHORTINT;
3262591efccSDavid Schultz 				flags |= CHARINT;
3272591efccSDavid Schultz 			} else
3282591efccSDavid Schultz 				flags |= SHORTINT;
3292591efccSDavid Schultz 			goto rflag;
3302591efccSDavid Schultz 		case 'j':
3312591efccSDavid Schultz 			flags |= INTMAXT;
3322591efccSDavid Schultz 			goto rflag;
3332591efccSDavid Schultz 		case 'l':
3342591efccSDavid Schultz 			if (flags & LONGINT) {
3352591efccSDavid Schultz 				flags &= ~LONGINT;
3362591efccSDavid Schultz 				flags |= LLONGINT;
3372591efccSDavid Schultz 			} else
3382591efccSDavid Schultz 				flags |= LONGINT;
3392591efccSDavid Schultz 			goto rflag;
3402591efccSDavid Schultz 		case 'q':
3412591efccSDavid Schultz 			flags |= LLONGINT;	/* not necessarily */
3422591efccSDavid Schultz 			goto rflag;
3432591efccSDavid Schultz 		case 't':
3442591efccSDavid Schultz 			flags |= PTRDIFFT;
3452591efccSDavid Schultz 			goto rflag;
3462591efccSDavid Schultz 		case 'z':
3472591efccSDavid Schultz 			flags |= SIZET;
3482591efccSDavid Schultz 			goto rflag;
3492591efccSDavid Schultz 		case 'C':
3502591efccSDavid Schultz 			flags |= LONGINT;
3512591efccSDavid Schultz 			/*FALLTHROUGH*/
3522591efccSDavid Schultz 		case 'c':
353e62e5ff9SDavid Schultz 			error = addtype(&types,
354e62e5ff9SDavid Schultz 					(flags & LONGINT) ? T_WINT : T_INT);
355e62e5ff9SDavid Schultz 			if (error)
356e62e5ff9SDavid Schultz 				goto error;
3572591efccSDavid Schultz 			break;
3582591efccSDavid Schultz 		case 'D':
3592591efccSDavid Schultz 			flags |= LONGINT;
3602591efccSDavid Schultz 			/*FALLTHROUGH*/
3612591efccSDavid Schultz 		case 'd':
3622591efccSDavid Schultz 		case 'i':
363e62e5ff9SDavid Schultz 			if ((error = addsarg(&types, flags)))
364e62e5ff9SDavid Schultz 				goto error;
3652591efccSDavid Schultz 			break;
3662591efccSDavid Schultz #ifndef NO_FLOATING_POINT
3672591efccSDavid Schultz 		case 'a':
3682591efccSDavid Schultz 		case 'A':
3692591efccSDavid Schultz 		case 'e':
3702591efccSDavid Schultz 		case 'E':
3712591efccSDavid Schultz 		case 'f':
3722591efccSDavid Schultz 		case 'g':
3732591efccSDavid Schultz 		case 'G':
374e62e5ff9SDavid Schultz 			error = addtype(&types,
375e62e5ff9SDavid Schultz 			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
376e62e5ff9SDavid Schultz 			if (error)
377e62e5ff9SDavid Schultz 				goto error;
3782591efccSDavid Schultz 			break;
3792591efccSDavid Schultz #endif /* !NO_FLOATING_POINT */
3802591efccSDavid Schultz 		case 'n':
3812591efccSDavid Schultz 			if (flags & INTMAXT)
382e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INTMAXT);
3832591efccSDavid Schultz 			else if (flags & PTRDIFFT)
384e62e5ff9SDavid Schultz 				error = addtype(&types, TP_PTRDIFFT);
3852591efccSDavid Schultz 			else if (flags & SIZET)
38688f919d6SDavid Schultz 				error = addtype(&types, TP_SSIZET);
3872591efccSDavid Schultz 			else if (flags & LLONGINT)
388e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LLONG);
3892591efccSDavid Schultz 			else if (flags & LONGINT)
390e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LONG);
3912591efccSDavid Schultz 			else if (flags & SHORTINT)
392e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SHORT);
3932591efccSDavid Schultz 			else if (flags & CHARINT)
394e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SCHAR);
3952591efccSDavid Schultz 			else
396e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INT);
397e62e5ff9SDavid Schultz 			if (error)
398e62e5ff9SDavid Schultz 				goto error;
3992591efccSDavid Schultz 			continue;	/* no output */
4002591efccSDavid Schultz 		case 'O':
4012591efccSDavid Schultz 			flags |= LONGINT;
4022591efccSDavid Schultz 			/*FALLTHROUGH*/
4032591efccSDavid Schultz 		case 'o':
404e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
405e62e5ff9SDavid Schultz 				goto error;
4062591efccSDavid Schultz 			break;
4072591efccSDavid Schultz 		case 'p':
408e62e5ff9SDavid Schultz 			if ((error = addtype(&types, TP_VOID)))
409e62e5ff9SDavid Schultz 				goto error;
4102591efccSDavid Schultz 			break;
4112591efccSDavid Schultz 		case 'S':
4122591efccSDavid Schultz 			flags |= LONGINT;
4132591efccSDavid Schultz 			/*FALLTHROUGH*/
4142591efccSDavid Schultz 		case 's':
415e62e5ff9SDavid Schultz 			error = addtype(&types,
416e62e5ff9SDavid Schultz 					(flags & LONGINT) ? TP_WCHAR : TP_CHAR);
417e62e5ff9SDavid Schultz 			if (error)
418e62e5ff9SDavid Schultz 				goto error;
4192591efccSDavid Schultz 			break;
4202591efccSDavid Schultz 		case 'U':
4212591efccSDavid Schultz 			flags |= LONGINT;
4222591efccSDavid Schultz 			/*FALLTHROUGH*/
4232591efccSDavid Schultz 		case 'u':
4242591efccSDavid Schultz 		case 'X':
4252591efccSDavid Schultz 		case 'x':
426e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
427e62e5ff9SDavid Schultz 				goto error;
4282591efccSDavid Schultz 			break;
4292591efccSDavid Schultz 		default:	/* "%?" prints ?, unless ? is NUL */
4302591efccSDavid Schultz 			if (ch == '\0')
4312591efccSDavid Schultz 				goto done;
4322591efccSDavid Schultz 			break;
4332591efccSDavid Schultz 		}
4342591efccSDavid Schultz 	}
4352591efccSDavid Schultz done:
43607bed96bSDavid Schultz 	build_arg_table(&types, ap, argtable);
437e62e5ff9SDavid Schultz error:
4382591efccSDavid Schultz 	freetypes(&types);
439e62e5ff9SDavid Schultz 	return (error || *argtable == NULL);
4402591efccSDavid Schultz }
4412591efccSDavid Schultz 
4422591efccSDavid Schultz /* wchar version of __find_arguments. */
443e62e5ff9SDavid Schultz int
4442591efccSDavid Schultz __find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
4452591efccSDavid Schultz {
4462591efccSDavid Schultz 	wchar_t *fmt;		/* format string */
4472591efccSDavid Schultz 	wchar_t ch;		/* character from fmt */
448130a08a3SRuslan Bukin 	u_int n;		/* handy integer (short term usage) */
449e62e5ff9SDavid Schultz 	int error;
4502591efccSDavid Schultz 	int flags;		/* flags as above */
4512591efccSDavid Schultz 	struct typetable types;	/* table of types */
4522591efccSDavid Schultz 
4532591efccSDavid Schultz 	fmt = (wchar_t *)fmt0;
4542591efccSDavid Schultz 	inittypes(&types);
455e62e5ff9SDavid Schultz 	error = 0;
4562591efccSDavid Schultz 
4572591efccSDavid Schultz 	/*
4582591efccSDavid Schultz 	 * Scan the format for conversions (`%' character).
4592591efccSDavid Schultz 	 */
4602591efccSDavid Schultz 	for (;;) {
4612591efccSDavid Schultz 		while ((ch = *fmt) != '\0' && ch != '%')
4622591efccSDavid Schultz 			fmt++;
4632591efccSDavid Schultz 		if (ch == '\0')
4642591efccSDavid Schultz 			goto done;
4652591efccSDavid Schultz 		fmt++;		/* skip over '%' */
4662591efccSDavid Schultz 
4672591efccSDavid Schultz 		flags = 0;
4682591efccSDavid Schultz 
4692591efccSDavid Schultz rflag:		ch = *fmt++;
4702591efccSDavid Schultz reswitch:	switch (ch) {
4712591efccSDavid Schultz 		case ' ':
4722591efccSDavid Schultz 		case '#':
4732591efccSDavid Schultz 			goto rflag;
4742591efccSDavid Schultz 		case '*':
475e62e5ff9SDavid Schultz 			if ((error = addwaster(&types, &fmt)))
476e62e5ff9SDavid Schultz 				goto error;
4772591efccSDavid Schultz 			goto rflag;
4782591efccSDavid Schultz 		case '-':
4792591efccSDavid Schultz 		case '+':
4802591efccSDavid Schultz 		case '\'':
4812591efccSDavid Schultz 			goto rflag;
4822591efccSDavid Schultz 		case '.':
4832591efccSDavid Schultz 			if ((ch = *fmt++) == '*') {
484e62e5ff9SDavid Schultz 				if ((error = addwaster(&types, &fmt)))
485e62e5ff9SDavid Schultz 					goto error;
4862591efccSDavid Schultz 				goto rflag;
4872591efccSDavid Schultz 			}
4882591efccSDavid Schultz 			while (is_digit(ch)) {
4892591efccSDavid Schultz 				ch = *fmt++;
4902591efccSDavid Schultz 			}
4912591efccSDavid Schultz 			goto reswitch;
4922591efccSDavid Schultz 		case '0':
4932591efccSDavid Schultz 			goto rflag;
4942591efccSDavid Schultz 		case '1': case '2': case '3': case '4':
4952591efccSDavid Schultz 		case '5': case '6': case '7': case '8': case '9':
4962591efccSDavid Schultz 			n = 0;
4972591efccSDavid Schultz 			do {
4982591efccSDavid Schultz 				n = 10 * n + to_digit(ch);
499130a08a3SRuslan Bukin 				/* Detect overflow */
500130a08a3SRuslan Bukin 				if (n > MAX_POSARG) {
501130a08a3SRuslan Bukin 					error = -1;
502130a08a3SRuslan Bukin 					goto error;
503130a08a3SRuslan Bukin 				}
5042591efccSDavid Schultz 				ch = *fmt++;
5052591efccSDavid Schultz 			} while (is_digit(ch));
5062591efccSDavid Schultz 			if (ch == '$') {
5072591efccSDavid Schultz 				types.nextarg = n;
5082591efccSDavid Schultz 				goto rflag;
5092591efccSDavid Schultz 			}
5102591efccSDavid Schultz 			goto reswitch;
5112591efccSDavid Schultz #ifndef NO_FLOATING_POINT
5122591efccSDavid Schultz 		case 'L':
5132591efccSDavid Schultz 			flags |= LONGDBL;
5142591efccSDavid Schultz 			goto rflag;
5152591efccSDavid Schultz #endif
5162591efccSDavid Schultz 		case 'h':
5172591efccSDavid Schultz 			if (flags & SHORTINT) {
5182591efccSDavid Schultz 				flags &= ~SHORTINT;
5192591efccSDavid Schultz 				flags |= CHARINT;
5202591efccSDavid Schultz 			} else
5212591efccSDavid Schultz 				flags |= SHORTINT;
5222591efccSDavid Schultz 			goto rflag;
5232591efccSDavid Schultz 		case 'j':
5242591efccSDavid Schultz 			flags |= INTMAXT;
5252591efccSDavid Schultz 			goto rflag;
5262591efccSDavid Schultz 		case 'l':
5272591efccSDavid Schultz 			if (flags & LONGINT) {
5282591efccSDavid Schultz 				flags &= ~LONGINT;
5292591efccSDavid Schultz 				flags |= LLONGINT;
5302591efccSDavid Schultz 			} else
5312591efccSDavid Schultz 				flags |= LONGINT;
5322591efccSDavid Schultz 			goto rflag;
5332591efccSDavid Schultz 		case 'q':
5342591efccSDavid Schultz 			flags |= LLONGINT;	/* not necessarily */
5352591efccSDavid Schultz 			goto rflag;
5362591efccSDavid Schultz 		case 't':
5372591efccSDavid Schultz 			flags |= PTRDIFFT;
5382591efccSDavid Schultz 			goto rflag;
5392591efccSDavid Schultz 		case 'z':
5402591efccSDavid Schultz 			flags |= SIZET;
5412591efccSDavid Schultz 			goto rflag;
5422591efccSDavid Schultz 		case 'C':
5432591efccSDavid Schultz 			flags |= LONGINT;
5442591efccSDavid Schultz 			/*FALLTHROUGH*/
5452591efccSDavid Schultz 		case 'c':
546e62e5ff9SDavid Schultz 			error = addtype(&types,
547e62e5ff9SDavid Schultz 					(flags & LONGINT) ? T_WINT : T_INT);
548e62e5ff9SDavid Schultz 			if (error)
549e62e5ff9SDavid Schultz 				goto error;
5502591efccSDavid Schultz 			break;
5512591efccSDavid Schultz 		case 'D':
5522591efccSDavid Schultz 			flags |= LONGINT;
5532591efccSDavid Schultz 			/*FALLTHROUGH*/
5542591efccSDavid Schultz 		case 'd':
5552591efccSDavid Schultz 		case 'i':
556e62e5ff9SDavid Schultz 			if ((error = addsarg(&types, flags)))
557e62e5ff9SDavid Schultz 				goto error;
5582591efccSDavid Schultz 			break;
5592591efccSDavid Schultz #ifndef NO_FLOATING_POINT
5602591efccSDavid Schultz 		case 'a':
5612591efccSDavid Schultz 		case 'A':
5622591efccSDavid Schultz 		case 'e':
5632591efccSDavid Schultz 		case 'E':
5642591efccSDavid Schultz 		case 'f':
5652591efccSDavid Schultz 		case 'g':
5662591efccSDavid Schultz 		case 'G':
567e62e5ff9SDavid Schultz 			error = addtype(&types,
568e62e5ff9SDavid Schultz 			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
569e62e5ff9SDavid Schultz 			if (error)
570e62e5ff9SDavid Schultz 				goto error;
5712591efccSDavid Schultz 			break;
5722591efccSDavid Schultz #endif /* !NO_FLOATING_POINT */
5732591efccSDavid Schultz 		case 'n':
5742591efccSDavid Schultz 			if (flags & INTMAXT)
575e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INTMAXT);
5762591efccSDavid Schultz 			else if (flags & PTRDIFFT)
577e62e5ff9SDavid Schultz 				error = addtype(&types, TP_PTRDIFFT);
5782591efccSDavid Schultz 			else if (flags & SIZET)
57988f919d6SDavid Schultz 				error = addtype(&types, TP_SSIZET);
5802591efccSDavid Schultz 			else if (flags & LLONGINT)
581e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LLONG);
5822591efccSDavid Schultz 			else if (flags & LONGINT)
583e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LONG);
5842591efccSDavid Schultz 			else if (flags & SHORTINT)
585e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SHORT);
5862591efccSDavid Schultz 			else if (flags & CHARINT)
587e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SCHAR);
5882591efccSDavid Schultz 			else
589e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INT);
590c4014b50SDavid Schultz 			if (error)
591c4014b50SDavid Schultz 				goto error;
5922591efccSDavid Schultz 			continue;	/* no output */
5932591efccSDavid Schultz 		case 'O':
5942591efccSDavid Schultz 			flags |= LONGINT;
5952591efccSDavid Schultz 			/*FALLTHROUGH*/
5962591efccSDavid Schultz 		case 'o':
597e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
598e62e5ff9SDavid Schultz 				goto error;
5992591efccSDavid Schultz 			break;
6002591efccSDavid Schultz 		case 'p':
601e62e5ff9SDavid Schultz 			if ((error = addtype(&types, TP_VOID)))
602e62e5ff9SDavid Schultz 				goto error;
6032591efccSDavid Schultz 			break;
6042591efccSDavid Schultz 		case 'S':
6052591efccSDavid Schultz 			flags |= LONGINT;
6062591efccSDavid Schultz 			/*FALLTHROUGH*/
6072591efccSDavid Schultz 		case 's':
608e62e5ff9SDavid Schultz 			error = addtype(&types,
609e62e5ff9SDavid Schultz 			    (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
610e62e5ff9SDavid Schultz 			if (error)
611e62e5ff9SDavid Schultz 				goto error;
6122591efccSDavid Schultz 			break;
6132591efccSDavid Schultz 		case 'U':
6142591efccSDavid Schultz 			flags |= LONGINT;
6152591efccSDavid Schultz 			/*FALLTHROUGH*/
6162591efccSDavid Schultz 		case 'u':
6172591efccSDavid Schultz 		case 'X':
6182591efccSDavid Schultz 		case 'x':
619e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
620e62e5ff9SDavid Schultz 				goto error;
6212591efccSDavid Schultz 			break;
6222591efccSDavid Schultz 		default:	/* "%?" prints ?, unless ? is NUL */
6232591efccSDavid Schultz 			if (ch == '\0')
6242591efccSDavid Schultz 				goto done;
6252591efccSDavid Schultz 			break;
6262591efccSDavid Schultz 		}
6272591efccSDavid Schultz 	}
6282591efccSDavid Schultz done:
62907bed96bSDavid Schultz 	build_arg_table(&types, ap, argtable);
630e62e5ff9SDavid Schultz error:
63107bed96bSDavid Schultz 	freetypes(&types);
632e62e5ff9SDavid Schultz 	return (error || *argtable == NULL);
63307bed96bSDavid Schultz }
63407bed96bSDavid Schultz 
6352591efccSDavid Schultz /*
636e62e5ff9SDavid Schultz  * Increase the size of the type table. Returns 0 on success.
6372591efccSDavid Schultz  */
638e62e5ff9SDavid Schultz static int
63907bed96bSDavid Schultz __grow_type_table(struct typetable *types)
64007bed96bSDavid Schultz {
64107bed96bSDavid Schultz 	enum typeid *const oldtable = types->table;
64207bed96bSDavid Schultz 	const int oldsize = types->tablesize;
64307bed96bSDavid Schultz 	enum typeid *newtable;
644*97721eb5SPedro F. Giffuni 	u_int n, newsize;
645130a08a3SRuslan Bukin 
646130a08a3SRuslan Bukin 	/* Detect overflow */
647130a08a3SRuslan Bukin 	if (types->nextarg > NL_ARGMAX)
648130a08a3SRuslan Bukin 		return (-1);
64907bed96bSDavid Schultz 
650*97721eb5SPedro F. Giffuni 	newsize = oldsize * 2;
65107bed96bSDavid Schultz 	if (newsize < types->nextarg + 1)
65207bed96bSDavid Schultz 		newsize = types->nextarg + 1;
65307bed96bSDavid Schultz 	if (oldsize == STATIC_ARG_TBL_SIZE) {
65407bed96bSDavid Schultz 		if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
655e62e5ff9SDavid Schultz 			return (-1);
65607bed96bSDavid Schultz 		bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
65707bed96bSDavid Schultz 	} else {
658e62e5ff9SDavid Schultz 		newtable = realloc(oldtable, newsize * sizeof(enum typeid));
65907bed96bSDavid Schultz 		if (newtable == NULL)
660e62e5ff9SDavid Schultz 			return (-1);
66107bed96bSDavid Schultz 	}
66207bed96bSDavid Schultz 	for (n = oldsize; n < newsize; n++)
66307bed96bSDavid Schultz 		newtable[n] = T_UNUSED;
66407bed96bSDavid Schultz 
66507bed96bSDavid Schultz 	types->table = newtable;
66607bed96bSDavid Schultz 	types->tablesize = newsize;
667e62e5ff9SDavid Schultz 
668e62e5ff9SDavid Schultz 	return (0);
66907bed96bSDavid Schultz }
67007bed96bSDavid Schultz 
67107bed96bSDavid Schultz /*
67207bed96bSDavid Schultz  * Build the argument table from the completed type table.
673e62e5ff9SDavid Schultz  * On malloc failure, *argtable is set to NULL.
67407bed96bSDavid Schultz  */
67507bed96bSDavid Schultz static void
67607bed96bSDavid Schultz build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
67707bed96bSDavid Schultz {
678130a08a3SRuslan Bukin 	u_int n;
67907bed96bSDavid Schultz 
68007bed96bSDavid Schultz 	if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
6812591efccSDavid Schultz 		*argtable = (union arg *)
68207bed96bSDavid Schultz 		    malloc (sizeof (union arg) * (types->tablemax + 1));
683e62e5ff9SDavid Schultz 		if (*argtable == NULL)
684e62e5ff9SDavid Schultz 			return;
6852591efccSDavid Schultz 	}
6862591efccSDavid Schultz 
6872591efccSDavid Schultz 	(*argtable) [0].intarg = 0;
68807bed96bSDavid Schultz 	for (n = 1; n <= types->tablemax; n++) {
68907bed96bSDavid Schultz 		switch (types->table[n]) {
6902591efccSDavid Schultz 		    case T_UNUSED: /* whoops! */
6912591efccSDavid Schultz 			(*argtable) [n].intarg = va_arg (ap, int);
6922591efccSDavid Schultz 			break;
6932591efccSDavid Schultz 		    case TP_SCHAR:
6942591efccSDavid Schultz 			(*argtable) [n].pschararg = va_arg (ap, signed char *);
6952591efccSDavid Schultz 			break;
6962591efccSDavid Schultz 		    case TP_SHORT:
6972591efccSDavid Schultz 			(*argtable) [n].pshortarg = va_arg (ap, short *);
6982591efccSDavid Schultz 			break;
6992591efccSDavid Schultz 		    case T_INT:
7002591efccSDavid Schultz 			(*argtable) [n].intarg = va_arg (ap, int);
7012591efccSDavid Schultz 			break;
7022591efccSDavid Schultz 		    case T_U_INT:
7032591efccSDavid Schultz 			(*argtable) [n].uintarg = va_arg (ap, unsigned int);
7042591efccSDavid Schultz 			break;
7052591efccSDavid Schultz 		    case TP_INT:
7062591efccSDavid Schultz 			(*argtable) [n].pintarg = va_arg (ap, int *);
7072591efccSDavid Schultz 			break;
7082591efccSDavid Schultz 		    case T_LONG:
7092591efccSDavid Schultz 			(*argtable) [n].longarg = va_arg (ap, long);
7102591efccSDavid Schultz 			break;
7112591efccSDavid Schultz 		    case T_U_LONG:
7122591efccSDavid Schultz 			(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
7132591efccSDavid Schultz 			break;
7142591efccSDavid Schultz 		    case TP_LONG:
7152591efccSDavid Schultz 			(*argtable) [n].plongarg = va_arg (ap, long *);
7162591efccSDavid Schultz 			break;
7172591efccSDavid Schultz 		    case T_LLONG:
7182591efccSDavid Schultz 			(*argtable) [n].longlongarg = va_arg (ap, long long);
7192591efccSDavid Schultz 			break;
7202591efccSDavid Schultz 		    case T_U_LLONG:
7212591efccSDavid Schultz 			(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
7222591efccSDavid Schultz 			break;
7232591efccSDavid Schultz 		    case TP_LLONG:
7242591efccSDavid Schultz 			(*argtable) [n].plonglongarg = va_arg (ap, long long *);
7252591efccSDavid Schultz 			break;
7262591efccSDavid Schultz 		    case T_PTRDIFFT:
7272591efccSDavid Schultz 			(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
7282591efccSDavid Schultz 			break;
7292591efccSDavid Schultz 		    case TP_PTRDIFFT:
7302591efccSDavid Schultz 			(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
7312591efccSDavid Schultz 			break;
7322591efccSDavid Schultz 		    case T_SIZET:
7332591efccSDavid Schultz 			(*argtable) [n].sizearg = va_arg (ap, size_t);
7342591efccSDavid Schultz 			break;
7350881683bSDavid Schultz 		    case T_SSIZET:
7360881683bSDavid Schultz 			(*argtable) [n].sizearg = va_arg (ap, ssize_t);
7370881683bSDavid Schultz 			break;
73888f919d6SDavid Schultz 		    case TP_SSIZET:
73988f919d6SDavid Schultz 			(*argtable) [n].pssizearg = va_arg (ap, ssize_t *);
7402591efccSDavid Schultz 			break;
7412591efccSDavid Schultz 		    case T_INTMAXT:
7422591efccSDavid Schultz 			(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
7432591efccSDavid Schultz 			break;
7442591efccSDavid Schultz 		    case T_UINTMAXT:
7452591efccSDavid Schultz 			(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
7462591efccSDavid Schultz 			break;
7472591efccSDavid Schultz 		    case TP_INTMAXT:
7482591efccSDavid Schultz 			(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
7492591efccSDavid Schultz 			break;
7502591efccSDavid Schultz 		    case T_DOUBLE:
7512591efccSDavid Schultz #ifndef NO_FLOATING_POINT
7522591efccSDavid Schultz 			(*argtable) [n].doublearg = va_arg (ap, double);
7532591efccSDavid Schultz #endif
7542591efccSDavid Schultz 			break;
7552591efccSDavid Schultz 		    case T_LONG_DOUBLE:
7562591efccSDavid Schultz #ifndef NO_FLOATING_POINT
7572591efccSDavid Schultz 			(*argtable) [n].longdoublearg = va_arg (ap, long double);
7582591efccSDavid Schultz #endif
7592591efccSDavid Schultz 			break;
7602591efccSDavid Schultz 		    case TP_CHAR:
7612591efccSDavid Schultz 			(*argtable) [n].pchararg = va_arg (ap, char *);
7622591efccSDavid Schultz 			break;
7632591efccSDavid Schultz 		    case TP_VOID:
7642591efccSDavid Schultz 			(*argtable) [n].pvoidarg = va_arg (ap, void *);
7652591efccSDavid Schultz 			break;
7662591efccSDavid Schultz 		    case T_WINT:
7672591efccSDavid Schultz 			(*argtable) [n].wintarg = va_arg (ap, wint_t);
7682591efccSDavid Schultz 			break;
7692591efccSDavid Schultz 		    case TP_WCHAR:
7702591efccSDavid Schultz 			(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
7712591efccSDavid Schultz 			break;
7722591efccSDavid Schultz 		}
7732591efccSDavid Schultz 	}
7742591efccSDavid Schultz }
775