Home | History | Annotate | Download | only in stdio
      1 /*-
      2  * Copyright (c) 1990 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to Berkeley by
      6  * Chris Torek.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. Neither the name of the University nor the names of its contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/mman.h>
     34 #include <sys/types.h>
     35 
     36 #include <errno.h>
     37 #include <float.h>
     38 #include <langinfo.h>
     39 #include <limits.h>
     40 #include <locale.h>
     41 #include <math.h>
     42 #include <stdarg.h>
     43 #include <stddef.h>
     44 #include <stdint.h>
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <string.h>
     48 #include <unistd.h>
     49 #include <wchar.h>
     50 
     51 #include "fvwrite.h"
     52 #include "gdtoa.h"
     53 #include "local.h"
     54 
     55 union arg {
     56   int intarg;
     57   unsigned int uintarg;
     58   long longarg;
     59   unsigned long ulongarg;
     60   long long longlongarg;
     61   unsigned long long ulonglongarg;
     62   ptrdiff_t ptrdiffarg;
     63   size_t sizearg;
     64   ssize_t ssizearg;
     65   intmax_t intmaxarg;
     66   uintmax_t uintmaxarg;
     67   void* pvoidarg;
     68   char* pchararg;
     69   signed char* pschararg;
     70   short* pshortarg;
     71   int* pintarg;
     72   long* plongarg;
     73   long long* plonglongarg;
     74   ptrdiff_t* pptrdiffarg;
     75   ssize_t* pssizearg;
     76   intmax_t* pintmaxarg;
     77   double doublearg;
     78   long double longdoublearg;
     79   wint_t wintarg;
     80   wchar_t* pwchararg;
     81 };
     82 
     83 // Helper function for `fprintf to unbuffered unix file': creates a
     84 // temporary buffer.  We only work on write-only files; this avoids
     85 // worries about ungetc buffers and so forth.
     86 static int __sbprintf(FILE* fp, const CHAR_TYPE* fmt, va_list ap) {
     87   FILE fake;
     88   struct __sfileext fakeext;
     89   unsigned char buf[BUFSIZ];
     90 
     91   _FILEEXT_SETUP(&fake, &fakeext);
     92   /* copy the important variables */
     93   fake._flags = fp->_flags & ~__SNBF;
     94   fake._file = fp->_file;
     95   fake._cookie = fp->_cookie;
     96   fake._write = fp->_write;
     97 
     98   /* set up the buffer */
     99   fake._bf._base = fake._p = buf;
    100   fake._bf._size = fake._w = sizeof(buf);
    101   fake._lbfsize = 0; /* not actually used, but Just In Case */
    102 
    103   /* do the work, then copy any error status */
    104   int ret = FUNCTION_NAME(&fake, fmt, ap);
    105   if (ret >= 0 && __sflush(&fake)) ret = EOF;
    106   if (fake._flags & __SERR) fp->_flags |= __SERR;
    107   return ret;
    108 }
    109 
    110 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable, size_t* argtablesiz);
    111 static int __grow_type_table(unsigned char** typetable, int* tablesize);
    112 
    113 #define DEFPREC 6
    114 
    115 #define to_digit(c) ((c) - '0')
    116 #define is_digit(c) ((unsigned)to_digit(c) <= 9)
    117 #define to_char(n) ((CHAR_TYPE)((n) + '0'))
    118 
    119 template <typename CharT>
    120 static int exponent(CharT* p0, int exp, int fmtch) {
    121   CharT* p = p0;
    122   *p++ = fmtch;
    123   if (exp < 0) {
    124     exp = -exp;
    125     *p++ = '-';
    126   } else {
    127     *p++ = '+';
    128   }
    129 
    130   CharT expbuf[MAXEXPDIG];
    131   CharT* t = expbuf + MAXEXPDIG;
    132   if (exp > 9) {
    133     do {
    134       *--t = to_char(exp % 10);
    135     } while ((exp /= 10) > 9);
    136     *--t = to_char(exp);
    137     for (; t < expbuf + MAXEXPDIG; *p++ = *t++) /* nothing */;
    138   } else {
    139     /*
    140      * Exponents for decimal floating point conversions
    141      * (%[eEgG]) must be at least two characters long,
    142      * whereas exponents for hexadecimal conversions can
    143      * be only one character long.
    144      */
    145     if (fmtch == 'e' || fmtch == 'E') *p++ = '0';
    146     *p++ = to_char(exp);
    147   }
    148   return (p - p0);
    149 }
    150 
    151 #define PAD(howmany, with)     \
    152   do {                         \
    153     if ((n = (howmany)) > 0) { \
    154       while (n > PADSIZE) {    \
    155         PRINT(with, PADSIZE);  \
    156         n -= PADSIZE;          \
    157       }                        \
    158       PRINT(with, n);          \
    159     }                          \
    160   } while (0)
    161 
    162 #define PRINTANDPAD(p, ep, len, with)       \
    163   do {                                      \
    164     n2 = (ep) - (p);                        \
    165     if (n2 > (len)) n2 = (len);             \
    166     if (n2 > 0) PRINT((p), n2);             \
    167     PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
    168   } while (0)
    169 
    170 /*
    171  * The size of the buffer we use as scratch space for integer
    172  * conversions, among other things.  Technically, we would need the
    173  * most space for base 10 conversions with thousands' grouping
    174  * characters between each pair of digits.  100 bytes is a
    175  * conservative overestimate even for a 128-bit uintmax_t.
    176  */
    177 #define BUF 100
    178 
    179 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
    180 
    181 /*
    182  * Flags used during conversion.
    183  */
    184 #define ALT 0x0001      /* alternate form */
    185 #define LADJUST 0x0004  /* left adjustment */
    186 #define LONGDBL 0x0008  /* long double */
    187 #define LONGINT 0x0010  /* long integer */
    188 #define LLONGINT 0x0020 /* long long integer */
    189 #define SHORTINT 0x0040 /* short integer */
    190 #define ZEROPAD 0x0080  /* zero (as opposed to blank) pad */
    191 #define FPT 0x0100      /* Floating point number */
    192 #define PTRINT 0x0200   /* (unsigned) ptrdiff_t */
    193 #define SIZEINT 0x0400  /* (signed) size_t */
    194 #define CHARINT 0x0800  /* 8 bit integer */
    195 #define MAXINT 0x1000   /* largest integer size (intmax_t) */
    196 
    197 /*
    198  * Type ids for argument type table.
    199  */
    200 #define T_UNUSED 0
    201 #define T_SHORT 1
    202 #define T_U_SHORT 2
    203 #define TP_SHORT 3
    204 #define T_INT 4
    205 #define T_U_INT 5
    206 #define TP_INT 6
    207 #define T_LONG 7
    208 #define T_U_LONG 8
    209 #define TP_LONG 9
    210 #define T_LLONG 10
    211 #define T_U_LLONG 11
    212 #define TP_LLONG 12
    213 #define T_DOUBLE 13
    214 #define T_LONG_DOUBLE 14
    215 #define TP_CHAR 15
    216 #define TP_VOID 16
    217 #define T_PTRINT 17
    218 #define TP_PTRINT 18
    219 #define T_SIZEINT 19
    220 #define T_SSIZEINT 20
    221 #define TP_SSIZEINT 21
    222 #define T_MAXINT 22
    223 #define T_MAXUINT 23
    224 #define TP_MAXINT 24
    225 #define T_CHAR 25
    226 #define T_U_CHAR 26
    227 #define T_WINT 27
    228 #define TP_WCHAR 28
    229 
    230 // To extend shorts properly, we need both signed and unsigned
    231 // argument extraction methods.
    232 #define SARG()                                                                               \
    233   ((intmax_t)(flags & MAXINT                                                                 \
    234                   ? GETARG(intmax_t)                                                         \
    235                   : flags & LLONGINT                                                         \
    236                         ? GETARG(long long)                                                  \
    237                         : flags & LONGINT                                                    \
    238                               ? GETARG(long)                                                 \
    239                               : flags & PTRINT                                               \
    240                                     ? GETARG(ptrdiff_t)                                      \
    241                                     : flags & SIZEINT                                        \
    242                                           ? GETARG(ssize_t)                                  \
    243                                           : flags & SHORTINT                                 \
    244                                                 ? (short)GETARG(int)                         \
    245                                                 : flags & CHARINT ? (signed char)GETARG(int) \
    246                                                                   : GETARG(int)))
    247 #define UARG()                                                                                \
    248   ((uintmax_t)(flags & MAXINT                                                                 \
    249                    ? GETARG(uintmax_t)                                                        \
    250                    : flags & LLONGINT                                                         \
    251                          ? GETARG(unsigned long long)                                         \
    252                          : flags & LONGINT                                                    \
    253                                ? GETARG(unsigned long)                                        \
    254                                : flags & PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */    \
    255                                      flags & SIZEINT                                          \
    256                                          ? GETARG(size_t)                                     \
    257                                          : flags & SHORTINT                                   \
    258                                                ? (unsigned short)GETARG(int)                  \
    259                                                : flags & CHARINT ? (unsigned char)GETARG(int) \
    260                                                                  : GETARG(unsigned int)))
    261 
    262 // Append a digit to a value and check for overflow.
    263 #define APPEND_DIGIT(val, dig)                            \
    264   do {                                                    \
    265     if ((val) > INT_MAX / 10) goto overflow;              \
    266     (val) *= 10;                                          \
    267     if ((val) > INT_MAX - to_digit((dig))) goto overflow; \
    268     (val) += to_digit((dig));                             \
    269   } while (0)
    270 
    271 // Get * arguments, including the form *nn$.  Preserve the nextarg
    272 // that the argument can be gotten once the type is determined.
    273 #define GETASTER(val)                                                     \
    274   n2 = 0;                                                                 \
    275   cp = fmt;                                                               \
    276   while (is_digit(*cp)) {                                                 \
    277     APPEND_DIGIT(n2, *cp);                                                \
    278     cp++;                                                                 \
    279   }                                                                       \
    280   if (*cp == '$') {                                                       \
    281     int hold = nextarg;                                                   \
    282     if (argtable == NULL) {                                               \
    283       argtable = statargtable;                                            \
    284       if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { \
    285         ret = -1;                                                         \
    286         goto error;                                                       \
    287       }                                                                   \
    288     }                                                                     \
    289     nextarg = n2;                                                         \
    290     val = GETARG(int);                                                    \
    291     nextarg = hold;                                                       \
    292     fmt = ++cp;                                                           \
    293   } else {                                                                \
    294     val = GETARG(int);                                                    \
    295   }
    296 
    297 // Get the argument indexed by nextarg.   If the argument table is
    298 // built, use it to get the argument.  If its not, get the next
    299 // argument (and arguments must be gotten sequentially).
    300 #define GETARG(type) \
    301   ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
    302 
    303 /*
    304  * Find all arguments when a positional parameter is encountered.  Returns a
    305  * table, indexed by argument number, of pointers to each arguments.  The
    306  * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
    307  * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
    308  * used since we are attempting to make snprintf thread safe, and alloca is
    309  * problematic since we have nested functions..)
    310  */
    311 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable,
    312                             size_t* argtablesiz) {
    313   int ch;                   /* character from fmt */
    314   int n, n2;                /* handy integer (short term usage) */
    315   int flags;                /* flags as above */
    316   unsigned char* typetable; /* table of types */
    317   unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
    318   int tablesize; /* current size of type table */
    319   int tablemax;  /* largest used index in table */
    320   int nextarg;   /* 1-based argument index */
    321   int ret = 0;   /* return value */
    322 
    323   /*
    324    * Add an argument type to the table, expanding if necessary.
    325    */
    326 #define ADDTYPE(type)                                                      \
    327   ((nextarg >= tablesize) ? __grow_type_table(&typetable, &tablesize) : 0, \
    328    (nextarg > tablemax) ? tablemax = nextarg : 0, typetable[nextarg++] = type)
    329 
    330 #define ADDSARG()                                                                             \
    331   ((flags & MAXINT)                                                                           \
    332        ? ADDTYPE(T_MAXINT)                                                                    \
    333        : ((flags & PTRINT) ? ADDTYPE(T_PTRINT)                                                \
    334                            : ((flags & SIZEINT)                                               \
    335                                   ? ADDTYPE(T_SSIZEINT)                                       \
    336                                   : ((flags & LLONGINT)                                       \
    337                                          ? ADDTYPE(T_LLONG)                                   \
    338                                          : ((flags & LONGINT)                                 \
    339                                                 ? ADDTYPE(T_LONG)                             \
    340                                                 : ((flags & SHORTINT)                         \
    341                                                        ? ADDTYPE(T_SHORT)                     \
    342                                                        : ((flags & CHARINT) ? ADDTYPE(T_CHAR) \
    343                                                                             : ADDTYPE(T_INT))))))))
    344 
    345 #define ADDUARG()                                                                  \
    346   ((flags & MAXINT)                                                                \
    347        ? ADDTYPE(T_MAXUINT)                                                        \
    348        : ((flags & PTRINT)                                                         \
    349               ? ADDTYPE(T_PTRINT)                                                  \
    350               : ((flags & SIZEINT)                                                 \
    351                      ? ADDTYPE(T_SIZEINT)                                          \
    352                      : ((flags & LLONGINT)                                         \
    353                             ? ADDTYPE(T_U_LLONG)                                   \
    354                             : ((flags & LONGINT)                                   \
    355                                    ? ADDTYPE(T_U_LONG)                             \
    356                                    : ((flags & SHORTINT)                           \
    357                                           ? ADDTYPE(T_U_SHORT)                     \
    358                                           : ((flags & CHARINT) ? ADDTYPE(T_U_CHAR) \
    359                                                                : ADDTYPE(T_U_INT))))))))
    360 
    361   /*
    362    * Add * arguments to the type array.
    363    */
    364 #define ADDASTER()         \
    365   n2 = 0;                  \
    366   cp = fmt;                \
    367   while (is_digit(*cp)) {  \
    368     APPEND_DIGIT(n2, *cp); \
    369     cp++;                  \
    370   }                        \
    371   if (*cp == '$') {        \
    372     int hold = nextarg;    \
    373     nextarg = n2;          \
    374     ADDTYPE(T_INT);        \
    375     nextarg = hold;        \
    376     fmt = ++cp;            \
    377   } else {                 \
    378     ADDTYPE(T_INT);        \
    379   }
    380   CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
    381   CHAR_TYPE* cp;
    382   typetable = stattypetable;
    383   tablesize = STATIC_ARG_TBL_SIZE;
    384   tablemax = 0;
    385   nextarg = 1;
    386   memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
    387 
    388   /*
    389    * Scan the format for conversions (`%' character).
    390    */
    391   for (;;) {
    392     for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue;
    393     if (ch == '\0') goto done;
    394     fmt++; /* skip over '%' */
    395 
    396     flags = 0;
    397 
    398   rflag:
    399     ch = *fmt++;
    400   reswitch:
    401     switch (ch) {
    402       case ' ':
    403       case '#':
    404       case '\'':
    405         goto rflag;
    406       case '*':
    407         ADDASTER();
    408         goto rflag;
    409       case '-':
    410       case '+':
    411         goto rflag;
    412       case '.':
    413         if ((ch = *fmt++) == '*') {
    414           ADDASTER();
    415           goto rflag;
    416         }
    417         while (is_digit(ch)) {
    418           ch = *fmt++;
    419         }
    420         goto reswitch;
    421       case '0':
    422         goto rflag;
    423       case '1':
    424       case '2':
    425       case '3':
    426       case '4':
    427       case '5':
    428       case '6':
    429       case '7':
    430       case '8':
    431       case '9':
    432         n = 0;
    433         do {
    434           APPEND_DIGIT(n, ch);
    435           ch = *fmt++;
    436         } while (is_digit(ch));
    437         if (ch == '$') {
    438           nextarg = n;
    439           goto rflag;
    440         }
    441         goto reswitch;
    442       case 'L':
    443         flags |= LONGDBL;
    444         goto rflag;
    445       case 'h':
    446         if (*fmt == 'h') {
    447           fmt++;
    448           flags |= CHARINT;
    449         } else {
    450           flags |= SHORTINT;
    451         }
    452         goto rflag;
    453       case 'j':
    454         flags |= MAXINT;
    455         goto rflag;
    456       case 'l':
    457         if (*fmt == 'l') {
    458           fmt++;
    459           flags |= LLONGINT;
    460         } else {
    461           flags |= LONGINT;
    462         }
    463         goto rflag;
    464       case 'q':
    465         flags |= LLONGINT;
    466         goto rflag;
    467       case 't':
    468         flags |= PTRINT;
    469         goto rflag;
    470       case 'z':
    471         flags |= SIZEINT;
    472         goto rflag;
    473       case 'C':
    474         flags |= LONGINT;
    475         /*FALLTHROUGH*/
    476       case 'c':
    477         if (flags & LONGINT)
    478           ADDTYPE(T_WINT);
    479         else
    480           ADDTYPE(T_INT);
    481         break;
    482       case 'D':
    483         flags |= LONGINT;
    484         /*FALLTHROUGH*/
    485       case 'd':
    486       case 'i':
    487         ADDSARG();
    488         break;
    489       case 'a':
    490       case 'A':
    491       case 'e':
    492       case 'E':
    493       case 'f':
    494       case 'F':
    495       case 'g':
    496       case 'G':
    497         if (flags & LONGDBL)
    498           ADDTYPE(T_LONG_DOUBLE);
    499         else
    500           ADDTYPE(T_DOUBLE);
    501         break;
    502 #ifndef NO_PRINTF_PERCENT_N
    503       case 'n':
    504         if (flags & LLONGINT)
    505           ADDTYPE(TP_LLONG);
    506         else if (flags & LONGINT)
    507           ADDTYPE(TP_LONG);
    508         else if (flags & SHORTINT)
    509           ADDTYPE(TP_SHORT);
    510         else if (flags & PTRINT)
    511           ADDTYPE(TP_PTRINT);
    512         else if (flags & SIZEINT)
    513           ADDTYPE(TP_SSIZEINT);
    514         else if (flags & MAXINT)
    515           ADDTYPE(TP_MAXINT);
    516         else
    517           ADDTYPE(TP_INT);
    518         continue; /* no output */
    519 #endif            /* NO_PRINTF_PERCENT_N */
    520       case 'O':
    521         flags |= LONGINT;
    522         /*FALLTHROUGH*/
    523       case 'o':
    524         ADDUARG();
    525         break;
    526       case 'p':
    527         ADDTYPE(TP_VOID);
    528         break;
    529       case 'S':
    530         flags |= LONGINT;
    531         /*FALLTHROUGH*/
    532       case 's':
    533         ADDTYPE((flags & LONGINT) ? TP_WCHAR : TP_CHAR);
    534         break;
    535       case 'U':
    536         flags |= LONGINT;
    537         /*FALLTHROUGH*/
    538       case 'u':
    539       case 'X':
    540       case 'x':
    541         ADDUARG();
    542         break;
    543       default: /* "%?" prints ?, unless ? is NUL */
    544         if (ch == '\0') goto done;
    545         break;
    546     }
    547   }
    548 done:
    549   /*
    550    * Build the argument table.
    551    */
    552   if (tablemax >= STATIC_ARG_TBL_SIZE) {
    553     *argtablesiz = sizeof(union arg) * (tablemax + 1);
    554     *argtable = static_cast<arg*>(mmap(NULL, *argtablesiz,
    555                                        PROT_WRITE | PROT_READ,
    556                                        MAP_ANON | MAP_PRIVATE, -1, 0));
    557     if (*argtable == MAP_FAILED) return -1;
    558   }
    559 
    560   for (n = 1; n <= tablemax; n++) {
    561     switch (typetable[n]) {
    562       case T_UNUSED:
    563       case T_CHAR:
    564       case T_U_CHAR:
    565       case T_SHORT:
    566       case T_U_SHORT:
    567       case T_INT:
    568         (*argtable)[n].intarg = va_arg(ap, int);
    569         break;
    570       case TP_SHORT:
    571         (*argtable)[n].pshortarg = va_arg(ap, short*);
    572         break;
    573       case T_U_INT:
    574         (*argtable)[n].uintarg = va_arg(ap, unsigned int);
    575         break;
    576       case TP_INT:
    577         (*argtable)[n].pintarg = va_arg(ap, int*);
    578         break;
    579       case T_LONG:
    580         (*argtable)[n].longarg = va_arg(ap, long);
    581         break;
    582       case T_U_LONG:
    583         (*argtable)[n].ulongarg = va_arg(ap, unsigned long);
    584         break;
    585       case TP_LONG:
    586         (*argtable)[n].plongarg = va_arg(ap, long*);
    587         break;
    588       case T_LLONG:
    589         (*argtable)[n].longlongarg = va_arg(ap, long long);
    590         break;
    591       case T_U_LLONG:
    592         (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
    593         break;
    594       case TP_LLONG:
    595         (*argtable)[n].plonglongarg = va_arg(ap, long long*);
    596         break;
    597       case T_DOUBLE:
    598         (*argtable)[n].doublearg = va_arg(ap, double);
    599         break;
    600       case T_LONG_DOUBLE:
    601         (*argtable)[n].longdoublearg = va_arg(ap, long double);
    602         break;
    603       case TP_CHAR:
    604         (*argtable)[n].pchararg = va_arg(ap, char*);
    605         break;
    606       case TP_VOID:
    607         (*argtable)[n].pvoidarg = va_arg(ap, void*);
    608         break;
    609       case T_PTRINT:
    610         (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
    611         break;
    612       case TP_PTRINT:
    613         (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t*);
    614         break;
    615       case T_SIZEINT:
    616         (*argtable)[n].sizearg = va_arg(ap, size_t);
    617         break;
    618       case T_SSIZEINT:
    619         (*argtable)[n].ssizearg = va_arg(ap, ssize_t);
    620         break;
    621       case TP_SSIZEINT:
    622         (*argtable)[n].pssizearg = va_arg(ap, ssize_t*);
    623         break;
    624       case T_MAXINT:
    625         (*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
    626         break;
    627       case T_MAXUINT:
    628         (*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t);
    629         break;
    630       case TP_MAXINT:
    631         (*argtable)[n].pintmaxarg = va_arg(ap, intmax_t*);
    632         break;
    633       case T_WINT:
    634         (*argtable)[n].wintarg = va_arg(ap, wint_t);
    635         break;
    636       case TP_WCHAR:
    637         (*argtable)[n].pwchararg = va_arg(ap, wchar_t*);
    638         break;
    639     }
    640   }
    641   goto finish;
    642 
    643 overflow:
    644   errno = ENOMEM;
    645   ret = -1;
    646 
    647 finish:
    648   if (typetable != NULL && typetable != stattypetable) {
    649     munmap(typetable, *argtablesiz);
    650     typetable = NULL;
    651   }
    652   return (ret);
    653 }
    654 
    655 /*
    656  * Increase the size of the type table.
    657  */
    658 static int __grow_type_table(unsigned char** typetable, int* tablesize) {
    659   unsigned char* old_table = *typetable;
    660   int new_size = *tablesize * 2;
    661 
    662   if (new_size < getpagesize()) new_size = getpagesize();
    663 
    664   if (*tablesize == STATIC_ARG_TBL_SIZE) {
    665     *typetable = static_cast<unsigned char*>(mmap(NULL, new_size,
    666                                                   PROT_WRITE | PROT_READ,
    667                                                   MAP_ANON | MAP_PRIVATE, -1, 0));
    668     if (*typetable == MAP_FAILED) return -1;
    669     bcopy(old_table, *typetable, *tablesize);
    670   } else {
    671     unsigned char* new_table = static_cast<unsigned char*>(mmap(NULL, new_size,
    672                                                                 PROT_WRITE | PROT_READ,
    673                                                                 MAP_ANON | MAP_PRIVATE, -1, 0));
    674     if (new_table == MAP_FAILED) return -1;
    675     memmove(new_table, *typetable, *tablesize);
    676     munmap(*typetable, *tablesize);
    677     *typetable = new_table;
    678   }
    679   memset(*typetable + *tablesize, T_UNUSED, (new_size - *tablesize));
    680 
    681   *tablesize = new_size;
    682   return 0;
    683 }
    684 
    685 struct helpers {
    686   // Flush out all the vectors defined by the given uio,
    687   // then reset it so that it can be reused.
    688   static int sprint(FILE* fp, struct __suio* uio) {
    689     if (uio->uio_resid == 0) {
    690       uio->uio_iovcnt = 0;
    691       return 0;
    692     }
    693     int result = __sfvwrite(fp, uio);
    694     uio->uio_resid = 0;
    695     uio->uio_iovcnt = 0;
    696     return result;
    697   }
    698 
    699   // Convert a wide character string argument for the %ls format to a multibyte
    700   // string representation. If not -1, prec specifies the maximum number of
    701   // bytes to output, and also means that we can't assume that the wide char
    702   // string is null-terminated.
    703   static char* wcsconv(wchar_t* wcsarg, int prec) {
    704     mbstate_t mbs;
    705     char buf[MB_LEN_MAX];
    706     wchar_t* p;
    707     char* convbuf;
    708     size_t clen, nbytes;
    709 
    710     // Allocate space for the maximum number of bytes we could output.
    711     if (prec < 0) {
    712       memset(&mbs, 0, sizeof(mbs));
    713       p = wcsarg;
    714       nbytes = wcsrtombs(NULL, (const wchar_t**)&p, 0, &mbs);
    715       if (nbytes == (size_t)-1) return NULL;
    716     } else {
    717       // Optimisation: if the output precision is small enough,
    718       // just allocate enough memory for the maximum instead of
    719       // scanning the string.
    720       if (prec < 128) {
    721         nbytes = prec;
    722       } else {
    723         nbytes = 0;
    724         p = wcsarg;
    725         memset(&mbs, 0, sizeof(mbs));
    726         for (;;) {
    727           clen = wcrtomb(buf, *p++, &mbs);
    728           if (clen == 0 || clen == (size_t)-1 || nbytes + clen > (size_t)prec) break;
    729           nbytes += clen;
    730         }
    731         if (clen == (size_t)-1) return NULL;
    732       }
    733     }
    734     if ((convbuf = static_cast<char*>(malloc(nbytes + 1))) == NULL) return NULL;
    735 
    736     // Fill the output buffer.
    737     p = wcsarg;
    738     memset(&mbs, 0, sizeof(mbs));
    739     if ((nbytes = wcsrtombs(convbuf, (const wchar_t**)&p, nbytes, &mbs)) == (size_t)-1) {
    740       free(convbuf);
    741       return NULL;
    742     }
    743     convbuf[nbytes] = '\0';
    744     return convbuf;
    745   }
    746 
    747   // Like __fputwc_unlock, but handles fake string (__SSTR) files properly.
    748   // File must already be locked.
    749   static wint_t xfputwc(wchar_t wc, FILE* fp) {
    750     if ((fp->_flags & __SSTR) == 0) return __fputwc_unlock(wc, fp);
    751 
    752     char buf[MB_LEN_MAX];
    753     mbstate_t mbs = {};
    754     size_t len = wcrtomb(buf, wc, &mbs);
    755     if (len == (size_t)-1) {
    756       fp->_flags |= __SERR;
    757       errno = EILSEQ;
    758       return WEOF;
    759     }
    760 
    761     struct __siov iov;
    762     iov.iov_base = buf;
    763     iov.iov_len = len;
    764     struct __suio uio;
    765     uio.uio_iov = &iov;
    766     uio.uio_resid = len;
    767     uio.uio_iovcnt = 1;
    768     return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
    769   }
    770 
    771   // Convert a multibyte character string argument for the %s format to a wide
    772   // string representation. ``prec'' specifies the maximum number of bytes
    773   // to output. If ``prec'' is greater than or equal to zero, we can't assume
    774   // that the multibyte character string ends in a null character.
    775   //
    776   // Returns NULL on failure.
    777   // To find out what happened check errno for ENOMEM, EILSEQ and EINVAL.
    778   static wchar_t* mbsconv(char* mbsarg, int prec) {
    779     mbstate_t mbs;
    780     const char* p;
    781     size_t insize, nchars, nconv;
    782 
    783     if (mbsarg == NULL) return NULL;
    784 
    785     // Supplied argument is a multibyte string; convert it to wide characters first.
    786     if (prec >= 0) {
    787       // String is not guaranteed to be NUL-terminated. Find the number of characters to print.
    788       p = mbsarg;
    789       insize = nchars = nconv = 0;
    790       bzero(&mbs, sizeof(mbs));
    791       while (nchars != (size_t)prec) {
    792         nconv = mbrlen(p, MB_CUR_MAX, &mbs);
    793         if (nconv == (size_t)0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
    794         p += nconv;
    795         nchars++;
    796         insize += nconv;
    797       }
    798       if (nconv == (size_t)-1 || nconv == (size_t)-2) return (NULL);
    799     } else {
    800       insize = strlen(mbsarg);
    801     }
    802 
    803     // Allocate buffer for the result and perform the conversion,
    804     // converting at most `size' bytes of the input multibyte string to
    805     // wide characters for printing.
    806     wchar_t* convbuf = static_cast<wchar_t*>(calloc(insize + 1, sizeof(*convbuf)));
    807     if (convbuf == NULL) return NULL;
    808     wchar_t* wcp = convbuf;
    809     p = mbsarg;
    810     bzero(&mbs, sizeof(mbs));
    811     nconv = 0;
    812     while (insize != 0) {
    813       nconv = mbrtowc(wcp, p, insize, &mbs);
    814       if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
    815       wcp++;
    816       p += nconv;
    817       insize -= nconv;
    818     }
    819     if (nconv == (size_t)-1 || nconv == (size_t)-2) {
    820       free(convbuf);
    821       return NULL;
    822     }
    823     *wcp = '\0';
    824 
    825     return convbuf;
    826   }
    827 
    828 };
    829