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