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