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