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