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