1 /*
2 Copyright (C) 2005-2012 Rich Felker
3
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the
6 "Software"), to deal in the Software without restriction, including
7 without limitation the rights to use, copy, modify, merge, publish,
8 distribute, sublicense, and/or sell copies of the Software, and to
9 permit persons to whom the Software is furnished to do so, subject to
10 the following conditions:
11
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 Modified in 2013 for the Android Open Source Project.
24 */
25
26 #include <errno.h>
27 #include <ctype.h>
28 #include <limits.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <wchar.h>
33 #include <inttypes.h>
34
35 #include "stdio_impl.h"
36
37 /* Convenient bit representation for modifier flags, which all fall
38 * within 31 codepoints of the space character. */
39
40 #define ALT_FORM (1U<<'#'-' ')
41 #define ZERO_PAD (1U<<'0'-' ')
42 #define LEFT_ADJ (1U<<'-'-' ')
43 #define PAD_POS (1U<<' '-' ')
44 #define MARK_POS (1U<<'+'-' ')
45 #define GROUPED (1U<<'\''-' ')
46
47 #define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
48
49 #if UINT_MAX == ULONG_MAX
50 #define LONG_IS_INT
51 #endif
52
53 #if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX
54 #define ODD_TYPES
55 #endif
56
57 /* State machine to accept length modifiers + conversion specifiers.
58 * Result is 0 on failure, or an argument type to pop on success. */
59
60 enum {
61 BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
62 ZTPRE, JPRE,
63 STOP,
64 PTR, INT, UINT, ULLONG,
65 #ifndef LONG_IS_INT
66 LONG, ULONG,
67 #else
68 #define LONG INT
69 #define ULONG UINT
70 #endif
71 SHORT, USHORT, CHAR, UCHAR,
72 #ifdef ODD_TYPES
73 LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
74 #else
75 #define LLONG ULLONG
76 #define SIZET ULONG
77 #define IMAX LLONG
78 #define UMAX ULLONG
79 #define PDIFF LONG
80 #define UIPTR ULONG
81 #endif
82 DBL, LDBL,
83 NOARG,
84 MAXSTATE
85 };
86
87 #define S(x) [(x)-'A']
88
89 static const unsigned char states[]['z'-'A'+1] = {
90 { /* 0: bare types */
91 S('d') = INT, S('i') = INT,
92 S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
93 S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
94 S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
95 S('c') = CHAR, S('C') = INT,
96 S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
97 S('m') = NOARG,
98 S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
99 S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
100 }, { /* 1: l-prefixed */
101 S('d') = LONG, S('i') = LONG,
102 S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
103 S('c') = INT, S('s') = PTR, S('n') = PTR,
104 S('l') = LLPRE,
105 }, { /* 2: ll-prefixed */
106 S('d') = LLONG, S('i') = LLONG,
107 S('o') = ULLONG, S('u') = ULLONG,
108 S('x') = ULLONG, S('X') = ULLONG,
109 S('n') = PTR,
110 }, { /* 3: h-prefixed */
111 S('d') = SHORT, S('i') = SHORT,
112 S('o') = USHORT, S('u') = USHORT,
113 S('x') = USHORT, S('X') = USHORT,
114 S('n') = PTR,
115 S('h') = HHPRE,
116 }, { /* 4: hh-prefixed */
117 S('d') = CHAR, S('i') = CHAR,
118 S('o') = UCHAR, S('u') = UCHAR,
119 S('x') = UCHAR, S('X') = UCHAR,
120 S('n') = PTR,
121 }, { /* 5: L-prefixed */
122 S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
123 S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
124 S('n') = PTR,
125 }, { /* 6: z- or t-prefixed (assumed to be same size) */
126 S('d') = PDIFF, S('i') = PDIFF,
127 S('o') = SIZET, S('u') = SIZET,
128 S('x') = SIZET, S('X') = SIZET,
129 S('n') = PTR,
130 }, { /* 7: j-prefixed */
131 S('d') = IMAX, S('i') = IMAX,
132 S('o') = UMAX, S('u') = UMAX,
133 S('x') = UMAX, S('X') = UMAX,
134 S('n') = PTR,
135 }
136 };
137
138 #define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
139
140 union arg
141 {
142 uintmax_t i;
143 long double f;
144 void *p;
145 };
146
pop_arg(union arg * arg,int type,va_list * ap)147 static void pop_arg(union arg *arg, int type, va_list *ap)
148 {
149 /* Give the compiler a hint for optimizing the switch. */
150 if ((unsigned)type > MAXSTATE) return;
151 switch (type) {
152 case PTR: arg->p = va_arg(*ap, void *);
153 break; case INT: arg->i = va_arg(*ap, int);
154 break; case UINT: arg->i = va_arg(*ap, unsigned int);
155 #ifndef LONG_IS_INT
156 break; case LONG: arg->i = va_arg(*ap, long);
157 break; case ULONG: arg->i = va_arg(*ap, unsigned long);
158 #endif
159 break; case ULLONG: arg->i = va_arg(*ap, unsigned long long);
160 break; case SHORT: arg->i = (short)va_arg(*ap, int);
161 break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int);
162 break; case CHAR: arg->i = (signed char)va_arg(*ap, int);
163 break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int);
164 #ifdef ODD_TYPES
165 break; case LLONG: arg->i = va_arg(*ap, long long);
166 break; case SIZET: arg->i = va_arg(*ap, size_t);
167 break; case IMAX: arg->i = va_arg(*ap, intmax_t);
168 break; case UMAX: arg->i = va_arg(*ap, uintmax_t);
169 break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t);
170 break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *);
171 #endif
172 break; case DBL: arg->f = va_arg(*ap, double);
173 break; case LDBL: arg->f = va_arg(*ap, long double);
174 }
175 }
176
out(FILE * f,const wchar_t * s,size_t l)177 static void out(FILE *f, const wchar_t *s, size_t l)
178 {
179 #if defined(__ANDROID__)
180 fake_file_outw(f, s, l);
181 #else
182 while (l--) fputwc(*s++, f);
183 #endif
184 }
185
getint(wchar_t ** s)186 static int getint(wchar_t **s) {
187 int i;
188 for (i=0; iswdigit(**s); (*s)++)
189 i = 10*i + (**s-'0');
190 return i;
191 }
192
193 static const char sizeprefix['y'-'a'] = {
194 ['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L',
195 ['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j',
196 ['p'-'a']='j'
197 };
198
wprintf_core(FILE * f,const wchar_t * fmt,va_list * ap,union arg * nl_arg,int * nl_type)199 static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
200 {
201 wchar_t *a, *z, *s=(wchar_t *)fmt, *s0;
202 unsigned l10n=0, litpct, fl;
203 int w, p;
204 union arg arg;
205 int argpos;
206 unsigned st, ps;
207 int cnt=0, l=0;
208 int i;
209 int t;
210 char *bs;
211 char charfmt[16];
212 wchar_t wc;
213
214 for (;;) {
215 /* Update output count, end loop when fmt is exhausted */
216 if (cnt >= 0) {
217 if (l > INT_MAX - cnt) {
218 if (!ferror(f)) errno = EOVERFLOW;
219 cnt = -1;
220 } else cnt += l;
221 }
222 if (!*s) break;
223
224 /* Handle literal text and %% format specifiers */
225 for (a=s; *s && *s!='%'; s++);
226 litpct = wcsspn(s, L"%")/2; /* Optimize %%%% runs */
227 z = s+litpct;
228 s += 2*litpct;
229 l = z-a;
230 if (f) out(f, a, l);
231 if (l) continue;
232
233 if (iswdigit(s[1]) && s[2]=='$') {
234 l10n=1;
235 argpos = s[1]-'0';
236 s+=3;
237 } else {
238 argpos = -1;
239 s++;
240 }
241
242 /* Read modifier flags */
243 for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
244 fl |= 1U<<*s-' ';
245
246 /* Read field width */
247 if (*s=='*') {
248 if (iswdigit(s[1]) && s[2]=='$') {
249 l10n=1;
250 nl_type[s[1]-'0'] = INT;
251 w = nl_arg[s[1]-'0'].i;
252 s+=3;
253 } else if (!l10n) {
254 w = f ? va_arg(*ap, int) : 0;
255 s++;
256 } else return -1;
257 if (w<0) fl|=LEFT_ADJ, w=-w;
258 } else if ((w=getint(&s))<0) return -1;
259
260 /* Read precision */
261 if (*s=='.' && s[1]=='*') {
262 if (isdigit(s[2]) && s[3]=='$') {
263 nl_type[s[2]-'0'] = INT;
264 p = nl_arg[s[2]-'0'].i;
265 s+=4;
266 } else if (!l10n) {
267 p = f ? va_arg(*ap, int) : 0;
268 s+=2;
269 } else return -1;
270 } else if (*s=='.') {
271 s++;
272 p = getint(&s);
273 } else p = -1;
274
275 /* Format specifier state machine */
276 s0=s;
277 st=0;
278 do {
279 if (OOB(*s)) return -1;
280 ps=st;
281 st=states[st]S(*s++);
282 } while (st-1<STOP);
283 if (!st) return -1;
284
285 /* Check validity of argument type (nl/normal) */
286 if (st==NOARG) {
287 if (argpos>=0) return -1;
288 else if (!f) continue;
289 } else {
290 if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
291 else if (f) pop_arg(&arg, st, ap);
292 else return 0;
293 }
294
295 if (!f) continue;
296 t = s[-1];
297 if (ps && (t&15)==3) t&=~32;
298
299 switch (t) {
300 case 'n':
301 #ifndef __ANDROID__ /* Disabled on Android for security reasons. */
302 switch(ps) {
303 case BARE: *(int *)arg.p = cnt; break;
304 case LPRE: *(long *)arg.p = cnt; break;
305 case LLPRE: *(long long *)arg.p = cnt; break;
306 case HPRE: *(unsigned short *)arg.p = cnt; break;
307 case HHPRE: *(unsigned char *)arg.p = cnt; break;
308 case ZTPRE: *(size_t *)arg.p = cnt; break;
309 case JPRE: *(uintmax_t *)arg.p = cnt; break;
310 }
311 #endif /* !__ANDROID__ */
312 continue;
313 case 'c':
314 fputwc(btowc(arg.i), f);
315 l = 1;
316 continue;
317 case 'C':
318 fputwc(arg.i, f);
319 l = 1;
320 continue;
321 case 'S':
322 a = arg.p;
323 z = wmemchr(a, 0, p);
324 if (!z) z=a+p;
325 else p=z-a;
326 if (w<p) w=p;
327 if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
328 out(f, a, p);
329 if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
330 l=w;
331 continue;
332 case 's':
333 bs = arg.p;
334 if (p<0) p = INT_MAX;
335 for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
336 if (i<0) return -1;
337 p=l;
338 if (w<p) w=p;
339 if (!(fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
340 bs = arg.p;
341 while (l--) {
342 i=mbtowc(&wc, bs, MB_LEN_MAX);
343 bs+=i;
344 fputwc(wc, f);
345 }
346 if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, "");
347 l=w;
348 continue;
349 }
350
351 snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c",
352 "#"+!(fl & ALT_FORM),
353 "+"+!(fl & MARK_POS),
354 "-"+!(fl & LEFT_ADJ),
355 " "+!(fl & PAD_POS),
356 "0"+!(fl & ZERO_PAD),
357 sizeprefix[(t|32)-'a'], t);
358
359 switch (t|32) {
360 case 'a': case 'e': case 'f': case 'g':
361 l = fprintf(f, charfmt, w, p, arg.f);
362 break;
363 case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
364 l = fprintf(f, charfmt, w, p, arg.i);
365 break;
366 }
367 }
368
369 if (f) return cnt;
370 if (!l10n) return 0;
371
372 for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
373 pop_arg(nl_arg+i, nl_type[i], ap);
374 for (; i<=NL_ARGMAX && !nl_type[i]; i++);
375 if (i<=NL_ARGMAX) return -1;
376 return 1;
377 }
378
379 #ifdef __ANDROID__
380 #undef FILE /* no longer needed */
vfwprintf(FILE * restrict f,const wchar_t * restrict fmt,va_list ap)381 int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
382 {
383 va_list ap2;
384 int nl_type[NL_ARGMAX] = {0};
385 union arg nl_arg[NL_ARGMAX];
386 int ret;
387 FakeFILE out[1];
388 fake_file_init_file(out, f);
389 va_copy(ap2, ap);
390 // Check for error in format string before writing anything to file.
391 if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
392 va_end(ap2);
393 return -1;
394 }
395 ret = wprintf_core(out, fmt, &ap2, nl_arg, nl_type);
396 va_end(ap2);
397 return ret;
398 }
399
vswprintf(wchar_t * restrict s,size_t l,const wchar_t * restrict fmt,va_list ap)400 int vswprintf(wchar_t *restrict s, size_t l, const wchar_t *restrict fmt, va_list ap)
401 {
402 va_list ap2;
403 int nl_type[NL_ARGMAX] = {0};
404 union arg nl_arg[NL_ARGMAX];
405 int ret;
406 FakeFILE out[1];
407 fake_file_init_wbuffer(out, s, l);
408 va_copy(ap2, ap);
409 ret = wprintf_core(out, fmt, &ap2, nl_arg, nl_type);
410 va_end(ap2);
411 if (fake_feof(out)) return -1;
412 return ret;
413 }
414 #else /* !__ANDROID__ */
vfwprintf(FILE * restrict f,const wchar_t * restrict fmt,va_list ap)415 int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
416 {
417 va_list ap2;
418 int nl_type[NL_ARGMAX] = {0};
419 union arg nl_arg[NL_ARGMAX];
420 int ret;
421
422 va_copy(ap2, ap);
423 if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) return -1;
424
425 FLOCK(f);
426 ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type);
427 FUNLOCK(f);
428 va_end(ap2);
429 return ret;
430 }
431 #endif /* !__ANDROID__ */
432