xref: /dflybsd-src/lib/libc/stdio/printf-pos.c (revision cf515c3a6f3a8964ad592e524442bc628f8ed63b)
1e0f95098SPeter Avalos /*-
2e0f95098SPeter Avalos  * Copyright (c) 1990, 1993
3e0f95098SPeter Avalos  *	The Regents of the University of California.  All rights reserved.
4e0f95098SPeter Avalos  *
5e0f95098SPeter Avalos  * This code is derived from software contributed to Berkeley by
6e0f95098SPeter Avalos  * Chris Torek.
7e0f95098SPeter Avalos  *
8e0f95098SPeter Avalos  * Redistribution and use in source and binary forms, with or without
9e0f95098SPeter Avalos  * modification, are permitted provided that the following conditions
10e0f95098SPeter Avalos  * are met:
11e0f95098SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
12e0f95098SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
13e0f95098SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
14e0f95098SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
15e0f95098SPeter Avalos  *    documentation and/or other materials provided with the distribution.
16*dc71b7abSJustin C. Sherrill  * 3. Neither the name of the University nor the names of its contributors
17e0f95098SPeter Avalos  *    may be used to endorse or promote products derived from this software
18e0f95098SPeter Avalos  *    without specific prior written permission.
19e0f95098SPeter Avalos  *
20e0f95098SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21e0f95098SPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22e0f95098SPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23e0f95098SPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24e0f95098SPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25e0f95098SPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26e0f95098SPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27e0f95098SPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28e0f95098SPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29e0f95098SPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30e0f95098SPeter Avalos  * SUCH DAMAGE.
31e0f95098SPeter Avalos  *
32e0f95098SPeter Avalos  * @(#)vfprintf.c	8.1 (Berkeley) 6/4/93
33e0f95098SPeter Avalos  * $FreeBSD: src/lib/libc/stdio/printf-pos.c,v 1.6 2009/03/02 04:07:58 das Exp $
34e0f95098SPeter Avalos  */
35e0f95098SPeter Avalos 
36e0f95098SPeter Avalos /*
37e0f95098SPeter Avalos  * This is the code responsible for handling positional arguments
38e0f95098SPeter Avalos  * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
39e0f95098SPeter Avalos  */
40e0f95098SPeter Avalos 
41e0f95098SPeter Avalos #include "namespace.h"
42e0f95098SPeter Avalos #include <sys/types.h>
43e0f95098SPeter Avalos 
44e0f95098SPeter Avalos #include <stdarg.h>
45e0f95098SPeter Avalos #include <stddef.h>
46e0f95098SPeter Avalos #include <stdint.h>
47e0f95098SPeter Avalos #include <stdio.h>
48e0f95098SPeter Avalos #include <stdlib.h>
49e0f95098SPeter Avalos #include <string.h>
50e0f95098SPeter Avalos #include <wchar.h>
51e0f95098SPeter Avalos 
52e0f95098SPeter Avalos #include "un-namespace.h"
53e0f95098SPeter Avalos #include "printflocal.h"
54e0f95098SPeter Avalos 
55e0f95098SPeter Avalos /*
56e0f95098SPeter Avalos  * Type ids for argument type table.
57e0f95098SPeter Avalos  */
58e0f95098SPeter Avalos enum typeid {
59e0f95098SPeter Avalos 	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
60e0f95098SPeter Avalos 	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
61e0f95098SPeter Avalos 	T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
62e0f95098SPeter Avalos 	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
63e0f95098SPeter Avalos 	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
64e0f95098SPeter Avalos };
65e0f95098SPeter Avalos 
66e0f95098SPeter Avalos /* An expandable array of types. */
67e0f95098SPeter Avalos struct typetable {
68e0f95098SPeter Avalos 	enum typeid *table; /* table of types */
69e0f95098SPeter Avalos 	enum typeid stattable[STATIC_ARG_TBL_SIZE];
70e0f95098SPeter Avalos 	int tablesize;		/* current size of type table */
71e0f95098SPeter Avalos 	int tablemax;		/* largest used index in table */
72e0f95098SPeter Avalos 	int nextarg;		/* 1-based argument index */
73e0f95098SPeter Avalos };
74e0f95098SPeter Avalos 
75e0f95098SPeter Avalos static int	__grow_type_table(struct typetable *);
76e0f95098SPeter Avalos static void	build_arg_table (struct typetable *, va_list, union arg **);
77e0f95098SPeter Avalos 
78e0f95098SPeter Avalos /*
79e0f95098SPeter Avalos  * Initialize a struct typetable.
80e0f95098SPeter Avalos  */
81e0f95098SPeter Avalos static inline void
inittypes(struct typetable * types)82e0f95098SPeter Avalos inittypes(struct typetable *types)
83e0f95098SPeter Avalos {
84e0f95098SPeter Avalos 	int n;
85e0f95098SPeter Avalos 
86e0f95098SPeter Avalos 	types->table = types->stattable;
87e0f95098SPeter Avalos 	types->tablesize = STATIC_ARG_TBL_SIZE;
88e0f95098SPeter Avalos 	types->tablemax = 0;
89e0f95098SPeter Avalos 	types->nextarg = 1;
90e0f95098SPeter Avalos 	for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
91e0f95098SPeter Avalos 		types->table[n] = T_UNUSED;
92e0f95098SPeter Avalos }
93e0f95098SPeter Avalos 
94e0f95098SPeter Avalos /*
95e0f95098SPeter Avalos  * struct typetable destructor.
96e0f95098SPeter Avalos  */
97e0f95098SPeter Avalos static inline void
freetypes(struct typetable * types)98e0f95098SPeter Avalos freetypes(struct typetable *types)
99e0f95098SPeter Avalos {
100e0f95098SPeter Avalos 
101e0f95098SPeter Avalos 	if (types->table != types->stattable)
102e0f95098SPeter Avalos 		free(types->table);
103e0f95098SPeter Avalos }
104e0f95098SPeter Avalos 
105e0f95098SPeter Avalos /*
106e0f95098SPeter Avalos  * Ensure that there is space to add a new argument type to the type table.
107e0f95098SPeter Avalos  * Expand the table if necessary. Returns 0 on success.
108e0f95098SPeter Avalos  */
109e0f95098SPeter Avalos static inline int
_ensurespace(struct typetable * types)110e0f95098SPeter Avalos _ensurespace(struct typetable *types)
111e0f95098SPeter Avalos {
112e0f95098SPeter Avalos 
113e0f95098SPeter Avalos 	if (types->nextarg >= types->tablesize) {
114e0f95098SPeter Avalos 		if (__grow_type_table(types))
115e0f95098SPeter Avalos 			return (-1);
116e0f95098SPeter Avalos 	}
117e0f95098SPeter Avalos 	if (types->nextarg > types->tablemax)
118e0f95098SPeter Avalos 		types->tablemax = types->nextarg;
119e0f95098SPeter Avalos 	return (0);
120e0f95098SPeter Avalos }
121e0f95098SPeter Avalos 
122e0f95098SPeter Avalos /*
123e0f95098SPeter Avalos  * Add an argument type to the table, expanding if necessary.
124e0f95098SPeter Avalos  * Returns 0 on success.
125e0f95098SPeter Avalos  */
126e0f95098SPeter Avalos static inline int
addtype(struct typetable * types,enum typeid type)127e0f95098SPeter Avalos addtype(struct typetable *types, enum typeid type)
128e0f95098SPeter Avalos {
129e0f95098SPeter Avalos 
130e0f95098SPeter Avalos 	if (_ensurespace(types))
131e0f95098SPeter Avalos 		return (-1);
132e0f95098SPeter Avalos 	types->table[types->nextarg++] = type;
133e0f95098SPeter Avalos 	return (0);
134e0f95098SPeter Avalos }
135e0f95098SPeter Avalos 
136e0f95098SPeter Avalos static inline int
addsarg(struct typetable * types,int flags)137e0f95098SPeter Avalos addsarg(struct typetable *types, int flags)
138e0f95098SPeter Avalos {
139e0f95098SPeter Avalos 
140e0f95098SPeter Avalos 	if (_ensurespace(types))
141e0f95098SPeter Avalos 		return (-1);
142e0f95098SPeter Avalos 	if (flags & INTMAXT)
143e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_INTMAXT;
144e0f95098SPeter Avalos 	else if (flags & SIZET)
145e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_SSIZET;
146e0f95098SPeter Avalos 	else if (flags & PTRDIFFT)
147e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_PTRDIFFT;
148e0f95098SPeter Avalos 	else if (flags & LLONGINT)
149e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_LLONG;
150e0f95098SPeter Avalos 	else if (flags & LONGINT)
151e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_LONG;
152e0f95098SPeter Avalos 	else
153e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_INT;
154e0f95098SPeter Avalos 	return (0);
155e0f95098SPeter Avalos }
156e0f95098SPeter Avalos 
157e0f95098SPeter Avalos static inline int
adduarg(struct typetable * types,int flags)158e0f95098SPeter Avalos adduarg(struct typetable *types, int flags)
159e0f95098SPeter Avalos {
160e0f95098SPeter Avalos 
161e0f95098SPeter Avalos 	if (_ensurespace(types))
162e0f95098SPeter Avalos 		return (-1);
163e0f95098SPeter Avalos 	if (flags & INTMAXT)
164e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_UINTMAXT;
165e0f95098SPeter Avalos 	else if (flags & SIZET)
166e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_SIZET;
167e0f95098SPeter Avalos 	else if (flags & PTRDIFFT)
168e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_SIZET;
169e0f95098SPeter Avalos 	else if (flags & LLONGINT)
170e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_U_LLONG;
171e0f95098SPeter Avalos 	else if (flags & LONGINT)
172e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_U_LONG;
173e0f95098SPeter Avalos 	else
174e0f95098SPeter Avalos 		types->table[types->nextarg++] = T_U_INT;
175e0f95098SPeter Avalos 	return (0);
176e0f95098SPeter Avalos }
177e0f95098SPeter Avalos 
178e0f95098SPeter Avalos /*
179e0f95098SPeter Avalos  * Add * arguments to the type array.
180e0f95098SPeter Avalos  */
181e0f95098SPeter Avalos static inline int
addaster(struct typetable * types,char ** fmtp)182e0f95098SPeter Avalos addaster(struct typetable *types, char **fmtp)
183e0f95098SPeter Avalos {
184e0f95098SPeter Avalos 	char *cp;
185e0f95098SPeter Avalos 	int n2;
186e0f95098SPeter Avalos 
187e0f95098SPeter Avalos 	n2 = 0;
188e0f95098SPeter Avalos 	cp = *fmtp;
189e0f95098SPeter Avalos 	while (is_digit(*cp)) {
190e0f95098SPeter Avalos 		n2 = 10 * n2 + to_digit(*cp);
191e0f95098SPeter Avalos 		cp++;
192e0f95098SPeter Avalos 	}
193e0f95098SPeter Avalos 	if (*cp == '$') {
194e0f95098SPeter Avalos 		int hold = types->nextarg;
195e0f95098SPeter Avalos 		types->nextarg = n2;
196e0f95098SPeter Avalos 		if (addtype(types, T_INT))
197e0f95098SPeter Avalos 			return (-1);
198e0f95098SPeter Avalos 		types->nextarg = hold;
199e0f95098SPeter Avalos 		*fmtp = ++cp;
200e0f95098SPeter Avalos 	} else {
201e0f95098SPeter Avalos 		if (addtype(types, T_INT))
202e0f95098SPeter Avalos 			return (-1);
203e0f95098SPeter Avalos 	}
204e0f95098SPeter Avalos 	return (0);
205e0f95098SPeter Avalos }
206e0f95098SPeter Avalos 
207e0f95098SPeter Avalos static inline int
addwaster(struct typetable * types,wchar_t ** fmtp)208e0f95098SPeter Avalos addwaster(struct typetable *types, wchar_t **fmtp)
209e0f95098SPeter Avalos {
210e0f95098SPeter Avalos 	wchar_t *cp;
211e0f95098SPeter Avalos 	int n2;
212e0f95098SPeter Avalos 
213e0f95098SPeter Avalos 	n2 = 0;
214e0f95098SPeter Avalos 	cp = *fmtp;
215e0f95098SPeter Avalos 	while (is_digit(*cp)) {
216e0f95098SPeter Avalos 		n2 = 10 * n2 + to_digit(*cp);
217e0f95098SPeter Avalos 		cp++;
218e0f95098SPeter Avalos 	}
219e0f95098SPeter Avalos 	if (*cp == '$') {
220e0f95098SPeter Avalos 		int hold = types->nextarg;
221e0f95098SPeter Avalos 		types->nextarg = n2;
222e0f95098SPeter Avalos 		if (addtype(types, T_INT))
223e0f95098SPeter Avalos 			return (-1);
224e0f95098SPeter Avalos 		types->nextarg = hold;
225e0f95098SPeter Avalos 		*fmtp = ++cp;
226e0f95098SPeter Avalos 	} else {
227e0f95098SPeter Avalos 		if (addtype(types, T_INT))
228e0f95098SPeter Avalos 			return (-1);
229e0f95098SPeter Avalos 	}
230e0f95098SPeter Avalos 	return (0);
231e0f95098SPeter Avalos }
232e0f95098SPeter Avalos 
233e0f95098SPeter Avalos /*
234e0f95098SPeter Avalos  * Find all arguments when a positional parameter is encountered.  Returns a
235e0f95098SPeter Avalos  * table, indexed by argument number, of pointers to each arguments.  The
236e0f95098SPeter Avalos  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
237e0f95098SPeter Avalos  * It will be replaces with a malloc-ed one if it overflows.
238e0f95098SPeter Avalos  * Returns 0 on success. On failure, returns nonzero and sets errno.
239e0f95098SPeter Avalos  */
240e0f95098SPeter Avalos int
__find_arguments(const char * fmt0,va_list ap,union arg ** argtable)241e0f95098SPeter Avalos __find_arguments(const char *fmt0, va_list ap, union arg **argtable)
242e0f95098SPeter Avalos {
243e0f95098SPeter Avalos 	char *fmt;		/* format string */
244e0f95098SPeter Avalos 	int ch;			/* character from fmt */
245e0f95098SPeter Avalos 	int n;			/* handy integer (short term usage) */
246e0f95098SPeter Avalos 	int error;
247e0f95098SPeter Avalos 	int flags;		/* flags as above */
248e0f95098SPeter Avalos 	struct typetable types;	/* table of types */
249e0f95098SPeter Avalos 
250e0f95098SPeter Avalos 	fmt = __DECONST(char *, fmt0);
251e0f95098SPeter Avalos 	inittypes(&types);
252e0f95098SPeter Avalos 	error = 0;
253e0f95098SPeter Avalos 
254e0f95098SPeter Avalos 	/*
255e0f95098SPeter Avalos 	 * Scan the format for conversions (`%' character).
256e0f95098SPeter Avalos 	 */
257e0f95098SPeter Avalos 	for (;;) {
258e0f95098SPeter Avalos 		while ((ch = *fmt) != '\0' && ch != '%')
259e0f95098SPeter Avalos 			fmt++;
260e0f95098SPeter Avalos 		if (ch == '\0')
261e0f95098SPeter Avalos 			goto done;
262e0f95098SPeter Avalos 		fmt++;		/* skip over '%' */
263e0f95098SPeter Avalos 
264e0f95098SPeter Avalos 		flags = 0;
265e0f95098SPeter Avalos 
266e0f95098SPeter Avalos rflag:		ch = *fmt++;
267e0f95098SPeter Avalos reswitch:	switch (ch) {
268e0f95098SPeter Avalos 		case ' ':
269e0f95098SPeter Avalos 		case '#':
270e0f95098SPeter Avalos 			goto rflag;
271e0f95098SPeter Avalos 		case '*':
272e0f95098SPeter Avalos 			if ((error = addaster(&types, &fmt)))
273e0f95098SPeter Avalos 				goto error;
274e0f95098SPeter Avalos 			goto rflag;
275e0f95098SPeter Avalos 		case '-':
276e0f95098SPeter Avalos 		case '+':
277e0f95098SPeter Avalos 		case '\'':
278e0f95098SPeter Avalos 			goto rflag;
279e0f95098SPeter Avalos 		case '.':
280e0f95098SPeter Avalos 			if ((ch = *fmt++) == '*') {
281e0f95098SPeter Avalos 				if ((error = addaster(&types, &fmt)))
282e0f95098SPeter Avalos 					goto error;
283e0f95098SPeter Avalos 				goto rflag;
284e0f95098SPeter Avalos 			}
285e0f95098SPeter Avalos 			while (is_digit(ch)) {
286e0f95098SPeter Avalos 				ch = *fmt++;
287e0f95098SPeter Avalos 			}
288e0f95098SPeter Avalos 			goto reswitch;
289e0f95098SPeter Avalos 		case '0':
290e0f95098SPeter Avalos 			goto rflag;
291e0f95098SPeter Avalos 		case '1': case '2': case '3': case '4':
292e0f95098SPeter Avalos 		case '5': case '6': case '7': case '8': case '9':
293e0f95098SPeter Avalos 			n = 0;
294e0f95098SPeter Avalos 			do {
295e0f95098SPeter Avalos 				n = 10 * n + to_digit(ch);
296e0f95098SPeter Avalos 				ch = *fmt++;
297e0f95098SPeter Avalos 			} while (is_digit(ch));
298e0f95098SPeter Avalos 			if (ch == '$') {
299e0f95098SPeter Avalos 				types.nextarg = n;
300e0f95098SPeter Avalos 				goto rflag;
301e0f95098SPeter Avalos 			}
302e0f95098SPeter Avalos 			goto reswitch;
303e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
304e0f95098SPeter Avalos 		case 'L':
305e0f95098SPeter Avalos 			flags |= LONGDBL;
306e0f95098SPeter Avalos 			goto rflag;
307e0f95098SPeter Avalos #endif
308e0f95098SPeter Avalos 		case 'h':
309e0f95098SPeter Avalos 			if (flags & SHORTINT) {
310e0f95098SPeter Avalos 				flags &= ~SHORTINT;
311e0f95098SPeter Avalos 				flags |= CHARINT;
312e0f95098SPeter Avalos 			} else
313e0f95098SPeter Avalos 				flags |= SHORTINT;
314e0f95098SPeter Avalos 			goto rflag;
315e0f95098SPeter Avalos 		case 'j':
316e0f95098SPeter Avalos 			flags |= INTMAXT;
317e0f95098SPeter Avalos 			goto rflag;
318e0f95098SPeter Avalos 		case 'l':
319e0f95098SPeter Avalos 			if (flags & LONGINT) {
320e0f95098SPeter Avalos 				flags &= ~LONGINT;
321e0f95098SPeter Avalos 				flags |= LLONGINT;
322e0f95098SPeter Avalos 			} else
323e0f95098SPeter Avalos 				flags |= LONGINT;
324e0f95098SPeter Avalos 			goto rflag;
325e0f95098SPeter Avalos 		case 'q':
326e0f95098SPeter Avalos 			flags |= LLONGINT;	/* not necessarily */
327e0f95098SPeter Avalos 			goto rflag;
328e0f95098SPeter Avalos 		case 't':
329e0f95098SPeter Avalos 			flags |= PTRDIFFT;
330e0f95098SPeter Avalos 			goto rflag;
331e0f95098SPeter Avalos 		case 'z':
332e0f95098SPeter Avalos 			flags |= SIZET;
333e0f95098SPeter Avalos 			goto rflag;
334e0f95098SPeter Avalos 		case 'C':
335e0f95098SPeter Avalos 			flags |= LONGINT;
336e0f95098SPeter Avalos 			/*FALLTHROUGH*/
337e0f95098SPeter Avalos 		case 'c':
338e0f95098SPeter Avalos 			error = addtype(&types,
339e0f95098SPeter Avalos 					(flags & LONGINT) ? T_WINT : T_INT);
340e0f95098SPeter Avalos 			if (error)
341e0f95098SPeter Avalos 				goto error;
342e0f95098SPeter Avalos 			break;
343e0f95098SPeter Avalos 		case 'D':
344e0f95098SPeter Avalos 			flags |= LONGINT;
345e0f95098SPeter Avalos 			/*FALLTHROUGH*/
346e0f95098SPeter Avalos 		case 'd':
347e0f95098SPeter Avalos 		case 'i':
348e0f95098SPeter Avalos 			if ((error = addsarg(&types, flags)))
349e0f95098SPeter Avalos 				goto error;
350e0f95098SPeter Avalos 			break;
351e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
352e0f95098SPeter Avalos 		case 'a':
353e0f95098SPeter Avalos 		case 'A':
354e0f95098SPeter Avalos 		case 'e':
355e0f95098SPeter Avalos 		case 'E':
356e0f95098SPeter Avalos 		case 'f':
357e0f95098SPeter Avalos 		case 'g':
358e0f95098SPeter Avalos 		case 'G':
359e0f95098SPeter Avalos 			error = addtype(&types,
360e0f95098SPeter Avalos 			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
361e0f95098SPeter Avalos 			if (error)
362e0f95098SPeter Avalos 				goto error;
363e0f95098SPeter Avalos 			break;
364e0f95098SPeter Avalos #endif /* !NO_FLOATING_POINT */
365e0f95098SPeter Avalos 		case 'n':
366e0f95098SPeter Avalos 			if (flags & INTMAXT)
367e0f95098SPeter Avalos 				error = addtype(&types, TP_INTMAXT);
368e0f95098SPeter Avalos 			else if (flags & PTRDIFFT)
369e0f95098SPeter Avalos 				error = addtype(&types, TP_PTRDIFFT);
370e0f95098SPeter Avalos 			else if (flags & SIZET)
371e0f95098SPeter Avalos 				error = addtype(&types, TP_SSIZET);
372e0f95098SPeter Avalos 			else if (flags & LLONGINT)
373e0f95098SPeter Avalos 				error = addtype(&types, TP_LLONG);
374e0f95098SPeter Avalos 			else if (flags & LONGINT)
375e0f95098SPeter Avalos 				error = addtype(&types, TP_LONG);
376e0f95098SPeter Avalos 			else if (flags & SHORTINT)
377e0f95098SPeter Avalos 				error = addtype(&types, TP_SHORT);
378e0f95098SPeter Avalos 			else if (flags & CHARINT)
379e0f95098SPeter Avalos 				error = addtype(&types, TP_SCHAR);
380e0f95098SPeter Avalos 			else
381e0f95098SPeter Avalos 				error = addtype(&types, TP_INT);
382e0f95098SPeter Avalos 			if (error)
383e0f95098SPeter Avalos 				goto error;
384e0f95098SPeter Avalos 			continue;	/* no output */
385e0f95098SPeter Avalos 		case 'O':
386e0f95098SPeter Avalos 			flags |= LONGINT;
387e0f95098SPeter Avalos 			/*FALLTHROUGH*/
388e0f95098SPeter Avalos 		case 'o':
389e0f95098SPeter Avalos 			if ((error = adduarg(&types, flags)))
390e0f95098SPeter Avalos 				goto error;
391e0f95098SPeter Avalos 			break;
392e0f95098SPeter Avalos 		case 'p':
393e0f95098SPeter Avalos 			if ((error = addtype(&types, TP_VOID)))
394e0f95098SPeter Avalos 				goto error;
395e0f95098SPeter Avalos 			break;
396e0f95098SPeter Avalos 		case 'S':
397e0f95098SPeter Avalos 			flags |= LONGINT;
398e0f95098SPeter Avalos 			/*FALLTHROUGH*/
399e0f95098SPeter Avalos 		case 's':
400e0f95098SPeter Avalos 			error = addtype(&types,
401e0f95098SPeter Avalos 					(flags & LONGINT) ? TP_WCHAR : TP_CHAR);
402e0f95098SPeter Avalos 			if (error)
403e0f95098SPeter Avalos 				goto error;
404e0f95098SPeter Avalos 			break;
405e0f95098SPeter Avalos 		case 'U':
406e0f95098SPeter Avalos 			flags |= LONGINT;
407e0f95098SPeter Avalos 			/*FALLTHROUGH*/
408e0f95098SPeter Avalos 		case 'u':
409e0f95098SPeter Avalos 		case 'X':
410e0f95098SPeter Avalos 		case 'x':
411e0f95098SPeter Avalos 			if ((error = adduarg(&types, flags)))
412e0f95098SPeter Avalos 				goto error;
413e0f95098SPeter Avalos 			break;
414e0f95098SPeter Avalos 		default:	/* "%?" prints ?, unless ? is NUL */
415e0f95098SPeter Avalos 			if (ch == '\0')
416e0f95098SPeter Avalos 				goto done;
417e0f95098SPeter Avalos 			break;
418e0f95098SPeter Avalos 		}
419e0f95098SPeter Avalos 	}
420e0f95098SPeter Avalos done:
421e0f95098SPeter Avalos 	build_arg_table(&types, ap, argtable);
422e0f95098SPeter Avalos error:
423e0f95098SPeter Avalos 	freetypes(&types);
424e0f95098SPeter Avalos 	return (error || *argtable == NULL);
425e0f95098SPeter Avalos }
426e0f95098SPeter Avalos 
427e0f95098SPeter Avalos /* wchar version of __find_arguments. */
428e0f95098SPeter Avalos int
__find_warguments(const wchar_t * fmt0,va_list ap,union arg ** argtable)429e0f95098SPeter Avalos __find_warguments(const wchar_t *fmt0, va_list ap, union arg **argtable)
430e0f95098SPeter Avalos {
431e0f95098SPeter Avalos 	wchar_t *fmt;		/* format string */
432e0f95098SPeter Avalos 	wchar_t ch;		/* character from fmt */
433e0f95098SPeter Avalos 	int n;			/* handy integer (short term usage) */
434e0f95098SPeter Avalos 	int error;
435e0f95098SPeter Avalos 	int flags;		/* flags as above */
436e0f95098SPeter Avalos 	struct typetable types;	/* table of types */
437e0f95098SPeter Avalos 
438e0f95098SPeter Avalos 	fmt = __DECONST(wchar_t *, fmt0);
439e0f95098SPeter Avalos 	inittypes(&types);
440e0f95098SPeter Avalos 	error = 0;
441e0f95098SPeter Avalos 
442e0f95098SPeter Avalos 	/*
443e0f95098SPeter Avalos 	 * Scan the format for conversions (`%' character).
444e0f95098SPeter Avalos 	 */
445e0f95098SPeter Avalos 	for (;;) {
446e0f95098SPeter Avalos 		while ((ch = *fmt) != '\0' && ch != '%')
447e0f95098SPeter Avalos 			fmt++;
448e0f95098SPeter Avalos 		if (ch == '\0')
449e0f95098SPeter Avalos 			goto done;
450e0f95098SPeter Avalos 		fmt++;		/* skip over '%' */
451e0f95098SPeter Avalos 
452e0f95098SPeter Avalos 		flags = 0;
453e0f95098SPeter Avalos 
454e0f95098SPeter Avalos rflag:		ch = *fmt++;
455e0f95098SPeter Avalos reswitch:	switch (ch) {
456e0f95098SPeter Avalos 		case ' ':
457e0f95098SPeter Avalos 		case '#':
458e0f95098SPeter Avalos 			goto rflag;
459e0f95098SPeter Avalos 		case '*':
460e0f95098SPeter Avalos 			if ((error = addwaster(&types, &fmt)))
461e0f95098SPeter Avalos 				goto error;
462e0f95098SPeter Avalos 			goto rflag;
463e0f95098SPeter Avalos 		case '-':
464e0f95098SPeter Avalos 		case '+':
465e0f95098SPeter Avalos 		case '\'':
466e0f95098SPeter Avalos 			goto rflag;
467e0f95098SPeter Avalos 		case '.':
468e0f95098SPeter Avalos 			if ((ch = *fmt++) == '*') {
469e0f95098SPeter Avalos 				if ((error = addwaster(&types, &fmt)))
470e0f95098SPeter Avalos 					goto error;
471e0f95098SPeter Avalos 				goto rflag;
472e0f95098SPeter Avalos 			}
473e0f95098SPeter Avalos 			while (is_digit(ch)) {
474e0f95098SPeter Avalos 				ch = *fmt++;
475e0f95098SPeter Avalos 			}
476e0f95098SPeter Avalos 			goto reswitch;
477e0f95098SPeter Avalos 		case '0':
478e0f95098SPeter Avalos 			goto rflag;
479e0f95098SPeter Avalos 		case '1': case '2': case '3': case '4':
480e0f95098SPeter Avalos 		case '5': case '6': case '7': case '8': case '9':
481e0f95098SPeter Avalos 			n = 0;
482e0f95098SPeter Avalos 			do {
483e0f95098SPeter Avalos 				n = 10 * n + to_digit(ch);
484e0f95098SPeter Avalos 				ch = *fmt++;
485e0f95098SPeter Avalos 			} while (is_digit(ch));
486e0f95098SPeter Avalos 			if (ch == '$') {
487e0f95098SPeter Avalos 				types.nextarg = n;
488e0f95098SPeter Avalos 				goto rflag;
489e0f95098SPeter Avalos 			}
490e0f95098SPeter Avalos 			goto reswitch;
491e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
492e0f95098SPeter Avalos 		case 'L':
493e0f95098SPeter Avalos 			flags |= LONGDBL;
494e0f95098SPeter Avalos 			goto rflag;
495e0f95098SPeter Avalos #endif
496e0f95098SPeter Avalos 		case 'h':
497e0f95098SPeter Avalos 			if (flags & SHORTINT) {
498e0f95098SPeter Avalos 				flags &= ~SHORTINT;
499e0f95098SPeter Avalos 				flags |= CHARINT;
500e0f95098SPeter Avalos 			} else
501e0f95098SPeter Avalos 				flags |= SHORTINT;
502e0f95098SPeter Avalos 			goto rflag;
503e0f95098SPeter Avalos 		case 'j':
504e0f95098SPeter Avalos 			flags |= INTMAXT;
505e0f95098SPeter Avalos 			goto rflag;
506e0f95098SPeter Avalos 		case 'l':
507e0f95098SPeter Avalos 			if (flags & LONGINT) {
508e0f95098SPeter Avalos 				flags &= ~LONGINT;
509e0f95098SPeter Avalos 				flags |= LLONGINT;
510e0f95098SPeter Avalos 			} else
511e0f95098SPeter Avalos 				flags |= LONGINT;
512e0f95098SPeter Avalos 			goto rflag;
513e0f95098SPeter Avalos 		case 'q':
514e0f95098SPeter Avalos 			flags |= LLONGINT;	/* not necessarily */
515e0f95098SPeter Avalos 			goto rflag;
516e0f95098SPeter Avalos 		case 't':
517e0f95098SPeter Avalos 			flags |= PTRDIFFT;
518e0f95098SPeter Avalos 			goto rflag;
519e0f95098SPeter Avalos 		case 'z':
520e0f95098SPeter Avalos 			flags |= SIZET;
521e0f95098SPeter Avalos 			goto rflag;
522e0f95098SPeter Avalos 		case 'C':
523e0f95098SPeter Avalos 			flags |= LONGINT;
524e0f95098SPeter Avalos 			/*FALLTHROUGH*/
525e0f95098SPeter Avalos 		case 'c':
526e0f95098SPeter Avalos 			error = addtype(&types,
527e0f95098SPeter Avalos 					(flags & LONGINT) ? T_WINT : T_INT);
528e0f95098SPeter Avalos 			if (error)
529e0f95098SPeter Avalos 				goto error;
530e0f95098SPeter Avalos 			break;
531e0f95098SPeter Avalos 		case 'D':
532e0f95098SPeter Avalos 			flags |= LONGINT;
533e0f95098SPeter Avalos 			/*FALLTHROUGH*/
534e0f95098SPeter Avalos 		case 'd':
535e0f95098SPeter Avalos 		case 'i':
536e0f95098SPeter Avalos 			if ((error = addsarg(&types, flags)))
537e0f95098SPeter Avalos 				goto error;
538e0f95098SPeter Avalos 			break;
539e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
540e0f95098SPeter Avalos 		case 'a':
541e0f95098SPeter Avalos 		case 'A':
542e0f95098SPeter Avalos 		case 'e':
543e0f95098SPeter Avalos 		case 'E':
544e0f95098SPeter Avalos 		case 'f':
545e0f95098SPeter Avalos 		case 'g':
546e0f95098SPeter Avalos 		case 'G':
547e0f95098SPeter Avalos 			error = addtype(&types,
548e0f95098SPeter Avalos 			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
549e0f95098SPeter Avalos 			if (error)
550e0f95098SPeter Avalos 				goto error;
551e0f95098SPeter Avalos 			break;
552e0f95098SPeter Avalos #endif /* !NO_FLOATING_POINT */
553e0f95098SPeter Avalos 		case 'n':
554e0f95098SPeter Avalos 			if (flags & INTMAXT)
555e0f95098SPeter Avalos 				error = addtype(&types, TP_INTMAXT);
556e0f95098SPeter Avalos 			else if (flags & PTRDIFFT)
557e0f95098SPeter Avalos 				error = addtype(&types, TP_PTRDIFFT);
558e0f95098SPeter Avalos 			else if (flags & SIZET)
559e0f95098SPeter Avalos 				error = addtype(&types, TP_SSIZET);
560e0f95098SPeter Avalos 			else if (flags & LLONGINT)
561e0f95098SPeter Avalos 				error = addtype(&types, TP_LLONG);
562e0f95098SPeter Avalos 			else if (flags & LONGINT)
563e0f95098SPeter Avalos 				error = addtype(&types, TP_LONG);
564e0f95098SPeter Avalos 			else if (flags & SHORTINT)
565e0f95098SPeter Avalos 				error = addtype(&types, TP_SHORT);
566e0f95098SPeter Avalos 			else if (flags & CHARINT)
567e0f95098SPeter Avalos 				error = addtype(&types, TP_SCHAR);
568e0f95098SPeter Avalos 			else
569e0f95098SPeter Avalos 				error = addtype(&types, TP_INT);
570e0f95098SPeter Avalos 			if (error)
571e0f95098SPeter Avalos 				goto error;
572e0f95098SPeter Avalos 			continue;	/* no output */
573e0f95098SPeter Avalos 		case 'O':
574e0f95098SPeter Avalos 			flags |= LONGINT;
575e0f95098SPeter Avalos 			/*FALLTHROUGH*/
576e0f95098SPeter Avalos 		case 'o':
577e0f95098SPeter Avalos 			if ((error = adduarg(&types, flags)))
578e0f95098SPeter Avalos 				goto error;
579e0f95098SPeter Avalos 			break;
580e0f95098SPeter Avalos 		case 'p':
581e0f95098SPeter Avalos 			if ((error = addtype(&types, TP_VOID)))
582e0f95098SPeter Avalos 				goto error;
583e0f95098SPeter Avalos 			break;
584e0f95098SPeter Avalos 		case 'S':
585e0f95098SPeter Avalos 			flags |= LONGINT;
586e0f95098SPeter Avalos 			/*FALLTHROUGH*/
587e0f95098SPeter Avalos 		case 's':
588e0f95098SPeter Avalos 			error = addtype(&types,
589e0f95098SPeter Avalos 			    (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
590e0f95098SPeter Avalos 			if (error)
591e0f95098SPeter Avalos 				goto error;
592e0f95098SPeter Avalos 			break;
593e0f95098SPeter Avalos 		case 'U':
594e0f95098SPeter Avalos 			flags |= LONGINT;
595e0f95098SPeter Avalos 			/*FALLTHROUGH*/
596e0f95098SPeter Avalos 		case 'u':
597e0f95098SPeter Avalos 		case 'X':
598e0f95098SPeter Avalos 		case 'x':
599e0f95098SPeter Avalos 			if ((error = adduarg(&types, flags)))
600e0f95098SPeter Avalos 				goto error;
601e0f95098SPeter Avalos 			break;
602e0f95098SPeter Avalos 		default:	/* "%?" prints ?, unless ? is NUL */
603e0f95098SPeter Avalos 			if (ch == '\0')
604e0f95098SPeter Avalos 				goto done;
605e0f95098SPeter Avalos 			break;
606e0f95098SPeter Avalos 		}
607e0f95098SPeter Avalos 	}
608e0f95098SPeter Avalos done:
609e0f95098SPeter Avalos 	build_arg_table(&types, ap, argtable);
610e0f95098SPeter Avalos error:
611e0f95098SPeter Avalos 	freetypes(&types);
612e0f95098SPeter Avalos 	return (error || *argtable == NULL);
613e0f95098SPeter Avalos }
614e0f95098SPeter Avalos 
615e0f95098SPeter Avalos /*
616e0f95098SPeter Avalos  * Increase the size of the type table. Returns 0 on success.
617e0f95098SPeter Avalos  */
618e0f95098SPeter Avalos static int
__grow_type_table(struct typetable * types)619e0f95098SPeter Avalos __grow_type_table(struct typetable *types)
620e0f95098SPeter Avalos {
621e0f95098SPeter Avalos 	enum typeid *const oldtable = types->table;
622e0f95098SPeter Avalos 	const int oldsize = types->tablesize;
623e0f95098SPeter Avalos 	enum typeid *newtable;
624e0f95098SPeter Avalos 	int n, newsize = oldsize * 2;
625e0f95098SPeter Avalos 
626e0f95098SPeter Avalos 	if (newsize < types->nextarg + 1)
627e0f95098SPeter Avalos 		newsize = types->nextarg + 1;
628e0f95098SPeter Avalos 	if (oldsize == STATIC_ARG_TBL_SIZE) {
629e0f95098SPeter Avalos 		if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
630e0f95098SPeter Avalos 			return (-1);
631e0f95098SPeter Avalos 		bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
632e0f95098SPeter Avalos 	} else {
633e0f95098SPeter Avalos 		newtable = realloc(oldtable, newsize * sizeof(enum typeid));
634e0f95098SPeter Avalos 		if (newtable == NULL)
635e0f95098SPeter Avalos 			return (-1);
636e0f95098SPeter Avalos 	}
637e0f95098SPeter Avalos 	for (n = oldsize; n < newsize; n++)
638e0f95098SPeter Avalos 		newtable[n] = T_UNUSED;
639e0f95098SPeter Avalos 
640e0f95098SPeter Avalos 	types->table = newtable;
641e0f95098SPeter Avalos 	types->tablesize = newsize;
642e0f95098SPeter Avalos 
643e0f95098SPeter Avalos 	return (0);
644e0f95098SPeter Avalos }
645e0f95098SPeter Avalos 
646e0f95098SPeter Avalos /*
647e0f95098SPeter Avalos  * Build the argument table from the completed type table.
648e0f95098SPeter Avalos  * On malloc failure, *argtable is set to NULL.
649e0f95098SPeter Avalos  */
650e0f95098SPeter Avalos static void
build_arg_table(struct typetable * types,va_list ap,union arg ** argtable)651e0f95098SPeter Avalos build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
652e0f95098SPeter Avalos {
653e0f95098SPeter Avalos 	int n;
654e0f95098SPeter Avalos 
655e0f95098SPeter Avalos 	if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
656e0f95098SPeter Avalos 		*argtable = (union arg *)
657e0f95098SPeter Avalos 		    malloc (sizeof (union arg) * (types->tablemax + 1));
658e0f95098SPeter Avalos 		if (*argtable == NULL)
659e0f95098SPeter Avalos 			return;
660e0f95098SPeter Avalos 	}
661e0f95098SPeter Avalos 
662e0f95098SPeter Avalos 	(*argtable) [0].intarg = 0;
663e0f95098SPeter Avalos 	for (n = 1; n <= types->tablemax; n++) {
664e0f95098SPeter Avalos 		switch (types->table[n]) {
665e0f95098SPeter Avalos 		    case T_UNUSED: /* whoops! */
666e0f95098SPeter Avalos 			(*argtable) [n].intarg = va_arg(ap, int);
667e0f95098SPeter Avalos 			break;
668e0f95098SPeter Avalos 		    case TP_SCHAR:
669e0f95098SPeter Avalos 			(*argtable) [n].pschararg = va_arg(ap, signed char *);
670e0f95098SPeter Avalos 			break;
671e0f95098SPeter Avalos 		    case TP_SHORT:
672e0f95098SPeter Avalos 			(*argtable) [n].pshortarg = va_arg(ap, short *);
673e0f95098SPeter Avalos 			break;
674e0f95098SPeter Avalos 		    case T_INT:
675e0f95098SPeter Avalos 			(*argtable) [n].intarg = va_arg(ap, int);
676e0f95098SPeter Avalos 			break;
677e0f95098SPeter Avalos 		    case T_U_INT:
678e0f95098SPeter Avalos 			(*argtable) [n].uintarg = va_arg(ap, unsigned int);
679e0f95098SPeter Avalos 			break;
680e0f95098SPeter Avalos 		    case TP_INT:
681e0f95098SPeter Avalos 			(*argtable) [n].pintarg = va_arg(ap, int *);
682e0f95098SPeter Avalos 			break;
683e0f95098SPeter Avalos 		    case T_LONG:
684e0f95098SPeter Avalos 			(*argtable) [n].longarg = va_arg(ap, long);
685e0f95098SPeter Avalos 			break;
686e0f95098SPeter Avalos 		    case T_U_LONG:
687e0f95098SPeter Avalos 			(*argtable) [n].ulongarg = va_arg(ap, unsigned long);
688e0f95098SPeter Avalos 			break;
689e0f95098SPeter Avalos 		    case TP_LONG:
690e0f95098SPeter Avalos 			(*argtable) [n].plongarg = va_arg(ap, long *);
691e0f95098SPeter Avalos 			break;
692e0f95098SPeter Avalos 		    case T_LLONG:
693e0f95098SPeter Avalos 			(*argtable) [n].longlongarg = va_arg(ap, long long);
694e0f95098SPeter Avalos 			break;
695e0f95098SPeter Avalos 		    case T_U_LLONG:
696e0f95098SPeter Avalos 			(*argtable) [n].ulonglongarg = va_arg(ap, unsigned long long);
697e0f95098SPeter Avalos 			break;
698e0f95098SPeter Avalos 		    case TP_LLONG:
699e0f95098SPeter Avalos 			(*argtable) [n].plonglongarg = va_arg(ap, long long *);
700e0f95098SPeter Avalos 			break;
701e0f95098SPeter Avalos 		    case T_PTRDIFFT:
702e0f95098SPeter Avalos 			(*argtable) [n].ptrdiffarg = va_arg(ap, ptrdiff_t);
703e0f95098SPeter Avalos 			break;
704e0f95098SPeter Avalos 		    case TP_PTRDIFFT:
705e0f95098SPeter Avalos 			(*argtable) [n].pptrdiffarg = va_arg(ap, ptrdiff_t *);
706e0f95098SPeter Avalos 			break;
707e0f95098SPeter Avalos 		    case T_SIZET:
708e0f95098SPeter Avalos 			(*argtable) [n].sizearg = va_arg(ap, size_t);
709e0f95098SPeter Avalos 			break;
710e0f95098SPeter Avalos 		    case T_SSIZET:
711e0f95098SPeter Avalos 			(*argtable) [n].sizearg = va_arg(ap, ssize_t);
712e0f95098SPeter Avalos 			break;
713e0f95098SPeter Avalos 		    case TP_SSIZET:
714e0f95098SPeter Avalos 			(*argtable) [n].pssizearg = va_arg(ap, ssize_t *);
715e0f95098SPeter Avalos 			break;
716e0f95098SPeter Avalos 		    case T_INTMAXT:
717e0f95098SPeter Avalos 			(*argtable) [n].intmaxarg = va_arg(ap, intmax_t);
718e0f95098SPeter Avalos 			break;
719e0f95098SPeter Avalos 		    case T_UINTMAXT:
720e0f95098SPeter Avalos 			(*argtable) [n].uintmaxarg = va_arg(ap, uintmax_t);
721e0f95098SPeter Avalos 			break;
722e0f95098SPeter Avalos 		    case TP_INTMAXT:
723e0f95098SPeter Avalos 			(*argtable) [n].pintmaxarg = va_arg(ap, intmax_t *);
724e0f95098SPeter Avalos 			break;
725e0f95098SPeter Avalos 		    case T_DOUBLE:
726e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
727e0f95098SPeter Avalos 			(*argtable) [n].doublearg = va_arg(ap, double);
728e0f95098SPeter Avalos #endif
729e0f95098SPeter Avalos 			break;
730e0f95098SPeter Avalos 		    case T_LONG_DOUBLE:
731e0f95098SPeter Avalos #ifndef NO_FLOATING_POINT
732e0f95098SPeter Avalos 			(*argtable) [n].longdoublearg = va_arg(ap, long double);
733e0f95098SPeter Avalos #endif
734e0f95098SPeter Avalos 			break;
735e0f95098SPeter Avalos 		    case TP_CHAR:
736e0f95098SPeter Avalos 			(*argtable) [n].pchararg = va_arg(ap, char *);
737e0f95098SPeter Avalos 			break;
738e0f95098SPeter Avalos 		    case TP_VOID:
739e0f95098SPeter Avalos 			(*argtable) [n].pvoidarg = va_arg(ap, void *);
740e0f95098SPeter Avalos 			break;
741e0f95098SPeter Avalos 		    case T_WINT:
742e0f95098SPeter Avalos 			(*argtable) [n].wintarg = va_arg(ap, wint_t);
743e0f95098SPeter Avalos 			break;
744e0f95098SPeter Avalos 		    case TP_WCHAR:
745e0f95098SPeter Avalos 			(*argtable) [n].pwchararg = va_arg(ap, wchar_t *);
746e0f95098SPeter Avalos 			break;
747e0f95098SPeter Avalos 		}
748e0f95098SPeter Avalos 	}
749e0f95098SPeter Avalos }
750