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