• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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