| Elliott Hughes | 506c6de | 2016-01-15 16:30:18 -0800 | [diff] [blame] | 1 | /*	$OpenBSD: vfprintf.c,v 1.71 2016/01/04 15:47:47 schwarze Exp $	*/ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 2 | /*- | 
 | 3 |  * Copyright (c) 1990 The Regents of the University of California. | 
 | 4 |  * All rights reserved. | 
 | 5 |  * | 
 | 6 |  * This code is derived from software contributed to Berkeley by | 
 | 7 |  * Chris Torek. | 
 | 8 |  * | 
 | 9 |  * Redistribution and use in source and binary forms, with or without | 
 | 10 |  * modification, are permitted provided that the following conditions | 
 | 11 |  * are met: | 
 | 12 |  * 1. Redistributions of source code must retain the above copyright | 
 | 13 |  *    notice, this list of conditions and the following disclaimer. | 
 | 14 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 | 15 |  *    notice, this list of conditions and the following disclaimer in the | 
 | 16 |  *    documentation and/or other materials provided with the distribution. | 
 | 17 |  * 3. Neither the name of the University nor the names of its contributors | 
 | 18 |  *    may be used to endorse or promote products derived from this software | 
 | 19 |  *    without specific prior written permission. | 
 | 20 |  * | 
 | 21 |  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 
 | 22 |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 | 23 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
 | 24 |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 
 | 25 |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
 | 26 |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
 | 27 |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
 | 28 |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
 | 29 |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
 | 30 |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
 | 31 |  * SUCH DAMAGE. | 
 | 32 |  */ | 
 | 33 |  | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 34 | #define CHAR_TYPE char | 
| Elliott Hughes | 93a1f8b | 2017-11-07 22:52:29 -0800 | [diff] [blame] | 35 | #define FUNCTION_NAME __vfprintf | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 36 | #define CHAR_TYPE_STRLEN strlen | 
 | 37 | #define CHAR_TYPE_STRNLEN strnlen | 
 | 38 | #define CHAR_TYPE_INF "INF" | 
 | 39 | #define CHAR_TYPE_inf "inf" | 
 | 40 | #define CHAR_TYPE_NAN "NAN" | 
 | 41 | #define CHAR_TYPE_nan "nan" | 
 | 42 | #define CHAR_TYPE_ORIENTATION -1 | 
