Logo Search packages:      
Sourcecode: ksh version File versions

deparse.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                  David Korn <dgk@research.att.com>                   *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * David Korn
 * AT&T Labs
 *
 * shell deparser
 *
 */

#include    "defs.h"
#include    "shnodes.h"
#include    "test.h"


#define HUGE_INT  (((unsigned)-1)>>1)
#define     BEGIN 0
#define MIDDLE    1
#define     END   2
#define PRE 1
#define POST      2


/* flags that can be specified with p_tree() */
#define NO_NEWLINE      1
#define NEED_BRACE      2
#define NO_BRACKET      4

static void p_comlist(const struct dolnod*,int);
static void p_arg(const struct argnod*, int endchar, int opts);
static void p_comarg(const struct comnod*);
static void p_keyword(const char*,int);
static void p_redirect(const struct ionod*);
static void p_switch(const struct regnod*);
static void here_body(const struct ionod*);
static void p_tree(const Shnode_t*,int);

static int level;
static int begin_line;
static int end_line;
static char io_op[7];
static char un_op[3] = "-?";
static const struct ionod *here_doc;
static Sfio_t *outfile;
static const char *forinit = "";

extern void sh_deparse(Sfio_t*, const Shnode_t*,int);

void sh_deparse(Sfio_t *out, const Shnode_t *t,int tflags)
{
      outfile = out;
      p_tree(t,tflags);
}
/*
 * print script corresponding to shell tree <t>
 */
