1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/mman.h> 34 #include <sys/types.h> 35 36 #include <errno.h> 37 #include <float.h> 38 #include <langinfo.h> 39 #include <limits.h> 40 #include <locale.h> 41 #include <math.h> 42 #include <stdarg.h> 43 #include <stddef.h> 44 #include <stdint.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <wchar.h> 50 51 #include "fvwrite.h" 52 #include "gdtoa.h" 53 #include "local.h" 54 55 union arg { 56 int intarg; 57 unsigned int uintarg; 58 long longarg; 59 unsigned long ulongarg; 60 long long longlongarg; 61 unsigned long long ulonglongarg; 62 ptrdiff_t ptrdiffarg; 63 size_t sizearg; 64 ssize_t ssizearg; 65 intmax_t intmaxarg; 66 uintmax_t uintmaxarg; 67 void* pvoidarg; 68 char* pchararg; 69 signed char* pschararg; 70 short* pshortarg; 71 int* pintarg; 72 long* plongarg; 73 long long* plonglongarg; 74 ptrdiff_t* pptrdiffarg; 75 ssize_t* pssizearg; 76 intmax_t* pintmaxarg; 77 double doublearg; 78 long double longdoublearg; 79 wint_t wintarg; 80 wchar_t* pwchararg; 81 }; 82 83 // Helper function for `fprintf to unbuffered unix file': creates a 84 // temporary buffer. We only work on write-only files; this avoids 85 // worries about ungetc buffers and so forth. 86 static int __sbprintf(FILE* fp, const CHAR_TYPE* fmt, va_list ap) { 87 FILE fake; 88 struct __sfileext fakeext; 89 unsigned char buf[BUFSIZ]; 90 91 _FILEEXT_SETUP(&fake, &fakeext); 92 /* copy the important variables */ 93 fake._flags = fp->_flags & ~__SNBF; 94 fake._file = fp->_file; 95 fake._cookie = fp->_cookie; 96 fake._write = fp->_write; 97 98 /* set up the buffer */ 99 fake._bf._base = fake._p = buf; 100 fake._bf._size = fake._w = sizeof(buf); 101 fake._lbfsize = 0; /* not actually used, but Just In Case */ 102 103 /* do the work, then copy any error status */ 104 int ret = FUNCTION_NAME(&fake, fmt, ap); 105 if (ret >= 0 && __sflush(&fake)) ret = EOF; 106 if (fake._flags & __SERR) fp->_flags |= __SERR; 107 return ret; 108 } 109 110 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable, size_t* argtablesiz); 111 static int __grow_type_table(unsigned char** typetable, int* tablesize); 112 113 #define DEFPREC 6 114 115 #define to_digit(c) ((c) - '0') 116 #define is_digit(c) ((unsigned)to_digit(c) <= 9) 117 #define to_char(n) ((CHAR_TYPE)((n) + '0')) 118 119 template <typename CharT> 120 static int exponent(CharT* p0, int exp, int fmtch) { 121 CharT* p = p0; 122 *p++ = fmtch; 123 if (exp < 0) { 124 exp = -exp; 125 *p++ = '-'; 126 } else { 127 *p++ = '+'; 128 } 129 130 CharT expbuf[MAXEXPDIG]; 131 CharT* t = expbuf + MAXEXPDIG; 132 if (exp > 9) { 133 do { 134 *--t = to_char(exp % 10); 135 } while ((exp /= 10) > 9); 136 *--t = to_char(exp); 137 for (; t < expbuf + MAXEXPDIG; *p++ = *t++) /* nothing */; 138 } else { 139 /* 140 * Exponents for decimal floating point conversions 141 * (%[eEgG]) must be at least two characters long, 142 * whereas exponents for hexadecimal conversions can 143 * be only one character long. 144 */ 145 if (fmtch == 'e' || fmtch == 'E') *p++ = '0'; 146 *p++ = to_char(exp); 147 } 148 return (p - p0); 149 } 150 151 #define PAD(howmany, with) \ 152 do { \ 153 if ((n = (howmany)) > 0) { \ 154 while (n > PADSIZE) { \ 155 PRINT(with, PADSIZE); \ 156 n -= PADSIZE; \ 157 } \ 158 PRINT(with, n); \ 159 } \ 160 } while (0) 161 162 #define PRINTANDPAD(p, ep, len, with) \ 163 do { \ 164 n2 = (ep) - (p); \ 165 if (n2 > (len)) n2 = (len); \ 166 if (n2 > 0) PRINT((p), n2); \ 167 PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ 168 } while (0) 169 170 /* 171 * The size of the buffer we use as scratch space for integer 172 * conversions, among other things. Technically, we would need the 173 * most space for base 10 conversions with thousands' grouping 174 * characters between each pair of digits. 100 bytes is a 175 * conservative overestimate even for a 128-bit uintmax_t. 176 */ 177 #define BUF 100 178 179 #define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ 180 181 /* 182 * Flags used during conversion. 183 */ 184 #define ALT 0x0001 /* alternate form */ 185 #define LADJUST 0x0004 /* left adjustment */ 186 #define LONGDBL 0x0008 /* long double */ 187 #define LONGINT 0x0010 /* long integer */ 188 #define LLONGINT 0x0020 /* long long integer */ 189 #define SHORTINT 0x0040 /* short integer */ 190 #define ZEROPAD 0x0080 /* zero (as opposed to blank) pad */ 191 #define FPT 0x0100 /* Floating point number */ 192 #define PTRINT 0x0200 /* (unsigned) ptrdiff_t */ 193 #define SIZEINT 0x0400 /* (signed) size_t */ 194 #define CHARINT 0x0800 /* 8 bit integer */ 195 #define MAXINT 0x1000 /* largest integer size (intmax_t) */ 196 197 /* 198 * Type ids for argument type table. 199 */ 200 #define T_UNUSED 0 201 #define T_SHORT 1 202 #define T_U_SHORT 2 203 #define TP_SHORT 3 204 #define T_INT 4 205 #define T_U_INT 5 206 #define TP_INT 6 207 #define T_LONG 7 208 #define T_U_LONG 8 209 #define TP_LONG 9 210 #define T_LLONG 10 211 #define T_U_LLONG 11 212 #define TP_LLONG 12 213 #define T_DOUBLE 13 214 #define T_LONG_DOUBLE 14 215 #define TP_CHAR 15 216 #define TP_VOID 16 217 #define T_PTRINT 17 218 #define TP_PTRINT 18 219 #define T_SIZEINT 19 220 #define T_SSIZEINT 20 221 #define TP_SSIZEINT 21 222 #define T_MAXINT 22 223 #define T_MAXUINT 23 224 #define TP_MAXINT 24 225 #define T_CHAR 25 226 #define T_U_CHAR 26 227 #define T_WINT 27 228 #define TP_WCHAR 28 229 230 // To extend shorts properly, we need both signed and unsigned 231 // argument extraction methods. 232 #define SARG() \ 233 ((intmax_t)(flags & MAXINT \ 234 ? GETARG(intmax_t) \ 235 : flags & LLONGINT \ 236 ? GETARG(long long) \ 237 : flags & LONGINT \ 238 ? GETARG(long) \ 239 : flags & PTRINT \ 240 ? GETARG(ptrdiff_t) \ 241 : flags & SIZEINT \ 242 ? GETARG(ssize_t) \ 243 : flags & SHORTINT \ 244 ? (short)GETARG(int) \ 245 : flags & CHARINT ? (signed char)GETARG(int) \ 246 : GETARG(int))) 247 #define UARG() \ 248 ((uintmax_t)(flags & MAXINT \ 249 ? GETARG(uintmax_t) \ 250 : flags & LLONGINT \ 251 ? GETARG(unsigned long long) \ 252 : flags & LONGINT \ 253 ? GETARG(unsigned long) \ 254 : flags & PTRINT ? (uintptr_t)GETARG(ptrdiff_t) : /* XXX */ \ 255 flags & SIZEINT \ 256 ? GETARG(size_t) \ 257 : flags & SHORTINT \ 258 ? (unsigned short)GETARG(int) \ 259 : flags & CHARINT ? (unsigned char)GETARG(int) \ 260 : GETARG(unsigned int))) 261 262 // Append a digit to a value and check for overflow. 263 #define APPEND_DIGIT(val, dig) \ 264 do { \ 265 if ((val) > INT_MAX / 10) goto overflow; \ 266 (val) *= 10; \ 267 if ((val) > INT_MAX - to_digit((dig))) goto overflow; \ 268 (val) += to_digit((dig)); \ 269 } while (0) 270 271 // Get * arguments, including the form *nn$. Preserve the nextarg 272 // that the argument can be gotten once the type is determined. 273 #define GETASTER(val) \ 274 n2 = 0; \ 275 cp = fmt; \ 276 while (is_digit(*cp)) { \ 277 APPEND_DIGIT(n2, *cp); \ 278 cp++; \ 279 } \ 280 if (*cp == '$') { \ 281 int hold = nextarg; \ 282 if (argtable == NULL) { \ 283 argtable = statargtable; \ 284 if (__find_arguments(fmt0, orgap, &argtable, &argtablesiz) == -1) { \ 285 ret = -1; \ 286 goto error; \ 287 } \ 288 } \ 289 nextarg = n2; \ 290 val = GETARG(int); \ 291 nextarg = hold; \ 292 fmt = ++cp; \ 293 } else { \ 294 val = GETARG(int); \ 295 } 296 297 // Get the argument indexed by nextarg. If the argument table is 298 // built, use it to get the argument. If its not, get the next 299 // argument (and arguments must be gotten sequentially). 300 #define GETARG(type) \ 301 ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : (nextarg++, va_arg(ap, type))) 302 303 /* 304 * Find all arguments when a positional parameter is encountered. Returns a 305 * table, indexed by argument number, of pointers to each arguments. The 306 * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. 307 * It will be replaced with a mmap-ed one if it overflows (malloc cannot be 308 * used since we are attempting to make snprintf thread safe, and alloca is 309 * problematic since we have nested functions..) 310 */ 311 static int __find_arguments(const CHAR_TYPE* fmt0, va_list ap, union arg** argtable, 312 size_t* argtablesiz) { 313 int ch; /* character from fmt */ 314 int n, n2; /* handy integer (short term usage) */ 315 int flags; /* flags as above */ 316 unsigned char* typetable; /* table of types */ 317 unsigned char stattypetable[STATIC_ARG_TBL_SIZE]; 318 int tablesize; /* current size of type table */ 319 int tablemax; /* largest used index in table */ 320 int nextarg; /* 1-based argument index */ 321 int ret = 0; /* return value */ 322 323 /* 324 * Add an argument type to the table, expanding if necessary. 325 */ 326 #define ADDTYPE(type) \ 327 ((nextarg >= tablesize) ? __grow_type_table(&typetable, &tablesize) : 0, \ 328 (nextarg > tablemax) ? tablemax = nextarg : 0, typetable[nextarg++] = type) 329 330 #define ADDSARG() \ 331 ((flags & MAXINT) \ 332 ? ADDTYPE(T_MAXINT) \ 333 : ((flags & PTRINT) ? ADDTYPE(T_PTRINT) \ 334 : ((flags & SIZEINT) \ 335 ? ADDTYPE(T_SSIZEINT) \ 336 : ((flags & LLONGINT) \ 337 ? ADDTYPE(T_LLONG) \ 338 : ((flags & LONGINT) \ 339 ? ADDTYPE(T_LONG) \ 340 : ((flags & SHORTINT) \ 341 ? ADDTYPE(T_SHORT) \ 342 : ((flags & CHARINT) ? ADDTYPE(T_CHAR) \ 343 : ADDTYPE(T_INT)))))))) 344 345 #define ADDUARG() \ 346 ((flags & MAXINT) \ 347 ? ADDTYPE(T_MAXUINT) \ 348 : ((flags & PTRINT) \ 349 ? ADDTYPE(T_PTRINT) \ 350 : ((flags & SIZEINT) \ 351 ? ADDTYPE(T_SIZEINT) \ 352 : ((flags & LLONGINT) \ 353 ? ADDTYPE(T_U_LLONG) \ 354 : ((flags & LONGINT) \ 355 ? ADDTYPE(T_U_LONG) \ 356 : ((flags & SHORTINT) \ 357 ? ADDTYPE(T_U_SHORT) \ 358 : ((flags & CHARINT) ? ADDTYPE(T_U_CHAR) \ 359 : ADDTYPE(T_U_INT)))))))) 360 361 /* 362 * Add * arguments to the type array. 363 */ 364 #define ADDASTER() \ 365 n2 = 0; \ 366 cp = fmt; \ 367 while (is_digit(*cp)) { \ 368 APPEND_DIGIT(n2, *cp); \ 369 cp++; \ 370 } \ 371 if (*cp == '$') { \ 372 int hold = nextarg; \ 373 nextarg = n2; \ 374 ADDTYPE(T_INT); \ 375 nextarg = hold; \ 376 fmt = ++cp; \ 377 } else { \ 378 ADDTYPE(T_INT); \ 379 } 380 CHAR_TYPE* fmt = const_cast<CHAR_TYPE*>(fmt0); 381 CHAR_TYPE* cp; 382 typetable = stattypetable; 383 tablesize = STATIC_ARG_TBL_SIZE; 384 tablemax = 0; 385 nextarg = 1; 386 memset(typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); 387 388 /* 389 * Scan the format for conversions (`%' character). 390 */ 391 for (;;) { 392 for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) continue; 393 if (ch == '\0') goto done; 394 fmt++; /* skip over '%' */ 395 396 flags = 0; 397 398 rflag: 399 ch = *fmt++; 400 reswitch: 401 switch (ch) { 402 case ' ': 403 case '#': 404 case '\'': 405 goto rflag; 406 case '*': 407 ADDASTER(); 408 goto rflag; 409 case '-': 410 case '+': 411 goto rflag; 412 case '.': 413 if ((ch = *fmt++) == '*') { 414 ADDASTER(); 415 goto rflag; 416 } 417 while (is_digit(ch)) { 418 ch = *fmt++; 419 } 420 goto reswitch; 421 case '0': 422 goto rflag; 423 case '1': 424 case '2': 425 case '3': 426 case '4': 427 case '5': 428 case '6': 429 case '7': 430 case '8': 431 case '9': 432 n = 0; 433 do { 434 APPEND_DIGIT(n, ch); 435 ch = *fmt++; 436 } while (is_digit(ch)); 437 if (ch == '$') { 438 nextarg = n; 439 goto rflag; 440 } 441 goto reswitch; 442 case 'L': 443 flags |= LONGDBL; 444 goto rflag; 445 case 'h': 446 if (*fmt == 'h') { 447 fmt++; 448 flags |= CHARINT; 449 } else { 450 flags |= SHORTINT; 451 } 452 goto rflag; 453 case 'j': 454 flags |= MAXINT; 455 goto rflag; 456 case 'l': 457 if (*fmt == 'l') { 458 fmt++; 459 flags |= LLONGINT; 460 } else { 461 flags |= LONGINT; 462 } 463 goto rflag; 464 case 'q': 465 flags |= LLONGINT; 466 goto rflag; 467 case 't': 468 flags |= PTRINT; 469 goto rflag; 470 case 'z': 471 flags |= SIZEINT; 472 goto rflag; 473 case 'C': 474 flags |= LONGINT; 475 /*FALLTHROUGH*/ 476 case 'c': 477 if (flags & LONGINT) 478 ADDTYPE(T_WINT); 479 else 480 ADDTYPE(T_INT); 481 break; 482 case 'D': 483 flags |= LONGINT; 484 /*FALLTHROUGH*/ 485 case 'd': 486 case 'i': 487 ADDSARG(); 488 break; 489 case 'a': 490 case 'A': 491 case 'e': 492 case 'E': 493 case 'f': 494 case 'F': 495 case 'g': 496 case 'G': 497 if (flags & LONGDBL) 498 ADDTYPE(T_LONG_DOUBLE); 499 else 500 ADDTYPE(T_DOUBLE); 501 break; 502 #ifndef NO_PRINTF_PERCENT_N 503 case 'n': 504 if (flags & LLONGINT) 505 ADDTYPE(TP_LLONG); 506 else if (flags & LONGINT) 507 ADDTYPE(TP_LONG); 508 else if (flags & SHORTINT) 509 ADDTYPE(TP_SHORT); 510 else if (flags & PTRINT) 511 ADDTYPE(TP_PTRINT); 512 else if (flags & SIZEINT) 513 ADDTYPE(TP_SSIZEINT); 514 else if (flags & MAXINT) 515 ADDTYPE(TP_MAXINT); 516 else 517 ADDTYPE(TP_INT); 518 continue; /* no output */ 519 #endif /* NO_PRINTF_PERCENT_N */ 520 case 'O': 521 flags |= LONGINT; 522 /*FALLTHROUGH*/ 523 case 'o': 524 ADDUARG(); 525 break; 526 case 'p': 527 ADDTYPE(TP_VOID); 528 break; 529 case 'S': 530 flags |= LONGINT; 531 /*FALLTHROUGH*/ 532 case 's': 533 ADDTYPE((flags & LONGINT) ? TP_WCHAR : TP_CHAR); 534 break; 535 case 'U': 536 flags |= LONGINT; 537 /*FALLTHROUGH*/ 538 case 'u': 539 case 'X': 540 case 'x': 541 ADDUARG(); 542 break; 543 default: /* "%?" prints ?, unless ? is NUL */ 544 if (ch == '\0') goto done; 545 break; 546 } 547 } 548 done: 549 /* 550 * Build the argument table. 551 */ 552 if (tablemax >= STATIC_ARG_TBL_SIZE) { 553 *argtablesiz = sizeof(union arg) * (tablemax + 1); 554 *argtable = static_cast<arg*>(mmap(NULL, *argtablesiz, 555 PROT_WRITE | PROT_READ, 556 MAP_ANON | MAP_PRIVATE, -1, 0)); 557 if (*argtable == MAP_FAILED) return -1; 558 } 559 560 for (n = 1; n <= tablemax; n++) { 561 switch (typetable[n]) { 562 case T_UNUSED: 563 case T_CHAR: 564 case T_U_CHAR: 565 case T_SHORT: 566 case T_U_SHORT: 567 case T_INT: 568 (*argtable)[n].intarg = va_arg(ap, int); 569 break; 570 case TP_SHORT: 571 (*argtable)[n].pshortarg = va_arg(ap, short*); 572 break; 573 case T_U_INT: 574 (*argtable)[n].uintarg = va_arg(ap, unsigned int); 575 break; 576 case TP_INT: 577 (*argtable)[n].pintarg = va_arg(ap, int*); 578 break; 579 case T_LONG: 580 (*argtable)[n].longarg = va_arg(ap, long); 581 break; 582 case T_U_LONG: 583 (*argtable)[n].ulongarg = va_arg(ap, unsigned long); 584 break; 585 case TP_LONG: 586 (*argtable)[n].plongarg = va_arg(ap, long*); 587 break; 588 case T_LLONG: 589 (*argtable)[n].longlongarg = va_arg(ap, long long); 590 break; 591 case T_U_LLONG: 592 (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long); 593 break; 594 case TP_LLONG: 595 (*argtable)[n].plonglongarg = va_arg(ap, long long*); 596 break; 597 case T_DOUBLE: 598 (*argtable)[n].doublearg = va_arg(ap, double); 599 break; 600 case T_LONG_DOUBLE: 601 (*argtable)[n].longdoublearg = va_arg(ap, long double); 602 break; 603 case TP_CHAR: 604 (*argtable)[n].pchararg = va_arg(ap, char*); 605 break; 606 case TP_VOID: 607 (*argtable)[n].pvoidarg = va_arg(ap, void*); 608 break; 609 case T_PTRINT: 610 (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t); 611 break; 612 case TP_PTRINT: 613 (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t*); 614 break; 615 case T_SIZEINT: 616 (*argtable)[n].sizearg = va_arg(ap, size_t); 617 break; 618 case T_SSIZEINT: 619 (*argtable)[n].ssizearg = va_arg(ap, ssize_t); 620 break; 621 case TP_SSIZEINT: 622 (*argtable)[n].pssizearg = va_arg(ap, ssize_t*); 623 break; 624 case T_MAXINT: 625 (*argtable)[n].intmaxarg = va_arg(ap, intmax_t); 626 break; 627 case T_MAXUINT: 628 (*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t); 629 break; 630 case TP_MAXINT: 631 (*argtable)[n].pintmaxarg = va_arg(ap, intmax_t*); 632 break; 633 case T_WINT: 634 (*argtable)[n].wintarg = va_arg(ap, wint_t); 635 break; 636 case TP_WCHAR: 637 (*argtable)[n].pwchararg = va_arg(ap, wchar_t*); 638 break; 639 } 640 } 641 goto finish; 642 643 overflow: 644 errno = ENOMEM; 645 ret = -1; 646 647 finish: 648 if (typetable != NULL && typetable != stattypetable) { 649 munmap(typetable, *argtablesiz); 650 typetable = NULL; 651 } 652 return (ret); 653 } 654 655 /* 656 * Increase the size of the type table. 657 */ 658 static int __grow_type_table(unsigned char** typetable, int* tablesize) { 659 unsigned char* old_table = *typetable; 660 int new_size = *tablesize * 2; 661 662 if (new_size < getpagesize()) new_size = getpagesize(); 663 664 if (*tablesize == STATIC_ARG_TBL_SIZE) { 665 *typetable = static_cast<unsigned char*>(mmap(NULL, new_size, 666 PROT_WRITE | PROT_READ, 667 MAP_ANON | MAP_PRIVATE, -1, 0)); 668 if (*typetable == MAP_FAILED) return -1; 669 bcopy(old_table, *typetable, *tablesize); 670 } else { 671 unsigned char* new_table = static_cast<unsigned char*>(mmap(NULL, new_size, 672 PROT_WRITE | PROT_READ, 673 MAP_ANON | MAP_PRIVATE, -1, 0)); 674 if (new_table == MAP_FAILED) return -1; 675 memmove(new_table, *typetable, *tablesize); 676 munmap(*typetable, *tablesize); 677 *typetable = new_table; 678 } 679 memset(*typetable + *tablesize, T_UNUSED, (new_size - *tablesize)); 680 681 *tablesize = new_size; 682 return 0; 683 } 684 685 struct helpers { 686 // Flush out all the vectors defined by the given uio, 687 // then reset it so that it can be reused. 688 static int sprint(FILE* fp, struct __suio* uio) { 689 if (uio->uio_resid == 0) { 690 uio->uio_iovcnt = 0; 691 return 0; 692 } 693 int result = __sfvwrite(fp, uio); 694 uio->uio_resid = 0; 695 uio->uio_iovcnt = 0; 696 return result; 697 } 698 699 // Convert a wide character string argument for the %ls format to a multibyte 700 // string representation. If not -1, prec specifies the maximum number of 701 // bytes to output, and also means that we can't assume that the wide char 702 // string is null-terminated. 703 static char* wcsconv(wchar_t* wcsarg, int prec) { 704 mbstate_t mbs; 705 char buf[MB_LEN_MAX]; 706 wchar_t* p; 707 char* convbuf; 708 size_t clen, nbytes; 709 710 // Allocate space for the maximum number of bytes we could output. 711 if (prec < 0) { 712 memset(&mbs, 0, sizeof(mbs)); 713 p = wcsarg; 714 nbytes = wcsrtombs(NULL, (const wchar_t**)&p, 0, &mbs); 715 if (nbytes == (size_t)-1) return NULL; 716 } else { 717 // Optimisation: if the output precision is small enough, 718 // just allocate enough memory for the maximum instead of 719 // scanning the string. 720 if (prec < 128) { 721 nbytes = prec; 722 } else { 723 nbytes = 0; 724 p = wcsarg; 725 memset(&mbs, 0, sizeof(mbs)); 726 for (;;) { 727 clen = wcrtomb(buf, *p++, &mbs); 728 if (clen == 0 || clen == (size_t)-1 || nbytes + clen > (size_t)prec) break; 729 nbytes += clen; 730 } 731 if (clen == (size_t)-1) return NULL; 732 } 733 } 734 if ((convbuf = static_cast<char*>(malloc(nbytes + 1))) == NULL) return NULL; 735 736 // Fill the output buffer. 737 p = wcsarg; 738 memset(&mbs, 0, sizeof(mbs)); 739 if ((nbytes = wcsrtombs(convbuf, (const wchar_t**)&p, nbytes, &mbs)) == (size_t)-1) { 740 free(convbuf); 741 return NULL; 742 } 743 convbuf[nbytes] = '\0'; 744 return convbuf; 745 } 746 747 // Like __fputwc_unlock, but handles fake string (__SSTR) files properly. 748 // File must already be locked. 749 static wint_t xfputwc(wchar_t wc, FILE* fp) { 750 if ((fp->_flags & __SSTR) == 0) return __fputwc_unlock(wc, fp); 751 752 char buf[MB_LEN_MAX]; 753 mbstate_t mbs = {}; 754 size_t len = wcrtomb(buf, wc, &mbs); 755 if (len == (size_t)-1) { 756 fp->_flags |= __SERR; 757 errno = EILSEQ; 758 return WEOF; 759 } 760 761 struct __siov iov; 762 iov.iov_base = buf; 763 iov.iov_len = len; 764 struct __suio uio; 765 uio.uio_iov = &iov; 766 uio.uio_resid = len; 767 uio.uio_iovcnt = 1; 768 return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); 769 } 770 771 // Convert a multibyte character string argument for the %s format to a wide 772 // string representation. ``prec'' specifies the maximum number of bytes 773 // to output. If ``prec'' is greater than or equal to zero, we can't assume 774 // that the multibyte character string ends in a null character. 775 // 776 // Returns NULL on failure. 777 // To find out what happened check errno for ENOMEM, EILSEQ and EINVAL. 778 static wchar_t* mbsconv(char* mbsarg, int prec) { 779 mbstate_t mbs; 780 const char* p; 781 size_t insize, nchars, nconv; 782 783 if (mbsarg == NULL) return NULL; 784 785 // Supplied argument is a multibyte string; convert it to wide characters first. 786 if (prec >= 0) { 787 // String is not guaranteed to be NUL-terminated. Find the number of characters to print. 788 p = mbsarg; 789 insize = nchars = nconv = 0; 790 bzero(&mbs, sizeof(mbs)); 791 while (nchars != (size_t)prec) { 792 nconv = mbrlen(p, MB_CUR_MAX, &mbs); 793 if (nconv == (size_t)0 || nconv == (size_t)-1 || nconv == (size_t)-2) break; 794 p += nconv; 795 nchars++; 796 insize += nconv; 797 } 798 if (nconv == (size_t)-1 || nconv == (size_t)-2) return (NULL); 799 } else { 800 insize = strlen(mbsarg); 801 } 802 803 // Allocate buffer for the result and perform the conversion, 804 // converting at most `size' bytes of the input multibyte string to 805 // wide characters for printing. 806 wchar_t* convbuf = static_cast<wchar_t*>(calloc(insize + 1, sizeof(*convbuf))); 807 if (convbuf == NULL) return NULL; 808 wchar_t* wcp = convbuf; 809 p = mbsarg; 810 bzero(&mbs, sizeof(mbs)); 811 nconv = 0; 812 while (insize != 0) { 813 nconv = mbrtowc(wcp, p, insize, &mbs); 814 if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) break; 815 wcp++; 816 p += nconv; 817 insize -= nconv; 818 } 819 if (nconv == (size_t)-1 || nconv == (size_t)-2) { 820 free(convbuf); 821 return NULL; 822 } 823 *wcp = '\0'; 824 825 return convbuf; 826 } 827 828 }; 829