| Elliott Hughes | 1f49317 | 2017-11-08 16:13:18 -0800 | [diff] [blame] | 43 | #include "printf_common.h" | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 44 |  | 
| Elliott Hughes | 1f49317 | 2017-11-08 16:13:18 -0800 | [diff] [blame] | 45 | int FUNCTION_NAME(FILE* fp, const CHAR_TYPE* fmt0, va_list ap) { | 
| Elliott Hughes | 654cd83 | 2018-08-30 16:00:42 -0700 | [diff] [blame] | 46 |   int caller_errno = errno; | 
| Elliott Hughes | b70576b | 2017-11-13 11:10:05 -0800 | [diff] [blame] | 47 |   int n, n2; | 
| Elliott Hughes | 93a1f8b | 2017-11-07 22:52:29 -0800 | [diff] [blame] | 48 |   CHAR_TYPE* cp;            /* handy char pointer (short term usage) */ | 
| Elliott Hughes | 93a1f8b | 2017-11-07 22:52:29 -0800 | [diff] [blame] | 49 |   CHAR_TYPE sign;           /* sign prefix (' ', '+', '-', or \0) */ | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 50 |   int flags;           /* flags as above */ | 
 | 51 |   int ret;             /* return value accumulator */ | 
 | 52 |   int width;           /* width from format (%8d), or 0 */ | 
 | 53 |   int prec;            /* precision from format; <0 for N/A */ | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 54 |   /* | 
 | 55 |    * We can decompose the printed representation of floating | 
 | 56 |    * point numbers into several parts, some of which may be empty: | 
 | 57 |    * | 
 | 58 |    * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ | 
 | 59 |    *    A       B     ---C---      D       E   F | 
 | 60 |    * | 
 | 61 |    * A:	'sign' holds this value if present; '\0' otherwise | 
 | 62 |    * B:	ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal | 
 | 63 |    * C:	cp points to the string MMMNNN.  Leading and trailing | 
 | 64 |    *	zeros are not in the string and must be added. | 
 | 65 |    * D:	expchar holds this character; '\0' if no exponent, e.g. %f | 
 | 66 |    * F:	at least two digits for decimal, at least one digit for hex | 
 | 67 |    */ | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 68 |   char* decimal_point = nullptr; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 69 |   int signflag; /* true if float is negative */ | 
 | 70 |   union {       /* floating point arguments %[aAeEfFgG] */ | 
 | 71 |     double dbl; | 
 | 72 |     long double ldbl; | 
 | 73 |   } fparg; | 
 | 74 |   int expt;                   /* integer value of exponent */ | 
 | 75 |   char expchar;               /* exponent character: [eEpP\0] */ | 
 | 76 |   char* dtoaend;              /* pointer to end of converted digits */ | 
 | 77 |   int expsize;                /* character count for expstr */ | 
 | 78 |   int lead;                   /* sig figs before decimal or group sep */ | 
 | 79 |   int ndig;                   /* actual number of digits returned by dtoa */ | 
| Elliott Hughes | 93a1f8b | 2017-11-07 22:52:29 -0800 | [diff] [blame] | 80 |   CHAR_TYPE expstr[MAXEXPDIG + 2]; /* buffer for exponent string: e+ZZZ */ | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 81 |   char* dtoaresult = nullptr; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 82 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 83 |   uintmax_t _umax;             /* integer arguments %[diouxX] */ | 
 | 84 |   enum { OCT, DEC, HEX } base; /* base for %[diouxX] conversion */ | 
 | 85 |   int dprec;                   /* a copy of prec if %[diouxX], 0 otherwise */ | 
 | 86 |   int realsz;                  /* field size expanded by dprec */ | 
 | 87 |   int size;                    /* size of converted field or string */ | 
 | 88 |   const char* xdigs;           /* digits for %[xX] conversion */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 89 | #define NIOV 8 | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 90 |   struct __suio uio;       /* output information: summary */ | 
 | 91 |   struct __siov iov[NIOV]; /* ... and individual io vectors */ | 
| Elliott Hughes | b70576b | 2017-11-13 11:10:05 -0800 | [diff] [blame] | 92 |   struct __siov* iovp; /* for PRINT macro */ | 
| Elliott Hughes | 93a1f8b | 2017-11-07 22:52:29 -0800 | [diff] [blame] | 93 |   CHAR_TYPE buf[BUF];           /* buffer with space for digits of uintmax_t */ | 
 | 94 |   CHAR_TYPE ox[2];              /* space for 0x; ox[1] is either x, X, or \0 */ | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 95 |   union arg* argtable;     /* args, built due to positional arg */ | 
 | 96 |   union arg statargtable[STATIC_ARG_TBL_SIZE]; | 
 | 97 |   size_t argtablesiz; | 
 | 98 |   int nextarg;   /* 1-based argument index */ | 
 | 99 |   va_list orgap; /* original argument pointer */ | 
| Elliott Hughes | 93a1f8b | 2017-11-07 22:52:29 -0800 | [diff] [blame] | 100 |   CHAR_TYPE* convbuf; /* buffer for wide/multibyte conversion */ | 
| Elliott Hughes | 0549371 | 2014-04-17 17:30:03 -0700 | [diff] [blame] | 101 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 102 |   /* | 
 | 103 |    * Choose PADSIZE to trade efficiency vs. size.  If larger printf | 
 | 104 |    * fields occur frequently, increase PADSIZE and make the initialisers | 
 | 105 |    * below longer. | 
 | 106 |    */ | 
 | 107 | #define PADSIZE 16 /* pad chunk size */ | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 108 |   static CHAR_TYPE blanks[PADSIZE] = { | 
 | 109 |     ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' | 
 | 110 |   }; | 
 | 111 |   static CHAR_TYPE zeroes[PADSIZE] = { | 
 | 112 |     '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' | 
 | 113 |   }; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 114 |  | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 115 |   static const char xdigs_lower[] = "0123456789abcdef"; | 
 | 116 |   static const char xdigs_upper[] = "0123456789ABCDEF"; | 
