• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$OpenBSD: tree.c,v 1.21 2015/09/01 13:12:31 tedu Exp $	*/
2 
3 /*-
4  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5  *		 2011, 2012, 2013, 2015, 2016, 2017
6  *	mirabilos <m@mirbsd.org>
7  *
8  * Provided that these terms and disclaimer and all copyright notices
9  * are retained or reproduced in an accompanying document, permission
10  * is granted to deal in this work without restriction, including un-
11  * limited rights to use, publicly perform, distribute, sell, modify,
12  * merge, give away, or sublicence.
13  *
14  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15  * the utmost extent permitted by applicable law, neither express nor
16  * implied; without malicious intent or gross negligence. In no event
17  * may a licensor, author or contributor be held liable for indirect,
18  * direct, other damage, loss, or other issues arising in any way out
19  * of dealing in the work, even if advised of the possibility of such
20  * damage or existence of a defect, except proven that it results out
21  * of said person's immediate fault when using the work as intended.
22  */
23 
24 #include "sh.h"
25 
26 __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.100 2020/10/31 04:28:54 tg Exp $");
27 
28 #define INDENT	8
29 
30 static void ptree(struct op *, int, struct shf *);
31 static void pioact(struct shf *, struct ioword *);
32 static const char *wdvarput(struct shf *, const char *, int, int);
33 static void vfptreef(struct shf *, int, const char *, va_list);
34 static struct ioword **iocopy(struct ioword **, Area *);
35 static void iofree(struct ioword **, Area *);
36 
37 /* "foo& ; bar" and "foo |& ; bar" are invalid */
38 static bool prevent_semicolon;
39 
40 /* here document diversion */
41 static unsigned short ptree_nest;
42 static bool ptree_hashere;
43 static struct shf ptree_heredoc;
44 #define ptree_outhere(shf) do {					\
45 	if (ptree_hashere) {					\
46 		char *ptree_thehere;				\
47 								\
48 		ptree_thehere = shf_sclose(&ptree_heredoc);	\
49 		shf_puts(ptree_thehere, (shf));			\
50 		shf_putc('\n', (shf));				\
51 		afree(ptree_thehere, ATEMP); 		\
52 		ptree_hashere = false;				\
53 		/*prevent_semicolon = true;*/			\
54 	}							\
55 } while (/* CONSTCOND */ 0)
56 
57 static const char Telif_pT[] = "elif %T";
58 
59 /*
60  * print a command tree
61  */
62 static void
ptree(struct op * t,int indent,struct shf * shf)63 ptree(struct op *t, int indent, struct shf *shf)
64 {
65 	const char **w;
66 	struct ioword **ioact;
67 	struct op *t1;
68 	int i;
69 	const char *ccp;
70 
71  Chain:
72 	if (t == NULL)
73 		return;
74 	switch (t->type) {
75 	case TCOM:
76 		prevent_semicolon = false;
77 		/* special-case 'var=<<EOF' (cf. exec.c:execute) */
78 		if (t->args &&
79 		    /* we have zero arguments, i.e. no program to run */
80 		    t->args[0] == NULL &&
81 		    /* we have exactly one variable assignment */
82 		    t->vars[0] != NULL && t->vars[1] == NULL &&
83 		    /* we have exactly one I/O redirection */
84 		    t->ioact != NULL && t->ioact[0] != NULL &&
85 		    t->ioact[1] == NULL &&
86 		    /* of type "here document" (or "here string") */
87 		    (t->ioact[0]->ioflag & IOTYPE) == IOHERE &&
88 		    /* the variable assignment begins with a valid varname */
89 		    (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
90 		    /* and has no right-hand side (i.e. "varname=") */
91 		    ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) ||
92 		    /* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR &&
93 		    ccp[3] == '=' && ccp[4] == EOS))) {
94 			fptreef(shf, indent, Tf_S, t->vars[0]);
95 			break;
96 		}
97 
98 		if (t->vars) {
99 			w = (const char **)t->vars;
100 			while (*w)
101 				fptreef(shf, indent, Tf_S_, *w++);
102 		}
103 #ifndef MKSH_SMALL
104 		  else
105 			shf_puts("#no-vars# ", shf);
106 #endif
107 		if (t->args) {
108 			w = t->args;
109 			if (*w && **w == CHAR) {
110 				char *cp = wdstrip(*w++, WDS_TPUTS);
111 
112 				if (valid_alias_name(cp))
113 					shf_putc('\\', shf);
114 				shf_puts(cp, shf);
115 				shf_putc(' ', shf);
116 				afree(cp, ATEMP);
117 			}
118 			while (*w)
119 				fptreef(shf, indent, Tf_S_, *w++);
120 		}
121 #ifndef MKSH_SMALL
122 		  else
123 			shf_puts("#no-args# ", shf);
124 #endif
125 		break;
126 	case TEXEC:
127 		t = t->left;
128 		goto Chain;
129 	case TPAREN:
130 		fptreef(shf, indent + 2, "( %T) ", t->left);
131 		break;
132 	case TPIPE:
133 		fptreef(shf, indent, "%T| ", t->left);
134 		t = t->right;
135 		goto Chain;
136 	case TLIST:
137 		fptreef(shf, indent, "%T%;", t->left);
138 		t = t->right;
139 		goto Chain;
140 	case TOR:
141 	case TAND:
142 		fptreef(shf, indent, "%T%s %T",
143 		    t->left, (t->type == TOR) ? "||" : "&&", t->right);
144 		break;
145 	case TBANG:
146 		shf_puts("! ", shf);
147 		prevent_semicolon = false;
148 		t = t->right;
149 		goto Chain;
150 	case TDBRACKET:
151 		w = t->args;
152 		shf_puts("[[", shf);
153 		while (*w)
154 			fptreef(shf, indent, Tf__S, *w++);
155 		shf_puts(" ]] ", shf);
156 		break;
157 	case TSELECT:
158 	case TFOR:
159 		fptreef(shf, indent, "%s %s ",
160 		    (t->type == TFOR) ? "for" : Tselect, t->str);
161 		if (t->vars != NULL) {
162 			shf_puts("in ", shf);
163 			w = (const char **)t->vars;
164 			while (*w)
165 				fptreef(shf, indent, Tf_S_, *w++);
166 			fptreef(shf, indent, Tft_end);
167 		}
168 		fptreef(shf, indent + INDENT, "do%N%T", t->left);
169 		fptreef(shf, indent, "%;done ");
170 		break;
171 	case TCASE:
172 		fptreef(shf, indent, "case %S in", t->str);
173 		for (t1 = t->left; t1 != NULL; t1 = t1->right) {
174 			fptreef(shf, indent, "%N(");
175 			w = (const char **)t1->vars;
176 			while (*w) {
177 				fptreef(shf, indent, "%S%c", *w,
178 				    (w[1] != NULL) ? '|' : ')');
179 				++w;
180 			}
181 			fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left,
182 			    t1->u.charflag);
183 		}
184 		fptreef(shf, indent, "%Nesac ");
185 		break;
186 	case TELIF:
187 		internal_errorf(TELIF_unexpected);
188 		/* FALLTHROUGH */
189 	case TIF:
190 		i = 2;
191 		t1 = t;
192 		goto process_TIF;
193 		do {
194 			t1 = t1->right;
195 			i = 0;
196 			fptreef(shf, indent, Tft_end);
197  process_TIF:
198 			/* 5 == strlen("elif ") */
199 			fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
200 			t1 = t1->right;
201 			if (t1->left != NULL) {
202 				fptreef(shf, indent, Tft_end);
203 				fptreef(shf, indent + INDENT, "%s%N%T",
204 				    "then", t1->left);
205 			}
206 		} while (t1->right && t1->right->type == TELIF);
207 		if (t1->right != NULL) {
208 			fptreef(shf, indent, Tft_end);
209 			fptreef(shf, indent + INDENT, "%s%N%T",
210 			    "else", t1->right);
211 		}
212 		fptreef(shf, indent, "%;fi ");
213 		break;
214 	case TWHILE:
215 	case TUNTIL:
216 		/* 6 == strlen("while "/"until ") */
217 		fptreef(shf, indent + 6, Tf_s_T,
218 		    (t->type == TWHILE) ? "while" : "until",
219 		    t->left);
220 		fptreef(shf, indent, Tft_end);
221 		fptreef(shf, indent + INDENT, "do%N%T", t->right);
222 		fptreef(shf, indent, "%;done ");
223 		break;
224 	case TBRACE:
225 		fptreef(shf, indent + INDENT, "{%N%T", t->left);
226 		fptreef(shf, indent, "%;} ");
227 		break;
228 	case TCOPROC:
229 		fptreef(shf, indent, "%T|& ", t->left);
230 		prevent_semicolon = true;
231 		break;
232 	case TASYNC:
233 		fptreef(shf, indent, "%T& ", t->left);
234 		prevent_semicolon = true;
235 		break;
236 	case TFUNCT:
237 		fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left);
238 		break;
239 	case TTIME:
240 		fptreef(shf, indent, Tf_s_T, Ttime, t->left);
241 		break;
242 	default:
243 		shf_puts("<botch>", shf);
244 		prevent_semicolon = false;
245 		break;
246 	}
247 	if ((ioact = t->ioact) != NULL)
248 		while (*ioact != NULL)
249 			pioact(shf, *ioact++);
250 }
251 
252 static void
pioact(struct shf * shf,struct ioword * iop)253 pioact(struct shf *shf, struct ioword *iop)
254 {
255 	unsigned short flag = iop->ioflag;
256 	unsigned short type = flag & IOTYPE;
257 	short expected;
258 
259 	expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
260 	    (type == IOCAT || type == IOWRITE) ? 1 :
261 	    (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
262 	    iop->unit + 1;
263 	if (iop->unit != expected)
264 		shf_fprintf(shf, Tf_d, (int)iop->unit);
265 
266 	switch (type) {
267 	case IOREAD:
268 		shf_putc('<', shf);
269 		break;
270 	case IOHERE:
271 		if (flag & IOHERESTR) {
272 			shf_puts("<<<", shf);
273 			goto ioheredelim;
274 		}
275 		shf_puts("<<", shf);
276 		if (flag & IOSKIP)
277 			shf_putc('-', shf);
278 		if (iop->heredoc /* nil when tracing */) {
279 			/* here document diversion */
280 			if (!ptree_hashere) {
281 				shf_sopen(NULL, 0, SHF_WR | SHF_DYNAMIC,
282 				    &ptree_heredoc);
283 				ptree_hashere = true;
284 			}
285 			shf_putc('\n', &ptree_heredoc);
286 			shf_puts(iop->heredoc, &ptree_heredoc);
287 			/* iop->delim is set before iop->heredoc */
288 			shf_puts(evalstr(iop->delim, 0), &ptree_heredoc);
289 		}
290  ioheredelim:
291 		/* delim is NULL during syntax error printing */
292 		if (iop->delim && !(iop->ioflag & IONDELIM))
293 			wdvarput(shf, iop->delim, 0, WDS_TPUTS);
294 		break;
295 	case IOCAT:
296 		shf_puts(">>", shf);
297 		break;
298 	case IOWRITE:
299 		shf_putc('>', shf);
300 		if (flag & IOCLOB)
301 			shf_putc('|', shf);
302 		break;
303 	case IORDWR:
304 		shf_puts("<>", shf);
305 		break;
306 	case IODUP:
307 		shf_puts(flag & IORDUP ? "<&" : ">&", shf);
308 		break;
309 	}
310 	/* name is NULL for IOHERE or when printing syntax errors */
311 	if (iop->ioname) {
312 		if (flag & IONAMEXP)
313 			print_value_quoted(shf, iop->ioname);
314 		else
315 			wdvarput(shf, iop->ioname, 0, WDS_TPUTS);
316 	}
317 	shf_putc(' ', shf);
318 	prevent_semicolon = false;
319 }
320 
321 /* variant of fputs for ptreef and wdstrip */
322 static const char *
wdvarput(struct shf * shf,const char * wp,int quotelevel,int opmode)323 wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
324 {
325 	int c;
326 	const char *cs;
327 
328 	/*-
329 	 * problems:
330 	 *	`...` -> $(...)
331 	 *	'foo' -> "foo"
332 	 *	x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
333 	 *	x${foo:-'hi'} -> x${foo:-hi}
334 	 * could change encoding to:
335 	 *	OQUOTE ["'] ... CQUOTE ["']
336 	 *	COMSUB [(`] ...\0	(handle $ ` \ and maybe " in `...` case)
337 	 */
338 	while (/* CONSTCOND */ 1)
339 		switch (*wp++) {
340 		case EOS:
341 			return (--wp);
342 		case ADELIM:
343 			if (ord(*wp) == ORD(/*{*/ '}')) {
344 				++wp;
345 				goto wdvarput_csubst;
346 			}
347 			/* FALLTHROUGH */
348 		case CHAR:
349 			c = ord(*wp++);
350 			shf_putc(c, shf);
351 			break;
352 		case QCHAR:
353 			c = ord(*wp++);
354 			if (opmode & WDS_TPUTS)
355 				switch (c) {
356 				default:
357 					if (quotelevel == 0)
358 						/* FALLTHROUGH */
359 				case ORD('"'):
360 				case ORD('`'):
361 				case ORD('$'):
362 				case ORD('\\'):
363 					  shf_putc(ORD('\\'), shf);
364 					break;
365 				}
366 			shf_putc(c, shf);
367 			break;
368 		case COMASUB:
369 		case COMSUB:
370 			shf_puts("$(", shf);
371 			cs = ")";
372 			if (ord(*wp) == ORD('(' /*)*/))
373 				shf_putc(' ', shf);
374  pSUB:
375 			while ((c = *wp++) != 0)
376 				shf_putc(c, shf);
377 			shf_puts(cs, shf);
378 			break;
379 		case FUNASUB:
380 		case FUNSUB:
381 			c = ORD(' ');
382 			if (0)
383 				/* FALLTHROUGH */
384 		case VALSUB:
385 			  c = ORD('|');
386 			shf_putc('$', shf);
387 			shf_putc('{', shf);
388 			shf_putc(c, shf);
389 			cs = ";}";
390 			goto pSUB;
391 		case EXPRSUB:
392 			shf_puts("$((", shf);
393 			cs = "))";
394 			goto pSUB;
395 		case OQUOTE:
396 			if (opmode & WDS_TPUTS) {
397 				quotelevel++;
398 				shf_putc('"', shf);
399 			}
400 			break;
401 		case CQUOTE:
402 			if (opmode & WDS_TPUTS) {
403 				if (quotelevel)
404 					quotelevel--;
405 				shf_putc('"', shf);
406 			}
407 			break;
408 		case OSUBST:
409 			shf_putc('$', shf);
410 			if (ord(*wp++) == ORD('{'))
411 				shf_putc('{', shf);
412 			while ((c = *wp++) != 0)
413 				shf_putc(c, shf);
414 			wp = wdvarput(shf, wp, 0, opmode);
415 			break;
416 		case CSUBST:
417 			if (ord(*wp++) == ORD('}')) {
418  wdvarput_csubst:
419 				shf_putc('}', shf);
420 			}
421 			return (wp);
422 		case OPAT:
423 			shf_putchar(*wp++, shf);
424 			shf_putc('(', shf);
425 			break;
426 		case SPAT:
427 			c = ORD('|');
428 			if (0)
429 				/* FALLTHROUGH */
430 		case CPAT:
431 			  c = ORD(/*(*/ ')');
432 			shf_putc(c, shf);
433 			break;
434 		}
435 }
436 
437 /*
438  * this is the _only_ way to reliably handle
439  * variable args with an ANSI compiler
440  */
441 /* VARARGS */
442 void
fptreef(struct shf * shf,int indent,const char * fmt,...)443 fptreef(struct shf *shf, int indent, const char *fmt, ...)
444 {
445 	va_list va;
446 
447 	va_start(va, fmt);
448 	vfptreef(shf, indent, fmt, va);
449 	va_end(va);
450 }
451 
452 /* VARARGS */
453 char *
snptreef(char * s,ssize_t n,const char * fmt,...)454 snptreef(char *s, ssize_t n, const char *fmt, ...)
455 {
456 	va_list va;
457 	struct shf shf;
458 
459 	shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
460 
461 	va_start(va, fmt);
462 	vfptreef(&shf, 0, fmt, va);
463 	va_end(va);
464 
465 	/* shf_sclose NUL terminates */
466 	return (shf_sclose(&shf));
467 }
468 
469 static void
vfptreef(struct shf * shf,int indent,const char * fmt,va_list va)470 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
471 {
472 	int c;
473 
474 	if (!ptree_nest++)
475 		ptree_hashere = false;
476 
477 	while ((c = ord(*fmt++))) {
478 		if (c == '%') {
479 			switch ((c = ord(*fmt++))) {
480 			case ORD('c'):
481 				/* character (octet, probably) */
482 				shf_putchar(va_arg(va, int), shf);
483 				break;
484 			case ORD('s'):
485 				/* string */
486 				shf_puts(va_arg(va, char *), shf);
487 				break;
488 			case ORD('S'):
489 				/* word */
490 				wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS);
491 				break;
492 			case ORD('d'):
493 				/* signed decimal */
494 				shf_fprintf(shf, Tf_d, va_arg(va, int));
495 				break;
496 			case ORD('u'):
497 				/* unsigned decimal */
498 				shf_fprintf(shf, "%u", va_arg(va, unsigned int));
499 				break;
500 			case ORD('T'):
501 				/* format tree */
502 				ptree(va_arg(va, struct op *), indent, shf);
503 				goto dont_trash_prevent_semicolon;
504 			case ORD(';'):
505 				/* newline or ; */
506 			case ORD('N'):
507 				/* newline or space */
508 				if (shf->flags & SHF_STRING) {
509 					if ((unsigned int)c == ORD(';') &&
510 					    !prevent_semicolon)
511 						shf_putc(';', shf);
512 					shf_putc(' ', shf);
513 				} else {
514 					int i = indent;
515 
516 					ptree_outhere(shf);
517 					shf_putc('\n', shf);
518 					while (i >= 8) {
519 						shf_putc('\t', shf);
520 						i -= 8;
521 					}
522 					while (i--)
523 						shf_putc(' ', shf);
524 				}
525 				break;
526 			case ORD('R'):
527 				/* I/O redirection */
528 				pioact(shf, va_arg(va, struct ioword *));
529 				break;
530 			default:
531 				shf_putc(c, shf);
532 				break;
533 			}
534 		} else
535 			shf_putc(c, shf);
536 		prevent_semicolon = false;
537  dont_trash_prevent_semicolon:
538 		;
539 	}
540 
541 	if (!--ptree_nest)
542 		ptree_outhere(shf);
543 }
544 
545 /*
546  * copy tree (for function definition)
547  */
548 struct op *
tcopy(struct op * t,Area * ap)549 tcopy(struct op *t, Area *ap)
550 {
551 	struct op *r;
552 	const char **tw;
553 	char **rw;
554 
555 	if (t == NULL)
556 		return (NULL);
557 
558 	r = alloc(sizeof(struct op), ap);
559 
560 	r->type = t->type;
561 	r->u.evalflags = t->u.evalflags;
562 
563 	if (t->type == TCASE)
564 		r->str = wdcopy(t->str, ap);
565 	else
566 		strdupx(r->str, t->str, ap);
567 
568 	if (t->vars == NULL)
569 		r->vars = NULL;
570 	else {
571 		tw = (const char **)t->vars;
572 		while (*tw)
573 			++tw;
574 		rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
575 		    sizeof(*tw), ap);
576 		tw = (const char **)t->vars;
577 		while (*tw)
578 			*rw++ = wdcopy(*tw++, ap);
579 		*rw = NULL;
580 	}
581 
582 	if (t->args == NULL)
583 		r->args = NULL;
584 	else {
585 		tw = t->args;
586 		while (*tw)
587 			++tw;
588 		r->args = (const char **)(rw = alloc2(tw - t->args + 1,
589 		    sizeof(*tw), ap));
590 		tw = t->args;
591 		while (*tw)
592 			*rw++ = wdcopy(*tw++, ap);
593 		*rw = NULL;
594 	}
595 
596 	r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
597 
598 	r->left = tcopy(t->left, ap);
599 	r->right = tcopy(t->right, ap);
600 	r->lineno = t->lineno;
601 
602 	return (r);
603 }
604 
605 char *
wdcopy(const char * wp,Area * ap)606 wdcopy(const char *wp, Area *ap)
607 {
608 	size_t len;
609 
610 	len = wdscan(wp, EOS) - wp;
611 	return (memcpy(alloc(len, ap), wp, len));
612 }
613 
614 /* return the position of prefix c in wp plus 1 */
615 const char *
wdscan(const char * wp,int c)616 wdscan(const char *wp, int c)
617 {
618 	int nest = 0;
619 
620 	while (/* CONSTCOND */ 1)
621 		switch (*wp++) {
622 		case EOS:
623 			return (wp);
624 		case ADELIM:
625 			if (c == ADELIM && nest == 0)
626 				return (wp + 1);
627 			if (ord(*wp) == ORD(/*{*/ '}'))
628 				goto wdscan_csubst;
629 			/* FALLTHROUGH */
630 		case CHAR:
631 		case QCHAR:
632 			wp++;
633 			break;
634 		case COMASUB:
635 		case COMSUB:
636 		case FUNASUB:
637 		case FUNSUB:
638 		case VALSUB:
639 		case EXPRSUB:
640 			while (*wp++ != 0)
641 				;
642 			break;
643 		case OQUOTE:
644 		case CQUOTE:
645 			break;
646 		case OSUBST:
647 			nest++;
648 			while (*wp++ != '\0')
649 				;
650 			break;
651 		case CSUBST:
652  wdscan_csubst:
653 			wp++;
654 			if (c == CSUBST && nest == 0)
655 				return (wp);
656 			nest--;
657 			break;
658 		case OPAT:
659 			nest++;
660 			wp++;
661 			break;
662 		case SPAT:
663 		case CPAT:
664 			if (c == wp[-1] && nest == 0)
665 				return (wp);
666 			if (wp[-1] == CPAT)
667 				nest--;
668 			break;
669 		default:
670 			internal_warningf(
671 			    "wdscan: unknown char 0x%X (carrying on)",
672 			    (unsigned char)wp[-1]);
673 		}
674 }
675 
676 /*
677  * return a copy of wp without any of the mark up characters and with
678  * quote characters (" ' \) stripped. (string is allocated from ATEMP)
679  */
680 char *
wdstrip(const char * wp,int opmode)681 wdstrip(const char *wp, int opmode)
682 {
683 	struct shf shf;
684 
685 	shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
686 	wdvarput(&shf, wp, 0, opmode);
687 	/* shf_sclose NUL terminates */
688 	return (shf_sclose(&shf));
689 }
690 
691 static struct ioword **
iocopy(struct ioword ** iow,Area * ap)692 iocopy(struct ioword **iow, Area *ap)
693 {
694 	struct ioword **ior;
695 	int i;
696 
697 	ior = iow;
698 	while (*ior)
699 		++ior;
700 	ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
701 
702 	for (i = 0; iow[i] != NULL; i++) {
703 		struct ioword *p, *q;
704 
705 		p = iow[i];
706 		q = alloc(sizeof(struct ioword), ap);
707 		ior[i] = q;
708 		*q = *p;
709 		if (p->ioname != NULL)
710 			q->ioname = wdcopy(p->ioname, ap);
711 		if (p->delim != NULL)
712 			q->delim = wdcopy(p->delim, ap);
713 		if (p->heredoc != NULL)
714 			strdupx(q->heredoc, p->heredoc, ap);
715 	}
716 	ior[i] = NULL;
717 
718 	return (ior);
719 }
720 
721 /*
722  * free tree (for function definition)
723  */
724 void
tfree(struct op * t,Area * ap)725 tfree(struct op *t, Area *ap)
726 {
727 	char **w;
728 
729 	if (t == NULL)
730 		return;
731 
732 	afree(t->str, ap);
733 
734 	if (t->vars != NULL) {
735 		for (w = t->vars; *w != NULL; w++)
736 			afree(*w, ap);
737 		afree(t->vars, ap);
738 	}
739 
740 	if (t->args != NULL) {
741 		/*XXX we assume the caller is right */
742 		union mksh_ccphack cw;
743 
744 		cw.ro = t->args;
745 		for (w = cw.rw; *w != NULL; w++)
746 			afree(*w, ap);
747 		afree(t->args, ap);
748 	}
749 
750 	if (t->ioact != NULL)
751 		iofree(t->ioact, ap);
752 
753 	tfree(t->left, ap);
754 	tfree(t->right, ap);
755 
756 	afree(t, ap);
757 }
758 
759 static void
iofree(struct ioword ** iow,Area * ap)760 iofree(struct ioword **iow, Area *ap)
761 {
762 	struct ioword **iop;
763 	struct ioword *p;
764 
765 	iop = iow;
766 	while ((p = *iop++) != NULL) {
767 		afree(p->ioname, ap);
768 		afree(p->delim, ap);
769 		afree(p->heredoc, ap);
770 		afree(p, ap);
771 	}
772 	afree(iow, ap);
773 }
774 
775 void
fpFUNCTf(struct shf * shf,int i,bool isksh,const char * k,struct op * v)776 fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
777 {
778 	if (isksh)
779 		fptreef(shf, i, "%s %s %T", Tfunction, k, v);
780 	else if (ktsearch(&keywords, k, hash(k)))
781 		fptreef(shf, i, "%s %s() %T", Tfunction, k, v);
782 	else
783 		fptreef(shf, i, "%s() %T", k, v);
784 }
785 
786 
787 /* for jobs.c */
788 void
vistree(char * dst,size_t sz,struct op * t)789 vistree(char *dst, size_t sz, struct op *t)
790 {
791 	unsigned int c;
792 	char *cp, *buf;
793 	size_t n;
794 
795 	buf = alloc(sz + 16, ATEMP);
796 	snptreef(buf, sz + 16, Tf_T, t);
797 	cp = buf;
798  vist_loop:
799 	if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
800 		if (c == 0 || n >= sz)
801 			/* NUL or not enough free space */
802 			goto vist_out;
803 		/* copy multibyte char */
804 		sz -= n;
805 		while (n--)
806 			*dst++ = *cp++;
807 		goto vist_loop;
808 	}
809 	if (--sz == 0 || (c = ord(*cp++)) == 0)
810 		/* NUL or not enough free space */
811 		goto vist_out;
812 	if (ksh_isctrl(c)) {
813 		/* C0 or C1 control character or DEL */
814 		if (--sz == 0)
815 			/* not enough free space for two chars */
816 			goto vist_out;
817 		*dst++ = '^';
818 		c = ksh_unctrl(c);
819 	} else if (UTFMODE && rtt2asc(c) > 0x7F) {
820 		/* better not try to display broken multibyte chars */
821 		/* also go easy on the UCS: no U+FFFD here */
822 		c = ORD('?');
823 	}
824 	*dst++ = c;
825 	goto vist_loop;
826 
827  vist_out:
828 	*dst = '\0';
829 	afree(buf, ATEMP);
830 }
831 
832 #ifdef DEBUG
833 void
dumpchar(struct shf * shf,unsigned char c)834 dumpchar(struct shf *shf, unsigned char c)
835 {
836 	if (ksh_isctrl(c)) {
837 		/* C0 or C1 control character or DEL */
838 		shf_putc('^', shf);
839 		c = ksh_unctrl(c);
840 	}
841 	shf_putc(c, shf);
842 }
843 
844 /* see: wdvarput */
845 static const char *
dumpwdvar_i(struct shf * shf,const char * wp,int quotelevel)846 dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
847 {
848 	int c;
849 
850 	while (/* CONSTCOND */ 1) {
851 		switch(*wp++) {
852 		case EOS:
853 			shf_puts("EOS", shf);
854 			return (--wp);
855 		case ADELIM:
856 			if (ord(*wp) == ORD(/*{*/ '}')) {
857 				shf_puts(/*{*/ "]ADELIM(})", shf);
858 				return (wp + 1);
859 			}
860 			shf_puts("ADELIM=", shf);
861 			if (0)
862 				/* FALLTHROUGH */
863 		case CHAR:
864 			  shf_puts("CHAR=", shf);
865 			dumpchar(shf, *wp++);
866 			break;
867 		case QCHAR:
868 			shf_puts("QCHAR<", shf);
869 			c = ord(*wp++);
870 			if (quotelevel == 0 || c == ORD('"') ||
871 			    c == ORD('\\') || ctype(c, C_DOLAR | C_GRAVE))
872 				shf_putc('\\', shf);
873 			dumpchar(shf, c);
874 			goto closeandout;
875 		case COMASUB:
876 			shf_puts("COMASUB<", shf);
877 			goto dumpsub;
878 		case COMSUB:
879 			shf_puts("COMSUB<", shf);
880  dumpsub:
881 			while ((c = *wp++) != 0)
882 				dumpchar(shf, c);
883  closeandout:
884 			shf_putc('>', shf);
885 			break;
886 		case FUNASUB:
887 			shf_puts("FUNASUB<", shf);
888 			goto dumpsub;
889 		case FUNSUB:
890 			shf_puts("FUNSUB<", shf);
891 			goto dumpsub;
892 		case VALSUB:
893 			shf_puts("VALSUB<", shf);
894 			goto dumpsub;
895 		case EXPRSUB:
896 			shf_puts("EXPRSUB<", shf);
897 			goto dumpsub;
898 		case OQUOTE:
899 			shf_fprintf(shf, "OQUOTE{%d" /*}*/, ++quotelevel);
900 			break;
901 		case CQUOTE:
902 			shf_fprintf(shf, /*{*/ "%d}CQUOTE", quotelevel);
903 			if (quotelevel)
904 				quotelevel--;
905 			else
906 				shf_puts("(err)", shf);
907 			break;
908 		case OSUBST:
909 			shf_puts("OSUBST(", shf);
910 			dumpchar(shf, *wp++);
911 			shf_puts(")[", shf);
912 			while ((c = *wp++) != 0)
913 				dumpchar(shf, c);
914 			shf_putc('|', shf);
915 			wp = dumpwdvar_i(shf, wp, 0);
916 			break;
917 		case CSUBST:
918 			shf_puts("]CSUBST(", shf);
919 			dumpchar(shf, *wp++);
920 			shf_putc(')', shf);
921 			return (wp);
922 		case OPAT:
923 			shf_puts("OPAT=", shf);
924 			dumpchar(shf, *wp++);
925 			break;
926 		case SPAT:
927 			shf_puts("SPAT", shf);
928 			break;
929 		case CPAT:
930 			shf_puts("CPAT", shf);
931 			break;
932 		default:
933 			shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
934 			break;
935 		}
936 		shf_putc(' ', shf);
937 	}
938 }
939 void
dumpwdvar(struct shf * shf,const char * wp)940 dumpwdvar(struct shf *shf, const char *wp)
941 {
942 	dumpwdvar_i(shf, wp, 0);
943 }
944 
945 void
dumpioact(struct shf * shf,struct op * t)946 dumpioact(struct shf *shf, struct op *t)
947 {
948 	struct ioword **ioact, *iop;
949 
950 	if ((ioact = t->ioact) == NULL)
951 		return;
952 
953 	shf_puts("{IOACT", shf);
954 	while ((iop = *ioact++) != NULL) {
955 		unsigned short type = iop->ioflag & IOTYPE;
956 #define DT(x) case x: shf_puts(#x, shf); break;
957 #define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
958 
959 		shf_putc(';', shf);
960 		switch (type) {
961 		DT(IOREAD)
962 		DT(IOWRITE)
963 		DT(IORDWR)
964 		DT(IOHERE)
965 		DT(IOCAT)
966 		DT(IODUP)
967 		default:
968 			shf_fprintf(shf, "unk%d", type);
969 		}
970 		DB(IOEVAL)
971 		DB(IOSKIP)
972 		DB(IOCLOB)
973 		DB(IORDUP)
974 		DB(IONAMEXP)
975 		DB(IOBASH)
976 		DB(IOHERESTR)
977 		DB(IONDELIM)
978 		shf_fprintf(shf, ",unit=%d", (int)iop->unit);
979 		if (iop->delim && !(iop->ioflag & IONDELIM)) {
980 			shf_puts(",delim<", shf);
981 			dumpwdvar(shf, iop->delim);
982 			shf_putc('>', shf);
983 		}
984 		if (iop->ioname) {
985 			if (iop->ioflag & IONAMEXP) {
986 				shf_puts(",name=", shf);
987 				print_value_quoted(shf, iop->ioname);
988 			} else {
989 				shf_puts(",name<", shf);
990 				dumpwdvar(shf, iop->ioname);
991 				shf_putc('>', shf);
992 			}
993 		}
994 		if (iop->heredoc) {
995 			shf_puts(",heredoc=", shf);
996 			print_value_quoted(shf, iop->heredoc);
997 		}
998 #undef DT
999 #undef DB
1000 	}
1001 	shf_putc('}', shf);
1002 }
1003 
1004 void
dumptree(struct shf * shf,struct op * t)1005 dumptree(struct shf *shf, struct op *t)
1006 {
1007 	int i, j;
1008 	const char **w, *name;
1009 	struct op *t1;
1010 	static int nesting;
1011 
1012 	for (i = 0; i < nesting; ++i)
1013 		shf_putc('\t', shf);
1014 	++nesting;
1015 	shf_puts("{tree:" /*}*/, shf);
1016 	if (t == NULL) {
1017 		name = "(null)";
1018 		goto out;
1019 	}
1020 	dumpioact(shf, t);
1021 	switch (t->type) {
1022 #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
1023 
1024 	OPEN(TCOM)
1025 		if (t->vars) {
1026 			i = 0;
1027 			w = (const char **)t->vars;
1028 			while (*w) {
1029 				shf_putc('\n', shf);
1030 				for (j = 0; j < nesting; ++j)
1031 					shf_putc('\t', shf);
1032 				shf_fprintf(shf, " var%d<", i++);
1033 				dumpwdvar(shf, *w++);
1034 				shf_putc('>', shf);
1035 			}
1036 		} else
1037 			shf_puts(" #no-vars#", shf);
1038 		if (t->args) {
1039 			i = 0;
1040 			w = t->args;
1041 			while (*w) {
1042 				shf_putc('\n', shf);
1043 				for (j = 0; j < nesting; ++j)
1044 					shf_putc('\t', shf);
1045 				shf_fprintf(shf, " arg%d<", i++);
1046 				dumpwdvar(shf, *w++);
1047 				shf_putc('>', shf);
1048 			}
1049 		} else
1050 			shf_puts(" #no-args#", shf);
1051 		break;
1052 	OPEN(TEXEC)
1053  dumpleftandout:
1054 		t = t->left;
1055  dumpandout:
1056 		shf_putc('\n', shf);
1057 		dumptree(shf, t);
1058 		break;
1059 	OPEN(TPAREN)
1060 		goto dumpleftandout;
1061 	OPEN(TPIPE)
1062  dumpleftmidrightandout:
1063 		shf_putc('\n', shf);
1064 		dumptree(shf, t->left);
1065 /* middumprightandout: (unused) */
1066 		shf_fprintf(shf, "/%s:", name);
1067  dumprightandout:
1068 		t = t->right;
1069 		goto dumpandout;
1070 	OPEN(TLIST)
1071 		goto dumpleftmidrightandout;
1072 	OPEN(TOR)
1073 		goto dumpleftmidrightandout;
1074 	OPEN(TAND)
1075 		goto dumpleftmidrightandout;
1076 	OPEN(TBANG)
1077 		goto dumprightandout;
1078 	OPEN(TDBRACKET)
1079 		i = 0;
1080 		w = t->args;
1081 		while (*w) {
1082 			shf_putc('\n', shf);
1083 			for (j = 0; j < nesting; ++j)
1084 				shf_putc('\t', shf);
1085 			shf_fprintf(shf, " arg%d<", i++);
1086 			dumpwdvar(shf, *w++);
1087 			shf_putc('>', shf);
1088 		}
1089 		break;
1090 	OPEN(TFOR)
1091  dumpfor:
1092 		shf_fprintf(shf, " str<%s>", t->str);
1093 		if (t->vars != NULL) {
1094 			i = 0;
1095 			w = (const char **)t->vars;
1096 			while (*w) {
1097 				shf_putc('\n', shf);
1098 				for (j = 0; j < nesting; ++j)
1099 					shf_putc('\t', shf);
1100 				shf_fprintf(shf, " var%d<", i++);
1101 				dumpwdvar(shf, *w++);
1102 				shf_putc('>', shf);
1103 			}
1104 		}
1105 		goto dumpleftandout;
1106 	OPEN(TSELECT)
1107 		goto dumpfor;
1108 	OPEN(TCASE)
1109 		shf_fprintf(shf, " str<%s>", t->str);
1110 		i = 0;
1111 		for (t1 = t->left; t1 != NULL; t1 = t1->right) {
1112 			shf_putc('\n', shf);
1113 			for (j = 0; j < nesting; ++j)
1114 				shf_putc('\t', shf);
1115 			shf_fprintf(shf, " sub%d[(", i);
1116 			w = (const char **)t1->vars;
1117 			while (*w) {
1118 				dumpwdvar(shf, *w);
1119 				if (w[1] != NULL)
1120 					shf_putc('|', shf);
1121 				++w;
1122 			}
1123 			shf_putc(')', shf);
1124 			dumpioact(shf, t);
1125 			shf_putc('\n', shf);
1126 			dumptree(shf, t1->left);
1127 			shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
1128 		}
1129 		break;
1130 	OPEN(TWHILE)
1131 		goto dumpleftmidrightandout;
1132 	OPEN(TUNTIL)
1133 		goto dumpleftmidrightandout;
1134 	OPEN(TBRACE)
1135 		goto dumpleftandout;
1136 	OPEN(TCOPROC)
1137 		goto dumpleftandout;
1138 	OPEN(TASYNC)
1139 		goto dumpleftandout;
1140 	OPEN(TFUNCT)
1141 		shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
1142 		    t->u.ksh_func ? Ttrue : Tfalse);
1143 		goto dumpleftandout;
1144 	OPEN(TTIME)
1145 		goto dumpleftandout;
1146 	OPEN(TIF)
1147  dumpif:
1148 		shf_putc('\n', shf);
1149 		dumptree(shf, t->left);
1150 		t = t->right;
1151 		dumpioact(shf, t);
1152 		if (t->left != NULL) {
1153 			shf_puts(" /TTHEN:\n", shf);
1154 			dumptree(shf, t->left);
1155 		}
1156 		if (t->right && t->right->type == TELIF) {
1157 			shf_puts(" /TELIF:", shf);
1158 			t = t->right;
1159 			dumpioact(shf, t);
1160 			goto dumpif;
1161 		}
1162 		if (t->right != NULL) {
1163 			shf_puts(" /TELSE:\n", shf);
1164 			dumptree(shf, t->right);
1165 		}
1166 		break;
1167 	OPEN(TEOF)
1168  dumpunexpected:
1169 		shf_puts(Tunexpected, shf);
1170 		break;
1171 	OPEN(TELIF)
1172 		goto dumpunexpected;
1173 	OPEN(TPAT)
1174 		goto dumpunexpected;
1175 	default:
1176 		name = "TINVALID";
1177 		shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
1178 		goto dumpunexpected;
1179 
1180 #undef OPEN
1181 	}
1182  out:
1183 	shf_fprintf(shf, /*{*/ " /%s}\n", name);
1184 	--nesting;
1185 }
1186 #endif
1187