1 /* $OpenBSD: tree.c,v 1.21 2015/09/01 13:12:31 tedu Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 5 * 2011, 2012, 2013, 2015, 2016, 2017 6 * mirabilos <m (at) mirbsd.org> 7 * 8 * Provided that these terms and disclaimer and all copyright notices 9 * are retained or reproduced in an accompanying document, permission 10 * is granted to deal in this work without restriction, including un- 11 * limited rights to use, publicly perform, distribute, sell, modify, 12 * merge, give away, or sublicence. 13 * 14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to 15 * the utmost extent permitted by applicable law, neither express nor 16 * implied; without malicious intent or gross negligence. In no event 17 * may a licensor, author or contributor be held liable for indirect, 18 * direct, other damage, loss, or other issues arising in any way out 19 * of dealing in the work, even if advised of the possibility of such 20 * damage or existence of a defect, except proven that it results out 21 * of said person's immediate fault when using the work as intended. 22 */ 23 24 #include "sh.h" 25 26 __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.95 2018/01/14 00:03:05 tg Exp $"); 27 28 #define INDENT 8 29 30 static void ptree(struct op *, int, struct shf *); 31 static void pioact(struct shf *, struct ioword *); 32 static const char *wdvarput(struct shf *, const char *, int, int); 33 static void vfptreef(struct shf *, int, const char *, va_list); 34 static struct ioword **iocopy(struct ioword **, Area *); 35 static void iofree(struct ioword **, Area *); 36 37 /* "foo& ; bar" and "foo |& ; bar" are invalid */ 38 static bool prevent_semicolon; 39 40 static const char Telif_pT[] = "elif %T"; 41 42 /* 43 * print a command tree 44 */ 45 static void 46 ptree(struct op *t, int indent, struct shf *shf) 47 { 48 const char **w; 49 struct ioword **ioact; 50 struct op *t1; 51 int i; 52 const char *ccp; 53 54 Chain: 55 if (t == NULL) 56 return; 57 switch (t->type) { 58 case TCOM: 59 prevent_semicolon = false; 60 /* special-case 'var=<<EOF' (cf. exec.c:execute) */ 61 if (t->args && 62 /* we have zero arguments, i.e. no program to run */ 63 t->args[0] == NULL && 64 /* we have exactly one variable assignment */ 65 t->vars[0] != NULL && t->vars[1] == NULL && 66 /* we have exactly one I/O redirection */ 67 t->ioact != NULL && t->ioact[0] != NULL && 68 t->ioact[1] == NULL && 69 /* of type "here document" (or "here string") */ 70 (t->ioact[0]->ioflag & IOTYPE) == IOHERE && 71 /* the variable assignment begins with a valid varname */ 72 (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] && 73 /* and has no right-hand side (i.e. "varname=") */ 74 ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) || 75 /* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR && 76 ccp[3] == '=' && ccp[4] == EOS))) { 77 fptreef(shf, indent, Tf_S, t->vars[0]); 78 break; 79 } 80 81 if (t->vars) { 82 w = (const char **)t->vars; 83 while (*w) 84 fptreef(shf, indent, Tf_S_, *w++); 85 } else 86 shf_puts("#no-vars# ", shf); 87 if (t->args) { 88 w = t->args; 89 if (*w && **w == CHAR) { 90 char *cp = wdstrip(*w++, WDS_TPUTS); 91 92 if (valid_alias_name(cp)) 93 shf_putc('\\', shf); 94 shf_puts(cp, shf); 95 shf_putc(' ', shf); 96 afree(cp, ATEMP); 97 } 98 while (*w) 99 fptreef(shf, indent, Tf_S_, *w++); 100 } else 101 shf_puts("#no-args# ", shf); 102 break; 103 case TEXEC: 104 t = t->left; 105 goto Chain; 106 case TPAREN: 107 fptreef(shf, indent + 2, "( %T) ", t->left); 108 break; 109 case TPIPE: 110 fptreef(shf, indent, "%T| ", t->left); 111 t = t->right; 112 goto Chain; 113 case TLIST: 114 fptreef(shf, indent, "%T%;", t->left); 115 t = t->right; 116 goto Chain; 117 case TOR: 118 case TAND: 119 fptreef(shf, indent, "%T%s %T", 120 t->left, (t->type == TOR) ? "||" : "&&", t->right); 121 break; 122 case TBANG: 123 shf_puts("! ", shf); 124 prevent_semicolon = false; 125 t = t->right; 126 goto Chain; 127 case TDBRACKET: 128 w = t->args; 129 shf_puts("[[", shf); 130 while (*w) 131 fptreef(shf, indent, Tf__S, *w++); 132 shf_puts(" ]] ", shf); 133 break; 134 case TSELECT: 135 case TFOR: 136 fptreef(shf, indent, "%s %s ", 137 (t->type == TFOR) ? "for" : Tselect, t->str); 138 if (t->vars != NULL) { 139 shf_puts("in ", shf); 140 w = (const char **)t->vars; 141 while (*w) 142 fptreef(shf, indent, Tf_S_, *w++); 143 fptreef(shf, indent, Tft_end); 144 } 145 fptreef(shf, indent + INDENT, "do%N%T", t->left); 146 fptreef(shf, indent, "%;done "); 147 break; 148 case TCASE: 149 fptreef(shf, indent, "case %S in", t->str); 150 for (t1 = t->left; t1 != NULL; t1 = t1->right) { 151 fptreef(shf, indent, "%N("); 152 w = (const char **)t1->vars; 153 while (*w) { 154 fptreef(shf, indent, "%S%c", *w, 155 (w[1] != NULL) ? '|' : ')'); 156 ++w; 157 } 158 fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left, 159 t1->u.charflag); 160 } 161 fptreef(shf, indent, "%Nesac "); 162 break; 163 case TELIF: 164 internal_errorf(TELIF_unexpected); 165 /* FALLTHROUGH */ 166 case TIF: 167 i = 2; 168 t1 = t; 169 goto process_TIF; 170 do { 171 t1 = t1->right; 172 i = 0; 173 fptreef(shf, indent, Tft_end); 174 process_TIF: 175 /* 5 == strlen("elif ") */ 176 fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left); 177 t1 = t1->right; 178 if (t1->left != NULL) { 179 fptreef(shf, indent, Tft_end); 180 fptreef(shf, indent + INDENT, "%s%N%T", 181 "then", t1->left); 182 } 183 } while (t1->right && t1->right->type == TELIF); 184 if (t1->right != NULL) { 185 fptreef(shf, indent, Tft_end); 186 fptreef(shf, indent + INDENT, "%s%N%T", 187 "else", t1->right); 188 } 189 fptreef(shf, indent, "%;fi "); 190 break; 191 case TWHILE: 192 case TUNTIL: 193 /* 6 == strlen("while "/"until ") */ 194 fptreef(shf, indent + 6, Tf_s_T, 195 (t->type == TWHILE) ? "while" : "until", 196 t->left); 197 fptreef(shf, indent, Tft_end); 198 fptreef(shf, indent + INDENT, "do%N%T", t->right); 199 fptreef(shf, indent, "%;done "); 200 break; 201 case TBRACE: 202 fptreef(shf, indent + INDENT, "{%N%T", t->left); 203 fptreef(shf, indent, "%;} "); 204 break; 205 case TCOPROC: 206 fptreef(shf, indent, "%T|& ", t->left); 207 prevent_semicolon = true; 208 break; 209 case TASYNC: 210 fptreef(shf, indent, "%T& ", t->left); 211 prevent_semicolon = true; 212 break; 213 case TFUNCT: 214 fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left); 215 break; 216 case TTIME: 217 fptreef(shf, indent, Tf_s_T, Ttime, t->left); 218 break; 219 default: 220 shf_puts("<botch>", shf); 221 prevent_semicolon = false; 222 break; 223 } 224 if ((ioact = t->ioact) != NULL) { 225 bool need_nl = false; 226 227 while (*ioact != NULL) 228 pioact(shf, *ioact++); 229 /* Print here documents after everything else... */ 230 ioact = t->ioact; 231 while (*ioact != NULL) { 232 struct ioword *iop = *ioact++; 233 234 /* heredoc is NULL when tracing (set -x) */ 235 if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE && 236 iop->heredoc) { 237 shf_putc('\n', shf); 238 shf_puts(iop->heredoc, shf); 239 fptreef(shf, indent, Tf_s, 240 evalstr(iop->delim, 0)); 241 need_nl = true; 242 } 243 } 244 /* 245 * Last delimiter must be followed by a newline (this 246 * often leads to an extra blank line, but it's not 247 * worth worrying about) 248 */ 249 if (need_nl) { 250 shf_putc('\n', shf); 251 prevent_semicolon = true; 252 } 253 } 254 } 255 256 static void 257 pioact(struct shf *shf, struct ioword *iop) 258 { 259 unsigned short flag = iop->ioflag; 260 unsigned short type = flag & IOTYPE; 261 short expected; 262 263 expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 : 264 (type == IOCAT || type == IOWRITE) ? 1 : 265 (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit : 266 iop->unit + 1; 267 if (iop->unit != expected) 268 shf_fprintf(shf, Tf_d, (int)iop->unit); 269 270 switch (type) { 271 case IOREAD: 272 shf_putc('<', shf); 273 break; 274 case IOHERE: 275 shf_puts("<<", shf); 276 if (flag & IOSKIP) 277 shf_putc('-', shf); 278 else if (flag & IOHERESTR) 279 shf_putc('<', shf); 280 break; 281 case IOCAT: 282 shf_puts(">>", shf); 283 break; 284 case IOWRITE: 285 shf_putc('>', shf); 286 if (flag & IOCLOB) 287 shf_putc('|', shf); 288 break; 289 case IORDWR: 290 shf_puts("<>", shf); 291 break; 292 case IODUP: 293 shf_puts(flag & IORDUP ? "<&" : ">&", shf); 294 break; 295 } 296 /* name/delim are NULL when printing syntax errors */ 297 if (type == IOHERE) { 298 if (iop->delim && !(iop->ioflag & IONDELIM)) 299 wdvarput(shf, iop->delim, 0, WDS_TPUTS); 300 } else if (iop->ioname) { 301 if (flag & IONAMEXP) 302 print_value_quoted(shf, iop->ioname); 303 else 304 wdvarput(shf, iop->ioname, 0, WDS_TPUTS); 305 } 306 shf_putc(' ', shf); 307 prevent_semicolon = false; 308 } 309 310 /* variant of fputs for ptreef and wdstrip */ 311 static const char * 312 wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode) 313 { 314 int c; 315 const char *cs; 316 317 /*- 318 * problems: 319 * `...` -> $(...) 320 * 'foo' -> "foo" 321 * x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS 322 * x${foo:-'hi'} -> x${foo:-hi} 323 * could change encoding to: 324 * OQUOTE ["'] ... CQUOTE ["'] 325 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case) 326 */ 327 while (/* CONSTCOND */ 1) 328 switch (*wp++) { 329 case EOS: 330 return (--wp); 331 case ADELIM: 332 if (ord(*wp) == ORD(/*{*/ '}')) { 333 ++wp; 334 goto wdvarput_csubst; 335 } 336 /* FALLTHROUGH */ 337 case CHAR: 338 c = ord(*wp++); 339 shf_putc(c, shf); 340 break; 341 case QCHAR: 342 c = ord(*wp++); 343 if (opmode & WDS_TPUTS) 344 switch (c) { 345 case ORD('\n'): 346 if (quotelevel == 0) { 347 c = ORD('\''); 348 shf_putc(c, shf); 349 shf_putc(ORD('\n'), shf); 350 } 351 break; 352 default: 353 if (quotelevel == 0) 354 /* FALLTHROUGH */ 355 case ORD('"'): 356 case ORD('`'): 357 case ORD('$'): 358 case ORD('\\'): 359 shf_putc(ORD('\\'), shf); 360 break; 361 } 362 shf_putc(c, shf); 363 break; 364 case COMASUB: 365 case COMSUB: 366 shf_puts("$(", shf); 367 cs = ")"; 368 if (ord(*wp) == ORD('(' /*)*/)) 369 shf_putc(' ', shf); 370 pSUB: 371 while ((c = *wp++) != 0) 372 shf_putc(c, shf); 373 shf_puts(cs, shf); 374 break; 375 case FUNASUB: 376 case FUNSUB: 377 c = ORD(' '); 378 if (0) 379 /* FALLTHROUGH */ 380 case VALSUB: 381 c = ORD('|'); 382 shf_putc('$', shf); 383 shf_putc('{', shf); 384 shf_putc(c, shf); 385 cs = ";}"; 386 goto pSUB; 387 case EXPRSUB: 388 shf_puts("$((", shf); 389 cs = "))"; 390 goto pSUB; 391 case OQUOTE: 392 if (opmode & WDS_TPUTS) { 393 quotelevel++; 394 shf_putc('"', shf); 395 } 396 break; 397 case CQUOTE: 398 if (opmode & WDS_TPUTS) { 399 if (quotelevel) 400 quotelevel--; 401 shf_putc('"', shf); 402 } 403 break; 404 case OSUBST: 405 shf_putc('$', shf); 406 if (ord(*wp++) == ORD('{')) 407 shf_putc('{', shf); 408 while ((c = *wp++) != 0) 409 shf_putc(c, shf); 410 wp = wdvarput(shf, wp, 0, opmode); 411 break; 412 case CSUBST: 413 if (ord(*wp++) == ORD('}')) { 414 wdvarput_csubst: 415 shf_putc('}', shf); 416 } 417 return (wp); 418 case OPAT: 419 shf_putchar(*wp++, shf); 420 shf_putc('(', shf); 421 break; 422 case SPAT: 423 c = ORD('|'); 424 if (0) 425 /* FALLTHROUGH */ 426 case CPAT: 427 c = ORD(/*(*/ ')'); 428 shf_putc(c, shf); 429 break; 430 } 431 } 432 433 /* 434 * this is the _only_ way to reliably handle 435 * variable args with an ANSI compiler 436 */ 437 /* VARARGS */ 438 void 439 fptreef(struct shf *shf, int indent, const char *fmt, ...) 440 { 441 va_list va; 442 443 va_start(va, fmt); 444 vfptreef(shf, indent, fmt, va); 445 va_end(va); 446 } 447 448 /* VARARGS */ 449 char * 450 snptreef(char *s, ssize_t n, const char *fmt, ...) 451 { 452 va_list va; 453 struct shf shf; 454 455 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf); 456 457 va_start(va, fmt); 458 vfptreef(&shf, 0, fmt, va); 459 va_end(va); 460 461 /* shf_sclose NUL terminates */ 462 return (shf_sclose(&shf)); 463 } 464 465 static void 466 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va) 467 { 468 int c; 469 470 while ((c = ord(*fmt++))) { 471 if (c == '%') { 472 switch ((c = ord(*fmt++))) { 473 case ORD('c'): 474 /* character (octet, probably) */ 475 shf_putchar(va_arg(va, int), shf); 476 break; 477 case ORD('s'): 478 /* string */ 479 shf_puts(va_arg(va, char *), shf); 480 break; 481 case ORD('S'): 482 /* word */ 483 wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS); 484 break; 485 case ORD('d'): 486 /* signed decimal */ 487 shf_fprintf(shf, Tf_d, va_arg(va, int)); 488 break; 489 case ORD('u'): 490 /* unsigned decimal */ 491 shf_fprintf(shf, "%u", va_arg(va, unsigned int)); 492 break; 493 case ORD('T'): 494 /* format tree */ 495 ptree(va_arg(va, struct op *), indent, shf); 496 goto dont_trash_prevent_semicolon; 497 case ORD(';'): 498 /* newline or ; */ 499 case ORD('N'): 500 /* newline or space */ 501 if (shf->flags & SHF_STRING) { 502 if ((unsigned int)c == ORD(';') && 503 !prevent_semicolon) 504 shf_putc(';', shf); 505 shf_putc(' ', shf); 506 } else { 507 int i; 508 509 shf_putc('\n', shf); 510 i = indent; 511 while (i >= 8) { 512 shf_putc('\t', shf); 513 i -= 8; 514 } 515 while (i--) 516 shf_putc(' ', shf); 517 } 518 break; 519 case ORD('R'): 520 /* I/O redirection */ 521 pioact(shf, va_arg(va, struct ioword *)); 522 break; 523 default: 524 shf_putc(c, shf); 525 break; 526 } 527 } else 528 shf_putc(c, shf); 529 prevent_semicolon = false; 530 dont_trash_prevent_semicolon: 531 ; 532 } 533 } 534 535 /* 536 * copy tree (for function definition) 537 */ 538 struct op * 539 tcopy(struct op *t, Area *ap) 540 { 541 struct op *r; 542 const char **tw; 543 char **rw; 544 545 if (t == NULL) 546 return (NULL); 547 548 r = alloc(sizeof(struct op), ap); 549 550 r->type = t->type; 551 r->u.evalflags = t->u.evalflags; 552 553 if (t->type == TCASE) 554 r->str = wdcopy(t->str, ap); 555 else 556 strdupx(r->str, t->str, ap); 557 558 if (t->vars == NULL) 559 r->vars = NULL; 560 else { 561 tw = (const char **)t->vars; 562 while (*tw) 563 ++tw; 564 rw = r->vars = alloc2(tw - (const char **)t->vars + 1, 565 sizeof(*tw), ap); 566 tw = (const char **)t->vars; 567 while (*tw) 568 *rw++ = wdcopy(*tw++, ap); 569 *rw = NULL; 570 } 571 572 if (t->args == NULL) 573 r->args = NULL; 574 else { 575 tw = t->args; 576 while (*tw) 577 ++tw; 578 r->args = (const char **)(rw = alloc2(tw - t->args + 1, 579 sizeof(*tw), ap)); 580 tw = t->args; 581 while (*tw) 582 *rw++ = wdcopy(*tw++, ap); 583 *rw = NULL; 584 } 585 586 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap); 587 588 r->left = tcopy(t->left, ap); 589 r->right = tcopy(t->right, ap); 590 r->lineno = t->lineno; 591 592 return (r); 593 } 594 595 char * 596 wdcopy(const char *wp, Area *ap) 597 { 598 size_t len; 599 600 len = wdscan(wp, EOS) - wp; 601 return (memcpy(alloc(len, ap), wp, len)); 602 } 603 604 /* return the position of prefix c in wp plus 1 */ 605 const char * 606 wdscan(const char *wp, int c) 607 { 608 int nest = 0; 609 610 while (/* CONSTCOND */ 1) 611 switch (*wp++) { 612 case EOS: 613 return (wp); 614 case ADELIM: 615 if (c == ADELIM && nest == 0) 616 return (wp + 1); 617 if (ord(*wp) == ORD(/*{*/ '}')) 618 goto wdscan_csubst; 619 /* FALLTHROUGH */ 620 case CHAR: 621 case QCHAR: 622 wp++; 623 break; 624 case COMASUB: 625 case COMSUB: 626 case FUNASUB: 627 case FUNSUB: 628 case VALSUB: 629 case EXPRSUB: 630 while (*wp++ != 0) 631 ; 632 break; 633 case OQUOTE: 634 case CQUOTE: 635 break; 636 case OSUBST: 637 nest++; 638 while (*wp++ != '\0') 639 ; 640 break; 641 case CSUBST: 642 wdscan_csubst: 643 wp++; 644 if (c == CSUBST && nest == 0) 645 return (wp); 646 nest--; 647 break; 648 case OPAT: 649 nest++; 650 wp++; 651 break; 652 case SPAT: 653 case CPAT: 654 if (c == wp[-1] && nest == 0) 655 return (wp); 656 if (wp[-1] == CPAT) 657 nest--; 658 break; 659 default: 660 internal_warningf( 661 "wdscan: unknown char 0x%X (carrying on)", 662 (unsigned char)wp[-1]); 663 } 664 } 665 666 /* 667 * return a copy of wp without any of the mark up characters and with 668 * quote characters (" ' \) stripped. (string is allocated from ATEMP) 669 */ 670 char * 671 wdstrip(const char *wp, int opmode) 672 { 673 struct shf shf; 674 675 shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf); 676 wdvarput(&shf, wp, 0, opmode); 677 /* shf_sclose NUL terminates */ 678 return (shf_sclose(&shf)); 679 } 680 681 static struct ioword ** 682 iocopy(struct ioword **iow, Area *ap) 683 { 684 struct ioword **ior; 685 int i; 686 687 ior = iow; 688 while (*ior) 689 ++ior; 690 ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap); 691 692 for (i = 0; iow[i] != NULL; i++) { 693 struct ioword *p, *q; 694 695 p = iow[i]; 696 q = alloc(sizeof(struct ioword), ap); 697 ior[i] = q; 698 *q = *p; 699 if (p->ioname != NULL) 700 q->ioname = wdcopy(p->ioname, ap); 701 if (p->delim != NULL) 702 q->delim = wdcopy(p->delim, ap); 703 if (p->heredoc != NULL) 704 strdupx(q->heredoc, p->heredoc, ap); 705 } 706 ior[i] = NULL; 707 708 return (ior); 709 } 710 711 /* 712 * free tree (for function definition) 713 */ 714 void 715 tfree(struct op *t, Area *ap) 716 { 717 char **w; 718 719 if (t == NULL) 720 return; 721 722 afree(t->str, ap); 723 724 if (t->vars != NULL) { 725 for (w = t->vars; *w != NULL; w++) 726 afree(*w, ap); 727 afree(t->vars, ap); 728 } 729 730 if (t->args != NULL) { 731 /*XXX we assume the caller is right */ 732 union mksh_ccphack cw; 733 734 cw.ro = t->args; 735 for (w = cw.rw; *w != NULL; w++) 736 afree(*w, ap); 737 afree(t->args, ap); 738 } 739 740 if (t->ioact != NULL) 741 iofree(t->ioact, ap); 742 743 tfree(t->left, ap); 744 tfree(t->right, ap); 745 746 afree(t, ap); 747 } 748 749 static void 750 iofree(struct ioword **iow, Area *ap) 751 { 752 struct ioword **iop; 753 struct ioword *p; 754 755 iop = iow; 756 while ((p = *iop++) != NULL) { 757 afree(p->ioname, ap); 758 afree(p->delim, ap); 759 afree(p->heredoc, ap); 760 afree(p, ap); 761 } 762 afree(iow, ap); 763 } 764 765 void 766 fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v) 767 { 768 if (isksh) 769 fptreef(shf, i, "%s %s %T", Tfunction, k, v); 770 else if (ktsearch(&keywords, k, hash(k))) 771 fptreef(shf, i, "%s %s() %T", Tfunction, k, v); 772 else 773 fptreef(shf, i, "%s() %T", k, v); 774 } 775 776 777 /* for jobs.c */ 778 void 779 vistree(char *dst, size_t sz, struct op *t) 780 { 781 unsigned int c; 782 char *cp, *buf; 783 size_t n; 784 785 buf = alloc(sz + 16, ATEMP); 786 snptreef(buf, sz + 16, Tf_T, t); 787 cp = buf; 788 vist_loop: 789 if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) { 790 if (c == 0 || n >= sz) 791 /* NUL or not enough free space */ 792 goto vist_out; 793 /* copy multibyte char */ 794 sz -= n; 795 while (n--) 796 *dst++ = *cp++; 797 goto vist_loop; 798 } 799 if (--sz == 0 || (c = ord(*cp++)) == 0) 800 /* NUL or not enough free space */ 801 goto vist_out; 802 if (ksh_isctrl(c)) { 803 /* C0 or C1 control character or DEL */ 804 if (--sz == 0) 805 /* not enough free space for two chars */ 806 goto vist_out; 807 *dst++ = '^'; 808 c = ksh_unctrl(c); 809 } else if (UTFMODE && rtt2asc(c) > 0x7F) { 810 /* better not try to display broken multibyte chars */ 811 /* also go easy on the Unicode: no U+FFFD here */ 812 c = ORD('?'); 813 } 814 *dst++ = c; 815 goto vist_loop; 816 817 vist_out: 818 *dst = '\0'; 819 afree(buf, ATEMP); 820 } 821 822 #ifdef DEBUG 823 void 824 dumpchar(struct shf *shf, int c) 825 { 826 if (ksh_isctrl(c)) { 827 /* C0 or C1 control character or DEL */ 828 shf_putc('^', shf); 829 c = ksh_unctrl(c); 830 } 831 shf_putc(c, shf); 832 } 833 834 /* see: wdvarput */ 835 static const char * 836 dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel) 837 { 838 int c; 839 840 while (/* CONSTCOND */ 1) { 841 switch(*wp++) { 842 case EOS: 843 shf_puts("EOS", shf); 844 return (--wp); 845 case ADELIM: 846 if (ord(*wp) == ORD(/*{*/ '}')) { 847 shf_puts(/*{*/ "]ADELIM(})", shf); 848 return (wp + 1); 849 } 850 shf_puts("ADELIM=", shf); 851 if (0) 852 /* FALLTHROUGH */ 853 case CHAR: 854 shf_puts("CHAR=", shf); 855 dumpchar(shf, *wp++); 856 break; 857 case QCHAR: 858 shf_puts("QCHAR<", shf); 859 c = ord(*wp++); 860 if (quotelevel == 0 || c == ORD('"') || 861 c == ORD('\\') || ctype(c, C_DOLAR | C_GRAVE)) 862 shf_putc('\\', shf); 863 dumpchar(shf, c); 864 goto closeandout; 865 case COMASUB: 866 shf_puts("COMASUB<", shf); 867 goto dumpsub; 868 case COMSUB: 869 shf_puts("COMSUB<", shf); 870 dumpsub: 871 while ((c = *wp++) != 0) 872 dumpchar(shf, c); 873 closeandout: 874 shf_putc('>', shf); 875 break; 876 case FUNASUB: 877 shf_puts("FUNASUB<", shf); 878 goto dumpsub; 879 case FUNSUB: 880 shf_puts("FUNSUB<", shf); 881 goto dumpsub; 882 case VALSUB: 883 shf_puts("VALSUB<", shf); 884 goto dumpsub; 885 case EXPRSUB: 886 shf_puts("EXPRSUB<", shf); 887 goto dumpsub; 888 case OQUOTE: 889 shf_fprintf(shf, "OQUOTE{%d" /*}*/, ++quotelevel); 890 break; 891 case CQUOTE: 892 shf_fprintf(shf, /*{*/ "%d}CQUOTE", quotelevel); 893 if (quotelevel) 894 quotelevel--; 895 else 896 shf_puts("(err)", shf); 897 break; 898 case OSUBST: 899 shf_puts("OSUBST(", shf); 900 dumpchar(shf, *wp++); 901 shf_puts(")[", shf); 902 while ((c = *wp++) != 0) 903 dumpchar(shf, c); 904 shf_putc('|', shf); 905 wp = dumpwdvar_i(shf, wp, 0); 906 break; 907 case CSUBST: 908 shf_puts("]CSUBST(", shf); 909 dumpchar(shf, *wp++); 910 shf_putc(')', shf); 911 return (wp); 912 case OPAT: 913 shf_puts("OPAT=", shf); 914 dumpchar(shf, *wp++); 915 break; 916 case SPAT: 917 shf_puts("SPAT", shf); 918 break; 919 case CPAT: 920 shf_puts("CPAT", shf); 921 break; 922 default: 923 shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]); 924 break; 925 } 926 shf_putc(' ', shf); 927 } 928 } 929 void 930 dumpwdvar(struct shf *shf, const char *wp) 931 { 932 dumpwdvar_i(shf, wp, 0); 933 } 934 935 void 936 dumpioact(struct shf *shf, struct op *t) 937 { 938 struct ioword **ioact, *iop; 939 940 if ((ioact = t->ioact) == NULL) 941 return; 942 943 shf_puts("{IOACT", shf); 944 while ((iop = *ioact++) != NULL) { 945 unsigned short type = iop->ioflag & IOTYPE; 946 #define DT(x) case x: shf_puts(#x, shf); break; 947 #define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf); 948 949 shf_putc(';', shf); 950 switch (type) { 951 DT(IOREAD) 952 DT(IOWRITE) 953 DT(IORDWR) 954 DT(IOHERE) 955 DT(IOCAT) 956 DT(IODUP) 957 default: 958 shf_fprintf(shf, "unk%d", type); 959 } 960 DB(IOEVAL) 961 DB(IOSKIP) 962 DB(IOCLOB) 963 DB(IORDUP) 964 DB(IONAMEXP) 965 DB(IOBASH) 966 DB(IOHERESTR) 967 DB(IONDELIM) 968 shf_fprintf(shf, ",unit=%d", (int)iop->unit); 969 if (iop->delim && !(iop->ioflag & IONDELIM)) { 970 shf_puts(",delim<", shf); 971 dumpwdvar(shf, iop->delim); 972 shf_putc('>', shf); 973 } 974 if (iop->ioname) { 975 if (iop->ioflag & IONAMEXP) { 976 shf_puts(",name=", shf); 977 print_value_quoted(shf, iop->ioname); 978 } else { 979 shf_puts(",name<", shf); 980 dumpwdvar(shf, iop->ioname); 981 shf_putc('>', shf); 982 } 983 } 984 if (iop->heredoc) { 985 shf_puts(",heredoc=", shf); 986 print_value_quoted(shf, iop->heredoc); 987 } 988 #undef DT 989 #undef DB 990 } 991 shf_putc('}', shf); 992 } 993 994 void 995 dumptree(struct shf *shf, struct op *t) 996 { 997 int i, j; 998 const char **w, *name; 999 struct op *t1; 1000 static int nesting; 1001 1002 for (i = 0; i < nesting; ++i) 1003 shf_putc('\t', shf); 1004 ++nesting; 1005 shf_puts("{tree:" /*}*/, shf); 1006 if (t == NULL) { 1007 name = "(null)"; 1008 goto out; 1009 } 1010 dumpioact(shf, t); 1011 switch (t->type) { 1012 #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/ 1013 1014 OPEN(TCOM) 1015 if (t->vars) { 1016 i = 0; 1017 w = (const char **)t->vars; 1018 while (*w) { 1019 shf_putc('\n', shf); 1020 for (j = 0; j < nesting; ++j) 1021 shf_putc('\t', shf); 1022 shf_fprintf(shf, " var%d<", i++); 1023 dumpwdvar(shf, *w++); 1024 shf_putc('>', shf); 1025 } 1026 } else 1027 shf_puts(" #no-vars#", shf); 1028 if (t->args) { 1029 i = 0; 1030 w = t->args; 1031 while (*w) { 1032 shf_putc('\n', shf); 1033 for (j = 0; j < nesting; ++j) 1034 shf_putc('\t', shf); 1035 shf_fprintf(shf, " arg%d<", i++); 1036 dumpwdvar(shf, *w++); 1037 shf_putc('>', shf); 1038 } 1039 } else 1040 shf_puts(" #no-args#", shf); 1041 break; 1042 OPEN(TEXEC) 1043 dumpleftandout: 1044 t = t->left; 1045 dumpandout: 1046 shf_putc('\n', shf); 1047 dumptree(shf, t); 1048 break; 1049 OPEN(TPAREN) 1050 goto dumpleftandout; 1051 OPEN(TPIPE) 1052 dumpleftmidrightandout: 1053 shf_putc('\n', shf); 1054 dumptree(shf, t->left); 1055 /* middumprightandout: (unused) */ 1056 shf_fprintf(shf, "/%s:", name); 1057 dumprightandout: 1058 t = t->right; 1059 goto dumpandout; 1060 OPEN(TLIST) 1061 goto dumpleftmidrightandout; 1062 OPEN(TOR) 1063 goto dumpleftmidrightandout; 1064 OPEN(TAND) 1065 goto dumpleftmidrightandout; 1066 OPEN(TBANG) 1067 goto dumprightandout; 1068 OPEN(TDBRACKET) 1069 i = 0; 1070 w = t->args; 1071 while (*w) { 1072 shf_putc('\n', shf); 1073 for (j = 0; j < nesting; ++j) 1074 shf_putc('\t', shf); 1075 shf_fprintf(shf, " arg%d<", i++); 1076 dumpwdvar(shf, *w++); 1077 shf_putc('>', shf); 1078 } 1079 break; 1080 OPEN(TFOR) 1081 dumpfor: 1082 shf_fprintf(shf, " str<%s>", t->str); 1083 if (t->vars != NULL) { 1084 i = 0; 1085 w = (const char **)t->vars; 1086 while (*w) { 1087 shf_putc('\n', shf); 1088 for (j = 0; j < nesting; ++j) 1089 shf_putc('\t', shf); 1090 shf_fprintf(shf, " var%d<", i++); 1091 dumpwdvar(shf, *w++); 1092 shf_putc('>', shf); 1093 } 1094 } 1095 goto dumpleftandout; 1096 OPEN(TSELECT) 1097 goto dumpfor; 1098 OPEN(TCASE) 1099 shf_fprintf(shf, " str<%s>", t->str); 1100 i = 0; 1101 for (t1 = t->left; t1 != NULL; t1 = t1->right) { 1102 shf_putc('\n', shf); 1103 for (j = 0; j < nesting; ++j) 1104 shf_putc('\t', shf); 1105 shf_fprintf(shf, " sub%d[(", i); 1106 w = (const char **)t1->vars; 1107 while (*w) { 1108 dumpwdvar(shf, *w); 1109 if (w[1] != NULL) 1110 shf_putc('|', shf); 1111 ++w; 1112 } 1113 shf_putc(')', shf); 1114 dumpioact(shf, t); 1115 shf_putc('\n', shf); 1116 dumptree(shf, t1->left); 1117 shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++); 1118 } 1119 break; 1120 OPEN(TWHILE) 1121 goto dumpleftmidrightandout; 1122 OPEN(TUNTIL) 1123 goto dumpleftmidrightandout; 1124 OPEN(TBRACE) 1125 goto dumpleftandout; 1126 OPEN(TCOPROC) 1127 goto dumpleftandout; 1128 OPEN(TASYNC) 1129 goto dumpleftandout; 1130 OPEN(TFUNCT) 1131 shf_fprintf(shf, " str<%s> ksh<%s>", t->str, 1132 t->u.ksh_func ? Ttrue : Tfalse); 1133 goto dumpleftandout; 1134 OPEN(TTIME) 1135 goto dumpleftandout; 1136 OPEN(TIF) 1137 dumpif: 1138 shf_putc('\n', shf); 1139 dumptree(shf, t->left); 1140 t = t->right; 1141 dumpioact(shf, t); 1142 if (t->left != NULL) { 1143 shf_puts(" /TTHEN:\n", shf); 1144 dumptree(shf, t->left); 1145 } 1146 if (t->right && t->right->type == TELIF) { 1147 shf_puts(" /TELIF:", shf); 1148 t = t->right; 1149 dumpioact(shf, t); 1150 goto dumpif; 1151 } 1152 if (t->right != NULL) { 1153 shf_puts(" /TELSE:\n", shf); 1154 dumptree(shf, t->right); 1155 } 1156 break; 1157 OPEN(TEOF) 1158 dumpunexpected: 1159 shf_puts(Tunexpected, shf); 1160 break; 1161 OPEN(TELIF) 1162 goto dumpunexpected; 1163 OPEN(TPAT) 1164 goto dumpunexpected; 1165 default: 1166 name = "TINVALID"; 1167 shf_fprintf(shf, "{T<%d>:" /*}*/, t->type); 1168 goto dumpunexpected; 1169 1170 #undef OPEN 1171 } 1172 out: 1173 shf_fprintf(shf, /*{*/ " /%s}\n", name); 1174 --nesting; 1175 } 1176 #endif 1177