static void p_tree(register const Shnode_t *t,register int tflags)
{
      register char *cp;
      int save = end_line;
      int needbrace = (tflags&NEED_BRACE);
      tflags &= ~NEED_BRACE;
      if(tflags&NO_NEWLINE)
            end_line = ' ';
      else
            end_line = '\n';
      switch(t->tre.tretyp&COMMSK)
      {
            case TTIME:
                  if(t->tre.tretyp&COMSCAN)
                        p_keyword("!",BEGIN);
                  else
                        p_keyword("time",BEGIN);
                  if(t->par.partre)
                        p_tree(t->par.partre,tflags); 
                  level--;
                  break;

            case TCOM:
                  if(begin_line && level>0)
                        sfnputc(outfile,'\t',level);
                  begin_line = 0;
                  p_comarg((struct comnod*)t);
                  break;

            case TSETIO:
                  if(t->tre.tretyp&FPCL)
                        tflags |= NEED_BRACE;
                  else
                        tflags = NO_NEWLINE|NEED_BRACE;
                  p_tree(t->fork.forktre,tflags);
                  p_redirect(t->fork.forkio);
                  break;

            case TFORK:
                  if(needbrace)
                        tflags |= NEED_BRACE;
                  if(t->tre.tretyp&(FAMP|FCOOP))
                  {
                        tflags = NEED_BRACE|NO_NEWLINE;
                        end_line = ' ';
                  }
                  else if(t->fork.forkio)
                        tflags = NO_NEWLINE;
                  p_tree(t->fork.forktre,tflags);
                  if(t->fork.forkio)
                        p_redirect(t->fork.forkio);
                  if(t->tre.tretyp&FCOOP)
                  {
                        sfputr(outfile,"|&",'\n');
                        begin_line = 1;
                  }
                  else if(t->tre.tretyp&FAMP)
                  {
                        sfputr(outfile,"&",'\n');
                        begin_line = 1;
                  }
                  break;
      
            case TIF:
                  p_keyword("if",BEGIN);
                  p_tree(t->if_.iftre,0);
                  p_keyword("then",MIDDLE);
                  p_tree(t->if_.thtre,0);
                  if(t->if_.eltre)
                  {
                        p_keyword("else",MIDDLE);
                        p_tree(t->if_.eltre,0);
                  }
                  p_keyword("fi",END);
                  break;

            case TWH:
                  if(t->wh.whinc)
                        cp = "for";
                  else if(t->tre.tretyp&COMSCAN)
                        cp = "until";
                  else
                        cp = "while";
                  p_keyword(cp,BEGIN);
                  if(t->wh.whinc)
                  {
                        struct argnod *arg = (t->wh.whtre)->ar.arexpr;
                        sfprintf(outfile,"(( %s; ",forinit);
                        forinit = "";
                        sfputr(outfile,arg->argval,';');
                        arg = (t->wh.whinc)->arexpr;
                        sfprintf(outfile," %s))\n",arg->argval);
                  }
                  else
                        p_tree(t->wh.whtre,0);
                  t = t->wh.dotre;
                  goto dolist;

            case TLST:
            {
                  Shnode_t *tr = t->lst.lstrit;
                  if(tr->tre.tretyp==TWH && tr->wh.whinc && t->lst.lstlef->tre.tretyp==TARITH)
                  {
                        /* arithmetic for statement */
                        struct argnod *init = (t->lst.lstlef)->ar.arexpr;
                        forinit= init->argval;
                        p_tree(t->lst.lstrit,tflags);
                        break;
                  }
                  if(needbrace)
                        p_keyword("{",BEGIN);
                  p_tree(t->lst.lstlef,0);
                  if(needbrace)
                        tflags = 0;
                  p_tree(t->lst.lstrit,tflags);
                  if(needbrace)
                        p_keyword("}",END);
                  break;
            }

            case TAND:
                  cp = "&&";
                  goto andor;
            case TORF:
                  cp = "||";
                  goto andor;
            case TFIL:
                  cp = "|";
            andor:
            {
                  int bracket = 0;
                  if(t->tre.tretyp&TTEST)
                  {
                        tflags |= NO_NEWLINE;
                        if(!(tflags&NO_BRACKET))
                        {
                              p_keyword("[[",BEGIN);
                              tflags |= NO_BRACKET;
                              bracket=1;
                        }
                  }
                  p_tree(t->lst.lstlef,NEED_BRACE|NO_NEWLINE|(tflags&NO_BRACKET));
                  sfputr(outfile,cp,here_doc?'\n':' ');
                  if(here_doc)
                  {
                        here_body(here_doc);
                        here_doc = 0;
                  }
                  level++;
                  p_tree(t->lst.lstrit,tflags|NEED_BRACE);
                  if(bracket)
                        p_keyword("]]",END);
                  level--;
                  break;
            }
      
            case TPAR:
                  p_keyword("(",BEGIN);
                  p_tree(t->par.partre,0); 
                  p_keyword(")",END);
                  break;

            case TARITH:
            {
                  register struct argnod *ap = t->ar.arexpr;
                  if(begin_line && level)
                        sfnputc(outfile,'\t',level);
                  sfprintf(outfile,"(( %s ))%c",ap->argval,end_line);
                  if(!(tflags&NO_NEWLINE))
                        begin_line=1;
                  break;
            }

            case TFOR:
                  cp = ((t->tre.tretyp&COMSCAN)?"select":"for");
                  p_keyword(cp,BEGIN);
                  sfputr(outfile,t->for_.fornam,' ');
                  if(t->for_.forlst)
                  {
                        sfputr(outfile,"in",' ');
                        tflags = end_line;
                        end_line = '\n';
                        p_comarg(t->for_.forlst);
                        end_line = tflags;
                  }
                  else
                        sfputc(outfile,'\n');
                  begin_line = 1;
                  t = t->for_.fortre;
            dolist:
                  p_keyword("do",MIDDLE);
                  p_tree(t,0);
                  p_keyword("done",END);
                  break;
      
            case TSW:
                  p_keyword("case",BEGIN);
                  p_arg(t->sw.swarg,' ',0);
                  if(t->sw.swlst)
                  {
                        begin_line = 1;
                        sfputr(outfile,"in",'\n');
                        tflags = end_line;
                        end_line = '\n';
                        p_switch(t->sw.swlst);
                        end_line = tflags;
                  }
                  p_keyword("esac",END);
                  break;

            case TFUN:
                  if(t->tre.tretyp&FPOSIX)
                  {
                        sfprintf(outfile,"%s",t->funct.functnam);
                        p_keyword("()\n",BEGIN);
                  }
                  else
                  {
                        p_keyword("function",BEGIN);
                        tflags = (t->funct.functargs?' ':'\n');
                        sfputr(outfile,t->funct.functnam,tflags);
                        if(t->funct.functargs)
                        {
                              tflags = end_line;
                              end_line = '\n';
                              p_comarg(t->funct.functargs);
                              end_line = tflags;
                        }
                  }
                  begin_line = 1;
                  p_keyword("{\n",MIDDLE);
                  begin_line = 1;
                  p_tree(t->funct.functtre,0); 
                  p_keyword("}",END);
                  break;
            /* new test compound command */
            case TTST:
                  if(!(tflags&NO_BRACKET))
                        p_keyword("[[",BEGIN);
                  if((t->tre.tretyp&TPAREN)==TPAREN)
                  {
                        p_keyword("(",BEGIN);
                        p_tree(t->lst.lstlef,NO_BRACKET|NO_NEWLINE); 
                        p_keyword(")",END);
                  }
                  else
                  {
                        int flags = (t->tre.tretyp)>>TSHIFT;
                        if(t->tre.tretyp&TNEGATE)
                              sfputr(outfile,"!",' ');
                        if(t->tre.tretyp&TUNARY)
                        {
                              un_op[1] = flags;
                              sfputr(outfile,un_op,' ');
                        }
                        else
                              cp = ((char*)(shtab_testops+(flags&037)-1)->sh_name);
                        p_arg(&(t->lst.lstlef->arg),' ',0);
                        if(t->tre.tretyp&TBINARY)
                        {
                              sfputr(outfile,cp,' ');
                              p_arg(&(t->lst.lstrit->arg),' ',0);
                        }
                  }
                  if(!(tflags&NO_BRACKET))
                        p_keyword("]]",END);
      }
      while(begin_line && here_doc)
      {
            here_body(here_doc);
            here_doc = 0;
      }
      end_line = save;
      return;
}

