tree.c revision 1.2 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