| Elliott Hughes | 0549371 | 2014-04-17 17:30:03 -0700 | [diff] [blame] | 117 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 118 | #define PRINT(ptr, len)                   \ | 
 | 119 |   do {                                    \ | 
 | 120 |     iovp->iov_base = (ptr);               \ | 
 | 121 |     iovp->iov_len = (len);                \ | 
 | 122 |     uio.uio_resid += (len);               \ | 
 | 123 |     iovp++;                               \ | 
 | 124 |     if (++uio.uio_iovcnt >= NIOV) {       \ | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 125 |       if (helpers::sprint(fp, &uio)) goto error; \ | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 126 |       iovp = iov;                         \ | 
 | 127 |     }                                     \ | 
 | 128 |   } while (0) | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 129 | #define FLUSH()                                          \ | 
 | 130 |   do {                                                   \ | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 131 |     if (uio.uio_resid && helpers::sprint(fp, &uio)) goto error; \ | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 132 |     uio.uio_iovcnt = 0;                                  \ | 
 | 133 |     iovp = iov;                                          \ | 
 | 134 |   } while (0) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 135 |  | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 136 |   _SET_ORIENTATION(fp, CHAR_TYPE_ORIENTATION); | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 137 |  | 
 | 138 |   // Writing "" to a read only file returns EOF, not 0. | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 139 |   if (cantwrite(fp)) { | 
 | 140 |     errno = EBADF; | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 141 |     return EOF; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 142 |   } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 143 |  | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 144 |   // Optimize writes to stderr and other unbuffered files). | 
 | 145 |   if ((fp->_flags & (__SNBF | __SWR | __SRW)) == (__SNBF | __SWR) && fp->_file >= 0) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 146 |     return (__sbprintf(fp, fmt0, ap)); | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 147 |   } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 148 |  | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 149 |   CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 150 |   argtable = nullptr; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 151 |   nextarg = 1; | 
 | 152 |   va_copy(orgap, ap); | 
 | 153 |   uio.uio_iov = iovp = iov; | 
 | 154 |   uio.uio_resid = 0; | 
 | 155 |   uio.uio_iovcnt = 0; | 
 | 156 |   ret = 0; | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 157 |   convbuf = nullptr; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 158 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 159 |   /* | 
 | 160 |    * Scan the format for conversions (`%' character). | 
 | 161 |    */ | 
 | 162 |   for (;;) { | 
| Elliott Hughes | b70576b | 2017-11-13 11:10:05 -0800 | [diff] [blame] | 163 |     int ch; | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 164 |     for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 165 |     if (fmt != cp) { | 
 | 166 |       ptrdiff_t m = fmt - cp; | 
 | 167 |       if (m < 0 || m > INT_MAX - ret) goto overflow; | 
 | 168 |       PRINT(cp, m); | 
 | 169 |       ret += m; | 
 | 170 |     } | 
| Elliott Hughes | 5305a4d | 2017-11-03 14:00:37 -0700 | [diff] [blame] | 171 |     if (ch == '\0') goto done; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 172 |     fmt++; /* skip over '%' */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 173 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 174 |     flags = 0; | 
 | 175 |     dprec = 0; | 
 | 176 |     width = 0; | 
 | 177 |     prec = -1; | 
 | 178 |     sign = '\0'; | 
 | 179 |     ox[1] = '\0'; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 180 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 181 |   rflag: | 
 | 182 |     ch = *fmt++; | 
 | 183 |   reswitch: | 
 | 184 |     switch (ch) { | 
 | 185 |       case ' ': | 
 | 186 |         /* | 
 | 187 |          * ``If the space and + flags both appear, the space | 
 | 188 |          * flag will be ignored.'' | 
 | 189 |          *	-- ANSI X3J11 | 
 | 190 |          */ | 
 | 191 |         if (!sign) sign = ' '; | 
 | 192 |         goto rflag; | 
 | 193 |       case '#': | 
 | 194 |         flags |= ALT; | 
 | 195 |         goto rflag; | 
 | 196 |       case '\'': | 
 | 197 |         /* grouping not implemented */ | 
 | 198 |         goto rflag; | 
 | 199 |       case '*': | 
 | 200 |         /* | 
 | 201 |          * ``A negative field width argument is taken as a | 
 | 202 |          * - flag followed by a positive field width.'' | 
 | 203 |          *	-- ANSI X3J11 | 
 | 204 |          * They don't exclude field widths read from args. | 
 | 205 |          */ | 
 | 206 |         GETASTER(width); | 
 | 207 |         if (width >= 0) goto rflag; | 
 | 208 |         if (width == INT_MIN) goto overflow; | 
 | 209 |         width = -width; | 
| George Burgess IV | fa5410f | 2018-08-13 17:44:06 -0700 | [diff] [blame] | 210 |         __BIONIC_FALLTHROUGH; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 211 |       case '-': | 
 | 212 |         flags |= LADJUST; | 
 | 213 |         goto rflag; | 
 | 214 |       case '+': | 
 | 215 |         sign = '+'; | 
 | 216 |         goto rflag; | 
 | 217 |       case '.': | 
 | 218 |         if ((ch = *fmt++) == '*') { | 
 | 219 |           GETASTER(n); | 
 | 220 |           prec = n < 0 ? -1 : n; | 
 | 221 |           goto rflag; | 
 | 222 |         } | 
 | 223 |         n = 0; | 
 | 224 |         while (is_digit(ch)) { | 
 | 225 |           APPEND_DIGIT(n, ch); | 
 | 226 |           ch = *fmt++; | 
 | 227 |         } | 
 | 228 |         if (ch == '$') { | 
 | 229 |           nextarg = n; | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 230 |           if (argtable == nullptr) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 231 |             argtable = statargtable; | 
 | 232 |             if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { | 
 | 233 |               ret = -1; | 
 | 234 |               goto error; | 
 | 235 |             } | 
 | 236 |           } | 
 | 237 |           goto rflag; | 
 | 238 |         } | 
 | 239 |         prec = n; | 
 | 240 |         goto reswitch; | 
 | 241 |       case '0': | 
 | 242 |         /* | 
 | 243 |          * ``Note that 0 is taken as a flag, not as the | 
 | 244 |          * beginning of a field width.'' | 
 | 245 |          *	-- ANSI X3J11 | 
 | 246 |          */ | 
 | 247 |         flags |= ZEROPAD; | 
 | 248 |         goto rflag; | 
 | 249 |       case '1': | 
 | 250 |       case '2': | 
 | 251 |       case '3': | 
 | 252 |       case '4': | 
 | 253 |       case '5': | 
 | 254 |       case '6': | 
 | 255 |       case '7': | 
 | 256 |       case '8': | 
 | 257 |       case '9': | 
 | 258 |         n = 0; | 
 | 259 |         do { | 
 | 260 |           APPEND_DIGIT(n, ch); | 
 | 261 |           ch = *fmt++; | 
 | 262 |         } while (is_digit(ch)); | 
 | 263 |         if (ch == '$') { | 
 | 264 |           nextarg = n; | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 265 |           if (argtable == nullptr) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 266 |             argtable = statargtable; | 
 | 267 |             if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { | 
 | 268 |               ret = -1; | 
 | 269 |               goto error; | 
 | 270 |             } | 
 | 271 |           } | 
 | 272 |           goto rflag; | 
 | 273 |         } | 
 | 274 |         width = n; | 
 | 275 |         goto reswitch; | 
 | 276 |       case 'L': | 
 | 277 |         flags |= LONGDBL; | 
 | 278 |         goto rflag; | 
 | 279 |       case 'h': | 
 | 280 |         if (*fmt == 'h') { | 
 | 281 |           fmt++; | 
 | 282 |           flags |= CHARINT; | 
 | 283 |         } else { | 
 | 284 |           flags |= SHORTINT; | 
 | 285 |         } | 
 | 286 |         goto rflag; | 
 | 287 |       case 'j': | 
 | 288 |         flags |= MAXINT; | 
 | 289 |         goto rflag; | 
 | 290 |       case 'l': | 
 | 291 |         if (*fmt == 'l') { | 
 | 292 |           fmt++; | 
 | 293 |           flags |= LLONGINT; | 
 | 294 |         } else { | 
 | 295 |           flags |= LONGINT; | 
 | 296 |         } | 
 | 297 |         goto rflag; | 
 | 298 |       case 'q': | 
 | 299 |         flags |= LLONGINT; | 
 | 300 |         goto rflag; | 
 | 301 |       case 't': | 
 | 302 |         flags |= PTRINT; | 
 | 303 |         goto rflag; | 
 | 304 |       case 'z': | 
 | 305 |         flags |= SIZEINT; | 
 | 306 |         goto rflag; | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 307 |       case 'C': | 
 | 308 |         flags |= LONGINT; | 
