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