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.72 2013/09/24 20:19:45 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 (ISCTRL(c & 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 = UNCTRL(c & 0x7F); 788 } else if (UTFMODE && c > 0x7F) { 789 /* better not try to display broken multibyte chars */ 790 /* also go easy on the Unicode: no U+FFFD here */ 791 c = '?'; 792 } 793 *dst++ = c; 794 goto vist_loop; 795 796 vist_out: 797 *dst = '\0'; 798 afree(buf, ATEMP); 799 } 800 801 #ifdef DEBUG 802 void 803 dumpchar(struct shf *shf, int c) 804 { 805 if (ISCTRL(c & 0x7F)) { 806 /* C0 or C1 control character or DEL */ 807 shf_putc((c & 0x80) ? '$' : '^', shf); 808 c = UNCTRL(c & 0x7F); 809 } 810 shf_putc(c, shf); 811 } 812 813 /* see: wdvarput */ 814 static const char * 815 dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel) 816 { 817 int c; 818 819 while (/* CONSTCOND */ 1) { 820 switch(*wp++) { 821 case EOS: 822 shf_puts("EOS", shf); 823 return (--wp); 824 case ADELIM: 825 shf_puts("ADELIM=", shf); 826 if (0) 827 case CHAR: 828 shf_puts("CHAR=", shf); 829 dumpchar(shf, *wp++); 830 break; 831 case QCHAR: 832 shf_puts("QCHAR<", shf); 833 c = *wp++; 834 if (quotelevel == 0 || 835 (c == '"' || c == '`' || c == '$' || c == '\\')) 836 shf_putc('\\', shf); 837 dumpchar(shf, c); 838 goto closeandout; 839 case COMSUB: 840 shf_puts("COMSUB<", shf); 841 dumpsub: 842 while ((c = *wp++) != 0) 843 dumpchar(shf, c); 844 closeandout: 845 shf_putc('>', shf); 846 break; 847 case FUNSUB: 848 shf_puts("FUNSUB<", shf); 849 goto dumpsub; 850 case VALSUB: 851 shf_puts("VALSUB<", shf); 852 goto dumpsub; 853 case EXPRSUB: 854 shf_puts("EXPRSUB<", shf); 855 goto dumpsub; 856 case OQUOTE: 857 shf_fprintf(shf, "OQUOTE{%d", ++quotelevel); 858 break; 859 case CQUOTE: 860 shf_fprintf(shf, "%d}CQUOTE", quotelevel); 861 if (quotelevel) 862 quotelevel--; 863 else 864 shf_puts("(err)", shf); 865 break; 866 case OSUBST: 867 shf_puts("OSUBST(", shf); 868 dumpchar(shf, *wp++); 869 shf_puts(")[", shf); 870 while ((c = *wp++) != 0) 871 dumpchar(shf, c); 872 shf_putc('|', shf); 873 wp = dumpwdvar_i(shf, wp, 0); 874 break; 875 case CSUBST: 876 shf_puts("]CSUBST(", shf); 877 dumpchar(shf, *wp++); 878 shf_putc(')', shf); 879 return (wp); 880 case OPAT: 881 shf_puts("OPAT=", shf); 882 dumpchar(shf, *wp++); 883 break; 884 case SPAT: 885 shf_puts("SPAT", shf); 886 break; 887 case CPAT: 888 shf_puts("CPAT", shf); 889 break; 890 default: 891 shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]); 892 break; 893 } 894 shf_putc(' ', shf); 895 } 896 } 897 void 898 dumpwdvar(struct shf *shf, const char *wp) 899 { 900 dumpwdvar_i(shf, wp, 0); 901 } 902 903 void 904 dumpioact(struct shf *shf, struct op *t) 905 { 906 struct ioword **ioact, *iop; 907 908 if ((ioact = t->ioact) == NULL) 909 return; 910 911 shf_puts("{IOACT", shf); 912 while ((iop = *ioact++) != NULL) { 913 int type = iop->flag & IOTYPE; 914 #define DT(x) case x: shf_puts(#x, shf); break; 915 #define DB(x) if (iop->flag & x) shf_puts("|" #x, shf); 916 917 shf_putc(';', shf); 918 switch (type) { 919 DT(IOREAD) 920 DT(IOWRITE) 921 DT(IORDWR) 922 DT(IOHERE) 923 DT(IOCAT) 924 DT(IODUP) 925 default: 926 shf_fprintf(shf, "unk%d", type); 927 } 928 DB(IOEVAL) 929 DB(IOSKIP) 930 DB(IOCLOB) 931 DB(IORDUP) 932 DB(IONAMEXP) 933 DB(IOBASH) 934 DB(IOHERESTR) 935 DB(IONDELIM) 936 shf_fprintf(shf, ",unit=%d", iop->unit); 937 if (iop->delim) { 938 shf_puts(",delim<", shf); 939 dumpwdvar(shf, iop->delim); 940 shf_putc('>', shf); 941 } 942 if (iop->name) { 943 if (iop->flag & IONAMEXP) { 944 shf_puts(",name=", shf); 945 print_value_quoted(shf, iop->name); 946 } else { 947 shf_puts(",name<", shf); 948 dumpwdvar(shf, iop->name); 949 shf_putc('>', shf); 950 } 951 } 952 if (iop->heredoc) { 953 shf_puts(",heredoc=", shf); 954 print_value_quoted(shf, iop->heredoc); 955 } 956 #undef DT 957 #undef DB 958 } 959 shf_putc('}', shf); 960 } 961 962 void 963 dumptree(struct shf *shf, struct op *t) 964 { 965 int i, j; 966 const char **w, *name; 967 struct op *t1; 968 static int nesting; 969 970 for (i = 0; i < nesting; ++i) 971 shf_putc('\t', shf); 972 ++nesting; 973 shf_puts("{tree:" /*}*/, shf); 974 if (t == NULL) { 975 name = "(null)"; 976 goto out; 977 } 978 dumpioact(shf, t); 979 switch (t->type) { 980 #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/ 981 982 OPEN(TCOM) 983 if (t->vars) { 984 i = 0; 985 w = (const char **)t->vars; 986 while (*w) { 987 shf_putc('\n', shf); 988 for (j = 0; j < nesting; ++j) 989 shf_putc('\t', shf); 990 shf_fprintf(shf, " var%d<", i++); 991 dumpwdvar(shf, *w++); 992 shf_putc('>', shf); 993 } 994 } else 995 shf_puts(" #no-vars#", shf); 996 if (t->args) { 997 i = 0; 998 w = t->args; 999 while (*w) { 1000 shf_putc('\n', shf); 1001 for (j = 0; j < nesting; ++j) 1002 shf_putc('\t', shf); 1003 shf_fprintf(shf, " arg%d<", i++); 1004 dumpwdvar(shf, *w++); 1005 shf_putc('>', shf); 1006 } 1007 } else 1008 shf_puts(" #no-args#", shf); 1009 break; 1010 OPEN(TEXEC) 1011 dumpleftandout: 1012 t = t->left; 1013 dumpandout: 1014 shf_putc('\n', shf); 1015 dumptree(shf, t); 1016 break; 1017 OPEN(TPAREN) 1018 goto dumpleftandout; 1019 OPEN(TPIPE) 1020 dumpleftmidrightandout: 1021 shf_putc('\n', shf); 1022 dumptree(shf, t->left); 1023 /* middumprightandout: (unused) */ 1024 shf_fprintf(shf, "/%s:", name); 1025 dumprightandout: 1026 t = t->right; 1027 goto dumpandout; 1028 OPEN(TLIST) 1029 goto dumpleftmidrightandout; 1030 OPEN(TOR) 1031 goto dumpleftmidrightandout; 1032 OPEN(TAND) 1033 goto dumpleftmidrightandout; 1034 OPEN(TBANG) 1035 goto dumprightandout; 1036 OPEN(TDBRACKET) 1037 i = 0; 1038 w = t->args; 1039 while (*w) { 1040 shf_putc('\n', shf); 1041 for (j = 0; j < nesting; ++j) 1042 shf_putc('\t', shf); 1043 shf_fprintf(shf, " arg%d<", i++); 1044 dumpwdvar(shf, *w++); 1045 shf_putc('>', shf); 1046 } 1047 break; 1048 OPEN(TFOR) 1049 dumpfor: 1050 shf_fprintf(shf, " str<%s>", t->str); 1051 if (t->vars != NULL) { 1052 i = 0; 1053 w = (const char **)t->vars; 1054 while (*w) { 1055 shf_putc('\n', shf); 1056 for (j = 0; j < nesting; ++j) 1057 shf_putc('\t', shf); 1058 shf_fprintf(shf, " var%d<", i++); 1059 dumpwdvar(shf, *w++); 1060 shf_putc('>', shf); 1061 } 1062 } 1063 goto dumpleftandout; 1064 OPEN(TSELECT) 1065 goto dumpfor; 1066 OPEN(TCASE) 1067 shf_fprintf(shf, " str<%s>", t->str); 1068 i = 0; 1069 for (t1 = t->left; t1 != NULL; t1 = t1->right) { 1070 shf_putc('\n', shf); 1071 for (j = 0; j < nesting; ++j) 1072 shf_putc('\t', shf); 1073 shf_fprintf(shf, " sub%d[(", i); 1074 w = (const char **)t1->vars; 1075 while (*w) { 1076 dumpwdvar(shf, *w); 1077 if (w[1] != NULL) 1078 shf_putc('|', shf); 1079 ++w; 1080 } 1081 shf_putc(')', shf); 1082 dumpioact(shf, t); 1083 shf_putc('\n', shf); 1084 dumptree(shf, t1->left); 1085 shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++); 1086 } 1087 break; 1088 OPEN(TWHILE) 1089 goto dumpleftmidrightandout; 1090 OPEN(TUNTIL) 1091 goto dumpleftmidrightandout; 1092 OPEN(TBRACE) 1093 goto dumpleftandout; 1094 OPEN(TCOPROC) 1095 goto dumpleftandout; 1096 OPEN(TASYNC) 1097 goto dumpleftandout; 1098 OPEN(TFUNCT) 1099 shf_fprintf(shf, " str<%s> ksh<%s>", t->str, 1100 t->u.ksh_func ? "yes" : "no"); 1101 goto dumpleftandout; 1102 OPEN(TTIME) 1103 goto dumpleftandout; 1104 OPEN(TIF) 1105 dumpif: 1106 shf_putc('\n', shf); 1107 dumptree(shf, t->left); 1108 t = t->right; 1109 dumpioact(shf, t); 1110 if (t->left != NULL) { 1111 shf_puts(" /TTHEN:\n", shf); 1112 dumptree(shf, t->left); 1113 } 1114 if (t->right && t->right->type == TELIF) { 1115 shf_puts(" /TELIF:", shf); 1116 t = t->right; 1117 dumpioact(shf, t); 1118 goto dumpif; 1119 } 1120 if (t->right != NULL) { 1121 shf_puts(" /TELSE:\n", shf); 1122 dumptree(shf, t->right); 1123 } 1124 break; 1125 OPEN(TEOF) 1126 dumpunexpected: 1127 shf_puts("unexpected", shf); 1128 break; 1129 OPEN(TELIF) 1130 goto dumpunexpected; 1131 OPEN(TPAT) 1132 goto dumpunexpected; 1133 default: 1134 name = "TINVALID"; 1135 shf_fprintf(shf, "{T<%d>:" /*}*/, t->type); 1136 goto dumpunexpected; 1137 1138 #undef OPEN 1139 } 1140 out: 1141 shf_fprintf(shf, /*{*/ " /%s}\n", name); 1142 --nesting; 1143 } 1144 #endif 1145