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