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