diff options
Diffstat (limited to 'contrib/sendmail/libsm/vfprintf.c')
-rw-r--r-- | contrib/sendmail/libsm/vfprintf.c | 1118 |
1 files changed, 0 insertions, 1118 deletions
diff --git a/contrib/sendmail/libsm/vfprintf.c b/contrib/sendmail/libsm/vfprintf.c deleted file mode 100644 index c4ca9bb..0000000 --- a/contrib/sendmail/libsm/vfprintf.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* - * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1990 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - */ - -#include <sm/gen.h> -SM_IDSTR(id, "@(#)$Id: vfprintf.c,v 1.54 2005/05/16 03:52:00 ca Exp $") - -/* -** Overall: -** Actual printing innards. -** This code is large and complicated... -*/ - -#include <sys/types.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <sm/config.h> -#include <sm/varargs.h> -#include <sm/io.h> -#include <sm/heap.h> -#include <sm/conf.h> -#include "local.h" -#include "fvwrite.h" - -static int sm_bprintf __P((SM_FILE_T *, const char *, va_list)); -static void sm_find_arguments __P((const char *, va_list , va_list **)); -static void sm_grow_type_table_x __P((unsigned char **, int *)); -static int sm_print __P((SM_FILE_T *, int, struct sm_uio *)); - -/* -** SM_PRINT -- print/flush to the file -** -** Flush out all the vectors defined by the given uio, -** then reset it so that it can be reused. -** -** Parameters: -** fp -- file pointer -** timeout -- time to complete operation (milliseconds) -** uio -- vector list of memory locations of data for printing -** -** Results: -** Success: 0 (zero) -** Failure: -*/ - -static int -sm_print(fp, timeout, uio) - SM_FILE_T *fp; - int timeout; - register struct sm_uio *uio; -{ - register int err; - - if (uio->uio_resid == 0) - { - uio->uio_iovcnt = 0; - return 0; - } - err = sm_fvwrite(fp, timeout, uio); - uio->uio_resid = 0; - uio->uio_iovcnt = 0; - return err; -} - -/* -** SM_BPRINTF -- allow formating to an unbuffered file. -** -** Helper function for `fprintf to unbuffered unix file': creates a -** temporary buffer (via a "fake" file pointer). -** We only work on write-only files; this avoids -** worries about ungetc buffers and so forth. -** -** Parameters: -** fp -- the file to send the o/p to -** fmt -- format instructions for the o/p -** ap -- vectors of data units used for formating -** -** Results: -** Failure: SM_IO_EOF and errno set -** Success: number of data units used in the formating -** -** Side effects: -** formatted o/p can be SM_IO_BUFSIZ length maximum -*/ - -static int -sm_bprintf(fp, fmt, ap) - SM_FILE_T *fp; - const char *fmt; - SM_VA_LOCAL_DECL -{ - int ret; - SM_FILE_T fake; - unsigned char buf[SM_IO_BUFSIZ]; - extern const char SmFileMagic[]; - - /* copy the important variables */ - fake.sm_magic = SmFileMagic; - fake.f_timeout = SM_TIME_FOREVER; - fake.f_timeoutstate = SM_TIME_BLOCK; - fake.f_flags = fp->f_flags & ~SMNBF; - fake.f_file = fp->f_file; - fake.f_cookie = fp->f_cookie; - fake.f_write = fp->f_write; - fake.f_close = NULL; - fake.f_open = NULL; - fake.f_read = NULL; - fake.f_seek = NULL; - fake.f_setinfo = fake.f_getinfo = NULL; - fake.f_type = "sm_bprintf:fake"; - - /* set up the buffer */ - fake.f_bf.smb_base = fake.f_p = buf; - fake.f_bf.smb_size = fake.f_w = sizeof(buf); - fake.f_lbfsize = 0; /* not actually used, but Just In Case */ - - /* do the work, then copy any error status */ - ret = sm_io_vfprintf(&fake, SM_TIME_FOREVER, fmt, ap); - if (ret >= 0 && sm_io_flush(&fake, SM_TIME_FOREVER)) - ret = SM_IO_EOF; /* errno set by sm_io_flush */ - if (fake.f_flags & SMERR) - fp->f_flags |= SMERR; - return ret; -} - - -#define BUF 40 - -#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ - - -/* 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) ((char) (n) + '0') - -/* Flags used during conversion. */ -#define ALT 0x001 /* alternate form */ -#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGINT 0x010 /* long integer */ -#define QUADINT 0x020 /* quad integer */ -#define SHORTINT 0x040 /* short integer */ -#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ -#define FPT 0x100 /* Floating point number */ - -/* -** SM_IO_VPRINTF -- performs actual formating for o/p -** -** Parameters: -** fp -- file pointer for o/p -** timeout -- time to complete the print -** fmt0 -- formating directives -** ap -- vectors with data units for formating -** -** Results: -** Success: number of data units used for formatting -** Failure: SM_IO_EOF and sets errno -*/ - -int -sm_io_vfprintf(fp, timeout, fmt0, ap) - SM_FILE_T *fp; - int timeout; - const char *fmt0; - SM_VA_LOCAL_DECL -{ - register char *fmt; /* format string */ - register int ch; /* character from fmt */ - register int n, m, n2; /* handy integers (short term usage) */ - register char *cp; /* handy char pointer (short term usage) */ - register struct sm_iov *iovp;/* for PRINT macro */ - register int flags; /* flags as above */ - int ret; /* return value accumulator */ - int width; /* width from format (%8d), or 0 */ - int prec; /* precision from format (%.3d), or -1 */ - char sign; /* sign prefix (' ', '+', '-', or \0) */ - wchar_t wc; - ULONGLONG_T _uquad; /* integer arguments %[diouxX] */ - enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */ - int dprec; /* a copy of prec if [diouxX], 0 otherwise */ - int realsz; /* field size expanded by dprec */ - int size; /* size of converted field or string */ - char *xdigs="0123456789abcdef"; /* digits for [xX] conversion */ -#define NIOV 8 - struct sm_uio uio; /* output information: summary */ - struct sm_iov iov[NIOV];/* ... and individual io vectors */ - char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ - char ox[2]; /* space for 0x hex-prefix */ - va_list *argtable; /* args, built due to positional arg */ - va_list statargtable[STATIC_ARG_TBL_SIZE]; - int nextarg; /* 1-based argument index */ - va_list orgap; /* original argument pointer */ - - /* - ** Choose PADSIZE to trade efficiency vs. size. If larger printf - ** fields occur frequently, increase PADSIZE and make the initialisers - ** below longer. - */ -#define PADSIZE 16 /* pad chunk size */ - static char blanks[PADSIZE] = - {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; - static char zeroes[PADSIZE] = - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - - /* - ** BEWARE, these `goto error' on error, and PAD uses `n'. - */ -#define PRINT(ptr, len) do { \ - iovp->iov_base = (ptr); \ - iovp->iov_len = (len); \ - uio.uio_resid += (len); \ - iovp++; \ - if (++uio.uio_iovcnt >= NIOV) \ - { \ - if (sm_print(fp, timeout, &uio)) \ - goto error; \ - iovp = iov; \ - } \ -} while (0) -#define PAD(howmany, with) do \ -{ \ - if ((n = (howmany)) > 0) \ - { \ - while (n > PADSIZE) { \ - PRINT(with, PADSIZE); \ - n -= PADSIZE; \ - } \ - PRINT(with, n); \ - } \ -} while (0) -#define FLUSH() do \ -{ \ - if (uio.uio_resid && sm_print(fp, timeout, &uio)) \ - goto error; \ - uio.uio_iovcnt = 0; \ - iovp = iov; \ -} while (0) - - /* - ** To extend shorts properly, we need both signed and unsigned - ** argument extraction methods. - */ -#define SARG() \ - (flags&QUADINT ? SM_VA_ARG(ap, LONGLONG_T) : \ - flags&LONGINT ? GETARG(long) : \ - flags&SHORTINT ? (long) (short) GETARG(int) : \ - (long) GETARG(int)) -#define UARG() \ - (flags&QUADINT ? SM_VA_ARG(ap, ULONGLONG_T) : \ - flags&LONGINT ? GETARG(unsigned long) : \ - flags&SHORTINT ? (unsigned long) (unsigned short) GETARG(int) : \ - (unsigned long) GETARG(unsigned int)) - - /* - ** Get * arguments, including the form *nn$. Preserve the nextarg - ** that the argument can be gotten once the type is determined. - */ -#define GETASTER(val) \ - n2 = 0; \ - cp = fmt; \ - while (is_digit(*cp)) \ - { \ - n2 = 10 * n2 + to_digit(*cp); \ - cp++; \ - } \ - if (*cp == '$') \ - { \ - int hold = nextarg; \ - if (argtable == NULL) \ - { \ - argtable = statargtable; \ - sm_find_arguments(fmt0, orgap, &argtable); \ - } \ - nextarg = n2; \ - val = GETARG(int); \ - nextarg = hold; \ - fmt = ++cp; \ - } \ - else \ - { \ - val = GETARG(int); \ - } - -/* -** Get the argument indexed by nextarg. If the argument table is -** built, use it to get the argument. If its not, get the next -** argument (and arguments must be gotten sequentially). -*/ - -#if SM_VA_STD -# define GETARG(type) \ - (((argtable != NULL) ? (void) (ap = argtable[nextarg]) : (void) 0), \ - nextarg++, SM_VA_ARG(ap, type)) -#else /* SM_VA_STD */ -# define GETARG(type) \ - ((argtable != NULL) ? (*((type*)(argtable[nextarg++]))) : \ - (nextarg++, SM_VA_ARG(ap, type))) -#endif /* SM_VA_STD */ - - /* sorry, fprintf(read_only_file, "") returns SM_IO_EOF, not 0 */ - if (cantwrite(fp)) - { - errno = EBADF; - return SM_IO_EOF; - } - - /* optimise fprintf(stderr) (and other unbuffered Unix files) */ - if ((fp->f_flags & (SMNBF|SMWR|SMRW)) == (SMNBF|SMWR) && - fp->f_file >= 0) - return sm_bprintf(fp, fmt0, ap); - - fmt = (char *) fmt0; - argtable = NULL; - nextarg = 1; - SM_VA_COPY(orgap, ap); - uio.uio_iov = iovp = iov; - uio.uio_resid = 0; - uio.uio_iovcnt = 0; - ret = 0; - - /* Scan the format for conversions (`%' character). */ - for (;;) - { - cp = fmt; - n = 0; - while ((wc = *fmt) != '\0') - { - if (wc == '%') - { - n = 1; - break; - } - fmt++; - } - if ((m = fmt - cp) != 0) - { - PRINT(cp, m); - ret += m; - } - if (n <= 0) - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - dprec = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: ch = *fmt++; -reswitch: switch (ch) - { - case ' ': - - /* - ** ``If the space and + flags both appear, the space - ** flag will be ignored.'' - ** -- ANSI X3J11 - */ - - if (!sign) - sign = ' '; - goto rflag; - case '#': - flags |= ALT; - goto rflag; - case '*': - - /* - ** ``A negative field width argument is taken as a - ** - flag followed by a positive field width.'' - ** -- ANSI X3J11 - ** They don't exclude field widths read from args. - */ - - GETASTER(width); - if (width >= 0) - goto rflag; - width = -width; - /* FALLTHROUGH */ - case '-': - flags |= LADJUST; - goto rflag; - case '+': - sign = '+'; - goto rflag; - case '.': - if ((ch = *fmt++) == '*') - { - GETASTER(n); - prec = n < 0 ? -1 : n; - goto rflag; - } - n = 0; - while (is_digit(ch)) - { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } - if (ch == '$') - { - nextarg = n; - if (argtable == NULL) - { - argtable = statargtable; - sm_find_arguments(fmt0, orgap, - &argtable); - } - goto rflag; - } - prec = n < 0 ? -1 : n; - goto reswitch; - case '0': - - /* - ** ``Note that 0 is taken as a flag, not as the - ** beginning of a field width.'' - ** -- ANSI X3J11 - */ - - flags |= ZEROPAD; - 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 == '$') - { - nextarg = n; - if (argtable == NULL) - { - argtable = statargtable; - sm_find_arguments(fmt0, orgap, - &argtable); - } - goto rflag; - } - width = n; - goto reswitch; - case 'h': - flags |= SHORTINT; - goto rflag; - case 'l': - if (*fmt == 'l') - { - fmt++; - flags |= QUADINT; - } - else - { - flags |= LONGINT; - } - goto rflag; - case 'q': - flags |= QUADINT; - goto rflag; - case 'c': - *(cp = buf) = GETARG(int); - size = 1; - sign = '\0'; - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - _uquad = SARG(); - if ((LONGLONG_T) _uquad < 0) - { - _uquad = -(LONGLONG_T) _uquad; - sign = '-'; - } - base = DEC; - goto number; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - { - double val; - char *p; - char fmt[16]; - char out[150]; - size_t len; - - /* - ** This code implements floating point output - ** in the most portable manner possible, - ** relying only on 'sprintf' as defined by - ** the 1989 ANSI C standard. - ** We silently cap width and precision - ** at 120, to avoid buffer overflow. - */ - - val = GETARG(double); - - p = fmt; - *p++ = '%'; - if (sign) - *p++ = sign; - if (flags & ALT) - *p++ = '#'; - if (flags & LADJUST) - *p++ = '-'; - if (flags & ZEROPAD) - *p++ = '0'; - *p++ = '*'; - if (prec >= 0) - { - *p++ = '.'; - *p++ = '*'; - } - *p++ = ch; - *p = '\0'; - - if (width > 120) - width = 120; - if (prec > 120) - prec = 120; - if (prec >= 0) -#if HASSNPRINTF - snprintf(out, sizeof(out), fmt, width, - prec, val); -#else /* HASSNPRINTF */ - sprintf(out, fmt, width, prec, val); -#endif /* HASSNPRINTF */ - else -#if HASSNPRINTF - snprintf(out, sizeof(out), fmt, width, - val); -#else /* HASSNPRINTF */ - sprintf(out, fmt, width, val); -#endif /* HASSNPRINTF */ - len = strlen(out); - PRINT(out, len); - FLUSH(); - continue; - } - case 'n': - if (flags & QUADINT) - *GETARG(LONGLONG_T *) = ret; - else if (flags & LONGINT) - *GETARG(long *) = ret; - else if (flags & SHORTINT) - *GETARG(short *) = ret; - else - *GETARG(int *) = ret; - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - _uquad = UARG(); - base = OCT; - goto nosign; - case 'p': - - /* - ** ``The argument shall be a pointer to void. The - ** value of the pointer is converted to a sequence - ** of printable characters, in an implementation- - ** defined manner.'' - ** -- ANSI X3J11 - */ - - /* NOSTRICT */ - { - union - { - void *p; - ULONGLONG_T ll; - unsigned long l; - unsigned i; - } u; - u.p = GETARG(void *); - if (sizeof(void *) == sizeof(ULONGLONG_T)) - _uquad = u.ll; - else if (sizeof(void *) == sizeof(long)) - _uquad = u.l; - else - _uquad = u.i; - } - base = HEX; - xdigs = "0123456789abcdef"; - flags |= HEXPREFIX; - ch = 'x'; - goto nosign; - case 's': - if ((cp = GETARG(char *)) == NULL) - cp = "(null)"; - if (prec >= 0) - { - /* - ** can't use strlen; can only look for the - ** NUL in the first `prec' characters, and - ** strlen() will go further. - */ - - char *p = memchr(cp, 0, prec); - - if (p != NULL) - { - size = p - cp; - if (size > prec) - size = prec; - } - else - size = prec; - } - else - size = strlen(cp); - sign = '\0'; - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - _uquad = UARG(); - base = DEC; - goto nosign; - case 'X': - xdigs = "0123456789ABCDEF"; - goto hex; - case 'x': - xdigs = "0123456789abcdef"; -hex: _uquad = UARG(); - base = HEX; - /* leading 0x/X only if non-zero */ - if (flags & ALT && _uquad != 0) - flags |= HEXPREFIX; - - /* unsigned conversions */ -nosign: sign = '\0'; - - /* - ** ``... diouXx conversions ... if a precision is - ** specified, the 0 flag will be ignored.'' - ** -- ANSI X3J11 - */ - -number: if ((dprec = prec) >= 0) - flags &= ~ZEROPAD; - - /* - ** ``The result of converting a zero value with an - ** explicit precision of zero is no characters.'' - ** -- ANSI X3J11 - */ - - cp = buf + BUF; - if (_uquad != 0 || prec != 0) - { - /* - ** Unsigned mod is hard, and unsigned mod - ** by a constant is easier than that by - ** a variable; hence this switch. - */ - - switch (base) - { - case OCT: - do - { - *--cp = to_char(_uquad & 7); - _uquad >>= 3; - } while (_uquad); - /* handle octal leading 0 */ - if (flags & ALT && *cp != '0') - *--cp = '0'; - break; - - case DEC: - /* many numbers are 1 digit */ - while (_uquad >= 10) - { - *--cp = to_char(_uquad % 10); - _uquad /= 10; - } - *--cp = to_char(_uquad); - break; - - case HEX: - do - { - *--cp = xdigs[_uquad & 15]; - _uquad >>= 4; - } while (_uquad); - break; - - default: - cp = "bug in sm_io_vfprintf: bad base"; - size = strlen(cp); - goto skipsize; - } - } - size = buf + BUF - cp; - skipsize: - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - /* pretend it was %c with argument ch */ - cp = buf; - *cp = ch; - size = 1; - sign = '\0'; - break; - } - - /* - ** All reasonable formats wind up here. At this point, `cp' - ** points to a string which (if not flags&LADJUST) should be - ** padded out to `width' places. If flags&ZEROPAD, it should - ** first be prefixed by any sign or other prefix; otherwise, - ** it should be blank padded before the prefix is emitted. - ** After any left-hand padding and prefixing, emit zeroes - ** required by a decimal [diouxX] precision, then print the - ** string proper, then emit zeroes required by any leftover - ** floating precision; finally, if LADJUST, pad with blanks. - ** - ** Compute actual size, so we know how much to pad. - ** size excludes decimal prec; realsz includes it. - */ - - realsz = dprec > size ? dprec : size; - if (sign) - realsz++; - else if (flags & HEXPREFIX) - realsz+= 2; - - /* right-adjusting blank padding */ - if ((flags & (LADJUST|ZEROPAD)) == 0) - PAD(width - realsz, blanks); - - /* prefix */ - if (sign) - { - PRINT(&sign, 1); - } - else if (flags & HEXPREFIX) - { - ox[0] = '0'; - ox[1] = ch; - PRINT(ox, 2); - } - - /* right-adjusting zero padding */ - if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) - PAD(width - realsz, zeroes); - - /* leading zeroes from decimal precision */ - PAD(dprec - size, zeroes); - - /* the string or number proper */ - PRINT(cp, size); - /* left-adjusting padding (always blank) */ - if (flags & LADJUST) - PAD(width - realsz, blanks); - - /* finally, adjust ret */ - ret += width > realsz ? width : realsz; - - FLUSH(); /* copy out the I/O vectors */ - } -done: - FLUSH(); -error: - if ((argtable != NULL) && (argtable != statargtable)) - sm_free(argtable); - return sm_error(fp) ? SM_IO_EOF : ret; - /* NOTREACHED */ -} - -/* Type ids for argument type table. */ -#define T_UNUSED 0 -#define T_SHORT 1 -#define T_U_SHORT 2 -#define TP_SHORT 3 -#define T_INT 4 -#define T_U_INT 5 -#define TP_INT 6 -#define T_LONG 7 -#define T_U_LONG 8 -#define TP_LONG 9 -#define T_QUAD 10 -#define T_U_QUAD 11 -#define TP_QUAD 12 -#define T_DOUBLE 13 -#define TP_CHAR 15 -#define TP_VOID 16 - -/* -** SM_FIND_ARGUMENTS -- find all args when a positional parameter is found. -** -** 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 replaced with a malloc-ed one if it overflows. -** -** Parameters: -** fmt0 -- formating directives -** ap -- vector list of data unit for formating consumption -** argtable -- an indexable table (returned) of 'ap' -** -** Results: -** none. -*/ - -static void -sm_find_arguments(fmt0, ap, argtable) - const char *fmt0; - SM_VA_LOCAL_DECL - va_list **argtable; -{ - register char *fmt; /* format string */ - register int ch; /* character from fmt */ - register int n, n2; /* handy integer (short term usage) */ - register char *cp; /* handy char pointer (short term usage) */ - register int flags; /* flags as above */ - unsigned char *typetable; /* table of types */ - unsigned char stattypetable[STATIC_ARG_TBL_SIZE]; - int tablesize; /* current size of type table */ - int tablemax; /* largest used index in table */ - int nextarg; /* 1-based argument index */ - - /* Add an argument type to the table, expanding if necessary. */ -#define ADDTYPE(type) \ - ((nextarg >= tablesize) ? \ - (sm_grow_type_table_x(&typetable, &tablesize), 0) : 0, \ - typetable[nextarg++] = type, \ - (nextarg > tablemax) ? tablemax = nextarg : 0) - -#define ADDSARG() \ - ((flags & LONGINT) ? ADDTYPE(T_LONG) : \ - ((flags & SHORTINT) ? ADDTYPE(T_SHORT) : ADDTYPE(T_INT))) - -#define ADDUARG() \ - ((flags & LONGINT) ? ADDTYPE(T_U_LONG) : \ - ((flags & SHORTINT) ? ADDTYPE(T_U_SHORT) : ADDTYPE(T_U_INT))) - - /* Add * arguments to the type array. */ -#define ADDASTER() \ - n2 = 0; \ - cp = fmt; \ - while (is_digit(*cp)) \ - { \ - n2 = 10 * n2 + to_digit(*cp); \ - cp++; \ - } \ - if (*cp == '$') \ - { \ - int hold = nextarg; \ - nextarg = n2; \ - ADDTYPE (T_INT); \ - nextarg = hold; \ - fmt = ++cp; \ - } \ - else \ - { \ - ADDTYPE (T_INT); \ - } - fmt = (char *) fmt0; - typetable = stattypetable; - tablesize = STATIC_ARG_TBL_SIZE; - tablemax = 0; - nextarg = 1; - (void) memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); - - /* Scan the format for conversions (`%' character). */ - for (;;) - { - for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) - /* void */; - if (ch == '\0') - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - -rflag: ch = *fmt++; -reswitch: switch (ch) - { - case ' ': - case '#': - goto rflag; - case '*': - ADDASTER(); - goto rflag; - case '-': - case '+': - goto rflag; - case '.': - if ((ch = *fmt++) == '*') - { - ADDASTER(); - 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 == '$') - { - nextarg = n; - goto rflag; - } - goto reswitch; - case 'h': - flags |= SHORTINT; - goto rflag; - case 'l': - flags |= LONGINT; - goto rflag; - case 'q': - flags |= QUADINT; - goto rflag; - case 'c': - ADDTYPE(T_INT); - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - if (flags & QUADINT) - { - ADDTYPE(T_QUAD); - } - else - { - ADDSARG(); - } - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - ADDTYPE(T_DOUBLE); - break; - case 'n': - if (flags & QUADINT) - ADDTYPE(TP_QUAD); - else if (flags & LONGINT) - ADDTYPE(TP_LONG); - else if (flags & SHORTINT) - ADDTYPE(TP_SHORT); - else - ADDTYPE(TP_INT); - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - if (flags & QUADINT) - ADDTYPE(T_U_QUAD); - else - ADDUARG(); - break; - case 'p': - ADDTYPE(TP_VOID); - break; - case 's': - ADDTYPE(TP_CHAR); - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - if (flags & QUADINT) - ADDTYPE(T_U_QUAD); - else - ADDUARG(); - break; - case 'X': - case 'x': - if (flags & QUADINT) - ADDTYPE(T_U_QUAD); - else - ADDUARG(); - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - break; - } - } -done: - /* Build the argument table. */ - if (tablemax >= STATIC_ARG_TBL_SIZE) - { - *argtable = (va_list *) - sm_malloc(sizeof(va_list) * (tablemax + 1)); - } - - for (n = 1; n <= tablemax; n++) - { - SM_VA_COPY((*argtable)[n], ap); - switch (typetable [n]) - { - case T_UNUSED: - (void) SM_VA_ARG(ap, int); - break; - case T_SHORT: - (void) SM_VA_ARG(ap, int); - break; - case T_U_SHORT: - (void) SM_VA_ARG(ap, int); - break; - case TP_SHORT: - (void) SM_VA_ARG(ap, short *); - break; - case T_INT: - (void) SM_VA_ARG(ap, int); - break; - case T_U_INT: - (void) SM_VA_ARG(ap, unsigned int); - break; - case TP_INT: - (void) SM_VA_ARG(ap, int *); - break; - case T_LONG: - (void) SM_VA_ARG(ap, long); - break; - case T_U_LONG: - (void) SM_VA_ARG(ap, unsigned long); - break; - case TP_LONG: - (void) SM_VA_ARG(ap, long *); - break; - case T_QUAD: - (void) SM_VA_ARG(ap, LONGLONG_T); - break; - case T_U_QUAD: - (void) SM_VA_ARG(ap, ULONGLONG_T); - break; - case TP_QUAD: - (void) SM_VA_ARG(ap, LONGLONG_T *); - break; - case T_DOUBLE: - (void) SM_VA_ARG(ap, double); - break; - case TP_CHAR: - (void) SM_VA_ARG(ap, char *); - break; - case TP_VOID: - (void) SM_VA_ARG(ap, void *); - break; - } - } - - if ((typetable != NULL) && (typetable != stattypetable)) - sm_free(typetable); -} - -/* -** SM_GROW_TYPE_TABLE -- Increase the size of the type table. -** -** Parameters: -** tabletype -- type of table to grow -** tablesize -- requested new table size -** -** Results: -** Raises an exception if can't allocate memory. -*/ - -static void -sm_grow_type_table_x(typetable, tablesize) - unsigned char **typetable; - int *tablesize; -{ - unsigned char *oldtable = *typetable; - int newsize = *tablesize * 2; - - if (*tablesize == STATIC_ARG_TBL_SIZE) - { - *typetable = (unsigned char *) sm_malloc_x(sizeof(unsigned char) - * newsize); - (void) memmove(*typetable, oldtable, *tablesize); - } - else - { - *typetable = (unsigned char *) sm_realloc_x(typetable, - sizeof(unsigned char) * newsize); - } - (void) memset(&typetable [*tablesize], T_UNUSED, - (newsize - *tablesize)); - - *tablesize = newsize; -} |