| George Burgess IV | fa5410f | 2018-08-13 17:44:06 -0700 | [diff] [blame] | 309 |         __BIONIC_FALLTHROUGH; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 310 |       case 'c': | 
 | 311 |         if (flags & LONGINT) { | 
 | 312 |           mbstate_t mbs; | 
 | 313 |           size_t mbseqlen; | 
| Elliott Hughes | 0549371 | 2014-04-17 17:30:03 -0700 | [diff] [blame] | 314 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 315 |           memset(&mbs, 0, sizeof(mbs)); | 
 | 316 |           mbseqlen = wcrtomb(buf, (wchar_t)GETARG(wint_t), &mbs); | 
 | 317 |           if (mbseqlen == (size_t)-1) { | 
 | 318 |             ret = -1; | 
 | 319 |             goto error; | 
 | 320 |           } | 
 | 321 |           cp = buf; | 
 | 322 |           size = (int)mbseqlen; | 
 | 323 |         } else { | 
 | 324 |           *(cp = buf) = GETARG(int); | 
 | 325 |           size = 1; | 
 | 326 |         } | 
 | 327 |         sign = '\0'; | 
 | 328 |         break; | 
 | 329 |       case 'D': | 
 | 330 |         flags |= LONGINT; | 
| George Burgess IV | fa5410f | 2018-08-13 17:44:06 -0700 | [diff] [blame] | 331 |         __BIONIC_FALLTHROUGH; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 332 |       case 'd': | 
 | 333 |       case 'i': | 
 | 334 |         _umax = SARG(); | 
 | 335 |         if ((intmax_t)_umax < 0) { | 
 | 336 |           _umax = -_umax; | 
 | 337 |           sign = '-'; | 
 | 338 |         } | 
 | 339 |         base = DEC; | 
 | 340 |         goto number; | 
 | 341 |       case 'a': | 
 | 342 |       case 'A': | 
 | 343 |         if (ch == 'a') { | 
 | 344 |           ox[1] = 'x'; | 
 | 345 |           xdigs = xdigs_lower; | 
 | 346 |           expchar = 'p'; | 
 | 347 |         } else { | 
 | 348 |           ox[1] = 'X'; | 
 | 349 |           xdigs = xdigs_upper; | 
 | 350 |           expchar = 'P'; | 
 | 351 |         } | 
 | 352 |         if (prec >= 0) prec++; | 
 | 353 |         if (dtoaresult) __freedtoa(dtoaresult); | 
 | 354 |         if (flags & LONGDBL) { | 
 | 355 |           fparg.ldbl = GETARG(long double); | 
 | 356 |           dtoaresult = cp = __hldtoa(fparg.ldbl, xdigs, prec, &expt, &signflag, &dtoaend); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 357 |           if (dtoaresult == nullptr) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 358 |             errno = ENOMEM; | 
 | 359 |             goto error; | 
 | 360 |           } | 
 | 361 |         } else { | 
 | 362 |           fparg.dbl = GETARG(double); | 
 | 363 |           dtoaresult = cp = __hdtoa(fparg.dbl, xdigs, prec, &expt, &signflag, &dtoaend); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 364 |           if (dtoaresult == nullptr) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 365 |             errno = ENOMEM; | 
 | 366 |             goto error; | 
 | 367 |           } | 
 | 368 |         } | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 369 |         if (prec < 0) prec = dtoaend - dtoaresult; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 370 |         if (expt == INT_MAX) ox[1] = '\0'; | 
 | 371 |         goto fp_common; | 
 | 372 |       case 'e': | 
 | 373 |       case 'E': | 
 | 374 |         expchar = ch; | 
 | 375 |         if (prec < 0) /* account for digit before decpt */ | 
 | 376 |           prec = DEFPREC + 1; | 
 | 377 |         else | 
 | 378 |           prec++; | 
 | 379 |         goto fp_begin; | 
 | 380 |       case 'f': | 
 | 381 |       case 'F': | 
 | 382 |         expchar = '\0'; | 
 | 383 |         goto fp_begin; | 
 | 384 |       case 'g': | 
 | 385 |       case 'G': | 
 | 386 |         expchar = ch - ('g' - 'e'); | 
 | 387 |         if (prec == 0) prec = 1; | 
 | 388 |       fp_begin: | 
 | 389 |         if (prec < 0) prec = DEFPREC; | 
 | 390 |         if (dtoaresult) __freedtoa(dtoaresult); | 
 | 391 |         if (flags & LONGDBL) { | 
 | 392 |           fparg.ldbl = GETARG(long double); | 
 | 393 |           dtoaresult = cp = __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 394 |           if (dtoaresult == nullptr) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 395 |             errno = ENOMEM; | 
 | 396 |             goto error; | 
 | 397 |           } | 
 | 398 |         } else { | 
 | 399 |           fparg.dbl = GETARG(double); | 
 | 400 |           dtoaresult = cp = __dtoa(fparg.dbl, expchar ? 2 : 3, prec, &expt, &signflag, &dtoaend); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 401 |           if (dtoaresult == nullptr) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 402 |             errno = ENOMEM; | 
 | 403 |             goto error; | 
 | 404 |           } | 
 | 405 |           if (expt == 9999) expt = INT_MAX; | 
 | 406 |         } | 
 | 407 |       fp_common: | 
 | 408 |         if (signflag) sign = '-'; | 
 | 409 |         if (expt == INT_MAX) { /* inf or nan */ | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 410 |           if (*cp == 'N') { | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 411 |             cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_nan : CHAR_TYPE_NAN); | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 412 |           } else { | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 413 |             cp = const_cast<CHAR_TYPE*>((ch >= 'a') ? CHAR_TYPE_inf : CHAR_TYPE_INF); | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 414 |           } | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 415 |           size = 3; | 
 | 416 |           flags &= ~ZEROPAD; | 
 | 417 |           break; | 
 | 418 |         } | 
 | 419 |         flags |= FPT; | 
 | 420 |         ndig = dtoaend - cp; | 
 | 421 |         if (ch == 'g' || ch == 'G') { | 
 | 422 |           if (expt > -4 && expt <= prec) { | 
 | 423 |             /* Make %[gG] smell like %[fF] */ | 
 | 424 |             expchar = '\0'; | 
 | 425 |             if (flags & ALT) | 
 | 426 |               prec -= expt; | 
 | 427 |             else | 
 | 428 |               prec = ndig - expt; | 
 | 429 |             if (prec < 0) prec = 0; | 
 | 430 |           } else { | 
 | 431 |             /* | 
 | 432 |              * Make %[gG] smell like %[eE], but | 
 | 433 |              * trim trailing zeroes if no # flag. | 
 | 434 |              */ | 
 | 435 |             if (!(flags & ALT)) prec = ndig; | 
 | 436 |           } | 
 | 437 |         } | 
 | 438 |         if (expchar) { | 
 | 439 |           expsize = exponent(expstr, expt - 1, expchar); | 
 | 440 |           size = expsize + prec; | 
 | 441 |           if (prec > 1 || flags & ALT) ++size; | 
 | 442 |         } else { | 
 | 443 |           /* space for digits before decimal point */ | 
 | 444 |           if (expt > 0) | 
 | 445 |             size = expt; | 
 | 446 |           else /* "0" */ | 
 | 447 |             size = 1; | 
 | 448 |           /* space for decimal pt and following digits */ | 
 | 449 |           if (prec || flags & ALT) size += prec + 1; | 
 | 450 |           lead = expt; | 
 | 451 |         } | 
 | 452 |         break; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 453 |       case 'n': | 
