1/*- 2 * Copyright (c) 2005 Poul-Henning Kamp 3 * Copyright (c) 1990, 1993 4 * The Regents of the University of California. 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 * $FreeBSD: src/lib/libc/stdio/xprintf.c,v 1.9 2010/03/11 17:03:32 jhb Exp $ 34 */ 35 36#include "namespace.h" 37#include <err.h> 38#include <sys/types.h> 39#include <stdio.h> 40#include <stddef.h> 41#include <stdlib.h> 42#include <locale.h> 43#include <stdint.h> 44#include <assert.h> 45#include <stdarg.h> 46#include <namespace.h> 47#include <string.h> 48#include <wchar.h> 49#include <errno.h> 50#include "un-namespace.h" 51 52//#define MACHTIME 53#ifdef MACHTIME 54#include <mach/mach_time.h> 55#endif // MACHTIME 56 57#ifdef XPRINTF_PERF 58#include <libkern/OSAtomic.h> 59#endif /* XPRINTF_PERF */ 60 61#include "local.h" 62#include "xprintf_private.h" 63#include "xprintf_domain.h" 64#include "fvwrite.h" 65 66/* 67 * Defining XPRINTF_DEBUG allows the __private_extern__ variable __use_xprintf 68 * to be set so that regular printf variants will use the extensible printf 69 * code path. This is normally off, and is only used to test the extensible 70 * printf code in the conformance tests. 71 */ 72#ifdef XPRINTF_DEBUG 73#include <unistd.h> 74int __use_xprintf = 0; 75#endif 76 77/* private stuff -----------------------------------------------------*/ 78 79union arg { 80 int intarg; 81 long longarg; 82 intmax_t intmaxarg; 83#ifndef NO_FLOATING_POINT 84 double doublearg; 85 long double longdoublearg; 86#endif 87 wint_t wintarg; 88 char *pchararg; 89 wchar_t *pwchararg; 90 void *pvoidarg; 91#ifdef VECTORS 92 VECTORTYPE vectorarg; 93 unsigned char vuchararg[16]; 94 signed char vchararg[16]; 95 unsigned short vushortarg[8]; 96 signed short vshortarg[8]; 97 unsigned int vuintarg[4]; 98 signed int vintarg[4]; 99 float vfloatarg[4]; 100#ifdef V64TYPE 101 double vdoublearg[2]; 102 unsigned long long vulonglongarg[2]; 103 long long vlonglongarg[2]; 104#endif /* V64TYPE */ 105#endif /* VECTORS */ 106}; 107 108/* 109 * Macros for converting digits to letters and vice versa 110 */ 111#define to_digit(c) ((c) - '0') 112#define is_digit(c) (((unsigned)to_digit(c)) <= 9) 113 114/* various globals ---------------------------------------------------*/ 115 116__private_extern__ const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */ 117__private_extern__ const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */ 118 119#define PADSIZE 16 120static char blanks[PADSIZE] = 121 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 122static char zeroes[PADSIZE] = 123 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 124 125/* printing and padding functions ------------------------------------*/ 126 127#define NIOV 8 128 129struct __printf_io { 130 FILE *fp; 131 struct __suio uio; 132 struct __siov iov[NIOV]; 133 struct __siov *iovp; 134}; 135 136static void 137__printf_init(struct __printf_io *io) 138{ 139 140 io->uio.uio_iov = io->iovp = &io->iov[0]; 141 io->uio.uio_resid = 0; 142 io->uio.uio_iovcnt = 0; 143} 144 145__private_extern__ void 146__printf_flush(struct __printf_io *io) 147{ 148 149 __sfvwrite(io->fp, &io->uio); 150 __printf_init(io); 151} 152 153__private_extern__ int 154__printf_puts(struct __printf_io *io, const void *ptr, int len) 155{ 156 157 158#if 0 159 if (io->fp->_flags & __SERR) 160 return (0); 161#endif 162 if (len == 0) 163 return (0); 164 io->iovp->iov_base = __DECONST(void *, ptr); 165 io->iovp->iov_len = len; 166 io->uio.uio_resid += len; 167 io->iovp++; 168 io->uio.uio_iovcnt++; 169 if (io->uio.uio_iovcnt >= NIOV) 170 __printf_flush(io); 171 return (len); 172} 173 174__private_extern__ int 175__printf_pad(struct __printf_io *io, int howmany, int zero) 176{ 177 int n; 178 const char *with; 179 int ret = 0; 180 181 if (zero) 182 with = zeroes; 183 else 184 with = blanks; 185 186 if ((n = (howmany)) > 0) { 187 while (n > PADSIZE) { 188 ret += __printf_puts(io, with, PADSIZE); 189 n -= PADSIZE; 190 } 191 ret += __printf_puts(io, with, n); 192 } 193 return (ret); 194} 195 196__private_extern__ int 197__printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len) 198{ 199 int ret = 0; 200 201 if ((!pi->left) && pi->width > len) 202 ret += __printf_pad(io, pi->width - len, pi->pad == '0'); 203 ret += __printf_puts(io, ptr, len); 204 if (pi->left && pi->width > len) 205 ret += __printf_pad(io, pi->width - len, pi->pad == '0'); 206 return (ret); 207} 208 209 210/* percent handling -------------------------------------------------*/ 211 212__private_extern__ int 213__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused) 214{ 215 216 return (0); 217} 218 219__private_extern__ int 220__printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused) 221{ 222 223 return (__printf_puts(io, "%", 1)); 224} 225 226/* 'n' ---------------------------------------------------------------*/ 227 228__private_extern__ int 229__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt) 230{ 231 232 assert(n >= 1); 233 argt[0] = PA_POINTER; 234 return (1); 235} 236 237/* 238 * This is a printf_render so that all output has been flushed before it 239 * gets called. 240 */ 241 242__private_extern__ int 243__printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg) 244{ 245 246 if (pi->is_char) 247 **((signed char **)arg[0]) = (signed char)pi->sofar; 248 else if (pi->is_short) 249 **((short **)arg[0]) = (short)pi->sofar; 250 else if (pi->is_long) 251 **((long **)arg[0]) = pi->sofar; 252 else if (pi->is_long_double) 253 **((long long **)arg[0]) = pi->sofar; 254 else if (pi->is_intmax) 255 **((intmax_t **)arg[0]) = pi->sofar; 256 else if (pi->is_ptrdiff) 257 **((ptrdiff_t **)arg[0]) = pi->sofar; 258 else if (pi->is_quad) 259 **((quad_t **)arg[0]) = pi->sofar; 260 else if (pi->is_size) 261 **((size_t **)arg[0]) = pi->sofar; 262 else 263 **((int **)arg[0]) = pi->sofar; 264 265 return (0); 266} 267 268/* dynamic array handling -------------------------------------------------*/ 269#define ARRAYDELTA 8 270 271struct array { 272#ifdef XPRINTF_PERF 273 struct array *next; 274#endif /* XPRINTF_PERF */ 275 void *data; 276 int itemsize; 277 int max; 278}; 279 280#ifdef XPRINTF_PERF 281__private_extern__ 282#else /* !XPRINTF_PERF */ 283static 284#endif /* !XPRINTF_PERF */ 285void 286arrayfree(struct array *a) 287{ 288 if(a) free(a->data); 289} 290 291static void * 292arrayget(struct array *a, int i) 293{ 294 if (i >= a->max) { 295 int oldsize = a->max * a->itemsize; 296 int newmax = i + ARRAYDELTA; 297 int newsize = newmax * a->itemsize; 298 void *newdata = realloc(a->data, newsize); 299 if(!newdata) return NULL; 300 bzero(newdata + oldsize, newsize - oldsize); 301 a->data = newdata; 302 a->max = newmax; 303 } 304 return a->data + i * a->itemsize; 305} 306 307static struct array * 308arrayinit(struct array *a, int itemsize) 309{ 310 a->data = CALLOC(ARRAYDELTA, itemsize); 311 if(!a->data) return NULL; 312 a->itemsize = itemsize; 313 a->max = ARRAYDELTA; 314 return a; 315} 316 317/* dynamic array caching -------------------------------------------------*/ 318/* 319 * Normally, dynamic array structures are created on the stack, and array 320 * itself is freshly allocated, and then freed when no longer needed. When 321 * the XPRINTF_PERF macro is defined, the dynamic array structures associated 322 * with all-in-one printf variants are not freed, but store in a cache for 323 * later use (dynamic array structures used for compile/execute continue to 324 * be freed after they are no longer needed). This means there should be 325 * at most one structure in the cached per thread that actually used the 326 * all-in-one printf variant. 327 * 328 * The amount of memory that is cached is fairly small, totally about 1K 329 * for three structures used by a format string using ten conversion 330 * specifiers. This is too small for purgeable memory. 331 * 332 * However, we do flush these caches in case we every are unable to allocate 333 * memory, and retry the allocation, just in case. 334 */ 335#ifdef XPRINTF_PERF 336static OSQueueHead arg_type_queue = OS_ATOMIC_QUEUE_INIT; 337static OSQueueHead printf_info_queue = OS_ATOMIC_QUEUE_INIT; 338static OSQueueHead union_arg_queue = OS_ATOMIC_QUEUE_INIT; 339 340#define DEFINE_DEQUEUE(which, type) \ 341static struct array * \ 342which ## _dequeue(void) \ 343{ \ 344 struct array *a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next)); \ 345 \ 346 if (a) { \ 347 bzero(a->data, a->max * a->itemsize); \ 348 return a; \ 349 } \ 350 a = (struct array *)MALLOC(sizeof(*a)); \ 351 if (!a) return NULL; \ 352 if (!arrayinit(a, sizeof(type))) { \ 353 free(a); \ 354 return NULL; \ 355 } \ 356 return a; \ 357} 358 359#define DEFINE_ENQUEUE(which) \ 360__private_extern__ void \ 361which ## _enqueue(struct array *a) \ 362{ \ 363 if (!a) return; \ 364 OSAtomicEnqueue(&which ## _queue, a, offsetof(struct array, next)); \ 365} 366 367#define DEFINE_FLUSH(which) \ 368static void \ 369which ## _flush(void) \ 370{ \ 371 struct array *a; \ 372 while((a = (struct array *)OSAtomicDequeue(&which ## _queue, offsetof(struct array, next))) != NULL) { \ 373 arrayfree(a); \ 374 free(a); \ 375 } \ 376} 377 378DEFINE_DEQUEUE(arg_type, int) 379DEFINE_ENQUEUE(arg_type) 380DEFINE_FLUSH(arg_type) 381DEFINE_DEQUEUE(printf_info, struct printf_info) 382DEFINE_ENQUEUE(printf_info) 383DEFINE_FLUSH(printf_info) 384DEFINE_DEQUEUE(union_arg, union arg) 385DEFINE_ENQUEUE(union_arg) 386DEFINE_FLUSH(union_arg) 387 388static void 389flush_queues(void) 390{ 391 arg_type_flush(); 392 printf_info_flush(); 393 union_arg_flush(); 394} 395 396__private_extern__ void * 397xprintf_calloc(size_t count, size_t size) 398{ 399 void *x = calloc(count, size); 400 if(!x) { 401 flush_queues(); 402 x = calloc(count, size); 403 } 404 return x; 405} 406 407__private_extern__ void * 408xprintf_malloc(size_t size) 409{ 410 void *x = malloc(size); 411 if(!x) { 412 flush_queues(); 413 x = malloc(size); 414 } 415 return x; 416} 417 418#if 0 419void 420show_queues(void) 421{ 422 struct array *a; 423 printf("arg_type:"); 424 while((a = (struct array *)OSAtomicDequeue(&arg_type_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a); 425 printf("\nprintf_info:"); 426 while((a = (struct array *)OSAtomicDequeue(&printf_info_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a); 427 printf("\nunion_arg:"); 428 while((a = (struct array *)OSAtomicDequeue(&union_arg_queue, offsetof(struct array, next))) != NULL) printf("\n%p", a); 429 printf("\n"); 430} 431#endif 432#endif /* XPRINTF_PERF */ 433 434/* -------------------------------------------------------------------------*/ 435 436__private_extern__ int 437__printf_comp(printf_comp_t restrict pc, printf_domain_t restrict domain) 438{ 439 struct printf_info *pi, *pil; 440 const char *fmt; 441 int ch, pii; 442 int *argt; 443 int nextarg; 444 int maxarg; 445 int ret = 0; 446 int n; 447#ifndef XPRINTF_PERF 448 struct array piarr, argtarr; 449#endif /* XPRINTF_PERF */ 450 struct array *pa, *aa; 451 452 fmt = pc->fmt; 453 maxarg = 0; 454 nextarg = 1; 455#ifdef XPRINTF_PERF 456 pa = printf_info_dequeue(); 457#else /* !XPRINTF_PERF */ 458 pa = arrayinit(&piarr, sizeof(*pi)); 459#endif /* !XPRINTF_PERF */ 460 if (!pa) { 461#ifdef XPRINTF_PERF 462 flush_queues(); 463#endif /* XPRINTF_PERF */ 464 return EOF; 465 } 466#ifdef XPRINTF_PERF 467 pc->pa = pa; 468 aa = arg_type_dequeue(); 469#else /* !XPRINTF_PERF */ 470 aa = arrayinit(&argtarr, sizeof(*argt)); 471#endif /* !XPRINTF_PERF */ 472 if (!aa) { 473 arrayfree(pa); 474#ifdef XPRINTF_PERF 475 free(pa); 476 flush_queues(); 477#endif /* XPRINTF_PERF */ 478 return EOF; 479 } 480#ifdef XPRINTF_PERF 481 pc->aa = aa; 482#endif /* XPRINTF_PERF */ 483 for (pii = 0; ; pii++) { 484 pi = arrayget(pa, pii); 485 if (!pi) { 486 ret = EOF; 487 goto error; 488 } 489 pil = pi; 490 if (*fmt == '\0') 491 break; 492 pil = pi + 1; 493 pi->prec = -1; 494 pi->pad = ' '; 495#ifdef VECTORS 496 pi->vsep = 'X'; /* Illegal value, changed to defaults later. */ 497#endif /* VECTORS */ 498 pi->begin = pi->end = fmt; 499 while (*fmt != '\0' && *fmt != '%') 500 pi->end = ++fmt; 501 if (*fmt == '\0') 502 break; 503 fmt++; 504 for (;;) { 505 pi->spec = *fmt; 506 switch (pi->spec) { 507 case ' ': 508 /*- 509 * ``If the space and + flags both appear, the space 510 * flag will be ignored.'' 511 * -- ANSI X3J11 512 */ 513 if (pi->showsign == 0) { 514 pi->space = 1; 515 pi->signchar = ' '; 516 } 517 fmt++; 518 continue; 519 case '#': 520 pi->alt = 1; 521 fmt++; 522 continue; 523#ifdef VECTORS 524 case ',': case ';': case ':': case '_': 525 pi->vsep = pi->spec; 526 fmt++; 527 continue; 528#endif /* VECTORS */ 529 case '.': 530 pi->prec = 0; 531 fmt++; 532 if (*fmt == '*') { 533 fmt++; 534 /* Look for *nn$ and deal with it */ 535 n = 0; 536 while (*fmt != '\0' && is_digit(*fmt)) { 537 n *= 10; 538 n += to_digit(*fmt); 539 fmt++; 540 } 541 if (*fmt == '$') { 542 if ((n + 1) > maxarg) 543 maxarg = (n + 1); 544 fmt++; 545 } else n = nextarg++; 546 pi->get_prec = n; 547 argt = (int *)arrayget(aa, n); 548 if (!argt) { 549 ret = EOF; 550 goto error; 551 } 552 *argt = PA_INT; 553 continue; 554 } 555 while (*fmt != '\0' && is_digit(*fmt)) { 556 pi->prec *= 10; 557 pi->prec += to_digit(*fmt); 558 fmt++; 559 } 560 continue; 561 case '-': 562 pi->left = 1; 563 fmt++; 564 continue; 565 case '+': 566 pi->showsign = 1; 567 pi->signchar = '+'; 568 fmt++; 569 continue; 570 case '*': 571 fmt++; 572 /* Look for *nn$ and deal with it */ 573 n = 0; 574 while (*fmt != '\0' && is_digit(*fmt)) { 575 n *= 10; 576 n += to_digit(*fmt); 577 fmt++; 578 } 579 if (*fmt == '$') { 580 if ((n + 1) > maxarg) 581 maxarg = (n + 1); 582 fmt++; 583 } else n = nextarg++; 584 pi->get_width = n; 585 argt = (int *)arrayget(aa, n); 586 if (!argt) { 587 ret = EOF; 588 goto error; 589 } 590 *argt = PA_INT; 591 continue; 592 case '%': 593 fmt++; 594 break; 595 case '\'': 596 pi->group = 1; 597 fmt++; 598 continue; 599 case '0': 600 /*- 601 * ``Note that 0 is taken as a flag, not as the 602 * beginning of a field width.'' 603 * -- ANSI X3J11 604 */ 605 pi->pad = '0'; 606 fmt++; 607 continue; 608 case '1': case '2': case '3': 609 case '4': case '5': case '6': 610 case '7': case '8': case '9': 611 n = 0; 612 while (*fmt != '\0' && is_digit(*fmt)) { 613 n *= 10; 614 n += to_digit(*fmt); 615 fmt++; 616 } 617 if (*fmt == '$') { 618 if (nextarg > maxarg) 619 maxarg = nextarg; 620 nextarg = n; 621 fmt++; 622 } else 623 pi->width = n; 624 continue; 625#if 0 626 case 'D': 627 case 'O': 628 case 'U': 629 pi->spec += ('a' - 'A'); 630 pi->is_intmax = 0; 631 if (pi->is_long_double || pi->is_quad) { 632 pi->is_long = 0; 633 pi->is_long_double = 1; 634 } else { 635 pi->is_long = 1; 636 pi->is_long_double = 0; 637 } 638 fmt++; 639 break; 640#endif 641 case 'j': 642 pi->is_intmax = 1; 643 fmt++; 644 continue; 645 case 'q': 646 pi->is_long = 0; 647 pi->is_quad = 1; 648 fmt++; 649 continue; 650 case 'L': 651 pi->is_long_double = 1; 652 fmt++; 653 continue; 654 case 'h': 655 fmt++; 656 if (*fmt == 'h') { 657 fmt++; 658 pi->is_char = 1; 659 } else { 660 pi->is_short = 1; 661 } 662 continue; 663 case 'l': 664 fmt++; 665 if (*fmt == 'l') { 666 fmt++; 667 pi->is_long_double = 1; 668 pi->is_quad = 0; 669 } else { 670 pi->is_quad = 0; 671 pi->is_long = 1; 672 } 673 continue; 674 case 't': 675 pi->is_ptrdiff = 1; 676 fmt++; 677 continue; 678 case 'v': 679#ifdef VECTORS 680 pi->is_vec = 1; 681#endif /* VECTORS */ 682 fmt++; 683 continue; 684 case 'z': 685 pi->is_size = 1; 686 fmt++; 687 continue; 688 default: 689 fmt++; 690 break; 691 } 692 if (printf_tbl_in_range(pi->spec)) { 693 switch(domain->type[printf_tbl_index(pi->spec)]) { 694 /* ignore PRINTF_DOMAIN_UNUSED until later */ 695 case PRINTF_DOMAIN_FLAG: 696 errx(1, "Unexpected flag: %c", pi->spec); 697 case PRINTF_DOMAIN_GLIBC_API: 698 case PRINTF_DOMAIN_FBSD_API: 699 /* 700 * Insure that there are always 701 * __PRINTFMAXARG available. 702 */ 703 if (!arrayget(aa, nextarg + __PRINTFMAXARG - 1)) { 704 ret = EOF; 705 goto error; 706 } 707 pi->context = domain->tbl[printf_tbl_index(pi->spec)].context; 708 pi->loc = pc->loc; 709 ch = domain->tbl[printf_tbl_index(pi->spec)].arginfo( 710 pi, __PRINTFMAXARG, arrayget(aa, nextarg)); 711 if (ch > 0) 712 pi->arg[0] = (void *)(long)nextarg; 713 if (ch > 1) 714 pi->arg[1] = (void *)(long)(nextarg + 1); 715 nextarg += ch; 716 break; 717 } 718 } 719 break; 720 } 721 } 722 if (nextarg > maxarg) 723 maxarg = nextarg; 724 pc->argt = aa->data; 725 pc->pi = pa->data; 726 pc->pil = pil; 727 pc->maxarg = ch = maxarg; 728 if (ch < 1) ch = 1; 729#ifdef XPRINTF_PERF 730 pc->ua = union_arg_dequeue(); 731 if (!pc->ua) { 732 ret = EOF; 733 goto error; 734 } 735 if (!arrayget(pc->ua, ch)) { 736 union_arg_enqueue(pc->ua); 737 ret = EOF; 738 goto error; 739 } 740 pc->args = pc->ua->data; 741#else /* !XPRINTF_PERF */ 742 pc->args = (union arg *)malloc(ch * sizeof(*pc->args)); 743 if (!pc->args) { 744 ret = EOF; 745 goto error; 746 } 747#endif /* !XPRINTF_PERF */ 748 for (pi = pc->pi; pi < pil; pi++) { 749 if (pi->arg[0]) pi->arg[0] = &pc->args[(long)pi->arg[0]]; 750 if (pi->arg[1]) pi->arg[1] = &pc->args[(long)pi->arg[1]]; 751 } 752#if 0 753 fprintf(stderr, "fmt0 <%s>\n", fmt0); 754 fprintf(stderr, "pil %p\n", pil); 755#endif 756 pc->domain = domain; 757 758 return (ret); 759error: 760 arrayfree(pa); 761 arrayfree(aa); 762#ifdef XPRINTF_PERF 763 free(pa); 764 free(aa); 765 flush_queues(); 766#endif /* XPRINTF_PERF */ 767 return (ret); 768} 769 770__private_extern__ int 771__printf_exec(printf_comp_t restrict pc, FILE * restrict fp, va_list ap) 772{ 773 struct printf_info *pi; 774 int ch; 775 int ret = 0; 776 int n; 777 struct __printf_io io; 778 779 __printf_init(&io); 780 io.fp = fp; 781 782 for (ch = 1; ch < pc->maxarg; ch++) { 783#if 0 784 fprintf(stderr, "arg %d %x\n", ch, pc->argt[ch]); 785#endif 786 switch(pc->argt[ch]) { 787 case PA_CHAR: 788 pc->args[ch].intarg = (char)va_arg (ap, int); 789 break; 790 case PA_INT: 791 pc->args[ch].intarg = va_arg (ap, int); 792 break; 793 case PA_INT | PA_FLAG_SHORT: 794 pc->args[ch].intarg = (short)va_arg (ap, int); 795 break; 796 case PA_INT | PA_FLAG_LONG: 797 pc->args[ch].longarg = va_arg (ap, long); 798 break; 799 case PA_INT | PA_FLAG_INTMAX: 800 pc->args[ch].intmaxarg = va_arg (ap, intmax_t); 801 break; 802 case PA_INT | PA_FLAG_QUAD: 803 pc->args[ch].intmaxarg = va_arg (ap, quad_t); 804 break; 805 case PA_INT | PA_FLAG_LONG_LONG: 806 pc->args[ch].intmaxarg = va_arg (ap, long long); 807 break; 808 case PA_INT | PA_FLAG_SIZE: 809 pc->args[ch].intmaxarg = va_arg (ap, size_t); 810 break; 811 case PA_INT | PA_FLAG_PTRDIFF: 812 pc->args[ch].intmaxarg = (unsigned long)va_arg (ap, ptrdiff_t); 813 break; 814 case PA_WCHAR: 815 pc->args[ch].wintarg = va_arg (ap, wint_t); 816 break; 817 case PA_POINTER: 818 pc->args[ch].pvoidarg = va_arg (ap, void *); 819 break; 820 case PA_STRING: 821 pc->args[ch].pchararg = va_arg (ap, char *); 822 break; 823 case PA_WSTRING: 824 pc->args[ch].pwchararg = va_arg (ap, wchar_t *); 825 break; 826 case PA_DOUBLE: 827#ifndef NO_FLOATING_POINT 828 pc->args[ch].doublearg = va_arg (ap, double); 829#endif 830 break; 831 case PA_DOUBLE | PA_FLAG_LONG_DOUBLE: 832#ifndef NO_FLOATING_POINT 833 pc->args[ch].longdoublearg = va_arg (ap, long double); 834#endif 835 break; 836#ifdef VECTORS 837 case PA_VECTOR: 838 pc->args[ch].vectorarg = va_arg (ap, VECTORTYPE); 839 break; 840#endif /* VECTORS */ 841 default: 842 errx(1, "argtype = %x (fmt = \"%s\")\n", 843 pc->argt[ch], pc->fmt); 844 } 845 } 846 for (pi = pc->pi; pi < pc->pil; pi++) { 847#if 0 848 fprintf(stderr, "pi %p", pi); 849 fprintf(stderr, " spec '%c'", pi->spec); 850 fprintf(stderr, " args %d", 851 ((uintptr_t)pi->arg[0] - (uintptr_t)pc->args) / sizeof pc->args[0]); 852 if (pi->width) fprintf(stderr, " width %d", pi->width); 853 if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad); 854 if (pi->left) fprintf(stderr, " left"); 855 if (pi->showsign) fprintf(stderr, " showsign"); 856 if (pi->signchar) fprintf(stderr, " signchar 0x%x", pi->signchar); 857 if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec); 858 if (pi->is_char) fprintf(stderr, " char"); 859 if (pi->is_short) fprintf(stderr, " short"); 860 if (pi->is_long) fprintf(stderr, " long"); 861 if (pi->is_long_double) fprintf(stderr, " long_double"); 862 fprintf(stderr, "\n"); 863 fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin); 864#endif 865 if (pi->get_width) { 866 pi->width = pc->args[pi->get_width].intarg; 867 /*- 868 * ``A negative field width argument is taken as a 869 * - flag followed by a positive field width.'' 870 * -- ANSI X3J11 871 * They don't exclude field widths read from args. 872 */ 873 if (pi->width < 0) { 874 pi->left = 1; 875 pi->width = -pi->width; 876 } 877 } 878 if (pi->get_prec) 879 pi->prec = pc->args[pi->get_prec].intarg; 880 ret += __printf_puts(&io, pi->begin, pi->end - pi->begin); 881 if (pi->spec) { 882 if (!printf_tbl_in_range(pi->spec)) goto unused; 883 switch(pc->domain->type[printf_tbl_index(pi->spec)]) { 884 case PRINTF_DOMAIN_UNUSED: 885 unused: 886 { 887 char unknown = pi->spec; 888 ret += __printf_out(&io, pi, &unknown, 1); 889 break; 890 } 891 case PRINTF_DOMAIN_GLIBC_API: 892 __printf_flush(&io); 893 pi->sofar = ret; 894 ret += ((printf_function *)pc->domain->tbl[printf_tbl_index(pi->spec)].render)( 895 fp, pi, (const void *)pi->arg); 896 break; 897 case PRINTF_DOMAIN_FBSD_API: 898 pi->sofar = ret; 899 n = ((printf_render *)pc->domain->tbl[printf_tbl_index(pi->spec)].render)( 900 &io, pi, (const void *)pi->arg); 901 if (n < 0) 902 io.fp->_flags |= __SERR; 903 else 904 ret += n; 905 break; 906 } 907 } 908 } 909 __printf_flush(&io); 910 return (ret); 911} 912 913__private_extern__ int 914__v2printf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt, va_list ap) 915{ 916 struct _printf_compiled spc; 917 int ret, saverrno; 918 919 /* 920 * All the printf family (including extensible printf variants) funnel 921 * down to this point. So we can do common work here, and then fork 922 * out to the appropriate handler. 923 */ 924 /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ 925 if (prepwrite(fp) != 0) { 926 errno = EBADF; 927 return (EOF); 928 } 929 ORIENT(fp, -1); 930 931 if (pc == XPRINTF_PLAIN) { 932 NORMALIZE_LOCALE(loc); 933#ifdef XPRINTF_DEBUG 934 if (!__use_xprintf) 935#endif 936 return __vfprintf(fp, loc, fmt, ap); 937#ifdef XPRINTF_DEBUG 938 xprintf_domain_init(); 939 domain = xprintf_domain_global; 940#endif 941 } else if (pc) { 942 pthread_mutex_lock(&pc->mutex); 943 pthread_rwlock_rdlock(&pc->domain->rwlock); 944 ret = __printf_exec(pc, fp, ap); 945 saverrno = errno; 946 pthread_rwlock_unlock(&pc->domain->rwlock); 947 pthread_mutex_unlock(&pc->mutex); 948 errno = saverrno; 949 return ret; 950 } 951 if (!domain) { 952 errno = EINVAL; 953 return EOF; 954 } 955 xprintf_domain_init(); 956 bzero(&spc, sizeof(spc)); 957 spc.fmt = fmt; 958 DEFAULT_CURRENT_LOCALE(loc); 959 XL_RETAIN(loc); 960 spc.loc = loc; 961 /* 962 * We don't need to lock the printf_comp_t mutex, since the 963 * printf_comp_t was just created on the stack, and is private. 964 */ 965 pthread_rwlock_rdlock(&domain->rwlock); 966 if (__printf_comp(&spc, domain) < 0) { 967 saverrno = errno; 968 pthread_rwlock_unlock(&domain->rwlock); 969 XL_RELEASE(loc); 970 errno = saverrno; 971 return EOF; 972 } 973 ret = __printf_exec(&spc, fp, ap); 974 saverrno = errno; 975 pthread_rwlock_unlock(&domain->rwlock); 976 XL_RELEASE(loc); 977 978#ifdef XPRINTF_PERF 979 printf_info_enqueue(spc.pa); 980 arg_type_enqueue(spc.aa); 981 union_arg_enqueue(spc.ua); 982#else /* !XPRINTF_PERF */ 983 free(spc.pi); 984 free(spc.argt); 985 free(spc.args); 986#endif /* !XPRINTF_PERF */ 987 errno = saverrno; 988 return ret; 989} 990 991extern int __fflush(FILE *fp); 992 993/* 994 * Helper function for `fprintf to unbuffered unix file': creates a 995 * temporary buffer. We only work on write-only files; this avoids 996 * worries about ungetc buffers and so forth. 997 */ 998static int 999__v3printf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt, va_list ap) 1000{ 1001 int ret; 1002 FILE fake; 1003 struct __sFILEX extra; 1004 unsigned char buf[BUFSIZ]; 1005 1006 fake._extra = &extra; 1007 INITEXTRA(&fake); 1008 1009 /* copy the important variables */ 1010 fake._flags = fp->_flags & ~__SNBF; 1011 fake._file = fp->_file; 1012 fake._cookie = fp->_cookie; 1013 fake._write = fp->_write; 1014 fake._orientation = fp->_orientation; 1015 fake._mbstate = fp->_mbstate; 1016 1017 /* set up the buffer */ 1018 fake._bf._base = fake._p = buf; 1019 fake._bf._size = fake._w = sizeof(buf); 1020 fake._lbfsize = 0; /* not actually used, but Just In Case */ 1021 1022 /* do the work, then copy any error status */ 1023 ret = __v2printf(pc, domain, &fake, loc, fmt, ap); 1024 if (ret >= 0 && __fflush(&fake)) 1025 ret = EOF; 1026 if (fake._flags & __SERR) 1027 fp->_flags |= __SERR; 1028 return (ret); 1029} 1030 1031__private_extern__ int 1032__xvprintf(printf_comp_t restrict pc, printf_domain_t restrict domain, FILE * restrict fp, locale_t restrict loc, const char * restrict fmt0, va_list ap) 1033{ 1034 int ret; 1035 1036 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 1037 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 1038 fp->_file >= 0) 1039 ret = __v3printf(pc, domain, fp, loc, fmt0, ap); 1040 else 1041 ret = __v2printf(pc, domain, fp, loc, fmt0, ap); 1042 return ret; 1043} 1044 1045/* extending ---------------------------------------------------------*/ 1046 1047// No global domain support 1048#if 0 1049int 1050register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo) 1051{ 1052 return register_printf_domain_function(NULL, spec, render, arginfo); 1053} 1054 1055__private_extern__ int 1056register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo) 1057{ 1058 return register_printf_domain_render(NULL, spec, render, arginfo); 1059} 1060 1061int 1062register_printf_render_std(const char *specs) 1063{ 1064 return register_printf_domain_render_std(NULL, specs); 1065} 1066#endif 1067 1068#ifdef VECTORS 1069/* vector support ----------------------------------------------------*/ 1070 1071#define PRINTVECTOR(_io, _pi, _arg, _cnt, _type, _elem, _render, _ret) { \ 1072 int i; \ 1073 _type a, *ap; \ 1074 a = (_type)(_arg)->_elem[0]; \ 1075 ap = &a; \ 1076 (_ret) += _render((_io), (_pi), (const void *)&ap); \ 1077 for(i = 1; i < (_cnt); i++) { \ 1078 (_ret) += __printf_puts((_io), (_pi)->begin, (_pi)->end - (_pi)->begin); \ 1079 a = (_type)(_arg)->_elem[i]; \ 1080 (_ret) += _render((_io), (_pi), (const void *)&ap); \ 1081 } \ 1082} 1083 1084#define PRINTVECTOR_P(_io, _pi, _arg, _cnt, _elem, _render, _ret) { \ 1085 int i; \ 1086 void * a, *ap; \ 1087 a = (void *)(uintptr_t)(_arg)->_elem[0]; \ 1088 ap = &a; \ 1089 (_ret) += _render((_io), (_pi), (const void *)&ap); \ 1090 for(i = 1; i < (_cnt); i++) { \ 1091 (_ret) += __printf_puts((_io), (_pi)->begin, (_pi)->end - (_pi)->begin); \ 1092 a = (void *)(uintptr_t)(_arg)->_elem[i]; \ 1093 (_ret) += _render((_io), (_pi), (const void *)&ap); \ 1094 } \ 1095} 1096 1097__private_extern__ int 1098__xprintf_vector(struct __printf_io *io, const struct printf_info *pi, const void *const *arg) 1099{ 1100 char vsep; /* Vector separator character. */ 1101 const union arg *argp; 1102 int ret = 0; 1103 struct printf_info info = *pi; 1104 1105 argp = arg[0]; 1106 vsep = pi->vsep; 1107 if (vsep == 'X') { 1108 if (pi->spec == 'c') 1109 vsep = '\0'; 1110 else 1111 vsep = ' '; 1112 } 1113 info.begin = info.end = &vsep; 1114 if (vsep) info.end++; 1115 info.is_vec = 0; 1116 1117 if (pi->is_short) { 1118 if (pi->spec == 'p') { 1119 PRINTVECTOR_P(io, &info, argp, 8, vushortarg, __printf_render_ptr, ret); 1120 } else { 1121 PRINTVECTOR(io, &info, argp, 8, unsigned int, vushortarg, __printf_render_int, ret); 1122 } 1123 } else if (pi->is_long) { 1124 info.is_long = 0; 1125 if (pi->spec == 'p') { 1126 PRINTVECTOR_P(io, &info, argp, 4, vuintarg, __printf_render_ptr, ret); 1127 } else { 1128 PRINTVECTOR(io, &info, argp, 4, unsigned int, vuintarg, __printf_render_int, ret); 1129 } 1130#ifdef V64TYPE 1131 } else if (pi->is_long_double) { 1132 switch (pi->spec) { 1133 case 'a': 1134 case 'A': 1135 case 'e': 1136 case 'E': 1137 case 'f': 1138 case 'g': 1139 case 'G': 1140 info.is_long_double = 0; 1141 PRINTVECTOR(io, &info, argp, 2, double, vdoublearg, __printf_render_float, ret); 1142 break; 1143 case 'p': 1144 info.is_long_double = 0; 1145 PRINTVECTOR_P(io, &info, argp, 2, vulonglongarg, __printf_render_ptr, ret); 1146 break; 1147 case 'd': 1148 case 'i': 1149 case 'u': 1150 case 'o': 1151 case 'x': 1152 case 'X': 1153 PRINTVECTOR(io, &info, argp, 2, unsigned long long, vulonglongarg, __printf_render_int, ret); 1154 break; 1155 default: 1156 /* 1157 * The default case should never 1158 * happen. 1159 */ 1160 case 'c': 1161 info.is_long_double = 0; 1162 PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_chr, ret); 1163 } 1164#endif /* V64TYPE */ 1165 } else { 1166 switch (pi->spec) { 1167 case 'a': 1168 case 'A': 1169 case 'e': 1170 case 'E': 1171 case 'f': 1172 case 'g': 1173 case 'G': 1174 PRINTVECTOR(io, &info, argp, 4, double, vfloatarg, __printf_render_float, ret); 1175 break; 1176 default: 1177 /* 1178 * The default case should never 1179 * happen. 1180 */ 1181 case 'p': 1182 PRINTVECTOR_P(io, &info, argp, 16, vuchararg, __printf_render_ptr, ret); 1183 break; 1184 case 'd': 1185 case 'i': 1186 case 'u': 1187 case 'o': 1188 case 'x': 1189 case 'X': 1190 info.is_char = 1; 1191 PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_int, ret); 1192 break; 1193 case 'c': 1194 PRINTVECTOR(io, &info, argp, 16, unsigned int, vuchararg, __printf_render_chr, ret); 1195 } 1196 } 1197 return ret; 1198} 1199#endif /* VECTORS */ 1200