1 /* $OpenBSD: vfwprintf.c,v 1.18 2017/08/15 00:20:39 deraadt 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 __find_arguments(fmt0, orgap, &argtable, &argtablesiz); \ 430 } \ 431 nextarg = n2; \ 432 val = GETARG(int); \ 433 nextarg = hold; \ 434 fmt = ++cp; \ 435 } else { \ 436 val = GETARG(int); \ 437 } 438 439 /* 440 * Get the argument indexed by nextarg. If the argument table is 441 * built, use it to get the argument. If its not, get the next 442 * argument (and arguments must be gotten sequentially). 443 */ 444 #define GETARG(type) \ 445 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ 446 (nextarg++, va_arg(ap, type))) 447 448 _SET_ORIENTATION(fp, 1); 449 /* sorry, fwprintf(read_only_file, "") returns EOF, not 0 */ 450 if (cantwrite(fp)) { 451 errno = EBADF; 452 return (EOF); 453 } 454 455 /* optimise fwprintf(stderr) (and other unbuffered Unix files) */ 456 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 457 fp->_file >= 0) 458 return (__sbprintf(fp, fmt0, ap)); 459 460 fmt = (wchar_t *)fmt0; 461 argtable = NULL; 462 nextarg = 1; 463 va_copy(orgap, ap); 464 ret = 0; 465 convbuf = NULL; 466 467 /* 468 * Scan the format for conversions (`%' character). 469 */ 470 for (;;) { 471 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 472 continue; 473 if (fmt != cp) { 474 ptrdiff_t m = fmt - cp; 475 if (m < 0 || m > INT_MAX - ret) 476 goto overflow; 477 PRINT(cp, m); 478 ret += m; 479 } 480 if (ch == '\0') 481 goto done; 482 fmt++; /* skip over '%' */ 483 484 flags = 0; 485 dprec = 0; 486 width = 0; 487 prec = -1; 488 sign = '\0'; 489 ox[1] = '\0'; 490 491 rflag: ch = *fmt++; 492 reswitch: switch (ch) { 493 case ' ': 494 /* 495 * ``If the space and + flags both appear, the space 496 * flag will be ignored.'' 497 * -- ANSI X3J11 498 */ 499 if (!sign) 500 sign = ' '; 501 goto rflag; 502 case '#': 503 flags |= ALT; 504 goto rflag; 505 case '\'': 506 /* grouping not implemented */ 507 goto rflag; 508 case '*': 509 /* 510 * ``A negative field width argument is taken as a 511 * - flag followed by a positive field width.'' 512 * -- ANSI X3J11 513 * They don't exclude field widths read from args. 514 */ 515 GETASTER(width); 516 if (width >= 0) 517 goto rflag; 518 if (width == INT_MIN) 519 goto overflow; 520 width = -width; 521 /* FALLTHROUGH */ 522 case '-': 523 flags |= LADJUST; 524 goto rflag; 525 case '+': 526 sign = '+'; 527 goto rflag; 528 case '.': 529 if ((ch = *fmt++) == '*') { 530 GETASTER(n); 531 prec = n < 0 ? -1 : n; 532 goto rflag; 533 } 534 n = 0; 535 while (is_digit(ch)) { 536 APPEND_DIGIT(n, ch); 537 ch = *fmt++; 538 } 539 if (ch == '$') { 540 nextarg = n; 541 if (argtable == NULL) { 542 argtable = statargtable; 543 __find_arguments(fmt0, orgap, 544 &argtable, &argtablesiz); 545 } 546 goto rflag; 547 } 548 prec = n; 549 goto reswitch; 550 case '0': 551 /* 552 * ``Note that 0 is taken as a flag, not as the 553 * beginning of a field width.'' 554 * -- ANSI X3J11 555 */ 556 flags |= ZEROPAD; 557 goto rflag; 558 case '1': case '2': case '3': case '4': 559 case '5': case '6': case '7': case '8': case '9': 560 n = 0; 561 do { 562 APPEND_DIGIT(n, ch); 563 ch = *fmt++; 564 } while (is_digit(ch)); 565 if (ch == '$') { 566 nextarg = n; 567 if (argtable == NULL) { 568 argtable = statargtable; 569 __find_arguments(fmt0, orgap, 570 &argtable, &argtablesiz); 571 } 572 goto rflag; 573 } 574 width = n; 575 goto reswitch; 576 #ifdef FLOATING_POINT 577 case 'L': 578 flags |= LONGDBL; 579 goto rflag; 580 #endif 581 case 'h': 582 if (*fmt == 'h') { 583 fmt++; 584 flags |= CHARINT; 585 } else { 586 flags |= SHORTINT; 587 } 588 goto rflag; 589 case 'j': 590 flags |= MAXINT; 591 goto rflag; 592 case 'l': 593 if (*fmt == 'l') { 594 fmt++; 595 flags |= LLONGINT; 596 } else { 597 flags |= LONGINT; 598 } 599 goto rflag; 600 case 'q': 601 flags |= LLONGINT; 602 goto rflag; 603 case 't': 604 flags |= PTRINT; 605 goto rflag; 606 case 'z': 607 flags |= SIZEINT; 608 goto rflag; 609 case 'C': 610 flags |= LONGINT; 611 /*FALLTHROUGH*/ 612 case 'c': 613 if (flags & LONGINT) 614 *(cp = buf) = (wchar_t)GETARG(wint_t); 615 else 616 *(cp = buf) = (wchar_t)btowc(GETARG(int)); 617 size = 1; 618 sign = '\0'; 619 break; 620 case 'D': 621 flags |= LONGINT; 622 /*FALLTHROUGH*/ 623 case 'd': 624 case 'i': 625 _umax = SARG(); 626 if ((intmax_t)_umax < 0) { 627 _umax = -_umax; 628 sign = '-'; 629 } 630 base = DEC; 631 goto number; 632 #ifdef FLOATING_POINT 633 case 'a': 634 case 'A': 635 if (ch == 'a') { 636 ox[1] = 'x'; 637 xdigs = xdigs_lower; 638 expchar = 'p'; 639 } else { 640 ox[1] = 'X'; 641 xdigs = xdigs_upper; 642 expchar = 'P'; 643 } 644 if (prec >= 0) 645 prec++; 646 if (dtoaresult) 647 __freedtoa(dtoaresult); 648 if (flags & LONGDBL) { 649 fparg.ldbl = GETARG(long double); 650 dtoaresult = 651 __hldtoa(fparg.ldbl, xdigs, prec, 652 &expt, &signflag, &dtoaend); 653 if (dtoaresult == NULL) { 654 errno = ENOMEM; 655 goto error; 656 } 657 } else { 658 fparg.dbl = GETARG(double); 659 dtoaresult = 660 __hdtoa(fparg.dbl, xdigs, prec, 661 &expt, &signflag, &dtoaend); 662 if (dtoaresult == NULL) { 663 errno = ENOMEM; 664 goto error; 665 } 666 } 667 if (prec < 0) 668 prec = dtoaend - dtoaresult; 669 if (expt == INT_MAX) 670 ox[1] = '\0'; 671 free(convbuf); 672 cp = convbuf = __mbsconv(dtoaresult, -1); 673 if (cp == NULL) 674 goto error; 675 ndig = dtoaend - dtoaresult; 676 goto fp_common; 677 case 'e': 678 case 'E': 679 expchar = ch; 680 if (prec < 0) /* account for digit before decpt */ 681 prec = DEFPREC + 1; 682 else 683 prec++; 684 goto fp_begin; 685 case 'f': 686 case 'F': 687 expchar = '\0'; 688 goto fp_begin; 689 case 'g': 690 case 'G': 691 expchar = ch - ('g' - 'e'); 692 if (prec == 0) 693 prec = 1; 694 fp_begin: 695 if (prec < 0) 696 prec = DEFPREC; 697 if (dtoaresult) 698 __freedtoa(dtoaresult); 699 if (flags & LONGDBL) { 700 fparg.ldbl = GETARG(long double); 701 dtoaresult = 702 __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, 703 &expt, &signflag, &dtoaend); 704 if (dtoaresult == NULL) { 705 errno = ENOMEM; 706 goto error; 707 } 708 } else { 709 fparg.dbl = GETARG(double); 710 dtoaresult = 711 __dtoa(fparg.dbl, expchar ? 2 : 3, prec, 712 &expt, &signflag, &dtoaend); 713 if (dtoaresult == NULL) { 714 errno = ENOMEM; 715 goto error; 716 } 717 if (expt == 9999) 718 expt = INT_MAX; 719 } 720 free(convbuf); 721 cp = convbuf = __mbsconv(dtoaresult, -1); 722 if (cp == NULL) 723 goto error; 724 ndig = dtoaend - dtoaresult; 725 fp_common: 726 if (signflag) 727 sign = '-'; 728 if (expt == INT_MAX) { /* inf or nan */ 729 if (*cp == 'N') 730 cp = (ch >= 'a') ? L"nan" : L"NAN"; 731 else 732 cp = (ch >= 'a') ? L"inf" : L"INF"; 733 size = 3; 734 flags &= ~ZEROPAD; 735 break; 736 } 737 flags |= FPT; 738 if (ch == 'g' || ch == 'G') { 739 if (expt > -4 && expt <= prec) { 740 /* Make %[gG] smell like %[fF] */ 741 expchar = '\0'; 742 if (flags & ALT) 743 prec -= expt; 744 else 745 prec = ndig - expt; 746 if (prec < 0) 747 prec = 0; 748 } else { 749 /* 750 * Make %[gG] smell like %[eE], but 751 * trim trailing zeroes if no # flag. 752 */ 753 if (!(flags & ALT)) 754 prec = ndig; 755 } 756 } 757 if (expchar) { 758 expsize = exponent(expstr, expt - 1, expchar); 759 size = expsize + prec; 760 if (prec > 1 || flags & ALT) 761 ++size; 762 } else { 763 /* space for digits before decimal point */ 764 if (expt > 0) 765 size = expt; 766 else /* "0" */ 767 size = 1; 768 /* space for decimal pt and following digits */ 769 if (prec || flags & ALT) 770 size += prec + 1; 771 lead = expt; 772 } 773 break; 774 #endif /* FLOATING_POINT */ 775 #ifndef NO_PRINTF_PERCENT_N 776 case 'n': 777 if (flags & LLONGINT) 778 *GETARG(long long *) = ret; 779 else if (flags & LONGINT) 780 *GETARG(long *) = ret; 781 else if (flags & SHORTINT) 782 *GETARG(short *) = ret; 783 else if (flags & CHARINT) 784 *GETARG(signed char *) = ret; 785 else if (flags & PTRINT) 786 *GETARG(ptrdiff_t *) = ret; 787 else if (flags & SIZEINT) 788 *GETARG(ssize_t *) = ret; 789 else if (flags & MAXINT) 790 *GETARG(intmax_t *) = ret; 791 else 792 *GETARG(int *) = ret; 793 continue; /* no output */ 794 #endif /* NO_PRINTF_PERCENT_N */ 795 case 'O': 796 flags |= LONGINT; 797 /*FALLTHROUGH*/ 798 case 'o': 799 _umax = UARG(); 800 base = OCT; 801 goto nosign; 802 case 'p': 803 /* 804 * ``The argument shall be a pointer to void. The 805 * value of the pointer is converted to a sequence 806 * of printable characters, in an implementation- 807 * defined manner.'' 808 * -- ANSI X3J11 809 */ 810 _umax = (u_long)GETARG(void *); 811 base = HEX; 812 xdigs = xdigs_lower; 813 ox[1] = 'x'; 814 goto nosign; 815 case 'S': 816 flags |= LONGINT; 817 /*FALLTHROUGH*/ 818 case 's': 819 if (flags & LONGINT) { 820 if ((cp = GETARG(wchar_t *)) == NULL) { 821 struct syslog_data sdata = SYSLOG_DATA_INIT; 822 int save_errno = errno; 823 824 syslog_r(LOG_CRIT | LOG_CONS, &sdata, 825 "vfwprintf %%ls NULL in \"%ls\"", fmt0); 826 errno = save_errno; 827 828 cp = L"(null)"; 829 } 830 } else { 831 char *mbsarg; 832 if ((mbsarg = GETARG(char *)) == NULL) { 833 struct syslog_data sdata = SYSLOG_DATA_INIT; 834 int save_errno = errno; 835 836 syslog_r(LOG_CRIT | LOG_CONS, &sdata, 837 "vfwprintf %%s NULL in \"%ls\"", fmt0); 838 errno = save_errno; 839 840 mbsarg = "(null)"; 841 } 842 free(convbuf); 843 convbuf = __mbsconv(mbsarg, prec); 844 if (convbuf == NULL) { 845 fp->_flags |= __SERR; 846 goto error; 847 } else 848 cp = convbuf; 849 } 850 if (prec >= 0) { 851 /* 852 * can't use wcslen; can only look for the 853 * NUL in the first `prec' characters, and 854 * wcslen() will go further. 855 */ 856 wchar_t *p = wmemchr(cp, 0, prec); 857 858 size = p ? (p - cp) : prec; 859 } else { 860 size_t len; 861 862 if ((len = wcslen(cp)) > INT_MAX) 863 goto overflow; 864 size = (int)len; 865 } 866 sign = '\0'; 867 break; 868 case 'U': 869 flags |= LONGINT; 870 /*FALLTHROUGH*/ 871 case 'u': 872 _umax = UARG(); 873 base = DEC; 874 goto nosign; 875 case 'X': 876 xdigs = xdigs_upper; 877 goto hex; 878 case 'x': 879 xdigs = xdigs_lower; 880 hex: _umax = UARG(); 881 base = HEX; 882 /* leading 0x/X only if non-zero */ 883 if (flags & ALT && _umax != 0) 884 ox[1] = ch; 885 886 /* unsigned conversions */ 887 nosign: sign = '\0'; 888 /* 889 * ``... diouXx conversions ... if a precision is 890 * specified, the 0 flag will be ignored.'' 891 * -- ANSI X3J11 892 */ 893 number: if ((dprec = prec) >= 0) 894 flags &= ~ZEROPAD; 895 896 /* 897 * ``The result of converting a zero value with an 898 * explicit precision of zero is no characters.'' 899 * -- ANSI X3J11 900 */ 901 cp = buf + BUF; 902 if (_umax != 0 || prec != 0) { 903 /* 904 * Unsigned mod is hard, and unsigned mod 905 * by a constant is easier than that by 906 * a variable; hence this switch. 907 */ 908 switch (base) { 909 case OCT: 910 do { 911 *--cp = to_char(_umax & 7); 912 _umax >>= 3; 913 } while (_umax); 914 /* handle octal leading 0 */ 915 if (flags & ALT && *cp != '0') 916 *--cp = '0'; 917 break; 918 919 case DEC: 920 /* many numbers are 1 digit */ 921 while (_umax >= 10) { 922 *--cp = to_char(_umax % 10); 923 _umax /= 10; 924 } 925 *--cp = to_char(_umax); 926 break; 927 928 case HEX: 929 do { 930 *--cp = xdigs[_umax & 15]; 931 _umax >>= 4; 932 } while (_umax); 933 break; 934 935 default: 936 cp = L"bug in vfwprintf: bad base"; 937 size = wcslen(cp); 938 goto skipsize; 939 } 940 } 941 size = buf + BUF - cp; 942 if (size > BUF) /* should never happen */ 943 abort(); 944 skipsize: 945 break; 946 default: /* "%?" prints ?, unless ? is NUL */ 947 if (ch == '\0') 948 goto done; 949 /* pretend it was %c with argument ch */ 950 cp = buf; 951 *cp = ch; 952 size = 1; 953 sign = '\0'; 954 break; 955 } 956 957 /* 958 * All reasonable formats wind up here. At this point, `cp' 959 * points to a string which (if not flags&LADJUST) should be 960 * padded out to `width' places. If flags&ZEROPAD, it should 961 * first be prefixed by any sign or other prefix; otherwise, 962 * it should be blank padded before the prefix is emitted. 963 * After any left-hand padding and prefixing, emit zeroes 964 * required by a decimal %[diouxX] precision, then print the 965 * string proper, then emit zeroes required by any leftover 966 * floating precision; finally, if LADJUST, pad with blanks. 967 * 968 * Compute actual size, so we know how much to pad. 969 * size excludes decimal prec; realsz includes it. 970 */ 971 realsz = dprec > size ? dprec : size; 972 if (sign) 973 realsz++; 974 if (ox[1]) 975 realsz+= 2; 976 977 /* right-adjusting blank padding */ 978 if ((flags & (LADJUST|ZEROPAD)) == 0) 979 PAD(width - realsz, blanks); 980 981 /* prefix */ 982 if (sign) 983 PRINT(&sign, 1); 984 if (ox[1]) { /* ox[1] is either x, X, or \0 */ 985 ox[0] = '0'; 986 PRINT(ox, 2); 987 } 988 989 /* right-adjusting zero padding */ 990 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) 991 PAD(width - realsz, zeroes); 992 993 /* leading zeroes from decimal precision */ 994 PAD(dprec - size, zeroes); 995 996 /* the string or number proper */ 997 #ifdef FLOATING_POINT 998 if ((flags & FPT) == 0) { 999 PRINT(cp, size); 1000 } else { /* glue together f_p fragments */ 1001 if (decimal_point == NULL) 1002 decimal_point = nl_langinfo(RADIXCHAR); 1003 if (!expchar) { /* %[fF] or sufficiently short %[gG] */ 1004 if (expt <= 0) { 1005 PRINT(zeroes, 1); 1006 if (prec || flags & ALT) 1007 PRINT(decimal_point, 1); 1008 PAD(-expt, zeroes); 1009 /* already handled initial 0's */ 1010 prec += expt; 1011 } else { 1012 PRINTANDPAD(cp, convbuf + ndig, 1013 lead, zeroes); 1014 cp += lead; 1015 if (prec || flags & ALT) 1016 PRINT(decimal_point, 1); 1017 } 1018 PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); 1019 } else { /* %[eE] or sufficiently long %[gG] */ 1020 if (prec > 1 || flags & ALT) { 1021 buf[0] = *cp++; 1022 buf[1] = *decimal_point; 1023 PRINT(buf, 2); 1024 PRINT(cp, ndig-1); 1025 PAD(prec - ndig, zeroes); 1026 } else { /* XeYYY */ 1027 PRINT(cp, 1); 1028 } 1029 PRINT(expstr, expsize); 1030 } 1031 } 1032 #else 1033 PRINT(cp, size); 1034 #endif 1035 /* left-adjusting padding (always blank) */ 1036 if (flags & LADJUST) 1037 PAD(width - realsz, blanks); 1038 1039 /* finally, adjust ret */ 1040 if (width < realsz) 1041 width = realsz; 1042 if (width > INT_MAX - ret) 1043 goto overflow; 1044 ret += width; 1045 } 1046 done: 1047 error: 1048 va_end(orgap); 1049 if (__sferror(fp)) 1050 ret = -1; 1051 goto finish; 1052 1053 overflow: 1054 errno = ENOMEM; 1055 ret = -1; 1056 1057 finish: 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 DEF_STRONG(vfwprintf); 1082 1083 /* 1084 * Type ids for argument type table. 1085 */ 1086 #define T_UNUSED 0 1087 #define T_SHORT 1 1088 #define T_U_SHORT 2 1089 #define TP_SHORT 3 1090 #define T_INT 4 1091 #define T_U_INT 5 1092 #define TP_INT 6 1093 #define T_LONG 7 1094 #define T_U_LONG 8 1095 #define TP_LONG 9 1096 #define T_LLONG 10 1097 #define T_U_LLONG 11 1098 #define TP_LLONG 12 1099 #define T_DOUBLE 13 1100 #define T_LONG_DOUBLE 14 1101 #define TP_CHAR 15 1102 #define TP_VOID 16 1103 #define T_PTRINT 17 1104 #define TP_PTRINT 18 1105 #define T_SIZEINT 19 1106 #define T_SSIZEINT 20 1107 #define TP_SSIZEINT 21 1108 #define T_MAXINT 22 1109 #define T_MAXUINT 23 1110 #define TP_MAXINT 24 1111 #define T_CHAR 25 1112 #define T_U_CHAR 26 1113 #define T_WINT 27 1114 #define TP_WCHAR 28 1115 1116 /* 1117 * Find all arguments when a positional parameter is encountered. Returns a 1118 * table, indexed by argument number, of pointers to each arguments. The 1119 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 1120 * It will be replaced with a mmap-ed one if it overflows (malloc cannot be 1121 * used since we are attempting to make snprintf thread safe, and alloca is 1122 * problematic since we have nested functions..) 1123 */ 1124 static int 1125 __find_arguments(const wchar_t *fmt0, va_list ap, union arg **argtable, 1126 size_t *argtablesiz) 1127 { 1128 wchar_t *fmt; /* format string */ 1129 int ch; /* character from fmt */ 1130 int n, n2; /* handy integer (short term usage) */ 1131 wchar_t *cp; /* handy char pointer (short term usage) */ 1132 int flags; /* flags as above */ 1133 unsigned char *typetable; /* table of types */ 1134 unsigned char stattypetable[STATIC_ARG_TBL_SIZE]; 1135 int tablesize; /* current size of type table */ 1136 int tablemax; /* largest used index in table */ 1137 int nextarg; /* 1-based argument index */ 1138 int ret = 0; /* return value */ 1139 1140 /* 1141 * Add an argument type to the table, expanding if necessary. 1142 */ 1143 #define ADDTYPE(type) \ 1144 ((nextarg >= tablesize) ? \ 1145 __grow_type_table(&typetable, &tablesize) : 0, \ 1146 (nextarg > tablemax) ? tablemax = nextarg : 0, \ 1147 typetable[nextarg++] = type) 1148 1149 #define ADDSARG() \ 1150 ((flags&MAXINT) ? ADDTYPE(T_MAXINT) : \ 1151 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \ 1152 ((flags&SIZEINT) ? ADDTYPE(T_SSIZEINT) : \ 1153 ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ 1154 ((flags&LONGINT) ? ADDTYPE(T_LONG) : \ 1155 ((flags&SHORTINT) ? ADDTYPE(T_SHORT) : \ 1156 ((flags&CHARINT) ? ADDTYPE(T_CHAR) : ADDTYPE(T_INT)))))))) 1157 1158 #define ADDUARG() \ 1159 ((flags&MAXINT) ? ADDTYPE(T_MAXUINT) : \ 1160 ((flags&PTRINT) ? ADDTYPE(T_PTRINT) : \ 1161 ((flags&SIZEINT) ? ADDTYPE(T_SIZEINT) : \ 1162 ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ 1163 ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : \ 1164 ((flags&SHORTINT) ? ADDTYPE(T_U_SHORT) : \ 1165 ((flags&CHARINT) ? ADDTYPE(T_U_CHAR) : ADDTYPE(T_U_INT)))))))) 1166 1167 /* 1168 * Add * arguments to the type array. 1169 */ 1170 #define ADDASTER() \ 1171 n2 = 0; \ 1172 cp = fmt; \ 1173 while (is_digit(*cp)) { \ 1174 APPEND_DIGIT(n2, *cp); \ 1175 cp++; \ 1176 } \ 1177 if (*cp == '$') { \ 1178 int hold = nextarg; \ 1179 nextarg = n2; \ 1180 ADDTYPE(T_INT); \ 1181 nextarg = hold; \ 1182 fmt = ++cp; \ 1183 } else { \ 1184 ADDTYPE(T_INT); \ 1185 } 1186 fmt = (wchar_t *)fmt0; 1187 typetable = stattypetable; 1188 tablesize = STATIC_ARG_TBL_SIZE; 1189 tablemax = 0; 1190 nextarg = 1; 1191 memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 1192 1193 /* 1194 * Scan the format for conversions (`%' character). 1195 */ 1196 for (;;) { 1197 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) 1198 continue; 1199 if (ch == '\0') 1200 goto done; 1201 fmt++; /* skip over '%' */ 1202 1203 flags = 0; 1204 1205 rflag: ch = *fmt++; 1206 reswitch: switch (ch) { 1207 case ' ': 1208 case '#': 1209 case '\'': 1210 goto rflag; 1211 case '*': 1212 ADDASTER(); 1213 goto rflag; 1214 case '-': 1215 case '+': 1216 goto rflag; 1217 case '.': 1218 if ((ch = *fmt++) == '*') { 1219 ADDASTER(); 1220 goto rflag; 1221 } 1222 while (is_digit(ch)) { 1223 ch = *fmt++; 1224 } 1225 goto reswitch; 1226 case '0': 1227 goto rflag; 1228 case '1': case '2': case '3': case '4': 1229 case '5': case '6': case '7': case '8': case '9': 1230 n = 0; 1231 do { 1232 APPEND_DIGIT(n ,ch); 1233 ch = *fmt++; 1234 } while (is_digit(ch)); 1235 if (ch == '$') { 1236 nextarg = n; 1237 goto rflag; 1238 } 1239 goto reswitch; 1240 #ifdef FLOATING_POINT 1241 case 'L': 1242 flags |= LONGDBL; 1243 goto rflag; 1244 #endif 1245 case 'h': 1246 if (*fmt == 'h') { 1247 fmt++; 1248 flags |= CHARINT; 1249 } else { 1250 flags |= SHORTINT; 1251 } 1252 goto rflag; 1253 case 'l': 1254 if (*fmt == 'l') { 1255 fmt++; 1256 flags |= LLONGINT; 1257 } else { 1258 flags |= LONGINT; 1259 } 1260 goto rflag; 1261 case 'q': 1262 flags |= LLONGINT; 1263 goto rflag; 1264 case 't': 1265 flags |= PTRINT; 1266 goto rflag; 1267 case 'z': 1268 flags |= SIZEINT; 1269 goto rflag; 1270 case 'C': 1271 flags |= LONGINT; 1272 /*FALLTHROUGH*/ 1273 case 'c': 1274 if (flags & LONGINT) 1275 ADDTYPE(T_WINT); 1276 else 1277 ADDTYPE(T_INT); 1278 break; 1279 case 'D': 1280 flags |= LONGINT; 1281 /*FALLTHROUGH*/ 1282 case 'd': 1283 case 'i': 1284 ADDSARG(); 1285 break; 1286 #ifdef FLOATING_POINT 1287 case 'a': 1288 case 'A': 1289 case 'e': 1290 case 'E': 1291 case 'f': 1292 case 'F': 1293 case 'g': 1294 case 'G': 1295 if (flags & LONGDBL) 1296 ADDTYPE(T_LONG_DOUBLE); 1297 else 1298 ADDTYPE(T_DOUBLE); 1299 break; 1300 #endif /* FLOATING_POINT */ 1301 #ifndef NO_PRINTF_PERCENT_N 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 #endif /* NO_PRINTF_PERCENT_N */ 1319 case 'O': 1320 flags |= LONGINT; 1321 /*FALLTHROUGH*/ 1322 case 'o': 1323 ADDUARG(); 1324 break; 1325 case 'p': 1326 ADDTYPE(TP_VOID); 1327 break; 1328 case 'S': 1329 flags |= LONGINT; 1330 /*FALLTHROUGH*/ 1331 case 's': 1332 if (flags & LONGINT) 1333 ADDTYPE(TP_CHAR); 1334 else 1335 ADDTYPE(TP_WCHAR); 1336 break; 1337 case 'U': 1338 flags |= LONGINT; 1339 /*FALLTHROUGH*/ 1340 case 'u': 1341 case 'X': 1342 case 'x': 1343 ADDUARG(); 1344 break; 1345 default: /* "%?" prints ?, unless ? is NUL */ 1346 if (ch == '\0') 1347 goto done; 1348 break; 1349 } 1350 } 1351 done: 1352 /* 1353 * Build the argument table. 1354 */ 1355 if (tablemax >= STATIC_ARG_TBL_SIZE) { 1356 *argtablesiz = sizeof(union arg) * (tablemax + 1); 1357 *argtable = mmap(NULL, *argtablesiz, 1358 PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0); 1359 if (*argtable == MAP_FAILED) 1360 return (-1); 1361 } 1362 1363 #if 0 1364 /* XXX is this required? */ 1365 (*argtable)[0].intarg = 0; 1366 #endif 1367 for (n = 1; n <= tablemax; n++) { 1368 switch (typetable[n]) { 1369 case T_UNUSED: 1370 case T_CHAR: 1371 case T_U_CHAR: 1372 case T_SHORT: 1373 case T_U_SHORT: 1374 case T_INT: 1375 (*argtable)[n].intarg = va_arg(ap, int); 1376 break; 1377 case TP_SHORT: 1378 (*argtable)[n].pshortarg = va_arg(ap, short *); 1379 break; 1380 case T_U_INT: 1381 (*argtable)[n].uintarg = va_arg(ap, unsigned int); 1382 break; 1383 case TP_INT: 1384 (*argtable)[n].pintarg = va_arg(ap, int *); 1385 break; 1386 case T_LONG: 1387 (*argtable)[n].longarg = va_arg(ap, long); 1388 break; 1389 case T_U_LONG: 1390 (*argtable)[n].ulongarg = va_arg(ap, unsigned long); 1391 break; 1392 case TP_LONG: 1393 (*argtable)[n].plongarg = va_arg(ap, long *); 1394 break; 1395 case T_LLONG: 1396 (*argtable)[n].longlongarg = va_arg(ap, long long); 1397 break; 1398 case T_U_LLONG: 1399 (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long); 1400 break; 1401 case TP_LLONG: 1402 (*argtable)[n].plonglongarg = va_arg(ap, long long *); 1403 break; 1404 #ifdef FLOATING_POINT 1405 case T_DOUBLE: 1406 (*argtable)[n].doublearg = va_arg(ap, double); 1407 break; 1408 case T_LONG_DOUBLE: 1409 (*argtable)[n].longdoublearg = va_arg(ap, long double); 1410 break; 1411 #endif 1412 case TP_CHAR: 1413 (*argtable)[n].pchararg = va_arg(ap, char *); 1414 break; 1415 case TP_VOID: 1416 (*argtable)[n].pvoidarg = va_arg(ap, void *); 1417 break; 1418 case T_PTRINT: 1419 (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t); 1420 break; 1421 case TP_PTRINT: 1422 (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *); 1423 break; 1424 case T_SIZEINT: 1425 (*argtable)[n].sizearg = va_arg(ap, size_t); 1426 break; 1427 case T_SSIZEINT: 1428 (*argtable)[n].ssizearg = va_arg(ap, ssize_t); 1429 break; 1430 case TP_SSIZEINT: 1431 (*argtable)[n].pssizearg = va_arg(ap, ssize_t *); 1432 break; 1433 case TP_MAXINT: 1434 (*argtable)[n].intmaxarg = va_arg(ap, intmax_t); 1435 break; 1436 case T_WINT: 1437 (*argtable)[n].wintarg = va_arg(ap, wint_t); 1438 break; 1439 case TP_WCHAR: 1440 (*argtable)[n].pwchararg = va_arg(ap, wchar_t *); 1441 break; 1442 } 1443 } 1444 goto finish; 1445 1446 overflow: 1447 errno = ENOMEM; 1448 ret = -1; 1449 1450 finish: 1451 if (typetable != NULL && typetable != stattypetable) { 1452 munmap(typetable, *argtablesiz); 1453 typetable = NULL; 1454 } 1455 return (ret); 1456 } 1457 1458 /* 1459 * Increase the size of the type table. 1460 */ 1461 static int 1462 __grow_type_table(unsigned char **typetable, int *tablesize) 1463 { 1464 unsigned char *oldtable = *typetable; 1465 int newsize = *tablesize * 2; 1466 1467 if (newsize < getpagesize()) 1468 newsize = getpagesize(); 1469 1470 if (*tablesize == STATIC_ARG_TBL_SIZE) { 1471 *typetable = mmap(NULL, newsize, PROT_WRITE|PROT_READ, 1472 MAP_ANON|MAP_PRIVATE, -1, 0); 1473 if (*typetable == MAP_FAILED) 1474 return (-1); 1475 bcopy(oldtable, *typetable, *tablesize); 1476 } else { 1477 unsigned char *new = mmap(NULL, newsize, PROT_WRITE|PROT_READ, 1478 MAP_ANON|MAP_PRIVATE, -1, 0); 1479 if (new == MAP_FAILED) 1480 return (-1); 1481 memmove(new, *typetable, *tablesize); 1482 munmap(*typetable, *tablesize); 1483 *typetable = new; 1484 } 1485 memset(*typetable + *tablesize, T_UNUSED, (newsize - *tablesize)); 1486 1487 *tablesize = newsize; 1488 return (0); 1489 } 1490 1491 1492 #ifdef FLOATING_POINT 1493 static int 1494 exponent(wchar_t *p0, int exp, int fmtch) 1495 { 1496 wchar_t *p, *t; 1497 wchar_t expbuf[MAXEXPDIG]; 1498 1499 p = p0; 1500 *p++ = fmtch; 1501 if (exp < 0) { 1502 exp = -exp; 1503 *p++ = '-'; 1504 } else 1505 *p++ = '+'; 1506 t = expbuf + MAXEXPDIG; 1507 if (exp > 9) { 1508 do { 1509 *--t = to_char(exp % 10); 1510 } while ((exp /= 10) > 9); 1511 *--t = to_char(exp); 1512 for (; t < expbuf + MAXEXPDIG; *p++ = *t++) 1513 /* nothing */; 1514 } else { 1515 /* 1516 * Exponents for decimal floating point conversions 1517 * (%[eEgG]) must be at least two characters long, 1518 * whereas exponents for hexadecimal conversions can 1519 * be only one character long. 1520 */ 1521 if (fmtch == 'e' || fmtch == 'E') 1522 *p++ = '0'; 1523 *p++ = to_char(exp); 1524 } 1525 return (p - p0); 1526 } 1527 #endif /* FLOATING_POINT */ 1528