| Elliott Hughes | 41398d0 | 2018-03-07 13:32:58 -0800 | [diff] [blame] | 454 |         __fortify_fatal("%%n not allowed on Android"); | 
| Elliott Hughes | 654cd83 | 2018-08-30 16:00:42 -0700 | [diff] [blame] | 455 |       case 'm': | 
| Elliott Hughes | f340a56 | 2018-09-06 10:42:40 -0700 | [diff] [blame] | 456 |         cp = strerror_r(caller_errno, buf, sizeof(buf)); | 
| Elliott Hughes | 654cd83 | 2018-08-30 16:00:42 -0700 | [diff] [blame] | 457 |         goto string; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 458 |       case 'O': | 
 | 459 |         flags |= LONGINT; | 
| George Burgess IV | fa5410f | 2018-08-13 17:44:06 -0700 | [diff] [blame] | 460 |         __BIONIC_FALLTHROUGH; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 461 |       case 'o': | 
 | 462 |         _umax = UARG(); | 
 | 463 |         base = OCT; | 
 | 464 |         goto nosign; | 
 | 465 |       case 'p': | 
 | 466 |         /* | 
 | 467 |          * ``The argument shall be a pointer to void.  The | 
 | 468 |          * value of the pointer is converted to a sequence | 
 | 469 |          * of printable characters, in an implementation- | 
 | 470 |          * defined manner.'' | 
 | 471 |          *	-- ANSI X3J11 | 
 | 472 |          */ | 
 | 473 |         _umax = (u_long)GETARG(void*); | 
 | 474 |         base = HEX; | 
 | 475 |         xdigs = xdigs_lower; | 
 | 476 |         ox[1] = 'x'; | 
 | 477 |         goto nosign; | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 478 |       case 'S': | 
 | 479 |         flags |= LONGINT; | 
