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