diff options
author | das <das@FreeBSD.org> | 2008-06-29 21:52:40 +0000 |
---|---|---|
committer | das <das@FreeBSD.org> | 2008-06-29 21:52:40 +0000 |
commit | 8d5e7f14f6536060c1f9eb8be2aab19f42dedc0d (patch) | |
tree | 2d4458558cb21698c7958f9066bc758360c4e903 /lib | |
parent | d36ce0f109efab721a127c6aa11db35ca9074797 (diff) | |
download | FreeBSD-src-8d5e7f14f6536060c1f9eb8be2aab19f42dedc0d.zip FreeBSD-src-8d5e7f14f6536060c1f9eb8be2aab19f42dedc0d.tar.gz |
Reduce the level of duplication between vfprintf() and vfwprintf()
by moving the positional argument handling code to a new file,
printf-pos.c, and moving common definitions to printflocal.h.
No functional change intended.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/stdio/Makefile.inc | 3 | ||||
-rw-r--r-- | lib/libc/stdio/printf-pos.c | 788 | ||||
-rw-r--r-- | lib/libc/stdio/printflocal.h | 94 | ||||
-rw-r--r-- | lib/libc/stdio/vfprintf.c | 487 | ||||
-rw-r--r-- | lib/libc/stdio/vfwprintf.c | 491 |
5 files changed, 888 insertions, 975 deletions
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc index 47dd3f5..fc106db 100644 --- a/lib/libc/stdio/Makefile.inc +++ b/lib/libc/stdio/Makefile.inc @@ -12,7 +12,8 @@ SRCS+= _flock_stub.c asprintf.c clrerr.c fclose.c fcloseall.c fdopen.c \ ftell.c funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwscanf.c \ fwrite.c getc.c \ getchar.c gets.c getw.c getwc.c getwchar.c makebuf.c mktemp.c \ - perror.c printf.c putc.c putchar.c puts.c putw.c putwc.c putwchar.c \ + perror.c printf.c printf-pos.c putc.c putchar.c \ + puts.c putw.c putwc.c putwchar.c \ refill.c remove.c rewind.c rget.c scanf.c setbuf.c setbuffer.c \ setvbuf.c snprintf.c sprintf.c sscanf.c stdio.c swprintf.c swscanf.c \ tempnam.c tmpfile.c \ diff --git a/lib/libc/stdio/printf-pos.c b/lib/libc/stdio/printf-pos.c new file mode 100644 index 0000000..c9b439b --- /dev/null +++ b/lib/libc/stdio/printf-pos.c @@ -0,0 +1,788 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * This is the code responsible for handling positional arguments + * (%m$ and %m$.n$) for vfprintf() and vfwprintf(). + */ + +#include "namespace.h" +#include <sys/types.h> + +#include <ctype.h> +#include <limits.h> +#include <locale.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <printf.h> + +#include <stdarg.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "local.h" +#include "fvwrite.h" +#include "printflocal.h" + +/* + * Type ids for argument type table. + */ +enum typeid { + T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, + T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, + T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, + T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, + T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR +}; + +/* An expandable array of types. */ +struct typetable { + enum typeid *table; /* table of types */ + enum typeid stattable[STATIC_ARG_TBL_SIZE]; + int tablesize; /* current size of type table */ + int tablemax; /* largest used index in table */ + int nextarg; /* 1-based argument index */ +}; + +static void __grow_type_table(struct typetable *); + +/* + * Initialize a struct typetable. + */ +static inline void +inittypes(struct typetable *types) +{ + int n; + + types->table = types->stattable; + types->tablesize = STATIC_ARG_TBL_SIZE; + types->tablemax = 0; + types->nextarg = 1; + for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) + types->table[n] = T_UNUSED; +} + +/* + * struct typetable destructor. + */ +static inline void +freetypes(struct typetable *types) +{ + + if (types->table != types->stattable) + free (types->table); +} + +/* + * Add an argument type to the table, expanding if necessary. + */ +static inline void +addtype(struct typetable *types, enum typeid type) +{ + + if (types->nextarg >= types->tablesize) + __grow_type_table(types); + if (types->nextarg > types->tablemax) + types->tablemax = types->nextarg; + types->table[types->nextarg++] = type; +} + +static inline void +addsarg(struct typetable *types, int flags) +{ + + if (flags & INTMAXT) + addtype(types, T_INTMAXT); + else if (flags & SIZET) + addtype(types, T_SIZET); + else if (flags & PTRDIFFT) + addtype(types, T_PTRDIFFT); + else if (flags & LLONGINT) + addtype(types, T_LLONG); + else if (flags & LONGINT) + addtype(types, T_LONG); + else + addtype(types, T_INT); +} + +static inline void +adduarg(struct typetable *types, int flags) +{ + + if (flags & INTMAXT) + addtype(types, T_UINTMAXT); + else if (flags & SIZET) + addtype(types, T_SIZET); + else if (flags & PTRDIFFT) + addtype(types, T_PTRDIFFT); + else if (flags & LLONGINT) + addtype(types, T_U_LLONG); + else if (flags & LONGINT) + addtype(types, T_U_LONG); + else + addtype(types, T_U_INT); +} + +/* + * Add * arguments to the type array. + */ +static inline void +addaster(struct typetable *types, char **fmtp) +{ + char *cp; + int n2; + + n2 = 0; + cp = *fmtp; + while (is_digit(*cp)) { + n2 = 10 * n2 + to_digit(*cp); + cp++; + } + if (*cp == '$') { + int hold = types->nextarg; + types->nextarg = n2; + addtype(types, T_INT); + types->nextarg = hold; + *fmtp = ++cp; + } else { + addtype(types, T_INT); + } +} + +static inline void +addwaster(struct typetable *types, wchar_t **fmtp) +{ + wchar_t *cp; + int n2; + + n2 = 0; + cp = *fmtp; + while (is_digit(*cp)) { + n2 = 10 * n2 + to_digit(*cp); + cp++; + } + if (*cp == '$') { + int hold = types->nextarg; + types->nextarg = n2; + addtype(types, T_INT); + types->nextarg = hold; + *fmtp = ++cp; + } else { + addtype(types, T_INT); + } +} + +/* + * Find all arguments when a positional parameter is encountered. Returns a + * table, indexed by argument number, of pointers to each arguments. The + * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. + * It will be replaces with a malloc-ed one if it overflows. + */ +void +__find_arguments (const char *fmt0, va_list ap, union arg **argtable) +{ + char *fmt; /* format string */ + int ch; /* character from fmt */ + int n; /* handy integer (short term usage) */ + int flags; /* flags as above */ + int width; /* width from format (%8d), or 0 */ + struct typetable types; /* table of types */ + + fmt = (char *)fmt0; + inittypes(&types); + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + while ((ch = *fmt) != '\0' && ch != '%') + fmt++; + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + width = 0; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + case '#': + goto rflag; + case '*': + addaster(&types, &fmt); + goto rflag; + case '-': + case '+': + case '\'': + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + addaster(&types, &fmt); + goto rflag; + } + while (is_digit(ch)) { + ch = *fmt++; + } + goto reswitch; + case '0': + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + if (ch == '$') { + types.nextarg = n; + goto rflag; + } + width = n; + goto reswitch; +#ifndef NO_FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + if (flags & SHORTINT) { + flags &= ~SHORTINT; + flags |= CHARINT; + } else + flags |= SHORTINT; + goto rflag; + case 'j': + flags |= INTMAXT; + goto rflag; + case 'l': + if (flags & LONGINT) { + flags &= ~LONGINT; + flags |= LLONGINT; + } else + flags |= LONGINT; + goto rflag; + case 'q': + flags |= LLONGINT; /* not necessarily */ + goto rflag; + case 't': + flags |= PTRDIFFT; + goto rflag; + case 'z': + flags |= SIZET; + goto rflag; + case 'C': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'c': + if (flags & LONGINT) + addtype(&types, T_WINT); + else + addtype(&types, T_INT); + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + addsarg(&types, flags); + break; +#ifndef NO_FLOATING_POINT + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (flags & LONGDBL) + addtype(&types, T_LONG_DOUBLE); + else + addtype(&types, T_DOUBLE); + break; +#endif /* !NO_FLOATING_POINT */ + case 'n': + if (flags & INTMAXT) + addtype(&types, TP_INTMAXT); + else if (flags & PTRDIFFT) + addtype(&types, TP_PTRDIFFT); + else if (flags & SIZET) + addtype(&types, TP_SIZET); + else if (flags & LLONGINT) + addtype(&types, TP_LLONG); + else if (flags & LONGINT) + addtype(&types, TP_LONG); + else if (flags & SHORTINT) + addtype(&types, TP_SHORT); + else if (flags & CHARINT) + addtype(&types, TP_SCHAR); + else + addtype(&types, TP_INT); + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + adduarg(&types, flags); + break; + case 'p': + addtype(&types, TP_VOID); + break; + case 'S': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 's': + if (flags & LONGINT) + addtype(&types, TP_WCHAR); + else + addtype(&types, TP_CHAR); + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + case 'X': + case 'x': + adduarg(&types, flags); + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + break; + } + } +done: + /* + * Build the argument table. + */ + if (types.tablemax >= STATIC_ARG_TBL_SIZE) { + *argtable = (union arg *) + malloc (sizeof (union arg) * (types.tablemax + 1)); + } + + (*argtable) [0].intarg = 0; + for (n = 1; n <= types.tablemax; n++) { + switch (types.table[n]) { + case T_UNUSED: /* whoops! */ + (*argtable) [n].intarg = va_arg (ap, int); + break; + case TP_SCHAR: + (*argtable) [n].pschararg = va_arg (ap, signed char *); + break; + case TP_SHORT: + (*argtable) [n].pshortarg = va_arg (ap, short *); + break; + case T_INT: + (*argtable) [n].intarg = va_arg (ap, int); + break; + case T_U_INT: + (*argtable) [n].uintarg = va_arg (ap, unsigned int); + break; + case TP_INT: + (*argtable) [n].pintarg = va_arg (ap, int *); + break; + case T_LONG: + (*argtable) [n].longarg = va_arg (ap, long); + break; + case T_U_LONG: + (*argtable) [n].ulongarg = va_arg (ap, unsigned long); + break; + case TP_LONG: + (*argtable) [n].plongarg = va_arg (ap, long *); + break; + case T_LLONG: + (*argtable) [n].longlongarg = va_arg (ap, long long); + break; + case T_U_LLONG: + (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); + break; + case TP_LLONG: + (*argtable) [n].plonglongarg = va_arg (ap, long long *); + break; + case T_PTRDIFFT: + (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); + break; + case TP_PTRDIFFT: + (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); + break; + case T_SIZET: + (*argtable) [n].sizearg = va_arg (ap, size_t); + break; + case TP_SIZET: + (*argtable) [n].psizearg = va_arg (ap, size_t *); + break; + case T_INTMAXT: + (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); + break; + case T_UINTMAXT: + (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); + break; + case TP_INTMAXT: + (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); + break; + case T_DOUBLE: +#ifndef NO_FLOATING_POINT + (*argtable) [n].doublearg = va_arg (ap, double); +#endif + break; + case T_LONG_DOUBLE: +#ifndef NO_FLOATING_POINT + (*argtable) [n].longdoublearg = va_arg (ap, long double); +#endif + break; + case TP_CHAR: + (*argtable) [n].pchararg = va_arg (ap, char *); + break; + case TP_VOID: + (*argtable) [n].pvoidarg = va_arg (ap, void *); + break; + case T_WINT: + (*argtable) [n].wintarg = va_arg (ap, wint_t); + break; + case TP_WCHAR: + (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); + break; + } + } + + freetypes(&types); +} + +/* wchar version of __find_arguments. */ +void +__find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable) +{ + wchar_t *fmt; /* format string */ + wchar_t ch; /* character from fmt */ + int n; /* handy integer (short term usage) */ + int flags; /* flags as above */ + int width; /* width from format (%8d), or 0 */ + struct typetable types; /* table of types */ + + fmt = (wchar_t *)fmt0; + inittypes(&types); + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + while ((ch = *fmt) != '\0' && ch != '%') + fmt++; + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + width = 0; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + case '#': + goto rflag; + case '*': + addwaster(&types, &fmt); + goto rflag; + case '-': + case '+': + case '\'': + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + addwaster(&types, &fmt); + goto rflag; + } + while (is_digit(ch)) { + ch = *fmt++; + } + goto reswitch; + case '0': + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + if (ch == '$') { + types.nextarg = n; + goto rflag; + } + width = n; + goto reswitch; +#ifndef NO_FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + if (flags & SHORTINT) { + flags &= ~SHORTINT; + flags |= CHARINT; + } else + flags |= SHORTINT; + goto rflag; + case 'j': + flags |= INTMAXT; + goto rflag; + case 'l': + if (flags & LONGINT) { + flags &= ~LONGINT; + flags |= LLONGINT; + } else + flags |= LONGINT; + goto rflag; + case 'q': + flags |= LLONGINT; /* not necessarily */ + goto rflag; + case 't': + flags |= PTRDIFFT; + goto rflag; + case 'z': + flags |= SIZET; + goto rflag; + case 'C': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'c': + if (flags & LONGINT) + addtype(&types, T_WINT); + else + addtype(&types, T_INT); + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + addsarg(&types, flags); + break; +#ifndef NO_FLOATING_POINT + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (flags & LONGDBL) + addtype(&types, T_LONG_DOUBLE); + else + addtype(&types, T_DOUBLE); + break; +#endif /* !NO_FLOATING_POINT */ + case 'n': + if (flags & INTMAXT) + addtype(&types, TP_INTMAXT); + else if (flags & PTRDIFFT) + addtype(&types, TP_PTRDIFFT); + else if (flags & SIZET) + addtype(&types, TP_SIZET); + else if (flags & LLONGINT) + addtype(&types, TP_LLONG); + else if (flags & LONGINT) + addtype(&types, TP_LONG); + else if (flags & SHORTINT) + addtype(&types, TP_SHORT); + else if (flags & CHARINT) + addtype(&types, TP_SCHAR); + else + addtype(&types, TP_INT); + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + adduarg(&types, flags); + break; + case 'p': + addtype(&types, TP_VOID); + break; + case 'S': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 's': + if (flags & LONGINT) + addtype(&types, TP_WCHAR); + else + addtype(&types, TP_CHAR); + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + case 'X': + case 'x': + adduarg(&types, flags); + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + break; + } + } +done: + /* + * Build the argument table. + */ + if (types.tablemax >= STATIC_ARG_TBL_SIZE) { + *argtable = (union arg *) + malloc (sizeof (union arg) * (types.tablemax + 1)); + } + + (*argtable) [0].intarg = 0; + for (n = 1; n <= types.tablemax; n++) { + switch (types.table[n]) { + case T_UNUSED: /* whoops! */ + (*argtable) [n].intarg = va_arg (ap, int); + break; + case TP_SCHAR: + (*argtable) [n].pschararg = va_arg (ap, signed char *); + break; + case TP_SHORT: + (*argtable) [n].pshortarg = va_arg (ap, short *); + break; + case T_INT: + (*argtable) [n].intarg = va_arg (ap, int); + break; + case T_U_INT: + (*argtable) [n].uintarg = va_arg (ap, unsigned int); + break; + case TP_INT: + (*argtable) [n].pintarg = va_arg (ap, int *); + break; + case T_LONG: + (*argtable) [n].longarg = va_arg (ap, long); + break; + case T_U_LONG: + (*argtable) [n].ulongarg = va_arg (ap, unsigned long); + break; + case TP_LONG: + (*argtable) [n].plongarg = va_arg (ap, long *); + break; + case T_LLONG: + (*argtable) [n].longlongarg = va_arg (ap, long long); + break; + case T_U_LLONG: + (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); + break; + case TP_LLONG: + (*argtable) [n].plonglongarg = va_arg (ap, long long *); + break; + case T_PTRDIFFT: + (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); + break; + case TP_PTRDIFFT: + (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); + break; + case T_SIZET: + (*argtable) [n].sizearg = va_arg (ap, size_t); + break; + case TP_SIZET: + (*argtable) [n].psizearg = va_arg (ap, size_t *); + break; + case T_INTMAXT: + (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); + break; + case T_UINTMAXT: + (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); + break; + case TP_INTMAXT: + (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); + break; + case T_DOUBLE: +#ifndef NO_FLOATING_POINT + (*argtable) [n].doublearg = va_arg (ap, double); +#endif + break; + case T_LONG_DOUBLE: +#ifndef NO_FLOATING_POINT + (*argtable) [n].longdoublearg = va_arg (ap, long double); +#endif + break; + case TP_CHAR: + (*argtable) [n].pchararg = va_arg (ap, char *); + break; + case TP_VOID: + (*argtable) [n].pvoidarg = va_arg (ap, void *); + break; + case T_WINT: + (*argtable) [n].wintarg = va_arg (ap, wint_t); + break; + case TP_WCHAR: + (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); + break; + } + } + + freetypes(&types); +} + +/* + * Increase the size of the type table. + */ +static void +__grow_type_table(struct typetable *types) +{ + enum typeid *const oldtable = types->table; + const int oldsize = types->tablesize; + enum typeid *newtable; + int n, newsize = oldsize * 2; + + if (newsize < types->nextarg + 1) + newsize = types->nextarg + 1; + if (oldsize == STATIC_ARG_TBL_SIZE) { + if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) + abort(); /* XXX handle better */ + bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); + } else { + newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); + if (newtable == NULL) + abort(); /* XXX handle better */ + } + for (n = oldsize; n < newsize; n++) + newtable[n] = T_UNUSED; + + types->table = newtable; + types->tablesize = newsize; +} diff --git a/lib/libc/stdio/printflocal.h b/lib/libc/stdio/printflocal.h new file mode 100644 index 0000000..f643e48 --- /dev/null +++ b/lib/libc/stdio/printflocal.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Flags used during conversion. + */ +#define ALT 0x001 /* alternate form */ +#define LADJUST 0x004 /* left adjustment */ +#define LONGDBL 0x008 /* long double */ +#define LONGINT 0x010 /* long integer */ +#define LLONGINT 0x020 /* long long integer */ +#define SHORTINT 0x040 /* short integer */ +#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ +#define FPT 0x100 /* Floating point number */ +#define GROUPING 0x200 /* use grouping ("'" flag) */ + /* C99 additional size modifiers: */ +#define SIZET 0x400 /* size_t */ +#define PTRDIFFT 0x800 /* ptrdiff_t */ +#define INTMAXT 0x1000 /* intmax_t */ +#define CHARINT 0x2000 /* print char using int format */ + +/* + * Macros for converting digits to letters and vice versa + */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') + +/* Size of the static argument table. */ +#define STATIC_ARG_TBL_SIZE 8 + +union arg { + int intarg; + u_int uintarg; + long longarg; + u_long ulongarg; + long long longlongarg; + unsigned long long ulonglongarg; + ptrdiff_t ptrdiffarg; + size_t sizearg; + intmax_t intmaxarg; + uintmax_t uintmaxarg; + void *pvoidarg; + char *pchararg; + signed char *pschararg; + short *pshortarg; + int *pintarg; + long *plongarg; + long long *plonglongarg; + ptrdiff_t *pptrdiffarg; + size_t *psizearg; + intmax_t *pintmaxarg; +#ifndef NO_FLOATING_POINT + double doublearg; + long double longdoublearg; +#endif + wint_t wintarg; + wchar_t *pwchararg; +}; + +/* Handle positional parameters. */ +void __find_arguments(const char *, va_list, union arg **); +void __find_warguments(const wchar_t *, va_list, union arg **); diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index aaf7154..2790547 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -62,57 +62,7 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" #include "local.h" #include "fvwrite.h" - -union arg { - int intarg; - u_int uintarg; - long longarg; - u_long ulongarg; - long long longlongarg; - unsigned long long ulonglongarg; - ptrdiff_t ptrdiffarg; - size_t sizearg; - intmax_t intmaxarg; - uintmax_t uintmaxarg; - void *pvoidarg; - char *pchararg; - signed char *pschararg; - short *pshortarg; - int *pintarg; - long *plongarg; - long long *plonglongarg; - ptrdiff_t *pptrdiffarg; - size_t *psizearg; - intmax_t *pintmaxarg; -#ifndef NO_FLOATING_POINT - double doublearg; - long double longdoublearg; -#endif - wint_t wintarg; - wchar_t *pwchararg; -}; - -/* - * Type ids for argument type table. - */ -enum typeid { - T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, - T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, - T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, - T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, - T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR -}; - -#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ - -/* An expandable array of types. */ -struct typetable { - enum typeid *table; /* table of types */ - enum typeid stattable[STATIC_ARG_TBL_SIZE]; - int tablesize; /* current size of type table */ - int tablemax; /* largest used index in table */ - int nextarg; /* 1-based argument index */ -}; +#include "printflocal.h" static int __sprint(FILE *, struct __suio *); static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); @@ -121,8 +71,6 @@ static char *__ujtoa(uintmax_t, char *, int, int, const char *, int, char, static char *__ultoa(u_long, char *, int, int, const char *, int, char, const char *); static char *__wcsconv(wchar_t *, int); -static void __find_arguments(const char *, va_list, union arg **); -static void __grow_type_table(struct typetable *); /* * Flush out all the vectors defined by the given uio, @@ -178,13 +126,6 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap) } /* - * Macros for converting digits to letters and vice versa - */ -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -/* * Convert an unsigned long to ASCII for printf purposes, returning * a pointer to the first character of the string representation. * Octal numbers can be forced to have a leading zero; hex numbers @@ -438,24 +379,6 @@ static int exponent(char *, int, int); #define BUF 100 /* - * Flags used during conversion. - */ -#define ALT 0x001 /* alternate form */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGDBL 0x008 /* long double */ -#define LONGINT 0x010 /* long integer */ -#define LLONGINT 0x020 /* long long integer */ -#define SHORTINT 0x040 /* short integer */ -#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ -#define FPT 0x100 /* Floating point number */ -#define GROUPING 0x200 /* use grouping ("'" flag) */ - /* C99 additional size modifiers: */ -#define SIZET 0x400 /* size_t */ -#define PTRDIFFT 0x800 /* ptrdiff_t */ -#define INTMAXT 0x1000 /* intmax_t */ -#define CHARINT 0x2000 /* print char using int format */ - -/* * Non-MT-safe version */ int @@ -1264,414 +1187,6 @@ error: /* NOTREACHED */ } -/* - * Initialize a struct typetable. - */ -static inline void -inittypes(struct typetable *types) -{ - int n; - - types->table = types->stattable; - types->tablesize = STATIC_ARG_TBL_SIZE; - types->tablemax = 0; - types->nextarg = 1; - for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) - types->table[n] = T_UNUSED; -} - -/* - * struct typetable destructor. - */ -static inline void -freetypes(struct typetable *types) -{ - - if (types->table != types->stattable) - free (types->table); -} - -/* - * Add an argument type to the table, expanding if necessary. - */ -static inline void -addtype(struct typetable *types, enum typeid type) -{ - - if (types->nextarg >= types->tablesize) - __grow_type_table(types); - if (types->nextarg > types->tablemax) - types->tablemax = types->nextarg; - types->table[types->nextarg++] = type; -} - -static inline void -addsarg(struct typetable *types, int flags) -{ - - if (flags & INTMAXT) - addtype(types, T_INTMAXT); - else if (flags & SIZET) - addtype(types, T_SIZET); - else if (flags & PTRDIFFT) - addtype(types, T_PTRDIFFT); - else if (flags & LLONGINT) - addtype(types, T_LLONG); - else if (flags & LONGINT) - addtype(types, T_LONG); - else - addtype(types, T_INT); -} - -static inline void -adduarg(struct typetable *types, int flags) -{ - - if (flags & INTMAXT) - addtype(types, T_UINTMAXT); - else if (flags & SIZET) - addtype(types, T_SIZET); - else if (flags & PTRDIFFT) - addtype(types, T_PTRDIFFT); - else if (flags & LLONGINT) - addtype(types, T_U_LLONG); - else if (flags & LONGINT) - addtype(types, T_U_LONG); - else - addtype(types, T_U_INT); -} - -/* - * Add * arguments to the type array. - */ -static inline void -addaster(struct typetable *types, char **fmtp) -{ - char *cp; - int n2; - - n2 = 0; - cp = *fmtp; - while (is_digit(*cp)) { - n2 = 10 * n2 + to_digit(*cp); - cp++; - } - if (*cp == '$') { - int hold = types->nextarg; - types->nextarg = n2; - addtype(types, T_INT); - types->nextarg = hold; - *fmtp = ++cp; - } else { - addtype(types, T_INT); - } -} - -/* - * Find all arguments when a positional parameter is encountered. Returns a - * table, indexed by argument number, of pointers to each arguments. The - * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. - * It will be replaces with a malloc-ed one if it overflows. - */ -static void -__find_arguments (const char *fmt0, va_list ap, union arg **argtable) -{ - char *fmt; /* format string */ - int ch; /* character from fmt */ - int n; /* handy integer (short term usage) */ - int flags; /* flags as above */ - int width; /* width from format (%8d), or 0 */ - struct typetable types; /* table of types */ - - fmt = (char *)fmt0; - inittypes(&types); - - /* - * Scan the format for conversions (`%' character). - */ - for (;;) { - while ((ch = *fmt) != '\0' && ch != '%') - fmt++; - if (ch == '\0') - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - width = 0; - -rflag: ch = *fmt++; -reswitch: switch (ch) { - case ' ': - case '#': - goto rflag; - case '*': - addaster(&types, &fmt); - goto rflag; - case '-': - case '+': - case '\'': - goto rflag; - case '.': - if ((ch = *fmt++) == '*') { - addaster(&types, &fmt); - goto rflag; - } - while (is_digit(ch)) { - ch = *fmt++; - } - goto reswitch; - case '0': - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } while (is_digit(ch)); - if (ch == '$') { - types.nextarg = n; - goto rflag; - } - width = n; - goto reswitch; -#ifndef NO_FLOATING_POINT - case 'L': - flags |= LONGDBL; - goto rflag; -#endif - case 'h': - if (flags & SHORTINT) { - flags &= ~SHORTINT; - flags |= CHARINT; - } else - flags |= SHORTINT; - goto rflag; - case 'j': - flags |= INTMAXT; - goto rflag; - case 'l': - if (flags & LONGINT) { - flags &= ~LONGINT; - flags |= LLONGINT; - } else - flags |= LONGINT; - goto rflag; - case 'q': - flags |= LLONGINT; /* not necessarily */ - goto rflag; - case 't': - flags |= PTRDIFFT; - goto rflag; - case 'z': - flags |= SIZET; - goto rflag; - case 'C': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'c': - if (flags & LONGINT) - addtype(&types, T_WINT); - else - addtype(&types, T_INT); - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - addsarg(&types, flags); - break; -#ifndef NO_FLOATING_POINT - case 'a': - case 'A': - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (flags & LONGDBL) - addtype(&types, T_LONG_DOUBLE); - else - addtype(&types, T_DOUBLE); - break; -#endif /* !NO_FLOATING_POINT */ - case 'n': - if (flags & INTMAXT) - addtype(&types, TP_INTMAXT); - else if (flags & PTRDIFFT) - addtype(&types, TP_PTRDIFFT); - else if (flags & SIZET) - addtype(&types, TP_SIZET); - else if (flags & LLONGINT) - addtype(&types, TP_LLONG); - else if (flags & LONGINT) - addtype(&types, TP_LONG); - else if (flags & SHORTINT) - addtype(&types, TP_SHORT); - else if (flags & CHARINT) - addtype(&types, TP_SCHAR); - else - addtype(&types, TP_INT); - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - adduarg(&types, flags); - break; - case 'p': - addtype(&types, TP_VOID); - break; - case 'S': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 's': - if (flags & LONGINT) - addtype(&types, TP_WCHAR); - else - addtype(&types, TP_CHAR); - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - case 'X': - case 'x': - adduarg(&types, flags); - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - break; - } - } -done: - /* - * Build the argument table. - */ - if (types.tablemax >= STATIC_ARG_TBL_SIZE) { - *argtable = (union arg *) - malloc (sizeof (union arg) * (types.tablemax + 1)); - } - - (*argtable) [0].intarg = 0; - for (n = 1; n <= types.tablemax; n++) { - switch (types.table[n]) { - case T_UNUSED: /* whoops! */ - (*argtable) [n].intarg = va_arg (ap, int); - break; - case TP_SCHAR: - (*argtable) [n].pschararg = va_arg (ap, signed char *); - break; - case TP_SHORT: - (*argtable) [n].pshortarg = va_arg (ap, short *); - break; - case T_INT: - (*argtable) [n].intarg = va_arg (ap, int); - break; - case T_U_INT: - (*argtable) [n].uintarg = va_arg (ap, unsigned int); - break; - case TP_INT: - (*argtable) [n].pintarg = va_arg (ap, int *); - break; - case T_LONG: - (*argtable) [n].longarg = va_arg (ap, long); - break; - case T_U_LONG: - (*argtable) [n].ulongarg = va_arg (ap, unsigned long); - break; - case TP_LONG: - (*argtable) [n].plongarg = va_arg (ap, long *); - break; - case T_LLONG: - (*argtable) [n].longlongarg = va_arg (ap, long long); - break; - case T_U_LLONG: - (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); - break; - case TP_LLONG: - (*argtable) [n].plonglongarg = va_arg (ap, long long *); - break; - case T_PTRDIFFT: - (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); - break; - case TP_PTRDIFFT: - (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); - break; - case T_SIZET: - (*argtable) [n].sizearg = va_arg (ap, size_t); - break; - case TP_SIZET: - (*argtable) [n].psizearg = va_arg (ap, size_t *); - break; - case T_INTMAXT: - (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); - break; - case T_UINTMAXT: - (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); - break; - case TP_INTMAXT: - (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); - break; - case T_DOUBLE: -#ifndef NO_FLOATING_POINT - (*argtable) [n].doublearg = va_arg (ap, double); -#endif - break; - case T_LONG_DOUBLE: -#ifndef NO_FLOATING_POINT - (*argtable) [n].longdoublearg = va_arg (ap, long double); -#endif - break; - case TP_CHAR: - (*argtable) [n].pchararg = va_arg (ap, char *); - break; - case TP_VOID: - (*argtable) [n].pvoidarg = va_arg (ap, void *); - break; - case T_WINT: - (*argtable) [n].wintarg = va_arg (ap, wint_t); - break; - case TP_WCHAR: - (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); - break; - } - } - - freetypes(&types); -} - -/* - * Increase the size of the type table. - */ -static void -__grow_type_table(struct typetable *types) -{ - enum typeid *const oldtable = types->table; - const int oldsize = types->tablesize; - enum typeid *newtable; - int n, newsize = oldsize * 2; - - if (newsize < types->nextarg + 1) - newsize = types->nextarg + 1; - if (oldsize == STATIC_ARG_TBL_SIZE) { - if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) - abort(); /* XXX handle better */ - bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); - } else { - newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); - if (newtable == NULL) - abort(); /* XXX handle better */ - } - for (n = oldsize; n < newsize; n++) - newtable[n] = T_UNUSED; - - types->table = newtable; - types->tablesize = newsize; -} - #ifndef NO_FLOATING_POINT diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c index a207f8c..eb51c6d 100644 --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -64,57 +64,7 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" #include "local.h" #include "fvwrite.h" - -union arg { - int intarg; - u_int uintarg; - long longarg; - u_long ulongarg; - long long longlongarg; - unsigned long long ulonglongarg; - ptrdiff_t ptrdiffarg; - size_t sizearg; - intmax_t intmaxarg; - uintmax_t uintmaxarg; - void *pvoidarg; - char *pchararg; - signed char *pschararg; - short *pshortarg; - int *pintarg; - long *plongarg; - long long *plonglongarg; - ptrdiff_t *pptrdiffarg; - size_t *psizearg; - intmax_t *pintmaxarg; -#ifndef NO_FLOATING_POINT - double doublearg; - long double longdoublearg; -#endif - wint_t wintarg; - wchar_t *pwchararg; -}; - -/* - * Type ids for argument type table. - */ -enum typeid { - T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, - T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, - T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, - T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, - T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR -}; - -#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ - -/* An expandable array of types. */ -struct typetable { - enum typeid *table; /* table of types */ - enum typeid stattable[STATIC_ARG_TBL_SIZE]; - int tablesize; /* current size of type table */ - int tablemax; /* largest used index in table */ - int nextarg; /* 1-based argument index */ -}; +#include "printflocal.h" static int __sbprintf(FILE *, const wchar_t *, va_list); static wint_t __xfputwc(wchar_t, FILE *); @@ -123,8 +73,6 @@ static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int, static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int, char, const char *); static wchar_t *__mbsconv(char *, int); -static void __find_arguments(const wchar_t *, va_list, union arg **); -static void __grow_type_table(struct typetable *); /* * Helper function for `fprintf to unbuffered unix file': creates a @@ -191,13 +139,6 @@ __xfputwc(wchar_t wc, FILE *fp) } /* - * Macros for converting digits to letters and vice versa - */ -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -/* * Convert an unsigned long to ASCII for printf purposes, returning * a pointer to the first character of the string representation. * Octal numbers can be forced to have a leading zero; hex numbers @@ -464,24 +405,6 @@ static int exponent(wchar_t *, int, wchar_t); #define BUF 100 /* - * Flags used during conversion. - */ -#define ALT 0x001 /* alternate form */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGDBL 0x008 /* long double */ -#define LONGINT 0x010 /* long integer */ -#define LLONGINT 0x020 /* long long integer */ -#define SHORTINT 0x040 /* short integer */ -#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ -#define FPT 0x100 /* Floating point number */ -#define GROUPING 0x200 /* use grouping ("'" flag) */ - /* C99 additional size modifiers: */ -#define SIZET 0x400 /* size_t */ -#define PTRDIFFT 0x800 /* ptrdiff_t */ -#define INTMAXT 0x1000 /* intmax_t */ -#define CHARINT 0x2000 /* print char using int format */ - -/* * Non-MT-safe version */ int @@ -636,7 +559,7 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) int hold = nextarg; \ if (argtable == NULL) { \ argtable = statargtable; \ - __find_arguments (fmt0, orgap, &argtable); \ + __find_warguments (fmt0, orgap, &argtable); \ } \ nextarg = n2; \ val = GETARG (int); \ @@ -760,7 +683,7 @@ reswitch: switch (ch) { nextarg = n; if (argtable == NULL) { argtable = statargtable; - __find_arguments (fmt0, orgap, + __find_warguments (fmt0, orgap, &argtable); } goto rflag; @@ -1256,414 +1179,6 @@ error: /* NOTREACHED */ } -/* - * Initialize a struct typetable. - */ -static inline void -inittypes(struct typetable *types) -{ - int n; - - types->table = types->stattable; - types->tablesize = STATIC_ARG_TBL_SIZE; - types->tablemax = 0; - types->nextarg = 1; - for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) - types->table[n] = T_UNUSED; -} - -/* - * struct typetable destructor. - */ -static inline void -freetypes(struct typetable *types) -{ - - if (types->table != types->stattable) - free(types->table); -} - -/* - * Add an argument type to the table, expanding if necessary. - */ -static inline void -addtype(struct typetable *types, enum typeid type) -{ - - if (types->nextarg >= types->tablesize) - __grow_type_table(types); - if (types->nextarg > types->tablemax) - types->tablemax = types->nextarg; - types->table[types->nextarg++] = type; -} - -static inline void -addsarg(struct typetable *types, int flags) -{ - - if (flags & INTMAXT) - addtype(types, T_INTMAXT); - else if (flags & SIZET) - addtype(types, T_SIZET); - else if (flags & PTRDIFFT) - addtype(types, T_PTRDIFFT); - else if (flags & LLONGINT) - addtype(types, T_LLONG); - else if (flags & LONGINT) - addtype(types, T_LONG); - else - addtype(types, T_INT); -} - -static inline void -adduarg(struct typetable *types, int flags) -{ - - if (flags & INTMAXT) - addtype(types, T_UINTMAXT); - else if (flags & SIZET) - addtype(types, T_SIZET); - else if (flags & PTRDIFFT) - addtype(types, T_PTRDIFFT); - else if (flags & LLONGINT) - addtype(types, T_U_LLONG); - else if (flags & LONGINT) - addtype(types, T_U_LONG); - else - addtype(types, T_U_INT); -} - -/* - * Add * arguments to the type array. - */ -static inline void -addaster(struct typetable *types, wchar_t **fmtp) -{ - wchar_t *cp; - int n2; - - n2 = 0; - cp = *fmtp; - while (is_digit(*cp)) { - n2 = 10 * n2 + to_digit(*cp); - cp++; - } - if (*cp == '$') { - int hold = types->nextarg; - types->nextarg = n2; - addtype(types, T_INT); - types->nextarg = hold; - *fmtp = ++cp; - } else { - addtype(types, T_INT); - } -} - -/* - * Find all arguments when a positional parameter is encountered. Returns a - * table, indexed by argument number, of pointers to each arguments. The - * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. - * It will be replaces with a malloc-ed one if it overflows. - */ -static void -__find_arguments (const wchar_t *fmt0, va_list ap, union arg **argtable) -{ - wchar_t *fmt; /* format string */ - wchar_t ch; /* character from fmt */ - int n; /* handy integer (short term usage) */ - int flags; /* flags as above */ - int width; /* width from format (%8d), or 0 */ - struct typetable types; /* table of types */ - - fmt = (wchar_t *)fmt0; - inittypes(&types); - - /* - * Scan the format for conversions (`%' character). - */ - for (;;) { - while ((ch = *fmt) != '\0' && ch != '%') - fmt++; - if (ch == '\0') - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - width = 0; - -rflag: ch = *fmt++; -reswitch: switch (ch) { - case ' ': - case '#': - goto rflag; - case '*': - addaster(&types, &fmt); - goto rflag; - case '-': - case '+': - case '\'': - goto rflag; - case '.': - if ((ch = *fmt++) == '*') { - addaster(&types, &fmt); - goto rflag; - } - while (is_digit(ch)) { - ch = *fmt++; - } - goto reswitch; - case '0': - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } while (is_digit(ch)); - if (ch == '$') { - types.nextarg = n; - goto rflag; - } - width = n; - goto reswitch; -#ifndef NO_FLOATING_POINT - case 'L': - flags |= LONGDBL; - goto rflag; -#endif - case 'h': - if (flags & SHORTINT) { - flags &= ~SHORTINT; - flags |= CHARINT; - } else - flags |= SHORTINT; - goto rflag; - case 'j': - flags |= INTMAXT; - goto rflag; - case 'l': - if (flags & LONGINT) { - flags &= ~LONGINT; - flags |= LLONGINT; - } else - flags |= LONGINT; - goto rflag; - case 'q': - flags |= LLONGINT; /* not necessarily */ - goto rflag; - case 't': - flags |= PTRDIFFT; - goto rflag; - case 'z': - flags |= SIZET; - goto rflag; - case 'C': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'c': - if (flags & LONGINT) - addtype(&types, T_WINT); - else - addtype(&types, T_INT); - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - addsarg(&types, flags); - break; -#ifndef NO_FLOATING_POINT - case 'a': - case 'A': - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (flags & LONGDBL) - addtype(&types, T_LONG_DOUBLE); - else - addtype(&types, T_DOUBLE); - break; -#endif /* !NO_FLOATING_POINT */ - case 'n': - if (flags & INTMAXT) - addtype(&types, TP_INTMAXT); - else if (flags & PTRDIFFT) - addtype(&types, TP_PTRDIFFT); - else if (flags & SIZET) - addtype(&types, TP_SIZET); - else if (flags & LLONGINT) - addtype(&types, TP_LLONG); - else if (flags & LONGINT) - addtype(&types, TP_LONG); - else if (flags & SHORTINT) - addtype(&types, TP_SHORT); - else if (flags & CHARINT) - addtype(&types, TP_SCHAR); - else - addtype(&types, TP_INT); - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - adduarg(&types, flags); - break; - case 'p': - addtype(&types, TP_VOID); - break; - case 'S': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 's': - if (flags & LONGINT) - addtype(&types, TP_WCHAR); - else - addtype(&types, TP_CHAR); - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - case 'X': - case 'x': - adduarg(&types, flags); - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - break; - } - } -done: - /* - * Build the argument table. - */ - if (types.tablemax >= STATIC_ARG_TBL_SIZE) { - *argtable = (union arg *) - malloc (sizeof (union arg) * (types.tablemax + 1)); - } - - (*argtable) [0].intarg = 0; - for (n = 1; n <= types.tablemax; n++) { - switch (types.table[n]) { - case T_UNUSED: /* whoops! */ - (*argtable) [n].intarg = va_arg (ap, int); - break; - case TP_SCHAR: - (*argtable) [n].pschararg = va_arg (ap, signed char *); - break; - case TP_SHORT: - (*argtable) [n].pshortarg = va_arg (ap, short *); - break; - case T_INT: - (*argtable) [n].intarg = va_arg (ap, int); - break; - case T_U_INT: - (*argtable) [n].uintarg = va_arg (ap, unsigned int); - break; - case TP_INT: - (*argtable) [n].pintarg = va_arg (ap, int *); - break; - case T_LONG: - (*argtable) [n].longarg = va_arg (ap, long); - break; - case T_U_LONG: - (*argtable) [n].ulongarg = va_arg (ap, unsigned long); - break; - case TP_LONG: - (*argtable) [n].plongarg = va_arg (ap, long *); - break; - case T_LLONG: - (*argtable) [n].longlongarg = va_arg (ap, long long); - break; - case T_U_LLONG: - (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long); - break; - case TP_LLONG: - (*argtable) [n].plonglongarg = va_arg (ap, long long *); - break; - case T_PTRDIFFT: - (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); - break; - case TP_PTRDIFFT: - (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); - break; - case T_SIZET: - (*argtable) [n].sizearg = va_arg (ap, size_t); - break; - case TP_SIZET: - (*argtable) [n].psizearg = va_arg (ap, size_t *); - break; - case T_INTMAXT: - (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); - break; - case T_UINTMAXT: - (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); - break; - case TP_INTMAXT: - (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); - break; - case T_DOUBLE: -#ifndef NO_FLOATING_POINT - (*argtable) [n].doublearg = va_arg (ap, double); -#endif - break; - case T_LONG_DOUBLE: -#ifndef NO_FLOATING_POINT - (*argtable) [n].longdoublearg = va_arg (ap, long double); -#endif - break; - case TP_CHAR: - (*argtable) [n].pchararg = va_arg (ap, char *); - break; - case TP_VOID: - (*argtable) [n].pvoidarg = va_arg (ap, void *); - break; - case T_WINT: - (*argtable) [n].wintarg = va_arg (ap, wint_t); - break; - case TP_WCHAR: - (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); - break; - } - } - - freetypes(&types); -} - -/* - * Increase the size of the type table. - */ -static void -__grow_type_table(struct typetable *types) -{ - enum typeid *const oldtable = types->table; - const int oldsize = types->tablesize; - enum typeid *newtable; - int n, newsize = oldsize * 2; - - if (newsize < types->nextarg + 1) - newsize = types->nextarg + 1; - if (oldsize == STATIC_ARG_TBL_SIZE) { - if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) - abort(); /* XXX handle better */ - bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); - } else { - newtable = reallocf(oldtable, newsize * sizeof(enum typeid)); - if (newtable == NULL) - abort(); /* XXX handle better */ - } - for (n = oldsize; n < newsize; n++) - newtable[n] = T_UNUSED; - - types->table = newtable; - types->tablesize = newsize; -} - #ifndef NO_FLOATING_POINT |