Home | History | Annotate | Download | only in stdio
      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 "stdio_impl.h"
     27 #include <errno.h>
     28 #include <ctype.h>
     29 #include <limits.h>
     30 #include <string.h>
     31 #include <stdarg.h>
     32 #include <wchar.h>
     33 #include <inttypes.h>
     34 
     35 // A wrapper around either a FILE* or a string buffer, used to output
     36 // the result of formatted expansion.
     37 typedef struct {
     38   FILE*    file;
     39   wchar_t* buffer;
     40   size_t   buffer_pos;
     41   size_t   buffer_size;
     42 } Out;
     43 
     44 void out_init_file(Out* out, FILE* f) {
     45   memset(out, 0, sizeof(*out));
     46   out->file = f;
     47 }
     48 
     49 void out_init_buffer(Out* out, wchar_t* buffer, size_t buffer_size) {
     50   memset(out, 0, sizeof(*out));
     51   out->buffer = buffer;
     52   out->buffer_pos = 0;
     53   out->buffer_size = buffer_size;
     54 }
     55 
     56 void out_write(Out* out, const wchar_t* text, size_t length) {
     57   if (out->file != NULL) {
     58     // Write into a file the UTF-8 encoded version.
     59     // TODO(digit): Support locale-specific encoding.
     60     size_t mb_len = wcstombs(NULL, text, length);
     61     char* mb_buffer = malloc(mb_len);
     62     wcstombs(mb_buffer, text, length);
     63     fwrite(mb_buffer, 1, mb_len, out->file);
     64     free(mb_buffer);
     65   } else {
     66     // Write into a bounded buffer.
     67     size_t avail = out->buffer_size - out->buffer_pos;
     68     if (length > avail)
     69       length = avail;
     70     memcpy((char*)(out->buffer + out->buffer_pos),
     71            (const char*)text,
     72            length * sizeof(wchar_t));
     73     out->buffer_pos += length;
     74   }
     75 }
     76 
     77 void out_putwc(Out* out, wchar_t wc) {
     78   if (out->file)
     79     fputwc(wc, out->file);
     80   else {
     81     if (out->buffer_pos < out->buffer_size)
     82       out->buffer[out->buffer_pos++] = wc;
     83   }
     84 }
     85 
     86 int out_printf(Out* out, const char* format, ...) {
     87   va_list args;
     88   va_start(args, format);
     89   if (out->file)
     90     return vfprintf(out->file, format, args);
     91   else {
     92     // TODO(digit): Make this faster.
     93     // First, generate formatted byte output.
     94     int mb_len = vsnprintf(NULL, 0, format, args);
     95     char* mb_buffer = malloc(mb_len + 1);
     96     vsnprintf(mb_buffer, mb_len + 1, format, args);
     97     // Then convert to wchar_t buffer.
     98     size_t wide_len = mbstowcs(NULL, mb_buffer, mb_len);
     99     wchar_t* wide_buffer = malloc((wide_len + 1) * sizeof(wchar_t));
    100     mbstowcs(wide_buffer, mb_buffer, mb_len);
    101     // Add to buffer.
    102     out_write(out, wide_buffer, wide_len);
    103     // finished
    104     free(wide_buffer);
    105     free(mb_buffer);
    106 
    107     return wide_len;
    108   }
    109   va_end(args);
    110 }
    111 int out_error(Out* out) {
    112   if (out->file != NULL)
    113     return ferror(out->file);
    114 
    115   return 0;
    116 }
    117 
    118 int out_overflow(Out* out) {
    119   if (out->file != NULL)
    120     return feof(out->file);
    121   else
    122     return (out->buffer_pos >= out->buffer_size);
    123 }
    124 
    125 /* Convenient bit representation for modifier flags, which all fall
    126  * within 31 codepoints of the space character. */
    127 
    128 #define ALT_FORM   (1U<<'#'-' ')
    129 #define ZERO_PAD   (1U<<'0'-' ')
    130 #define LEFT_ADJ   (1U<<'-'-' ')
    131 #define PAD_POS    (1U<<' '-' ')
    132 #define MARK_POS   (1U<<'+'-' ')
    133 #define GROUPED    (1U<<'\''-' ')
    134 
    135 #define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED)
    136 
    137 #if UINT_MAX == ULONG_MAX
    138 #define LONG_IS_INT
    139 #endif
    140 
    141 #if SIZE_MAX != ULONG_MAX || UINTMAX_MAX != ULLONG_MAX
    142 #define ODD_TYPES
    143 #endif
    144 
    145 /* State machine to accept length modifiers + conversion specifiers.
    146  * Result is 0 on failure, or an argument type to pop on success. */
    147 
    148 enum {
    149 	BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE,
    150 	ZTPRE, JPRE,
    151 	STOP,
    152 	PTR, INT, UINT, ULLONG,
    153 #ifndef LONG_IS_INT
    154 	LONG, ULONG,
    155 #else
    156 #define LONG INT
    157 #define ULONG UINT
    158 #endif
    159 	SHORT, USHORT, CHAR, UCHAR,
    160 #ifdef ODD_TYPES
    161 	LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR,
    162 #else
    163 #define LLONG ULLONG
    164 #define SIZET ULONG
    165 #define IMAX LLONG
    166 #define UMAX ULLONG
    167 #define PDIFF LONG
    168 #define UIPTR ULONG
    169 #endif
    170 	DBL, LDBL,
    171 	NOARG,
    172 	MAXSTATE
    173 };
    174 
    175 #define S(x) [(x)-'A']
    176 
    177 static const unsigned char states[]['z'-'A'+1] = {
    178 	{ /* 0: bare types */
    179 		S('d') = INT, S('i') = INT,
    180 		S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT,
    181 		S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL,
    182 		S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL,
    183 		S('c') = CHAR, S('C') = INT,
    184 		S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR,
    185 		S('m') = NOARG,
    186 		S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE,
    187 		S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE,
    188 	}, { /* 1: l-prefixed */
    189 		S('d') = LONG, S('i') = LONG,
    190 		S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG,
    191 		S('c') = INT, S('s') = PTR, S('n') = PTR,
    192 		S('l') = LLPRE,
    193 	}, { /* 2: ll-prefixed */
    194 		S('d') = LLONG, S('i') = LLONG,
    195 		S('o') = ULLONG, S('u') = ULLONG,
    196 		S('x') = ULLONG, S('X') = ULLONG,
    197 		S('n') = PTR,
    198 	}, { /* 3: h-prefixed */
    199 		S('d') = SHORT, S('i') = SHORT,
    200 		S('o') = USHORT, S('u') = USHORT,
    201 		S('x') = USHORT, S('X') = USHORT,
    202 		S('n') = PTR,
    203 		S('h') = HHPRE,
    204 	}, { /* 4: hh-prefixed */
    205 		S('d') = CHAR, S('i') = CHAR,
    206 		S('o') = UCHAR, S('u') = UCHAR,
    207 		S('x') = UCHAR, S('X') = UCHAR,
    208 		S('n') = PTR,
    209 	}, { /* 5: L-prefixed */
    210 		S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL,
    211 		S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL,
    212 		S('n') = PTR,
    213 	}, { /* 6: z- or t-prefixed (assumed to be same size) */
    214 		S('d') = PDIFF, S('i') = PDIFF,
    215 		S('o') = SIZET, S('u') = SIZET,
    216 		S('x') = SIZET, S('X') = SIZET,
    217 		S('n') = PTR,
    218 	}, { /* 7: j-prefixed */
    219 		S('d') = IMAX, S('i') = IMAX,
    220 		S('o') = UMAX, S('u') = UMAX,
    221 		S('x') = UMAX, S('X') = UMAX,
    222 		S('n') = PTR,
    223 	}
    224 };
    225 
    226 #define OOB(x) ((unsigned)(x)-'A' > 'z'-'A')
    227 
    228 union arg
    229 {
    230 	uintmax_t i;
    231 	long double f;
    232 	void *p;
    233 };
    234 
    235 static void pop_arg(union arg *arg, int type, va_list *ap)
    236 {
    237 	/* Give the compiler a hint for optimizing the switch. */
    238 	if ((unsigned)type > MAXSTATE) return;
    239 	switch (type) {
    240 	       case PTR:	arg->p = va_arg(*ap, void *);
    241 	break; case INT:	arg->i = va_arg(*ap, int);
    242 	break; case UINT:	arg->i = va_arg(*ap, unsigned int);
    243 #ifndef LONG_IS_INT
    244 	break; case LONG:	arg->i = va_arg(*ap, long);
    245 	break; case ULONG:	arg->i = va_arg(*ap, unsigned long);
    246 #endif
    247 	break; case ULLONG:	arg->i = va_arg(*ap, unsigned long long);
    248 	break; case SHORT:	arg->i = (short)va_arg(*ap, int);
    249 	break; case USHORT:	arg->i = (unsigned short)va_arg(*ap, int);
    250 	break; case CHAR:	arg->i = (signed char)va_arg(*ap, int);
    251 	break; case UCHAR:	arg->i = (unsigned char)va_arg(*ap, int);
    252 #ifdef ODD_TYPES
    253 	break; case LLONG:	arg->i = va_arg(*ap, long long);
    254 	break; case SIZET:	arg->i = va_arg(*ap, size_t);
    255 	break; case IMAX:	arg->i = va_arg(*ap, intmax_t);
    256 	break; case UMAX:	arg->i = va_arg(*ap, uintmax_t);
    257 	break; case PDIFF:	arg->i = va_arg(*ap, ptrdiff_t);
    258 	break; case UIPTR:	arg->i = (uintptr_t)va_arg(*ap, void *);
    259 #endif
    260 	break; case DBL:	arg->f = va_arg(*ap, double);
    261 	break; case LDBL:	arg->f = va_arg(*ap, long double);
    262 	}
    263 }
    264 
    265 static int getint(wchar_t **s) {
    266 	int i;
    267 	for (i=0; iswdigit(**s); (*s)++)
    268 		i = 10*i + (**s-'0');
    269 	return i;
    270 }
    271 
    272 static const char sizeprefix['y'-'a'] = {
    273 ['a'-'a']='L', ['e'-'a']='L', ['f'-'a']='L', ['g'-'a']='L',
    274 ['d'-'a']='j', ['i'-'a']='j', ['o'-'a']='j', ['u'-'a']='j', ['x'-'a']='j',
    275 ['p'-'a']='j'
    276 };
    277 
    278 static int wprintf_core(Out *out, const wchar_t *fmt, va_list *ap, union arg *nl_arg, int *nl_type)
    279 {
    280 	wchar_t *a, *z, *s=(wchar_t *)fmt, *s0;
    281 	unsigned l10n=0, litpct, fl;
    282 	int w, p;
    283 	union arg arg;
    284 	int argpos;
    285 	unsigned st, ps;
    286 	int cnt=0, l=0;
    287 	int i;
    288 	int t;
    289 	char *bs;
    290 	char charfmt[16];
    291 	wchar_t wc;
    292 
    293 	for (;;) {
    294 		/* Update output count, end loop when fmt is exhausted */
    295 		if (cnt >= 0) {
    296 			if (l > INT_MAX - cnt) {
    297 				if (!out_error(out)) errno = EOVERFLOW;
    298 				cnt = -1;
    299 			} else cnt += l;
    300 		}
    301 		if (!*s) break;
    302 
    303 		/* Handle literal text and %% format specifiers */
    304 		for (a=s; *s && *s!='%'; s++);
    305 		litpct = wcsspn(s, L"%")/2; /* Optimize %%%% runs */
    306 		z = s+litpct;
    307 		s += 2*litpct;
    308 		l = z-a;
    309 		if (out) out_write(out, a, l);
    310 		if (l) continue;
    311 
    312 		if (iswdigit(s[1]) && s[2]=='$') {
    313 			l10n=1;
    314 			argpos = s[1]-'0';
    315 			s+=3;
    316 		} else {
    317 			argpos = -1;
    318 			s++;
    319 		}
    320 
    321 		/* Read modifier flags */
    322 		for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++)
    323 			fl |= 1U<<*s-' ';
    324 
    325 		/* Read field width */
    326 		if (*s=='*') {
    327 			if (iswdigit(s[1]) && s[2]=='$') {
    328 				l10n=1;
    329 				nl_type[s[1]-'0'] = INT;
    330 				w = nl_arg[s[1]-'0'].i;
    331 				s+=3;
    332 			} else if (!l10n) {
    333 				w = out ? va_arg(*ap, int) : 0;
    334 				s++;
    335 			} else return -1;
    336 			if (w<0) fl|=LEFT_ADJ, w=-w;
    337 		} else if ((w=getint(&s))<0) return -1;
    338 
    339 		/* Read precision */
    340 		if (*s=='.' && s[1]=='*') {
    341 			if (isdigit(s[2]) && s[3]=='$') {
    342 				nl_type[s[2]-'0'] = INT;
    343 				p = nl_arg[s[2]-'0'].i;
    344 				s+=4;
    345 			} else if (!l10n) {
    346 				p = out ? va_arg(*ap, int) : 0;
    347 				s+=2;
    348 			} else return -1;
    349 		} else if (*s=='.') {
    350 			s++;
    351 			p = getint(&s);
    352 		} else p = -1;
    353 
    354 		/* Format specifier state machine */
    355 		s0=s;
    356 		st=0;
    357 		do {
    358 			if (OOB(*s)) return -1;
    359 			ps=st;
    360 			st=states[st]S(*s++);
    361 		} while (st-1<STOP);
    362 		if (!st) return -1;
    363 
    364 		/* Check validity of argument type (nl/normal) */
    365 		if (st==NOARG) {
    366 			if (argpos>=0) return -1;
    367 			else if (!out) continue;
    368 		} else {
    369 			if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos];
    370 			else if (out) pop_arg(&arg, st, ap);
    371 			else return 0;
    372 		}
    373 
    374 		if (!out) continue;
    375 		t = s[-1];
    376 		if (ps && (t&15)==3) t&=~32;
    377 
    378 		switch (t) {
    379 		case 'n':
    380 			switch(ps) {
    381 			case BARE: *(int *)arg.p = cnt; break;
    382 			case LPRE: *(long *)arg.p = cnt; break;
    383 			case LLPRE: *(long long *)arg.p = cnt; break;
    384 			case HPRE: *(unsigned short *)arg.p = cnt; break;
    385 			case HHPRE: *(unsigned char *)arg.p = cnt; break;
    386 			case ZTPRE: *(size_t *)arg.p = cnt; break;
    387 			case JPRE: *(uintmax_t *)arg.p = cnt; break;
    388 			}
    389 			continue;
    390 		case 'c':
    391 			out_putwc(out, btowc(arg.i));
    392 			l = 1;
    393 			continue;
    394 		case 'C':
    395 			out_putwc(out, arg.i);
    396 			l = 1;
    397 			continue;
    398 		case 'S':
    399 			a = arg.p;
    400 			z = wmemchr(a, 0, p);
    401 			if (!z) z=a+p;
    402 			else p=z-a;
    403 			if (w<p) w=p;
    404 			if (!(fl&LEFT_ADJ)) out_printf(out, "%.*s", w-p, "");
    405 			out_write(out, a, p);
    406 			if ((fl&LEFT_ADJ)) out_printf(out, "%.*s", w-p, "");
    407 			l=w;
    408 			continue;
    409 		case 's':
    410 			bs = arg.p;
    411 			if (p<0) p = INT_MAX;
    412 			for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++);
    413 			if (i<0) return -1;
    414 			p=l;
    415 			if (w<p) w=p;
    416 			if (!(fl&LEFT_ADJ)) out_printf(out, "%.*s", w-p, "");
    417 			bs = arg.p;
    418 			while (l--) {
    419 				i=mbtowc(&wc, bs, MB_LEN_MAX);
    420 				bs+=i;
    421 				out_putwc(out, wc);
    422 			}
    423 			if ((fl&LEFT_ADJ)) out_printf(out, "%.*s", w-p, "");
    424 			l=w;
    425 			continue;
    426 		}
    427 
    428 		snprintf(charfmt, sizeof charfmt, "%%%s%s%s%s%s*.*%c%c",
    429 			"#"+!(fl & ALT_FORM),
    430 			"+"+!(fl & MARK_POS),
    431 			"-"+!(fl & LEFT_ADJ),
    432 			" "+!(fl & PAD_POS),
    433 			"0"+!(fl & ZERO_PAD),
    434 			sizeprefix[(t|32)-'a'], t);
    435 
    436 		switch (t|32) {
    437 		case 'a': case 'e': case 'f': case 'g':
    438 			l = out_printf(out, charfmt, w, p, arg.f);
    439 			break;
    440 		case 'd': case 'i': case 'o': case 'u': case 'x': case 'p':
    441 			l = out_printf(out, charfmt, w, p, arg.i);
    442 			break;
    443 		}
    444 	}
    445 
    446 	if (out) return cnt;
    447 	if (!l10n) return 0;
    448 
    449 	for (i=1; i<=NL_ARGMAX && nl_type[i]; i++)
    450 		pop_arg(nl_arg+i, nl_type[i], ap);
    451 	for (; i<=NL_ARGMAX && !nl_type[i]; i++);
    452 	if (i<=NL_ARGMAX) return -1;
    453 	return 1;
    454 }
    455 
    456 int vfwprintf(FILE *restrict f, const wchar_t *restrict fmt, va_list ap)
    457 {
    458 	va_list ap2;
    459 	int nl_type[NL_ARGMAX] = {0};
    460 	union arg nl_arg[NL_ARGMAX];
    461 	int ret;
    462         Out out[1];
    463         out_init_file(out, f);
    464 	va_copy(ap2, ap);
    465         // Check for error in format string before writing anything to file.
    466 	if (wprintf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) {
    467           va_end(ap2);
    468           return -1;
    469         }
    470 	ret = wprintf_core(out, fmt, &ap2, nl_arg, nl_type);
    471 	va_end(ap2);
    472 	return ret;
    473 }
    474 
    475 int vswprintf(wchar_t *restrict s, size_t l, const wchar_t *restrict fmt, va_list ap)
    476 {
    477   va_list ap2;
    478   int nl_type[NL_ARGMAX] = {0};
    479   union arg nl_arg[NL_ARGMAX];
    480   int ret;
    481   Out out[1];
    482   out_init_buffer(out, s, l);
    483   va_copy(ap2, ap);
    484   ret = wprintf_core(out, fmt, &ap2, nl_arg, nl_type);
    485   va_end(ap2);
    486   if (out_overflow(out)) return -1;
    487   return ret;
    488 }
    489