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