Yet more printf de-duplication.

Bug: http://b/67371539
Test: ran tests
Change-Id: Iae38055426596919c0de4f5080c99eba95fac3a9
diff --git a/libc/stdio/printf_common.h b/libc/stdio/printf_common.h
index 13b4246..050120e 100644
--- a/libc/stdio/printf_common.h
+++ b/libc/stdio/printf_common.h
@@ -681,3 +681,148 @@
   *tablesize = new_size;
   return 0;
 }
+
+struct helpers {
+  // Flush out all the vectors defined by the given uio,
+  // then reset it so that it can be reused.
+  static int sprint(FILE* fp, struct __suio* uio) {
+    if (uio->uio_resid == 0) {
+      uio->uio_iovcnt = 0;
+      return 0;
+    }
+    int result = __sfvwrite(fp, uio);
+    uio->uio_resid = 0;
+    uio->uio_iovcnt = 0;
+    return result;
+  }
+
+  // Convert a wide character string argument for the %ls format to a multibyte
+  // string representation. If not -1, prec specifies the maximum number of
+  // bytes to output, and also means that we can't assume that the wide char
+  // string is null-terminated.
+  static char* wcsconv(wchar_t* wcsarg, int prec) {
+    mbstate_t mbs;
+    char buf[MB_LEN_MAX];
+    wchar_t* p;
+    char* convbuf;
+    size_t clen, nbytes;
+
+    // Allocate space for the maximum number of bytes we could output.
+    if (prec < 0) {
+      memset(&mbs, 0, sizeof(mbs));
+      p = wcsarg;
+      nbytes = wcsrtombs(NULL, (const wchar_t**)&p, 0, &mbs);
+      if (nbytes == (size_t)-1) return NULL;
+    } else {
+      // Optimisation: if the output precision is small enough,
+      // just allocate enough memory for the maximum instead of
+      // scanning the string.
+      if (prec < 128) {
+        nbytes = prec;
+      } else {
+        nbytes = 0;
+        p = wcsarg;
+        memset(&mbs, 0, sizeof(mbs));
+        for (;;) {
+          clen = wcrtomb(buf, *p++, &mbs);
+          if (clen == 0 || clen == (size_t)-1 || nbytes + clen > (size_t)prec) break;
+          nbytes += clen;
+        }
+        if (clen == (size_t)-1) return NULL;
+      }
+    }
+    if ((convbuf = static_cast<char*>(malloc(nbytes + 1))) == NULL) return NULL;
+
+    // Fill the output buffer.
+    p = wcsarg;
+    memset(&mbs, 0, sizeof(mbs));
+    if ((nbytes = wcsrtombs(convbuf, (const wchar_t**)&p, nbytes, &mbs)) == (size_t)-1) {
+      free(convbuf);
+      return NULL;
+    }
+    convbuf[nbytes] = '\0';
+    return convbuf;
+  }
+
+  // Like __fputwc_unlock, but handles fake string (__SSTR) files properly.
+  // File must already be locked.
+  static wint_t xfputwc(wchar_t wc, FILE* fp) {
+    if ((fp->_flags & __SSTR) == 0) return __fputwc_unlock(wc, fp);
+
+    char buf[MB_LEN_MAX];
+    mbstate_t mbs = {};
+    size_t len = wcrtomb(buf, wc, &mbs);
+    if (len == (size_t)-1) {
+      fp->_flags |= __SERR;
+      errno = EILSEQ;
+      return WEOF;
+    }
+
+    struct __siov iov;
+    iov.iov_base = buf;
+    iov.iov_len = len;
+    struct __suio uio;
+    uio.uio_iov = &iov;
+    uio.uio_resid = len;
+    uio.uio_iovcnt = 1;
+    return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
+  }
+
+  // Convert a multibyte character string argument for the %s format to a wide
+  // string representation. ``prec'' specifies the maximum number of bytes
+  // to output. If ``prec'' is greater than or equal to zero, we can't assume
+  // that the multibyte character string ends in a null character.
+  //
+  // Returns NULL on failure.
+  // To find out what happened check errno for ENOMEM, EILSEQ and EINVAL.
+  static wchar_t* mbsconv(char* mbsarg, int prec) {
+    mbstate_t mbs;
+    const char* p;
+    size_t insize, nchars, nconv;
+
+    if (mbsarg == NULL) return NULL;
+
+    // Supplied argument is a multibyte string; convert it to wide characters first.
+    if (prec >= 0) {
+      // String is not guaranteed to be NUL-terminated. Find the number of characters to print.
+      p = mbsarg;
+      insize = nchars = nconv = 0;
+      bzero(&mbs, sizeof(mbs));
+      while (nchars != (size_t)prec) {
+        nconv = mbrlen(p, MB_CUR_MAX, &mbs);
+        if (nconv == (size_t)0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
+        p += nconv;
+        nchars++;
+        insize += nconv;
+      }
+      if (nconv == (size_t)-1 || nconv == (size_t)-2) return (NULL);
+    } else {
+      insize = strlen(mbsarg);
+    }
+
+    // Allocate buffer for the result and perform the conversion,
+    // converting at most `size' bytes of the input multibyte string to
+    // wide characters for printing.
+    wchar_t* convbuf = static_cast<wchar_t*>(calloc(insize + 1, sizeof(*convbuf)));
+    if (convbuf == NULL) return NULL;
+    wchar_t* wcp = convbuf;
+    p = mbsarg;
+    bzero(&mbs, sizeof(mbs));
+    nconv = 0;
+    while (insize != 0) {
+      nconv = mbrtowc(wcp, p, insize, &mbs);
+      if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
+      wcp++;
+      p += nconv;
+      insize -= nconv;
+    }
+    if (nconv == (size_t)-1 || nconv == (size_t)-2) {
+      free(convbuf);
+      return NULL;
+    }
+    *wcp = '\0';
+
+    return convbuf;
+  }
+
+};
diff --git a/libc/stdio/vfprintf.cpp b/libc/stdio/vfprintf.cpp
index a60b862..e1aecbc 100644
--- a/libc/stdio/vfprintf.cpp
+++ b/libc/stdio/vfprintf.cpp
@@ -33,77 +33,15 @@
 
 #define CHAR_TYPE char
 #define FUNCTION_NAME __vfprintf
+#define CHAR_TYPE_STRLEN strlen
+#define CHAR_TYPE_STRNLEN strnlen
+#define CHAR_TYPE_INF "INF"
+#define CHAR_TYPE_inf "inf"
+#define CHAR_TYPE_NAN "NAN"
+#define CHAR_TYPE_nan "nan"
+#define CHAR_TYPE_ORIENTATION -1
 #include "printf_common.h"
 
-/*
- * Flush out all the vectors defined by the given uio,
- * then reset it so that it can be reused.
- */
-static int __sprint(FILE* fp, struct __suio* uio) {
-  int err;
-
-  if (uio->uio_resid == 0) {
-    uio->uio_iovcnt = 0;
-    return (0);
-  }
-  err = __sfvwrite(fp, uio);
-  uio->uio_resid = 0;
-  uio->uio_iovcnt = 0;
-  return (err);
-}
-
-/*
- * Convert a wide character string argument for the %ls format to a multibyte
- * string representation. If not -1, prec specifies the maximum number of
- * bytes to output, and also means that we can't assume that the wide char
- * string is null-terminated.
- */
-static char* __wcsconv(wchar_t* wcsarg, int prec) {
-  mbstate_t mbs;
-  char buf[MB_LEN_MAX];
-  wchar_t* p;
-  char* convbuf;
-  size_t clen, nbytes;
-
-  /* Allocate space for the maximum number of bytes we could output. */
-  if (prec < 0) {
-    memset(&mbs, 0, sizeof(mbs));
-    p = wcsarg;
-    nbytes = wcsrtombs(NULL, (const wchar_t**)&p, 0, &mbs);
-    if (nbytes == (size_t)-1) return (NULL);
-  } else {
-    /*
-     * Optimisation: if the output precision is small enough,
-     * just allocate enough memory for the maximum instead of
-     * scanning the string.
-     */
-    if (prec < 128)
-      nbytes = prec;
-    else {
-      nbytes = 0;
-      p = wcsarg;
-      memset(&mbs, 0, sizeof(mbs));
-      for (;;) {
-        clen = wcrtomb(buf, *p++, &mbs);
-        if (clen == 0 || clen == (size_t)-1 || nbytes + clen > (size_t)prec) break;
-        nbytes += clen;
-      }
-      if (clen == (size_t)-1) return (NULL);
-    }
-  }
-  if ((convbuf = static_cast<char*>(malloc(nbytes + 1))) == NULL) return NULL;
-
-  /* Fill the output buffer. */
-  p = wcsarg;
-  memset(&mbs, 0, sizeof(mbs));
-  if ((nbytes = wcsrtombs(convbuf, (const wchar_t**)&p, nbytes, &mbs)) == (size_t)-1) {
-    free(convbuf);
-    return (NULL);
-  }
-  convbuf[nbytes] = '\0';
-  return (convbuf);
-}
-
 int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
   int ch;              /* character from fmt */
   int n, n2;           /* handy integers (short term usage) */
@@ -187,18 +125,18 @@
     uio.uio_resid += (len);               \
     iovp++;                               \
     if (++uio.uio_iovcnt >= NIOV) {       \
-      if (__sprint(fp, &uio)) goto error; \
+      if (helpers::sprint(fp, &uio)) goto error; \
       iovp = iov;                         \
     }                                     \
   } while (0)
 #define FLUSH()                                          \
   do {                                                   \
-    if (uio.uio_resid && __sprint(fp, &uio)) goto error; \
+    if (uio.uio_resid && helpers::sprint(fp, &uio)) goto error; \
     uio.uio_iovcnt = 0;                                  \
     iovp = iov;                                          \
   } while (0)
 
