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