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: releng/10.3/lib/libc/stdio/printf-pos.c 249808 2013-04-23 13:33:13Z emaste $"); 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