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