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