gonzui


Format: Advanced Search

t2ex/bsd_source/lib/libc/src_bsd/stdio/vfprintf.cbare sourcepermlink (0.14 seconds)

Search this content:

    1: /* Reduce buffer size of __sbprintf()
    2:  */
    3: 
    4: /*      $OpenBSD: vfprintf.c,v 1.61 2011/07/06 19:53:52 stsp Exp $   */
    5: /*-
    6:  * Copyright (c) 1990 The Regents of the University of California.
    7:  * All rights reserved.
    8:  *
    9:  * This code is derived from software contributed to Berkeley by
   10:  * Chris Torek.
   11:  *
   12:  * Redistribution and use in source and binary forms, with or without
   13:  * modification, are permitted provided that the following conditions
   14:  * are met:
   15:  * 1. Redistributions of source code must retain the above copyright
   16:  *    notice, this list of conditions and the following disclaimer.
   17:  * 2. Redistributions in binary form must reproduce the above copyright
   18:  *    notice, this list of conditions and the following disclaimer in the
   19:  *    documentation and/or other materials provided with the distribution.
   20:  * 3. Neither the name of the University nor the names of its contributors
   21:  *    may be used to endorse or promote products derived from this software
   22:  *    without specific prior written permission.
   23:  *
   24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34:  * SUCH DAMAGE.
   35:  */
   36: #define FLOATING_POINT
   37: /*
   38:  * Actual printf innards.
   39:  *
   40:  * This code is large and complicated...
   41:  */
   42: 
   43: #include <sys/types.h>
   44: #include <sys/mman.h>
   45: 
   46: #include <errno.h>
   47: #include <limits.h>
   48: #include <stdarg.h>
   49: #include <stddef.h>
   50: #include <stdio.h>
   51: #include <stdint.h>
   52: #include <stdlib.h>
   53: #include <string.h>
   54: #include <unistd.h>
   55: #include <wchar.h>
   56: 
   57: #include "local.h"
   58: #include "fvwrite.h"
   59: 
   60: union arg {
   61:         int                    intarg;
   62:         unsigned int           uintarg;
   63:         long                   longarg;
   64:         unsigned long          ulongarg;
   65:         long long              longlongarg;
   66:         unsigned long long     ulonglongarg;
   67:         ptrdiff_t              ptrdiffarg;
   68:         size_t                 sizearg;
   69:         ssize_t                        ssizearg;
   70:         intmax_t               intmaxarg;
   71:         uintmax_t              uintmaxarg;
   72:         void                   *pvoidarg;
   73:         char                   *pchararg;
   74:         signed char            *pschararg;
   75:         short                  *pshortarg;
   76:         int                    *pintarg;
   77:         long                   *plongarg;
   78:         long long              *plonglongarg;
   79:         ptrdiff_t              *pptrdiffarg;
   80:         ssize_t                        *pssizearg;
   81:         intmax_t               *pintmaxarg;
   82: #ifdef FLOATING_POINT
   83:         double                 doublearg;
   84:         long double            longdoublearg;
   85: #endif
   86: #ifdef PRINTF_WIDE_CHAR
   87:         wint_t                 wintarg;
   88:         wchar_t                        *pwchararg;
   89: #endif
   90: };
   91: 
   92: static int __find_arguments(const char *fmt0, va_list ap, union arg **argtable,
   93:     size_t *argtablesiz);
   94: static int __grow_type_table(unsigned char **typetable, int *tablesize);
   95: 
   96: /*
   97:  * Flush out all the vectors defined by the given uio,
   98:  * then reset it so that it can be reused.
   99:  */
  100: static int
  101: __sprint(FILE *fp, struct __suio *uio)
  102: {
  103:         int err;
  104: 
  105:         if (uio->uio_resid == 0) {
  106:                 uio->uio_iovcnt = 0;
  107:                 return (0);
  108:         }
  109:         err = __sfvwrite(fp, uio);
  110:         uio->uio_resid = 0;
  111:         uio->uio_iovcnt = 0;
  112:         return (err);
  113: }
  114: 
  115: /*
  116:  * Helper function for `fprintf to unbuffered unix file': creates a
  117:  * temporary buffer.  We only work on write-only files; this avoids
  118:  * worries about ungetc buffers and so forth.
  119:  */
  120: static int
  121: __sbprintf(FILE *fp, const char *fmt, va_list ap)
  122: {
  123:         int ret;
  124:         FILE fake;
  125:         struct __sfileext fakeext;
  126:         unsigned char buf[128/*BUFSIZ*/];
  127: 
  128:         _FILEEXT_SETUP(&fake, &fakeext);
  129:         /* copy the important variables */
  130:         fake._flags = fp->_flags & ~__SNBF;
  131:         fake._file = fp->_file;
  132:         fake._cookie = fp->_cookie;
  133:         fake._write = fp->_write;
  134: 
  135:         /* set up the buffer */
  136:         fake._bf._base = fake._p = buf;
  137:         fake._bf._size = fake._w = sizeof(buf);
  138:         fake._lbfsize = 0;     /* not actually used, but Just In Case */
  139: 
  140:         /* do the work, then copy any error status */
  141:         ret = __vfprintf(&fake, fmt, ap);
  142:         if (ret >= 0 && __sflush(&fake))
  143:                 ret = EOF;
  144:         if (fake._flags & __SERR)
  145:                 fp->_flags |= __SERR;
  146:         return (ret);
  147: }
  148: 
  149: #ifdef PRINTF_WIDE_CHAR
  150: /*
  151:  * Convert a wide character string argument for the %ls format to a multibyte
  152:  * string representation. If not -1, prec specifies the maximum number of
  153:  * bytes to output, and also means that we can't assume that the wide char
  154:  * string is null-terminated.
  155:  */
  156: static char *
  157: __wcsconv(wchar_t *wcsarg, int prec)
  158: {
  159:         mbstate_t mbs;
  160:         char buf[MB_LEN_MAX];
  161:         wchar_t *p;
  162:         char *convbuf;
  163:         size_t clen, nbytes;
  164: 
  165:         /* Allocate space for the maximum number of bytes we could output. */
  166:         if (prec < 0) {
  167:                 memset(&mbs, 0, sizeof(mbs));
  168:                 p = wcsarg;
  169:                 nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
  170:                 if (nbytes == (size_t)-1) {
  171:                         /*errno = EILSEQ*/;
  172:                         return (NULL);
  173:                 }
  174:         } else {
  175:                 /*
  176:                  * Optimisation: if the output precision is small enough,
  177:                  * just allocate enough memory for the maximum instead of
  178:                  * scanning the string.
  179:                  */
  180:                 if (prec < 128)
  181:                         nbytes = prec;
  182:                 else {
  183:                         nbytes = 0;
  184:                         p = wcsarg;
  185:                         memset(&mbs, 0, sizeof(mbs));
  186:                         for (;;) {
  187:                                 clen = wcrtomb(buf, *p++, &mbs);
  188:                                 if (clen == 0 || clen == (size_t)-1 ||
  189:                                     nbytes + clen > (size_t)prec)
  190:                                         break;
  191:                                 nbytes += clen;
  192:                         }
  193:                         if (clen == (size_t)-1) {
  194:                                 /*errno = EILSEQ*/;
  195:                                 return (NULL);
  196:                         }
  197:                 }
  198:         }
  199:         if ((convbuf = malloc(nbytes + 1)) == NULL)
  200:                 return (NULL);
  201: 
  202:         /* Fill the output buffer. */
  203:         p = wcsarg;
  204:         memset(&mbs, 0, sizeof(mbs));
  205:         if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
  206:             nbytes, &mbs)) == (size_t)-1) {
  207:                 free(convbuf);
  208:                 /*errno = EILSEQ*/;
  209:                 return (NULL);
  210:         }
  211:         convbuf[nbytes] = '\0';
  212:         return (convbuf);
  213: }
  214: #endif
  215: 
  216: #ifdef FLOATING_POINT
  217: #include <float.h>
  218: #include <locale.h>
  219: #include <math.h>
  220: #include "floatio.h"
  221: 
  222: #define DEFPREC         6
  223: 
  224: extern char *__dtoa(double, int, int, int *, int *, char **);
  225: extern void  __freedtoa(char *);
  226: static int exponent(char *, int, int);
  227: #endif /* FLOATING_POINT */
  228: 
  229: /*
  230:  * The size of the buffer we use as scratch space for integer
  231:  * conversions, among other things.  Technically, we would need the
  232:  * most space for base 10 conversions with thousands' grouping
  233:  * characters between each pair of digits.  100 bytes is a
  234:  * conservative overestimate even for a 128-bit uintmax_t.
  235:  */
  236: #define BUF     100
  237: 
  238: #define STATIC_ARG_TBL_SIZE 8   /* Size of static argument table. */
  239: 
  240: 
  241: /*
  242:  * Macros for converting digits to letters and vice versa
  243:  */
  244: #define to_digit(c)     ((c) - '0')
  245: #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
  246: #define to_char(n)      ((n) + '0')
  247: 
  248: /*
  249:  * Flags used during conversion.
  250:  */
  251: #define ALT             0x0001             /* alternate form */
  252: #define LADJUST         0x0004         /* left adjustment */
  253: #define LONGDBL         0x0008         /* long double */
  254: #define LONGINT         0x0010         /* long integer */
  255: #define LLONGINT        0x0020         /* long long integer */
  256: #define SHORTINT        0x0040         /* short integer */
  257: #define ZEROPAD         0x0080         /* zero (as opposed to blank) pad */
  258: #define FPT             0x0100             /* Floating point number */
  259: #define PTRINT          0x0200          /* (unsigned) ptrdiff_t */
  260: #define SIZEINT         0x0400         /* (signed) size_t */
  261: #define CHARINT         0x0800         /* 8 bit integer */
  262: #define MAXINT          0x1000          /* largest integer size (intmax_t) */
  263: 
  264: int
  265: vfprintf(FILE *fp, const char *fmt0, __va_list ap)
  266: {
  267:         int ret;
  268: 
  269:         FLOCKFILE(fp);
  270:         ret = __vfprintf(fp, fmt0, ap);
  271:         FUNLOCKFILE(fp);
  272:         return (ret);
  273: }
  274: 
  275: int
  276: __vfprintf(FILE *fp, const char *fmt0, __va_list ap)
  277: {
  278:         char *fmt;             /* format string */
  279:         int ch;                        /* character from fmt */
  280:         int n, n2;             /* handy integers (short term usage) */
  281:         char *cp;              /* handy char pointer (short term usage) */
  282:         struct __siov *iovp;   /* for PRINT macro */
  283:         int flags;             /* flags as above */
  284:         int ret;               /* return value accumulator */
  285:         int width;             /* width from format (%8d), or 0 */
  286:         int prec;              /* precision from format; <0 for N/A */
  287:         char sign;             /* sign prefix (' ', '+', '-', or \0) */
  288:         wchar_t wc;
  289:         mbstate_t ps;
  290: #ifdef FLOATING_POINT
  291:         /*
  292:          * We can decompose the printed representation of floating
  293:          * point numbers into several parts, some of which may be empty:
  294:          *
  295:          * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
  296:          *    A       B     ---C---      D       E   F
  297:          *
  298:          * A:  'sign' holds this value if present; '\0' otherwise
  299:          * B:  ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
  300:          * C:  cp points to the string MMMNNN.  Leading and trailing
  301:          *     zeros are not in the string and must be added.
  302:          * D:  expchar holds this character; '\0' if no exponent, e.g. %f
  303:          * F:  at least two digits for decimal, at least one digit for hex
  304:          */
  305:         char *decimal_point = /*localeconv()->decimal_point*/".";
  306:         int signflag;          /* true if float is negative */
  307:         union {                        /* floating point arguments %[aAeEfFgG] */
  308:                 double dbl;
  309:                 long double ldbl;
  310:         } fparg;
  311:         int expt;              /* integer value of exponent */
  312:         char expchar;          /* exponent character: [eEpP\0] */
  313:         char *dtoaend;         /* pointer to end of converted digits */
  314:         int expsize;           /* character count for expstr */
  315:         int lead;              /* sig figs before decimal or group sep */
  316:         int ndig;              /* actual number of digits returned by dtoa */
  317:         char expstr[MAXEXPDIG+2];      /* buffer for exponent string: e+ZZZ */
  318:         char *dtoaresult = NULL;
  319: #endif
  320: 
  321:         uintmax_t _umax;       /* integer arguments %[diouxX] */
  322:         enum { OCT, DEC, HEX } base;   /* base for %[diouxX] conversion */
  323:         int dprec;             /* a copy of prec if %[diouxX], 0 otherwise */
  324:         int realsz;            /* field size expanded by dprec */
  325:         int size;              /* size of converted field or string */
  326:         const char *xdigs;     /* digits for %[xX] conversion */
  327: #define NIOV 8
  328:         struct __suio uio;     /* output information: summary */
  329:         struct __siov iov[NIOV];/* ... and individual io vectors */
  330:         char buf[BUF];         /* buffer with space for digits of uintmax_t */
  331:         char ox[2];            /* space for 0x; ox[1] is either x, X, or \0 */
  332:         union arg *argtable;   /* args, built due to positional arg */
  333:         union arg statargtable[STATIC_ARG_TBL_SIZE];
  334:         size_t argtablesiz;
  335:         int nextarg;           /* 1-based argument index */
  336:         va_list orgap;         /* original argument pointer */
  337: #ifdef PRINTF_WIDE_CHAR
  338:         char *convbuf;         /* buffer for wide to multi-byte conversion */
  339: #endif
  340: 
  341:         /*
  342:          * Choose PADSIZE to trade efficiency vs. size.  If larger printf
  343:          * fields occur frequently, increase PADSIZE and make the initialisers
  344:          * below longer.
  345:          */
  346: #define PADSIZE 16              /* pad chunk size */
  347:         static char blanks[PADSIZE] =
  348:          {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  349:         static char zeroes[PADSIZE] =
  350:          {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  351: 
  352:         static const char xdigs_lower[16] = "0123456789abcdef";
  353:         static const char xdigs_upper[16] = "0123456789ABCDEF";
  354: 
  355:         /*
  356:          * BEWARE, these `goto error' on error, and PAD uses `n'.
  357:          */
  358: #define PRINT(ptr, len) do { \
  359:         iovp->iov_base = (ptr); \
  360:         iovp->iov_len = (len); \
  361:         uio.uio_resid += (len); \
  362:         iovp++; \
  363:         if (++uio.uio_iovcnt >= NIOV) { \
  364:                 if (__sprint(fp, &uio)) \
  365:                         goto error; \
  366:                 iovp = iov; \
  367:         } \
  368: } while (0)
  369: #define PAD(howmany, with) do { \
  370:         if ((n = (howmany)) > 0) { \
  371:                 while (n > PADSIZE) { \
  372:                         PRINT(with, PADSIZE); \
  373:                         n -= PADSIZE; \
  374:                 } \
  375:                 PRINT(with, n); \
  376:         } \
  377: } while (0)
  378: #define PRINTANDPAD(p, ep, len, with) do {      \
  379:         n2 = (ep) - (p);                               \
  380:         if (n2 > (len))                                \
  381:                 n2 = (len);                   \
  382:         if (n2 > 0)                            \
  383:                 PRINT((p), n2);                       \
  384:         PAD((len) - (n2 > 0 ? n2 : 0), (with));        \
  385: } while(0)
  386: #define FLUSH() do { \
  387:         if (uio.uio_resid && __sprint(fp, &uio)) \
  388:                 goto error; \
  389:         uio.uio_iovcnt = 0; \
  390:         iovp = iov; \
  391: } while (0)
  392: 
  393:         /*
  394:          * To extend shorts properly, we need both signed and unsigned
  395:          * argument extraction methods.
  396:          */
  397: #define SARG() \
  398:         ((intmax_t)(flags&MAXINT ? GETARG(intmax_t) : \
  399:             flags&LLONGINT ? GETARG(long long) : \
  400:             flags&LONGINT ? GETARG(long) : \
  401:             flags&PTRINT ? GETARG(ptrdiff_t) : \
  402:             flags&SIZEINT ? GETARG(ssize_t) : \
  403:             flags&SHORTINT ? (short)GETARG(int) : \
  404:             flags&CHARINT ? (__signed char)GETARG(int) : \
  405:             GETARG(int)))
  406: #define UARG() \
  407:         ((uintmax_t)(flags&MAXINT ? GETARG(uintmax_t) : \
  408:             flags&LLONGINT ? GETARG(unsigned long long) : \
  409:             flags&LONGINT ? GETARG(unsigned long) : \
  410:             flags&PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */ \
  411:             flags&SIZEINT ? GETARG(size_t) : \
  412:             flags&SHORTINT ? (unsigned short)GETARG(int) : \
  413:             flags&CHARINT ? (unsigned char)GETARG(int) : \
  414:             GETARG(unsigned int)))
  415: 
  416:         /*
  417:          * Append a digit to a value and check for overflow.
  418:          */
  419: #define APPEND_DIGIT(val, dig) do { \
  420:         if ((val) > INT_MAX / 10) \
  421:                 goto overflow; \
  422:         (val) *= 10; \
  423:         if ((val) > INT_MAX - to_digit((dig))) \
  424:                 goto overflow; \
  425:         (val) += to_digit((dig)); \
  426: } while (0)
  427: 
  428:          /*
  429:           * Get * arguments, including the form *nn$.  Preserve the nextarg
  430:           * that the argument can be gotten once the type is determined.
  431:           */
  432: #define GETASTER(val) \
  433:         n2 = 0; \
  434:         cp = fmt; \
  435:         while (is_digit(*cp)) { \
  436:                 APPEND_DIGIT(n2, *cp); \
  437:                 cp++; \
  438:         } \
  439:         if (/**cp == '$'*/0) { \
  440:                 int hold = nextarg; \
  441:                 if (argtable == NULL) { \
  442:                         argtable = statargtable; \
  443:                         __find_arguments(fmt0, orgap, &argtable, &argtablesiz); \
  444:                 } \
  445:                 nextarg = n2; \
  446:                 val = GETARG(int); \
  447:                 nextarg = hold; \
  448:                 fmt = ++cp; \
  449:         } else { \
  450:                 val = GETARG(int); \
  451:         }
  452: 
  453: /*
  454: * Get the argument indexed by nextarg.   If the argument table is
  455: * built, use it to get the argument.  If its not, get the next
  456: * argument (and arguments must be gotten sequentially).
  457: */
  458: #define GETARG(type) \
  459:         ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
  460:                 (nextarg++, va_arg(ap, type)))
  461: 
  462:         _SET_ORIENTATION(fp, -1);
  463:         /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  464:         if (cantwrite(fp)) {
  465:                 /*errno = EBADF*/;
  466:                 return (EOF);
  467:         }
  468: 
  469:         /* optimise fprintf(stderr) (and other unbuffered Unix files) */
  470:         if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
  471:             fp->_file >= 0)
  472:                 return (__sbprintf(fp, fmt0, ap));
  473: 
  474:         fmt = (char *)fmt0;
  475:         argtable = NULL;
  476:         nextarg = 1;
  477:         va_copy(orgap, ap);
  478:         uio.uio_iov = iovp = iov;
  479:         uio.uio_resid = 0;
  480:         uio.uio_iovcnt = 0;
  481:         ret = 0;
  482: #ifdef PRINTF_WIDE_CHAR
  483:         convbuf = NULL;
  484: #endif
  485: 
  486:         memset(&ps, 0, sizeof(ps));
  487:         /*
  488:          * Scan the format for conversions (`%' character).
  489:          */
  490:         for (;;) {
  491:                 cp = fmt;
  492: #ifndef _T2EX_NO_MULTIBYTE
  493:                 while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
  494: #else
  495:                 while ((n = ((wc = (wchar_t)(unsigned char)*fmt) != '\0') ? 1 : 0) > 0) {
  496: #endif
  497:                         fmt += n;
  498:                         if (wc == '%') {
  499:                                 fmt--;
  500:                                 break;
  501:                         }
  502:                 }
  503:                 if (fmt != cp) {
  504:                         ptrdiff_t m = fmt - cp;
  505:                         if (m < 0 || m > INT_MAX - ret)
  506:                                 goto overflow;
  507:                         PRINT(cp, m);
  508:                         ret += m;
  509:                 }
  510:                 if (n <= 0)
  511:                         goto done;
  512:                 fmt++;                /* skip over '%' */
  513: 
  514:                 flags = 0;
  515:                 dprec = 0;
  516:                 width = 0;
  517:                 prec = -1;
  518:                 sign = '\0';
  519:                 ox[1] = '\0';
  520: 
  521: rflag:          ch = *fmt++;
  522: reswitch:       switch (ch) {
  523:                 case ' ':
  524:                         /*
  525:                          * ``If the space and + flags both appear, the space
  526:                          * flag will be ignored.''
  527:                          *   -- ANSI X3J11
  528:                          */
  529:                         if (!sign)
  530:                                 sign = ' ';
  531:                         goto rflag;
  532:                 case '#':
  533:                         flags |= ALT;
  534:                         goto rflag;
  535:                 case '\'':
  536:                         /* grouping not implemented */
  537:                         goto rflag;
  538:                 case '*':
  539:                         /*
  540:                          * ``A negative field width argument is taken as a
  541:                          * - flag followed by a positive field width.''
  542:                          *   -- ANSI X3J11
  543:                          * They don't exclude field widths read from args.
  544:                          */
  545:                         GETASTER(width);
  546:                         if (width >= 0)
  547:                                 goto rflag;
  548:                         if (width == INT_MIN)
  549:                                 goto overflow;
  550:                         width = -width;
  551:                         /* FALLTHROUGH */
  552:                 case '-':
  553:                         flags |= LADJUST;
  554:                         goto rflag;
  555:                 case '+':
  556:                         sign = '+';
  557:                         goto rflag;
  558:                 case '.':
  559:                         if ((ch = *fmt++) == '*') {
  560:                                 GETASTER(n);
  561:                                 prec = n < 0 ? -1 : n;
  562:                                 goto rflag;
  563:                         }
  564:                         n = 0;
  565:                         while (is_digit(ch)) {
  566:                                 APPEND_DIGIT(n, ch);
  567:                                 ch = *fmt++;
  568:                         }
  569:                         if (/*ch == '$'*/0) {
  570:                                 nextarg = n;
  571:                                 if (argtable == NULL) {
  572:                                         argtable = statargtable;
  573:                                         __find_arguments(fmt0, orgap,
  574:                                             &argtable, &argtablesiz);
  575:                                 }
  576:                                 goto rflag;
  577:                         }
  578:                         prec = n;
  579:                         goto reswitch;
  580:                 case '0':
  581:                         /*
  582:                          * ``Note that 0 is taken as a flag, not as the
  583:                          * beginning of a field width.''
  584:                          *   -- ANSI X3J11
  585:                          */
  586:                         flags |= ZEROPAD;
  587:                         goto rflag;
  588:                 case '1': case '2': case '3': case '4':
  589:                 case '5': case '6': case '7': case '8': case '9':
  590:                         n = 0;
  591:                         do {
  592:                                 APPEND_DIGIT(n, ch);
  593:                                 ch = *fmt++;
  594:                         } while (is_digit(ch));
  595:                         if (/*ch == '$'*/0) {
  596:                                 nextarg = n;
  597:                                 if (argtable == NULL) {
  598:                                         argtable = statargtable;
  599:                                         __find_arguments(fmt0, orgap,
  600:                                             &argtable, &argtablesiz);
  601:                                 }
  602:                                 goto rflag;
  603:                         }
  604:                         width = n;
  605:                         goto reswitch;
  606: #ifdef FLOATING_POINT
  607:                 case 'L':
  608:                         flags |= LONGDBL;
  609:                         goto rflag;
  610: #endif
  611:                 case 'h':
  612:                         if (*fmt == 'h') {
  613:                                 fmt++;
  614:                                 flags |= CHARINT;
  615:                         } else {
  616:                                 flags |= SHORTINT;
  617:                         }
  618:                         goto rflag;
  619:                 case 'j':
  620:                         flags |= MAXINT;
  621:                         goto rflag;
  622:                 case 'l':
  623:                         if (*fmt == 'l') {
  624:                                 fmt++;
  625:                                 flags |= LLONGINT;
  626:                         } else {
  627:                                 flags |= LONGINT;
  628:                         }
  629:                         goto rflag;
  630:                 case 'q':
  631:                         flags |= LLONGINT;
  632:                         goto rflag;
  633:                 case 't':
  634:                         flags |= PTRINT;
  635:                         goto rflag;
  636:                 case 'z':
  637:                         flags |= SIZEINT;
  638:                         goto rflag;
  639:                 case 'c':
  640: #ifdef PRINTF_WIDE_CHAR
  641:                         if (flags & LONGINT) {
  642:                                 mbstate_t mbs;
  643:                                 size_t mbseqlen;
  644: 
  645:                                 memset(&mbs, 0, sizeof(mbs));
  646:                                 mbseqlen = wcrtomb(buf,
  647:                                     (wchar_t)GETARG(wint_t), &mbs);
  648:                                 if (mbseqlen == (size_t)-1) {
  649:                                         fp->_flags |= __SERR;
  650:                                         /*errno = EILSEQ*/;
  651:                                         goto error;
  652:                                 }
  653:                                 cp = buf;
  654:                                 size = (int)mbseqlen;
  655:                         } else {
  656: #endif
  657:                                 *(cp = buf) = GETARG(int);
  658:                                 size = 1;
  659: #ifdef PRINTF_WIDE_CHAR
  660:                         }
  661: #endif
  662:                         sign = '\0';
  663:                         break;
  664:                 case 'D':
  665:                         flags |= LONGINT;
  666:                         /*FALLTHROUGH*/
  667:                 case 'd':
  668:                 case 'i':
  669:                         _umax = SARG();
  670:                         if ((intmax_t)_umax < 0) {
  671:                                 _umax = -_umax;
  672:                                 sign = '-';
  673:                         }
  674:                         base = DEC;
  675:                         goto number;
  676: #ifdef FLOATING_POINT
  677:                 case 'a':
  678:                 case 'A':
  679:                         if (ch == 'a') {
  680:                                 ox[1] = 'x';
  681:                                 xdigs = xdigs_lower;
  682:                                 expchar = 'p';
  683:                         } else {
  684:                                 ox[1] = 'X';
  685:                                 xdigs = xdigs_upper;
  686:                                 expchar = 'P';
  687:                         }
  688:                         if (prec >= 0)
  689:                                 prec++;
  690:                         if (dtoaresult)
  691:                                 __freedtoa(dtoaresult);
  692:                         if (flags & LONGDBL) {
  693:                                 fparg.ldbl = GETARG(long double);
  694:                                 dtoaresult = cp =
  695:                                     __hldtoa(fparg.ldbl, xdigs, prec,
  696:                                     &expt, &signflag, &dtoaend);
  697:                                 if (dtoaresult == NULL) {
  698:                                         /*errno = ENOMEM*/;
  699:                                         goto error;
  700:                                 }
  701:                         } else {
  702:                                 fparg.dbl = GETARG(double);
  703:                                 dtoaresult = cp =
  704:                                     __hdtoa(fparg.dbl, xdigs, prec,
  705:                                     &expt, &signflag, &dtoaend);
  706:                                 if (dtoaresult == NULL) {
  707:                                         /*errno = ENOMEM*/;
  708:                                         goto error;
  709:                                 }
  710:                         }
  711:                         if (prec < 0)
  712:                                 prec = dtoaend - cp;
  713:                         if (expt == INT_MAX)
  714:                                 ox[1] = '\0';
  715:                         goto fp_common;
  716:                 case 'e':
  717:                 case 'E':
  718:                         expchar = ch;
  719:                         if (prec < 0)        /* account for digit before decpt */
  720:                                 prec = DEFPREC + 1;
  721:                         else
  722:                                 prec++;
  723:                         goto fp_begin;
  724:                 case 'f':
  725:                 case 'F':
  726:                         expchar = '\0';
  727:                         goto fp_begin;
  728:                 case 'g':
  729:                 case 'G':
  730:                         expchar = ch - ('g' - 'e');
  731:                         if (prec == 0)
  732:                                 prec = 1;
  733: fp_begin:
  734:                         if (prec < 0)
  735:                                 prec = DEFPREC;
  736:                         if (dtoaresult)
  737:                                 __freedtoa(dtoaresult);
  738:                         if (flags & LONGDBL) {
  739:                                 fparg.ldbl = GETARG(long double);
  740:                                 dtoaresult = cp =
  741:                                     __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
  742:                                     &expt, &signflag, &dtoaend);
  743:                                 if (dtoaresult == NULL) {
  744:                                         /*errno = ENOMEM*/;
  745:                                         goto error;
  746:                                 }
  747:                         } else {
  748:                                 fparg.dbl = GETARG(double);
  749:                                 dtoaresult = cp =
  750:                                     __dtoa(fparg.dbl, expchar ? 2 : 3, prec,
  751:                                     &expt, &signflag, &dtoaend);
  752:                                 if (dtoaresult == NULL) {
  753:                                         /*errno = ENOMEM*/;
  754:                                         goto error;
  755:                                 }
  756:                                 if (expt == 9999)
  757:                                         expt = INT_MAX;
  758:                         }
  759: fp_common:
  760:                         if (signflag)
  761:                                 sign = '-';
  762:                         if (expt == INT_MAX) {       /* inf or nan */
  763:                                 if (*cp == 'N') {
  764:                                         cp = (ch >= 'a') ? "nan" : "NAN";
  765:                                         sign = '\0';
  766:                                 } else
  767:                                         cp = (ch >= 'a') ? "inf" : "INF";
  768:                                 size = 3;
  769:                                 flags &= ~ZEROPAD;
  770:                                 break;
  771:                         }
  772:                         flags |= FPT;
  773:                         ndig = dtoaend - cp;
  774:                         if (ch == 'g' || ch == 'G') {
  775:                                 if (expt > -4 && expt <= prec) {
  776:                                         /* Make %[gG] smell like %[fF] */
  777:                                         expchar = '\0';
  778:                                         if (flags & ALT)
  779:                                                 prec -= expt;
  780:                                         else
  781:                                                 prec = ndig - expt;
  782:                                         if (prec < 0)
  783:                                                 prec = 0;
  784:                                 } else {
  785:                                         /*
  786:                                          * Make %[gG] smell like %[eE], but
  787:                                          * trim trailing zeroes if no # flag.
  788:                                          */
  789:                                         if (!(flags & ALT))
  790:                                                 prec = ndig;
  791:                                 }
  792:                         }
  793:                         if (expchar) {
  794:                                 expsize = exponent(expstr, expt - 1, expchar);
  795:                                 size = expsize + prec;
  796:                                 if (prec > 1 || flags & ALT)
  797:                                         ++size;
  798:                         } else {
  799:                                 /* space for digits before decimal point */
  800:                                 if (expt > 0)
  801:                                         size = expt;
  802:                                 else        /* "0" */
  803:                                         size = 1;
  804:                                 /* space for decimal pt and following digits */
  805:                                 if (prec || flags & ALT)
  806:                                         size += prec + 1;
  807:                                 lead = expt;
  808:                         }
  809:                         break;
  810: #endif /* FLOATING_POINT */
  811:                 case 'n':
  812:                         if (flags & LLONGINT)
  813:                                 *GETARG(long long *) = ret;
  814:                         else if (flags & LONGINT)
  815:                                 *GETARG(long *) = ret;
  816:                         else if (flags & SHORTINT)
  817:                                 *GETARG(short *) = ret;
  818:                         else if (flags & CHARINT)
  819:                                 *GETARG(__signed char *) = ret;
  820:                         else if (flags & PTRINT)
  821:                                 *GETARG(ptrdiff_t *) = ret;
  822:                         else if (flags & SIZEINT)
  823:                                 *GETARG(ssize_t *) = ret;
  824:                         else if (flags & MAXINT)
  825:                                 *GETARG(intmax_t *) = ret;
  826:                         else
  827:                                 *GETARG(int *) = ret;
  828:                         continue;    /* no output */
  829:                 case 'O':
  830:                         flags |= LONGINT;
  831:                         /*FALLTHROUGH*/
  832:                 case 'o':
  833:                         _umax = UARG();
  834:                         base = OCT;
  835:                         goto nosign;
  836:                 case 'p':
  837:                         /*
  838:                          * ``The argument shall be a pointer to void.  The
  839:                          * value of the pointer is converted to a sequence
  840:                          * of printable characters, in an implementation-
  841:                          * defined manner.''
  842:                          *   -- ANSI X3J11
  843:                          */
  844:                         /* NOSTRICT */
  845:                         _umax = (u_long)GETARG(void *);
  846:                         base = HEX;
  847:                         xdigs = xdigs_lower;
  848:                         ox[1] = 'x';
  849:                         goto nosign;
  850:                 case 's':
  851: #ifdef PRINTF_WIDE_CHAR
  852:                         if (flags & LONGINT) {
  853:                                 wchar_t *wcp;
  854: 
  855:                                 if (convbuf != NULL) {
  856:                                         free(convbuf);
  857:                                         convbuf = NULL;
  858:                                 }
  859:                                 if ((wcp = GETARG(wchar_t *)) == NULL) {
  860:                                         cp = "(null)";
  861:                                 } else {
  862:                                         convbuf = __wcsconv(wcp, prec);
  863:                                         if (convbuf == NULL) {
  864:                                                 fp->_flags = __SERR;
  865:                                                 goto error;
  866:                                         }
  867:                                         cp = convbuf;
  868:                                 }
  869:                         } else
  870: #endif /* PRINTF_WIDE_CHAR */
  871:                         if ((cp = GETARG(char *)) == NULL)
  872:                                 cp = "(null)";
  873:                         if (prec >= 0) {
  874:                                 /*
  875:                                  * can't use strlen; can only look for the
  876:                                  * NUL in the first `prec' characters, and
  877:                                  * strlen() will go further.
  878:                                  */
  879:                                 char *p = memchr(cp, 0, prec);
  880: 
  881:                                 size = p ? (p - cp) : prec;
  882:                         } else {
  883:                                 size_t len;
  884: 
  885:                                 if ((len = strlen(cp)) > INT_MAX)
  886:                                         goto overflow;
  887:                                 size = (int)len;
  888:                         }
  889:                         sign = '\0';
  890:                         break;
  891:                 case 'U':
  892:                         flags |= LONGINT;
  893:                         /*FALLTHROUGH*/
  894:                 case 'u':
  895:                         _umax = UARG();
  896:                         base = DEC;
  897:                         goto nosign;
  898:                 case 'X':
  899:                         xdigs = xdigs_upper;
  900:                         goto hex;
  901:                 case 'x':
  902:                         xdigs = xdigs_lower;
  903: hex:                    _umax = UARG();
  904:                         base = HEX;
  905:                         /* leading 0x/X only if non-zero */
  906:                         if (flags & ALT && _umax != 0)
  907:                                 ox[1] = ch;
  908: 
  909:                         /* unsigned conversions */
  910: nosign:                 sign = '\0';
  911:                         /*
  912:                          * ``... diouXx conversions ... if a precision is
  913:                          * specified, the 0 flag will be ignored.''
  914:                          *   -- ANSI X3J11
  915:                          */
  916: number:                 if ((dprec = prec) >= 0)
  917:                                 flags &= ~ZEROPAD;
  918: 
  919:                         /*
  920:                          * ``The result of converting a zero value with an
  921:                          * explicit precision of zero is no characters.''
  922:                          *   -- ANSI X3J11
  923:                          */
  924:                         cp = buf + BUF;
  925:                         if (_umax != 0 || prec != 0) {
  926:                                 /*
  927:                                  * Unsigned mod is hard, and unsigned mod
  928:                                  * by a constant is easier than that by
  929:                                  * a variable; hence this switch.
  930:                                  */
  931:                                 switch (base) {
  932:                                 case OCT:
  933:                                         do {
  934:                                                 *--cp = to_char(_umax & 7);
  935:                                                 _umax >>= 3;
  936:                                         } while (_umax);
  937:                                         /* handle octal leading 0 */
  938:                                         if (flags & ALT && *cp != '0')
  939:                                                 *--cp = '0';
  940:                                         break;
  941: 
  942:                                 case DEC:
  943:                                         /* many numbers are 1 digit */
  944:                                         while (_umax >= 10) {
  945:                                                 *--cp = to_char(_umax % 10);
  946:                                                 _umax /= 10;
  947:                                         }
  948:                                         *--cp = to_char(_umax);
  949:                                         break;
  950: 
  951:                                 case HEX:
  952:                                         do {
  953:                                                 *--cp = xdigs[_umax & 15];
  954:                                                 _umax >>= 4;
  955:                                         } while (_umax);
  956:                                         break;
  957: 
  958:                                 default:
  959:                                         cp = "bug in vfprintf: bad base";
  960:                                         size = strlen(cp);
  961:                                         goto skipsize;
  962:                                 }
  963:                         }
  964:                         size = buf + BUF - cp;
  965:                         if (size > BUF)      /* should never happen */
  966:                                 /*abort()*/;
  967:                 skipsize:
  968:                         break;
  969:                 default:      /* "%?" prints ?, unless ? is NUL */
  970:                         if (ch == '\0')
  971:                                 goto done;
  972:                         /* pretend it was %c with argument ch */
  973:                         cp = buf;
  974:                         *cp = ch;
  975:                         size = 1;
  976:                         sign = '\0';
  977:                         break;
  978:                 }
  979: 
  980:                 /*
  981:                  * All reasonable formats wind up here.  At this point, `cp'
  982:                  * points to a string which (if not flags&LADJUST) should be
  983:                  * padded out to `width' places.  If flags&ZEROPAD, it should
  984:                  * first be prefixed by any sign or other prefix; otherwise,
  985:                  * it should be blank padded before the prefix is emitted.
  986:                  * After any left-hand padding and prefixing, emit zeroes
  987:                  * required by a decimal %[diouxX] precision, then print the
  988:                  * string proper, then emit zeroes required by any leftover
  989:                  * floating precision; finally, if LADJUST, pad with blanks.
  990:                  *
  991:                  * Compute actual size, so we know how much to pad.
  992:                  * size excludes decimal prec; realsz includes it.
  993:                  */
  994:                 realsz = dprec > size ? dprec : size;
  995:                 if (sign)
  996:                         realsz++;
  997:                 if (ox[1])
  998:                         realsz+= 2;
  999: 
 1000:                 /* right-adjusting blank padding */
 1001:                 if ((flags & (LADJUST|ZEROPAD)) == 0)
 1002:                         PAD(width - realsz, blanks);
 1003: 
 1004:                 /* prefix */
 1005:                 if (sign)
 1006:                         PRINT(&sign, 1);
 1007:                 if (ox[1]) {  /* ox[1] is either x, X, or \0 */
 1008:                         ox[0] = '0';
 1009:                         PRINT(ox, 2);
 1010:                 }
 1011: 
 1012:                 /* right-adjusting zero padding */
 1013:                 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
 1014:                         PAD(width - realsz, zeroes);
 1015: 
 1016:                 /* leading zeroes from decimal precision */
 1017:                 PAD(dprec - size, zeroes);
 1018: 
 1019:                 /* the string or number proper */
 1020: #ifdef FLOATING_POINT
 1021:                 if ((flags & FPT) == 0) {
 1022:                         PRINT(cp, size);
 1023:                 } else {      /* glue together f_p fragments */
 1024:                         if (!expchar) {      /* %[fF] or sufficiently short %[gG] */
 1025:                                 if (expt <= 0) {
 1026:                                         PRINT(zeroes, 1);
 1027:                                         if (prec || flags & ALT)
 1028:                                                 PRINT(decimal_point, 1);
 1029:                                         PAD(-expt, zeroes);
 1030:                                         /* already handled initial 0's */
 1031:                                         prec += expt;
 1032:                                 } else {
 1033:                                         PRINTANDPAD(cp, dtoaend, lead, zeroes);
 1034:                                         cp += lead;
 1035:                                         if (prec || flags & ALT)
 1036:                                                 PRINT(decimal_point, 1);
 1037:                                 }
 1038:                                 PRINTANDPAD(cp, dtoaend, prec, zeroes);
 1039:                         } else {     /* %[eE] or sufficiently long %[gG] */
 1040:                                 if (prec > 1 || flags & ALT) {
 1041:                                         buf[0] = *cp++;
 1042:                                         buf[1] = *decimal_point;
 1043:                                         PRINT(buf, 2);
 1044:                                         PRINT(cp, ndig-1);
 1045:                                         PAD(prec - ndig, zeroes);
 1046:                                 } else { /* XeYYY */
 1047:                                         PRINT(cp, 1);
 1048:                                 }
 1049:                                 PRINT(expstr, expsize);
 1050:                         }
 1051:                 }
 1052: #else
 1053:                 PRINT(cp, size);
 1054: #endif
 1055:                 /* left-adjusting padding (always blank) */
 1056:                 if (flags & LADJUST)
 1057:                         PAD(width - realsz, blanks);
 1058: 
 1059:                 /* finally, adjust ret */
 1060:                 if (width < realsz)
 1061:                         width = realsz;
 1062:                 if (width > INT_MAX - ret)
 1063:                         goto overflow;
 1064:                 ret += width;
 1065: 
 1066:                 FLUSH();      /* copy out the I/O vectors */
 1067:         }
 1068: done:
 1069:         FLUSH();
 1070: error:
 1071:         va_end(orgap);
 1072:         if (__sferror(fp))
 1073:                 ret = -1;
 1074:         goto finish;
 1075: 
 1076: overflow:
 1077:         /*errno = ENOMEM*/;
 1078:         ret = -1;
 1079: 
 1080: finish:
 1081: #ifdef PRINTF_WIDE_CHAR
 1082:         if (convbuf)
 1083:                 free(convbuf);
 1084: #endif
 1085: #ifdef FLOATING_POINT
 1086:         if (dtoaresult)
 1087:                 __freedtoa(dtoaresult);
 1088: #endif
 1089:         if (argtable != NULL && argtable != statargtable) {
 1090:                 /*munmap(argtable, argtablesiz);*/;
 1091:                 argtable = NULL;
 1092:         }
 1093:         return (ret);
 1094: }
 1095: 
 1096: /*
 1097:  * Type ids for argument type table.
 1098:  */
 1099: #define T_UNUSED        0
 1100: #define T_SHORT         1
 1101: #define T_U_SHORT       2
 1102: #define TP_SHORT        3
 1103: #define T_INT           4
 1104: #define T_U_INT         5
 1105: #define TP_INT          6
 1106: #define T_LONG          7
 1107: #define T_U_LONG        8
 1108: #define TP_LONG         9
 1109: #define T_LLONG         10
 1110: #define T_U_LLONG       11
 1111: #define TP_LLONG        12
 1112: #define T_DOUBLE        13
 1113: #define T_LONG_DOUBLE   14
 1114: #define TP_CHAR         15
 1115: #define TP_VOID         16
 1116: #define T_PTRINT        17
 1117: #define TP_PTRINT       18
 1118: #define T_SIZEINT       19
 1119: #define T_SSIZEINT      20
 1120: #define TP_SSIZEINT     21
 1121: #define T_MAXINT        22
 1122: #define T_MAXUINT       23
 1123: #define TP_MAXINT       24
 1124: #define T_CHAR          25
 1125: #define T_U_CHAR        26
 1126: #define T_WINT          27
 1127: #define TP_WCHAR        28
 1128: 
 1129: /*
 1130:  * Find all arguments when a positional parameter is encountered.  Returns a
 1131:  * table, indexed by argument number, of pointers to each arguments.  The
 1132:  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
 1133:  * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
 1134:  * used since we are attempting to make snprintf thread safe, and alloca is
 1135:  * problematic since we have nested functions..)
 1136:  */
 1137: static int
 1138: __find_arguments(const char *fmt0, va_list ap, union arg **argtable,
 1139:     size_t *argtablesiz)
 1140: {
 1141:         char *fmt;             /* format string */
 1142:         int ch;                        /* character from fmt */
 1143:         int n, n2;             /* handy integer (short term usage) */
 1144:         char *cp;              /* handy char pointer (short term usage) */
 1145:         int flags;             /* flags as above */
 1146:         unsigned char *typetable; /* table of types */
 1147:         unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
 1148:         int tablesize;         /* current size of type table */
 1149:         int tablemax;          /* largest used index in table */
 1150:         int nextarg;           /* 1-based argument index */
 1151:         int ret = 0;           /* return value */
 1152:         wchar_t wc;
 1153:         mbstate_t ps;
 1154: 
 1155:         /*
 1156:          * Add an argument type to the table, expanding if necessary.
 1157:          */
 1158: #define ADDTYPE(type) \
 1159:         ((nextarg >= tablesize) ? \
 1160:                 __grow_type_table(&typetable, &tablesize) : 0, \
 1161:         (nextarg > tablemax) ? tablemax = nextarg : 0, \
 1162:         typetable[nextarg++] = type)
 1163: 
 1164: #define ADDSARG() \
 1165:         ((flags&MAXINT) ? ADDTYPE(T_MAXINT) : \
 1166:             ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
 1167:             ((flags&SIZEINT) ? ADDTYPE(T_SSIZEINT) : \
 1168:             ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \
 1169:             ((flags&LONGINT) ? ADDTYPE(T_LONG) : \
 1170:             ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : \
 1171:             ((flags&CHARINT) ? ADDTYPE(T_CHAR) : ADDTYPE(T_INT))))))))
 1172: 
 1173: #define ADDUARG() \
 1174:         ((flags&MAXINT) ? ADDTYPE(T_MAXUINT) : \
 1175:             ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \
 1176:             ((flags&SIZEINT) ? ADDTYPE(T_SIZEINT) : \
 1177:             ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \
 1178:             ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \
 1179:             ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : \
 1180:             ((flags&CHARINT) ? ADDTYPE(T_U_CHAR) : ADDTYPE(T_U_INT))))))))
 1181: 
 1182:         /*
 1183:          * Add * arguments to the type array.
 1184:          */
 1185: #define ADDASTER() \
 1186:         n2 = 0; \
 1187:         cp = fmt; \
 1188:         while (is_digit(*cp)) { \
 1189:                 APPEND_DIGIT(n2, *cp); \
 1190:                 cp++; \
 1191:         } \
 1192:         if (/**cp == '$'*/0) { \
 1193:                 int hold = nextarg; \
 1194:                 nextarg = n2; \
 1195:                 ADDTYPE(T_INT); \
 1196:                 nextarg = hold; \
 1197:                 fmt = ++cp; \
 1198:         } else { \
 1199:                 ADDTYPE(T_INT); \
 1200:         }
 1201:         fmt = (char *)fmt0;
 1202:         typetable = stattypetable;
 1203:         tablesize = STATIC_ARG_TBL_SIZE;
 1204:         tablemax = 0;
 1205:         nextarg = 1;
 1206:         memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
 1207:         memset(&ps, 0, sizeof(ps));
 1208: 
 1209:         /*
 1210:          * Scan the format for conversions (`%' character).
 1211:          */
 1212:         for (;;) {
 1213:                 cp = fmt;
 1214: #ifndef _T2EX_NO_MULTIBYTE
 1215:                 while ((n = mbrtowc(&wc, fmt, MB_CUR_MAX, &ps)) > 0) {
 1216: #else
 1217:                 while ((n = ((wc = (wchar_t)(unsigned char)*fmt) != '\0') ? 1 : 0) > 0) {
 1218: #endif
 1219:                         fmt += n;
 1220:                         if (wc == '%') {
 1221:                                 fmt--;
 1222:                                 break;
 1223:                         }
 1224:                 }
 1225:                 if (n <= 0)
 1226:                         goto done;
 1227:                 fmt++;                /* skip over '%' */
 1228: 
 1229:                 flags = 0;
 1230: 
 1231: rflag:          ch = *fmt++;
 1232: reswitch:       switch (ch) {
 1233:                 case ' ':
 1234:                 case '#':
 1235:                 case '\'':
 1236:                         goto rflag;
 1237:                 case '*':
 1238:                         ADDASTER();
 1239:                         goto rflag;
 1240:                 case '-':
 1241:                 case '+':
 1242:                         goto rflag;
 1243:                 case '.':
 1244:                         if ((ch = *fmt++) == '*') {
 1245:                                 ADDASTER();
 1246:                                 goto rflag;
 1247:                         }
 1248:                         while (is_digit(ch)) {
 1249:                                 ch = *fmt++;
 1250:                         }
 1251:                         goto reswitch;
 1252:                 case '0':
 1253:                         goto rflag;
 1254:                 case '1': case '2': case '3': case '4':
 1255:                 case '5': case '6': case '7': case '8': case '9':
 1256:                         n = 0;
 1257:                         do {
 1258:                                 APPEND_DIGIT(n ,ch);
 1259:                                 ch = *fmt++;
 1260:                         } while (is_digit(ch));
 1261:                         if (/*ch == '$'*/0) {
 1262:                                 nextarg = n;
 1263:                                 goto rflag;
 1264:                         }
 1265:                         goto reswitch;
 1266: #ifdef FLOATING_POINT
 1267:                 case 'L':
 1268:                         flags |= LONGDBL;
 1269:                         goto rflag;
 1270: #endif
 1271:                 case 'h':
 1272:                         if (*fmt == 'h') {
 1273:                                 fmt++;
 1274:                                 flags |= CHARINT;
 1275:                         } else {
 1276:                                 flags |= SHORTINT;
 1277:                         }
 1278:                         goto rflag;
 1279:                 case 'l':
 1280:                         if (*fmt == 'l') {
 1281:                                 fmt++;
 1282:                                 flags |= LLONGINT;
 1283:                         } else {
 1284:                                 flags |= LONGINT;
 1285:                         }
 1286:                         goto rflag;
 1287:                 case 'q':
 1288:                         flags |= LLONGINT;
 1289:                         goto rflag;
 1290:                 case 't':
 1291:                         flags |= PTRINT;
 1292:                         goto rflag;
 1293:                 case 'z':
 1294:                         flags |= SIZEINT;
 1295:                         goto rflag;
 1296:                 case 'c':
 1297: #ifdef PRINTF_WIDE_CHAR
 1298:                         if (flags & LONGINT)
 1299:                                 ADDTYPE(T_WINT);
 1300:                         else
 1301: #endif
 1302:                                 ADDTYPE(T_INT);
 1303:                         break;
 1304:                 case 'D':
 1305:                         flags |= LONGINT;
 1306:                         /*FALLTHROUGH*/
 1307:                 case 'd':
 1308:                 case 'i':
 1309:                         ADDSARG();
 1310:                         break;
 1311: #ifdef FLOATING_POINT
 1312:                 case 'a':
 1313:                 case 'A':
 1314:                 case 'e':
 1315:                 case 'E':
 1316:                 case 'f':
 1317:                 case 'F':
 1318:                 case 'g':
 1319:                 case 'G':
 1320:                         if (flags & LONGDBL)
 1321:                                 ADDTYPE(T_LONG_DOUBLE);
 1322:                         else
 1323:                                 ADDTYPE(T_DOUBLE);
 1324:                         break;
 1325: #endif /* FLOATING_POINT */
 1326:                 case 'n':
 1327:                         if (flags & LLONGINT)
 1328:                                 ADDTYPE(TP_LLONG);
 1329:                         else if (flags & LONGINT)
 1330:                                 ADDTYPE(TP_LONG);
 1331:                         else if (flags & SHORTINT)
 1332:                                 ADDTYPE(TP_SHORT);
 1333:                         else if (flags & PTRINT)
 1334:                                 ADDTYPE(TP_PTRINT);
 1335:                         else if (flags & SIZEINT)
 1336:                                 ADDTYPE(TP_SSIZEINT);
 1337:                         else if (flags & MAXINT)
 1338:                                 ADDTYPE(TP_MAXINT);
 1339:                         else
 1340:                                 ADDTYPE(TP_INT);
 1341:                         continue;    /* no output */
 1342:                 case 'O':
 1343:                         flags |= LONGINT;
 1344:                         /*FALLTHROUGH*/
 1345:                 case 'o':
 1346:                         ADDUARG();
 1347:                         break;
 1348:                 case 'p':
 1349:                         ADDTYPE(TP_VOID);
 1350:                         break;
 1351:                 case 's':
 1352: #ifdef PRINTF_WIDE_CHAR
 1353:                         if (flags & LONGINT)
 1354:                                 ADDTYPE(TP_WCHAR);
 1355:                         else
 1356: #endif
 1357:                                 ADDTYPE(TP_CHAR);
 1358:                         break;
 1359:                 case 'U':
 1360:                         flags |= LONGINT;
 1361:                         /*FALLTHROUGH*/
 1362:                 case 'u':
 1363:                 case 'X':
 1364:                 case 'x':
 1365:                         ADDUARG();
 1366:                         break;
 1367:                 default:      /* "%?" prints ?, unless ? is NUL */
 1368:                         if (ch == '\0')
 1369:                                 goto done;
 1370:                         break;
 1371:                 }
 1372:         }
 1373: done:
 1374:         /*
 1375:          * Build the argument table.
 1376:          */
 1377:         if (tablemax >= STATIC_ARG_TBL_SIZE) {
 1378:                 *argtablesiz = sizeof(union arg) * (tablemax + 1);
 1379:                 *argtable = /*mmap(NULL, *argtablesiz,
 1380:                     PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0);*/MAP_FAILED;
 1381:                 if (*argtable == MAP_FAILED)
 1382:                         return (-1);
 1383:         }
 1384: 
 1385: #if 0
 1386:         /* XXX is this required? */
 1387:         (*argtable)[0].intarg = 0;
 1388: #endif
 1389:         for (n = 1; n <= tablemax; n++) {
 1390:                 switch (typetable[n]) {
 1391:                 case T_UNUSED:
 1392:                 case T_CHAR:
 1393:                 case T_U_CHAR:
 1394:                 case T_SHORT:
 1395:                 case T_U_SHORT:
 1396:                 case T_INT:
 1397:                         (*argtable)[n].intarg = va_arg(ap, int);
 1398:                         break;
 1399:                 case TP_SHORT:
 1400:                         (*argtable)[n].pshortarg = va_arg(ap, short *);
 1401:                         break;
 1402:                 case T_U_INT:
 1403:                         (*argtable)[n].uintarg = va_arg(ap, unsigned int);
 1404:                         break;
 1405:                 case TP_INT:
 1406:                         (*argtable)[n].pintarg = va_arg(ap, int *);
 1407:                         break;
 1408:                 case T_LONG:
 1409:                         (*argtable)[n].longarg = va_arg(ap, long);
 1410:                         break;
 1411:                 case T_U_LONG:
 1412:                         (*argtable)[n].ulongarg = va_arg(ap, unsigned long);
 1413:                         break;
 1414:                 case TP_LONG:
 1415:                         (*argtable)[n].plongarg = va_arg(ap, long *);
 1416:                         break;
 1417:                 case T_LLONG:
 1418:                         (*argtable)[n].longlongarg = va_arg(ap, long long);
 1419:                         break;
 1420:                 case T_U_LLONG:
 1421:                         (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
 1422:                         break;
 1423:                 case TP_LLONG:
 1424:                         (*argtable)[n].plonglongarg = va_arg(ap, long long *);
 1425:                         break;
 1426: #ifdef FLOATING_POINT
 1427:                 case T_DOUBLE:
 1428:                         (*argtable)[n].doublearg = va_arg(ap, double);
 1429:                         break;
 1430:                 case T_LONG_DOUBLE:
 1431:                         (*argtable)[n].longdoublearg = va_arg(ap, long double);
 1432:                         break;
 1433: #endif
 1434:                 case TP_CHAR:
 1435:                         (*argtable)[n].pchararg = va_arg(ap, char *);
 1436:                         break;
 1437:                 case TP_VOID:
 1438:                         (*argtable)[n].pvoidarg = va_arg(ap, void *);
 1439:                         break;
 1440:                 case T_PTRINT:
 1441:                         (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
 1442:                         break;
 1443:                 case TP_PTRINT:
 1444:                         (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *);
 1445:                         break;
 1446:                 case T_SIZEINT:
 1447:                         (*argtable)[n].sizearg = va_arg(ap, size_t);
 1448:                         break;
 1449:                 case T_SSIZEINT:
 1450:                         (*argtable)[n].ssizearg = va_arg(ap, ssize_t);
 1451:                         break;
 1452:                 case TP_SSIZEINT:
 1453:                         (*argtable)[n].pssizearg = va_arg(ap, ssize_t *);
 1454:                         break;
 1455:                 case TP_MAXINT:
 1456:                         (*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
 1457:                         break;
 1458: #ifdef PRINTF_WIDE_CHAR
 1459:                 case T_WINT:
 1460:                         (*argtable)[n].wintarg = va_arg(ap, wint_t);
 1461:                         break;
 1462:                 case TP_WCHAR:
 1463:                         (*argtable)[n].pwchararg = va_arg(ap, wchar_t *);
 1464:                         break;
 1465: #endif
 1466:                 }
 1467:         }
 1468:         goto finish;
 1469: 
 1470: overflow:
 1471:         /*errno = ENOMEM*/;
 1472:         ret = -1;
 1473: 
 1474: finish:
 1475:         if (typetable != NULL && typetable != stattypetable) {
 1476:                 /*munmap(typetable, *argtablesiz);*/;
 1477:                 typetable = NULL;
 1478:         }
 1479:         return (ret);
 1480: }
 1481: 
 1482: /*
 1483:  * Increase the size of the type table.
 1484:  */
 1485: static int
 1486: __grow_type_table(unsigned char **typetable, int *tablesize)
 1487: {
 1488:         unsigned char *oldtable = *typetable;
 1489:         int newsize = *tablesize * 2;
 1490: 
 1491:         if (newsize < /*getpagesize()*/4096)
 1492:                 newsize = /*getpagesize()*/4096;
 1493: 
 1494:         if (*tablesize == STATIC_ARG_TBL_SIZE) {
 1495:                 *typetable = /*mmap(NULL, newsize, PROT_WRITE|PROT_READ,
 1496:                     MAP_ANON|MAP_PRIVATE, -1, 0);*/MAP_FAILED;
 1497:                 if (*typetable == MAP_FAILED)
 1498:                         return (-1);
 1499:                 bcopy(oldtable, *typetable, *tablesize);
 1500:         } else {
 1501:                 unsigned char *new = /*mmap(NULL, newsize, PROT_WRITE|PROT_READ,
 1502:                     MAP_ANON|MAP_PRIVATE, -1, 0);*/MAP_FAILED;
 1503:                 if (new == MAP_FAILED)
 1504:                         return (-1);
 1505:                 memmove(new, *typetable, *tablesize);
 1506:                 /*munmap(*typetable, *tablesize);*/;
 1507:                 *typetable = new;
 1508:         }
 1509:         memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize));
 1510: 
 1511:         *tablesize = newsize;
 1512:         return (0);
 1513: }
 1514: 
 1515:  
 1516: #ifdef FLOATING_POINT
 1517: static int
 1518: exponent(char *p0, int exp, int fmtch)
 1519: {
 1520:         char *p, *t;
 1521:         char expbuf[MAXEXPDIG];
 1522: 
 1523:         p = p0;
 1524:         *p++ = fmtch;
 1525:         if (exp < 0) {
 1526:                 exp = -exp;
 1527:                 *p++ = '-';
 1528:         } else
 1529:                 *p++ = '+';
 1530:         t = expbuf + MAXEXPDIG;
 1531:         if (exp > 9) {
 1532:                 do {
 1533:                         *--t = to_char(exp % 10);
 1534:                 } while ((exp /= 10) > 9);
 1535:                 *--t = to_char(exp);
 1536:                 for (; t < expbuf + MAXEXPDIG; *p++ = *t++)
 1537:                         /* nothing */;
 1538:         } else {
 1539:                 /*
 1540:                  * Exponents for decimal floating point conversions
 1541:                  * (%[eEgG]) must be at least two characters long,
 1542:                  * whereas exponents for hexadecimal conversions can
 1543:                  * be only one character long.
 1544:                  */
 1545:                 if (fmtch == 'e' || fmtch == 'E')
 1546:                         *p++ = '0';
 1547:                 *p++ = to_char(exp);
 1548:         }
 1549:         return (p - p0);
 1550: }
 1551: #endif /* FLOATING_POINT */