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