xref: /titanic_50/usr/src/lib/libshell/common/sh/deparse.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
18da2e3ebdSchin *                                                                      *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin  * David Korn
23da2e3ebdSchin  * AT&T Labs
24da2e3ebdSchin  *
25da2e3ebdSchin  * shell deparser
26da2e3ebdSchin  *
27da2e3ebdSchin  */
28da2e3ebdSchin 
29da2e3ebdSchin #include	"defs.h"
30da2e3ebdSchin #include	"shnodes.h"
31da2e3ebdSchin #include	"test.h"
32da2e3ebdSchin 
33da2e3ebdSchin 
34da2e3ebdSchin #define HUGE_INT	(((unsigned)-1)>>1)
35da2e3ebdSchin #define	BEGIN	0
36da2e3ebdSchin #define MIDDLE	1
37da2e3ebdSchin #define	END	2
38da2e3ebdSchin #define PRE	1
39da2e3ebdSchin #define POST	2
40da2e3ebdSchin 
41da2e3ebdSchin 
42da2e3ebdSchin /* flags that can be specified with p_tree() */
43da2e3ebdSchin #define NO_NEWLINE	1
44da2e3ebdSchin #define NEED_BRACE	2
45da2e3ebdSchin #define NO_BRACKET	4
46da2e3ebdSchin 
47da2e3ebdSchin static void p_comlist(const struct dolnod*,int);
48da2e3ebdSchin static void p_arg(const struct argnod*, int endchar, int opts);
49da2e3ebdSchin static void p_comarg(const struct comnod*);
50da2e3ebdSchin static void p_keyword(const char*,int);
51da2e3ebdSchin static void p_redirect(const struct ionod*);
52da2e3ebdSchin static void p_switch(const struct regnod*);
53da2e3ebdSchin static void here_body(const struct ionod*);
54da2e3ebdSchin static void p_tree(const Shnode_t*,int);
55da2e3ebdSchin 
56da2e3ebdSchin static int level;
57da2e3ebdSchin static int begin_line;
58da2e3ebdSchin static int end_line;
59da2e3ebdSchin static char io_op[7];
60da2e3ebdSchin static char un_op[3] = "-?";
61da2e3ebdSchin static const struct ionod *here_doc;
62da2e3ebdSchin static Sfio_t *outfile;
63da2e3ebdSchin static const char *forinit = "";
64da2e3ebdSchin 
65da2e3ebdSchin extern void sh_deparse(Sfio_t*, const Shnode_t*,int);
66da2e3ebdSchin 
sh_deparse(Sfio_t * out,const Shnode_t * t,int tflags)67da2e3ebdSchin void sh_deparse(Sfio_t *out, const Shnode_t *t,int tflags)
68da2e3ebdSchin {
69da2e3ebdSchin 	outfile = out;
70da2e3ebdSchin 	p_tree(t,tflags);
71da2e3ebdSchin }
72da2e3ebdSchin /*
73da2e3ebdSchin  * print script corresponding to shell tree <t>
74da2e3ebdSchin  */
p_tree(register const Shnode_t * t,register int tflags)75da2e3ebdSchin static void p_tree(register const Shnode_t *t,register int tflags)
76da2e3ebdSchin {
77da2e3ebdSchin 	register char *cp;
78da2e3ebdSchin 	int save = end_line;
79da2e3ebdSchin 	int needbrace = (tflags&NEED_BRACE);
80da2e3ebdSchin 	tflags &= ~NEED_BRACE;
81da2e3ebdSchin 	if(tflags&NO_NEWLINE)
82da2e3ebdSchin 		end_line = ' ';
83da2e3ebdSchin 	else
84da2e3ebdSchin 		end_line = '\n';
85da2e3ebdSchin 	switch(t->tre.tretyp&COMMSK)
86da2e3ebdSchin 	{
87da2e3ebdSchin 		case TTIME:
88da2e3ebdSchin 			if(t->tre.tretyp&COMSCAN)
89da2e3ebdSchin 				p_keyword("!",BEGIN);
90da2e3ebdSchin 			else
91da2e3ebdSchin 				p_keyword("time",BEGIN);
92da2e3ebdSchin 			if(t->par.partre)
93da2e3ebdSchin 				p_tree(t->par.partre,tflags);
94da2e3ebdSchin 			level--;
95da2e3ebdSchin 			break;
96da2e3ebdSchin 
97da2e3ebdSchin 		case TCOM:
98da2e3ebdSchin 			if(begin_line && level>0)
99da2e3ebdSchin 				sfnputc(outfile,'\t',level);
100da2e3ebdSchin 			begin_line = 0;
101da2e3ebdSchin 			p_comarg((struct comnod*)t);
102da2e3ebdSchin 			break;
103da2e3ebdSchin 
104da2e3ebdSchin 		case TSETIO:
105da2e3ebdSchin 			if(t->tre.tretyp&FPCL)
106da2e3ebdSchin 				tflags |= NEED_BRACE;
107da2e3ebdSchin 			else
108da2e3ebdSchin 				tflags = NO_NEWLINE|NEED_BRACE;
109da2e3ebdSchin 			p_tree(t->fork.forktre,tflags);
110da2e3ebdSchin 			p_redirect(t->fork.forkio);
111da2e3ebdSchin 			break;
112da2e3ebdSchin 
113da2e3ebdSchin 		case TFORK:
114da2e3ebdSchin 			if(needbrace)
115da2e3ebdSchin 				tflags |= NEED_BRACE;
116da2e3ebdSchin 			if(t->tre.tretyp&(FAMP|FCOOP))
117da2e3ebdSchin 			{
118da2e3ebdSchin 				tflags = NEED_BRACE|NO_NEWLINE;
119da2e3ebdSchin 				end_line = ' ';
120da2e3ebdSchin 			}
121da2e3ebdSchin 			else if(t->fork.forkio)
122da2e3ebdSchin 				tflags = NO_NEWLINE;
123da2e3ebdSchin 			p_tree(t->fork.forktre,tflags);
124da2e3ebdSchin 			if(t->fork.forkio)
125da2e3ebdSchin 				p_redirect(t->fork.forkio);
126da2e3ebdSchin 			if(t->tre.tretyp&FCOOP)
127da2e3ebdSchin 			{
128da2e3ebdSchin 				sfputr(outfile,"|&",'\n');
129da2e3ebdSchin 				begin_line = 1;
130da2e3ebdSchin 			}
131da2e3ebdSchin 			else if(t->tre.tretyp&FAMP)
132da2e3ebdSchin 			{
133da2e3ebdSchin 				sfputr(outfile,"&",'\n');
134da2e3ebdSchin 				begin_line = 1;
135da2e3ebdSchin 			}
136da2e3ebdSchin 			break;
137da2e3ebdSchin 
138da2e3ebdSchin 		case TIF:
139da2e3ebdSchin 			p_keyword("if",BEGIN);
140da2e3ebdSchin 			p_tree(t->if_.iftre,0);
141da2e3ebdSchin 			p_keyword("then",MIDDLE);
142da2e3ebdSchin 			p_tree(t->if_.thtre,0);
143da2e3ebdSchin 			if(t->if_.eltre)
144da2e3ebdSchin 			{
145da2e3ebdSchin 				p_keyword("else",MIDDLE);
146da2e3ebdSchin 				p_tree(t->if_.eltre,0);
147da2e3ebdSchin 			}
148da2e3ebdSchin 			p_keyword("fi",END);
149da2e3ebdSchin 			break;
150da2e3ebdSchin 
151da2e3ebdSchin 		case TWH:
152da2e3ebdSchin 			if(t->wh.whinc)
153da2e3ebdSchin 				cp = "for";
154da2e3ebdSchin 			else if(t->tre.tretyp&COMSCAN)
155da2e3ebdSchin 				cp = "until";
156da2e3ebdSchin 			else
157da2e3ebdSchin 				cp = "while";
158da2e3ebdSchin 			p_keyword(cp,BEGIN);
159da2e3ebdSchin 			if(t->wh.whinc)
160da2e3ebdSchin 			{
161da2e3ebdSchin 				struct argnod *arg = (t->wh.whtre)->ar.arexpr;
162da2e3ebdSchin 				sfprintf(outfile,"(( %s; ",forinit);
163da2e3ebdSchin 				forinit = "";
164da2e3ebdSchin 				sfputr(outfile,arg->argval,';');
165da2e3ebdSchin 				arg = (t->wh.whinc)->arexpr;
166da2e3ebdSchin 				sfprintf(outfile," %s))\n",arg->argval);
167da2e3ebdSchin 			}
168da2e3ebdSchin 			else
169da2e3ebdSchin 				p_tree(t->wh.whtre,0);
170da2e3ebdSchin 			t = t->wh.dotre;
171da2e3ebdSchin 			goto dolist;
172da2e3ebdSchin 
173da2e3ebdSchin 		case TLST:
174da2e3ebdSchin 		{
175da2e3ebdSchin 			Shnode_t *tr = t->lst.lstrit;
176da2e3ebdSchin 			if(tr->tre.tretyp==TWH && tr->wh.whinc && t->lst.lstlef->tre.tretyp==TARITH)
177da2e3ebdSchin 			{
178da2e3ebdSchin 				/* arithmetic for statement */
179da2e3ebdSchin 				struct argnod *init = (t->lst.lstlef)->ar.arexpr;
180da2e3ebdSchin 				forinit= init->argval;
181da2e3ebdSchin 				p_tree(t->lst.lstrit,tflags);
182da2e3ebdSchin 				break;
183da2e3ebdSchin 			}
184da2e3ebdSchin 			if(needbrace)
185da2e3ebdSchin 				p_keyword("{",BEGIN);
186da2e3ebdSchin 			p_tree(t->lst.lstlef,0);
187da2e3ebdSchin 			if(needbrace)
188da2e3ebdSchin 				tflags = 0;
189da2e3ebdSchin 			p_tree(t->lst.lstrit,tflags);
190da2e3ebdSchin 			if(needbrace)
191da2e3ebdSchin 				p_keyword("}",END);
192da2e3ebdSchin 			break;
193da2e3ebdSchin 		}
194da2e3ebdSchin 
195da2e3ebdSchin 		case TAND:
196da2e3ebdSchin 			cp = "&&";
197da2e3ebdSchin 			goto andor;
198da2e3ebdSchin 		case TORF:
199da2e3ebdSchin 			cp = "||";
200da2e3ebdSchin 			goto andor;
201da2e3ebdSchin 		case TFIL:
202da2e3ebdSchin 			cp = "|";
203da2e3ebdSchin 		andor:
204da2e3ebdSchin 		{
205da2e3ebdSchin 			int bracket = 0;
206da2e3ebdSchin 			if(t->tre.tretyp&TTEST)
207da2e3ebdSchin 			{
208da2e3ebdSchin 				tflags |= NO_NEWLINE;
209da2e3ebdSchin 				if(!(tflags&NO_BRACKET))
210da2e3ebdSchin 				{
211da2e3ebdSchin 					p_keyword("[[",BEGIN);
212da2e3ebdSchin 					tflags |= NO_BRACKET;
213da2e3ebdSchin 					bracket=1;
214da2e3ebdSchin 				}
215da2e3ebdSchin 			}
216da2e3ebdSchin 			p_tree(t->lst.lstlef,NEED_BRACE|NO_NEWLINE|(tflags&NO_BRACKET));
217da2e3ebdSchin 			sfputr(outfile,cp,here_doc?'\n':' ');
218da2e3ebdSchin 			if(here_doc)
219da2e3ebdSchin 			{
220da2e3ebdSchin 				here_body(here_doc);
221da2e3ebdSchin 				here_doc = 0;
222da2e3ebdSchin 			}
223da2e3ebdSchin 			level++;
224da2e3ebdSchin 			p_tree(t->lst.lstrit,tflags|NEED_BRACE);
225da2e3ebdSchin 			if(bracket)
226da2e3ebdSchin 				p_keyword("]]",END);
227da2e3ebdSchin 			level--;
228da2e3ebdSchin 			break;
229da2e3ebdSchin 		}
230da2e3ebdSchin 
231da2e3ebdSchin 		case TPAR:
232da2e3ebdSchin 			p_keyword("(",BEGIN);
233da2e3ebdSchin 			p_tree(t->par.partre,0);
234da2e3ebdSchin 			p_keyword(")",END);
235da2e3ebdSchin 			break;
236da2e3ebdSchin 
237da2e3ebdSchin 		case TARITH:
238da2e3ebdSchin 		{
239da2e3ebdSchin 			register struct argnod *ap = t->ar.arexpr;
240da2e3ebdSchin 			if(begin_line && level)
241da2e3ebdSchin 				sfnputc(outfile,'\t',level);
242da2e3ebdSchin 			sfprintf(outfile,"(( %s ))%c",ap->argval,end_line);
243da2e3ebdSchin 			if(!(tflags&NO_NEWLINE))
244da2e3ebdSchin 				begin_line=1;
245da2e3ebdSchin 			break;
246da2e3ebdSchin 		}
247da2e3ebdSchin 
248da2e3ebdSchin 		case TFOR:
249da2e3ebdSchin 			cp = ((t->tre.tretyp&COMSCAN)?"select":"for");
250da2e3ebdSchin 			p_keyword(cp,BEGIN);
251da2e3ebdSchin 			sfputr(outfile,t->for_.fornam,' ');
252da2e3ebdSchin 			if(t->for_.forlst)
253da2e3ebdSchin 			{
254da2e3ebdSchin 				sfputr(outfile,"in",' ');
255da2e3ebdSchin 				tflags = end_line;
256da2e3ebdSchin 				end_line = '\n';
257da2e3ebdSchin 				p_comarg(t->for_.forlst);
258da2e3ebdSchin 				end_line = tflags;
259da2e3ebdSchin 			}
260da2e3ebdSchin 			else
261da2e3ebdSchin 				sfputc(outfile,'\n');
262da2e3ebdSchin 			begin_line = 1;
263da2e3ebdSchin 			t = t->for_.fortre;
264da2e3ebdSchin 		dolist:
265da2e3ebdSchin 			p_keyword("do",MIDDLE);
266da2e3ebdSchin 			p_tree(t,0);
267da2e3ebdSchin 			p_keyword("done",END);
268da2e3ebdSchin 			break;
269da2e3ebdSchin 
270da2e3ebdSchin 		case TSW:
271da2e3ebdSchin 			p_keyword("case",BEGIN);
272da2e3ebdSchin 			p_arg(t->sw.swarg,' ',0);
273da2e3ebdSchin 			if(t->sw.swlst)
274da2e3ebdSchin 			{
275da2e3ebdSchin 				begin_line = 1;
276da2e3ebdSchin 				sfputr(outfile,"in",'\n');
277da2e3ebdSchin 				tflags = end_line;
278da2e3ebdSchin 				end_line = '\n';
279da2e3ebdSchin 				p_switch(t->sw.swlst);
280da2e3ebdSchin 				end_line = tflags;
281da2e3ebdSchin 			}
282da2e3ebdSchin 			p_keyword("esac",END);
283da2e3ebdSchin 			break;
284da2e3ebdSchin 
285da2e3ebdSchin 		case TFUN:
286da2e3ebdSchin 			if(t->tre.tretyp&FPOSIX)
287da2e3ebdSchin 			{
288da2e3ebdSchin 				sfprintf(outfile,"%s",t->funct.functnam);
289da2e3ebdSchin 				p_keyword("()\n",BEGIN);
290da2e3ebdSchin 			}
291da2e3ebdSchin 			else
292da2e3ebdSchin 			{
293da2e3ebdSchin 				p_keyword("function",BEGIN);
294da2e3ebdSchin 				tflags = (t->funct.functargs?' ':'\n');
295da2e3ebdSchin 				sfputr(outfile,t->funct.functnam,tflags);
296da2e3ebdSchin 				if(t->funct.functargs)
297da2e3ebdSchin 				{
298da2e3ebdSchin 					tflags = end_line;
299da2e3ebdSchin 					end_line = '\n';
300da2e3ebdSchin 					p_comarg(t->funct.functargs);
301da2e3ebdSchin 					end_line = tflags;
302da2e3ebdSchin 				}
303da2e3ebdSchin 			}
304da2e3ebdSchin 			begin_line = 1;
305da2e3ebdSchin 			p_keyword("{\n",MIDDLE);
306da2e3ebdSchin 			begin_line = 1;
307da2e3ebdSchin 			p_tree(t->funct.functtre,0);
308da2e3ebdSchin 			p_keyword("}",END);
309da2e3ebdSchin 			break;
310da2e3ebdSchin 		/* new test compound command */
311da2e3ebdSchin 		case TTST:
312da2e3ebdSchin 			if(!(tflags&NO_BRACKET))
313da2e3ebdSchin 				p_keyword("[[",BEGIN);
314da2e3ebdSchin 			if((t->tre.tretyp&TPAREN)==TPAREN)
315da2e3ebdSchin 			{
316da2e3ebdSchin 				p_keyword("(",BEGIN);
317da2e3ebdSchin 				p_tree(t->lst.lstlef,NO_BRACKET|NO_NEWLINE);
318da2e3ebdSchin 				p_keyword(")",END);
319da2e3ebdSchin 			}
320da2e3ebdSchin 			else
321da2e3ebdSchin 			{
322da2e3ebdSchin 				int flags = (t->tre.tretyp)>>TSHIFT;
323da2e3ebdSchin 				if(t->tre.tretyp&TNEGATE)
324da2e3ebdSchin 					sfputr(outfile,"!",' ');
325da2e3ebdSchin 				if(t->tre.tretyp&TUNARY)
326da2e3ebdSchin 				{
327da2e3ebdSchin 					un_op[1] = flags;
328da2e3ebdSchin 					sfputr(outfile,un_op,' ');
329da2e3ebdSchin 				}
330da2e3ebdSchin 				else
331da2e3ebdSchin 					cp = ((char*)(shtab_testops+(flags&037)-1)->sh_name);
332da2e3ebdSchin 				p_arg(&(t->lst.lstlef->arg),' ',0);
333da2e3ebdSchin 				if(t->tre.tretyp&TBINARY)
334da2e3ebdSchin 				{
335da2e3ebdSchin 					sfputr(outfile,cp,' ');
336da2e3ebdSchin 					p_arg(&(t->lst.lstrit->arg),' ',0);
337da2e3ebdSchin 				}
338da2e3ebdSchin 			}
339da2e3ebdSchin 			if(!(tflags&NO_BRACKET))
340da2e3ebdSchin 				p_keyword("]]",END);
341da2e3ebdSchin 	}
342da2e3ebdSchin 	while(begin_line && here_doc)
343da2e3ebdSchin 	{
344da2e3ebdSchin 		here_body(here_doc);
345da2e3ebdSchin 		here_doc = 0;
346da2e3ebdSchin 	}
347da2e3ebdSchin 	end_line = save;
348da2e3ebdSchin 	return;
349da2e3ebdSchin }
350da2e3ebdSchin 
351da2e3ebdSchin /*
352da2e3ebdSchin  * print a keyword
353da2e3ebdSchin  * increment indent level for flag==BEGIN
354da2e3ebdSchin  * decrement indent level for flag==END
355da2e3ebdSchin  */
p_keyword(const char * word,int flag)356da2e3ebdSchin static void p_keyword(const char *word,int flag)
357da2e3ebdSchin {
358da2e3ebdSchin 	register int sep;
359da2e3ebdSchin 	if(flag==END)
360da2e3ebdSchin 		sep = end_line;
361da2e3ebdSchin 	else if(*word=='[' || *word=='(')
362da2e3ebdSchin 		sep = ' ';
363da2e3ebdSchin 	else
364da2e3ebdSchin 		sep = '\t';
365da2e3ebdSchin 	if(flag!=BEGIN)
366da2e3ebdSchin 		level--;
367da2e3ebdSchin 	if(begin_line && level)
368da2e3ebdSchin 		sfnputc(outfile,'\t',level);
369da2e3ebdSchin 	sfputr(outfile,word,sep);
370da2e3ebdSchin 	if(sep=='\n')
371da2e3ebdSchin 		begin_line=1;
372da2e3ebdSchin 	else
373da2e3ebdSchin 		begin_line=0;
374da2e3ebdSchin 	if(flag!=END)
375da2e3ebdSchin 		level++;
376da2e3ebdSchin }
377da2e3ebdSchin 
p_arg(register const struct argnod * arg,register int endchar,int opts)378da2e3ebdSchin static void p_arg(register const struct argnod *arg,register int endchar,int opts)
379da2e3ebdSchin {
380da2e3ebdSchin 	register const char *cp;
381da2e3ebdSchin 	register int flag;
382da2e3ebdSchin 	do
383da2e3ebdSchin 	{
384da2e3ebdSchin 		if(!arg->argnxt.ap)
385da2e3ebdSchin 			flag = endchar;
386da2e3ebdSchin 		else if(opts&PRE)
387da2e3ebdSchin 		{
388da2e3ebdSchin 			/* case alternation lists in reverse order */
389da2e3ebdSchin 			p_arg(arg->argnxt.ap,'|',opts);
390da2e3ebdSchin 			flag = endchar;
391da2e3ebdSchin 		}
392da2e3ebdSchin 		else if(opts)
393da2e3ebdSchin 			flag = ' ';
394da2e3ebdSchin 		cp = arg->argval;
395da2e3ebdSchin 		if(*cp==0 && opts==POST && arg->argchn.ap)
396da2e3ebdSchin 		{
397da2e3ebdSchin 			/* compound assignment */
398da2e3ebdSchin 			struct fornod *fp=(struct fornod*)arg->argchn.ap;
399da2e3ebdSchin 			sfprintf(outfile,"%s=(\n",fp->fornam);
400da2e3ebdSchin 			sfnputc(outfile,'\t',++level);
401da2e3ebdSchin 			p_tree(fp->fortre,0);
402da2e3ebdSchin 			if(--level)
403da2e3ebdSchin 				sfnputc(outfile,'\t',level);
404da2e3ebdSchin 			sfputc(outfile,')');
405da2e3ebdSchin 		}
406da2e3ebdSchin 		else if((arg->argflag&ARG_RAW) && (cp[1] || (*cp!='[' && *cp!=']')))
407da2e3ebdSchin 			cp = sh_fmtq(cp);
408da2e3ebdSchin 		sfputr(outfile,cp,flag);
409da2e3ebdSchin 		if(flag=='\n')
410da2e3ebdSchin 			begin_line = 1;
411da2e3ebdSchin 		arg = arg->argnxt.ap;
412da2e3ebdSchin 	}
413da2e3ebdSchin 	while((opts&POST) && arg);
414da2e3ebdSchin 	return;
415da2e3ebdSchin }
416da2e3ebdSchin 
p_redirect(register const struct ionod * iop)417da2e3ebdSchin static void p_redirect(register const struct ionod *iop)
418da2e3ebdSchin {
419da2e3ebdSchin 	register char *cp;
420da2e3ebdSchin 	register int iof,iof2;
421da2e3ebdSchin 	for(;iop;iop=iop->ionxt)
422da2e3ebdSchin 	{
423da2e3ebdSchin 		iof=iop->iofile;
424da2e3ebdSchin 		cp = io_op;
425da2e3ebdSchin 		if(iop->iovname)
426da2e3ebdSchin 		{
427da2e3ebdSchin 			sfwrite(outfile,"(;",2);
428da2e3ebdSchin 			sfputr(outfile,iop->iovname,')');
429da2e3ebdSchin 			cp++;
430da2e3ebdSchin 		}
431da2e3ebdSchin 		else
432da2e3ebdSchin 			*cp = '0'+(iof&IOUFD);
433da2e3ebdSchin 		if(iof&IOPUT)
434da2e3ebdSchin 		{
435da2e3ebdSchin 			if(*cp == '1' && !iop->iovname)
436da2e3ebdSchin 				cp++;
437da2e3ebdSchin 			io_op[1] = '>';
438da2e3ebdSchin 		}
439da2e3ebdSchin 		else
440da2e3ebdSchin 		{
441da2e3ebdSchin 			if(*cp == '0' && !iop->iovname)
442da2e3ebdSchin 				cp++;
443da2e3ebdSchin 			io_op[1] = '<';
444da2e3ebdSchin 		}
445da2e3ebdSchin 		io_op[2] = 0;
446da2e3ebdSchin 		io_op[3] = 0;
447da2e3ebdSchin 		if(iof&IOLSEEK)
448da2e3ebdSchin 		{
449da2e3ebdSchin 			io_op[1] = '#';
450da2e3ebdSchin 			if(iof&IOARITH)
451da2e3ebdSchin 				strcpy(&io_op[3]," ((");
452da2e3ebdSchin 		}
453da2e3ebdSchin 		else if(iof&IOMOV)
454da2e3ebdSchin 			io_op[2] = '&';
455da2e3ebdSchin 		else if(iof&(IORDW|IOAPP))
456da2e3ebdSchin 			io_op[2] = '>';
457da2e3ebdSchin 		else if(iof&IOCLOB)
458da2e3ebdSchin 			io_op[2] = '|';
459da2e3ebdSchin 		if(iop->iodelim)
460da2e3ebdSchin 		{
461da2e3ebdSchin 			/* here document */
462da2e3ebdSchin #ifdef xxx
463da2e3ebdSchin 			iop->iolink = (char*)here_doc;
464da2e3ebdSchin #endif
465da2e3ebdSchin 			here_doc  = iop;
466da2e3ebdSchin 			io_op[2] = '<';
467da2e3ebdSchin #ifdef future
468da2e3ebdSchin 			if(iof&IOSTRIP)
469da2e3ebdSchin 				io_op[3] = '-';
470da2e3ebdSchin #endif
471da2e3ebdSchin 		}
472da2e3ebdSchin 		sfputr(outfile,cp,' ');
473da2e3ebdSchin 		if(iop->ionxt)
474da2e3ebdSchin 			iof = ' ';
475da2e3ebdSchin 		else
476da2e3ebdSchin 		{
477da2e3ebdSchin 			if((iof=end_line)=='\n')
478da2e3ebdSchin 				begin_line = 1;
479da2e3ebdSchin 		}
480da2e3ebdSchin 		if((iof&IOLSEEK) && (iof&IOARITH))
481da2e3ebdSchin 			iof2 = iof, iof = ' ';
482da2e3ebdSchin 		if(iop->iodelim)
483da2e3ebdSchin 		{
484da2e3ebdSchin 			if(!(iop->iofile&IODOC))
485da2e3ebdSchin 				sfwrite(outfile,"''",2);
486da2e3ebdSchin 			sfputr(outfile,sh_fmtq(iop->iodelim),iof);
487da2e3ebdSchin 		}
488da2e3ebdSchin 		else if(iop->iofile&IORAW)
489da2e3ebdSchin 			sfputr(outfile,sh_fmtq(iop->ioname),iof);
490da2e3ebdSchin 		else
491da2e3ebdSchin 			sfputr(outfile,iop->ioname,iof);
492da2e3ebdSchin 		if((iof&IOLSEEK) && (iof&IOARITH))
493da2e3ebdSchin 			sfputr(outfile, "))", iof2);
494da2e3ebdSchin 	}
495da2e3ebdSchin 	return;
496da2e3ebdSchin }
497da2e3ebdSchin 
p_comarg(register const struct comnod * com)498da2e3ebdSchin static void p_comarg(register const struct comnod *com)
499da2e3ebdSchin {
500da2e3ebdSchin 	register int flag = end_line;
501da2e3ebdSchin 	if(com->comarg || com->comio)
502da2e3ebdSchin 		flag = ' ';
503da2e3ebdSchin 	if(com->comset)
504da2e3ebdSchin 		p_arg(com->comset,flag,POST);
505da2e3ebdSchin 	if(com->comarg)
506da2e3ebdSchin 	{
507da2e3ebdSchin 		if(!com->comio)
508da2e3ebdSchin 			flag = end_line;
509da2e3ebdSchin 		if(com->comtyp&COMSCAN)
510da2e3ebdSchin 			p_arg(com->comarg,flag,POST);
511da2e3ebdSchin 		else
512da2e3ebdSchin 			p_comlist((struct dolnod*)com->comarg,flag);
513da2e3ebdSchin 	}
514da2e3ebdSchin 	if(com->comio)
515da2e3ebdSchin 		p_redirect(com->comio);
516da2e3ebdSchin 	return;
517da2e3ebdSchin }
518da2e3ebdSchin 
p_comlist(const struct dolnod * dol,int endchar)519da2e3ebdSchin static void p_comlist(const struct dolnod *dol,int endchar)
520da2e3ebdSchin {
521da2e3ebdSchin 	register char *cp, *const*argv;
522da2e3ebdSchin 	register int flag = ' ', special;
523da2e3ebdSchin 	argv = dol->dolval+ARG_SPARE;
524da2e3ebdSchin 	cp = *argv;
525da2e3ebdSchin 	special = (*cp=='[' && cp[1]==0);
526da2e3ebdSchin 	do
527da2e3ebdSchin 	{
528da2e3ebdSchin 		if(cp)
529da2e3ebdSchin 			argv++;
530da2e3ebdSchin 		else
531da2e3ebdSchin 			cp = "";
532da2e3ebdSchin 		if(*argv==0)
533da2e3ebdSchin 		{
534da2e3ebdSchin 			if((flag=endchar)=='\n')
535da2e3ebdSchin 				begin_line = 1;
536da2e3ebdSchin 			special = (*cp==']' && cp[1]==0);
537da2e3ebdSchin 		}
538da2e3ebdSchin 		sfputr(outfile,special?cp:sh_fmtq(cp),flag);
539da2e3ebdSchin 		special = 0;
540da2e3ebdSchin 	}
541da2e3ebdSchin 	while(cp  = *argv);
542da2e3ebdSchin 	return;
543da2e3ebdSchin }
544da2e3ebdSchin 
p_switch(register const struct regnod * reg)545da2e3ebdSchin static void p_switch(register const struct regnod *reg)
546da2e3ebdSchin {
547da2e3ebdSchin 	if(level>1)
548da2e3ebdSchin 		sfnputc(outfile,'\t',level-1);
549da2e3ebdSchin 	p_arg(reg->regptr,')',PRE);
550da2e3ebdSchin 	begin_line = 0;
551da2e3ebdSchin 	sfputc(outfile,'\t');
552da2e3ebdSchin 	if(reg->regcom)
553da2e3ebdSchin 		p_tree(reg->regcom,0);
554da2e3ebdSchin 	level++;
555da2e3ebdSchin 	if(reg->regflag)
556da2e3ebdSchin 		p_keyword(";&",END);
557da2e3ebdSchin 	else
558da2e3ebdSchin 		p_keyword(";;",END);
559da2e3ebdSchin 	if(reg->regnxt)
560da2e3ebdSchin 		p_switch(reg->regnxt);
561da2e3ebdSchin 	return;
562da2e3ebdSchin }
563da2e3ebdSchin 
564da2e3ebdSchin /*
565da2e3ebdSchin  * output here documents
566da2e3ebdSchin  */
here_body(register const struct ionod * iop)567da2e3ebdSchin static void here_body(register const struct ionod *iop)
568da2e3ebdSchin {
569da2e3ebdSchin 	Sfio_t *infile;
570da2e3ebdSchin #ifdef xxx
571da2e3ebdSchin 	if(iop->iolink)
572da2e3ebdSchin 		here_body((struct inode*)iop->iolink);
573da2e3ebdSchin 	iop->iolink = 0;
574da2e3ebdSchin #endif
575da2e3ebdSchin 	if(iop->iofile&IOSTRG)
576da2e3ebdSchin 		infile = sfnew((Sfio_t*)0,iop->ioname,iop->iosize,-1,SF_STRING|SF_READ);
577da2e3ebdSchin 	else
578da2e3ebdSchin 		sfseek(infile=sh.heredocs,iop->iooffset,SEEK_SET);
579da2e3ebdSchin 	sfmove(infile,outfile,iop->iosize,-1);
580da2e3ebdSchin 	if(iop->iofile&IOSTRG)
581da2e3ebdSchin 		sfclose(infile);
582da2e3ebdSchin 	sfputr(outfile,iop->iodelim,'\n');
583da2e3ebdSchin }
584da2e3ebdSchin 
585