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