1 /* $NetBSD: tree.c,v 1.9 2018/05/08 16:37:59 kamil Exp $ */ 2 3 /* 4 * command tree climbing 5 */ 6 #include <sys/cdefs.h> 7 8 #ifndef lint 9 __RCSID("$NetBSD: tree.c,v 1.9 2018/05/08 16:37:59 kamil 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 struct op *t; 33 int indent; 34 struct shf *shf; 35 { 36 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 struct shf *shf; 220 int indent; 221 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 int c; 281 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 char *wp; 296 struct shf *shf; 297 { 298 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 fptreef(struct shf *shf, int indent, const char *fmt, ...) 379 { 380 va_list va; 381 382 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 snptreef(char *s, int n, const char *fmt, ...) 392 { 393 va_list va; 394 struct shf shf; 395 396 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf); 397 398 va_start(va, fmt); 399 vfptreef(&shf, 0, fmt, va); 400 va_end(va); 401 402 return shf_sclose(&shf); /* null terminates */ 403 } 404 405 static void 406 vfptreef(shf, indent, fmt, va) 407 struct shf *shf; 408 int indent; 409 const char *fmt; 410 va_list va; 411 { 412 int c; 413 414 while ((c = *fmt++)) 415 if (c == '%') { 416 long n; 417 char *p; 418 int neg; 419 420 switch ((c = *fmt++)) { 421 case 'c': 422 tputc(va_arg(va, int), shf); 423 break; 424 case 's': 425 p = va_arg(va, char *); 426 while (*p) 427 tputc(*p++, shf); 428 break; 429 case 'S': /* word */ 430 p = va_arg(va, char *); 431 tputS(p, shf); 432 break; 433 case 'd': case 'u': /* decimal */ 434 n = (c == 'd') ? va_arg(va, int) 435 : va_arg(va, unsigned int); 436 neg = c=='d' && n<0; 437 p = ulton((neg) ? -n : n, 10); 438 if (neg) 439 *--p = '-'; 440 while (*p) 441 tputc(*p++, shf); 442 break; 443 case 'T': /* format tree */ 444 ptree(va_arg(va, struct op *), indent, shf); 445 break; 446 case ';': /* newline or ; */ 447 case 'N': /* newline or space */ 448 if (shf->flags & SHF_STRING) { 449 if (c == ';') 450 tputc(';', shf); 451 tputc(' ', shf); 452 } else { 453 int i; 454 455 tputc('\n', shf); 456 for (i = indent; i >= 8; i -= 8) 457 tputc('\t', shf); 458 for (; i > 0; --i) 459 tputc(' ', shf); 460 } 461 break; 462 case 'R': 463 pioact(shf, indent, va_arg(va, struct ioword *)); 464 break; 465 default: 466 tputc(c, shf); 467 break; 468 } 469 } else 470 tputc(c, shf); 471 } 472 473 /* 474 * copy tree (for function definition) 475 */ 476 477 struct op * 478 tcopy(t, ap) 479 struct op *t; 480 Area *ap; 481 { 482 struct op *r; 483 char **tw, **rw; 484 485 if (t == NULL) 486 return NULL; 487 488 r = (struct op *) alloc(sizeof(struct op), ap); 489 490 r->type = t->type; 491 r->u.evalflags = t->u.evalflags; 492 493 r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap); 494 495 if (t->vars == NULL) 496 r->vars = NULL; 497 else { 498 for (tw = t->vars; *tw++ != NULL; ) 499 ; 500 rw = r->vars = (char **) 501 alloc((tw - t->vars + 1) * sizeof(*tw), ap); 502 for (tw = t->vars; *tw != NULL; ) 503 *rw++ = wdcopy(*tw++, ap); 504 *rw = NULL; 505 } 506 507 if (t->args == NULL) 508 r->args = NULL; 509 else { 510 for (tw = t->args; *tw++ != NULL; ) 511 ; 512 rw = r->args = (char **) 513 alloc((tw - t->args + 1) * sizeof(*tw), ap); 514 for (tw = t->args; *tw != NULL; ) 515 *rw++ = wdcopy(*tw++, ap); 516 *rw = NULL; 517 } 518 519 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap); 520 521 r->left = tcopy(t->left, ap); 522 r->right = tcopy(t->right, ap); 523 r->lineno = t->lineno; 524 525 return r; 526 } 527 528 char * 529 wdcopy(wp, ap) 530 const char *wp; 531 Area *ap; 532 { 533 size_t len = wdscan(wp, EOS) - wp; 534 return memcpy(alloc(len, ap), wp, len); 535 } 536 537 /* return the position of prefix c in wp plus 1 */ 538 char * 539 wdscan(wp, c) 540 const char *wp; 541 int c; 542 { 543 int nest = 0; 544 545 while (1) 546 switch (*wp++) { 547 case EOS: 548 return (char *) __UNCONST(wp); 549 case CHAR: 550 case QCHAR: 551 wp++; 552 break; 553 case COMSUB: 554 case EXPRSUB: 555 while (*wp++ != 0) 556 ; 557 break; 558 case OQUOTE: 559 case CQUOTE: 560 break; 561 case OSUBST: 562 nest++; 563 while (*wp++ != '\0') 564 ; 565 break; 566 case CSUBST: 567 wp++; 568 if (c == CSUBST && nest == 0) 569 return (char *) __UNCONST(wp); 570 nest--; 571 break; 572 #ifdef KSH 573 case OPAT: 574 nest++; 575 wp++; 576 break; 577 case SPAT: 578 case CPAT: 579 if (c == wp[-1] && nest == 0) 580 return (char *) __UNCONST(wp); 581 if (wp[-1] == CPAT) 582 nest--; 583 break; 584 #endif /* KSH */ 585 default: 586 internal_errorf(0, 587 "wdscan: unknown char 0x%x (carrying on)", 588 wp[-1]); 589 } 590 } 591 592 /* return a copy of wp without any of the mark up characters and 593 * with quote characters (" ' \) stripped. 594 * (string is allocated from ATEMP) 595 */ 596 char * 597 wdstrip(wp) 598 const char *wp; 599 { 600 struct shf shf; 601 int c; 602 603 shf_sopen((char *) 0, 32, SHF_WR | SHF_DYNAMIC, &shf); 604 605 /* problems: 606 * `...` -> $(...) 607 * x${foo:-"hi"} -> x${foo:-hi} 608 * x${foo:-'hi'} -> x${foo:-hi} 609 */ 610 while (1) 611 switch ((c = *wp++)) { 612 case EOS: 613 return shf_sclose(&shf); /* null terminates */ 614 case CHAR: 615 case QCHAR: 616 shf_putchar(*wp++, &shf); 617 break; 618 case COMSUB: 619 shf_putchar('$', &shf); 620 shf_putchar('(', &shf); 621 while (*wp != 0) 622 shf_putchar(*wp++, &shf); 623 shf_putchar(')', &shf); 624 break; 625 case EXPRSUB: 626 shf_putchar('$', &shf); 627 shf_putchar('(', &shf); 628 shf_putchar('(', &shf); 629 while (*wp != 0) 630 shf_putchar(*wp++, &shf); 631 shf_putchar(')', &shf); 632 shf_putchar(')', &shf); 633 break; 634 case OQUOTE: 635 break; 636 case CQUOTE: 637 break; 638 case OSUBST: 639 shf_putchar('$', &shf); 640 if (*wp++ == '{') 641 shf_putchar('{', &shf); 642 while ((c = *wp++) != 0) 643 shf_putchar(c, &shf); 644 break; 645 case CSUBST: 646 if (*wp++ == '}') 647 shf_putchar('}', &shf); 648 break; 649 #ifdef KSH 650 case OPAT: 651 shf_putchar(*wp++, &shf); 652 shf_putchar('(', &shf); 653 break; 654 case SPAT: 655 shf_putchar('|', &shf); 656 break; 657 case CPAT: 658 shf_putchar(')', &shf); 659 break; 660 #endif /* KSH */ 661 } 662 } 663 664 static struct ioword ** 665 iocopy(iow, ap) 666 struct ioword **iow; 667 Area *ap; 668 { 669 struct ioword **ior; 670 int i; 671 672 for (ior = iow; *ior++ != NULL; ) 673 ; 674 ior = (struct ioword **) alloc((ior - iow + 1) * sizeof(*ior), ap); 675 676 for (i = 0; iow[i] != NULL; i++) { 677 struct ioword *p, *q; 678 679 p = iow[i]; 680 q = (struct ioword *) alloc(sizeof(*p), ap); 681 ior[i] = q; 682 *q = *p; 683 if (p->name != (char *) 0) 684 q->name = wdcopy(p->name, ap); 685 if (p->delim != (char *) 0) 686 q->delim = wdcopy(p->delim, ap); 687 if (p->heredoc != (char *) 0) 688 q->heredoc = str_save(p->heredoc, ap); 689 } 690 ior[i] = NULL; 691 692 return ior; 693 } 694 695 /* 696 * free tree (for function definition) 697 */ 698 699 void 700 tfree(t, ap) 701 struct op *t; 702 Area *ap; 703 { 704 char **w; 705 706 if (t == NULL) 707 return; 708 709 if (t->str != NULL) 710 afree((void*)t->str, ap); 711 712 if (t->vars != NULL) { 713 for (w = t->vars; *w != NULL; w++) 714 afree((void*)*w, ap); 715 afree((void*)t->vars, ap); 716 } 717 718 if (t->args != NULL) { 719 for (w = t->args; *w != NULL; w++) 720 afree((void*)*w, ap); 721 afree((void*)t->args, ap); 722 } 723 724 if (t->ioact != NULL) 725 iofree(t->ioact, ap); 726 727 tfree(t->left, ap); 728 tfree(t->right, ap); 729 730 afree((void*)t, ap); 731 } 732 733 static void 734 iofree(iow, ap) 735 struct ioword **iow; 736 Area *ap; 737 { 738 struct ioword **iop; 739 struct ioword *p; 740 741 for (iop = iow; (p = *iop++) != NULL; ) { 742 if (p->name != NULL) 743 afree((void*)p->name, ap); 744 if (p->delim != NULL) 745 afree((void*)p->delim, ap); 746 if (p->heredoc != NULL) 747 afree((void*)p->heredoc, ap); 748 afree((void*)p, ap); 749 } 750 } 751