xref: /netbsd-src/bin/ksh/tree.c (revision dc306354b0b29af51801a7632f1e95265a68cd81)
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