1 /* $NetBSD: tree.c,v 1.6 2005/06/26 19:09:00 christos Exp $ */ 2 3 /* 4 * command tree climbing 5 */ 6 #include <sys/cdefs.h> 7 8 #ifndef lint 9 __RCSID("$NetBSD: tree.c,v 1.6 2005/06/26 19:09:00 christos Exp $"); 10 #endif 11 12 13 #include "sh.h" 14 15 #define INDENT 4 16 17 #define tputc(c, shf) shf_putchar(c, shf); 18 static void ptree ARGS((struct op *t, int indent, struct shf *f)); 19 static void pioact ARGS((struct shf *f, int indent, struct ioword *iop)); 20 static void tputC ARGS((int c, struct shf *shf)); 21 static void tputS ARGS((char *wp, struct shf *shf)); 22 static void vfptreef ARGS((struct shf *shf, int indent, const char *fmt, va_list va)); 23 static struct ioword **iocopy ARGS((struct ioword **iow, Area *ap)); 24 static void iofree ARGS((struct ioword **iow, Area *ap)); 25 26 /* 27 * print a command tree 28 */ 29 30 static void 31 ptree(t, indent, shf) 32 register struct op *t; 33 int indent; 34 register struct shf *shf; 35 { 36 register char **w; 37 struct ioword **ioact; 38 struct op *t1; 39 40 Chain: 41 if (t == NULL) 42 return; 43 switch (t->type) { 44 case TCOM: 45 if (t->vars) 46 for (w = t->vars; *w != NULL; ) 47 fptreef(shf, indent, "%S ", *w++); 48 else 49 fptreef(shf, indent, "#no-vars# "); 50 if (t->args) 51 for (w = t->args; *w != NULL; ) 52 fptreef(shf, indent, "%S ", *w++); 53 else 54 fptreef(shf, indent, "#no-args# "); 55 break; 56 case TEXEC: 57 #if 0 /* ?not useful - can't be called? */ 58 /* Print original vars */ 59 if (t->left->vars) 60 for (w = t->left->vars; *w != NULL; ) 61 fptreef(shf, indent, "%S ", *w++); 62 else 63 fptreef(shf, indent, "#no-vars# "); 64 /* Print expanded vars */ 65 if (t->args) 66 for (w = t->args; *w != NULL; ) 67 fptreef(shf, indent, "%s ", *w++); 68 else 69 fptreef(shf, indent, "#no-args# "); 70 /* Print original io */ 71 t = t->left; 72 #else 73 t = t->left; 74 goto Chain; 75 #endif 76 case TPAREN: 77 fptreef(shf, indent + 2, "( %T) ", t->left); 78 break; 79 case TPIPE: 80 fptreef(shf, indent, "%T| ", t->left); 81 t = t->right; 82 goto Chain; 83 case TLIST: 84 fptreef(shf, indent, "%T%;", t->left); 85 t = t->right; 86 goto Chain; 87 case TOR: 88 case TAND: 89 fptreef(shf, indent, "%T%s %T", 90 t->left, (t->type==TOR) ? "||" : "&&", t->right); 91 break; 92 case TBANG: 93 fptreef(shf, indent, "! "); 94 t = t->right; 95 goto Chain; 96 case TDBRACKET: 97 { 98 int i; 99 100 fptreef(shf, indent, "[["); 101 for (i = 0; t->args[i]; i++) 102 fptreef(shf, indent, " %S", t->args[i]); 103 fptreef(shf, indent, " ]] "); 104 break; 105 } 106 #ifdef KSH 107 case TSELECT: 108 fptreef(shf, indent, "select %s ", t->str); 109 /* fall through */ 110 #endif /* KSH */ 111 case TFOR: 112 if (t->type == TFOR) 113 fptreef(shf, indent, "for %s ", t->str); 114 if (t->vars != NULL) { 115 fptreef(shf, indent, "in "); 116 for (w = t->vars; *w; ) 117 fptreef(shf, indent, "%S ", *w++); 118 fptreef(shf, indent, "%;"); 119 } 120 fptreef(shf, indent + INDENT, "do%N%T", t->left); 121 fptreef(shf, indent, "%;done "); 122 break; 123 case TCASE: 124 fptreef(shf, indent, "case %S in", t->str); 125 for (t1 = t->left; t1 != NULL; t1 = t1->right) { 126 fptreef(shf, indent, "%N("); 127 for (w = t1->vars; *w != NULL; w++) 128 fptreef(shf, indent, "%S%c", *w, 129 (w[1] != NULL) ? '|' : ')'); 130 fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left); 131 } 132 fptreef(shf, indent, "%Nesac "); 133 break; 134 case TIF: 135 case TELIF: 136 /* 3 == strlen("if ") */ 137 fptreef(shf, indent + 3, "if %T", t->left); 138 for (;;) { 139 t = t->right; 140 if (t->left != NULL) { 141 fptreef(shf, indent, "%;"); 142 fptreef(shf, indent + INDENT, "then%N%T", 143 t->left); 144 } 145 if (t->right == NULL || t->right->type != TELIF) 146 break; 147 t = t->right; 148 fptreef(shf, indent, "%;"); 149 /* 5 == strlen("elif ") */ 150 fptreef(shf, indent + 5, "elif %T", t->left); 151 } 152 if (t->right != NULL) { 153 fptreef(shf, indent, "%;"); 154 fptreef(shf, indent + INDENT, "else%;%T", t->right); 155 } 156 fptreef(shf, indent, "%;fi "); 157 break; 158 case TWHILE: 159 case TUNTIL: 160 /* 6 == strlen("while"/"until") */ 161 fptreef(shf, indent + 6, "%s %T", 162 (t->type==TWHILE) ? "while" : "until", 163 t->left); 164 fptreef(shf, indent, "%;do"); 165 fptreef(shf, indent + INDENT, "%;%T", t->right); 166 fptreef(shf, indent, "%;done "); 167 break; 168 case TBRACE: 169 fptreef(shf, indent + INDENT, "{%;%T", t->left); 170 fptreef(shf, indent, "%;} "); 171 break; 172 case TCOPROC: 173 fptreef(shf, indent, "%T|& ", t->left); 174 break; 175 case TASYNC: 176 fptreef(shf, indent, "%T& ", t->left); 177 break; 178 case TFUNCT: 179 fptreef(shf, indent, 180 t->u.ksh_func ? "function %s %T" : "%s() %T", 181 t->str, t->left); 182 break; 183 case TTIME: 184 fptreef(shf, indent, "time %T", t->left); 185 break; 186 default: 187 fptreef(shf, indent, "<botch>"); 188 break; 189 } 190 if ((ioact = t->ioact) != NULL) { 191 int need_nl = 0; 192 193 while (*ioact != NULL) 194 pioact(shf, indent, *ioact++); 195 /* Print here documents after everything else... */ 196 for (ioact = t->ioact; *ioact != NULL; ) { 197 struct ioword *iop = *ioact++; 198 199 /* heredoc is 0 when tracing (set -x) */ 200 if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) { 201 tputc('\n', shf); 202 shf_puts(iop->heredoc, shf); 203 fptreef(shf, indent, "%s", 204 evalstr(iop->delim, 0)); 205 need_nl = 1; 206 } 207 } 208 /* Last delimiter must be followed by a newline (this often 209 * leads to an extra blank line, but its not worth worrying 210 * about) 211 */ 212 if (need_nl) 213 tputc('\n', shf); 214 } 215 } 216 217 static void 218 pioact(shf, indent, iop) 219 register struct shf *shf; 220 int indent; 221 register struct ioword *iop; 222 { 223 int flag = iop->flag; 224 int type = flag & IOTYPE; 225 int expected; 226 227 expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 228 : (type == IOCAT || type == IOWRITE) ? 1 229 : (type == IODUP && (iop->unit == !(flag & IORDUP))) ? 230 iop->unit 231 : iop->unit + 1; 232 if (iop->unit != expected) 233 tputc('0' + iop->unit, shf); 234 235 switch (type) { 236 case IOREAD: 237 fptreef(shf, indent, "< "); 238 break; 239 case IOHERE: 240 if (flag&IOSKIP) 241 fptreef(shf, indent, "<<- "); 242 else 243 fptreef(shf, indent, "<< "); 244 break; 245 case IOCAT: 246 fptreef(shf, indent, ">> "); 247 break; 248 case IOWRITE: 249 if (flag&IOCLOB) 250 fptreef(shf, indent, ">| "); 251 else 252 fptreef(shf, indent, "> "); 253 break; 254 case IORDWR: 255 fptreef(shf, indent, "<> "); 256 break; 257 case IODUP: 258 if (flag & IORDUP) 259 fptreef(shf, indent, "<&"); 260 else 261 fptreef(shf, indent, ">&"); 262 break; 263 } 264 /* name/delim are 0 when printing syntax errors */ 265 if (type == IOHERE) { 266 if (iop->delim) 267 fptreef(shf, indent, "%S ", iop->delim); 268 } else if (iop->name) 269 fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ", 270 iop->name); 271 } 272 273 274 /* 275 * variants of fputc, fputs for ptreef and snptreef 276 */ 277 278 static void 279 tputC(c, shf) 280 register int c; 281 register struct shf *shf; 282 { 283 if ((c&0x60) == 0) { /* C0|C1 */ 284 tputc((c&0x80) ? '$' : '^', shf); 285 tputc(((c&0x7F)|0x40), shf); 286 } else if ((c&0x7F) == 0x7F) { /* DEL */ 287 tputc((c&0x80) ? '$' : '^', shf); 288 tputc('?', shf); 289 } else 290 tputc(c, shf); 291 } 292 293 static void 294 tputS(wp, shf) 295 register char *wp; 296 register struct shf *shf; 297 { 298 register int c, quoted=0; 299 300 /* problems: 301 * `...` -> $(...) 302 * 'foo' -> "foo" 303 * could change encoding to: 304 * OQUOTE ["'] ... CQUOTE ["'] 305 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case) 306 */ 307 while (1) 308 switch ((c = *wp++)) { 309 case EOS: 310 return; 311 case CHAR: 312 tputC(*wp++, shf); 313 break; 314 case QCHAR: 315 c = *wp++; 316 if (!quoted || (c == '"' || c == '`' || c == '$')) 317 tputc('\\', shf); 318 tputC(c, shf); 319 break; 320 case COMSUB: 321 tputc('$', shf); 322 tputc('(', shf); 323 while (*wp != 0) 324 tputC(*wp++, shf); 325 tputc(')', shf); 326 wp++; 327 break; 328 case EXPRSUB: 329 tputc('$', shf); 330 tputc('(', shf); 331 tputc('(', shf); 332 while (*wp != 0) 333 tputC(*wp++, shf); 334 tputc(')', shf); 335 tputc(')', shf); 336 wp++; 337 break; 338 case OQUOTE: 339 quoted = 1; 340 tputc('"', shf); 341 break; 342 case CQUOTE: 343 quoted = 0; 344 tputc('"', shf); 345 break; 346 case OSUBST: 347 tputc('$', shf); 348 if (*wp++ == '{') 349 tputc('{', shf); 350 while ((c = *wp++) != 0) 351 tputC(c, shf); 352 break; 353 case CSUBST: 354 if (*wp++ == '}') 355 tputc('}', shf); 356 break; 357 #ifdef KSH 358 case OPAT: 359 tputc(*wp++, shf); 360 tputc('(', shf); 361 break; 362 case SPAT: 363 tputc('|', shf); 364 break; 365 case CPAT: 366 tputc(')', shf); 367 break; 368 #endif /* KSH */ 369 } 370 } 371 372 /* 373 * this is the _only_ way to reliably handle 374 * variable args with an ANSI compiler 375 */ 376 /* VARARGS */ 377 int 378 #ifdef HAVE_PROTOTYPES 379 fptreef(struct shf *shf, int indent, const char *fmt, ...) 380 #else 381 fptreef(shf, indent, fmt, va_alist) 382 struct shf *shf; 383 int indent; 384 const char *fmt; 385 va_dcl 386 #endif 387 { 388 va_list va; 389 390 SH_VA_START(va, fmt); 391 392 vfptreef(shf, indent, fmt, va); 393 va_end(va); 394 return 0; 395 } 396 397 /* VARARGS */ 398 char * 399 #ifdef HAVE_PROTOTYPES 400 snptreef(char *s, int n, const char *fmt, ...) 401 #else 402 snptreef(s, n, fmt, va_alist) 403 char *s; 404 int n; 405 const char *fmt; 406 va_dcl 407 #endif 408 { 409 va_list va; 410 struct shf shf; 411 412 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf); 413 414 SH_VA_START(va, fmt); 415 vfptreef(&shf, 0, fmt, va); 416 va_end(va); 417 418 return shf_sclose(&shf); /* null terminates */ 419 } 420 421 static void 422 vfptreef(shf, indent, fmt, va) 423 register struct shf *shf; 424 int indent; 425 const char *fmt; 426 register va_list va; 427 { 428 register int c; 429 430 while ((c = *fmt++)) 431 if (c == '%') { 432 register long n; 433 register char *p; 434 int neg; 435 436 switch ((c = *fmt++)) { 437 case 'c': 438 tputc(va_arg(va, int), shf); 439 break; 440 case 's': 441 p = va_arg(va, char *); 442 while (*p) 443 tputc(*p++, shf); 444 break; 445 case 'S': /* word */ 446 p = va_arg(va, char *); 447 tputS(p, shf); 448 break; 449 case 'd': case 'u': /* decimal */ 450 n = (c == 'd') ? va_arg(va, int) 451 : va_arg(va, unsigned int); 452 neg = c=='d' && n<0; 453 p = ulton((neg) ? -n : n, 10); 454 if (neg) 455 *--p = '-'; 456 while (*p) 457 tputc(*p++, shf); 458 break; 459 case 'T': /* format tree */ 460 ptree(va_arg(va, struct op *), indent, shf); 461 break; 462 case ';': /* newline or ; */ 463 case 'N': /* newline or space */ 464 if (shf->flags & SHF_STRING) { 465 if (c == ';') 466 tputc(';', shf); 467 tputc(' ', shf); 468 } else { 469 int i; 470 471 tputc('\n', shf); 472 for (i = indent; i >= 8; i -= 8) 473 tputc('\t', shf); 474 for (; i > 0; --i) 475 tputc(' ', shf); 476 } 477 break; 478 case 'R': 479 pioact(shf, indent, va_arg(va, struct ioword *)); 480 break; 481 default: 482 tputc(c, shf); 483 break; 484 } 485 } else 486 tputc(c, shf); 487 } 488 489 /* 490 * copy tree (for function definition) 491 */ 492 493 struct op * 494 tcopy(t, ap) 495 register struct op *t; 496 Area *ap; 497 { 498 register struct op *r; 499 register char **tw, **rw; 500 501 if (t == NULL) 502 return NULL; 503 504 r = (struct op *) alloc(sizeof(struct op), ap); 505 506 r->type = t->type; 507 r->u.evalflags = t->u.evalflags; 508 509 r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap); 510 511 if (t->vars == NULL) 512 r->vars = NULL; 513 else { 514 for (tw = t->vars; *tw++ != NULL; ) 515 ; 516 rw = r->vars = (char **) 517 alloc((tw - t->vars + 1) * sizeof(*tw), ap); 518 for (tw = t->vars; *tw != NULL; ) 519 *rw++ = wdcopy(*tw++, ap); 520 *rw = NULL; 521 } 522 523 if (t->args == NULL) 524 r->args = NULL; 525 else { 526 for (tw = t->args; *tw++ != NULL; ) 527 ; 528 rw = r->args = (char **) 529 alloc((tw - t->args + 1) * sizeof(*tw), ap); 530 for (tw = t->args; *tw != NULL; ) 531 *rw++ = wdcopy(*tw++, ap); 532 *rw = NULL; 533 } 534 535 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap); 536 537 r->left = tcopy(t->left, ap); 538 r->right = tcopy(t->right, ap); 539 r->lineno = t->lineno; 540 541 return r; 542 } 543 544 char * 545 wdcopy(wp, ap) 546 const char *wp; 547 Area *ap; 548 { 549 size_t len = wdscan(wp, EOS) - wp; 550 return memcpy(alloc(len, ap), wp, len); 551 } 552 553 /* return the position of prefix c in wp plus 1 */ 554 char * 555 wdscan(wp, c) 556 register const char *wp; 557 register int c; 558 { 559 register int nest = 0; 560 561 while (1) 562 switch (*wp++) { 563 case EOS: 564 return (char *) __UNCONST(wp); 565 case CHAR: 566 case QCHAR: 567 wp++; 568 break; 569 case COMSUB: 570 case EXPRSUB: 571 while (*wp++ != 0) 572 ; 573 break; 574 case OQUOTE: 575 case CQUOTE: 576 break; 577 case OSUBST: 578 nest++; 579 while (*wp++ != '\0') 580 ; 581 break; 582 case CSUBST: 583 wp++; 584 if (c == CSUBST && nest == 0) 585 return (char *) __UNCONST(wp); 586 nest--; 587 break; 588 #ifdef KSH 589 case OPAT: 590 nest++; 591 wp++; 592 break; 593 case SPAT: 594 case CPAT: 595 if (c == wp[-1] && nest == 0) 596 return (char *) __UNCONST(wp); 597 if (wp[-1] == CPAT) 598 nest--; 599 break; 600 #endif /* KSH */ 601 default: 602 internal_errorf(0, 603 "wdscan: unknown char 0x%x (carrying on)", 604 wp[-1]); 605 } 606 } 607 608 /* return a copy of wp without any of the mark up characters and 609 * with quote characters (" ' \) stripped. 610 * (string is allocated from ATEMP) 611 */ 612 char * 613 wdstrip(wp) 614 const char *wp; 615 { 616 struct shf shf; 617 int c; 618 619 shf_sopen((char *) 0, 32, SHF_WR | SHF_DYNAMIC, &shf); 620 621 /* problems: 622 * `...` -> $(...) 623 * x${foo:-"hi"} -> x${foo:-hi} 624 * x${foo:-'hi'} -> x${foo:-hi} 625 */ 626 while (1) 627 switch ((c = *wp++)) { 628 case EOS: 629 return shf_sclose(&shf); /* null terminates */ 630 case CHAR: 631 case QCHAR: 632 shf_putchar(*wp++, &shf); 633 break; 634 case COMSUB: 635 shf_putchar('$', &shf); 636 shf_putchar('(', &shf); 637 while (*wp != 0) 638 shf_putchar(*wp++, &shf); 639 shf_putchar(')', &shf); 640 break; 641 case EXPRSUB: 642 shf_putchar('$', &shf); 643 shf_putchar('(', &shf); 644 shf_putchar('(', &shf); 645 while (*wp != 0) 646 shf_putchar(*wp++, &shf); 647 shf_putchar(')', &shf); 648 shf_putchar(')', &shf); 649 break; 650 case OQUOTE: 651 break; 652 case CQUOTE: 653 break; 654 case OSUBST: 655 shf_putchar('$', &shf); 656 if (*wp++ == '{') 657 shf_putchar('{', &shf); 658 while ((c = *wp++) != 0) 659 shf_putchar(c, &shf); 660 break; 661 case CSUBST: 662 if (*wp++ == '}') 663 shf_putchar('}', &shf); 664 break; 665 #ifdef KSH 666 case OPAT: 667 shf_putchar(*wp++, &shf); 668 shf_putchar('(', &shf); 669 break; 670 case SPAT: 671 shf_putchar('|', &shf); 672 break; 673 case CPAT: 674 shf_putchar(')', &shf); 675 break; 676 #endif /* KSH */ 677 } 678 } 679 680 static struct ioword ** 681 iocopy(iow, ap) 682 register struct ioword **iow; 683 Area *ap; 684 { 685 register struct ioword **ior; 686 register int i; 687 688 for (ior = iow; *ior++ != NULL; ) 689 ; 690 ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap); 691 692 for (i = 0; iow[i] != NULL; i++) { 693 register struct ioword *p, *q; 694 695 p = iow[i]; 696 q = (struct ioword *) alloc(sizeof(*p), ap); 697 ior[i] = q; 698 *q = *p; 699 if (p->name != (char *) 0) 700 q->name = wdcopy(p->name, ap); 701 if (p->delim != (char *) 0) 702 q->delim = wdcopy(p->delim, ap); 703 if (p->heredoc != (char *) 0) 704 q->heredoc = str_save(p->heredoc, ap); 705 } 706 ior[i] = NULL; 707 708 return ior; 709 } 710 711 /* 712 * free tree (for function definition) 713 */ 714 715 void 716 tfree(t, ap) 717 register struct op *t; 718 Area *ap; 719 { 720 register char **w; 721 722 if (t == NULL) 723 return; 724 725 if (t->str != NULL) 726 afree((void*)t->str, ap); 727 728 if (t->vars != NULL) { 729 for (w = t->vars; *w != NULL; w++) 730 afree((void*)*w, ap); 731 afree((void*)t->vars, ap); 732 } 733 734 if (t->args != NULL) { 735 for (w = t->args; *w != NULL; w++) 736 afree((void*)*w, ap); 737 afree((void*)t->args, ap); 738 } 739 740 if (t->ioact != NULL) 741 iofree(t->ioact, ap); 742 743 tfree(t->left, ap); 744 tfree(t->right, ap); 745 746 afree((void*)t, ap); 747 } 748 749 static void 750 iofree(iow, ap) 751 struct ioword **iow; 752 Area *ap; 753 { 754 register struct ioword **iop; 755 register struct ioword *p; 756 757 for (iop = iow; (p = *iop++) != NULL; ) { 758 if (p->name != NULL) 759 afree((void*)p->name, ap); 760 if (p->delim != NULL) 761 afree((void*)p->delim, ap); 762 if (p->heredoc != NULL) 763 afree((void*)p->heredoc, ap); 764 afree((void*)p, ap); 765 } 766 } 767