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