| George Burgess IV | fa5410f | 2018-08-13 17:44:06 -0700 | [diff] [blame] | 480 |         __BIONIC_FALLTHROUGH; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 481 |       case 's': | 
 | 482 |         if (flags & LONGINT) { | 
 | 483 |           wchar_t* wcp; | 
| Elliott Hughes | 0549371 | 2014-04-17 17:30:03 -0700 | [diff] [blame] | 484 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 485 |           free(convbuf); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 486 |           convbuf = nullptr; | 
 | 487 |           if ((wcp = GETARG(wchar_t*)) == nullptr) { | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 488 |             cp = const_cast<char*>("(null)"); | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 489 |           } else { | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 490 |             convbuf = helpers::wcsconv(wcp, prec); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 491 |             if (convbuf == nullptr) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 492 |               ret = -1; | 
 | 493 |               goto error; | 
 | 494 |             } | 
 | 495 |             cp = convbuf; | 
 | 496 |           } | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 497 |         } else if ((cp = GETARG(char*)) == nullptr) { | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 498 |           cp = const_cast<char*>("(null)"); | 
 | 499 |         } | 
| Elliott Hughes | 654cd83 | 2018-08-30 16:00:42 -0700 | [diff] [blame] | 500 |   string: | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 501 |         if (prec >= 0) { | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 502 |           size = CHAR_TYPE_STRNLEN(cp, prec); | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 503 |         } else { | 
 | 504 |           size_t len; | 
| Elliott Hughes | 0549371 | 2014-04-17 17:30:03 -0700 | [diff] [blame] | 505 |  | 
| Elliott Hughes | bc27bdc | 2017-11-10 15:25:49 -0800 | [diff] [blame] | 506 |           if ((len = CHAR_TYPE_STRLEN(cp)) > INT_MAX) goto overflow; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 507 |           size = (int)len; | 
 | 508 |         } | 
 | 509 |         sign = '\0'; | 
 | 510 |         break; | 
 | 511 |       case 'U': | 
 | 512 |         flags |= LONGINT; | 
