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