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