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