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