11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1990, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Chris Torek.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
16249808Semaste * 3. Neither the name of the University nor the names of its contributors
171573Srgrimes *    may be used to endorse or promote products derived from this software
181573Srgrimes *    without specific prior written permission.
191573Srgrimes *
201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301573Srgrimes * SUCH DAMAGE.
311573Srgrimes */
321573Srgrimes
331573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
341573Srgrimesstatic char sccsid[] = "@(#)vfprintf.c	8.1 (Berkeley) 6/4/93";
351573Srgrimes#endif /* LIBC_SCCS and not lint */
3692986Sobrien#include <sys/cdefs.h>
3792986Sobrien__FBSDID("$FreeBSD$");
381573Srgrimes
391573Srgrimes/*
40180104Sdas * This is the code responsible for handling positional arguments
41180104Sdas * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
421573Srgrimes */
431573Srgrimes
4471579Sdeischen#include "namespace.h"
451573Srgrimes#include <sys/types.h>
461573Srgrimes
47180106Sdas#include <stdarg.h>
4887113Sfenner#include <stddef.h>
4987113Sfenner#include <stdint.h>
501573Srgrimes#include <stdio.h>
511573Srgrimes#include <stdlib.h>
521573Srgrimes#include <string.h>
53103633Stjr#include <wchar.h>
541573Srgrimes
5571579Sdeischen#include "un-namespace.h"
56180104Sdas#include "printflocal.h"
571573Srgrimes
5887113Sfenner/*
5987113Sfenner * Type ids for argument type table.
6087113Sfenner */
6187113Sfennerenum typeid {
6287113Sfenner	T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
6387113Sfenner	T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
64189268Sdas	T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
6587113Sfenner	T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
66103633Stjr	T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
6787113Sfenner};
6887113Sfenner
69180102Sdas/* An expandable array of types. */
70180102Sdasstruct typetable {
71180102Sdas	enum typeid *table; /* table of types */
72180102Sdas	enum typeid stattable[STATIC_ARG_TBL_SIZE];
73180102Sdas	int tablesize;		/* current size of type table */
74180102Sdas	int tablemax;		/* largest used index in table */
75180102Sdas	int nextarg;		/* 1-based argument index */
76180102Sdas};
77180102Sdas
78180106Sdasstatic int	__grow_type_table(struct typetable *);
79180105Sdasstatic void	build_arg_table (struct typetable *, va_list, union arg **);
8016586Sjraynard
811573Srgrimes/*
82180104Sdas * Initialize a struct typetable.
831573Srgrimes */
84180104Sdasstatic inline void
85180104Sdasinittypes(struct typetable *types)
861573Srgrimes{
87180104Sdas	int n;
881573Srgrimes
89180104Sdas	types->table = types->stattable;
90180104Sdas	types->tablesize = STATIC_ARG_TBL_SIZE;
91180104Sdas	types->tablemax = 0;
92180104Sdas	types->nextarg = 1;
93180104Sdas	for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
94180104Sdas		types->table[n] = T_UNUSED;
951573Srgrimes}
961573Srgrimes
971573Srgrimes/*
98180104Sdas * struct typetable destructor.
99180104Sdas */
100180104Sdasstatic inline void
101180104Sdasfreetypes(struct typetable *types)
1021573Srgrimes{
1031573Srgrimes
104180104Sdas	if (types->table != types->stattable)
105180104Sdas		free (types->table);
1061573Srgrimes}
1071573Srgrimes
1081573Srgrimes/*
109180106Sdas * Ensure that there is space to add a new argument type to the type table.
110180106Sdas * Expand the table if necessary. Returns 0 on success.
111180106Sdas */
112180106Sdasstatic inline int
113180106Sdas_ensurespace(struct typetable *types)
114180106Sdas{
115180106Sdas
116180106Sdas	if (types->nextarg >= types->tablesize) {
117180106Sdas		if (__grow_type_table(types))
118180106Sdas			return (-1);
119180106Sdas	}
120180106Sdas	if (types->nextarg > types->tablemax)
121180106Sdas		types->tablemax = types->nextarg;
122180106Sdas	return (0);
123180106Sdas}
124180106Sdas
125180106Sdas/*
126180104Sdas * Add an argument type to the table, expanding if necessary.
127180106Sdas * Returns 0 on success.
1281573Srgrimes */
129180106Sdasstatic inline int
130180104Sdasaddtype(struct typetable *types, enum typeid type)
1311573Srgrimes{
1321573Srgrimes
133180107Sdas	if (_ensurespace(types))
134180107Sdas		return (-1);
135180104Sdas	types->table[types->nextarg++] = type;
136180106Sdas	return (0);
137180104Sdas}
1381573Srgrimes
139180106Sdasstatic inline int
140180104Sdasaddsarg(struct typetable *types, int flags)
141180104Sdas{
1421573Srgrimes
143180106Sdas	if (_ensurespace(types))
144180106Sdas		return (-1);
145180104Sdas	if (flags & INTMAXT)
146180106Sdas		types->table[types->nextarg++] = T_INTMAXT;
147180104Sdas	else if (flags & SIZET)
148189131Sdas		types->table[types->nextarg++] = T_SSIZET;
149180104Sdas	else if (flags & PTRDIFFT)
150180106Sdas		types->table[types->nextarg++] = T_PTRDIFFT;
151180104Sdas	else if (flags & LLONGINT)
152180106Sdas		types->table[types->nextarg++] = T_LLONG;
153180104Sdas	else if (flags & LONGINT)
154180106Sdas		types->table[types->nextarg++] = T_LONG;
155180104Sdas	else
156180106Sdas		types->table[types->nextarg++] = T_INT;
157180106Sdas	return (0);
1581573Srgrimes}
1591573Srgrimes
160180106Sdasstatic inline int
161180104Sdasadduarg(struct typetable *types, int flags)
1621573Srgrimes{
1631573Srgrimes
164180106Sdas	if (_ensurespace(types))
165180106Sdas		return (-1);
166180104Sdas	if (flags & INTMAXT)
167180106Sdas		types->table[types->nextarg++] = T_UINTMAXT;
168180104Sdas	else if (flags & SIZET)
169180106Sdas		types->table[types->nextarg++] = T_SIZET;
170180104Sdas	else if (flags & PTRDIFFT)
171189131Sdas		types->table[types->nextarg++] = T_SIZET;
172180104Sdas	else if (flags & LLONGINT)
173180106Sdas		types->table[types->nextarg++] = T_U_LLONG;
174180104Sdas	else if (flags & LONGINT)
175180106Sdas		types->table[types->nextarg++] = T_U_LONG;
176180104Sdas	else
177180106Sdas		types->table[types->nextarg++] = T_U_INT;
178180106Sdas	return (0);
1791573Srgrimes}
1801573Srgrimes
18171579Sdeischen/*
182180104Sdas * Add * arguments to the type array.
183103633Stjr */
184180106Sdasstatic inline int
185180104Sdasaddaster(struct typetable *types, char **fmtp)
186103633Stjr{
187180104Sdas	char *cp;
188180104Sdas	int n2;
189103633Stjr
190180104Sdas	n2 = 0;
191180104Sdas	cp = *fmtp;
192180104Sdas	while (is_digit(*cp)) {
193180104Sdas		n2 = 10 * n2 + to_digit(*cp);
194180104Sdas		cp++;
195180104Sdas	}
196180104Sdas	if (*cp == '$') {
197180104Sdas		int hold = types->nextarg;
198180104Sdas		types->nextarg = n2;
199180107Sdas		if (addtype(types, T_INT))
200180107Sdas			return (-1);
201180104Sdas		types->nextarg = hold;
202180104Sdas		*fmtp = ++cp;
203148363Stjr	} else {
204180107Sdas		if (addtype(types, T_INT))
205180107Sdas			return (-1);
206103633Stjr	}
207180106Sdas	return (0);
208103633Stjr}
209103633Stjr
210180106Sdasstatic inline int
211180104Sdasaddwaster(struct typetable *types, wchar_t **fmtp)
21271579Sdeischen{
213180104Sdas	wchar_t *cp;
214180104Sdas	int n2;
21571579Sdeischen
216180104Sdas	n2 = 0;
217180104Sdas	cp = *fmtp;
218180104Sdas	while (is_digit(*cp)) {
219180104Sdas		n2 = 10 * n2 + to_digit(*cp);
220180104Sdas		cp++;
221180104Sdas	}
222180104Sdas	if (*cp == '$') {
223180104Sdas		int hold = types->nextarg;
224180104Sdas		types->nextarg = n2;
225180107Sdas		if (addtype(types, T_INT))
226180107Sdas			return (-1);
227180104Sdas		types->nextarg = hold;
228180104Sdas		*fmtp = ++cp;
229180104Sdas	} else {
230180107Sdas		if (addtype(types, T_INT))
231180107Sdas			return (-1);
232180104Sdas	}
233180106Sdas	return (0);
23471579Sdeischen}
23571579Sdeischen
236113142Sdas/*
237180104Sdas * Find all arguments when a positional parameter is encountered.  Returns a
238180104Sdas * table, indexed by argument number, of pointers to each arguments.  The
239180104Sdas * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
240180104Sdas * It will be replaces with a malloc-ed one if it overflows.
241180106Sdas * Returns 0 on success. On failure, returns nonzero and sets errno.
242180104Sdas */
243180106Sdasint
244180104Sdas__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
2451573Srgrimes{
24671579Sdeischen	char *fmt;		/* format string */
24771579Sdeischen	int ch;			/* character from fmt */
248180104Sdas	int n;			/* handy integer (short term usage) */
249180106Sdas	int error;
25071579Sdeischen	int flags;		/* flags as above */
251180104Sdas	struct typetable types;	/* table of types */
252153486Sphk
2531573Srgrimes	fmt = (char *)fmt0;
254180104Sdas	inittypes(&types);
255180106Sdas	error = 0;
2561573Srgrimes
2571573Srgrimes	/*
2581573Srgrimes	 * Scan the format for conversions (`%' character).
2591573Srgrimes	 */
2601573Srgrimes	for (;;) {
261180104Sdas		while ((ch = *fmt) != '\0' && ch != '%')
262180104Sdas			fmt++;
2631573Srgrimes		if (ch == '\0')
2641573Srgrimes			goto done;
2651573Srgrimes		fmt++;		/* skip over '%' */
2661573Srgrimes
2671573Srgrimes		flags = 0;
2681573Srgrimes
2691573Srgrimesrflag:		ch = *fmt++;
2701573Srgrimesreswitch:	switch (ch) {
2711573Srgrimes		case ' ':
2721573Srgrimes		case '#':
2731573Srgrimes			goto rflag;
2741573Srgrimes		case '*':
275180106Sdas			if ((error = addaster(&types, &fmt)))
276180106Sdas				goto error;
277180104Sdas			goto rflag;
2781573Srgrimes		case '-':
2791573Srgrimes		case '+':
28087113Sfenner		case '\'':
28187113Sfenner			goto rflag;
2821573Srgrimes		case '.':
2831573Srgrimes			if ((ch = *fmt++) == '*') {
284180106Sdas				if ((error = addaster(&types, &fmt)))
285180106Sdas					goto error;
2861573Srgrimes				goto rflag;
2871573Srgrimes			}
2881573Srgrimes			while (is_digit(ch)) {
2891573Srgrimes				ch = *fmt++;
2901573Srgrimes			}
2911573Srgrimes			goto reswitch;
2921573Srgrimes		case '0':
2931573Srgrimes			goto rflag;
2941573Srgrimes		case '1': case '2': case '3': case '4':
2951573Srgrimes		case '5': case '6': case '7': case '8': case '9':
2961573Srgrimes			n = 0;
2971573Srgrimes			do {
2981573Srgrimes				n = 10 * n + to_digit(ch);
2991573Srgrimes				ch = *fmt++;
3001573Srgrimes			} while (is_digit(ch));
30121674Sjkh			if (ch == '$') {
302180104Sdas				types.nextarg = n;
30321674Sjkh				goto rflag;
304103399Stjr			}
3051573Srgrimes			goto reswitch;
306128819Sdas#ifndef NO_FLOATING_POINT
3071573Srgrimes		case 'L':
3081573Srgrimes			flags |= LONGDBL;
3091573Srgrimes			goto rflag;
3101573Srgrimes#endif
3111573Srgrimes		case 'h':
31287113Sfenner			if (flags & SHORTINT) {
31387113Sfenner				flags &= ~SHORTINT;
31487113Sfenner				flags |= CHARINT;
31587113Sfenner			} else
31687113Sfenner				flags |= SHORTINT;
3171573Srgrimes			goto rflag;
31887113Sfenner		case 'j':
31987113Sfenner			flags |= INTMAXT;
32087113Sfenner			goto rflag;
3211573Srgrimes		case 'l':
32287113Sfenner			if (flags & LONGINT) {
32387113Sfenner				flags &= ~LONGINT;
32487113Sfenner				flags |= LLONGINT;
32587113Sfenner			} else
32644674Sdfr				flags |= LONGINT;
3271573Srgrimes			goto rflag;
3281573Srgrimes		case 'q':
32987113Sfenner			flags |= LLONGINT;	/* not necessarily */
3301573Srgrimes			goto rflag;
33187113Sfenner		case 't':
33287113Sfenner			flags |= PTRDIFFT;
33387113Sfenner			goto rflag;
33487113Sfenner		case 'z':
33587113Sfenner			flags |= SIZET;
33687113Sfenner			goto rflag;
337105204Stjr		case 'C':
338105204Stjr			flags |= LONGINT;
339105204Stjr			/*FALLTHROUGH*/
3401573Srgrimes		case 'c':
341180106Sdas			error = addtype(&types,
342180106Sdas					(flags & LONGINT) ? T_WINT : T_INT);
343180106Sdas			if (error)
344180106Sdas				goto error;
3451573Srgrimes			break;
3461573Srgrimes		case 'D':
3471573Srgrimes			flags |= LONGINT;
3481573Srgrimes			/*FALLTHROUGH*/
3491573Srgrimes		case 'd':
3501573Srgrimes		case 'i':
351180106Sdas			if ((error = addsarg(&types, flags)))
352180106Sdas				goto error;
353180104Sdas			break;
354128819Sdas#ifndef NO_FLOATING_POINT
35587113Sfenner		case 'a':
35687113Sfenner		case 'A':
3577033Sbde		case 'e':
3581573Srgrimes		case 'E':
3597033Sbde		case 'f':
3601573Srgrimes		case 'g':
3611573Srgrimes		case 'G':
362180106Sdas			error = addtype(&types,
363180106Sdas			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
364180106Sdas			if (error)
365180106Sdas				goto error;
3661573Srgrimes			break;
367128819Sdas#endif /* !NO_FLOATING_POINT */
3681573Srgrimes		case 'n':
369180104Sdas			if (flags & INTMAXT)
370180106Sdas				error = addtype(&types, TP_INTMAXT);
371180104Sdas			else if (flags & PTRDIFFT)
372180106Sdas				error = addtype(&types, TP_PTRDIFFT);
37387113Sfenner			else if (flags & SIZET)
374189268Sdas				error = addtype(&types, TP_SSIZET);
375180104Sdas			else if (flags & LLONGINT)
376180106Sdas				error = addtype(&types, TP_LLONG);
3771573Srgrimes			else if (flags & LONGINT)
378180106Sdas				error = addtype(&types, TP_LONG);
3791573Srgrimes			else if (flags & SHORTINT)
380180106Sdas				error = addtype(&types, TP_SHORT);
38187113Sfenner			else if (flags & CHARINT)
382180106Sdas				error = addtype(&types, TP_SCHAR);
3831573Srgrimes			else
384180106Sdas				error = addtype(&types, TP_INT);
385180106Sdas			if (error)
386180106Sdas				goto error;
3871573Srgrimes			continue;	/* no output */
3881573Srgrimes		case 'O':
3891573Srgrimes			flags |= LONGINT;
3901573Srgrimes			/*FALLTHROUGH*/
3911573Srgrimes		case 'o':
392180106Sdas			if ((error = adduarg(&types, flags)))
393180106Sdas				goto error;
394180104Sdas			break;
3951573Srgrimes		case 'p':
396180106Sdas			if ((error = addtype(&types, TP_VOID)))
397180106Sdas				goto error;
398180104Sdas			break;
399105204Stjr		case 'S':
400105204Stjr			flags |= LONGINT;
401105204Stjr			/*FALLTHROUGH*/
4021573Srgrimes		case 's':
403180106Sdas			error = addtype(&types,
404180106Sdas					(flags & LONGINT) ? TP_WCHAR : TP_CHAR);
405180106Sdas			if (error)
406180106Sdas				goto error;
4071573Srgrimes			break;
4081573Srgrimes		case 'U':
4091573Srgrimes			flags |= LONGINT;
4101573Srgrimes			/*FALLTHROUGH*/
4111573Srgrimes		case 'u':
4121573Srgrimes		case 'X':
4131573Srgrimes		case 'x':
414180106Sdas			if ((error = adduarg(&types, flags)))
415180106Sdas				goto error;
4161573Srgrimes			break;
4171573Srgrimes		default:	/* "%?" prints ?, unless ? is NUL */
4181573Srgrimes			if (ch == '\0')
4191573Srgrimes				goto done;
4201573Srgrimes			break;
4211573Srgrimes		}
422180104Sdas	}
423180104Sdasdone:
424180105Sdas	build_arg_table(&types, ap, argtable);
425180106Sdaserror:
426180104Sdas	freetypes(&types);
427180106Sdas	return (error || *argtable == NULL);
428180102Sdas}
429180102Sdas
430180104Sdas/* wchar version of __find_arguments. */
431180106Sdasint
432180104Sdas__find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
433180102Sdas{
434180104Sdas	wchar_t *fmt;		/* format string */
435180104Sdas	wchar_t ch;		/* character from fmt */
436180102Sdas	int n;			/* handy integer (short term usage) */
437180106Sdas	int error;
43871579Sdeischen	int flags;		/* flags as above */
439180102Sdas	struct typetable types;	/* table of types */
44021674Sjkh
441180104Sdas	fmt = (wchar_t *)fmt0;
442180102Sdas	inittypes(&types);
443180106Sdas	error = 0;
44421674Sjkh
44521674Sjkh	/*
44621674Sjkh	 * Scan the format for conversions (`%' character).
44721674Sjkh	 */
44821674Sjkh	for (;;) {
449180102Sdas		while ((ch = *fmt) != '\0' && ch != '%')
450180102Sdas			fmt++;
45121674Sjkh		if (ch == '\0')
45221674Sjkh			goto done;
45321674Sjkh		fmt++;		/* skip over '%' */
45421674Sjkh
45521674Sjkh		flags = 0;
45621674Sjkh
45721674Sjkhrflag:		ch = *fmt++;
45821674Sjkhreswitch:	switch (ch) {
45921674Sjkh		case ' ':
46021674Sjkh		case '#':
46121674Sjkh			goto rflag;
46221674Sjkh		case '*':
463180106Sdas			if ((error = addwaster(&types, &fmt)))
464180106Sdas				goto error;
46521674Sjkh			goto rflag;
46621674Sjkh		case '-':
46721674Sjkh		case '+':
46887113Sfenner		case '\'':
46921674Sjkh			goto rflag;
47021674Sjkh		case '.':
47121674Sjkh			if ((ch = *fmt++) == '*') {
472180106Sdas				if ((error = addwaster(&types, &fmt)))
473180106Sdas					goto error;
47421674Sjkh				goto rflag;
47521674Sjkh			}
47621674Sjkh			while (is_digit(ch)) {
47721674Sjkh				ch = *fmt++;
47821674Sjkh			}
47921674Sjkh			goto reswitch;
48021674Sjkh		case '0':
48121674Sjkh			goto rflag;
48221674Sjkh		case '1': case '2': case '3': case '4':
48321674Sjkh		case '5': case '6': case '7': case '8': case '9':
48421674Sjkh			n = 0;
48521674Sjkh			do {
48621674Sjkh				n = 10 * n + to_digit(ch);
48721674Sjkh				ch = *fmt++;
48821674Sjkh			} while (is_digit(ch));
48921674Sjkh			if (ch == '$') {
490180102Sdas				types.nextarg = n;
49121674Sjkh				goto rflag;
49221674Sjkh			}
49321674Sjkh			goto reswitch;
494128819Sdas#ifndef NO_FLOATING_POINT
49521674Sjkh		case 'L':
49621674Sjkh			flags |= LONGDBL;
49721674Sjkh			goto rflag;
49821674Sjkh#endif
49921674Sjkh		case 'h':
50087113Sfenner			if (flags & SHORTINT) {
50187113Sfenner				flags &= ~SHORTINT;
50287113Sfenner				flags |= CHARINT;
50387113Sfenner			} else
50487113Sfenner				flags |= SHORTINT;
50521674Sjkh			goto rflag;
50687113Sfenner		case 'j':
50787113Sfenner			flags |= INTMAXT;
50887113Sfenner			goto rflag;
50921674Sjkh		case 'l':
51087113Sfenner			if (flags & LONGINT) {
51187113Sfenner				flags &= ~LONGINT;
51287113Sfenner				flags |= LLONGINT;
51387113Sfenner			} else
51444674Sdfr				flags |= LONGINT;
51521674Sjkh			goto rflag;
51621674Sjkh		case 'q':
51787113Sfenner			flags |= LLONGINT;	/* not necessarily */
51821674Sjkh			goto rflag;
51987113Sfenner		case 't':
52087113Sfenner			flags |= PTRDIFFT;
52187113Sfenner			goto rflag;
52287113Sfenner		case 'z':
52387113Sfenner			flags |= SIZET;
52487113Sfenner			goto rflag;
525105204Stjr		case 'C':
526105204Stjr			flags |= LONGINT;
527105204Stjr			/*FALLTHROUGH*/
52821674Sjkh		case 'c':
529180106Sdas			error = addtype(&types,
530180106Sdas					(flags & LONGINT) ? T_WINT : T_INT);
531180106Sdas			if (error)
532180106Sdas				goto error;
53321674Sjkh			break;
53421674Sjkh		case 'D':
53521674Sjkh			flags |= LONGINT;
53621674Sjkh			/*FALLTHROUGH*/
53721674Sjkh		case 'd':
53821674Sjkh		case 'i':
539180106Sdas			if ((error = addsarg(&types, flags)))
540180106Sdas				goto error;
54121674Sjkh			break;
542128819Sdas#ifndef NO_FLOATING_POINT
54387113Sfenner		case 'a':
54487113Sfenner		case 'A':
54521674Sjkh		case 'e':
54621674Sjkh		case 'E':
54721674Sjkh		case 'f':
54821674Sjkh		case 'g':
54921674Sjkh		case 'G':
550180106Sdas			error = addtype(&types,
551180106Sdas			    (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
552180106Sdas			if (error)
553180106Sdas				goto error;
55421674Sjkh			break;
555128819Sdas#endif /* !NO_FLOATING_POINT */
55621674Sjkh		case 'n':
55787113Sfenner			if (flags & INTMAXT)
558180106Sdas				error = addtype(&types, TP_INTMAXT);
55987113Sfenner			else if (flags & PTRDIFFT)
560180106Sdas				error = addtype(&types, TP_PTRDIFFT);
56187113Sfenner			else if (flags & SIZET)
562189268Sdas				error = addtype(&types, TP_SSIZET);
56387113Sfenner			else if (flags & LLONGINT)
564180106Sdas				error = addtype(&types, TP_LLONG);
56521674Sjkh			else if (flags & LONGINT)
566180106Sdas				error = addtype(&types, TP_LONG);
56721674Sjkh			else if (flags & SHORTINT)
568180106Sdas				error = addtype(&types, TP_SHORT);
56987113Sfenner			else if (flags & CHARINT)
570180106Sdas				error = addtype(&types, TP_SCHAR);
57121674Sjkh			else
572180106Sdas				error = addtype(&types, TP_INT);
573180107Sdas			if (error)
574180107Sdas				goto error;
57521674Sjkh			continue;	/* no output */
57621674Sjkh		case 'O':
57721674Sjkh			flags |= LONGINT;
57821674Sjkh			/*FALLTHROUGH*/
57921674Sjkh		case 'o':
580180106Sdas			if ((error = adduarg(&types, flags)))
581180106Sdas				goto error;
58221674Sjkh			break;
58321674Sjkh		case 'p':
584180106Sdas			if ((error = addtype(&types, TP_VOID)))
585180106Sdas				goto error;
58621674Sjkh			break;
587105204Stjr		case 'S':
588105204Stjr			flags |= LONGINT;
589105204Stjr			/*FALLTHROUGH*/
59021674Sjkh		case 's':
591180106Sdas			error = addtype(&types,
592180106Sdas			    (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
593180106Sdas			if (error)
594180106Sdas				goto error;
59521674Sjkh			break;
59621674Sjkh		case 'U':
59721674Sjkh			flags |= LONGINT;
59821674Sjkh			/*FALLTHROUGH*/
59921674Sjkh		case 'u':
60021674Sjkh		case 'X':
60121674Sjkh		case 'x':
602180106Sdas			if ((error = adduarg(&types, flags)))
603180106Sdas				goto error;
60421674Sjkh			break;
60521674Sjkh		default:	/* "%?" prints ?, unless ? is NUL */
60621674Sjkh			if (ch == '\0')
60721674Sjkh				goto done;
60821674Sjkh			break;
60921674Sjkh		}
61021674Sjkh	}
61121674Sjkhdone:
612180105Sdas	build_arg_table(&types, ap, argtable);
613180106Sdaserror:
614180105Sdas	freetypes(&types);
615180106Sdas	return (error || *argtable == NULL);
616180105Sdas}
617180105Sdas
618180105Sdas/*
619180106Sdas * Increase the size of the type table. Returns 0 on success.
620180105Sdas */
621180106Sdasstatic int
622180105Sdas__grow_type_table(struct typetable *types)
623180105Sdas{
624180105Sdas	enum typeid *const oldtable = types->table;
625180105Sdas	const int oldsize = types->tablesize;
626180105Sdas	enum typeid *newtable;
627180105Sdas	int n, newsize = oldsize * 2;
628180105Sdas
629180105Sdas	if (newsize < types->nextarg + 1)
630180105Sdas		newsize = types->nextarg + 1;
631180105Sdas	if (oldsize == STATIC_ARG_TBL_SIZE) {
632180105Sdas		if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
633180106Sdas			return (-1);
634180105Sdas		bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
635180105Sdas	} else {
636180106Sdas		newtable = realloc(oldtable, newsize * sizeof(enum typeid));
637180105Sdas		if (newtable == NULL)
638180106Sdas			return (-1);
639180105Sdas	}
640180105Sdas	for (n = oldsize; n < newsize; n++)
641180105Sdas		newtable[n] = T_UNUSED;
642180105Sdas
643180105Sdas	types->table = newtable;
644180105Sdas	types->tablesize = newsize;
645180106Sdas
646180106Sdas	return (0);
647180105Sdas}
648180105Sdas
649180105Sdas/*
650180105Sdas * Build the argument table from the completed type table.
651180106Sdas * On malloc failure, *argtable is set to NULL.
652180105Sdas */
653180105Sdasstatic void
654180105Sdasbuild_arg_table(struct typetable *types, va_list ap, union arg **argtable)
655180105Sdas{
656180105Sdas	int n;
657180105Sdas
658180105Sdas	if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
65984922Sdfr		*argtable = (union arg *)
660180105Sdas		    malloc (sizeof (union arg) * (types->tablemax + 1));
661180106Sdas		if (*argtable == NULL)
662180106Sdas			return;
66321674Sjkh	}
6641573Srgrimes
66584922Sdfr	(*argtable) [0].intarg = 0;
666180105Sdas	for (n = 1; n <= types->tablemax; n++) {
667180105Sdas		switch (types->table[n]) {
66887113Sfenner		    case T_UNUSED: /* whoops! */
66984922Sdfr			(*argtable) [n].intarg = va_arg (ap, int);
67021674Sjkh			break;
67187113Sfenner		    case TP_SCHAR:
67287113Sfenner			(*argtable) [n].pschararg = va_arg (ap, signed char *);
67321674Sjkh			break;
67421674Sjkh		    case TP_SHORT:
67584922Sdfr			(*argtable) [n].pshortarg = va_arg (ap, short *);
67621674Sjkh			break;
67721674Sjkh		    case T_INT:
67884922Sdfr			(*argtable) [n].intarg = va_arg (ap, int);
67921674Sjkh			break;
68021674Sjkh		    case T_U_INT:
68184922Sdfr			(*argtable) [n].uintarg = va_arg (ap, unsigned int);
68221674Sjkh			break;
68321674Sjkh		    case TP_INT:
68484922Sdfr			(*argtable) [n].pintarg = va_arg (ap, int *);
68521674Sjkh			break;
68621674Sjkh		    case T_LONG:
68784922Sdfr			(*argtable) [n].longarg = va_arg (ap, long);
68821674Sjkh			break;
68921674Sjkh		    case T_U_LONG:
69084922Sdfr			(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
69121674Sjkh			break;
69221674Sjkh		    case TP_LONG:
69384922Sdfr			(*argtable) [n].plongarg = va_arg (ap, long *);
69421674Sjkh			break;
69587113Sfenner		    case T_LLONG:
69687113Sfenner			(*argtable) [n].longlongarg = va_arg (ap, long long);
69721674Sjkh			break;
69887113Sfenner		    case T_U_LLONG:
69987113Sfenner			(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
70021674Sjkh			break;
70187113Sfenner		    case TP_LLONG:
70287113Sfenner			(*argtable) [n].plonglongarg = va_arg (ap, long long *);
70321674Sjkh			break;
70487113Sfenner		    case T_PTRDIFFT:
70587113Sfenner			(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
70687113Sfenner			break;
70787113Sfenner		    case TP_PTRDIFFT:
70887113Sfenner			(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
70987113Sfenner			break;
71087113Sfenner		    case T_SIZET:
71187113Sfenner			(*argtable) [n].sizearg = va_arg (ap, size_t);
71287113Sfenner			break;
713189131Sdas		    case T_SSIZET:
714189131Sdas			(*argtable) [n].sizearg = va_arg (ap, ssize_t);
715189131Sdas			break;
716189268Sdas		    case TP_SSIZET:
717189268Sdas			(*argtable) [n].pssizearg = va_arg (ap, ssize_t *);
71887113Sfenner			break;
71987113Sfenner		    case T_INTMAXT:
72087113Sfenner			(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
72187113Sfenner			break;
72287113Sfenner		    case T_UINTMAXT:
72387113Sfenner			(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
72487113Sfenner			break;
72587113Sfenner		    case TP_INTMAXT:
72687113Sfenner			(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
72787113Sfenner			break;
728157381Sphk		    case T_DOUBLE:
729128819Sdas#ifndef NO_FLOATING_POINT
73084922Sdfr			(*argtable) [n].doublearg = va_arg (ap, double);
731157381Sphk#endif
73221674Sjkh			break;
73321674Sjkh		    case T_LONG_DOUBLE:
734157381Sphk#ifndef NO_FLOATING_POINT
73584922Sdfr			(*argtable) [n].longdoublearg = va_arg (ap, long double);
736157381Sphk#endif
73721674Sjkh			break;
73821674Sjkh		    case TP_CHAR:
73984922Sdfr			(*argtable) [n].pchararg = va_arg (ap, char *);
74021674Sjkh			break;
74121674Sjkh		    case TP_VOID:
74284922Sdfr			(*argtable) [n].pvoidarg = va_arg (ap, void *);
74321674Sjkh			break;
744103633Stjr		    case T_WINT:
745103633Stjr			(*argtable) [n].wintarg = va_arg (ap, wint_t);
746103633Stjr			break;
747103633Stjr		    case TP_WCHAR:
748103633Stjr			(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
749103633Stjr			break;
75021674Sjkh		}
75121674Sjkh	}
75221674Sjkh}
753