github.com/afumu/libc@v0.0.6/musl/src/stdio/vfprintf.c (about) 1 #include "stdio_impl.h" 2 #include <errno.h> 3 #include <ctype.h> 4 #include <limits.h> 5 #include <string.h> 6 #include <stdarg.h> 7 #include <stddef.h> 8 #include <stdlib.h> 9 #include <wchar.h> 10 #include <inttypes.h> 11 #include <math.h> 12 #include <float.h> 13 14 /* Some useful macros */ 15 16 #define MAX(a,b) ((a)>(b) ? (a) : (b)) 17 #define MIN(a,b) ((a)<(b) ? (a) : (b)) 18 19 /* Convenient bit representation for modifier flags, which all fall 20 * within 31 codepoints of the space character. */ 21 22 #define ALT_FORM (1U<<'#'-' ') 23 #define ZERO_PAD (1U<<'0'-' ') 24 #define LEFT_ADJ (1U<<'-'-' ') 25 #define PAD_POS (1U<<' '-' ') 26 #define MARK_POS (1U<<'+'-' ') 27 #define GROUPED (1U<<'\''-' ') 28 29 #define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS|GROUPED) 30 31 /* State machine to accept length modifiers + conversion specifiers. 32 * Result is 0 on failure, or an argument type to pop on success. */ 33 34 enum { 35 BARE, LPRE, LLPRE, HPRE, HHPRE, BIGLPRE, 36 ZTPRE, JPRE, 37 STOP, 38 PTR, INT, UINT, ULLONG, 39 LONG, ULONG, 40 SHORT, USHORT, CHAR, UCHAR, 41 LLONG, SIZET, IMAX, UMAX, PDIFF, UIPTR, 42 DBL, LDBL, 43 NOARG, 44 MAXSTATE 45 }; 46 47 #define S(x) [(x)-'A'] 48 49 static const unsigned char states[]['z'-'A'+1] = { 50 { /* 0: bare types */ 51 S('d') = INT, S('i') = INT, 52 S('o') = UINT, S('u') = UINT, S('x') = UINT, S('X') = UINT, 53 S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, 54 S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, 55 S('c') = CHAR, S('C') = INT, 56 S('s') = PTR, S('S') = PTR, S('p') = UIPTR, S('n') = PTR, 57 S('m') = NOARG, 58 S('l') = LPRE, S('h') = HPRE, S('L') = BIGLPRE, 59 S('z') = ZTPRE, S('j') = JPRE, S('t') = ZTPRE, 60 }, { /* 1: l-prefixed */ 61 S('d') = LONG, S('i') = LONG, 62 S('o') = ULONG, S('u') = ULONG, S('x') = ULONG, S('X') = ULONG, 63 S('e') = DBL, S('f') = DBL, S('g') = DBL, S('a') = DBL, 64 S('E') = DBL, S('F') = DBL, S('G') = DBL, S('A') = DBL, 65 S('c') = INT, S('s') = PTR, S('n') = PTR, 66 S('l') = LLPRE, 67 }, { /* 2: ll-prefixed */ 68 S('d') = LLONG, S('i') = LLONG, 69 S('o') = ULLONG, S('u') = ULLONG, 70 S('x') = ULLONG, S('X') = ULLONG, 71 S('n') = PTR, 72 }, { /* 3: h-prefixed */ 73 S('d') = SHORT, S('i') = SHORT, 74 S('o') = USHORT, S('u') = USHORT, 75 S('x') = USHORT, S('X') = USHORT, 76 S('n') = PTR, 77 S('h') = HHPRE, 78 }, { /* 4: hh-prefixed */ 79 S('d') = CHAR, S('i') = CHAR, 80 S('o') = UCHAR, S('u') = UCHAR, 81 S('x') = UCHAR, S('X') = UCHAR, 82 S('n') = PTR, 83 }, { /* 5: L-prefixed */ 84 S('e') = LDBL, S('f') = LDBL, S('g') = LDBL, S('a') = LDBL, 85 S('E') = LDBL, S('F') = LDBL, S('G') = LDBL, S('A') = LDBL, 86 S('n') = PTR, 87 }, { /* 6: z- or t-prefixed (assumed to be same size) */ 88 S('d') = PDIFF, S('i') = PDIFF, 89 S('o') = SIZET, S('u') = SIZET, 90 S('x') = SIZET, S('X') = SIZET, 91 S('n') = PTR, 92 }, { /* 7: j-prefixed */ 93 S('d') = IMAX, S('i') = IMAX, 94 S('o') = UMAX, S('u') = UMAX, 95 S('x') = UMAX, S('X') = UMAX, 96 S('n') = PTR, 97 } 98 }; 99 100 #define OOB(x) ((unsigned)(x)-'A' > 'z'-'A') 101 102 union arg 103 { 104 uintmax_t i; 105 long double f; 106 void *p; 107 }; 108 109 static void pop_arg(union arg *arg, int type, va_list *ap) 110 { 111 switch (type) { 112 case PTR: arg->p = va_arg(*ap, void *); 113 break; case INT: arg->i = va_arg(*ap, int); 114 break; case UINT: arg->i = va_arg(*ap, unsigned int); 115 break; case LONG: arg->i = va_arg(*ap, long); 116 break; case ULONG: arg->i = va_arg(*ap, unsigned long); 117 break; case ULLONG: arg->i = va_arg(*ap, unsigned long long); 118 break; case SHORT: arg->i = (short)va_arg(*ap, int); 119 break; case USHORT: arg->i = (unsigned short)va_arg(*ap, int); 120 break; case CHAR: arg->i = (signed char)va_arg(*ap, int); 121 break; case UCHAR: arg->i = (unsigned char)va_arg(*ap, int); 122 break; case LLONG: arg->i = va_arg(*ap, long long); 123 break; case SIZET: arg->i = va_arg(*ap, size_t); 124 break; case IMAX: arg->i = va_arg(*ap, intmax_t); 125 break; case UMAX: arg->i = va_arg(*ap, uintmax_t); 126 break; case PDIFF: arg->i = va_arg(*ap, ptrdiff_t); 127 break; case UIPTR: arg->i = (uintptr_t)va_arg(*ap, void *); 128 break; case DBL: arg->f = va_arg(*ap, double); 129 break; case LDBL: arg->f = va_arg(*ap, long double); 130 } 131 } 132 133 static void out(FILE *f, const char *s, size_t l) 134 { 135 if (!(f->flags & F_ERR)) __fwritex((void *)s, l, f); 136 } 137 138 static void pad(FILE *f, char c, int w, int l, int fl) 139 { 140 char pad[256]; 141 if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; 142 l = w - l; 143 memset(pad, c, l>sizeof pad ? sizeof pad : l); 144 for (; l >= sizeof pad; l -= sizeof pad) 145 out(f, pad, sizeof pad); 146 out(f, pad, l); 147 } 148 149 static const char xdigits[16] = { 150 "0123456789ABCDEF" 151 }; 152 153 static char *fmt_x(uintmax_t x, char *s, int lower) 154 { 155 for (; x; x>>=4) *--s = xdigits[(x&15)]|lower; 156 return s; 157 } 158 159 static char *fmt_o(uintmax_t x, char *s) 160 { 161 for (; x; x>>=3) *--s = '0' + (x&7); 162 return s; 163 } 164 165 static char *fmt_u(uintmax_t x, char *s) 166 { 167 unsigned long y; 168 for ( ; x>ULONG_MAX; x/=10) *--s = '0' + x%10; 169 for (y=x; y; y/=10) *--s = '0' + y%10; 170 return s; 171 } 172 173 /* Do not override this check. The floating point printing code below 174 * depends on the float.h constants being right. If they are wrong, it 175 * may overflow the stack. */ 176 #if LDBL_MANT_DIG == 53 177 typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double)]; 178 #endif 179 180 static int fmt_fp(FILE *f, long double y, int w, int p, int fl, int t) 181 { 182 uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion 183 + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion 184 uint32_t *a, *d, *r, *z; 185 int e2=0, e, i, j, l; 186 char buf[9+LDBL_MANT_DIG/4], *s; 187 const char *prefix="-0X+0X 0X-0x+0x 0x"; 188 int pl; 189 char ebuf0[3*sizeof(int)], *ebuf=&ebuf0[3*sizeof(int)], *estr; 190 191 pl=1; 192 if (signbit(y)) { 193 y=-y; 194 } else if (fl & MARK_POS) { 195 prefix+=3; 196 } else if (fl & PAD_POS) { 197 prefix+=6; 198 } else prefix++, pl=0; 199 200 if (!isfinite(y)) { 201 char *s = (t&32)?"inf":"INF"; 202 if (y!=y) s=(t&32)?"nan":"NAN"; 203 pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); 204 out(f, prefix, pl); 205 out(f, s, 3); 206 pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); 207 return MAX(w, 3+pl); 208 } 209 210 y = frexpl(y, &e2) * 2; 211 if (y) e2--; 212 213 if ((t|32)=='a') { 214 long double round = 8.0; 215 int re; 216 217 if (t&32) prefix += 9; 218 pl += 2; 219 220 if (p<0 || p>=LDBL_MANT_DIG/4-1) re=0; 221 else re=LDBL_MANT_DIG/4-1-p; 222 223 if (re) { 224 round *= 1<<(LDBL_MANT_DIG%4); 225 while (re--) round*=16; 226 if (*prefix=='-') { 227 y=-y; 228 y-=round; 229 y+=round; 230 y=-y; 231 } else { 232 y+=round; 233 y-=round; 234 } 235 } 236 237 estr=fmt_u(e2<0 ? -e2 : e2, ebuf); 238 if (estr==ebuf) *--estr='0'; 239 *--estr = (e2<0 ? '-' : '+'); 240 *--estr = t+('p'-'a'); 241 242 s=buf; 243 do { 244 int x=y; 245 *s++=xdigits[x]|(t&32); 246 y=16*(y-x); 247 if (s-buf==1 && (y||p>0||(fl&ALT_FORM))) *s++='.'; 248 } while (y); 249 250 if (p > INT_MAX-2-(ebuf-estr)-pl) 251 return -1; 252 if (p && s-buf-2 < p) 253 l = (p+2) + (ebuf-estr); 254 else 255 l = (s-buf) + (ebuf-estr); 256 257 pad(f, ' ', w, pl+l, fl); 258 out(f, prefix, pl); 259 pad(f, '0', w, pl+l, fl^ZERO_PAD); 260 out(f, buf, s-buf); 261 pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); 262 out(f, estr, ebuf-estr); 263 pad(f, ' ', w, pl+l, fl^LEFT_ADJ); 264 return MAX(w, pl+l); 265 } 266 if (p<0) p=6; 267 268 if (y) y *= 0x1p28, e2-=28; 269 270 if (e2<0) a=r=z=big; 271 else a=r=z=big+sizeof(big)/sizeof(*big) - LDBL_MANT_DIG - 1; 272 273 do { 274 *z = y; 275 y = 1000000000*(y-*z++); 276 } while (y); 277 278 while (e2>0) { 279 uint32_t carry=0; 280 int sh=MIN(29,e2); 281 for (d=z-1; d>=a; d--) { 282 uint64_t x = ((uint64_t)*d<<sh)+carry; 283 *d = x % 1000000000; 284 carry = x / 1000000000; 285 } 286 if (carry) *--a = carry; 287 while (z>a && !z[-1]) z--; 288 e2-=sh; 289 } 290 while (e2<0) { 291 uint32_t carry=0, *b; 292 int sh=MIN(9,-e2), need=1+(p+LDBL_MANT_DIG/3U+8)/9; 293 for (d=a; d<z; d++) { 294 uint32_t rm = *d & (1<<sh)-1; 295 *d = (*d>>sh) + carry; 296 carry = (1000000000>>sh) * rm; 297 } 298 if (!*a) a++; 299 if (carry) *z++ = carry; 300 /* Avoid (slow!) computation past requested precision */ 301 b = (t|32)=='f' ? r : a; 302 if (z-b > need) z = b+need; 303 e2+=sh; 304 } 305 306 if (a<z) for (i=10, e=9*(r-a); *a>=i; i*=10, e++); 307 else e=0; 308 309 /* Perform rounding: j is precision after the radix (possibly neg) */ 310 j = p - ((t|32)!='f')*e - ((t|32)=='g' && p); 311 if (j < 9*(z-r-1)) { 312 uint32_t x; 313 /* We avoid C's broken division of negative numbers */ 314 d = r + 1 + ((j+9*LDBL_MAX_EXP)/9 - LDBL_MAX_EXP); 315 j += 9*LDBL_MAX_EXP; 316 j %= 9; 317 for (i=10, j++; j<9; i*=10, j++); 318 x = *d % i; 319 /* Are there any significant digits past j? */ 320 if (x || d+1!=z) { 321 long double round = 2/LDBL_EPSILON; 322 long double small; 323 if ((*d/i & 1) || (i==1000000000 && d>a && (d[-1]&1))) 324 round += 2; 325 if (x<i/2) small=0x0.8p0; 326 else if (x==i/2 && d+1==z) small=0x1.0p0; 327 else small=0x1.8p0; 328 if (pl && *prefix=='-') round*=-1, small*=-1; 329 *d -= x; 330 /* Decide whether to round by probing round+small */ 331 if (round+small != round) { 332 *d = *d + i; 333 while (*d > 999999999) { 334 *d--=0; 335 if (d<a) *--a=0; 336 (*d)++; 337 } 338 for (i=10, e=9*(r-a); *a>=i; i*=10, e++); 339 } 340 } 341 if (z>d+1) z=d+1; 342 } 343 for (; z>a && !z[-1]; z--); 344 345 if ((t|32)=='g') { 346 if (!p) p++; 347 if (p>e && e>=-4) { 348 t--; 349 p-=e+1; 350 } else { 351 t-=2; 352 p--; 353 } 354 if (!(fl&ALT_FORM)) { 355 /* Count trailing zeros in last place */ 356 if (z>a && z[-1]) for (i=10, j=0; z[-1]%i==0; i*=10, j++); 357 else j=9; 358 if ((t|32)=='f') 359 p = MIN(p,MAX(0,9*(z-r-1)-j)); 360 else 361 p = MIN(p,MAX(0,9*(z-r-1)+e-j)); 362 } 363 } 364 if (p > INT_MAX-1-(p || (fl&ALT_FORM))) 365 return -1; 366 l = 1 + p + (p || (fl&ALT_FORM)); 367 if ((t|32)=='f') { 368 if (e > INT_MAX-l) return -1; 369 if (e>0) l+=e; 370 } else { 371 estr=fmt_u(e<0 ? -e : e, ebuf); 372 while(ebuf-estr<2) *--estr='0'; 373 *--estr = (e<0 ? '-' : '+'); 374 *--estr = t; 375 if (ebuf-estr > INT_MAX-l) return -1; 376 l += ebuf-estr; 377 } 378 379 if (l > INT_MAX-pl) return -1; 380 pad(f, ' ', w, pl+l, fl); 381 out(f, prefix, pl); 382 pad(f, '0', w, pl+l, fl^ZERO_PAD); 383 384 if ((t|32)=='f') { 385 if (a>r) a=r; 386 for (d=a; d<=r; d++) { 387 char *s = fmt_u(*d, buf+9); 388 if (d!=a) while (s>buf) *--s='0'; 389 else if (s==buf+9) *--s='0'; 390 out(f, s, buf+9-s); 391 } 392 if (p || (fl&ALT_FORM)) out(f, ".", 1); 393 for (; d<z && p>0; d++, p-=9) { 394 char *s = fmt_u(*d, buf+9); 395 while (s>buf) *--s='0'; 396 out(f, s, MIN(9,p)); 397 } 398 pad(f, '0', p+9, 9, 0); 399 } else { 400 if (z<=a) z=a+1; 401 for (d=a; d<z && p>=0; d++) { 402 char *s = fmt_u(*d, buf+9); 403 if (s==buf+9) *--s='0'; 404 if (d!=a) while (s>buf) *--s='0'; 405 else { 406 out(f, s++, 1); 407 if (p>0||(fl&ALT_FORM)) out(f, ".", 1); 408 } 409 out(f, s, MIN(buf+9-s, p)); 410 p -= buf+9-s; 411 } 412 pad(f, '0', p+18, 18, 0); 413 out(f, estr, ebuf-estr); 414 } 415 416 pad(f, ' ', w, pl+l, fl^LEFT_ADJ); 417 418 return MAX(w, pl+l); 419 } 420 421 static int getint(char **s) { 422 int i; 423 for (i=0; isdigit(**s); (*s)++) { 424 if (i > INT_MAX/10U || **s-'0' > INT_MAX-10*i) i = -1; 425 else i = 10*i + (**s-'0'); 426 } 427 return i; 428 } 429 430 static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, int *nl_type) 431 { 432 char *a, *z, *s=(char *)fmt; 433 unsigned l10n=0, fl; 434 int w, p, xp; 435 union arg arg; 436 int argpos; 437 unsigned st, ps; 438 int cnt=0, l=0; 439 size_t i; 440 char buf[sizeof(uintmax_t)*3+3+LDBL_MANT_DIG/4]; 441 const char *prefix; 442 int t, pl; 443 wchar_t wc[2], *ws; 444 char mb[4]; 445 446 for (;;) { 447 /* This error is only specified for snprintf, but since it's 448 * unspecified for other forms, do the same. Stop immediately 449 * on overflow; otherwise %n could produce wrong results. */ 450 if (l > INT_MAX - cnt) goto overflow; 451 452 /* Update output count, end loop when fmt is exhausted */ 453 cnt += l; 454 if (!*s) break; 455 456 /* Handle literal text and %% format specifiers */ 457 for (a=s; *s && *s!='%'; s++); 458 for (z=s; s[0]=='%' && s[1]=='%'; z++, s+=2); 459 if (z-a > INT_MAX-cnt) goto overflow; 460 l = z-a; 461 if (f) out(f, a, l); 462 if (l) continue; 463 464 if (isdigit(s[1]) && s[2]=='$') { 465 l10n=1; 466 argpos = s[1]-'0'; 467 s+=3; 468 } else { 469 argpos = -1; 470 s++; 471 } 472 473 /* Read modifier flags */ 474 for (fl=0; (unsigned)*s-' '<32 && (FLAGMASK&(1U<<*s-' ')); s++) 475 fl |= 1U<<*s-' '; 476 477 /* Read field width */ 478 if (*s=='*') { 479 if (isdigit(s[1]) && s[2]=='$') { 480 l10n=1; 481 nl_type[s[1]-'0'] = INT; 482 w = nl_arg[s[1]-'0'].i; 483 s+=3; 484 } else if (!l10n) { 485 w = f ? va_arg(*ap, int) : 0; 486 s++; 487 } else goto inval; 488 if (w<0) fl|=LEFT_ADJ, w=-w; 489 } else if ((w=getint(&s))<0) goto overflow; 490 491 /* Read precision */ 492 if (*s=='.' && s[1]=='*') { 493 if (isdigit(s[2]) && s[3]=='$') { 494 nl_type[s[2]-'0'] = INT; 495 p = nl_arg[s[2]-'0'].i; 496 s+=4; 497 } else if (!l10n) { 498 p = f ? va_arg(*ap, int) : 0; 499 s+=2; 500 } else goto inval; 501 xp = (p>=0); 502 } else if (*s=='.') { 503 s++; 504 p = getint(&s); 505 xp = 1; 506 } else { 507 p = -1; 508 xp = 0; 509 } 510 511 /* Format specifier state machine */ 512 st=0; 513 do { 514 if (OOB(*s)) goto inval; 515 ps=st; 516 st=states[st]S(*s++); 517 } while (st-1<STOP); 518 if (!st) goto inval; 519 520 /* Check validity of argument type (nl/normal) */ 521 if (st==NOARG) { 522 if (argpos>=0) goto inval; 523 } else { 524 if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; 525 else if (f) pop_arg(&arg, st, ap); 526 else return 0; 527 } 528 529 if (!f) continue; 530 531 z = buf + sizeof(buf); 532 prefix = "-+ 0X0x"; 533 pl = 0; 534 t = s[-1]; 535 536 /* Transform ls,lc -> S,C */ 537 if (ps && (t&15)==3) t&=~32; 538 539 /* - and 0 flags are mutually exclusive */ 540 if (fl & LEFT_ADJ) fl &= ~ZERO_PAD; 541 542 switch(t) { 543 case 'n': 544 switch(ps) { 545 case BARE: *(int *)arg.p = cnt; break; 546 case LPRE: *(long *)arg.p = cnt; break; 547 case LLPRE: *(long long *)arg.p = cnt; break; 548 case HPRE: *(unsigned short *)arg.p = cnt; break; 549 case HHPRE: *(unsigned char *)arg.p = cnt; break; 550 case ZTPRE: *(size_t *)arg.p = cnt; break; 551 case JPRE: *(uintmax_t *)arg.p = cnt; break; 552 } 553 continue; 554 case 'p': 555 p = MAX(p, 2*sizeof(void*)); 556 t = 'x'; 557 fl |= ALT_FORM; 558 case 'x': case 'X': 559 a = fmt_x(arg.i, z, t&32); 560 if (arg.i && (fl & ALT_FORM)) prefix+=(t>>4), pl=2; 561 if (0) { 562 case 'o': 563 a = fmt_o(arg.i, z); 564 if ((fl&ALT_FORM) && p<z-a+1) p=z-a+1; 565 } if (0) { 566 case 'd': case 'i': 567 pl=1; 568 if (arg.i>INTMAX_MAX) { 569 arg.i=-arg.i; 570 } else if (fl & MARK_POS) { 571 prefix++; 572 } else if (fl & PAD_POS) { 573 prefix+=2; 574 } else pl=0; 575 case 'u': 576 a = fmt_u(arg.i, z); 577 } 578 if (xp && p<0) goto overflow; 579 if (xp) fl &= ~ZERO_PAD; 580 if (!arg.i && !p) { 581 a=z; 582 break; 583 } 584 p = MAX(p, z-a + !arg.i); 585 break; 586 case 'c': 587 *(a=z-(p=1))=arg.i; 588 fl &= ~ZERO_PAD; 589 break; 590 case 'm': 591 if (1) a = strerror(errno); else 592 case 's': 593 a = arg.p ? arg.p : "(null)"; 594 z = a + strnlen(a, p<0 ? INT_MAX : p); 595 if (p<0 && *z) goto overflow; 596 p = z-a; 597 fl &= ~ZERO_PAD; 598 break; 599 case 'C': 600 wc[0] = arg.i; 601 wc[1] = 0; 602 arg.p = wc; 603 p = -1; 604 case 'S': 605 ws = arg.p; 606 for (i=l=0; i<p && *ws && (l=wctomb(mb, *ws++))>=0 && l<=p-i; i+=l); 607 if (l<0) return -1; 608 if (i > INT_MAX) goto overflow; 609 p = i; 610 pad(f, ' ', w, p, fl); 611 ws = arg.p; 612 for (i=0; i<0U+p && *ws && i+(l=wctomb(mb, *ws++))<=p; i+=l) 613 out(f, mb, l); 614 pad(f, ' ', w, p, fl^LEFT_ADJ); 615 l = w>p ? w : p; 616 continue; 617 case 'e': case 'f': case 'g': case 'a': 618 case 'E': case 'F': case 'G': case 'A': 619 if (xp && p<0) goto overflow; 620 l = fmt_fp(f, arg.f, w, p, fl, t); 621 if (l<0) goto overflow; 622 continue; 623 } 624 625 if (p < z-a) p = z-a; 626 if (p > INT_MAX-pl) goto overflow; 627 if (w < pl+p) w = pl+p; 628 if (w > INT_MAX-cnt) goto overflow; 629 630 pad(f, ' ', w, pl+p, fl); 631 out(f, prefix, pl); 632 pad(f, '0', w, pl+p, fl^ZERO_PAD); 633 pad(f, '0', p, z-a, 0); 634 out(f, a, z-a); 635 pad(f, ' ', w, pl+p, fl^LEFT_ADJ); 636 637 l = w; 638 } 639 640 if (f) return cnt; 641 if (!l10n) return 0; 642 643 for (i=1; i<=NL_ARGMAX && nl_type[i]; i++) 644 pop_arg(nl_arg+i, nl_type[i], ap); 645 for (; i<=NL_ARGMAX && !nl_type[i]; i++); 646 if (i<=NL_ARGMAX) goto inval; 647 return 1; 648 649 inval: 650 errno = EINVAL; 651 return -1; 652 overflow: 653 errno = EOVERFLOW; 654 return -1; 655 } 656 657 int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap) 658 { 659 va_list ap2; 660 int nl_type[NL_ARGMAX+1] = {0}; 661 union arg nl_arg[NL_ARGMAX+1]; 662 unsigned char internal_buf[80], *saved_buf = 0; 663 int olderr; 664 int ret; 665 666 /* the copy allows passing va_list* even if va_list is an array */ 667 va_copy(ap2, ap); 668 if (printf_core(0, fmt, &ap2, nl_arg, nl_type) < 0) { 669 va_end(ap2); 670 return -1; 671 } 672 673 FLOCK(f); 674 olderr = f->flags & F_ERR; 675 if (f->mode < 1) f->flags &= ~F_ERR; 676 if (!f->buf_size) { 677 saved_buf = f->buf; 678 f->buf = internal_buf; 679 f->buf_size = sizeof internal_buf; 680 f->wpos = f->wbase = f->wend = 0; 681 } 682 if (!f->wend && __towrite(f)) ret = -1; 683 else ret = printf_core(f, fmt, &ap2, nl_arg, nl_type); 684 if (saved_buf) { 685 f->write(f, 0, 0); 686 if (!f->wpos) ret = -1; 687 f->buf = saved_buf; 688 f->buf_size = 0; 689 f->wpos = f->wbase = f->wend = 0; 690 } 691 if (f->flags & F_ERR) ret = -1; 692 f->flags |= olderr; 693 FUNLOCK(f); 694 va_end(ap2); 695 return ret; 696 }