| Elliott Hughes | 1f49317 | 2017-11-08 16:13:18 -0800 | [diff] [blame] | 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; | 
| Elliott Hughes | 1f49317 | 2017-11-08 16:13:18 -0800 | [diff] [blame] | 502 |       case 'n': | 
| Elliott Hughes | 41398d0 | 2018-03-07 13:32:58 -0800 | [diff] [blame] | 503 |         __fortify_fatal("%%n not allowed on Android"); | 
| Elliott Hughes | 1f49317 | 2017-11-08 16:13:18 -0800 | [diff] [blame] | 504 |       case 'O': | 
 | 505 |         flags |= LONGINT; | 
 | 506 |         /*FALLTHROUGH*/ | 
 | 507 |       case 'o': | 
 | 508 |         ADDUARG(); | 
 | 509 |         break; | 
 | 510 |       case 'p': | 
 | 511 |         ADDTYPE(TP_VOID); | 
 | 512 |         break; | 
 | 513 |       case 'S': | 
 | 514 |         flags |= LONGINT; | 
 | 515 |         /*FALLTHROUGH*/ | 
 | 516 |       case 's': | 
 | 517 |         ADDTYPE((flags & LONGINT) ? TP_WCHAR : TP_CHAR); | 
 | 518 |         break; | 
 | 519 |       case 'U': | 
 | 520 |         flags |= LONGINT; | 
 | 521 |         /*FALLTHROUGH*/ | 
 | 522 |       case 'u': | 
 | 523 |       case 'X': | 
 | 524 |       case 'x': | 
 | 525 |         ADDUARG(); | 
 | 526 |         break; | 
 | 527 |       default: /* "%?" prints ?, unless ? is NUL */ | 
 | 528 |         if (ch == '\0') goto done; | 
 | 529 |         break; | 
 | 530 |     } | 
 | 531 |   } | 
 | 532 | done: | 
 | 533 |   /* | 
 | 534 |    * Build the argument table. | 
 | 535 |    */ | 
 | 536 |   if (tablemax >= STATIC_ARG_TBL_SIZE) { | 
 | 537 |     *argtablesiz = sizeof(union arg) * (tablemax + 1); | 
 | 538 |     *argtable = static_cast<arg*>(mmap(NULL, *argtablesiz, | 
 | 539 |                                        PROT_WRITE | PROT_READ, | 
 | 540 |                                        MAP_ANON | MAP_PRIVATE, -1, 0)); | 
 | 541 |     if (*argtable == MAP_FAILED) return -1; | 
 | 542 |   } | 
 | 543 |  | 
 | 544 |   for (n = 1; n <= tablemax; n++) { | 
 | 545 |     switch (typetable[n]) { | 
 | 546 |       case T_UNUSED: | 
 | 547 |       case T_CHAR: | 
 | 548 |       case T_U_CHAR: | 
 | 549 |       case T_SHORT: | 
 | 550 |       case T_U_SHORT: | 
 | 551 |       case T_INT: | 
 | 552 |         (*argtable)[n].intarg = va_arg(ap, int); | 
 | 553 |         break; | 
 | 554 |       case TP_SHORT: | 
 | 555 |         (*argtable)[n].pshortarg = va_arg(ap, short*); | 
 | 556 |         break; | 
 | 557 |       case T_U_INT: | 
 | 558 |         (*argtable)[n].uintarg = va_arg(ap, unsigned int); | 
 | 559 |         break; | 
 | 560 |       case TP_INT: | 
 | 561 |         (*argtable)[n].pintarg = va_arg(ap, int*); | 
 | 562 |         break; | 
 | 563 |       case T_LONG: | 
 | 564 |         (*argtable)[n].longarg = va_arg(ap, long); | 
 | 565 |         break; | 
 | 566 |       case T_U_LONG: | 
 | 567 |         (*argtable)[n].ulongarg = va_arg(ap, unsigned long); | 
 | 568 |         break; | 
 | 569 |       case TP_LONG: | 
 | 570 |         (*argtable)[n].plongarg = va_arg(ap, long*); | 
 | 571 |         break; | 
 | 572 |       case T_LLONG: | 
 | 573 |         (*argtable)[n].longlongarg = va_arg(ap, long long); | 
 | 574 |         break; | 
 | 575 |       case T_U_LLONG: | 
 | 576 |         (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long); | 
 | 577 |         break; | 
 | 578 |       case TP_LLONG: | 
 | 579 |         (*argtable)[n].plonglongarg = va_arg(ap, long long*); | 
 | 580 |         break; | 
 | 581 |       case T_DOUBLE: | 
 | 582 |         (*argtable)[n].doublearg = va_arg(ap, double); | 
 | 583 |         break; | 
 | 584 |       case T_LONG_DOUBLE: | 
 | 585 |         (*argtable)[n].longdoublearg = va_arg(ap, long double); | 
 | 586 |         break; | 
 | 587 |       case TP_CHAR: | 
 | 588 |         (*argtable)[n].pchararg = va_arg(ap, char*); | 
 | 589 |         break; | 
 | 590 |       case TP_VOID: | 
 | 591 |         (*argtable)[n].pvoidarg = va_arg(ap, void*); | 
 | 592 |         break; | 
 | 593 |       case T_PTRINT: | 
 | 594 |         (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t); | 
 | 595 |         break; | 
 | 596 |       case TP_PTRINT: | 
 | 597 |         (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t*); | 
 | 598 |         break; | 
 | 599 |       case T_SIZEINT: | 
 | 600 |         (*argtable)[n].sizearg = va_arg(ap, size_t); | 
 | 601 |         break; | 
 | 602 |       case T_SSIZEINT: | 
 | 603 |         (*argtable)[n].ssizearg = va_arg(ap, ssize_t); | 
 | 604 |         break; | 
 | 605 |       case TP_SSIZEINT: | 
 | 606 |         (*argtable)[n].pssizearg = va_arg(ap, ssize_t*); | 
 | 607 |         break; | 
 | 608 |       case T_MAXINT: | 
 | 609 |         (*argtable)[n].intmaxarg = va_arg(ap, intmax_t); | 
 | 610 |         break; | 
 | 611 |       case T_MAXUINT: | 
 | 612 |         (*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t); | 
 | 613 |         break; | 
 | 614 |       case TP_MAXINT: | 
 | 615 |         (*argtable)[n].pintmaxarg = va_arg(ap, intmax_t*); | 
 | 616 |         break; | 
 | 617 |       case T_WINT: | 
 | 618 |         (*argtable)[n].wintarg = va_arg(ap, wint_t); | 
 | 619 |         break; | 
 | 620 |       case TP_WCHAR: | 
 | 621 |         (*argtable)[n].pwchararg = va_arg(ap, wchar_t*); | 
 | 622 |         break; | 
 | 623 |     } | 
 | 624 |   } | 
 | 625 |   goto finish; | 
 | 626 |  | 
 | 627 | overflow: | 
 | 628 |   errno = ENOMEM; | 
 | 629 |   ret = -1; | 
 | 630 |  | 
 | 631 | finish: | 
 | 632 |   if (typetable != NULL && typetable != stattypetable) { | 
 | 633 |     munmap(typetable, *argtablesiz); | 
 | 634 |     typetable = NULL; | 
 | 635 |   } | 
 | 636 |   return (ret); | 
 | 637 | } | 
 | 638 |  | 
 | 639 | /* | 
 | 640 |  * Increase the size of the type table. | 
 | 641 |  */ | 
 | 642 | static int __grow_type_table(unsigned char** typetable, int* tablesize) { | 
 | 643 |   unsigned char* old_table = *typetable; | 
 | 644 |   int new_size = *tablesize * 2; | 
 | 645 |  | 
 | 646 |   if (new_size < getpagesize()) new_size = getpagesize(); | 
 | 647 |  | 
 | 648 |   if (*tablesize == STATIC_ARG_TBL_SIZE) { | 
 | 649 |     *typetable = static_cast<unsigned char*>(mmap(NULL, new_size, | 
 | 650 |                                                   PROT_WRITE | PROT_READ, | 
 | 651 |                                                   MAP_ANON | MAP_PRIVATE, -1, 0)); | 
 | 652 |     if (*typetable == MAP_FAILED) return -1; | 
 | 653 |     bcopy(old_table, *typetable, *tablesize); | 
 | 654 |   } else { | 
 | 655 |     unsigned char* new_table = static_cast<unsigned char*>(mmap(NULL, new_size, | 
 | 656 |                                                                 PROT_WRITE | PROT_READ, | 
 | 657 |                                                                 MAP_ANON | MAP_PRIVATE, -1, 0)); | 
 | 658 |     if (new_table == MAP_FAILED) return -1; | 
 | 659 |     memmove(new_table, *typetable, *tablesize); | 
 | 660 |     munmap(*typetable, *tablesize); | 
 | 661 |     *typetable = new_table; | 
 | 662 |   } | 
 | 663 |   memset(*typetable + *tablesize, T_UNUSED, (new_size - *tablesize)); | 
 | 664 |  | 
 | 665 |   *tablesize = new_size; | 
 | 666 |   return 0; | 
 | 667 | } | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 668 |  | 
 | 669 | struct helpers { | 
 | 670 |   // Flush out all the vectors defined by the given uio, | 
 | 671 |   // then reset it so that it can be reused. | 
 | 672 |   static int sprint(FILE* fp, struct __suio* uio) { | 
 | 673 |     if (uio->uio_resid == 0) { | 
 | 674 |       uio->uio_iovcnt = 0; | 
 | 675 |       return 0; | 
 | 676 |     } | 
 | 677 |     int result = __sfvwrite(fp, uio); | 
 | 678 |     uio->uio_resid = 0; | 
 | 679 |     uio->uio_iovcnt = 0; | 
 | 680 |     return result; | 
 | 681 |   } | 
 | 682 |  | 
 | 683 |   // Convert a wide character string argument for the %ls format to a multibyte | 
 | 684 |   // string representation. If not -1, prec specifies the maximum number of | 
 | 685 |   // bytes to output, and also means that we can't assume that the wide char | 
 | 686 |   // string is null-terminated. | 
 | 687 |   static char* wcsconv(wchar_t* wcsarg, int prec) { | 
 | 688 |     mbstate_t mbs; | 
 | 689 |     char buf[MB_LEN_MAX]; | 
 | 690 |     wchar_t* p; | 
 | 691 |     char* convbuf; | 
 | 692 |     size_t clen, nbytes; | 
 | 693 |  | 
 | 694 |     // Allocate space for the maximum number of bytes we could output. | 
 | 695 |     if (prec < 0) { | 
 | 696 |       memset(&mbs, 0, sizeof(mbs)); | 
 | 697 |       p = wcsarg; | 
 | 698 |       nbytes = wcsrtombs(NULL, (const wchar_t**)&p, 0, &mbs); | 
 | 699 |       if (nbytes == (size_t)-1) return NULL; | 
 | 700 |     } else { | 
 | 701 |       // Optimisation: if the output precision is small enough, | 
 | 702 |       // just allocate enough memory for the maximum instead of | 
 | 703 |       // scanning the string. | 
 | 704 |       if (prec < 128) { | 
 | 705 |         nbytes = prec; | 
 | 706 |       } else { | 
 | 707 |         nbytes = 0; | 
 | 708 |         p = wcsarg; | 
 | 709 |         memset(&mbs, 0, sizeof(mbs)); | 
 | 710 |         for (;;) { | 
 | 711 |           clen = wcrtomb(buf, *p++, &mbs); | 
 | 712 |           if (clen == 0 || clen == (size_t)-1 || nbytes + clen > (size_t)prec) break; | 
 | 713 |           nbytes += clen; | 
 | 714 |         } | 
 | 715 |         if (clen == (size_t)-1) return NULL; | 
 | 716 |       } | 
 | 717 |     } | 
 | 718 |     if ((convbuf = static_cast<char*>(malloc(nbytes + 1))) == NULL) return NULL; | 
 | 719 |  | 
 | 720 |     // Fill the output buffer. | 
 | 721 |     p = wcsarg; | 
 | 722 |     memset(&mbs, 0, sizeof(mbs)); | 
 | 723 |     if ((nbytes = wcsrtombs(convbuf, (const wchar_t**)&p, nbytes, &mbs)) == (size_t)-1) { | 
 | 724 |       free(convbuf); | 
 | 725 |       return NULL; | 
 | 726 |     } | 
 | 727 |     convbuf[nbytes] = '\0'; | 
 | 728 |     return convbuf; | 
 | 729 |   } | 
 | 730 |  | 
 | 731 |   // Like __fputwc_unlock, but handles fake string (__SSTR) files properly. | 
 | 732 |   // File must already be locked. | 
 | 733 |   static wint_t xfputwc(wchar_t wc, FILE* fp) { | 
 | 734 |     if ((fp->_flags & __SSTR) == 0) return __fputwc_unlock(wc, fp); | 
 | 735 |  | 
 | 736 |     char buf[MB_LEN_MAX]; | 
 | 737 |     mbstate_t mbs = {}; | 
 | 738 |     size_t len = wcrtomb(buf, wc, &mbs); | 
 | 739 |     if (len == (size_t)-1) { | 
 | 740 |       fp->_flags |= __SERR; | 
 | 741 |       errno = EILSEQ; | 
 | 742 |       return WEOF; | 
 | 743 |     } | 
 | 744 |  | 
 | 745 |     struct __siov iov; | 
 | 746 |     iov.iov_base = buf; | 
 | 747 |     iov.iov_len = len; | 
 | 748 |     struct __suio uio; | 
 | 749 |     uio.uio_iov = &iov; | 
 | 750 |     uio.uio_resid = len; | 
 | 751 |     uio.uio_iovcnt = 1; | 
 | 752 |     return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); | 
 | 753 |   } | 
 | 754 |  | 
 | 755 |   // Convert a multibyte character string argument for the %s format to a wide | 
 | 756 |   // string representation. ``prec'' specifies the maximum number of bytes | 
 | 757 |   // to output. If ``prec'' is greater than or equal to zero, we can't assume | 
 | 758 |   // that the multibyte character string ends in a null character. | 
 | 759 |   // | 
 | 760 |   // Returns NULL on failure. | 
 | 761 |   // To find out what happened check errno for ENOMEM, EILSEQ and EINVAL. | 
 | 762 |   static wchar_t* mbsconv(char* mbsarg, int prec) { | 
 | 763 |     mbstate_t mbs; | 
 | 764 |     const char* p; | 
 | 765 |     size_t insize, nchars, nconv; | 
 | 766 |  | 
 | 767 |     if (mbsarg == NULL) return NULL; | 
 | 768 |  | 
 | 769 |     // Supplied argument is a multibyte string; convert it to wide characters first. | 
 | 770 |     if (prec >= 0) { | 
 | 771 |       // String is not guaranteed to be NUL-terminated. Find the number of characters to print. | 
 | 772 |       p = mbsarg; | 
 | 773 |       insize = nchars = nconv = 0; | 
 | 774 |       bzero(&mbs, sizeof(mbs)); | 
 | 775 |       while (nchars != (size_t)prec) { | 
 | 776 |         nconv = mbrlen(p, MB_CUR_MAX, &mbs); | 
 | 777 |         if (nconv == (size_t)0 || nconv == (size_t)-1 || nconv == (size_t)-2) break; | 
 | 778 |         p += nconv; | 
 | 779 |         nchars++; | 
 | 780 |         insize += nconv; | 
 | 781 |       } | 
 | 782 |       if (nconv == (size_t)-1 || nconv == (size_t)-2) return (NULL); | 
 | 783 |     } else { | 
 | 784 |       insize = strlen(mbsarg); | 
 | 785 |     } | 
 | 786 |  | 
 | 787 |     // Allocate buffer for the result and perform the conversion, | 
 | 788 |     // converting at most `size' bytes of the input multibyte string to | 
 | 789 |     // wide characters for printing. | 
 | 790 |     wchar_t* convbuf = static_cast<wchar_t*>(calloc(insize + 1, sizeof(*convbuf))); | 
 | 791 |     if (convbuf == NULL) return NULL; | 
 | 792 |     wchar_t* wcp = convbuf; | 
 | 793 |     p = mbsarg; | 
 | 794 |     bzero(&mbs, sizeof(mbs)); | 
 | 795 |     nconv = 0; | 
 | 796 |     while (insize != 0) { | 
 | 797 |       nconv = mbrtowc(wcp, p, insize, &mbs); | 
 | 798 |       if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) break; | 
 | 799 |       wcp++; | 
 | 800 |       p += nconv; | 
 | 801 |       insize -= nconv; | 
 | 802 |     } | 
 | 803 |     if (nconv == (size_t)-1 || nconv == (size_t)-2) { | 
 | 804 |       free(convbuf); | 
 | 805 |       return NULL; | 
 | 806 |     } | 
 | 807 |     *wcp = '\0'; | 
 | 808 |  | 
 | 809 |     return convbuf; | 
 | 810 |   } | 
 | 811 |  | 
 | 812 | }; |