14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 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 */ 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 */ 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 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 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 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 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 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 */ 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