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