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$ 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 "un-namespace.h" 50 51 #include "printf.h" 52 #include "fvwrite.h" 53 54 int __use_xprintf = -1; 55 56 /* private stuff -----------------------------------------------------*/ 57 58 union arg { 59 int intarg; 60 long longarg; 61 intmax_t intmaxarg; 62 #ifndef NO_FLOATING_POINT 63 double doublearg; 64 long double longdoublearg; 65 #endif 66 wint_t wintarg; 67 char *pchararg; 68 wchar_t *pwchararg; 69 void *pvoidarg; 70 }; 71 72 /* 73 * Macros for converting digits to letters and vice versa 74 */ 75 #define to_digit(c) ((c) - '0') 76 #define is_digit(c) (((unsigned)to_digit(c)) <= 9) 77 78 /* various globals ---------------------------------------------------*/ 79 80 const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */ 81 const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */ 82 83 #define PADSIZE 16 84 static char blanks[PADSIZE] = 85 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; 86 static char zeroes[PADSIZE] = 87 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; 88 89 /* printing and padding functions ------------------------------------*/ 90 91 #define NIOV 8 92 93 struct __printf_io { 94 FILE *fp; 95 struct __suio uio; 96 struct __siov iov[NIOV]; 97 struct __siov *iovp; 98 }; 99 100 static void 101 __printf_init(struct __printf_io *io) 102 { 103 104 io->uio.uio_iov = io->iovp = &io->iov[0]; 105 io->uio.uio_resid = 0; 106 io->uio.uio_iovcnt = 0; 107 } 108 109 void 110 __printf_flush(struct __printf_io *io) 111 { 112 113 __sfvwrite(io->fp, &io->uio); 114 __printf_init(io); 115 } 116 117 int 118 __printf_puts(struct __printf_io *io, const void *ptr, int len) 119 { 120 121 122 if (io->fp->_flags & __SERR) 123 return (0); 124 if (len == 0) 125 return (0); 126 io->iovp->iov_base = __DECONST(void *, ptr); 127 io->iovp->iov_len = len; 128 io->uio.uio_resid += len; 129 io->iovp++; 130 io->uio.uio_iovcnt++; 131 if (io->uio.uio_iovcnt >= NIOV) 132 __printf_flush(io); 133 return (len); 134 } 135 136 int 137 __printf_pad(struct __printf_io *io, int howmany, int zero) 138 { 139 int n; 140 const char *with; 141 int ret = 0; 142 143 if (zero) 144 with = zeroes; 145 else 146 with = blanks; 147 148 if ((n = (howmany)) > 0) { 149 while (n > PADSIZE) { 150 ret += __printf_puts(io, with, PADSIZE); 151 n -= PADSIZE; 152 } 153 ret += __printf_puts(io, with, n); 154 } 155 return (ret); 156 } 157 158 int 159 __printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len) 160 { 161 int ret = 0; 162 163 if ((!pi->left) && pi->width > len) 164 ret += __printf_pad(io, pi->width - len, pi->pad == '0'); 165 ret += __printf_puts(io, ptr, len); 166 if (pi->left && pi->width > len) 167 ret += __printf_pad(io, pi->width - len, pi->pad == '0'); 168 return (ret); 169 } 170 171 172 /* percent handling -------------------------------------------------*/ 173 174 static int 175 __printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, int *argt __unused) 176 { 177 178 return (0); 179 } 180 181 static int 182 __printf_render_pct(struct __printf_io *io, const struct printf_info *pi __unused, const void *const *arg __unused) 183 { 184 185 return (__printf_puts(io, "%", 1)); 186 } 187 188 /* 'n' ---------------------------------------------------------------*/ 189 190 static int 191 __printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt) 192 { 193 194 assert(n >= 1); 195 argt[0] = PA_POINTER; 196 return (1); 197 } 198 199 /* 200 * This is a printf_render so that all output has been flushed before it 201 * gets called. 202 */ 203 204 static int 205 __printf_render_n(FILE *io __unused, const struct printf_info *pi, const void *const *arg) 206 { 207 208 if (pi->is_char) 209 **((signed char **)arg[0]) = (signed char)pi->sofar; 210 else if (pi->is_short) 211 **((short **)arg[0]) = (short)pi->sofar; 212 else if (pi->is_long) 213 **((long **)arg[0]) = pi->sofar; 214 else if (pi->is_long_double) 215 **((long long **)arg[0]) = pi->sofar; 216 else if (pi->is_intmax) 217 **((intmax_t **)arg[0]) = pi->sofar; 218 else if (pi->is_ptrdiff) 219 **((ptrdiff_t **)arg[0]) = pi->sofar; 220 else if (pi->is_quad) 221 **((quad_t **)arg[0]) = pi->sofar; 222 else if (pi->is_size) 223 **((size_t **)arg[0]) = pi->sofar; 224 else 225 **((int **)arg[0]) = pi->sofar; 226 227 return (0); 228 } 229 230 /* table -------------------------------------------------------------*/ 231 232 /*lint -esym(785, printf_tbl) */ 233 static struct { 234 printf_arginfo_function *arginfo; 235 printf_function *gnurender; 236 printf_render *render; 237 } printf_tbl[256] = { 238 ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct }, 239 ['A'] = { __printf_arginfo_float, NULL, __printf_render_float }, 240 ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr }, 241 ['E'] = { __printf_arginfo_float, NULL, __printf_render_float }, 242 ['F'] = { __printf_arginfo_float, NULL, __printf_render_float }, 243 ['G'] = { __printf_arginfo_float, NULL, __printf_render_float }, 244 ['S'] = { __printf_arginfo_str, NULL, __printf_render_str }, 245 ['X'] = { __printf_arginfo_int, NULL, __printf_render_int }, 246 ['a'] = { __printf_arginfo_float, NULL, __printf_render_float }, 247 ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr }, 248 ['d'] = { __printf_arginfo_int, NULL, __printf_render_int }, 249 ['e'] = { __printf_arginfo_float, NULL, __printf_render_float }, 250 ['f'] = { __printf_arginfo_float, NULL, __printf_render_float }, 251 ['g'] = { __printf_arginfo_float, NULL, __printf_render_float }, 252 ['i'] = { __printf_arginfo_int, NULL, __printf_render_int }, 253 ['n'] = { __printf_arginfo_n, __printf_render_n, NULL }, 254 ['o'] = { __printf_arginfo_int, NULL, __printf_render_int }, 255 ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr }, 256 ['q'] = { __printf_arginfo_int, NULL, __printf_render_int }, 257 ['s'] = { __printf_arginfo_str, NULL, __printf_render_str }, 258 ['u'] = { __printf_arginfo_int, NULL, __printf_render_int }, 259 ['x'] = { __printf_arginfo_int, NULL, __printf_render_int }, 260 }; 261 262 263 static int 264 __v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap) 265 { 266 struct printf_info *pi, *pil; 267 const char *fmt; 268 int ch; 269 struct printf_info pia[pct + 10]; 270 int argt[pct + 10]; 271 union arg args[pct + 10]; 272 int nextarg; 273 int maxarg; 274 int ret = 0; 275 int n; 276 struct __printf_io io; 277 278 __printf_init(&io); 279 io.fp = fp; 280 281 fmt = fmt0; 282 maxarg = 0; 283 nextarg = 1; 284 memset(argt, 0, sizeof argt); 285 for (pi = pia; ; pi++) { 286 memset(pi, 0, sizeof *pi); 287 pil = pi; 288 if (*fmt == '\0') 289 break; 290 pil = pi + 1; 291 pi->prec = -1; 292 pi->pad = ' '; 293 pi->begin = pi->end = fmt; 294 while (*fmt != '\0' && *fmt != '%') 295 pi->end = ++fmt; 296 if (*fmt == '\0') 297 break; 298 fmt++; 299 for (;;) { 300 pi->spec = *fmt; 301 switch (pi->spec) { 302 case ' ': 303 /*- 304 * ``If the space and + flags both appear, the space 305 * flag will be ignored.'' 306 * -- ANSI X3J11 307 */ 308 if (pi->showsign == 0) 309 pi->showsign = ' '; 310 fmt++; 311 continue; 312 case '#': 313 pi->alt = 1; 314 fmt++; 315 continue; 316 case '.': 317 pi->prec = 0; 318 fmt++; 319 if (*fmt == '*') { 320 fmt++; 321 pi->get_prec = nextarg; 322 argt[nextarg++] = PA_INT; 323 continue; 324 } 325 while (*fmt != '\0' && is_digit(*fmt)) { 326 pi->prec *= 10; 327 pi->prec += to_digit(*fmt); 328 fmt++; 329 } 330 continue; 331 case '-': 332 pi->left = 1; 333 fmt++; 334 continue; 335 case '+': 336 pi->showsign = '+'; 337 fmt++; 338 continue; 339 case '*': 340 fmt++; 341 pi->get_width = nextarg; 342 argt[nextarg++] = PA_INT; 343 continue; 344 case '%': 345 fmt++; 346 break; 347 case '\'': 348 pi->group = 1; 349 fmt++; 350 continue; 351 case '0': 352 /*- 353 * ``Note that 0 is taken as a flag, not as the 354 * beginning of a field width.'' 355 * -- ANSI X3J11 356 */ 357 pi->pad = '0'; 358 fmt++; 359 continue; 360 case '1': case '2': case '3': 361 case '4': case '5': case '6': 362 case '7': case '8': case '9': 363 n = 0; 364 while (*fmt != '\0' && is_digit(*fmt)) { 365 n *= 10; 366 n += to_digit(*fmt); 367 fmt++; 368 } 369 if (*fmt == '$') { 370 if (nextarg > maxarg) 371 maxarg = nextarg; 372 nextarg = n; 373 fmt++; 374 } else 375 pi->width = n; 376 continue; 377 case 'D': 378 case 'O': 379 case 'U': 380 pi->spec += ('a' - 'A'); 381 pi->is_intmax = 0; 382 if (pi->is_long_double || pi->is_quad) { 383 pi->is_long = 0; 384 pi->is_long_double = 1; 385 } else { 386 pi->is_long = 1; 387 pi->is_long_double = 0; 388 } 389 fmt++; 390 break; 391 case 'j': 392 pi->is_intmax = 1; 393 fmt++; 394 continue; 395 case 'q': 396 pi->is_long = 0; 397 pi->is_quad = 1; 398 fmt++; 399 continue; 400 case 'L': 401 pi->is_long_double = 1; 402 fmt++; 403 continue; 404 case 'h': 405 fmt++; 406 if (*fmt == 'h') { 407 fmt++; 408 pi->is_char = 1; 409 } else { 410 pi->is_short = 1; 411 } 412 continue; 413 case 'l': 414 fmt++; 415 if (*fmt == 'l') { 416 fmt++; 417 pi->is_long_double = 1; 418 pi->is_quad = 0; 419 } else { 420 pi->is_quad = 0; 421 pi->is_long = 1; 422 } 423 continue; 424 case 't': 425 pi->is_ptrdiff = 1; 426 fmt++; 427 continue; 428 case 'z': 429 pi->is_size = 1; 430 fmt++; 431 continue; 432 default: 433 fmt++; 434 break; 435 } 436 if (printf_tbl[pi->spec].arginfo == NULL) 437 errx(1, "arginfo[%c] = NULL", pi->spec); 438 ch = printf_tbl[pi->spec].arginfo( 439 pi, __PRINTFMAXARG, &argt[nextarg]); 440 if (ch > 0) 441 pi->arg[0] = &args[nextarg]; 442 if (ch > 1) 443 pi->arg[1] = &args[nextarg + 1]; 444 nextarg += ch; 445 break; 446 } 447 } 448 if (nextarg > maxarg) 449 maxarg = nextarg; 450 #if 0 451 fprintf(stderr, "fmt0 <%s>\n", fmt0); 452 fprintf(stderr, "pil %p\n", pil); 453 #endif 454 for (ch = 1; ch < maxarg; ch++) { 455 #if 0 456 fprintf(stderr, "arg %d %x\n", ch, argt[ch]); 457 #endif 458 switch(argt[ch]) { 459 case PA_CHAR: 460 args[ch].intarg = (char)va_arg (ap, int); 461 break; 462 case PA_INT: 463 args[ch].intarg = va_arg (ap, int); 464 break; 465 case PA_INT | PA_FLAG_SHORT: 466 args[ch].intarg = (short)va_arg (ap, int); 467 break; 468 case PA_INT | PA_FLAG_LONG: 469 args[ch].longarg = va_arg (ap, long); 470 break; 471 case PA_INT | PA_FLAG_INTMAX: 472 args[ch].intmaxarg = va_arg (ap, intmax_t); 473 break; 474 case PA_INT | PA_FLAG_QUAD: 475 args[ch].intmaxarg = va_arg (ap, quad_t); 476 break; 477 case PA_INT | PA_FLAG_LONG_LONG: 478 args[ch].intmaxarg = va_arg (ap, long long); 479 break; 480 case PA_INT | PA_FLAG_SIZE: 481 args[ch].intmaxarg = va_arg (ap, size_t); 482 break; 483 case PA_INT | PA_FLAG_PTRDIFF: 484 args[ch].intmaxarg = va_arg (ap, ptrdiff_t); 485 break; 486 case PA_WCHAR: 487 args[ch].wintarg = va_arg (ap, wint_t); 488 break; 489 case PA_POINTER: 490 args[ch].pvoidarg = va_arg (ap, void *); 491 break; 492 case PA_STRING: 493 args[ch].pchararg = va_arg (ap, char *); 494 break; 495 case PA_WSTRING: 496 args[ch].pwchararg = va_arg (ap, wchar_t *); 497 break; 498 case PA_DOUBLE: 499 #ifndef NO_FLOATING_POINT 500 args[ch].doublearg = va_arg (ap, double); 501 #endif 502 break; 503 case PA_DOUBLE | PA_FLAG_LONG_DOUBLE: 504 #ifndef NO_FLOATING_POINT 505 args[ch].longdoublearg = va_arg (ap, long double); 506 #endif 507 break; 508 default: 509 errx(1, "argtype = %x (fmt = \"%s\")\n", 510 argt[ch], fmt0); 511 } 512 } 513 for (pi = pia; pi < pil; pi++) { 514 #if 0 515 fprintf(stderr, "pi %p", pi); 516 fprintf(stderr, " spec '%c'", pi->spec); 517 fprintf(stderr, " args %d", 518 ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]); 519 if (pi->width) fprintf(stderr, " width %d", pi->width); 520 if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad); 521 if (pi->left) fprintf(stderr, " left"); 522 if (pi->showsign) fprintf(stderr, " showsign"); 523 if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec); 524 if (pi->is_char) fprintf(stderr, " char"); 525 if (pi->is_short) fprintf(stderr, " short"); 526 if (pi->is_long) fprintf(stderr, " long"); 527 if (pi->is_long_double) fprintf(stderr, " long_double"); 528 fprintf(stderr, "\n"); 529 fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin); 530 #endif 531 if (pi->get_width) { 532 pi->width = args[pi->get_width].intarg; 533 /*- 534 * ``A negative field width argument is taken as a 535 * - flag followed by a positive field width.'' 536 * -- ANSI X3J11 537 * They don't exclude field widths read from args. 538 */ 539 if (pi->width < 0) { 540 pi->left = 1; 541 pi->width = -pi->width; 542 } 543 } 544 if (pi->get_prec) 545 pi->prec = args[pi->get_prec].intarg; 546 ret += __printf_puts(&io, pi->begin, pi->end - pi->begin); 547 if (printf_tbl[pi->spec].gnurender != NULL) { 548 __printf_flush(&io); 549 pi->sofar = ret; 550 ret += printf_tbl[pi->spec].gnurender( 551 fp, pi, (const void *)pi->arg); 552 } else if (printf_tbl[pi->spec].render != NULL) { 553 pi->sofar = ret; 554 n = printf_tbl[pi->spec].render( 555 &io, pi, (const void *)pi->arg); 556 if (n < 0) 557 io.fp->_flags |= __SERR; 558 else 559 ret += n; 560 } else if (pi->begin == pi->end) 561 errx(1, "render[%c] = NULL", *fmt); 562 } 563 __printf_flush(&io); 564 return (ret); 565 } 566 567 extern int __fflush(FILE *fp); 568 569 /* 570 * Helper function for `fprintf to unbuffered unix file': creates a 571 * temporary buffer. We only work on write-only files; this avoids 572 * worries about ungetc buffers and so forth. 573 */ 574 static int 575 __v3printf(FILE *fp, const char *fmt, int pct, va_list ap) 576 { 577 int ret; 578 FILE fake; 579 unsigned char buf[BUFSIZ]; 580 581 /* copy the important variables */ 582 fake._flags = fp->_flags & ~__SNBF; 583 fake._file = fp->_file; 584 fake._cookie = fp->_cookie; 585 fake._write = fp->_write; 586 fake._orientation = fp->_orientation; 587 fake._mbstate = fp->_mbstate; 588 589 /* set up the buffer */ 590 fake._bf._base = fake._p = buf; 591 fake._bf._size = fake._w = sizeof(buf); 592 fake._lbfsize = 0; /* not actually used, but Just In Case */ 593 594 /* do the work, then copy any error status */ 595 ret = __v2printf(&fake, fmt, pct, ap); 596 if (ret >= 0 && __fflush(&fake)) 597 ret = EOF; 598 if (fake._flags & __SERR) 599 fp->_flags |= __SERR; 600 return (ret); 601 } 602 603 int 604 __xvprintf(FILE *fp, const char *fmt0, va_list ap) 605 { 606 unsigned u; 607 const char *p; 608 609 /* Count number of '%' signs handling double '%' signs */ 610 for (p = fmt0, u = 0; *p; p++) { 611 if (*p != '%') 612 continue; 613 u++; 614 if (p[1] == '%') 615 p++; 616 } 617 618 /* optimise fprintf(stderr) (and other unbuffered Unix files) */ 619 if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && 620 fp->_file >= 0) 621 return (__v3printf(fp, fmt0, u, ap)); 622 else 623 return (__v2printf(fp, fmt0, u, ap)); 624 } 625 626 /* extending ---------------------------------------------------------*/ 627 628 int 629 register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo) 630 { 631 632 if (spec > 255 || spec < 0) 633 return (-1); 634 printf_tbl[spec].gnurender = render; 635 printf_tbl[spec].arginfo = arginfo; 636 __use_xprintf = 1; 637 return (0); 638 } 639 640 int 641 register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo) 642 { 643 644 if (spec > 255 || spec < 0) 645 return (-1); 646 printf_tbl[spec].render = render; 647 printf_tbl[spec].arginfo = arginfo; 648 __use_xprintf = 1; 649 return (0); 650 } 651 652 int 653 register_printf_render_std(const unsigned char *specs) 654 { 655 656 for (; *specs != '\0'; specs++) { 657 switch (*specs) { 658 case 'H': 659 register_printf_render(*specs, 660 __printf_render_hexdump, 661 __printf_arginfo_hexdump); 662 break; 663 case 'M': 664 register_printf_render(*specs, 665 __printf_render_errno, 666 __printf_arginfo_errno); 667 break; 668 case 'Q': 669 register_printf_render(*specs, 670 __printf_render_quote, 671 __printf_arginfo_quote); 672 break; 673 case 'T': 674 register_printf_render(*specs, 675 __printf_render_time, 676 __printf_arginfo_time); 677 break; 678 case 'V': 679 register_printf_render(*specs, 680 __printf_render_vis, 681 __printf_arginfo_vis); 682 break; 683 default: 684 return (-1); 685 } 686 } 687 return (0); 688 } 689 690