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