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