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