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