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