Move shared parts of the two printfs out.

Bug: http://b/67371539
Test: ran tests
Change-Id: I24eae6a5d2c64ff4fd65c8d508a3709bab5a11c4
diff --git a/libc/stdio/printf_common.h b/libc/stdio/printf_common.h
new file mode 100644
index 0000000..13b4246
--- /dev/null
+++ b/libc/stdio/printf_common.h
@@ -0,0 +1,683 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <float.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <locale.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "fvwrite.h"
+#include "gdtoa.h"
+#include "local.h"
+
+union arg {
+  int intarg;
+  unsigned int uintarg;
+  long longarg;
+  unsigned long ulongarg;
+  long long longlongarg;
+  unsigned long long ulonglongarg;
+  ptrdiff_t ptrdiffarg;
+  size_t sizearg;
+  ssize_t ssizearg;
+  intmax_t intmaxarg;
+  uintmax_t uintmaxarg;
+  void* pvoidarg;
+  char* pchararg;
+  signed char* pschararg;
+  short* pshortarg;
+  int* pintarg;
+  long* plongarg;
+  long long* plonglongarg;
+  ptrdiff_t* pptrdiffarg;
+  ssize_t* pssizearg;
+  intmax_t* pintmaxarg;
+  double doublearg;
+  long double longdoublearg;
+  wint_t wintarg;
+  wchar_t* pwchararg;
+};
+
+// Helper function for `fprintf to unbuffered unix file': creates a
+// temporary buffer.  We only work on write-only files; this avoids
+// worries about ungetc buffers and so forth.
+static int __sbprintf(FILE* fp, const CHAR_TYPE* fmt, va_list ap) {
+  FILE fake;
+  struct __sfileext fakeext;
+  unsigned char buf[BUFSIZ];
+
+  _FILEEXT_SETUP(&fake, &fakeext);
+  /* copy the important variables */
+  fake._flags = fp->_flags & ~__SNBF;
+  fake._file = fp->_file;
+  fake._cookie = fp->_cookie;
+  fake._write = fp->_write;
+
+  /* set up the buffer */
+  fake._bf._base = fake._p = buf;
+  fake._bf._size = fake._w = sizeof(buf);
+  fake._lbfsize = 0; /* not actually used, but Just In Case */
+
+  /* do the work, then copy any error status */
+  int ret = FUNCTION_NAME(&fake, fmt, ap);
+  if (ret >= 0 && __sflush(&fake)) ret = EOF;
+  if (fake._flags & __SERR) fp->_flags |= __SERR;
+  return ret;
+}
+
+static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable, size_t* argtablesiz);
+static int __grow_type_table(unsigned char** typetable, int* tablesize);
+
+#define DEFPREC 6
+
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) ((unsigned)to_digit(c) <= 9)
+#define to_char(n) ((CHAR_TYPE)((n) + '0'))
+
+template <typename CharT>
+static int exponent(CharT* p0, int exp, int fmtch) {
+  CharT* p = p0;
+  *p++ = fmtch;
+  if (exp < 0) {
+    exp = -exp;
+    *p++ = '-';
+  } else {
+    *p++ = '+';
+  }
+
+  CharT expbuf[MAXEXPDIG];
+  CharT* t = expbuf + MAXEXPDIG;
+  if (exp > 9) {
+    do {
+      *--t = to_char(exp % 10);
+    } while ((exp /= 10) > 9);
+    *--t = to_char(exp);
+    for (; t < expbuf + MAXEXPDIG; *p++ = *t++) /* nothing */;
+  } else {
+    /*
+     * Exponents for decimal floating point conversions
+     * (%[eEgG]) must be at least two characters long,
+     * whereas exponents for hexadecimal conversions can
+     * be only one character long.
+     */
+    if (fmtch == 'e' || fmtch == 'E') *p++ = '0';
+    *p++ = to_char(exp);
+  }
+  return (p - p0);
+}
+
+#define PAD(howmany, with)     \
+  do {                         \
+    if ((n = (howmany)) > 0) { \
+      while (n > PADSIZE) {    \
+        PRINT(with, PADSIZE);  \
+        n -= PADSIZE;          \
+      }                        \
+      PRINT(with, n);          \
+    }                          \
+  } while (0)
+
+#define PRINTANDPAD(p, ep, len, with)       \
+  do {                                      \
+    n2 = (ep) - (p);                        \
+    if (n2 > (len)) n2 = (len);             \
+    if (n2 > 0) PRINT((p), n2);             \
+    PAD((len) - (n2 > 0 ? n2 : 0), (with)); \
+  } while (0)
+
+/*
+ * The size of the buffer we use as scratch space for integer
+ * conversions, among other things.  Technically, we would need the
+ * most space for base 10 conversions with thousands' grouping
+ * characters between each pair of digits.  100 bytes is a
+ * conservative overestimate even for a 128-bit uintmax_t.
+ */
+#define BUF 100
+
+#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */
+
+/*
+ * Flags used during conversion.
+ */
+#define ALT 0x0001      /* alternate form */
+#define LADJUST 0x0004  /* left adjustment */
+#define LONGDBL 0x0008  /* long double */
+#define LONGINT 0x0010  /* long integer */
+#define LLONGINT 0x0020 /* long long integer */
+#define SHORTINT 0x0040 /* short integer */
+#define ZEROPAD 0x0080  /* zero (as opposed to blank) pad */
+#define FPT 0x0100      /* Floating point number */
+#define PTRINT 0x0200   /* (unsigned) ptrdiff_t */
+#define SIZEINT 0x0400  /* (signed) size_t */
+#define CHARINT 0x0800  /* 8 bit integer */
+#define MAXINT 0x1000   /* largest integer size (intmax_t) */
+
+/*
+ * Type ids for argument type table.
+ */
+#define T_UNUSED 0
+#define T_SHORT 1
+#define T_U_SHORT 2
+#define TP_SHORT 3
+#define T_INT 4
+#define T_U_INT 5
+#define TP_INT 6
+#define T_LONG 7
+#define T_U_LONG 8
+#define TP_LONG 9
+#define T_LLONG 10
+#define T_U_LLONG 11
+#define TP_LLONG 12
+#define T_DOUBLE 13
+#define T_LONG_DOUBLE 14
+#define TP_CHAR 15
+#define TP_VOID 16
+#define T_PTRINT 17
+#define TP_PTRINT 18
+#define T_SIZEINT 19
+#define T_SSIZEINT 20
+#define TP_SSIZEINT 21
+#define T_MAXINT 22
+#define T_MAXUINT 23
+#define TP_MAXINT 24
+#define T_CHAR 25
+#define T_U_CHAR 26
+#define T_WINT 27
+#define TP_WCHAR 28
+
+// To extend shorts properly, we need both signed and unsigned
+// argument extraction methods.
+#define SARG()                                                                               \
+  ((intmax_t)(flags & MAXINT                                                                 \
+                  ? GETARG(intmax_t)                                                         \
+                  : flags & LLONGINT                                                         \
+                        ? GETARG(long long)                                                  \
+                        : flags & LONGINT                                                    \
+                              ? GETARG(long)                                                 \
+                              : flags & PTRINT                                               \
+                                    ? GETARG(ptrdiff_t)                                      \
+                                    : flags & SIZEINT                                        \
+                                          ? GETARG(ssize_t)                                  \
+                                          : flags & SHORTINT                                 \
+                                                ? (short)GETARG(int)                         \
+                                                : flags & CHARINT ? (signed char)GETARG(int) \
+                                                                  : GETARG(int)))
+#define UARG()                                                                                \
+  ((uintmax_t)(flags & MAXINT                                                                 \
+                   ? GETARG(uintmax_t)                                                        \
+                   : flags & LLONGINT                                                         \
+                         ? GETARG(unsigned long long)                                         \
+                         : flags & LONGINT                                                    \
+                               ? GETARG(unsigned long)                                        \
+                               : flags & PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */    \
+                                     flags & SIZEINT                                          \
+                                         ? GETARG(size_t)                                     \
+                                         : flags & SHORTINT                                   \
+                                               ? (unsigned short)GETARG(int)                  \
+                                               : flags & CHARINT ? (unsigned char)GETARG(int) \
+                                                                 : GETARG(unsigned int)))
+
+// Append a digit to a value and check for overflow.
+#define APPEND_DIGIT(val, dig)                            \
+  do {                                                    \
+    if ((val) > INT_MAX / 10) goto overflow;              \
+    (val) *= 10;                                          \
+    if ((val) > INT_MAX - to_digit((dig))) goto overflow; \
+    (val) += to_digit((dig));                             \
+  } while (0)
+
+// Get * arguments, including the form *nn$.  Preserve the nextarg
+// that the argument can be gotten once the type is determined.
+#define GETASTER(val)                                                     \
+  n2 = 0;                                                                 \
+  cp = fmt;                                                               \
+  while (is_digit(*cp)) {                                                 \
+    APPEND_DIGIT(n2, *cp);                                                \
+    cp++;                                                                 \
+  }                                                                       \
+  if (*cp == '$') {                                                       \
+    int hold = nextarg;                                                   \
+    if (argtable == NULL) {                                               \
+      argtable = statargtable;                                            \
+      if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { \
+        ret = -1;                                                         \
+        goto error;                                                       \
+      }                                                                   \
+    }                                                                     \
+    nextarg = n2;                                                         \
+    val = GETARG(int);                                                    \
+    nextarg = hold;                                                       \
+    fmt = ++cp;                                                           \
+  } else {                                                                \
+    val = GETARG(int);                                                    \
+  }
+
+// Get the argument indexed by nextarg.   If the argument table is
+// built, use it to get the argument.  If its not, get the next
+// argument (and arguments must be gotten sequentially).
+#define GETARG(type) \
+  ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type)))
+
+/*
+ * Find all arguments when a positional parameter is encountered.  Returns a
+ * table, indexed by argument number, of pointers to each arguments.  The
+ * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
+ * It will be replaced with a mmap-ed one if it overflows (malloc cannot be
+ * used since we are attempting to make snprintf thread safe, and alloca is
+ * problematic since we have nested functions..)
+ */
+static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable,
+                            size_t* argtablesiz) {
+  int ch;                   /* character from fmt */
+  int n, n2;                /* handy integer (short term usage) */
+  int flags;                /* flags as above */
+  unsigned char* typetable; /* table of types */
+  unsigned char stattypetable[STATIC_ARG_TBL_SIZE];
+  int tablesize; /* current size of type table */
+  int tablemax;  /* largest used index in table */
+  int nextarg;   /* 1-based argument index */
+  int ret = 0;   /* return value */
+
+  /*
+   * Add an argument type to the table, expanding if necessary.
+   */
+#define ADDTYPE(type)                                                      \
+  ((nextarg >= tablesize) ? __grow_type_table(&typetable, &tablesize) : 0, \
+   (nextarg > tablemax) ? tablemax = nextarg : 0, typetable[nextarg++] = type)
+
+#define ADDSARG()                                                                             \
+  ((flags & MAXINT)                                                                           \
+       ? ADDTYPE(T_MAXINT)                                                                    \
+       : ((flags & PTRINT) ? ADDTYPE(T_PTRINT)                                                \
+                           : ((flags & SIZEINT)                                               \
+                                  ? ADDTYPE(T_SSIZEINT)                                       \
+                                  : ((flags & LLONGINT)                                       \
+                                         ? ADDTYPE(T_LLONG)                                   \
+                                         : ((flags & LONGINT)                                 \
+                                                ? ADDTYPE(T_LONG)                             \
+                                                : ((flags & SHORTINT)                         \
+                                                       ? ADDTYPE(T_SHORT)                     \
+                                                       : ((flags & CHARINT) ? ADDTYPE(T_CHAR) \
+                                                                            : ADDTYPE(T_INT))))))))
+
+#define ADDUARG()                                                                  \
+  ((flags & MAXINT)                                                                \
+       ? ADDTYPE(T_MAXUINT)                                                        \
+       : ((flags & PTRINT)                                                         \
+              ? ADDTYPE(T_PTRINT)                                                  \
+              : ((flags & SIZEINT)                                                 \
+                     ? ADDTYPE(T_SIZEINT)                                          \
+                     : ((flags & LLONGINT)                                         \
+                            ? ADDTYPE(T_U_LLONG)                                   \
+                            : ((flags & LONGINT)                                   \
+                                   ? ADDTYPE(T_U_LONG)                             \
+                                   : ((flags & SHORTINT)                           \
+                                          ? ADDTYPE(T_U_SHORT)                     \
+                                          : ((flags & CHARINT) ? ADDTYPE(T_U_CHAR) \
+                                                               : ADDTYPE(T_U_INT))))))))
+
+  /*
+   * Add * arguments to the type array.
+   */
+#define ADDASTER()         \
+  n2 = 0;                  \
+  cp = fmt;                \
+  while (is_digit(*cp)) {  \
+    APPEND_DIGIT(n2, *cp); \
+    cp++;                  \
+  }                        \
+  if (*cp == '$') {        \
+    int hold = nextarg;    \
+    nextarg = n2;          \
+    ADDTYPE(T_INT);        \
+    nextarg = hold;        \
+    fmt = ++cp;            \
+  } else {                 \
+    ADDTYPE(T_INT);        \
+  }
+  CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0);
+  CHAR_TYPE* cp;
+  typetable = stattypetable;
+  tablesize = STATIC_ARG_TBL_SIZE;
+  tablemax = 0;
+  nextarg = 1;
+  memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE);
+
+  /*
+   * Scan the format for conversions (`%' character).
+   */
+  for (;;) {
+    for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue;
+    if (ch == '\0') goto done;
+    fmt++; /* skip over '%' */
+
+    flags = 0;
+
+  rflag:
+    ch = *fmt++;
+  reswitch:
+    switch (ch) {
+      case ' ':
+      case '#':
+      case '\'':
+        goto rflag;
+      case '*':
+        ADDASTER();
+        goto rflag;
+      case '-':
+      case '+':
+        goto rflag;
+      case '.':
+        if ((ch = *fmt++) == '*') {
+          ADDASTER();
+          goto rflag;
+        }
+        while (is_digit(ch)) {
+          ch = *fmt++;
+        }
+        goto reswitch;
+      case '0':
+        goto rflag;
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        n = 0;
+        do {
+          APPEND_DIGIT(n, ch);
+          ch = *fmt++;
+        } while (is_digit(ch));
+        if (ch == '$') {
+          nextarg = n;
+          goto rflag;
+        }
+        goto reswitch;
+      case 'L':
+        flags |= LONGDBL;
+        goto rflag;
+      case 'h':
+        if (*fmt == 'h') {
+          fmt++;
+          flags |= CHARINT;
+        } else {
+          flags |= SHORTINT;
+        }
+        goto rflag;
+      case 'j':
+        flags |= MAXINT;
+        goto rflag;
+      case 'l':
+        if (*fmt == 'l') {
+          fmt++;
+          flags |= LLONGINT;
+        } else {
+          flags |= LONGINT;
+        }
+        goto rflag;
+      case 'q':
+        flags |= LLONGINT;
+        goto rflag;
+      case 't':
+        flags |= PTRINT;
+        goto rflag;
+      case 'z':
+        flags |= SIZEINT;
+        goto rflag;
+      case 'C':
+        flags |= LONGINT;
+        /*FALLTHROUGH*/
+      case 'c':
+        if (flags & LONGINT)
+          ADDTYPE(T_WINT);
+        else
+          ADDTYPE(T_INT);
+        break;
+      case 'D':
+        flags |= LONGINT;
+        /*FALLTHROUGH*/
+      case 'd':
+      case 'i':
+        ADDSARG();
+        break;
+      case 'a':
+      case 'A':
+      case 'e':
+      case 'E':
+      case 'f':
+      case 'F':
+      case 'g':
+      case 'G':
+        if (flags & LONGDBL)
+          ADDTYPE(T_LONG_DOUBLE);
+        else
+          ADDTYPE(T_DOUBLE);
+        break;
+#ifndef NO_PRINTF_PERCENT_N
+      case 'n':
+        if (flags & LLONGINT)
+          ADDTYPE(TP_LLONG);
+        else if (flags & LONGINT)
+          ADDTYPE(TP_LONG);
+        else if (flags & SHORTINT)
+          ADDTYPE(TP_SHORT);
+        else if (flags & PTRINT)
+          ADDTYPE(TP_PTRINT);
+        else if (flags & SIZEINT)
+          ADDTYPE(TP_SSIZEINT);
+        else if (flags & MAXINT)
+          ADDTYPE(TP_MAXINT);
+        else
+          ADDTYPE(TP_INT);
+        continue; /* no output */
+#endif            /* NO_PRINTF_PERCENT_N */
+      case 'O':
+        flags |= LONGINT;
+        /*FALLTHROUGH*/
+      case 'o':
+        ADDUARG();
+        break;
+      case 'p':
+        ADDTYPE(TP_VOID);
+        break;
+      case 'S':
+        flags |= LONGINT;
+        /*FALLTHROUGH*/
+      case 's':
+        ADDTYPE((flags & LONGINT) ? TP_WCHAR : TP_CHAR);
+        break;
+      case 'U':
+        flags |= LONGINT;
+        /*FALLTHROUGH*/
+      case 'u':
+      case 'X':
+      case 'x':
+        ADDUARG();
+        break;
+      default: /* "%?" prints ?, unless ? is NUL */
+        if (ch == '\0') goto done;
+        break;
+    }
+  }
+done:
+  /*
+   * Build the argument table.
+   */
+  if (tablemax >= STATIC_ARG_TBL_SIZE) {
+    *argtablesiz = sizeof(union arg) * (tablemax + 1);
+    *argtable = static_cast<arg*>(mmap(NULL, *argtablesiz,
+                                       PROT_WRITE | PROT_READ,
+                                       MAP_ANON | MAP_PRIVATE, -1, 0));
+    if (*argtable == MAP_FAILED) return -1;
+  }
+
+  for (n = 1; n <= tablemax; n++) {
+    switch (typetable[n]) {
+      case T_UNUSED:
+      case T_CHAR:
+      case T_U_CHAR:
+      case T_SHORT:
+      case T_U_SHORT:
+      case T_INT:
+        (*argtable)[n].intarg = va_arg(ap, int);
+        break;
+      case TP_SHORT:
+        (*argtable)[n].pshortarg = va_arg(ap, short*);
+        break;
+      case T_U_INT:
+        (*argtable)[n].uintarg = va_arg(ap, unsigned int);
+        break;
+      case TP_INT:
+        (*argtable)[n].pintarg = va_arg(ap, int*);
+        break;
+      case T_LONG:
+        (*argtable)[n].longarg = va_arg(ap, long);
+        break;
+      case T_U_LONG:
+        (*argtable)[n].ulongarg = va_arg(ap, unsigned long);
+        break;
+      case TP_LONG:
+        (*argtable)[n].plongarg = va_arg(ap, long*);
+        break;
+      case T_LLONG:
+        (*argtable)[n].longlongarg = va_arg(ap, long long);
+        break;
+      case T_U_LLONG:
+        (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long);
+        break;
+      case TP_LLONG:
+        (*argtable)[n].plonglongarg = va_arg(ap, long long*);
+        break;
+      case T_DOUBLE:
+        (*argtable)[n].doublearg = va_arg(ap, double);
+        break;
+      case T_LONG_DOUBLE:
+        (*argtable)[n].longdoublearg = va_arg(ap, long double);
+        break;
+      case TP_CHAR:
+        (*argtable)[n].pchararg = va_arg(ap, char*);
+        break;
+      case TP_VOID:
+        (*argtable)[n].pvoidarg = va_arg(ap, void*);
+        break;
+      case T_PTRINT:
+        (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t);
+        break;
+      case TP_PTRINT:
+        (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t*);
+        break;
+      case T_SIZEINT:
+        (*argtable)[n].sizearg = va_arg(ap, size_t);
+        break;
+      case T_SSIZEINT:
+        (*argtable)[n].ssizearg = va_arg(ap, ssize_t);
+        break;
+      case TP_SSIZEINT:
+        (*argtable)[n].pssizearg = va_arg(ap, ssize_t*);
+        break;
+      case T_MAXINT:
+        (*argtable)[n].intmaxarg = va_arg(ap, intmax_t);
+        break;
+      case T_MAXUINT:
+        (*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t);
+        break;
+      case TP_MAXINT:
+        (*argtable)[n].pintmaxarg = va_arg(ap, intmax_t*);
+        break;
+      case T_WINT:
+        (*argtable)[n].wintarg = va_arg(ap, wint_t);
+        break;
+      case TP_WCHAR:
+        (*argtable)[n].pwchararg = va_arg(ap, wchar_t*);
+        break;
+    }
+  }
+  goto finish;
+
+overflow:
+  errno = ENOMEM;
+  ret = -1;
+
+finish:
+  if (typetable != NULL && typetable != stattypetable) {
+    munmap(typetable, *argtablesiz);
+    typetable = NULL;
+  }
+  return (ret);
+}
+
+/*
+ * Increase the size of the type table.
+ */
+static int __grow_type_table(unsigned char** typetable, int* tablesize) {
+  unsigned char* old_table = *typetable;
+  int new_size = *tablesize * 2;
+
+  if (new_size < getpagesize()) new_size = getpagesize();
+
+  if (*tablesize == STATIC_ARG_TBL_SIZE) {
+    *typetable = static_cast<unsigned char*>(mmap(NULL, new_size,
+                                                  PROT_WRITE | PROT_READ,
+                                                  MAP_ANON | MAP_PRIVATE, -1, 0));
+    if (*typetable == MAP_FAILED) return -1;
+    bcopy(old_table, *typetable, *tablesize);
+  } else {
+    unsigned char* new_table = static_cast<unsigned char*>(mmap(NULL, new_size,
+                                                                PROT_WRITE | PROT_READ,
+                                                                MAP_ANON | MAP_PRIVATE, -1, 0));
+    if (new_table == MAP_FAILED) return -1;
+    memmove(new_table, *typetable, *tablesize);
+    munmap(*typetable, *tablesize);
+    *typetable = new_table;
+  }
+  memset(*typetable + *tablesize, T_UNUSED, (new_size - *tablesize));
+
+  *tablesize = new_size;
+  return 0;
+}