| George Burgess IV | fa5410f | 2018-08-13 17:44:06 -0700 | [diff] [blame] | 513 |         __BIONIC_FALLTHROUGH; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 514 |       case 'u': | 
 | 515 |         _umax = UARG(); | 
 | 516 |         base = DEC; | 
 | 517 |         goto nosign; | 
 | 518 |       case 'X': | 
 | 519 |         xdigs = xdigs_upper; | 
 | 520 |         goto hex; | 
 | 521 |       case 'x': | 
 | 522 |         xdigs = xdigs_lower; | 
 | 523 |       hex: | 
 | 524 |         _umax = UARG(); | 
 | 525 |         base = HEX; | 
 | 526 |         /* leading 0x/X only if non-zero */ | 
 | 527 |         if (flags & ALT && _umax != 0) ox[1] = ch; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 528 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 529 |         /* unsigned conversions */ | 
 | 530 |       nosign: | 
 | 531 |         sign = '\0'; | 
 | 532 |         /* | 
 | 533 |          * ``... diouXx conversions ... if a precision is | 
 | 534 |          * specified, the 0 flag will be ignored.'' | 
 | 535 |          *	-- ANSI X3J11 | 
 | 536 |          */ | 
 | 537 |       number: | 
 | 538 |         if ((dprec = prec) >= 0) flags &= ~ZEROPAD; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 539 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 540 |         /* | 
 | 541 |          * ``The result of converting a zero value with an | 
 | 542 |          * explicit precision of zero is no characters.'' | 
 | 543 |          *	-- ANSI X3J11 | 
 | 544 |          */ | 
 | 545 |         cp = buf + BUF; | 
 | 546 |         if (_umax != 0 || prec != 0) { | 
 | 547 |           /* | 
 | 548 |            * Unsigned mod is hard, and unsigned mod | 
 | 549 |            * by a constant is easier than that by | 
 | 550 |            * a variable; hence this switch. | 
 | 551 |            */ | 
 | 552 |           switch (base) { | 
 | 553 |             case OCT: | 
 | 554 |               do { | 
 | 555 |                 *--cp = to_char(_umax & 7); | 
 | 556 |                 _umax >>= 3; | 
 | 557 |               } while (_umax); | 
 | 558 |               /* handle octal leading 0 */ | 
 | 559 |               if (flags & ALT && *cp != '0') *--cp = '0'; | 
 | 560 |               break; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 561 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 562 |             case DEC: | 
 | 563 |               /* many numbers are 1 digit */ | 
 | 564 |               while (_umax >= 10) { | 
 | 565 |                 *--cp = to_char(_umax % 10); | 
 | 566 |                 _umax /= 10; | 
 | 567 |               } | 
 | 568 |               *--cp = to_char(_umax); | 
 | 569 |               break; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 570 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 571 |             case HEX: | 
 | 572 |               do { | 
 | 573 |                 *--cp = xdigs[_umax & 15]; | 
 | 574 |                 _umax >>= 4; | 
 | 575 |               } while (_umax); | 
 | 576 |               break; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 577 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 578 |             default: | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 579 |               abort(); | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 580 |           } | 
 | 581 |         } | 
 | 582 |         size = buf + BUF - cp; | 