/*
 * print a keyword
 * increment indent level for flag==BEGIN
 * decrement indent level for flag==END
 */
static void p_keyword(const char *word,int flag)
{
      register int sep;
      if(flag==END)
            sep = end_line;
      else if(*word=='[' || *word=='(')
            sep = ' ';
      else
            sep = '\t';
      if(flag!=BEGIN)
            level--;
      if(begin_line && level)
            sfnputc(outfile,'\t',level);
      sfputr(outfile,word,sep);
      if(sep=='\n')
            begin_line=1;
      else
            begin_line=0;
      if(flag!=END)
            level++;
}

static void p_arg(register const struct argnod *arg,register int endchar,int opts)
{
      register const char *cp;
      register int flag;
      do
      {
            if(!arg->argnxt.ap)
                  flag = endchar;
            else if(opts&PRE)
            {
                  /* case alternation lists in reverse order */
                  p_arg(arg->argnxt.ap,'|',opts);
                  flag = endchar;
            }
            else if(opts)
                  flag = ' ';
            cp = arg->argval;
            if(*cp==0 && opts==POST && arg->argchn.ap)
            {
                  /* compound assignment */
                  struct fornod *fp=(struct fornod*)arg->argchn.ap;
                  sfprintf(outfile,"%s=(\n",fp->fornam);
                  sfnputc(outfile,'\t',++level);
                  p_tree(fp->fortre,0);
                  if(--level)
                        sfnputc(outfile,'\t',level);
                  sfputc(outfile,')');
            }
            else if((arg->argflag&ARG_RAW) && (cp[1] || (*cp!='[' && *cp!=']')))
                  cp = sh_fmtq(cp);
            sfputr(outfile,cp,flag);
            if(flag=='\n')
                  begin_line = 1;
            arg = arg->argnxt.ap;
      }
      while((opts&POST) && arg);
      return;
}

