1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
34 #define HUGE_INT (((unsigned)-1)>>1)
42 /* flags that can be specified with p_tree() */
47 static void p_comlist(const struct dolnod
*,int);
48 static void p_arg(const struct argnod
*, int endchar
, int opts
);
49 static void p_comarg(const struct comnod
*);
50 static void p_keyword(const char*,int);
51 static void p_redirect(const struct ionod
*);
52 static void p_switch(const struct regnod
*);
53 static void here_body(const struct ionod
*);
54 static void p_tree(const Shnode_t
*,int);
57 static int begin_line
;
60 static char un_op
[3] = "-?";
61 static const struct ionod
*here_doc
;
62 static Sfio_t
*outfile
;
63 static const char *forinit
= "";
65 extern void sh_deparse(Sfio_t
*, const Shnode_t
*,int);
67 void sh_deparse(Sfio_t
*out
, const Shnode_t
*t
,int tflags
)
73 * print script corresponding to shell tree <t>
75 static void p_tree(register const Shnode_t
*t
,register int tflags
)
79 int needbrace
= (tflags
&NEED_BRACE
);
80 tflags
&= ~NEED_BRACE
;
85 switch(t
->tre
.tretyp
&COMMSK
)
88 if(t
->tre
.tretyp
&COMSCAN
)
91 p_keyword("time",BEGIN
);
93 p_tree(t
->par
.partre
,tflags
);
98 if(begin_line
&& level
>0)
99 sfnputc(outfile
,'\t',level
);
101 p_comarg((struct comnod
*)t
);
105 if(t
->tre
.tretyp
&FPCL
)
106 tflags
|= NEED_BRACE
;
108 tflags
= NO_NEWLINE
|NEED_BRACE
;
109 p_tree(t
->fork
.forktre
,tflags
);
110 p_redirect(t
->fork
.forkio
);
115 tflags
|= NEED_BRACE
;
116 if(t
->tre
.tretyp
&(FAMP
|FCOOP
))
118 tflags
= NEED_BRACE
|NO_NEWLINE
;
121 else if(t
->fork
.forkio
)
123 p_tree(t
->fork
.forktre
,tflags
);
125 p_redirect(t
->fork
.forkio
);
126 if(t
->tre
.tretyp
&FCOOP
)
128 sfputr(outfile
,"|&",'\n');
131 else if(t
->tre
.tretyp
&FAMP
)
133 sfputr(outfile
,"&",'\n');
139 p_keyword("if",BEGIN
);
140 p_tree(t
->if_
.iftre
,0);
141 p_keyword("then",MIDDLE
);
142 p_tree(t
->if_
.thtre
,0);
145 p_keyword("else",MIDDLE
);
146 p_tree(t
->if_
.eltre
,0);
154 else if(t
->tre
.tretyp
&COMSCAN
)
161 struct argnod
*arg
= (t
->wh
.whtre
)->ar
.arexpr
;
162 sfprintf(outfile
,"(( %s; ",forinit
);
164 sfputr(outfile
,arg
->argval
,';');
165 arg
= (t
->wh
.whinc
)->arexpr
;
166 sfprintf(outfile
," %s))\n",arg
->argval
);
169 p_tree(t
->wh
.whtre
,0);
175 Shnode_t
*tr
= t
->lst
.lstrit
;
176 if(tr
->tre
.tretyp
==TWH
&& tr
->wh
.whinc
&& t
->lst
.lstlef
->tre
.tretyp
==TARITH
)
178 /* arithmetic for statement */
179 struct argnod
*init
= (t
->lst
.lstlef
)->ar
.arexpr
;
180 forinit
= init
->argval
;
181 p_tree(t
->lst
.lstrit
,tflags
);
185 p_keyword("{",BEGIN
);
186 p_tree(t
->lst
.lstlef
,0);
189 p_tree(t
->lst
.lstrit
,tflags
);
206 if(t
->tre
.tretyp
&TTEST
)
208 tflags
|= NO_NEWLINE
;
209 if(!(tflags
&NO_BRACKET
))
211 p_keyword("[[",BEGIN
);
212 tflags
|= NO_BRACKET
;
216 p_tree(t
->lst
.lstlef
,NEED_BRACE
|NO_NEWLINE
|(tflags
&NO_BRACKET
));
217 sfputr(outfile
,cp
,here_doc
?'\n':' ');
224 p_tree(t
->lst
.lstrit
,tflags
|NEED_BRACE
);
232 p_keyword("(",BEGIN
);
233 p_tree(t
->par
.partre
,0);
239 register struct argnod
*ap
= t
->ar
.arexpr
;
240 if(begin_line
&& level
)
241 sfnputc(outfile
,'\t',level
);
242 sfprintf(outfile
,"(( %s ))%c",ap
->argval
,end_line
);
243 if(!(tflags
&NO_NEWLINE
))
249 cp
= ((t
->tre
.tretyp
&COMSCAN
)?"select":"for");
251 sfputr(outfile
,t
->for_
.fornam
,' ');
254 sfputr(outfile
,"in",' ');
257 p_comarg(t
->for_
.forlst
);
261 sfputc(outfile
,'\n');
265 p_keyword("do",MIDDLE
);
267 p_keyword("done",END
);
271 p_keyword("case",BEGIN
);
272 p_arg(t
->sw
.swarg
,' ',0);
276 sfputr(outfile
,"in",'\n');
279 p_switch(t
->sw
.swlst
);
282 p_keyword("esac",END
);
286 if(t
->tre
.tretyp
&FPOSIX
)
288 sfprintf(outfile
,"%s",t
->funct
.functnam
);
289 p_keyword("()\n",BEGIN
);
293 p_keyword("function",BEGIN
);
294 tflags
= (t
->funct
.functargs
?' ':'\n');
295 sfputr(outfile
,t
->funct
.functnam
,tflags
);
296 if(t
->funct
.functargs
)
300 p_comarg(t
->funct
.functargs
);
305 p_keyword("{\n",MIDDLE
);
307 p_tree(t
->funct
.functtre
,0);
310 /* new test compound command */
312 if(!(tflags
&NO_BRACKET
))
313 p_keyword("[[",BEGIN
);
314 if((t
->tre
.tretyp
&TPAREN
)==TPAREN
)
316 p_keyword("(",BEGIN
);
317 p_tree(t
->lst
.lstlef
,NO_BRACKET
|NO_NEWLINE
);
322 int flags
= (t
->tre
.tretyp
)>>TSHIFT
;
323 if(t
->tre
.tretyp
&TNEGATE
)
324 sfputr(outfile
,"!",' ');
325 if(t
->tre
.tretyp
&TUNARY
)
328 sfputr(outfile
,un_op
,' ');
331 cp
= ((char*)(shtab_testops
+(flags
&037)-1)->sh_name
);
332 p_arg(&(t
->lst
.lstlef
->arg
),' ',0);
333 if(t
->tre
.tretyp
&TBINARY
)
335 sfputr(outfile
,cp
,' ');
336 p_arg(&(t
->lst
.lstrit
->arg
),' ',0);
339 if(!(tflags
&NO_BRACKET
))
342 while(begin_line
&& here_doc
)
353 * increment indent level for flag==BEGIN
354 * decrement indent level for flag==END
356 static void p_keyword(const char *word
,int flag
)
361 else if(*word
=='[' || *word
=='(')
367 if(begin_line
&& level
)
368 sfnputc(outfile
,'\t',level
);
369 sfputr(outfile
,word
,sep
);
378 static void p_arg(register const struct argnod
*arg
,register int endchar
,int opts
)
380 register const char *cp
;
388 /* case alternation lists in reverse order */
389 p_arg(arg
->argnxt
.ap
,'|',opts
);
395 if(*cp
==0 && opts
==POST
&& arg
->argchn
.ap
)
397 /* compound assignment */
398 struct fornod
*fp
=(struct fornod
*)arg
->argchn
.ap
;
399 sfprintf(outfile
,"%s=(\n",fp
->fornam
);
400 sfnputc(outfile
,'\t',++level
);
401 p_tree(fp
->fortre
,0);
403 sfnputc(outfile
,'\t',level
);
406 else if((arg
->argflag
&ARG_RAW
) && (cp
[1] || (*cp
!='[' && *cp
!=']')))
408 sfputr(outfile
,cp
,flag
);
411 arg
= arg
->argnxt
.ap
;
413 while((opts
&POST
) && arg
);
417 static void p_redirect(register const struct ionod
*iop
)
420 register int iof
,iof2
;
421 for(;iop
;iop
=iop
->ionxt
)
427 sfwrite(outfile
,"(;",2);
428 sfputr(outfile
,iop
->iovname
,')');
432 *cp
= '0'+(iof
&IOUFD
);
435 if(*cp
== '1' && !iop
->iovname
)
441 if(*cp
== '0' && !iop
->iovname
)
451 strcpy(&io_op
[3]," ((");
455 else if(iof
&(IORDW
|IOAPP
))
463 iop
->iolink
= (char*)here_doc
;
472 sfputr(outfile
,cp
,' ');
477 if((iof
=end_line
)=='\n')
480 if((iof
&IOLSEEK
) && (iof
&IOARITH
))
481 iof2
= iof
, iof
= ' ';
484 if(!(iop
->iofile
&IODOC
))
485 sfwrite(outfile
,"''",2);
486 sfputr(outfile
,sh_fmtq(iop
->iodelim
),iof
);
488 else if(iop
->iofile
&IORAW
)
489 sfputr(outfile
,sh_fmtq(iop
->ioname
),iof
);
491 sfputr(outfile
,iop
->ioname
,iof
);
492 if((iof
&IOLSEEK
) && (iof
&IOARITH
))
493 sfputr(outfile
, "))", iof2
);
498 static void p_comarg(register const struct comnod
*com
)
500 register int flag
= end_line
;
501 if(com
->comarg
|| com
->comio
)
504 p_arg(com
->comset
,flag
,POST
);
509 if(com
->comtyp
&COMSCAN
)
510 p_arg(com
->comarg
,flag
,POST
);
512 p_comlist((struct dolnod
*)com
->comarg
,flag
);
515 p_redirect(com
->comio
);
519 static void p_comlist(const struct dolnod
*dol
,int endchar
)
521 register char *cp
, *const*argv
;
522 register int flag
= ' ', special
;
523 argv
= dol
->dolval
+ARG_SPARE
;
525 special
= (*cp
=='[' && cp
[1]==0);
534 if((flag
=endchar
)=='\n')
536 special
= (*cp
==']' && cp
[1]==0);
538 sfputr(outfile
,special
?cp
:sh_fmtq(cp
),flag
);
545 static void p_switch(register const struct regnod
*reg
)
548 sfnputc(outfile
,'\t',level
-1);
549 p_arg(reg
->regptr
,')',PRE
);
551 sfputc(outfile
,'\t');
553 p_tree(reg
->regcom
,0);
560 p_switch(reg
->regnxt
);
565 * output here documents
567 static void here_body(register const struct ionod
*iop
)
572 here_body((struct inode
*)iop
->iolink
);
575 if(iop
->iofile
&IOSTRG
)
576 infile
= sfnew((Sfio_t
*)0,iop
->ioname
,iop
->iosize
,-1,SF_STRING
|SF_READ
);
578 sfseek(infile
=sh
.heredocs
,iop
->iooffset
,SEEK_SET
);
579 sfmove(infile
,outfile
,iop
->iosize
,-1);
580 if(iop
->iofile
&IOSTRG
)
582 sfputr(outfile
,iop
->iodelim
,'\n');