| Elliott Hughes | 2f9c8ce | 2017-11-01 13:54:47 -0700 | [diff] [blame] | 583 |         if (size > BUF) abort(); /* should never happen */ | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 584 |         break; | 
 | 585 |       default: /* "%?" prints ?, unless ? is NUL */ | 
 | 586 |         if (ch == '\0') goto done; | 
 | 587 |         /* pretend it was %c with argument ch */ | 
 | 588 |         cp = buf; | 
 | 589 |         *cp = ch; | 
 | 590 |         size = 1; | 
 | 591 |         sign = '\0'; | 
 | 592 |         break; | 
 | 593 |     } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 594 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 595 |     /* | 
 | 596 |      * All reasonable formats wind up here.  At this point, `cp' | 
 | 597 |      * points to a string which (if not flags&LADJUST) should be | 
 | 598 |      * padded out to `width' places.  If flags&ZEROPAD, it should | 
 | 599 |      * first be prefixed by any sign or other prefix; otherwise, | 
 | 600 |      * it should be blank padded before the prefix is emitted. | 
 | 601 |      * After any left-hand padding and prefixing, emit zeroes | 
 | 602 |      * required by a decimal %[diouxX] precision, then print the | 
 | 603 |      * string proper, then emit zeroes required by any leftover | 
 | 604 |      * floating precision; finally, if LADJUST, pad with blanks. | 
 | 605 |      * | 
 | 606 |      * Compute actual size, so we know how much to pad. | 
 | 607 |      * size excludes decimal prec; realsz includes it. | 
 | 608 |      */ | 
 | 609 |     realsz = dprec > size ? dprec : size; | 
 | 610 |     if (sign) realsz++; | 
 | 611 |     if (ox[1]) realsz += 2; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 612 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 613 |     /* right-adjusting blank padding */ | 
 | 614 |     if ((flags & (LADJUST | ZEROPAD)) == 0) PAD(width - realsz, blanks); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 615 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 616 |     /* prefix */ | 
 | 617 |     if (sign) PRINT(&sign, 1); | 
 | 618 |     if (ox[1]) { /* ox[1] is either x, X, or \0 */ | 
 | 619 |       ox[0] = '0'; | 
 | 620 |       PRINT(ox, 2); | 
 | 621 |     } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 622 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 623 |     /* right-adjusting zero padding */ | 
 | 624 |     if ((flags & (LADJUST | ZEROPAD)) == ZEROPAD) PAD(width - realsz, zeroes); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 625 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 626 |     /* leading zeroes from decimal precision */ | 
 | 627 |     PAD(dprec - size, zeroes); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 628 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 629 |     /* the string or number proper */ | 
 | 630 |     if ((flags & FPT) == 0) { | 
 | 631 |       PRINT(cp, size); | 
 | 632 |     } else { /* glue together f_p fragments */ | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 633 |       if (decimal_point == nullptr) decimal_point = nl_langinfo(RADIXCHAR); | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 634 |       if (!expchar) { /* %[fF] or sufficiently short %[gG] */ | 
 | 635 |         if (expt <= 0) { | 
 | 636 |           PRINT(zeroes, 1); | 
 | 637 |           if (prec || flags & ALT) PRINT(decimal_point, 1); | 
 | 638 |           PAD(-expt, zeroes); | 
 | 639 |           /* already handled initial 0's */ | 
 | 640 |           prec += expt; | 
 | 641 |         } else { | 
 | 642 |           PRINTANDPAD(cp, dtoaend, lead, zeroes); | 
 | 643 |           cp += lead; | 
 | 644 |           if (prec || flags & ALT) PRINT(decimal_point, 1); | 
 | 645 |         } | 
 | 646 |         PRINTANDPAD(cp, dtoaend, prec, zeroes); | 
 | 647 |       } else { /* %[eE] or sufficiently long %[gG] */ | 
 | 648 |         if (prec > 1 || flags & ALT) { | 
 | 649 |           buf[0] = *cp++; | 
 | 650 |           buf[1] = *decimal_point; | 
 | 651 |           PRINT(buf, 2); | 
 | 652 |           PRINT(cp, ndig - 1); | 
 | 653 |           PAD(prec - ndig, zeroes); | 
 | 654 |         } else { /* XeYYY */ | 
 | 655 |           PRINT(cp, 1); | 
 | 656 |         } | 
 | 657 |         PRINT(expstr, expsize); | 
 | 658 |       } | 
 | 659 |     } | 
 | 660 |     /* left-adjusting padding (always blank) */ | 
 | 661 |     if (flags & LADJUST) PAD(width - realsz, blanks); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 662 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 663 |     /* finally, adjust ret */ | 
 | 664 |     if (width < realsz) width = realsz; | 
 | 665 |     if (width > INT_MAX - ret) goto overflow; | 
 | 666 |     ret += width; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 667 |  | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 668 |     FLUSH(); /* copy out the I/O vectors */ | 
 | 669 |   } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 670 | done: | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 671 |   FLUSH(); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 672 | error: | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 673 |   va_end(orgap); | 
 | 674 |   if (__sferror(fp)) ret = -1; | 
 | 675 |   goto finish; | 
| Elliott Hughes | 0549371 | 2014-04-17 17:30:03 -0700 | [diff] [blame] | 676 |  | 
 | 677 | overflow: | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 678 |   errno = ENOMEM; | 
 | 679 |   ret = -1; | 
| Elliott Hughes | 0549371 | 2014-04-17 17:30:03 -0700 | [diff] [blame] | 680 |  | 
 | 681 | finish: | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 682 |   free(convbuf); | 
 | 683 |   if (dtoaresult) __freedtoa(dtoaresult); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 684 |   if (argtable != nullptr && argtable != statargtable) { | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 685 |     munmap(argtable, argtablesiz); | 
| Yi Kong | 32bc0fc | 2018-08-02 17:31:13 -0700 | [diff] [blame] | 686 |     argtable = nullptr; | 
| Elliott Hughes | c8f2c52 | 2017-10-31 13:07:51 -0700 | [diff] [blame] | 687 |   } | 
 | 688 |   return (ret); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 689 | } |