14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * David Korn
234887Schin * AT&T Labs
244887Schin *
254887Schin * shell deparser
264887Schin *
274887Schin */
284887Schin
294887Schin #include "defs.h"
304887Schin #include "shnodes.h"
314887Schin #include "test.h"
324887Schin
334887Schin
344887Schin #define HUGE_INT (((unsigned)-1)>>1)
354887Schin #define BEGIN 0
364887Schin #define MIDDLE 1
374887Schin #define END 2
384887Schin #define PRE 1
394887Schin #define POST 2
404887Schin
414887Schin
424887Schin /* flags that can be specified with p_tree() */
434887Schin #define NO_NEWLINE 1
444887Schin #define NEED_BRACE 2
454887Schin #define NO_BRACKET 4
464887Schin
474887Schin static void p_comlist(const struct dolnod*,int);
484887Schin static void p_arg(const struct argnod*, int endchar, int opts);
494887Schin static void p_comarg(const struct comnod*);
504887Schin static void p_keyword(const char*,int);
514887Schin static void p_redirect(const struct ionod*);
524887Schin static void p_switch(const struct regnod*);
534887Schin static void here_body(const struct ionod*);
544887Schin static void p_tree(const Shnode_t*,int);
554887Schin
564887Schin static int level;
574887Schin static int begin_line;
584887Schin static int end_line;
594887Schin static char io_op[7];
604887Schin static char un_op[3] = "-?";
614887Schin static const struct ionod *here_doc;
624887Schin static Sfio_t *outfile;
634887Schin static const char *forinit = "";
644887Schin
654887Schin extern void sh_deparse(Sfio_t*, const Shnode_t*,int);
664887Schin
sh_deparse(Sfio_t * out,const Shnode_t * t,int tflags)674887Schin void sh_deparse(Sfio_t *out, const Shnode_t *t,int tflags)
684887Schin {
694887Schin outfile = out;
704887Schin p_tree(t,tflags);
714887Schin }
724887Schin /*
734887Schin * print script corresponding to shell tree <t>
744887Schin */
p_tree(register const Shnode_t * t,register int tflags)754887Schin static void p_tree(register const Shnode_t *t,register int tflags)
764887Schin {
774887Schin register char *cp;
784887Schin int save = end_line;
794887Schin int needbrace = (tflags&NEED_BRACE);
804887Schin tflags &= ~NEED_BRACE;
814887Schin if(tflags&NO_NEWLINE)
824887Schin end_line = ' ';
834887Schin else
844887Schin end_line = '\n';
854887Schin switch(t->tre.tretyp&COMMSK)
864887Schin {
874887Schin case TTIME:
884887Schin if(t->tre.tretyp&COMSCAN)
894887Schin p_keyword("!",BEGIN);
904887Schin else
914887Schin p_keyword("time",BEGIN);
924887Schin if(t->par.partre)
934887Schin p_tree(t->par.partre,tflags);
944887Schin level--;
954887Schin break;
964887Schin
974887Schin case TCOM:
984887Schin if(begin_line && level>0)
994887Schin sfnputc(outfile,'\t',level);
1004887Schin begin_line = 0;
1014887Schin p_comarg((struct comnod*)t);
1024887Schin break;
1034887Schin
1044887Schin case TSETIO:
1054887Schin if(t->tre.tretyp&FPCL)
1064887Schin tflags |= NEED_BRACE;
1074887Schin else
1084887Schin tflags = NO_NEWLINE|NEED_BRACE;
1094887Schin p_tree(t->fork.forktre,tflags);
1104887Schin p_redirect(t->fork.forkio);
1114887Schin break;
1124887Schin
1134887Schin case TFORK:
1144887Schin if(needbrace)
1154887Schin tflags |= NEED_BRACE;
1164887Schin if(t->tre.tretyp&(FAMP|FCOOP))
1174887Schin {
1184887Schin tflags = NEED_BRACE|NO_NEWLINE;
1194887Schin end_line = ' ';
1204887Schin }
1214887Schin else if(t->fork.forkio)
1224887Schin tflags = NO_NEWLINE;
1234887Schin p_tree(t->fork.forktre,tflags);
1244887Schin if(t->fork.forkio)
1254887Schin p_redirect(t->fork.forkio);
1264887Schin if(t->tre.tretyp&FCOOP)
1274887Schin {
1284887Schin sfputr(outfile,"|&",'\n');
1294887Schin begin_line = 1;
1304887Schin }
1314887Schin else if(t->tre.tretyp&FAMP)
1324887Schin {
1334887Schin sfputr(outfile,"&",'\n');
1344887Schin begin_line = 1;
1354887Schin }
1364887Schin break;
1374887Schin
1384887Schin case TIF:
1394887Schin p_keyword("if",BEGIN);
1404887Schin p_tree(t->if_.iftre,0);
1414887Schin p_keyword("then",MIDDLE);
1424887Schin p_tree(t->if_.thtre,0);
1434887Schin if(t->if_.eltre)
1444887Schin {
1454887Schin p_keyword("else",MIDDLE);
1464887Schin p_tree(t->if_.eltre,0);
1474887Schin }
1484887Schin p_keyword("fi",END);
1494887Schin break;
1504887Schin
1514887Schin case TWH:
1524887Schin if(t->wh.whinc)
1534887Schin cp = "for";
1544887Schin else if(t->tre.tretyp&COMSCAN)
1554887Schin cp = "until";
1564887Schin else
1574887Schin cp = "while";
1584887Schin p_keyword(cp,BEGIN);
1594887Schin if(t->wh.whinc)
1604887Schin {
1614887Schin struct argnod *arg = (t->wh.whtre)->ar.arexpr;
1624887Schin sfprintf(outfile,"(( %s; ",forinit);
1634887Schin forinit = "";
1644887Schin sfputr(outfile,arg->argval,';');
1654887Schin arg = (t->wh.whinc)->arexpr;
1664887Schin sfprintf(outfile," %s))\n",arg->argval);
1674887Schin }
1684887Schin else
1694887Schin p_tree(t->wh.whtre,0);
1704887Schin t = t->wh.dotre;
1714887Schin goto dolist;
1724887Schin
1734887Schin case TLST:
1744887Schin {
1754887Schin Shnode_t *tr = t->lst.lstrit;
1764887Schin if(tr->tre.tretyp==TWH && tr->wh.whinc && t->lst.lstlef->tre.tretyp==TARITH)
1774887Schin {
1784887Schin /* arithmetic for statement */
1794887Schin struct argnod *init = (t->lst.lstlef)->ar.arexpr;
1804887Schin forinit= init->argval;
1814887Schin p_tree(t->lst.lstrit,tflags);
1824887Schin break;
1834887Schin }
1844887Schin if(needbrace)
1854887Schin p_keyword("{",BEGIN);
1864887Schin p_tree(t->lst.lstlef,0);
1874887Schin if(needbrace)
1884887Schin tflags = 0;
1894887Schin p_tree(t->lst.lstrit,tflags);
1904887Schin if(needbrace)
1914887Schin p_keyword("}",END);
1924887Schin break;
1934887Schin }
1944887Schin
1954887Schin case TAND:
1964887Schin cp = "&&";
1974887Schin goto andor;
1984887Schin case TORF:
1994887Schin cp = "||";
2004887Schin goto andor;
2014887Schin case TFIL:
2024887Schin cp = "|";
2034887Schin andor:
2044887Schin {
2054887Schin int bracket = 0;
2064887Schin if(t->tre.tretyp&TTEST)
2074887Schin {
2084887Schin tflags |= NO_NEWLINE;
2094887Schin if(!(tflags&NO_BRACKET))
2104887Schin {
2114887Schin p_keyword("[[",BEGIN);
2124887Schin tflags |= NO_BRACKET;
2134887Schin bracket=1;
2144887Schin }
2154887Schin }
2164887Schin p_tree(t->lst.lstlef,NEED_BRACE|NO_NEWLINE|(tflags&NO_BRACKET));
2174887Schin sfputr(outfile,cp,here_doc?'\n':' ');
2184887Schin if(here_doc)
2194887Schin {
2204887Schin here_body(here_doc);
2214887Schin here_doc = 0;
2224887Schin }
2234887Schin level++;
2244887Schin p_tree(t->lst.lstrit,tflags|NEED_BRACE);
2254887Schin if(bracket)
2264887Schin p_keyword("]]",END);
2274887Schin level--;
2284887Schin break;
2294887Schin }
2304887Schin
2314887Schin case TPAR:
2324887Schin p_keyword("(",BEGIN);
2334887Schin p_tree(t->par.partre,0);
2344887Schin p_keyword(")",END);
2354887Schin break;
2364887Schin
2374887Schin case TARITH:
2384887Schin {
2394887Schin register struct argnod *ap = t->ar.arexpr;
2404887Schin if(begin_line && level)
2414887Schin sfnputc(outfile,'\t',level);
2424887Schin sfprintf(outfile,"(( %s ))%c",ap->argval,end_line);
2434887Schin if(!(tflags&NO_NEWLINE))
2444887Schin begin_line=1;
2454887Schin break;
2464887Schin }
2474887Schin
2484887Schin case TFOR:
2494887Schin cp = ((t->tre.tretyp&COMSCAN)?"select":"for");
2504887Schin p_keyword(cp,BEGIN);
2514887Schin sfputr(outfile,t->for_.fornam,' ');
2524887Schin if(t->for_.forlst)
2534887Schin {
2544887Schin sfputr(outfile,"in",' ');
2554887Schin tflags = end_line;
2564887Schin end_line = '\n';
2574887Schin p_comarg(t->for_.forlst);
2584887Schin end_line = tflags;
2594887Schin }
2604887Schin else
2614887Schin sfputc(outfile,'\n');
2624887Schin begin_line = 1;
2634887Schin t = t->for_.fortre;
2644887Schin dolist:
2654887Schin p_keyword("do",MIDDLE);
2664887Schin p_tree(t,0);
2674887Schin p_keyword("done",END);
2684887Schin break;
2694887Schin
2704887Schin case TSW:
2714887Schin p_keyword("case",BEGIN);
2724887Schin p_arg(t->sw.swarg,' ',0);
2734887Schin if(t->sw.swlst)
2744887Schin {
2754887Schin begin_line = 1;
2764887Schin sfputr(outfile,"in",'\n');
2774887Schin tflags = end_line;
2784887Schin end_line = '\n';
2794887Schin p_switch(t->sw.swlst);
2804887Schin end_line = tflags;
2814887Schin }
2824887Schin p_keyword("esac",END);
2834887Schin break;
2844887Schin
2854887Schin case TFUN:
2864887Schin if(t->tre.tretyp&FPOSIX)
2874887Schin {
2884887Schin sfprintf(outfile,"%s",t->funct.functnam);
2894887Schin p_keyword("()\n",BEGIN);
2904887Schin }
2914887Schin else
2924887Schin {
2934887Schin p_keyword("function",BEGIN);
2944887Schin tflags = (t->funct.functargs?' ':'\n');
2954887Schin sfputr(outfile,t->funct.functnam,tflags);
2964887Schin if(t->funct.functargs)
2974887Schin {
2984887Schin tflags = end_line;
2994887Schin end_line = '\n';
3004887Schin p_comarg(t->funct.functargs);
3014887Schin end_line = tflags;
3024887Schin }
3034887Schin }
3044887Schin begin_line = 1;
3054887Schin p_keyword("{\n",MIDDLE);
3064887Schin begin_line = 1;
3074887Schin p_tree(t->funct.functtre,0);
3084887Schin p_keyword("}",END);
3094887Schin break;
3104887Schin /* new test compound command */
3114887Schin case TTST:
3124887Schin if(!(tflags&NO_BRACKET))
3134887Schin p_keyword("[[",BEGIN);
3144887Schin if((t->tre.tretyp&TPAREN)==TPAREN)
3154887Schin {
3164887Schin p_keyword("(",BEGIN);
3174887Schin p_tree(t->lst.lstlef,NO_BRACKET|NO_NEWLINE);
3184887Schin p_keyword(")",END);
3194887Schin }
3204887Schin else
3214887Schin {
3224887Schin int flags = (t->tre.tretyp)>>TSHIFT;
3234887Schin if(t->tre.tretyp&TNEGATE)
3244887Schin sfputr(outfile,"!",' ');
3254887Schin if(t->tre.tretyp&TUNARY)
3264887Schin {
3274887Schin un_op[1] = flags;
3284887Schin sfputr(outfile,un_op,' ');
3294887Schin }
3304887Schin else
3314887Schin cp = ((char*)(shtab_testops+(flags&037)-1)->sh_name);
3324887Schin p_arg(&(t->lst.lstlef->arg),' ',0);
3334887Schin if(t->tre.tretyp&TBINARY)
3344887Schin {
3354887Schin sfputr(outfile,cp,' ');
3364887Schin p_arg(&(t->lst.lstrit->arg),' ',0);
3374887Schin }
3384887Schin }
3394887Schin if(!(tflags&NO_BRACKET))
3404887Schin p_keyword("]]",END);
3414887Schin }
3424887Schin while(begin_line && here_doc)
3434887Schin {
3444887Schin here_body(here_doc);
3454887Schin here_doc = 0;
3464887Schin }
3474887Schin end_line = save;
3484887Schin return;
3494887Schin }
3504887Schin
3514887Schin /*
3524887Schin * print a keyword
3534887Schin * increment indent level for flag==BEGIN
3544887Schin * decrement indent level for flag==END
3554887Schin */
p_keyword(const char * word,int flag)3564887Schin static void p_keyword(const char *word,int flag)
3574887Schin {
3584887Schin register int sep;
3594887Schin if(flag==END)
3604887Schin sep = end_line;
3614887Schin else if(*word=='[' || *word=='(')
3624887Schin sep = ' ';
3634887Schin else
3644887Schin sep = '\t';
3654887Schin if(flag!=BEGIN)
3664887Schin level--;
3674887Schin if(begin_line && level)
3684887Schin sfnputc(outfile,'\t',level);
3694887Schin sfputr(outfile,word,sep);
3704887Schin if(sep=='\n')
3714887Schin begin_line=1;
3724887Schin else
3734887Schin begin_line=0;
3744887Schin if(flag!=END)
3754887Schin level++;
3764887Schin }
3774887Schin
p_arg(register const struct argnod * arg,register int endchar,int opts)3784887Schin static void p_arg(register const struct argnod *arg,register int endchar,int opts)
3794887Schin {
3804887Schin register const char *cp;
3814887Schin register int flag;
3824887Schin do
3834887Schin {
3844887Schin if(!arg->argnxt.ap)
3854887Schin flag = endchar;
3864887Schin else if(opts&PRE)
3874887Schin {
3884887Schin /* case alternation lists in reverse order */
3894887Schin p_arg(arg->argnxt.ap,'|',opts);
3904887Schin flag = endchar;
3914887Schin }
3924887Schin else if(opts)
3934887Schin flag = ' ';
3944887Schin cp = arg->argval;
3954887Schin if(*cp==0 && opts==POST && arg->argchn.ap)
3964887Schin {
3974887Schin /* compound assignment */
3984887Schin struct fornod *fp=(struct fornod*)arg->argchn.ap;
3994887Schin sfprintf(outfile,"%s=(\n",fp->fornam);
4004887Schin sfnputc(outfile,'\t',++level);
4014887Schin p_tree(fp->fortre,0);
4024887Schin if(--level)
4034887Schin sfnputc(outfile,'\t',level);
4044887Schin sfputc(outfile,')');
4054887Schin }
4064887Schin else if((arg->argflag&ARG_RAW) && (cp[1] || (*cp!='[' && *cp!=']')))
4074887Schin cp = sh_fmtq(cp);
4084887Schin sfputr(outfile,cp,flag);
4094887Schin if(flag=='\n')
4104887Schin begin_line = 1;
4114887Schin arg = arg->argnxt.ap;
4124887Schin }
4134887Schin while((opts&POST) && arg);
4144887Schin return;
4154887Schin }
4164887Schin
p_redirect(register const struct ionod * iop)4174887Schin static void p_redirect(register const struct ionod *iop)
4184887Schin {
4194887Schin register char *cp;
4204887Schin register int iof,iof2;
4214887Schin for(;iop;iop=iop->ionxt)
4224887Schin {
4234887Schin iof=iop->iofile;
4244887Schin cp = io_op;
4254887Schin if(iop->iovname)
4264887Schin {
4274887Schin sfwrite(outfile,"(;",2);
4284887Schin sfputr(outfile,iop->iovname,')');
4294887Schin cp++;
4304887Schin }
4314887Schin else
4324887Schin *cp = '0'+(iof&IOUFD);
4334887Schin if(iof&IOPUT)
4344887Schin {
4354887Schin if(*cp == '1' && !iop->iovname)
4364887Schin cp++;
4374887Schin io_op[1] = '>';
4384887Schin }
4394887Schin else
4404887Schin {
4414887Schin if(*cp == '0' && !iop->iovname)
4424887Schin cp++;
4434887Schin io_op[1] = '<';
4444887Schin }
4454887Schin io_op[2] = 0;
4464887Schin io_op[3] = 0;
4474887Schin if(iof&IOLSEEK)
4484887Schin {
4494887Schin io_op[1] = '#';
4504887Schin if(iof&IOARITH)
4514887Schin strcpy(&io_op[3]," ((");
4524887Schin }
4534887Schin else if(iof&IOMOV)
4544887Schin io_op[2] = '&';
4554887Schin else if(iof&(IORDW|IOAPP))
4564887Schin io_op[2] = '>';
4574887Schin else if(iof&IOCLOB)
4584887Schin io_op[2] = '|';
4594887Schin if(iop->iodelim)
4604887Schin {
4614887Schin /* here document */
4624887Schin #ifdef xxx
4634887Schin iop->iolink = (char*)here_doc;
4644887Schin #endif
4654887Schin here_doc = iop;
4664887Schin io_op[2] = '<';
4674887Schin #ifdef future
4684887Schin if(iof&IOSTRIP)
4694887Schin io_op[3] = '-';
4704887Schin #endif
4714887Schin }
4724887Schin sfputr(outfile,cp,' ');
4734887Schin if(iop->ionxt)
4744887Schin iof = ' ';
4754887Schin else
4764887Schin {
4774887Schin if((iof=end_line)=='\n')
4784887Schin begin_line = 1;
4794887Schin }
4804887Schin if((iof&IOLSEEK) && (iof&IOARITH))
4814887Schin iof2 = iof, iof = ' ';
4824887Schin if(iop->iodelim)
4834887Schin {
4844887Schin if(!(iop->iofile&IODOC))
4854887Schin sfwrite(outfile,"''",2);
4864887Schin sfputr(outfile,sh_fmtq(iop->iodelim),iof);
4874887Schin }
4884887Schin else if(iop->iofile&IORAW)
4894887Schin sfputr(outfile,sh_fmtq(iop->ioname),iof);
4904887Schin else
4914887Schin sfputr(outfile,iop->ioname,iof);
4924887Schin if((iof&IOLSEEK) && (iof&IOARITH))
4934887Schin sfputr(outfile, "))", iof2);
4944887Schin }
4954887Schin return;
4964887Schin }
4974887Schin
p_comarg(register const struct comnod * com)4984887Schin static void p_comarg(register const struct comnod *com)
4994887Schin {
5004887Schin register int flag = end_line;
5014887Schin if(com->comarg || com->comio)
5024887Schin flag = ' ';
5034887Schin if(com->comset)
5044887Schin p_arg(com->comset,flag,POST);
5054887Schin if(com->comarg)
5064887Schin {
5074887Schin if(!com->comio)
5084887Schin flag = end_line;
5094887Schin if(com->comtyp&COMSCAN)
5104887Schin p_arg(com->comarg,flag,POST);
5114887Schin else
5124887Schin p_comlist((struct dolnod*)com->comarg,flag);
5134887Schin }
5144887Schin if(com->comio)
5154887Schin p_redirect(com->comio);
5164887Schin return;
5174887Schin }
5184887Schin
p_comlist(const struct dolnod * dol,int endchar)5194887Schin static void p_comlist(const struct dolnod *dol,int endchar)
5204887Schin {
5214887Schin register char *cp, *const*argv;
5224887Schin register int flag = ' ', special;
5234887Schin argv = dol->dolval+ARG_SPARE;
5244887Schin cp = *argv;
5254887Schin special = (*cp=='[' && cp[1]==0);
5264887Schin do
5274887Schin {
5284887Schin if(cp)
5294887Schin argv++;
5304887Schin else
5314887Schin cp = "";
5324887Schin if(*argv==0)
5334887Schin {
5344887Schin if((flag=endchar)=='\n')
5354887Schin begin_line = 1;
5364887Schin special = (*cp==']' && cp[1]==0);
5374887Schin }
5384887Schin sfputr(outfile,special?cp:sh_fmtq(cp),flag);
5394887Schin special = 0;
5404887Schin }
5414887Schin while(cp = *argv);
5424887Schin return;
5434887Schin }
5444887Schin
p_switch(register const struct regnod * reg)5454887Schin static void p_switch(register const struct regnod *reg)
5464887Schin {
5474887Schin if(level>1)
5484887Schin sfnputc(outfile,'\t',level-1);
5494887Schin p_arg(reg->regptr,')',PRE);
5504887Schin begin_line = 0;
5514887Schin sfputc(outfile,'\t');
5524887Schin if(reg->regcom)
5534887Schin p_tree(reg->regcom,0);
5544887Schin level++;
5554887Schin if(reg->regflag)
5564887Schin p_keyword(";&",END);
5574887Schin else
5584887Schin p_keyword(";;",END);
5594887Schin if(reg->regnxt)
5604887Schin p_switch(reg->regnxt);
5614887Schin return;
5624887Schin }
5634887Schin
5644887Schin /*
5654887Schin * output here documents
5664887Schin */
here_body(register const struct ionod * iop)5674887Schin static void here_body(register const struct ionod *iop)
5684887Schin {
5694887Schin Sfio_t *infile;
5704887Schin #ifdef xxx
5714887Schin if(iop->iolink)
5724887Schin here_body((struct inode*)iop->iolink);
5734887Schin iop->iolink = 0;
5744887Schin #endif
5754887Schin if(iop->iofile&IOSTRG)
5764887Schin infile = sfnew((Sfio_t*)0,iop->ioname,iop->iosize,-1,SF_STRING|SF_READ);
5774887Schin else
5784887Schin sfseek(infile=sh.heredocs,iop->iooffset,SEEK_SET);
5794887Schin sfmove(infile,outfile,iop->iosize,-1);
5804887Schin if(iop->iofile&IOSTRG)
5814887Schin sfclose(infile);
5824887Schin sfputr(outfile,iop->iodelim,'\n');
5834887Schin }
5844887Schin
585