-  _SET_ORIENTATION(fp, -1);
+  _SET_ORIENTATION(fp, CHAR_TYPE_ORIENTATION);
 
   // Writing "" to a read only file returns EOF, not 0.
   if (cantwrite(fp)) {
@@ -430,7 +368,7 @@
             goto error;
           }
         }
-        if (prec < 0) prec = dtoaend - cp;
+        if (prec < 0) prec = dtoaend - dtoaresult;
         if (expt == INT_MAX) ox[1] = '\0';
         goto fp_common;
       case 'e':
@@ -472,9 +410,9 @@
         if (signflag) sign = '-';
         if (expt == INT_MAX) { /* inf or nan */
           if (*cp == 'N') {
-            cp = const_cast<char*>((ch >= 'a') ? "nan" : "NAN");
+            cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_nan : CHAR_TYPE_NAN);
           } else {
-            cp = const_cast<char*>((ch >= 'a') ? "inf" : "INF");
+            cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_inf : CHAR_TYPE_INF);
           }
           size = 3;
           flags &= ~ZEROPAD;
@@ -566,7 +504,7 @@
           if ((wcp = GETARG(wchar_t*)) == NULL) {
             cp = const_cast<char*>("(null)");
           } else {
-            convbuf = __wcsconv(wcp, prec);
+            convbuf = helpers::wcsconv(wcp, prec);
             if (convbuf == NULL) {
               ret = -1;
               goto error;
@@ -577,11 +515,11 @@
           cp = const_cast<char*>("(null)");
         }
         if (prec >= 0) {
-          size = strnlen(cp, prec);
+          size = CHAR_TYPE_STRNLEN(cp, prec);
         } else {
           size_t len;
 
-          if ((len = strlen(cp)) > INT_MAX) goto overflow;
+          if ((len = CHAR_TYPE_STRLEN(cp)) > INT_MAX) goto overflow;
           size = (int)len;
         }
         sign = '\0';
diff --git a/libc/stdio/vfwprintf.cpp b/libc/stdio/vfwprintf.cpp
index 97bfc0b..e4bbbba 100644
--- a/libc/stdio/vfwprintf.cpp
+++ b/libc/stdio/vfwprintf.cpp
@@ -33,103 +33,15 @@
 
 #define CHAR_TYPE wchar_t
 #define FUNCTION_NAME __vfwprintf
+#define CHAR_TYPE_STRLEN wcslen
+#define CHAR_TYPE_STRNLEN wcsnlen
+#define CHAR_TYPE_INF L"INF"
+#define CHAR_TYPE_inf L"inf"
+#define CHAR_TYPE_NAN L"NAN"
+#define CHAR_TYPE_nan L"nan"
+#define CHAR_TYPE_ORIENTATION 1
 #include "printf_common.h"
 
-/*
- * Like __fputwc_unlock, but handles fake string (__SSTR) files properly.
- * File must already be locked.
- */
-static wint_t __xfputwc(wchar_t wc, FILE* fp) {
-  mbstate_t mbs;
-  char buf[MB_LEN_MAX];
-  struct __suio uio;
-  struct __siov iov;
-  size_t len;
-
-  if ((fp->_flags & __SSTR) == 0) return (__fputwc_unlock(wc, fp));
-
-  bzero(&mbs, sizeof(mbs));
-  len = wcrtomb(buf, wc, &mbs);
-  if (len == (size_t)-1) {
-    fp->_flags |= __SERR;
-    errno = EILSEQ;
-    return (WEOF);
-  }
-  uio.uio_iov = &iov;
-  uio.uio_resid = len;
-  uio.uio_iovcnt = 1;
-  iov.iov_base = buf;
-  iov.iov_len = len;
-  return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
-}
-
-/*
- * Convert a multibyte character string argument for the %s format to a wide
- * string representation. ``prec'' specifies the maximum number of bytes
- * to output. If ``prec'' is greater than or equal to zero, we can't assume
- * that the multibyte character string ends in a null character.
- *
- * Returns NULL on failure.
- * To find out what happened check errno for ENOMEM, EILSEQ and EINVAL.
- */
-static wchar_t* __mbsconv(char* mbsarg, int prec) {
-  mbstate_t mbs;
-  wchar_t *convbuf, *wcp;
-  const char* p;
-  size_t insize, nchars, nconv;
-
-  if (mbsarg == NULL) return (NULL);
-
-  /*
-   * Supplied argument is a multibyte string; convert it to wide
-   * characters first.
-   */
-  if (prec >= 0) {
-    /*
-     * String is not guaranteed to be NUL-terminated. Find the
-     * number of characters to print.
-     */
-    p = mbsarg;
-    insize = nchars = nconv = 0;
-    bzero(&mbs, sizeof(mbs));
-    while (nchars != (size_t)prec) {
-      nconv = mbrlen(p, MB_CUR_MAX, &mbs);
-      if (nconv == (size_t)0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
-      p += nconv;
-      nchars++;
-      insize += nconv;
-    }
-    if (nconv == (size_t)-1 || nconv == (size_t)-2) return (NULL);
-  } else
-    insize = strlen(mbsarg);
-
-  /*
-   * Allocate buffer for the result and perform the conversion,
-   * converting at most `size' bytes of the input multibyte string to
-   * wide characters for printing.
-   */
-  convbuf = static_cast<wchar_t*>(calloc(insize + 1, sizeof(*convbuf)));
-  if (convbuf == NULL) return (NULL);
-  wcp = convbuf;
-  p = mbsarg;
-  bzero(&mbs, sizeof(mbs));
-  nconv = 0;
-  while (insize != 0) {
-    nconv = mbrtowc(wcp, p, insize, &mbs);
-    if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) break;
-    wcp++;
-    p += nconv;
-    insize -= nconv;
-  }
-  if (nconv == (size_t)-1 || nconv == (size_t)-2) {
-    free(convbuf);
-    return (NULL);
-  }
-  *wcp = '\0';
-
-  return (convbuf);
-}
-
 int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) {
   wchar_t ch;    /* character from fmt */
   int n, n2, n3; /* handy integers (short term usage) */
@@ -206,11 +118,11 @@
 #define PRINT(ptr, len)                                   \
   do {                                                    \
     for (n3 = 0; n3 < (len); n3++) {                      \
-      if ((__xfputwc((ptr)[n3], fp)) == WEOF) goto error; \
+      if ((helpers::xfputwc((ptr)[n3], fp)) == WEOF) goto error; \
     }                                                     \
   } while (0)
 
-  _SET_ORIENTATION(fp, 1);
+  _SET_ORIENTATION(fp, CHAR_TYPE_ORIENTATION);
 
   // Writing "" to a read only file returns EOF, not 0.
   if (cantwrite(fp)) {
@@ -431,7 +343,7 @@
         if (prec < 0) prec = dtoaend - dtoaresult;
         if (expt == INT_MAX) ox[1] = '\0';
         free(convbuf);
-        cp = convbuf = __mbsconv(dtoaresult, -1);
+        cp = convbuf = helpers::mbsconv(dtoaresult, -1);
         if (cp == NULL) goto error;
         ndig = dtoaend - dtoaresult;
         goto fp_common;
@@ -471,16 +383,16 @@
           if (expt == 9999) expt = INT_MAX;
         }
         free(convbuf);
-        cp = convbuf = __mbsconv(dtoaresult, -1);
+        cp = convbuf = helpers::mbsconv(dtoaresult, -1);
         if (cp == NULL) goto error;
         ndig = dtoaend - dtoaresult;
       fp_common:
         if (signflag) sign = '-';
         if (expt == INT_MAX) { /* inf or nan */
           if (*cp == 'N') {
-            cp = const_cast<wchar_t*>((ch >= 'a') ? L"nan" : L"NAN");
+            cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_nan : CHAR_TYPE_NAN);
           } else {
-            cp = const_cast<wchar_t*>((ch >= 'a') ? L"inf" : L"INF");
+            cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_inf : CHAR_TYPE_INF);
           }
           size = 3;
           flags &= ~ZEROPAD;
@@ -569,7 +481,7 @@
           char* mbsarg;
           if ((mbsarg = GETARG(char*)) == NULL) mbsarg = const_cast<char*>("(null)");
           free(convbuf);
-          convbuf = __mbsconv(mbsarg, prec);
+          convbuf = helpers::mbsconv(mbsarg, prec);
           if (convbuf == NULL) {
             fp->_flags |= __SERR;
             goto error;
@@ -578,11 +490,11 @@
           }
         }
         if (prec >= 0) {
-          size = wcsnlen(cp, prec);
+          size = CHAR_TYPE_STRNLEN(cp, prec);
         } else {
           size_t len;
 
-          if ((len = wcslen(cp)) > INT_MAX) goto overflow;
+          if ((len = CHAR_TYPE_STRLEN(cp)) > INT_MAX) goto overflow;
           size = (int)len;
         }
         sign = '\0';