static void p_redirect(register const struct ionod *iop)
{
      register char *cp;
      register int iof,iof2;
      for(;iop;iop=iop->ionxt)
      {
            iof=iop->iofile;
            cp = io_op;
            if(iop->iovname)
            {
                  sfwrite(outfile,"(;",2);
                  sfputr(outfile,iop->iovname,')');
                  cp++;
            }
            else
                  *cp = '0'+(iof&IOUFD);
            if(iof&IOPUT)
            {
                  if(*cp == '1' && !iop->iovname)
                        cp++;
                  io_op[1] = '>';
            }
            else
            {
                  if(*cp == '0' && !iop->iovname)
                        cp++;
                  io_op[1] = '<';
            }
            io_op[2] = 0;
            io_op[3] = 0;
            if(iof&IOLSEEK)
            {
                  io_op[1] = '#';
                  if(iof&IOARITH)
                        strcpy(&io_op[3]," ((");
            }
            else if(iof&IOMOV)
                  io_op[2] = '&';
            else if(iof&(IORDW|IOAPP))
                  io_op[2] = '>';
            else if(iof&IOCLOB)
                  io_op[2] = '|';
            if(iop->iodelim)
            {
                  /* here document */
#ifdef xxx
                  iop->iolink = (char*)here_doc;
#endif
                  here_doc  = iop;
                  io_op[2] = '<';
#ifdef future
                  if(iof&IOSTRIP)
                        io_op[3] = '-';
#endif
            }
            sfputr(outfile,cp,' ');
            if(iop->ionxt)
                  iof = ' ';
            else
            {
                  if((iof=end_line)=='\n')
                        begin_line = 1;
            }
            if((iof&IOLSEEK) && (iof&IOARITH))
                  iof2 = iof, iof = ' ';
            if(iop->iodelim)
            {
                  if(!(iop->iofile&IODOC))
                        sfwrite(outfile,"''",2);
                  sfputr(outfile,sh_fmtq(iop->iodelim),iof);
            }
            else if(iop->iofile&IORAW)
                  sfputr(outfile,sh_fmtq(iop->ioname),iof);
            else
                  sfputr(outfile,iop->ioname,iof);
            if((iof&IOLSEEK) && (iof&IOARITH))
                  sfputr(outfile, "))", iof2);
      }
      return;
}

static void p_comarg(register const struct comnod *com)
{
      register int flag = end_line;
      if(com->comarg || com->comio)
            flag = ' ';
      if(com->comset)
            p_arg(com->comset,flag,POST);
      if(com->comarg)
      {
            if(!com->comio)
                  flag = end_line;
            if(com->comtyp&COMSCAN)
                  p_arg(com->comarg,flag,POST);
            else
                  p_comlist((struct dolnod*)com->comarg,flag);
      }
      if(com->comio)
            p_redirect(com->comio);
      return;
}

static void p_comlist(const struct dolnod *dol,int endchar)
{
      register char *cp, *const*argv;
      register int flag = ' ', special;
      argv = dol->dolval+ARG_SPARE;
      cp = *argv;
      special = (*cp=='[' && cp[1]==0);
      do
      {
            if(cp)
                  argv++;
            else
                  cp = "";
            if(*argv==0)
            {
                  if((flag=endchar)=='\n')
                        begin_line = 1;
                  special = (*cp==']' && cp[1]==0);
            }
            sfputr(outfile,special?cp:sh_fmtq(cp),flag);
            special = 0;
      }
      while(cp  = *argv);
      return;
}

static void p_switch(register const struct regnod *reg)
{
      if(level>1)
            sfnputc(outfile,'\t',level-1);
      p_arg(reg->regptr,')',PRE);
      begin_line = 0;
      sfputc(outfile,'\t');
      if(reg->regcom)
            p_tree(reg->regcom,0);
      level++;
      if(reg->regflag)
            p_keyword(";&",END);
      else
            p_keyword(";;",END);
      if(reg->regnxt)
            p_switch(reg->regnxt);
      return;
}

/*
 * output here documents
 */
static void here_body(register const struct ionod *iop)
{
      Sfio_t *infile;
#ifdef xxx
      if(iop->iolink)
            here_body((struct inode*)iop->iolink);
      iop->iolink = 0;
#endif
      if(iop->iofile&IOSTRG)
            infile = sfnew((Sfio_t*)0,iop->ioname,iop->iosize,-1,SF_STRING|SF_READ);
      else
            sfseek(infile=sh.heredocs,iop->iooffset,SEEK_SET);
      sfmove(infile,outfile,iop->iosize,-1);
      if(iop->iofile&IOSTRG)
            sfclose(infile);
      sfputr(outfile,iop->iodelim,'\n');
}


Generated by  Doxygen 1.6.0   Back to index