xref: /freebsd/lib/libc/stdio/printf-pos.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
12591efccSDavid Schultz /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni  *
42591efccSDavid Schultz  * Copyright (c) 1990, 1993
52591efccSDavid Schultz  *	The Regents of the University of California.  All rights reserved.
62591efccSDavid Schultz  *
72591efccSDavid Schultz  * This code is derived from software contributed to Berkeley by
82591efccSDavid Schultz  * Chris Torek.
92591efccSDavid Schultz  *
102591efccSDavid Schultz  * Redistribution and use in source and binary forms, with or without
112591efccSDavid Schultz  * modification, are permitted provided that the following conditions
122591efccSDavid Schultz  * are met:
132591efccSDavid Schultz  * 1. Redistributions of source code must retain the above copyright
142591efccSDavid Schultz  *    notice, this list of conditions and the following disclaimer.
152591efccSDavid Schultz  * 2. Redistributions in binary form must reproduce the above copyright
162591efccSDavid Schultz  *    notice, this list of conditions and the following disclaimer in the
172591efccSDavid Schultz  *    documentation and/or other materials provided with the distribution.
181d8053c5SEd Maste  * 3. Neither the name of the University nor the names of its contributors
192591efccSDavid Schultz  *    may be used to endorse or promote products derived from this software
202591efccSDavid Schultz  *    without specific prior written permission.
212591efccSDavid Schultz  *
222591efccSDavid Schultz  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232591efccSDavid Schultz  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242591efccSDavid Schultz  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252591efccSDavid Schultz  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262591efccSDavid Schultz  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272591efccSDavid Schultz  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282591efccSDavid Schultz  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292591efccSDavid Schultz  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302591efccSDavid Schultz  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312591efccSDavid Schultz  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322591efccSDavid Schultz  * SUCH DAMAGE.
332591efccSDavid Schultz  */
342591efccSDavid Schultz 
352591efccSDavid Schultz /*
362591efccSDavid Schultz  * This is the code responsible for handling positional arguments
372591efccSDavid Schultz  * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
382591efccSDavid Schultz  */
392591efccSDavid Schultz 
402591efccSDavid Schultz #include "namespace.h"
412591efccSDavid Schultz #include <sys/types.h>
422591efccSDavid Schultz 
43130a08a3SRuslan Bukin #include <limits.h>
44e62e5ff9SDavid Schultz #include <stdarg.h>
452591efccSDavid Schultz #include <stddef.h>
462591efccSDavid Schultz #include <stdint.h>
472591efccSDavid Schultz #include <stdio.h>
482591efccSDavid Schultz #include <stdlib.h>
492591efccSDavid Schultz #include <string.h>
502591efccSDavid Schultz #include <wchar.h>
512591efccSDavid Schultz 
522591efccSDavid Schultz #include "un-namespace.h"
532591efccSDavid Schultz #include "printflocal.h"
542591efccSDavid Schultz 
55130a08a3SRuslan Bukin #ifdef	NL_ARGMAX
56130a08a3SRuslan Bukin #define	MAX_POSARG	NL_ARGMAX
57130a08a3SRuslan Bukin #else
58130a08a3SRuslan Bukin #define	MAX_POSARG	65536
59130a08a3SRuslan Bukin #endif
60130a08a3SRuslan Bukin 
612591efccSDavid Schultz /*
622591efccSDavid Schultz  * Type ids for argument type table.
632591efccSDavid Schultz  */
642591efccSDavid Schultz enum typeid {
652591efccSDavid Schultz 	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
662591efccSDavid Schultz 	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
6788f919d6SDavid Schultz 	T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
682591efccSDavid Schultz 	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
692591efccSDavid Schultz 	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
702591efccSDavid Schultz };
712591efccSDavid Schultz 
722591efccSDavid Schultz /* An expandable array of types. */
732591efccSDavid Schultz struct typetable {
742591efccSDavid Schultz 	enum typeid *table; /* table of types */
752591efccSDavid Schultz 	enum typeid stattable[STATIC_ARG_TBL_SIZE];
76130a08a3SRuslan Bukin 	u_int tablesize;	/* current size of type table */
77130a08a3SRuslan Bukin 	u_int tablemax;		/* largest used index in table */
78130a08a3SRuslan Bukin 	u_int nextarg;		/* 1-based argument index */
792591efccSDavid Schultz };
802591efccSDavid Schultz 
81e62e5ff9SDavid Schultz static int	__grow_type_table(struct typetable *);
8207bed96bSDavid Schultz static void	build_arg_table (struct typetable *, va_list, union arg **);
832591efccSDavid Schultz 
842591efccSDavid Schultz /*
852591efccSDavid Schultz  * Initialize a struct typetable.
862591efccSDavid Schultz  */
872591efccSDavid Schultz static inline void
inittypes(struct typetable * types)882591efccSDavid Schultz inittypes(struct typetable *types)
892591efccSDavid Schultz {
90130a08a3SRuslan Bukin 	u_int n;
912591efccSDavid Schultz 
922591efccSDavid Schultz 	types->table = types->stattable;
932591efccSDavid Schultz 	types->tablesize = STATIC_ARG_TBL_SIZE;
942591efccSDavid Schultz 	types->tablemax = 0;
952591efccSDavid Schultz 	types->nextarg = 1;
962591efccSDavid Schultz 	for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
972591efccSDavid Schultz 		types->table[n] = T_UNUSED;
982591efccSDavid Schultz }
992591efccSDavid Schultz 
1002591efccSDavid Schultz /*
1012591efccSDavid Schultz  * struct typetable destructor.
1022591efccSDavid Schultz  */
1032591efccSDavid Schultz static inline void
freetypes(struct typetable * types)1042591efccSDavid Schultz freetypes(struct typetable *types)
1052591efccSDavid Schultz {
1062591efccSDavid Schultz 
1072591efccSDavid Schultz 	if (types->table != types->stattable)
1082591efccSDavid Schultz 		free (types->table);
1092591efccSDavid Schultz }
1102591efccSDavid Schultz 
1112591efccSDavid Schultz /*
112e62e5ff9SDavid Schultz  * Ensure that there is space to add a new argument type to the type table.
113e62e5ff9SDavid Schultz  * Expand the table if necessary. Returns 0 on success.
1142591efccSDavid Schultz  */
115e62e5ff9SDavid Schultz static inline int
_ensurespace(struct typetable * types)116e62e5ff9SDavid Schultz _ensurespace(struct typetable *types)
117e62e5ff9SDavid Schultz {
118e62e5ff9SDavid Schultz 
119e62e5ff9SDavid Schultz 	if (types->nextarg >= types->tablesize) {
120e62e5ff9SDavid Schultz 		if (__grow_type_table(types))
121e62e5ff9SDavid Schultz 			return (-1);
122e62e5ff9SDavid Schultz 	}
123e62e5ff9SDavid Schultz 	if (types->nextarg > types->tablemax)
124e62e5ff9SDavid Schultz 		types->tablemax = types->nextarg;
125e62e5ff9SDavid Schultz 	return (0);
126e62e5ff9SDavid Schultz }
127e62e5ff9SDavid Schultz 
128e62e5ff9SDavid Schultz /*
129e62e5ff9SDavid Schultz  * Add an argument type to the table, expanding if necessary.
130e62e5ff9SDavid Schultz  * Returns 0 on success.
131e62e5ff9SDavid Schultz  */
132e62e5ff9SDavid Schultz static inline int
addtype(struct typetable * types,enum typeid type)1332591efccSDavid Schultz addtype(struct typetable *types, enum typeid type)
1342591efccSDavid Schultz {
1352591efccSDavid Schultz 
136c4014b50SDavid Schultz 	if (_ensurespace(types))
137c4014b50SDavid Schultz 		return (-1);
1382591efccSDavid Schultz 	types->table[types->nextarg++] = type;
139e62e5ff9SDavid Schultz 	return (0);
1402591efccSDavid Schultz }
1412591efccSDavid Schultz 
142e62e5ff9SDavid Schultz static inline int
addsarg(struct typetable * types,int flags)1432591efccSDavid Schultz addsarg(struct typetable *types, int flags)
1442591efccSDavid Schultz {
1452591efccSDavid Schultz 
146e62e5ff9SDavid Schultz 	if (_ensurespace(types))
147e62e5ff9SDavid Schultz 		return (-1);
1482591efccSDavid Schultz 	if (flags & INTMAXT)
149e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_INTMAXT;
1502591efccSDavid Schultz 	else if (flags & SIZET)
1510881683bSDavid Schultz 		types->table[types->nextarg++] = T_SSIZET;
1522591efccSDavid Schultz 	else if (flags & PTRDIFFT)
153e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_PTRDIFFT;
1542591efccSDavid Schultz 	else if (flags & LLONGINT)
155e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_LLONG;
1562591efccSDavid Schultz 	else if (flags & LONGINT)
157e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_LONG;
1582591efccSDavid Schultz 	else
159e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_INT;
160e62e5ff9SDavid Schultz 	return (0);
1612591efccSDavid Schultz }
1622591efccSDavid Schultz 
163e62e5ff9SDavid Schultz static inline int
adduarg(struct typetable * types,int flags)1642591efccSDavid Schultz adduarg(struct typetable *types, int flags)
1652591efccSDavid Schultz {
1662591efccSDavid Schultz 
167e62e5ff9SDavid Schultz 	if (_ensurespace(types))
168e62e5ff9SDavid Schultz 		return (-1);
1692591efccSDavid Schultz 	if (flags & INTMAXT)
170e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_UINTMAXT;
1712591efccSDavid Schultz 	else if (flags & SIZET)
172e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_SIZET;
1732591efccSDavid Schultz 	else if (flags & PTRDIFFT)
1740881683bSDavid Schultz 		types->table[types->nextarg++] = T_SIZET;
1752591efccSDavid Schultz 	else if (flags & LLONGINT)
176e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_U_LLONG;
1772591efccSDavid Schultz 	else if (flags & LONGINT)
178e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_U_LONG;
1792591efccSDavid Schultz 	else
180e62e5ff9SDavid Schultz 		types->table[types->nextarg++] = T_U_INT;
181e62e5ff9SDavid Schultz 	return (0);
1822591efccSDavid Schultz }
1832591efccSDavid Schultz 
1842591efccSDavid Schultz /*
1852591efccSDavid Schultz  * Add * arguments to the type array.
1862591efccSDavid Schultz  */
187e62e5ff9SDavid Schultz static inline int
addaster(struct typetable * types,char ** fmtp)1882591efccSDavid Schultz addaster(struct typetable *types, char **fmtp)
1892591efccSDavid Schultz {
1902591efccSDavid Schultz 	char *cp;
191130a08a3SRuslan Bukin 	u_int n2;
1922591efccSDavid Schultz 
1932591efccSDavid Schultz 	n2 = 0;
1942591efccSDavid Schultz 	cp = *fmtp;
1952591efccSDavid Schultz 	while (is_digit(*cp)) {
1962591efccSDavid Schultz 		n2 = 10 * n2 + to_digit(*cp);
1972591efccSDavid Schultz 		cp++;
1982591efccSDavid Schultz 	}
1992591efccSDavid Schultz 	if (*cp == '$') {
200130a08a3SRuslan Bukin 		u_int hold = types->nextarg;
2012591efccSDavid Schultz 		types->nextarg = n2;
202c4014b50SDavid Schultz 		if (addtype(types, T_INT))
203c4014b50SDavid Schultz 			return (-1);
2042591efccSDavid Schultz 		types->nextarg = hold;
2052591efccSDavid Schultz 		*fmtp = ++cp;
2062591efccSDavid Schultz 	} else {
207c4014b50SDavid Schultz 		if (addtype(types, T_INT))
208c4014b50SDavid Schultz 			return (-1);
2092591efccSDavid Schultz 	}
210e62e5ff9SDavid Schultz 	return (0);
2112591efccSDavid Schultz }
2122591efccSDavid Schultz 
213e62e5ff9SDavid Schultz static inline int
addwaster(struct typetable * types,wchar_t ** fmtp)2142591efccSDavid Schultz addwaster(struct typetable *types, wchar_t **fmtp)
2152591efccSDavid Schultz {
2162591efccSDavid Schultz 	wchar_t *cp;
217130a08a3SRuslan Bukin 	u_int n2;
2182591efccSDavid Schultz 
2192591efccSDavid Schultz 	n2 = 0;
2202591efccSDavid Schultz 	cp = *fmtp;
2212591efccSDavid Schultz 	while (is_digit(*cp)) {
2222591efccSDavid Schultz 		n2 = 10 * n2 + to_digit(*cp);
2232591efccSDavid Schultz 		cp++;
2242591efccSDavid Schultz 	}
2252591efccSDavid Schultz 	if (*cp == '$') {
226130a08a3SRuslan Bukin 		u_int hold = types->nextarg;
2272591efccSDavid Schultz 		types->nextarg = n2;
228c4014b50SDavid Schultz 		if (addtype(types, T_INT))
229c4014b50SDavid Schultz 			return (-1);
2302591efccSDavid Schultz 		types->nextarg = hold;
2312591efccSDavid Schultz 		*fmtp = ++cp;
2322591efccSDavid Schultz 	} else {
233c4014b50SDavid Schultz 		if (addtype(types, T_INT))
234c4014b50SDavid Schultz 			return (-1);
2352591efccSDavid Schultz 	}
236e62e5ff9SDavid Schultz 	return (0);
2372591efccSDavid Schultz }
2382591efccSDavid Schultz 
2392591efccSDavid Schultz /*
2402591efccSDavid Schultz  * Find all arguments when a positional parameter is encountered.  Returns a
2412591efccSDavid Schultz  * table, indexed by argument number, of pointers to each arguments.  The
2422591efccSDavid Schultz  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
2432591efccSDavid Schultz  * It will be replaces with a malloc-ed one if it overflows.
244e62e5ff9SDavid Schultz  * Returns 0 on success. On failure, returns nonzero and sets errno.
2452591efccSDavid Schultz  */
246e62e5ff9SDavid Schultz int
__find_arguments(const char * fmt0,va_list ap,union arg ** argtable)2472591efccSDavid Schultz __find_arguments (const char *fmt0, va_list ap, union arg **argtable)
2482591efccSDavid Schultz {
2492591efccSDavid Schultz 	char *fmt;		/* format string */
2502591efccSDavid Schultz 	int ch;			/* character from fmt */
251130a08a3SRuslan Bukin 	u_int n;		/* handy integer (short term usage) */
252e62e5ff9SDavid Schultz 	int error;
2532591efccSDavid Schultz 	int flags;		/* flags as above */
2542591efccSDavid Schultz 	struct typetable types;	/* table of types */
2552591efccSDavid Schultz 
2562591efccSDavid Schultz 	fmt = (char *)fmt0;
2572591efccSDavid Schultz 	inittypes(&types);
258e62e5ff9SDavid Schultz 	error = 0;
2592591efccSDavid Schultz 
2602591efccSDavid Schultz 	/*
2612591efccSDavid Schultz 	 * Scan the format for conversions (`%' character).
2622591efccSDavid Schultz 	 */
2632591efccSDavid Schultz 	for (;;) {
2642591efccSDavid Schultz 		while ((ch = *fmt) != '\0' && ch != '%')
2652591efccSDavid Schultz 			fmt++;
2662591efccSDavid Schultz 		if (ch == '\0')
2672591efccSDavid Schultz 			goto done;
2682591efccSDavid Schultz 		fmt++;		/* skip over '%' */
2692591efccSDavid Schultz 
2702591efccSDavid Schultz 		flags = 0;
2712591efccSDavid Schultz 
2722591efccSDavid Schultz rflag:		ch = *fmt++;
2732591efccSDavid Schultz reswitch:	switch (ch) {
2742591efccSDavid Schultz 		case ' ':
2752591efccSDavid Schultz 		case '#':
2762591efccSDavid Schultz 			goto rflag;
2772591efccSDavid Schultz 		case '*':
278e62e5ff9SDavid Schultz 			if ((error = addaster(&types, &fmt)))
279e62e5ff9SDavid Schultz 				goto error;
2802591efccSDavid Schultz 			goto rflag;
2812591efccSDavid Schultz 		case '-':
2822591efccSDavid Schultz 		case '+':
2832591efccSDavid Schultz 		case '\'':
2842591efccSDavid Schultz 			goto rflag;
2852591efccSDavid Schultz 		case '.':
2862591efccSDavid Schultz 			if ((ch = *fmt++) == '*') {
287e62e5ff9SDavid Schultz 				if ((error = addaster(&types, &fmt)))
288e62e5ff9SDavid Schultz 					goto error;
2892591efccSDavid Schultz 				goto rflag;
2902591efccSDavid Schultz 			}
2912591efccSDavid Schultz 			while (is_digit(ch)) {
2922591efccSDavid Schultz 				ch = *fmt++;
2932591efccSDavid Schultz 			}
2942591efccSDavid Schultz 			goto reswitch;
2952591efccSDavid Schultz 		case '0':
2962591efccSDavid Schultz 			goto rflag;
2972591efccSDavid Schultz 		case '1': case '2': case '3': case '4':
2982591efccSDavid Schultz 		case '5': case '6': case '7': case '8': case '9':
2992591efccSDavid Schultz 			n = 0;
3002591efccSDavid Schultz 			do {
3012591efccSDavid Schultz 				n = 10 * n + to_digit(ch);
302130a08a3SRuslan Bukin 				/* Detect overflow */
303130a08a3SRuslan Bukin 				if (n > MAX_POSARG) {
304130a08a3SRuslan Bukin 					error = -1;
305130a08a3SRuslan Bukin 					goto error;
306130a08a3SRuslan Bukin 				}
3072591efccSDavid Schultz 				ch = *fmt++;
3082591efccSDavid Schultz 			} while (is_digit(ch));
3092591efccSDavid Schultz 			if (ch == '$') {
3102591efccSDavid Schultz 				types.nextarg = n;
3112591efccSDavid Schultz 				goto rflag;
3122591efccSDavid Schultz 			}
3132591efccSDavid Schultz 			goto reswitch;
3142591efccSDavid Schultz #ifndef NO_FLOATING_POINT
3152591efccSDavid Schultz 		case 'L':
3162591efccSDavid Schultz 			flags |= LONGDBL;
3172591efccSDavid Schultz 			goto rflag;
3182591efccSDavid Schultz #endif
3192591efccSDavid Schultz 		case 'h':
3202591efccSDavid Schultz 			if (flags & SHORTINT) {
3212591efccSDavid Schultz 				flags &= ~SHORTINT;
3222591efccSDavid Schultz 				flags |= CHARINT;
3232591efccSDavid Schultz 			} else
3242591efccSDavid Schultz 				flags |= SHORTINT;
3252591efccSDavid Schultz 			goto rflag;
3262591efccSDavid Schultz 		case 'j':
3272591efccSDavid Schultz 			flags |= INTMAXT;
3282591efccSDavid Schultz 			goto rflag;
3292591efccSDavid Schultz 		case 'l':
3302591efccSDavid Schultz 			if (flags & LONGINT) {
3312591efccSDavid Schultz 				flags &= ~LONGINT;
3322591efccSDavid Schultz 				flags |= LLONGINT;
3332591efccSDavid Schultz 			} else
3342591efccSDavid Schultz 				flags |= LONGINT;
3352591efccSDavid Schultz 			goto rflag;
3362591efccSDavid Schultz 		case 'q':
3372591efccSDavid Schultz 			flags |= LLONGINT;	/* not necessarily */
3382591efccSDavid Schultz 			goto rflag;
3392591efccSDavid Schultz 		case 't':
3402591efccSDavid Schultz 			flags |= PTRDIFFT;
3412591efccSDavid Schultz 			goto rflag;
3422591efccSDavid Schultz 		case 'z':
3432591efccSDavid Schultz 			flags |= SIZET;
3442591efccSDavid Schultz 			goto rflag;
3452591efccSDavid Schultz 		case 'C':
3462591efccSDavid Schultz 			flags |= LONGINT;
3472591efccSDavid Schultz 			/*FALLTHROUGH*/
3482591efccSDavid Schultz 		case 'c':
349e62e5ff9SDavid Schultz 			error = addtype(&types,
350e62e5ff9SDavid Schultz 					(flags & LONGINT) ? T_WINT : T_INT);
351e62e5ff9SDavid Schultz 			if (error)
352e62e5ff9SDavid Schultz 				goto error;
3532591efccSDavid Schultz 			break;
3542591efccSDavid Schultz 		case 'D':
3552591efccSDavid Schultz 			flags |= LONGINT;
3562591efccSDavid Schultz 			/*FALLTHROUGH*/
3572591efccSDavid Schultz 		case 'd':
3582591efccSDavid Schultz 		case 'i':
359e62e5ff9SDavid Schultz 			if ((error = addsarg(&types, flags)))
360e62e5ff9SDavid Schultz 				goto error;
3612591efccSDavid Schultz 			break;
3622591efccSDavid Schultz #ifndef NO_FLOATING_POINT
3632591efccSDavid Schultz 		case 'a':
3642591efccSDavid Schultz 		case 'A':
3652591efccSDavid Schultz 		case 'e':
3662591efccSDavid Schultz 		case 'E':
3672591efccSDavid Schultz 		case 'f':
3682591efccSDavid Schultz 		case 'g':
3692591efccSDavid Schultz 		case 'G':
370e62e5ff9SDavid Schultz 			error = addtype(&types,
371e62e5ff9SDavid Schultz 			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
372e62e5ff9SDavid Schultz 			if (error)
373e62e5ff9SDavid Schultz 				goto error;
3742591efccSDavid Schultz 			break;
3752591efccSDavid Schultz #endif /* !NO_FLOATING_POINT */
3762591efccSDavid Schultz 		case 'n':
3772591efccSDavid Schultz 			if (flags & INTMAXT)
378e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INTMAXT);
3792591efccSDavid Schultz 			else if (flags & PTRDIFFT)
380e62e5ff9SDavid Schultz 				error = addtype(&types, TP_PTRDIFFT);
3812591efccSDavid Schultz 			else if (flags & SIZET)
38288f919d6SDavid Schultz 				error = addtype(&types, TP_SSIZET);
3832591efccSDavid Schultz 			else if (flags & LLONGINT)
384e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LLONG);
3852591efccSDavid Schultz 			else if (flags & LONGINT)
386e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LONG);
3872591efccSDavid Schultz 			else if (flags & SHORTINT)
388e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SHORT);
3892591efccSDavid Schultz 			else if (flags & CHARINT)
390e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SCHAR);
3912591efccSDavid Schultz 			else
392e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INT);
393e62e5ff9SDavid Schultz 			if (error)
394e62e5ff9SDavid Schultz 				goto error;
3952591efccSDavid Schultz 			continue;	/* no output */
3962591efccSDavid Schultz 		case 'O':
3972591efccSDavid Schultz 			flags |= LONGINT;
3982591efccSDavid Schultz 			/*FALLTHROUGH*/
3992591efccSDavid Schultz 		case 'o':
400e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
401e62e5ff9SDavid Schultz 				goto error;
4022591efccSDavid Schultz 			break;
4032591efccSDavid Schultz 		case 'p':
404e62e5ff9SDavid Schultz 			if ((error = addtype(&types, TP_VOID)))
405e62e5ff9SDavid Schultz 				goto error;
4062591efccSDavid Schultz 			break;
4072591efccSDavid Schultz 		case 'S':
4082591efccSDavid Schultz 			flags |= LONGINT;
4092591efccSDavid Schultz 			/*FALLTHROUGH*/
4102591efccSDavid Schultz 		case 's':
411e62e5ff9SDavid Schultz 			error = addtype(&types,
412e62e5ff9SDavid Schultz 					(flags & LONGINT) ? TP_WCHAR : TP_CHAR);
413e62e5ff9SDavid Schultz 			if (error)
414e62e5ff9SDavid Schultz 				goto error;
4152591efccSDavid Schultz 			break;
4162591efccSDavid Schultz 		case 'U':
4172591efccSDavid Schultz 			flags |= LONGINT;
4182591efccSDavid Schultz 			/*FALLTHROUGH*/
4192591efccSDavid Schultz 		case 'u':
4202591efccSDavid Schultz 		case 'X':
4212591efccSDavid Schultz 		case 'x':
422e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
423e62e5ff9SDavid Schultz 				goto error;
4242591efccSDavid Schultz 			break;
4252591efccSDavid Schultz 		default:	/* "%?" prints ?, unless ? is NUL */
4262591efccSDavid Schultz 			if (ch == '\0')
4272591efccSDavid Schultz 				goto done;
4282591efccSDavid Schultz 			break;
4292591efccSDavid Schultz 		}
4302591efccSDavid Schultz 	}
4312591efccSDavid Schultz done:
43207bed96bSDavid Schultz 	build_arg_table(&types, ap, argtable);
433e62e5ff9SDavid Schultz error:
4342591efccSDavid Schultz 	freetypes(&types);
435e62e5ff9SDavid Schultz 	return (error || *argtable == NULL);
4362591efccSDavid Schultz }
4372591efccSDavid Schultz 
4382591efccSDavid Schultz /* wchar version of __find_arguments. */
439e62e5ff9SDavid Schultz int
__find_warguments(const wchar_t * fmt0,va_list ap,union arg ** argtable)4402591efccSDavid Schultz __find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
4412591efccSDavid Schultz {
4422591efccSDavid Schultz 	wchar_t *fmt;		/* format string */
4432591efccSDavid Schultz 	wchar_t ch;		/* character from fmt */
444130a08a3SRuslan Bukin 	u_int n;		/* handy integer (short term usage) */
445e62e5ff9SDavid Schultz 	int error;
4462591efccSDavid Schultz 	int flags;		/* flags as above */
4472591efccSDavid Schultz 	struct typetable types;	/* table of types */
4482591efccSDavid Schultz 
4492591efccSDavid Schultz 	fmt = (wchar_t *)fmt0;
4502591efccSDavid Schultz 	inittypes(&types);
451e62e5ff9SDavid Schultz 	error = 0;
4522591efccSDavid Schultz 
4532591efccSDavid Schultz 	/*
4542591efccSDavid Schultz 	 * Scan the format for conversions (`%' character).
4552591efccSDavid Schultz 	 */
4562591efccSDavid Schultz 	for (;;) {
4572591efccSDavid Schultz 		while ((ch = *fmt) != '\0' && ch != '%')
4582591efccSDavid Schultz 			fmt++;
4592591efccSDavid Schultz 		if (ch == '\0')
4602591efccSDavid Schultz 			goto done;
4612591efccSDavid Schultz 		fmt++;		/* skip over '%' */
4622591efccSDavid Schultz 
4632591efccSDavid Schultz 		flags = 0;
4642591efccSDavid Schultz 
4652591efccSDavid Schultz rflag:		ch = *fmt++;
4662591efccSDavid Schultz reswitch:	switch (ch) {
4672591efccSDavid Schultz 		case ' ':
4682591efccSDavid Schultz 		case '#':
4692591efccSDavid Schultz 			goto rflag;
4702591efccSDavid Schultz 		case '*':
471e62e5ff9SDavid Schultz 			if ((error = addwaster(&types, &fmt)))
472e62e5ff9SDavid Schultz 				goto error;
4732591efccSDavid Schultz 			goto rflag;
4742591efccSDavid Schultz 		case '-':
4752591efccSDavid Schultz 		case '+':
4762591efccSDavid Schultz 		case '\'':
4772591efccSDavid Schultz 			goto rflag;
4782591efccSDavid Schultz 		case '.':
4792591efccSDavid Schultz 			if ((ch = *fmt++) == '*') {
480e62e5ff9SDavid Schultz 				if ((error = addwaster(&types, &fmt)))
481e62e5ff9SDavid Schultz 					goto error;
4822591efccSDavid Schultz 				goto rflag;
4832591efccSDavid Schultz 			}
4842591efccSDavid Schultz 			while (is_digit(ch)) {
4852591efccSDavid Schultz 				ch = *fmt++;
4862591efccSDavid Schultz 			}
4872591efccSDavid Schultz 			goto reswitch;
4882591efccSDavid Schultz 		case '0':
4892591efccSDavid Schultz 			goto rflag;
4902591efccSDavid Schultz 		case '1': case '2': case '3': case '4':
4912591efccSDavid Schultz 		case '5': case '6': case '7': case '8': case '9':
4922591efccSDavid Schultz 			n = 0;
4932591efccSDavid Schultz 			do {
4942591efccSDavid Schultz 				n = 10 * n + to_digit(ch);
495130a08a3SRuslan Bukin 				/* Detect overflow */
496130a08a3SRuslan Bukin 				if (n > MAX_POSARG) {
497130a08a3SRuslan Bukin 					error = -1;
498130a08a3SRuslan Bukin 					goto error;
499130a08a3SRuslan Bukin 				}
5002591efccSDavid Schultz 				ch = *fmt++;
5012591efccSDavid Schultz 			} while (is_digit(ch));
5022591efccSDavid Schultz 			if (ch == '$') {
5032591efccSDavid Schultz 				types.nextarg = n;
5042591efccSDavid Schultz 				goto rflag;
5052591efccSDavid Schultz 			}
5062591efccSDavid Schultz 			goto reswitch;
5072591efccSDavid Schultz #ifndef NO_FLOATING_POINT
5082591efccSDavid Schultz 		case 'L':
5092591efccSDavid Schultz 			flags |= LONGDBL;
5102591efccSDavid Schultz 			goto rflag;
5112591efccSDavid Schultz #endif
5122591efccSDavid Schultz 		case 'h':
5132591efccSDavid Schultz 			if (flags & SHORTINT) {
5142591efccSDavid Schultz 				flags &= ~SHORTINT;
5152591efccSDavid Schultz 				flags |= CHARINT;
5162591efccSDavid Schultz 			} else
5172591efccSDavid Schultz 				flags |= SHORTINT;
5182591efccSDavid Schultz 			goto rflag;
5192591efccSDavid Schultz 		case 'j':
5202591efccSDavid Schultz 			flags |= INTMAXT;
5212591efccSDavid Schultz 			goto rflag;
5222591efccSDavid Schultz 		case 'l':
5232591efccSDavid Schultz 			if (flags & LONGINT) {
5242591efccSDavid Schultz 				flags &= ~LONGINT;
5252591efccSDavid Schultz 				flags |= LLONGINT;
5262591efccSDavid Schultz 			} else
5272591efccSDavid Schultz 				flags |= LONGINT;
5282591efccSDavid Schultz 			goto rflag;
5292591efccSDavid Schultz 		case 'q':
5302591efccSDavid Schultz 			flags |= LLONGINT;	/* not necessarily */
5312591efccSDavid Schultz 			goto rflag;
5322591efccSDavid Schultz 		case 't':
5332591efccSDavid Schultz 			flags |= PTRDIFFT;
5342591efccSDavid Schultz 			goto rflag;
5352591efccSDavid Schultz 		case 'z':
5362591efccSDavid Schultz 			flags |= SIZET;
5372591efccSDavid Schultz 			goto rflag;
5382591efccSDavid Schultz 		case 'C':
5392591efccSDavid Schultz 			flags |= LONGINT;
5402591efccSDavid Schultz 			/*FALLTHROUGH*/
5412591efccSDavid Schultz 		case 'c':
542e62e5ff9SDavid Schultz 			error = addtype(&types,
543e62e5ff9SDavid Schultz 					(flags & LONGINT) ? T_WINT : T_INT);
544e62e5ff9SDavid Schultz 			if (error)
545e62e5ff9SDavid Schultz 				goto error;
5462591efccSDavid Schultz 			break;
5472591efccSDavid Schultz 		case 'D':
5482591efccSDavid Schultz 			flags |= LONGINT;
5492591efccSDavid Schultz 			/*FALLTHROUGH*/
5502591efccSDavid Schultz 		case 'd':
5512591efccSDavid Schultz 		case 'i':
552e62e5ff9SDavid Schultz 			if ((error = addsarg(&types, flags)))
553e62e5ff9SDavid Schultz 				goto error;
5542591efccSDavid Schultz 			break;
5552591efccSDavid Schultz #ifndef NO_FLOATING_POINT
5562591efccSDavid Schultz 		case 'a':
5572591efccSDavid Schultz 		case 'A':
5582591efccSDavid Schultz 		case 'e':
5592591efccSDavid Schultz 		case 'E':
5602591efccSDavid Schultz 		case 'f':
5612591efccSDavid Schultz 		case 'g':
5622591efccSDavid Schultz 		case 'G':
563e62e5ff9SDavid Schultz 			error = addtype(&types,
564e62e5ff9SDavid Schultz 			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
565e62e5ff9SDavid Schultz 			if (error)
566e62e5ff9SDavid Schultz 				goto error;
5672591efccSDavid Schultz 			break;
5682591efccSDavid Schultz #endif /* !NO_FLOATING_POINT */
5692591efccSDavid Schultz 		case 'n':
5702591efccSDavid Schultz 			if (flags & INTMAXT)
571e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INTMAXT);
5722591efccSDavid Schultz 			else if (flags & PTRDIFFT)
573e62e5ff9SDavid Schultz 				error = addtype(&types, TP_PTRDIFFT);
5742591efccSDavid Schultz 			else if (flags & SIZET)
57588f919d6SDavid Schultz 				error = addtype(&types, TP_SSIZET);
5762591efccSDavid Schultz 			else if (flags & LLONGINT)
577e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LLONG);
5782591efccSDavid Schultz 			else if (flags & LONGINT)
579e62e5ff9SDavid Schultz 				error = addtype(&types, TP_LONG);
5802591efccSDavid Schultz 			else if (flags & SHORTINT)
581e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SHORT);
5822591efccSDavid Schultz 			else if (flags & CHARINT)
583e62e5ff9SDavid Schultz 				error = addtype(&types, TP_SCHAR);
5842591efccSDavid Schultz 			else
585e62e5ff9SDavid Schultz 				error = addtype(&types, TP_INT);
586c4014b50SDavid Schultz 			if (error)
587c4014b50SDavid Schultz 				goto error;
5882591efccSDavid Schultz 			continue;	/* no output */
5892591efccSDavid Schultz 		case 'O':
5902591efccSDavid Schultz 			flags |= LONGINT;
5912591efccSDavid Schultz 			/*FALLTHROUGH*/
5922591efccSDavid Schultz 		case 'o':
593e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
594e62e5ff9SDavid Schultz 				goto error;
5952591efccSDavid Schultz 			break;
5962591efccSDavid Schultz 		case 'p':
597e62e5ff9SDavid Schultz 			if ((error = addtype(&types, TP_VOID)))
598e62e5ff9SDavid Schultz 				goto error;
5992591efccSDavid Schultz 			break;
6002591efccSDavid Schultz 		case 'S':
6012591efccSDavid Schultz 			flags |= LONGINT;
6022591efccSDavid Schultz 			/*FALLTHROUGH*/
6032591efccSDavid Schultz 		case 's':
604e62e5ff9SDavid Schultz 			error = addtype(&types,
605e62e5ff9SDavid Schultz 			    (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
606e62e5ff9SDavid Schultz 			if (error)
607e62e5ff9SDavid Schultz 				goto error;
6082591efccSDavid Schultz 			break;
6092591efccSDavid Schultz 		case 'U':
6102591efccSDavid Schultz 			flags |= LONGINT;
6112591efccSDavid Schultz 			/*FALLTHROUGH*/
6122591efccSDavid Schultz 		case 'u':
6132591efccSDavid Schultz 		case 'X':
6142591efccSDavid Schultz 		case 'x':
615e62e5ff9SDavid Schultz 			if ((error = adduarg(&types, flags)))
616e62e5ff9SDavid Schultz 				goto error;
6172591efccSDavid Schultz 			break;
6182591efccSDavid Schultz 		default:	/* "%?" prints ?, unless ? is NUL */
6192591efccSDavid Schultz 			if (ch == '\0')
6202591efccSDavid Schultz 				goto done;
6212591efccSDavid Schultz 			break;
6222591efccSDavid Schultz 		}
6232591efccSDavid Schultz 	}
6242591efccSDavid Schultz done:
62507bed96bSDavid Schultz 	build_arg_table(&types, ap, argtable);
626e62e5ff9SDavid Schultz error:
62707bed96bSDavid Schultz 	freetypes(&types);
628e62e5ff9SDavid Schultz 	return (error || *argtable == NULL);
62907bed96bSDavid Schultz }
63007bed96bSDavid Schultz 
6312591efccSDavid Schultz /*
632e62e5ff9SDavid Schultz  * Increase the size of the type table. Returns 0 on success.
6332591efccSDavid Schultz  */
634e62e5ff9SDavid Schultz static int
__grow_type_table(struct typetable * types)63507bed96bSDavid Schultz __grow_type_table(struct typetable *types)
63607bed96bSDavid Schultz {
63707bed96bSDavid Schultz 	enum typeid *const oldtable = types->table;
63807bed96bSDavid Schultz 	const int oldsize = types->tablesize;
63907bed96bSDavid Schultz 	enum typeid *newtable;
64097721eb5SPedro F. Giffuni 	u_int n, newsize;
641130a08a3SRuslan Bukin 
642130a08a3SRuslan Bukin 	/* Detect overflow */
643130a08a3SRuslan Bukin 	if (types->nextarg > NL_ARGMAX)
644130a08a3SRuslan Bukin 		return (-1);
64507bed96bSDavid Schultz 
64697721eb5SPedro F. Giffuni 	newsize = oldsize * 2;
64707bed96bSDavid Schultz 	if (newsize < types->nextarg + 1)
64807bed96bSDavid Schultz 		newsize = types->nextarg + 1;
64907bed96bSDavid Schultz 	if (oldsize == STATIC_ARG_TBL_SIZE) {
65007bed96bSDavid Schultz 		if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
651e62e5ff9SDavid Schultz 			return (-1);
65207bed96bSDavid Schultz 		bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
65307bed96bSDavid Schultz 	} else {
6549f36610fSPedro F. Giffuni 		newtable = reallocarray(oldtable, newsize, sizeof(enum typeid));
65507bed96bSDavid Schultz 		if (newtable == NULL)
656e62e5ff9SDavid Schultz 			return (-1);
65707bed96bSDavid Schultz 	}
65807bed96bSDavid Schultz 	for (n = oldsize; n < newsize; n++)
65907bed96bSDavid Schultz 		newtable[n] = T_UNUSED;
66007bed96bSDavid Schultz 
66107bed96bSDavid Schultz 	types->table = newtable;
66207bed96bSDavid Schultz 	types->tablesize = newsize;
663e62e5ff9SDavid Schultz 
664e62e5ff9SDavid Schultz 	return (0);
66507bed96bSDavid Schultz }
66607bed96bSDavid Schultz 
66707bed96bSDavid Schultz /*
66807bed96bSDavid Schultz  * Build the argument table from the completed type table.
669e62e5ff9SDavid Schultz  * On malloc failure, *argtable is set to NULL.
67007bed96bSDavid Schultz  */
67107bed96bSDavid Schultz static void
build_arg_table(struct typetable * types,va_list ap,union arg ** argtable)67207bed96bSDavid Schultz build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
67307bed96bSDavid Schultz {
674130a08a3SRuslan Bukin 	u_int n;
67507bed96bSDavid Schultz 
67607bed96bSDavid Schultz 	if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
6772591efccSDavid Schultz 		*argtable = (union arg *)
67807bed96bSDavid Schultz 		    malloc (sizeof (union arg) * (types->tablemax + 1));
679e62e5ff9SDavid Schultz 		if (*argtable == NULL)
680e62e5ff9SDavid Schultz 			return;
6812591efccSDavid Schultz 	}
6822591efccSDavid Schultz 
6832591efccSDavid Schultz 	(*argtable) [0].intarg = 0;
68407bed96bSDavid Schultz 	for (n = 1; n <= types->tablemax; n++) {
68507bed96bSDavid Schultz 		switch (types->table[n]) {
6862591efccSDavid Schultz 		    case T_UNUSED: /* whoops! */
6872591efccSDavid Schultz 			(*argtable) [n].intarg = va_arg (ap, int);
6882591efccSDavid Schultz 			break;
6892591efccSDavid Schultz 		    case TP_SCHAR:
6902591efccSDavid Schultz 			(*argtable) [n].pschararg = va_arg (ap, signed char *);
6912591efccSDavid Schultz 			break;
6922591efccSDavid Schultz 		    case TP_SHORT:
6932591efccSDavid Schultz 			(*argtable) [n].pshortarg = va_arg (ap, short *);
6942591efccSDavid Schultz 			break;
6952591efccSDavid Schultz 		    case T_INT:
6962591efccSDavid Schultz 			(*argtable) [n].intarg = va_arg (ap, int);
6972591efccSDavid Schultz 			break;
6982591efccSDavid Schultz 		    case T_U_INT:
6992591efccSDavid Schultz 			(*argtable) [n].uintarg = va_arg (ap, unsigned int);
7002591efccSDavid Schultz 			break;
7012591efccSDavid Schultz 		    case TP_INT:
7022591efccSDavid Schultz 			(*argtable) [n].pintarg = va_arg (ap, int *);
7032591efccSDavid Schultz 			break;
7042591efccSDavid Schultz 		    case T_LONG:
7052591efccSDavid Schultz 			(*argtable) [n].longarg = va_arg (ap, long);
7062591efccSDavid Schultz 			break;
7072591efccSDavid Schultz 		    case T_U_LONG:
7082591efccSDavid Schultz 			(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
7092591efccSDavid Schultz 			break;
7102591efccSDavid Schultz 		    case TP_LONG:
7112591efccSDavid Schultz 			(*argtable) [n].plongarg = va_arg (ap, long *);
7122591efccSDavid Schultz 			break;
7132591efccSDavid Schultz 		    case T_LLONG:
7142591efccSDavid Schultz 			(*argtable) [n].longlongarg = va_arg (ap, long long);
7152591efccSDavid Schultz 			break;
7162591efccSDavid Schultz 		    case T_U_LLONG:
7172591efccSDavid Schultz 			(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
7182591efccSDavid Schultz 			break;
7192591efccSDavid Schultz 		    case TP_LLONG:
7202591efccSDavid Schultz 			(*argtable) [n].plonglongarg = va_arg (ap, long long *);
7212591efccSDavid Schultz 			break;
7222591efccSDavid Schultz 		    case T_PTRDIFFT:
7232591efccSDavid Schultz 			(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
7242591efccSDavid Schultz 			break;
7252591efccSDavid Schultz 		    case TP_PTRDIFFT:
7262591efccSDavid Schultz 			(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
7272591efccSDavid Schultz 			break;
7282591efccSDavid Schultz 		    case T_SIZET:
7292591efccSDavid Schultz 			(*argtable) [n].sizearg = va_arg (ap, size_t);
7302591efccSDavid Schultz 			break;
7310881683bSDavid Schultz 		    case T_SSIZET:
7320881683bSDavid Schultz 			(*argtable) [n].sizearg = va_arg (ap, ssize_t);
7330881683bSDavid Schultz 			break;
73488f919d6SDavid Schultz 		    case TP_SSIZET:
73588f919d6SDavid Schultz 			(*argtable) [n].pssizearg = va_arg (ap, ssize_t *);
7362591efccSDavid Schultz 			break;
7372591efccSDavid Schultz 		    case T_INTMAXT:
7382591efccSDavid Schultz 			(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
7392591efccSDavid Schultz 			break;
7402591efccSDavid Schultz 		    case T_UINTMAXT:
7412591efccSDavid Schultz 			(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
7422591efccSDavid Schultz 			break;
7432591efccSDavid Schultz 		    case TP_INTMAXT:
7442591efccSDavid Schultz 			(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
7452591efccSDavid Schultz 			break;
7462591efccSDavid Schultz 		    case T_DOUBLE:
7472591efccSDavid Schultz #ifndef NO_FLOATING_POINT
7482591efccSDavid Schultz 			(*argtable) [n].doublearg = va_arg (ap, double);
7492591efccSDavid Schultz #endif
7502591efccSDavid Schultz 			break;
7512591efccSDavid Schultz 		    case T_LONG_DOUBLE:
7522591efccSDavid Schultz #ifndef NO_FLOATING_POINT
7532591efccSDavid Schultz 			(*argtable) [n].longdoublearg = va_arg (ap, long double);
7542591efccSDavid Schultz #endif
7552591efccSDavid Schultz 			break;
7562591efccSDavid Schultz 		    case TP_CHAR:
7572591efccSDavid Schultz 			(*argtable) [n].pchararg = va_arg (ap, char *);
7582591efccSDavid Schultz 			break;
7592591efccSDavid Schultz 		    case TP_VOID:
7602591efccSDavid Schultz 			(*argtable) [n].pvoidarg = va_arg (ap, void *);
7612591efccSDavid Schultz 			break;
7622591efccSDavid Schultz 		    case T_WINT:
7632591efccSDavid Schultz 			(*argtable) [n].wintarg = va_arg (ap, wint_t);
7642591efccSDavid Schultz 			break;
7652591efccSDavid Schultz 		    case TP_WCHAR:
7662591efccSDavid Schultz 			(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
7672591efccSDavid Schultz 			break;
7682591efccSDavid Schultz 		}
7692591efccSDavid Schultz 	}
7702591efccSDavid Schultz }
771