1 /* $OpenBSD: vfwprintf.c,v 1.5 2012/06/26 14:53:23 matthew Exp $ */ 2 /*- 3 * Copyright (c) 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Chris Torek. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* 35 * Actual wprintf innards. 36 * 37 * This code is large and complicated... 38 */ 39 40 #include <sys/types.h> 41 #include <sys/mman.h> 42 43 #include <errno.h> 44 #include <langinfo.h> 45 #include <limits.h> 46 #include <stdarg.h> 47 #include <stddef.h> 48 #include <stdio.h> 49 #include <stdint.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 54 #include "local.h" 55 #include "fvwrite.h" 56 57 union arg { 58 int intarg; 59 unsigned int uintarg; 60 long longarg; 61 unsigned long ulongarg; 62 long long longlongarg; 63 unsigned long long ulonglongarg; 64 ptrdiff_t ptrdiffarg; 65 size_t sizearg; 66 ssize_t ssizearg; 67 intmax_t intmaxarg; 68 uintmax_t uintmaxarg; 69 void *pvoidarg; 70 char *pchararg; 71 signed char *pschararg; 72 short *pshortarg; 73 int *pintarg; 74 long *plongarg; 75 long long *plonglongarg; 76 ptrdiff_t *pptrdiffarg; 77 ssize_t *pssizearg; 78 intmax_t *pintmaxarg; 79 #ifdef FLOATING_POINT 80 double doublearg; 81 long double longdoublearg; 82 #endif 83 wint_t wintarg; 84 wchar_t *pwchararg; 85 }; 86 87 static int __find_arguments(const wchar_t *fmt0, va_list ap, union arg **argtable, 88 size_t *argtablesiz); 89 static int __grow_type_table(unsigned char **typetable, int *tablesize); 90 91 /* 92 * Helper function for `fprintf to unbuffered unix file': creates a 93 * temporary buffer. We only work on write-only files; this avoids 94 * worries about ungetc buffers and so forth. 95 */ 96 static int 97 __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) 98 { 99 int ret; 100 FILE fake; 101 struct __sfileext fakeext; 102 unsigned char buf[BUFSIZ]; 103 104 _FILEEXT_SETUP(&fake, &fakeext); 105 /* copy the important variables */ 106 fake._flags = fp->_flags & ~__SNBF; 107 fake._file = fp->_file; 108 fake._cookie = fp->_cookie; 109 fake._write = fp->_write; 110 111 /* set up the buffer */ 112 fake._bf._base = fake._p = buf; 113 fake._bf._size = fake._w = sizeof(buf); 114 fake._lbfsize = 0; /* not actually used, but Just In Case */ 115 116 /* do the work, then copy any error status */ 117 ret = __vfwprintf(&fake, fmt, ap); 118 if (ret >= 0 && __sflush(&fake)) 119 ret = EOF; 120 if (fake._flags & __SERR) 121 fp->_flags |= __SERR; 122 return (ret); 123 } 124 125 /* 126 * Like __fputwc_unlock, but handles fake string (__SSTR) files properly. 127 * File must already be locked. 128 */ 129 static wint_t 130 __xfputwc(wchar_t wc, FILE *fp) 131 { 132 mbstate_t mbs; 133 char buf[MB_LEN_MAX]; 134 struct __suio uio; 135 struct __siov iov; 136 size_t len; 137 138 if ((fp->_flags & __SSTR) == 0) 139 return (__fputwc_unlock(wc, fp)); 140 141 bzero(&mbs, sizeof(mbs)); 142 len = wcrtomb(buf, wc, &mbs); 143 if (len == (size_t)-1) { 144 fp->_flags |= __SERR; 145 errno = EILSEQ; 146 return (WEOF); 147 } 148 uio.uio_iov = &iov; 149 uio.uio_resid = len; 150 uio.uio_iovcnt = 1; 151 iov.iov_base = buf; 152 iov.iov_len = len; 153 return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); 154 } 155 156 /* 157 * Convert a multibyte character string argument for the %s format to a wide 158 * string representation. ``prec'' specifies the maximum number of bytes 159 * to output. If ``prec'' is greater than or equal to zero, we can't assume 160 * that the multibyte character string ends in a null character. 161 * 162 * Returns NULL on failure. 163 * To find out what happened check errno for ENOMEM, EILSEQ and EINVAL. 164 */ 165 static wchar_t * 166 __mbsconv(char *mbsarg, int prec) 167 { 168 mbstate_t mbs; 169 wchar_t *convbuf, *wcp; 170 const char *p; 171 size_t insize, nchars, nconv; 172 173 if (mbsarg == NULL) 174 return (NULL); 175 176 /* 177 * Supplied argument is a multibyte string; convert it to wide 178 * characters first. 179 */ 180 if (prec >= 0) { 181 /* 182 * String is not guaranteed to be NUL-terminated. Find the 183 * number of characters to print. 184 */ 185 p = mbsarg; 186 insize = nchars = nconv = 0; 187 bzero(&mbs, sizeof(mbs)); 188 while (nchars != (size_t)prec) { 189 nconv = mbrlen(p, MB_CUR_MAX, &mbs); 190 if (nconv == (size_t)0 || nconv == (size_t)-1 || 191 nconv == (size_t)-2) 192 break; 193 p += nconv; 194 nchars++; 195 insize += nconv; 196 } 197 if (nconv == (size_t)-1 || nconv == (size_t)-2) 198 return (NULL); 199 } else 200 insize = strlen(mbsarg); 201 202 /* 203 * Allocate buffer for the result and perform the conversion, 204 * converting at most `size' bytes of the input multibyte string to 205 * wide characters for printing. 206 */ 207 convbuf = calloc(insize + 1, sizeof(*convbuf)); 208 if (convbuf == NULL) 209 return (NULL); 210 wcp = convbuf; 211 p = mbsarg; 212 bzero(&mbs, sizeof(mbs)); 213 nconv = 0; 214 while (insize != 0) { 215 nconv = mbrtowc(wcp, p, insize, &mbs); 216 if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) 217 break; 218 wcp++; 219 p += nconv; 220 insize -= nconv; 221 } 222 if (nconv == (size_t)-1 || nconv == (size_t)-2) { 223 free(convbuf); 224 return (NULL); 225 } 226 *wcp = '\0'; 227 228 return (convbuf); 229 } 230 231 #ifdef FLOATING_POINT 232 #include <float.h> 233 #include <locale.h> 234 #include <math.h> 235 #include "floatio.h" 236 237 #define DEFPREC 6 238 239 extern char *__dtoa(double, int, int, int *, int *, char **); 240 extern void __freedtoa(char *); 241 static int exponent(wchar_t *, int, int); 242 #endif /* FLOATING_POINT */ 243 244 /* 245 * The size of the buffer we use as scratch space for integer 246 * conversions, among other things. Technically, we would need the 247 * most space for base 10 conversions with thousands' grouping 248 * characters between each pair of digits. 100 bytes is a 249 * conservative overestimate even for a 128-bit uintmax_t. 250 */ 251 #define BUF 100 252 253 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 254 255 256 /* 257 * Macros for converting digits to letters and vice versa 258 */ 259 #define to_digit(c) ((c) - '0') 260 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 261 #define to_char(n) ((wchar_t)((n) + '0')) 262 263 /* 264 * Flags used during conversion. 265 */ 266 #define ALT 0x0001 /* alternate form */ 267 #define LADJUST 0x0004 /* left adjustment */ 268 #define LONGDBL 0x0008 /* long double */ 269 #define LONGINT 0x0010 /* long integer */ 270 #define LLONGINT 0x0020 /* long long integer */ 271 #define SHORTINT 0x0040 /* short integer */ 272 #define ZEROPAD 0x0080 /* zero (as opposed to blank) pad */ 273 #define FPT 0x0100 /* Floating point number */ 274 #define PTRINT 0x0200 /* (unsigned) ptrdiff_t */ 275 #define SIZEINT 0x0400 /* (signed) size_t */ 276 #define CHARINT 0x0800 /* 8 bit integer */ 277 #define MAXINT 0x1000 /* largest integer size (intmax_t) */ 278 279 int 280 __vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, __va_list ap) 281 { 282 wchar_t *fmt; /* format string */ 283 wchar_t ch; /* character from fmt */ 284 int n, n2, n3; /* handy integers (short term usage) */ 285 wchar_t *cp; /* handy char pointer (short term usage) */ 286 int flags; /* flags as above */ 287 int ret; /* return value accumulator */ 288 int width; /* width from format (%8d), or 0 */ 289 int prec; /* precision from format; <0 for N/A */ 290 wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ 291 #ifdef FLOATING_POINT 292 /* 293 * We can decompose the printed representation of floating 294 * point numbers into several parts, some of which may be empty: 295 * 296 * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ 297 * A B ---C--- D E F 298 * 299 * A: 'sign' holds this value if present; '\0' otherwise 300 * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal 301 * C: cp points to the string MMMNNN. Leading and trailing 302 * zeros are not in the string and must be added. 303 * D: expchar holds this character; '\0' if no exponent, e.g. %f 304 * F: at least two digits for decimal, at least one digit for hex 305 */ 306 char *decimal_point = NULL; 307 int signflag; /* true if float is negative */ 308 union { /* floating point arguments %[aAeEfFgG] */ 309 double dbl; 310 long double ldbl; 311 } fparg; 312 int expt; /* integer value of exponent */ 313 char expchar; /* exponent character: [eEpP\0] */ 314 char *dtoaend; /* pointer to end of converted digits */ 315 int expsize; /* character count for expstr */ 316 int lead; /* sig figs before decimal or group sep */ 317 int ndig; /* actual number of digits returned by dtoa */ 318 wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ 319 char *dtoaresult = NULL; 320 #endif 321 322 uintmax_t _umax; /* integer arguments %[diouxX] */ 323 enum { OCT, DEC, HEX } base; /* base for %[diouxX] conversion */ 324 int dprec; /* a copy of prec if %[diouxX], 0 otherwise */ 325 int realsz; /* field size expanded by dprec */ 326 int size; /* size of converted field or string */ 327 const char *xdigs; /* digits for %[xX] conversion */ 328 #define NIOV 8 329 struct __suio uio; /* output information: summary */ 330 struct __siov iov[NIOV];/* ... and individual io vectors */ 331 wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ 332 wchar_t ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ 333 union arg *argtable; /* args, built due to positional arg */ 334 union arg statargtable[STATIC_ARG_TBL_SIZE]; 335 size_t argtablesiz; 336 int nextarg; /* 1-based argument index */ 337 va_list orgap; /* original argument pointer */ 338 wchar_t *convbuf; /* buffer for multibyte to wide conversion */ 339 340 /* 341 * Choose PADSIZE to trade efficiency vs. size. If larger printf 342 * fields occur frequently, increase PADSIZE and make the initialisers 343 * below longer. 344 */ 345 #define PADSIZE 16 /* pad chunk size */ 346 static wchar_t blanks[PADSIZE] = 347 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 348 static wchar_t zeroes[PADSIZE] = 349 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 350 351 static const char xdigs_lower[16] = "0123456789abcdef"; 352 static const char xdigs_upper[16] = "0123456789ABCDEF"; 353 354 /* 355 * BEWARE, these `goto error' on error, PRINT uses 'n3', 356 * PAD uses `n' and 'n3', and PRINTANDPAD uses 'n', 'n2', and 'n3'. 357 */ 358 #define PRINT(ptr, len) do { \ 359 for (n3 = 0; n3 < (len); n3++) { \ 360 if ((__xfputwc((ptr)[n3], fp)) == WEOF) \ 361 goto error; \ 362 } \ 363 } while (0) 364 #define PAD(howmany, with) do { \ 365 if ((n = (howmany)) > 0) { \ 366 while (n > PADSIZE) { \ 367 PRINT(with, PADSIZE); \ 368 n -= PADSIZE; \ 369 } \ 370 PRINT(with, n); \ 371 } \ 372 } while (0) 373 #define PRINTANDPAD(p, ep, len, with) do { \ 374 n2 = (ep) - (p); \ 375 if (n2 > (len)) \ 376 n2 = (len); \ 377 if (n2 > 0) \ 378 PRINT((p), n2); \ 379 PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 380 } while(0) 381 382 /* 383 * To extend shorts properly, we need both signed and unsigned 384 * argument extraction methods. 385 */ 386 #define SARG() \ 387 ((intmax_t)(flags&MAXINT ? GETARG(intmax_t) : \ 388 flags&LLONGINT ? GETARG(long long) : \ 389 flags&LONGINT ? GETARG(long) : \ 390 flags&PTRINT ? GETARG(ptrdiff_t) : \ 391 flags&SIZEINT ? GETARG(ssize_t) : \ 392 flags&SHORTINT ? (short)GETARG(int) : \ 393 flags&CHARINT ? (__signed char)GETARG(int) : \ 394 GETARG(int))) 395 #define UARG() \ 396 ((uintmax_t)(flags&MAXINT ? GETARG(uintmax_t) : \ 397 flags&LLONGINT ? GETARG(unsigned long long) : \ 398 flags&LONGINT ? GETARG(unsigned long) : \ 399 flags&PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */ \ 400 flags&SIZEINT ? GETARG(size_t) : \ 401 flags&SHORTINT ? (unsigned short)GETARG(int) : \ 402 flags&CHARINT ? (unsigned char)GETARG(int) : \ 403 GETARG(unsigned int))) 404 405 /* 406 * Append a digit to a value and check for overflow. 407 */ 408 #define APPEND_DIGIT(val, dig) do { \ 409 if ((val) > INT_MAX / 10) \ 410 goto overflow; \ 411 (val) *= 10; \ 412 if ((val) > INT_MAX - to_digit((dig))) \ 413 goto overflow; \ 414 (val) += to_digit((dig)); \ 415 } while (0) 416 417 /* 418 * Get * arguments, including the form *nn$. Preserve the nextarg 419 * that the argument can be gotten once the type is determined. 420 */ 421 #define GETASTER(val) \ 422 n2 = 0; \ 423 cp = fmt; \ 424 while (is_digit(*cp)) { \ 425 APPEND_DIGIT(n2, *cp); \ 426 cp++; \ 427 } \ 428 if (*cp == '$') { \ 429 int hold = nextarg; \ 430 if (argtable == NULL) { \ 431 argtable = statargtable; \ 432 __find_arguments(fmt0, orgap, &argtable, &argtablesiz); \ 433 } \ 434 nextarg = n2; \ 435 val = GETARG(int); \ 436 nextarg = hold; \ 437 fmt = ++cp; \ 438 } else { \ 439 val = GETARG(int); \ 440 } 441 442 /* 443 * Get the argument indexed by nextarg. If the argument table is 444 * built, use it to get the argument. If its not, get the next 445 * argument (and arguments must be gotten sequentially). 446 */ 447 #define GETARG(type) \ 448 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 449 (nextarg++, va_arg(ap, type))) 450 451 _SET_ORIENTATION(fp, 1); 452 /* sorry, fwprintf(read_only_file, "") returns EOF, not 0 */ 453 if (cantwrite(fp)) { 454 errno = EBADF; 455 return (EOF); 456 } 457 458 /* optimise fwprintf(stderr) (and other unbuffered Unix files) */ 459 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 460 fp->_file >= 0) 461 return (__sbprintf(fp, fmt0, ap)); 462 463 fmt = (wchar_t *)fmt0; 464 argtable = NULL; 465 nextarg = 1; 466 va_copy(orgap, ap); 467 uio.uio_iov = iov; 468 uio.uio_resid = 0; 469 uio.uio_iovcnt = 0; 470 ret = 0; 471 convbuf = NULL; 472 473 /* 474 * Scan the format for conversions (`%' character). 475 */ 476 for (;;) { 477 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 478 continue; 479 if (fmt != cp) { 480 ptrdiff_t m = fmt - cp; 481 if (m < 0 || m > INT_MAX - ret) 482 goto overflow; 483 PRINT(cp, m); 484 ret += m; 485 } 486 if (ch == '\0') 487 goto done; 488 fmt++; /* skip over '%' */ 489 490 flags = 0; 491 dprec = 0; 492 width = 0; 493 prec = -1; 494 sign = '\0'; 495 ox[1] = '\0'; 496 497 rflag: ch = *fmt++; 498 reswitch: switch (ch) { 499 case ' ': 500 /* 501 * ``If the space and + flags both appear, the space 502 * flag will be ignored.'' 503 * -- ANSI X3J11 504 */ 505 if (!sign) 506 sign = ' '; 507 goto rflag; 508 case '#': 509 flags |= ALT; 510 goto rflag; 511 case '\'': 512 /* grouping not implemented */ 513 goto rflag; 514 case '*': 515 /* 516 * ``A negative field width argument is taken as a 517 * - flag followed by a positive field width.'' 518 * -- ANSI X3J11 519 * They don't exclude field widths read from args. 520 */ 521 GETASTER(width); 522 if (width >= 0) 523 goto rflag; 524 if (width == INT_MIN) 525 goto overflow; 526 width = -width; 527 /* FALLTHROUGH */ 528 case '-': 529 flags |= LADJUST; 530 goto rflag; 531 case '+': 532 sign = '+'; 533 goto rflag; 534 case '.': 535 if ((ch = *fmt++) == '*') { 536 GETASTER(n); 537 prec = n < 0 ? -1 : n; 538 goto rflag; 539 } 540 n = 0; 541 while (is_digit(ch)) { 542 APPEND_DIGIT(n, ch); 543 ch = *fmt++; 544 } 545 if (ch == '$') { 546 nextarg = n; 547 if (argtable == NULL) { 548 argtable = statargtable; 549 __find_arguments(fmt0, orgap, 550 &argtable, &argtablesiz); 551 } 552 goto rflag; 553 } 554 prec = n; 555 goto reswitch; 556 case '0': 557 /* 558 * ``Note that 0 is taken as a flag, not as the 559 * beginning of a field width.'' 560 * -- ANSI X3J11 561 */ 562 flags |= ZEROPAD; 563 goto rflag; 564 case '1': case '2': case '3': case '4': 565 case '5': case '6': case '7': case '8': case '9': 566 n = 0; 567 do { 568 APPEND_DIGIT(n, ch); 569 ch = *fmt++; 570 } while (is_digit(ch)); 571 if (ch == '$') { 572 nextarg = n; 573 if (argtable == NULL) { 574 argtable = statargtable; 575 __find_arguments(fmt0, orgap, 576 &argtable, &argtablesiz); 577 } 578 goto rflag; 579 } 580 width = n; 581 goto reswitch; 582 #ifdef FLOATING_POINT 583 case 'L': 584 flags |= LONGDBL; 585 goto rflag; 586 #endif 587 case 'h': 588 if (*fmt == 'h') { 589 fmt++; 590 flags |= CHARINT; 591 } else { 592 flags |= SHORTINT; 593 } 594 goto rflag; 595 case 'j': 596 flags |= MAXINT; 597 goto rflag; 598 case 'l': 599 if (*fmt == 'l') { 600 fmt++; 601 flags |= LLONGINT; 602 } else { 603 flags |= LONGINT; 604 } 605 goto rflag; 606 case 'q': 607 flags |= LLONGINT; 608 goto rflag; 609 case 't': 610 flags |= PTRINT; 611 goto rflag; 612 case 'z': 613 flags |= SIZEINT; 614 goto rflag; 615 case 'C': 616 flags |= LONGINT; 617 /*FALLTHROUGH*/ 618 case 'c': 619 if (flags & LONGINT) 620 *(cp = buf) = (wchar_t)GETARG(wint_t); 621 else 622 *(cp = buf) = (wchar_t)btowc(GETARG(int)); 623 size = 1; 624 sign = '\0'; 625 break; 626 case 'D': 627 flags |= LONGINT; 628 /*FALLTHROUGH*/ 629 case 'd': 630 case 'i': 631 _umax = SARG(); 632 if ((intmax_t)_umax < 0) { 633 _umax = -_umax; 634 sign = '-'; 635 } 636 base = DEC; 637 goto number; 638 #ifdef FLOATING_POINT 639 case 'a': 640 case 'A': 641 if (ch == 'a') { 642 ox[1] = 'x'; 643 xdigs = xdigs_lower; 644 expchar = 'p'; 645 } else { 646 ox[1] = 'X'; 647 xdigs = xdigs_upper; 648 expchar = 'P'; 649 } 650 if (prec >= 0) 651 prec++; 652 if (dtoaresult) 653 __freedtoa(dtoaresult); 654 if (flags & LONGDBL) { 655 fparg.ldbl = GETARG(long double); 656 dtoaresult = 657 __hldtoa(fparg.ldbl, xdigs, prec, 658 &expt, &signflag, &dtoaend); 659 if (dtoaresult == NULL) { 660 errno = ENOMEM; 661 goto error; 662 } 663 } else { 664 fparg.dbl = GETARG(double); 665 dtoaresult = 666 __hdtoa(fparg.dbl, xdigs, prec, 667 &expt, &signflag, &dtoaend); 668 if (dtoaresult == NULL) { 669 errno = ENOMEM; 670 goto error; 671 } 672 } 673 if (prec < 0) 674 prec = dtoaend - dtoaresult; 675 if (expt == INT_MAX) 676 ox[1] = '\0'; 677 if (convbuf) { 678 free(convbuf); 679 convbuf = NULL; 680 } 681 cp = convbuf = __mbsconv(dtoaresult, -1); 682 if (cp == NULL) 683 goto error; 684 ndig = dtoaend - dtoaresult; 685 goto fp_common; 686 case 'e': 687 case 'E': 688 expchar = ch; 689 if (prec < 0) /* account for digit before decpt */ 690 prec = DEFPREC + 1; 691 else 692 prec++; 693 goto fp_begin; 694 case 'f': 695 case 'F': 696 expchar = '\0'; 697 goto fp_begin; 698 case 'g': 699 case 'G': 700 expchar = ch - ('g' - 'e'); 701 if (prec == 0) 702 prec = 1; 703 fp_begin: 704 if (prec < 0) 705 prec = DEFPREC; 706 if (dtoaresult) 707 __freedtoa(dtoaresult); 708 if (flags & LONGDBL) { 709 fparg.ldbl = GETARG(long double); 710 dtoaresult = 711 __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 712 &expt, &signflag, &dtoaend); 713 if (dtoaresult == NULL) { 714 errno = ENOMEM; 715 goto error; 716 } 717 } else { 718 fparg.dbl = GETARG(double); 719 dtoaresult = 720 __dtoa(fparg.dbl, expchar ? 2 : 3, prec, 721 &expt, &signflag, &dtoaend); 722 if (dtoaresult == NULL) { 723 errno = ENOMEM; 724 goto error; 725 } 726 if (expt == 9999) 727 expt = INT_MAX; 728 } 729 if (convbuf) { 730 free(convbuf); 731 convbuf = NULL; 732 } 733 cp = convbuf = __mbsconv(dtoaresult, -1); 734 if (cp == NULL) 735 goto error; 736 ndig = dtoaend - dtoaresult; 737 fp_common: 738 if (signflag) 739 sign = '-'; 740 if (expt == INT_MAX) { /* inf or nan */ 741 if (*cp == 'N') { 742 cp = (ch >= 'a') ? L"nan" : L"NAN"; 743 sign = '\0'; 744 } else 745 cp = (ch >= 'a') ? L"inf" : L"INF"; 746 size = 3; 747 flags &= ~ZEROPAD; 748 break; 749 } 750 flags |= FPT; 751 if (ch == 'g' || ch == 'G') { 752 if (expt > -4 && expt <= prec) { 753 /* Make %[gG] smell like %[fF] */ 754 expchar = '\0'; 755 if (flags & ALT) 756 prec -= expt; 757 else 758 prec = ndig - expt; 759 if (prec < 0) 760 prec = 0; 761 } else { 762 /* 763 * Make %[gG] smell like %[eE], but 764 * trim trailing zeroes if no # flag. 765 */ 766 if (!(flags & ALT)) 767 prec = ndig; 768 } 769 } 770 if (expchar) { 771 expsize = exponent(expstr, expt - 1, expchar); 772 size = expsize + prec; 773 if (prec > 1 || flags & ALT) 774 ++size; 775 } else { 776 /* space for digits before decimal point */ 777 if (expt > 0) 778 size = expt; 779 else /* "0" */ 780 size = 1; 781 /* space for decimal pt and following digits */ 782 if (prec || flags & ALT) 783 size += prec + 1; 784 lead = expt; 785 } 786 break; 787 #endif /* FLOATING_POINT */ 788 case 'n': 789 if (flags & LLONGINT) 790 *GETARG(long long *) = ret; 791 else if (flags & LONGINT) 792 *GETARG(long *) = ret; 793 else if (flags & SHORTINT) 794 *GETARG(short *) = ret; 795 else if (flags & CHARINT) 796 *GETARG(__signed char *) = ret; 797 else if (flags & PTRINT) 798 *GETARG(ptrdiff_t *) = ret; 799 else if (flags & SIZEINT) 800 *GETARG(ssize_t *) = ret; 801 else if (flags & MAXINT) 802 *GETARG(intmax_t *) = ret; 803 else 804 *GETARG(int *) = ret; 805 continue; /* no output */ 806 case 'O': 807 flags |= LONGINT; 808 /*FALLTHROUGH*/ 809 case 'o': 810 _umax = UARG(); 811 base = OCT; 812 goto nosign; 813 case 'p': 814 /* 815 * ``The argument shall be a pointer to void. The 816 * value of the pointer is converted to a sequence 817 * of printable characters, in an implementation- 818 * defined manner.'' 819 * -- ANSI X3J11 820 */ 821 /* NOSTRICT */ 822 _umax = (u_long)GETARG(void *); 823 base = HEX; 824 xdigs = xdigs_lower; 825 ox[1] = 'x'; 826 goto nosign; 827 case 'S': 828 flags |= LONGINT; 829 /*FALLTHROUGH*/ 830 case 's': 831 if (flags & LONGINT) { 832 if ((cp = GETARG(wchar_t *)) == NULL) 833 cp = L"(null)"; 834 } else { 835 char *mbsarg; 836 if ((mbsarg = GETARG(char *)) == NULL) 837 mbsarg = "(null)"; 838 if (convbuf) { 839 free(convbuf); 840 convbuf = NULL; 841 } 842 convbuf = __mbsconv(mbsarg, prec); 843 if (convbuf == NULL) { 844 fp->_flags |= __SERR; 845 goto error; 846 } else 847 cp = convbuf; 848 } 849 if (prec >= 0) { 850 /* 851 * can't use wcslen; can only look for the 852 * NUL in the first `prec' characters, and 853 * wcslen() will go further. 854 */ 855 wchar_t *p = wmemchr(cp, 0, prec); 856 857 size = p ? (p - cp) : prec; 858 } else { 859 size_t len; 860 861 if ((len = wcslen(cp)) > INT_MAX) 862 goto overflow; 863 size = (int)len; 864 } 865 sign = '\0'; 866 break; 867 case 'U': 868 flags |= LONGINT; 869 /*FALLTHROUGH*/ 870 case 'u': 871 _umax = UARG(); 872 base = DEC; 873 goto nosign; 874 case 'X': 875 xdigs = xdigs_upper; 876 goto hex; 877 case 'x': 878 xdigs = xdigs_lower; 879 hex: _umax = UARG(); 880 base = HEX; 881 /* leading 0x/X only if non-zero */ 882 if (flags & ALT && _umax != 0) 883 ox[1] = ch; 884 885 /* unsigned conversions */ 886 nosign: sign = '\0'; 887 /* 888 * ``... diouXx conversions ... if a precision is 889 * specified, the 0 flag will be ignored.'' 890 * -- ANSI X3J11 891 */ 892 number: if ((dprec = prec) >= 0) 893 flags &= ~ZEROPAD; 894 895 /* 896 * ``The result of converting a zero value with an 897 * explicit precision of zero is no characters.'' 898 * -- ANSI X3J11 899 */ 900 cp = buf + BUF; 901 if (_umax != 0 || prec != 0) { 902 /* 903 * Unsigned mod is hard, and unsigned mod 904 * by a constant is easier than that by 905 * a variable; hence this switch. 906 */ 907 switch (base) { 908 case OCT: 909 do { 910 *--cp = to_char(_umax & 7); 911 _umax >>= 3; 912 } while (_umax); 913 /* handle octal leading 0 */ 914 if (flags & ALT && *cp != '0') 915 *--cp = '0'; 916 break; 917 918 case DEC: 919 /* many numbers are 1 digit */ 920 while (_umax >= 10) { 921 *--cp = to_char(_umax % 10); 922 _umax /= 10; 923 } 924 *--cp = to_char(_umax); 925 break; 926 927 case HEX: 928 do { 929 *--cp = xdigs[_umax & 15]; 930 _umax >>= 4; 931 } while (_umax); 932 break; 933 934 default: 935 cp = L"bug in vfwprintf: bad base"; 936 size = wcslen(cp); 937 goto skipsize; 938 } 939 } 940 size = buf + BUF - cp; 941 if (size > BUF) /* should never happen */ 942 abort(); 943 skipsize: 944 break; 945 default: /* "%?" prints ?, unless ? is NUL */ 946 if (ch == '\0') 947 goto done; 948 /* pretend it was %c with argument ch */ 949 cp = buf; 950 *cp = ch; 951 size = 1; 952 sign = '\0'; 953 break; 954 } 955 956 /* 957 * All reasonable formats wind up here. At this point, `cp' 958 * points to a string which (if not flags&LADJUST) should be 959 * padded out to `width' places. If flags&ZEROPAD, it should 960 * first be prefixed by any sign or other prefix; otherwise, 961 * it should be blank padded before the prefix is emitted. 962 * After any left-hand padding and prefixing, emit zeroes 963 * required by a decimal %[diouxX] precision, then print the 964 * string proper, then emit zeroes required by any leftover 965 * floating precision; finally, if LADJUST, pad with blanks. 966 * 967 * Compute actual size, so we know how much to pad. 968 * size excludes decimal prec; realsz includes it. 969 */ 970 realsz = dprec > size ? dprec : size; 971 if (sign) 972 realsz++; 973 if (ox[1]) 974 realsz+= 2; 975 976 /* right-adjusting blank padding */ 977 if ((flags & (LADJUST|ZEROPAD)) == 0) 978 PAD(width - realsz, blanks); 979 980 /* prefix */ 981 if (sign) 982 PRINT(&sign, 1); 983 if (ox[1]) { /* ox[1] is either x, X, or \0 */ 984 ox[0] = '0'; 985 PRINT(ox, 2); 986 } 987 988 /* right-adjusting zero padding */ 989 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 990 PAD(width - realsz, zeroes); 991 992 /* leading zeroes from decimal precision */ 993 PAD(dprec - size, zeroes); 994 995 /* the string or number proper */ 996 #ifdef FLOATING_POINT 997 if ((flags & FPT) == 0) { 998 PRINT(cp, size); 999 } else { /* glue together f_p fragments */ 1000 if (decimal_point == NULL) 1001 decimal_point = nl_langinfo(RADIXCHAR); 1002 if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1003 if (expt <= 0) { 1004 PRINT(zeroes, 1); 1005 if (prec || flags & ALT) 1006 PRINT(decimal_point, 1); 1007 PAD(-expt, zeroes); 1008 /* already handled initial 0's */ 1009 prec += expt; 1010 } else { 1011 PRINTANDPAD(cp, convbuf + ndig, 1012 lead, zeroes); 1013 cp += lead; 1014 if (prec || flags & ALT) 1015 PRINT(decimal_point, 1); 1016 } 1017 PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); 1018 } else { /* %[eE] or sufficiently long %[gG] */ 1019 if (prec > 1 || flags & ALT) { 1020 buf[0] = *cp++; 1021 buf[1] = *decimal_point; 1022 PRINT(buf, 2); 1023 PRINT(cp, ndig-1); 1024 PAD(prec - ndig, zeroes); 1025 } else { /* XeYYY */ 1026 PRINT(cp, 1); 1027 } 1028 PRINT(expstr, expsize); 1029 } 1030 } 1031 #else 1032 PRINT(cp, size); 1033 #endif 1034 /* left-adjusting padding (always blank) */ 1035 if (flags & LADJUST) 1036 PAD(width - realsz, blanks); 1037 1038 /* finally, adjust ret */ 1039 if (width < realsz) 1040 width = realsz; 1041 if (width > INT_MAX - ret) 1042 goto overflow; 1043 ret += width; 1044 } 1045 done: 1046 error: 1047 va_end(orgap); 1048 if (__sferror(fp)) 1049 ret = -1; 1050 goto finish; 1051 1052 overflow: 1053 errno = ENOMEM; 1054 ret = -1; 1055 1056 finish: 1057 if (convbuf) 1058 free(convbuf); 1059 #ifdef FLOATING_POINT 1060 if (dtoaresult) 1061 __freedtoa(dtoaresult); 1062 #endif 1063 if (argtable != NULL && argtable != statargtable) { 1064 munmap(argtable, argtablesiz); 1065 argtable = NULL; 1066 } 1067 return (ret); 1068 } 1069 1070 int 1071 vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, __va_list ap) 1072 { 1073 int r; 1074 1075 FLOCKFILE(fp); 1076 r = __vfwprintf(fp, fmt0, ap); 1077 FUNLOCKFILE(fp); 1078 1079 return (r); 1080 } 1081 1082 /* 1083 * Type ids for argument type table. 1084 */ 1085 #define T_UNUSED 0 1086 #define T_SHORT 1 1087 #define T_U_SHORT 2 1088 #define TP_SHORT 3 1089 #define T_INT 4 1090 #define T_U_INT 5 1091 #define TP_INT 6 1092 #define T_LONG 7 1093 #define T_U_LONG 8 1094 #define TP_LONG 9 1095 #define T_LLONG 10 1096 #define T_U_LLONG 11 1097 #define TP_LLONG 12 1098 #define T_DOUBLE 13 1099 #define T_LONG_DOUBLE 14 1100 #define TP_CHAR 15 1101 #define TP_VOID 16 1102 #define T_PTRINT 17 1103 #define TP_PTRINT 18 1104 #define T_SIZEINT 19 1105 #define T_SSIZEINT 20 1106 #define TP_SSIZEINT 21 1107 #define T_MAXINT 22 1108 #define T_MAXUINT 23 1109 #define TP_MAXINT 24 1110 #define T_CHAR 25 1111 #define T_U_CHAR 26 1112 #define T_WINT 27 1113 #define TP_WCHAR 28 1114 1115 /* 1116 * Find all arguments when a positional parameter is encountered. Returns a 1117 * table, indexed by argument number, of pointers to each arguments. The 1118 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 1119 * It will be replaced with a mmap-ed one if it overflows (malloc cannot be 1120 * used since we are attempting to make snprintf thread safe, and alloca is 1121 * problematic since we have nested functions..) 1122 */ 1123 static int 1124 __find_arguments(const wchar_t *fmt0, va_list ap, union arg **argtable, 1125 size_t *argtablesiz) 1126 { 1127 wchar_t *fmt; /* format string */ 1128 int ch; /* character from fmt */ 1129 int n, n2; /* handy integer (short term usage) */ 1130 wchar_t *cp; /* handy char pointer (short term usage) */ 1131 int flags; /* flags as above */ 1132 unsigned char *typetable; /* table of types */ 1133 unsigned char stattypetable[STATIC_ARG_TBL_SIZE]; 1134 int tablesize; /* current size of type table */ 1135 int tablemax; /* largest used index in table */ 1136 int nextarg; /* 1-based argument index */ 1137 int ret = 0; /* return value */ 1138 1139 /* 1140 * Add an argument type to the table, expanding if necessary. 1141 */ 1142 #define ADDTYPE(type) \ 1143 ((nextarg >= tablesize) ? \ 1144 __grow_type_table(&typetable, &tablesize) : 0, \ 1145 (nextarg > tablemax) ? tablemax = nextarg : 0, \ 1146 typetable[nextarg++] = type) 1147 1148 #define ADDSARG() \ 1149 ((flags&MAXINT) ? ADDTYPE(T_MAXINT) : \ 1150 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \ 1151 ((flags&SIZEINT) ? ADDTYPE(T_SSIZEINT) : \ 1152 ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 1153 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \ 1154 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : \ 1155 ((flags&CHARINT) ? ADDTYPE(T_CHAR) : ADDTYPE(T_INT)))))))) 1156 1157 #define ADDUARG() \ 1158 ((flags&MAXINT) ? ADDTYPE(T_MAXUINT) : \ 1159 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \ 1160 ((flags&SIZEINT) ? ADDTYPE(T_SIZEINT) : \ 1161 ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 1162 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \ 1163 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : \ 1164 ((flags&CHARINT) ? ADDTYPE(T_U_CHAR) : ADDTYPE(T_U_INT)))))))) 1165 1166 /* 1167 * Add * arguments to the type array. 1168 */ 1169 #define ADDASTER() \ 1170 n2 = 0; \ 1171 cp = fmt; \ 1172 while (is_digit(*cp)) { \ 1173 APPEND_DIGIT(n2, *cp); \ 1174 cp++; \ 1175 } \ 1176 if (*cp == '$') { \ 1177 int hold = nextarg; \ 1178 nextarg = n2; \ 1179 ADDTYPE(T_INT); \ 1180 nextarg = hold; \ 1181 fmt = ++cp; \ 1182 } else { \ 1183 ADDTYPE(T_INT); \ 1184 } 1185 fmt = (wchar_t *)fmt0; 1186 typetable = stattypetable; 1187 tablesize = STATIC_ARG_TBL_SIZE; 1188 tablemax = 0; 1189 nextarg = 1; 1190 memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 1191 1192 /* 1193 * Scan the format for conversions (`%' character). 1194 */ 1195 for (;;) { 1196 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 1197 continue; 1198 if (ch == '\0') 1199 goto done; 1200 fmt++; /* skip over '%' */ 1201 1202 flags = 0; 1203 1204 rflag: ch = *fmt++; 1205 reswitch: switch (ch) { 1206 case ' ': 1207 case '#': 1208 case '\'': 1209 goto rflag; 1210 case '*': 1211 ADDASTER(); 1212 goto rflag; 1213 case '-': 1214 case '+': 1215 goto rflag; 1216 case '.': 1217 if ((ch = *fmt++) == '*') { 1218 ADDASTER(); 1219 goto rflag; 1220 } 1221 while (is_digit(ch)) { 1222 ch = *fmt++; 1223 } 1224 goto reswitch; 1225 case '0': 1226 goto rflag; 1227 case '1': case '2': case '3': case '4': 1228 case '5': case '6': case '7': case '8': case '9': 1229 n = 0; 1230 do { 1231 APPEND_DIGIT(n ,ch); 1232 ch = *fmt++; 1233 } while (is_digit(ch)); 1234 if (ch == '$') { 1235 nextarg = n; 1236 goto rflag; 1237 } 1238 goto reswitch; 1239 #ifdef FLOATING_POINT 1240 case 'L': 1241 flags |= LONGDBL; 1242 goto rflag; 1243 #endif 1244 case 'h': 1245 if (*fmt == 'h') { 1246 fmt++; 1247 flags |= CHARINT; 1248 } else { 1249 flags |= SHORTINT; 1250 } 1251 goto rflag; 1252 case 'l': 1253 if (*fmt == 'l') { 1254 fmt++; 1255 flags |= LLONGINT; 1256 } else { 1257 flags |= LONGINT; 1258 } 1259 goto rflag; 1260 case 'q': 1261 flags |= LLONGINT; 1262 goto rflag; 1263 case 't': 1264 flags |= PTRINT; 1265 goto rflag; 1266 case 'z': 1267 flags |= SIZEINT; 1268 goto rflag; 1269 case 'C': 1270 flags |= LONGINT; 1271 /*FALLTHROUGH*/ 1272 case 'c': 1273 if (flags & LONGINT) 1274 ADDTYPE(T_WINT); 1275 else 1276 ADDTYPE(T_INT); 1277 break; 1278 case 'D': 1279 flags |= LONGINT; 1280 /*FALLTHROUGH*/ 1281 case 'd': 1282 case 'i': 1283 ADDSARG(); 1284 break; 1285 #ifdef FLOATING_POINT 1286 case 'a': 1287 case 'A': 1288 case 'e': 1289 case 'E': 1290 case 'f': 1291 case 'F': 1292 case 'g': 1293 case 'G': 1294 if (flags & LONGDBL) 1295 ADDTYPE(T_LONG_DOUBLE); 1296 else 1297 ADDTYPE(T_DOUBLE); 1298 break; 1299 #endif /* FLOATING_POINT */ 1300 case 'n': 1301 if (flags & LLONGINT) 1302 ADDTYPE(TP_LLONG); 1303 else if (flags & LONGINT) 1304 ADDTYPE(TP_LONG); 1305 else if (flags & SHORTINT) 1306 ADDTYPE(TP_SHORT); 1307 else if (flags & PTRINT) 1308 ADDTYPE(TP_PTRINT); 1309 else if (flags & SIZEINT) 1310 ADDTYPE(TP_SSIZEINT); 1311 else if (flags & MAXINT) 1312 ADDTYPE(TP_MAXINT); 1313 else 1314 ADDTYPE(TP_INT); 1315 continue; /* no output */ 1316 case 'O': 1317 flags |= LONGINT; 1318 /*FALLTHROUGH*/ 1319 case 'o': 1320 ADDUARG(); 1321 break; 1322 case 'p': 1323 ADDTYPE(TP_VOID); 1324 break; 1325 case 'S': 1326 flags |= LONGINT; 1327 /*FALLTHROUGH*/ 1328 case 's': 1329 if (flags & LONGINT) 1330 ADDTYPE(TP_CHAR); 1331 else 1332 ADDTYPE(TP_WCHAR); 1333 break; 1334 case 'U': 1335 flags |= LONGINT; 1336 /*FALLTHROUGH*/ 1337 case 'u': 1338 case 'X': 1339 case 'x': 1340 ADDUARG(); 1341 break; 1342 default: /* "%?" prints ?, unless ? is NUL */ 1343 if (ch == '\0') 1344 goto done; 1345 break; 1346 } 1347 } 1348 done: 1349 /* 1350 * Build the argument table. 1351 */ 1352 if (tablemax >= STATIC_ARG_TBL_SIZE) { 1353 *argtablesiz = sizeof(union arg) * (tablemax + 1); 1354 *argtable = mmap(NULL, *argtablesiz, 1355 PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0); 1356 if (*argtable == MAP_FAILED) 1357 return (-1); 1358 } 1359 1360 #if 0 1361 /* XXX is this required? */ 1362 (*argtable)[0].intarg = 0; 1363 #endif 1364 for (n = 1; n <= tablemax; n++) { 1365 switch (typetable[n]) { 1366 case T_UNUSED: 1367 case T_CHAR: 1368 case T_U_CHAR: 1369 case T_SHORT: 1370 case T_U_SHORT: 1371 case T_INT: 1372 (*argtable)[n].intarg = va_arg(ap, int); 1373 break; 1374 case TP_SHORT: 1375 (*argtable)[n].pshortarg = va_arg(ap, short *); 1376 break; 1377 case T_U_INT: 1378 (*argtable)[n].uintarg = va_arg(ap, unsigned int); 1379 break; 1380 case TP_INT: 1381 (*argtable)[n].pintarg = va_arg(ap, int *); 1382 break; 1383 case T_LONG: 1384 (*argtable)[n].longarg = va_arg(ap, long); 1385 break; 1386 case T_U_LONG: 1387 (*argtable)[n].ulongarg = va_arg(ap, unsigned long); 1388 break; 1389 case TP_LONG: 1390 (*argtable)[n].plongarg = va_arg(ap, long *); 1391 break; 1392 case T_LLONG: 1393 (*argtable)[n].longlongarg = va_arg(ap, long long); 1394 break; 1395 case T_U_LLONG: 1396 (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long); 1397 break; 1398 case TP_LLONG: 1399 (*argtable)[n].plonglongarg = va_arg(ap, long long *); 1400 break; 1401 #ifdef FLOATING_POINT 1402 case T_DOUBLE: 1403 (*argtable)[n].doublearg = va_arg(ap, double); 1404 break; 1405 case T_LONG_DOUBLE: 1406 (*argtable)[n].longdoublearg = va_arg(ap, long double); 1407 break; 1408 #endif 1409 case TP_CHAR: 1410 (*argtable)[n].pchararg = va_arg(ap, char *); 1411 break; 1412 case TP_VOID: 1413 (*argtable)[n].pvoidarg = va_arg(ap, void *); 1414 break; 1415 case T_PTRINT: 1416 (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t); 1417 break; 1418 case TP_PTRINT: 1419 (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *); 1420 break; 1421 case T_SIZEINT: 1422 (*argtable)[n].sizearg = va_arg(ap, size_t); 1423 break; 1424 case T_SSIZEINT: 1425 (*argtable)[n].ssizearg = va_arg(ap, ssize_t); 1426 break; 1427 case TP_SSIZEINT: 1428 (*argtable)[n].pssizearg = va_arg(ap, ssize_t *); 1429 break; 1430 case TP_MAXINT: 1431 (*argtable)[n].intmaxarg = va_arg(ap, intmax_t); 1432 break; 1433 case T_WINT: 1434 (*argtable)[n].wintarg = va_arg(ap, wint_t); 1435 break; 1436 case TP_WCHAR: 1437 (*argtable)[n].pwchararg = va_arg(ap, wchar_t *); 1438 break; 1439 } 1440 } 1441 goto finish; 1442 1443 overflow: 1444 errno = ENOMEM; 1445 ret = -1; 1446 1447 finish: 1448 if (typetable != NULL && typetable != stattypetable) { 1449 munmap(typetable, *argtablesiz); 1450 typetable = NULL; 1451 } 1452 return (ret); 1453 } 1454 1455 /* 1456 * Increase the size of the type table. 1457 */ 1458 static int 1459 __grow_type_table(unsigned char **typetable, int *tablesize) 1460 { 1461 unsigned char *oldtable = *typetable; 1462 int newsize = *tablesize * 2; 1463 1464 if (newsize < getpagesize()) 1465 newsize = getpagesize(); 1466 1467 if (*tablesize == STATIC_ARG_TBL_SIZE) { 1468 *typetable = mmap(NULL, newsize, PROT_WRITE|PROT_READ, 1469 MAP_ANON|MAP_PRIVATE, -1, 0); 1470 if (*typetable == MAP_FAILED) 1471 return (-1); 1472 bcopy(oldtable, *typetable, *tablesize); 1473 } else { 1474 unsigned char *new = mmap(NULL, newsize, PROT_WRITE|PROT_READ, 1475 MAP_ANON|MAP_PRIVATE, -1, 0); 1476 if (new == MAP_FAILED) 1477 return (-1); 1478 memmove(new, *typetable, *tablesize); 1479 munmap(*typetable, *tablesize); 1480 *typetable = new; 1481 } 1482 memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize)); 1483 1484 *tablesize = newsize; 1485 return (0); 1486 } 1487 1488 1489 #ifdef FLOATING_POINT 1490 static int 1491 exponent(wchar_t *p0, int exp, int fmtch) 1492 { 1493 wchar_t *p, *t; 1494 wchar_t expbuf[MAXEXPDIG]; 1495 1496 p = p0; 1497 *p++ = fmtch; 1498 if (exp < 0) { 1499 exp = -exp; 1500 *p++ = '-'; 1501 } else 1502 *p++ = '+'; 1503 t = expbuf + MAXEXPDIG; 1504 if (exp > 9) { 1505 do { 1506 *--t = to_char(exp % 10); 1507 } while ((exp /= 10) > 9); 1508 *--t = to_char(exp); 1509 for (; t < expbuf + MAXEXPDIG; *p++ = *t++) 1510 /* nothing */; 1511 } else { 1512 /* 1513 * Exponents for decimal floating point conversions 1514 * (%[eEgG]) must be at least two characters long, 1515 * whereas exponents for hexadecimal conversions can 1516 * be only one character long. 1517 */ 1518 if (fmtch == 'e' || fmtch == 'E') 1519 *p++ = '0'; 1520 *p++ = to_char(exp); 1521 } 1522 return (p - p0); 1523 } 1524 #endif /* FLOATING_POINT */ 1525