date and time created 88/07/21 17:33:07 by marc
authorMarc Teitelbaum <marc@ucbvax.Berkeley.EDU>
Fri, 22 Jul 1988 08:33:07 +0000 (00:33 -0800)
committerMarc Teitelbaum <marc@ucbvax.Berkeley.EDU>
Fri, 22 Jul 1988 08:33:07 +0000 (00:33 -0800)
SCCS-vsn: local/toolchest/ksh/sh/cmd.c 1.1

usr/src/local/toolchest/ksh/sh/cmd.c [new file with mode: 0644]

diff --git a/usr/src/local/toolchest/ksh/sh/cmd.c b/usr/src/local/toolchest/ksh/sh/cmd.c
new file mode 100644 (file)
index 0000000..7aa6388
--- /dev/null
@@ -0,0 +1,839 @@
+/*
+
+ *      Copyright (c) 1984, 1985, 1986 AT&T
+ *      All Rights Reserved
+
+ *      THIS IS UNPUBLISHED PROPRIETARY SOURCE 
+ *      CODE OF AT&T.
+ *      The copyright notice above does not 
+ *      evidence any actual or intended
+ *      publication of such source code.
+
+ */
+/* @(#)cmd.c   1.1 */
+/*
+ * UNIX shell
+ *
+ * S. R. Bourne
+ * Rewritten by David Korn
+ * AT&T Bell Laboratories
+ *
+ */
+
+#include       "defs.h"
+#include       "sym.h"
+#include       "flags.h"
+#include       "name.h"
+#include       "io.h"
+#include       "history.h"
+#include       "mode.h"
+#include       "stak.h"
+#include       "shtype.h"
+#include       "brkincr.h"
+#include       "builtins.h"
+
+
+/* These routines are defined by this module */
+void   synbad();
+TREPTR cmd();
+TREPTR makefork();
+
+/* These routines are referenced by this module */
+extern void    addblok();
+extern void    chkpr();
+extern void    exitsh();
+extern void    free();
+extern STKPTR  getstak();
+extern void    hist_cancel();
+extern void    hist_flush();
+extern long    hist_position();
+extern char    *malloc();
+extern char    *movstr();
+extern void    p_setout();
+extern void    p_str();
+extern void    p_prp();
+extern void    p_num();
+
+static TREPTR  makelist();
+static ARGPTR  qscan();
+static IOPTR   inout();
+static void    chkword();
+static void    chkflags();
+static void    chksym();
+static TREPTR  term();
+static TREPTR  list();
+static REGPTR  syncase();
+static TREPTR  item();
+static int     skipnl();
+static void    prsym();
+
+
+static int     heredoc;
+
+/*
+ * ========    command line decoding   ========
+ *
+ *  This is the parser for a shell command line
+ */
+
+
+
+
+/*
+ * Make a node which will cause the shell to fork
+ */
+
+TREPTR makefork(flgs, i)
+int    flgs;
+TREPTR         i;
+{
+       register FORKPTR        t;
+       t=(FORKPTR) getstak(FORKTYPE);
+       t->forktyp = flgs|TFORK;
+       t->forktre = i;
+       t->forkio = 0;
+       return((TREPTR)t);
+}
+
+/*
+ *  Make a node corresponding to a command list
+ */
+
+static TREPTR  makelist(type,i,r)
+int    type;
+TREPTR         i, r;
+{
+       register LSTPTR t;
+       if(i==0 || r==0)
+               synbad();
+       else
+       {
+               t = (LSTPTR) getstak(LSTTYPE);
+               t->lsttyp = type;
+               t->lstlef = i;
+               t->lstrit = r;
+       }
+       return((TREPTR)t);
+}
+
+/*
+ * cmd
+ *     empty
+ *     list
+ *     list & [ cmd ]
+ *     list [ ; cmd ]
+ */
+
+TREPTR cmd(sym,flg)
+register int   sym;
+int    flg;
+{
+       register int flag = FINT|FPRS|FAMP;
+       register TREPTR i, e;
+       IOPTR saviotemp = iotemp;
+       /* parser output goes on standard error */
+       p_setout(stderr);
+       i = list(flg);
+       if(wdval==NL)
+       {
+               if(flg&NLFLG)
+               {
+                       wdval=';';
+                       chkpr(0);
+               }
+       }
+       else if(i==0 && (flg&MTFLG)==0)
+               synbad();
+       switch(wdval)
+       {
+               case COOPSYM:           /* set up a cooperating process */
+                       flag |= FPIN|FPOU;
+               case '&':
+                       if(i)
+                       {
+                               if(saviotemp!=iotemp || heredoc)
+                                       flag |= FTMP;
+                               i = (TREPTR)makefork(flag, i);
+                       }
+                       else
+                                synbad();
+
+               case ';':
+                       if(e=cmd(sym,flg|MTFLG))
+                               i=(TREPTR)makelist(TLST, i, e);
+                       break;
+
+               case EOFSYM:
+                       if(sym==NL)
+                               break;
+
+               default:
+                       if(sym)
+                               chksym(sym);
+
+       }
+       /* restore output stream */
+       return(i);
+}
+
+/*
+ * list
+ *     term
+ *     list && term
+ *     list || term
+ */
+
+static TREPTR  list(flg)
+{
+       register TREPTR r;
+       register int    b;
+       r = term(flg);
+       while(r && ((b=(wdval==ANDFSYM)) || wdval==ORFSYM))
+       {
+               r = makelist((b ? TAND : TORF), r, term(NLFLG));
+       }
+       return(r);
+}
+
+/*
+ * term
+ *     item
+ *     item |^ term
+ */
+
+static TREPTR  term(flg)
+register int flg;
+{
+       register TREPTR t;
+       register PARPTR p = NULL;
+       heredoc = 0;
+       reserv++;
+       if(flg&NLFLG)
+               skipnl();
+       else
+                word();
+       /* check to see if pipeline is to be timed */
+       if(wdval==TIMSYM)
+       {
+               p=(PARPTR) getstak(PARTYPE);
+               p->partyp=TTIME;
+               reserv++;
+               word();
+       }
+       if((t=item(NLFLG|MTFLG)) && wdval=='|')
+       {
+               flg = heredoc|FPOU;
+               t=makelist(TFIL,makefork(flg,t),makefork(FPIN|FPCL,term(NLFLG)));
+       }
+       if(p)
+       {
+               p->partre= t;
+               return((TREPTR)p);
+       }
+       else
+               return(t);
+}
+
+/*
+ * case statement
+ */
+
+static REGPTR  syncase(esym)
+register int esym;
+{
+       wdset |= E_FLAG;        /* set to avoid aliasing expressions */
+       skipnl();
+       if(wdval==esym)
+       {
+               wdset &= ~E_FLAG;
+               return(0);
+       }
+       else
+       {
+               register REGPTR r=(REGPTR) getstak(REGTYPE);
+               r->regptr=0;
+               while(1)
+               {
+                       chkflags(wdarg,1);
+                       wdarg->argnxt=r->regptr;
+                       r->regptr=wdarg;
+                       if(wdval==')' || wdval=='|' || ( word()!=')' && wdval!='|' ))
+                               synbad();
+                       if(wdval=='|')
+                               word();
+                       else
+                               break;
+               }
+               wdset &= ~E_FLAG;
+               r->regcom=cmd(0,NLFLG|MTFLG);
+               if(wdval==ECSYM)
+                       r->regnxt=syncase(esym);
+               else
+               {
+                       chksym(esym);
+                       r->regnxt=0;
+               }
+               return(r);
+       }
+}
+
+/*
+ * item
+ *
+ *     ( cmd ) [ < in ] [ > out ]
+ *     word word* [ < in ] [ > out ]
+ *     if ... then ... else ... fi
+ *     for ... while ... do ... done
+ *     case ... in ... esac
+ *     begin ... end
+ */
+
+static TREPTR  item(flag)
+BOOL           flag;
+{
+       register TREPTR t;
+       register IOPTR  io;
+       if(flag)
+               io=inout((IOPTR)0,1);
+       else
+               io=0;
+       switch(wdval)
+       {
+               /* case statement */
+               case CASYM:
+               {
+                       t=(TREPTR) getstak(SWTYPE);
+                       chkword();
+                       ((SWPTR) t)->swarg=wdarg->argval;
+                       skipnl();
+                       chksym(INSYM|BRSYM);
+                       ((SWPTR) t)->swlst=syncase(wdval==INSYM?ESSYM:KTSYM);
+                       ((SWPTR) t)->swtyp=TSW;
+                       break;
+               }
+
+               /* if statement */
+               case IFSYM:
+               {
+                       register int w;
+                       t=(TREPTR) getstak(IFTYPE);
+                       ((IFPTR) t)->iftyp=TIF;
+                       ((IFPTR) t)->iftre=cmd(THSYM,NLFLG);
+                       ((IFPTR) t)->thtre=cmd(ELSYM|FISYM|EFSYM,NLFLG);
+                       ((IFPTR) t)->eltre=((w=wdval)==ELSYM?cmd(FISYM,NLFLG):
+                               (w==EFSYM?(wdval=IFSYM, item(0)):0));
+                       if(w==EFSYM)
+                               return(t);
+                       break;
+               }
+
+               /* for and select statement */
+               case FORSYM:
+               case SELSYM:
+               {
+                       t=(TREPTR) getstak(FORTYPE);
+                       ((FORPTR) t)->fortyp=(wdval==FORSYM?TFOR:TSELECT);
+                       ((FORPTR) t)->forlst=0;
+                       chkword();
+                       ((FORPTR) t)->fornam=(char*) wdarg->argval;
+                       if(skipnl()==INSYM)
+                       {
+                               chkword();
+                                ((FORPTR) t)->forlst=(COMPTR) item(0);
+                               if(wdval!=NL && wdval!=';')
+                                       synbad();
+                               if(wdval==NL)
+                                       chkpr(0);
+                               skipnl();
+                       }
+                       /* 'for i;do cmd' is valid syntax */
+                       else if(wdval==';')
+                       {
+                               reserv = 1;
+                               word();
+                       }
+                       chksym(DOSYM|BRSYM);
+                       ((FORPTR) t)->fortre=cmd(wdval==DOSYM?ODSYM:KTSYM,NLFLG);
+                       break;
+               }
+
+               /* This is the code for parsing function definitions */
+               case PROCSYM:
+               funct_5_2:
+               {
+                       TREPTR cmdptr;
+                       BLKPTR blokptr;
+                       int savstates = states;
+                       int saveline = firstline;
+                       register FILE *fd = NULL;
+                       IOPTR saviotemp = iotemp;
+                       t=(TREPTR) getstak(PROCTYPE);
+                       ((PROCPTR) t)->proctyp=TPROC;
+                       ((PROCPTR) t)->procloc = -1;
+                       firstline = standin->flin;
+                       if(wdval == PROCSYM)
+                               chkword();
+                       ((PROCPTR) t)->procnam=(char *) wdarg->argval;
+                       skipnl();
+                       chksym(BRSYM);
+                       /* force a new stak frame to compile the command */
+                       addblok(-1);
+                       if(is_option(INTFLG))
+                       {
+                               /* just in case history file not open yet */
+                               hist_open();
+                               if(fc_fix)
+                               {
+                                       fd = fc_fix->fixfd;
+                                       states |= FIXFLG;
+                                       ((PROCPTR)t)->procloc = 
+                                               hist_position(fc_fix->fixind) +
+                                               fd->_ptr - fd->_base;
+                               }
+                       }
+                       cmdptr = cmd(KTSYM,NLFLG);
+                       /* force another stak frame to save the command */
+                       addblok(-1);
+                       blokptr = stakbsy;
+                       stakbsy = stakbsy->word;
+                       /* save the entry point in block */
+                       blokptr->word = BLK(cmdptr);
+                       ((PROCPTR) t)->proctre = blokptr;
+                       if(iotemp != saviotemp)
+                       {
+                               iotemp = saviotemp;
+                               states |= RM_TMP;
+                       }
+                       if(fd && (savstates&FIXFLG)==0)
+                       {
+                               hist_flush();
+                               hist_cancel();
+                               states &= ~FIXFLG;
+                       }
+                       firstline = saveline;
+                       break;
+               }
+
+               /* while and until */
+               case WHSYM:
+               case UNSYM:
+               {
+                       t=(TREPTR) getstak(WHTYPE);
+                       ((WHPTR) t)->whtyp=(wdval==WHSYM ? TWH : TUN);
+                       ((WHPTR) t)->whtre = cmd(DOSYM,NLFLG);
+                       ((WHPTR) t)->dotre = cmd(ODSYM,NLFLG);
+                       break;
+               }
+
+               /* command group with { */
+               case BRSYM:
+                       t=cmd(KTSYM,NLFLG);
+                       break;
+
+               case '(':
+               {
+                       register PARPTR  p;
+                       p=(PARPTR) getstak(PARTYPE);
+                       p->partre=cmd(')',NLFLG);
+                       p->partyp=TPAR;
+                       t=makefork(0,(TREPTR)p);
+                       break;
+               }
+
+               default:
+                       if(io==0)
+                               return(0);
+
+               /* simple command */
+               case 0:
+               {
+                       register ARGPTR argp;
+                       register ARGPTR *argtail;
+                       register ARGPTR *argset=0;
+                       int     keywd=KEYFLG;
+                       int     argno = 0;
+                       int bltin = 0;
+                       t=(TREPTR) getstak(COMTYPE);
+                       ((COMPTR)t)->comio=io; /*initial io chain*/
+                       /* set command line number for error messages */
+                       ((COMPTR)t)->comline = (exec_flag?cmdline:
+                               standin->flin-firstline-1);
+                       argtail = &(((COMPTR)t)->comarg);
+                       while(wdval==0)
+                       {
+                               argp = wdarg;
+                               argp->argchn = 0;
+                               /* test for keyword argument */
+                               if(wdset&keywd)
+                               {
+                                       chkflags(argp,0);
+                                       argp->argnxt=(ARGPTR) argset;
+                                       argset=(ARGPTR *) argp;
+                                       /* alias substitutions allowed */
+                                       wdset |= (KEYFLG|S_FLAG);
+                               }
+                               else
+                               {
+                                       wdset = 0;      /* don't hunt for aliases*/
+                                       chkflags(argp,1);
+                                       if((argp->argflag&A_RAW) == 0)
+                                               argno = -1;
+                                       if(argno>=0 && argno++==0)
+                                       {
+                                               /* check for builtin command */
+                                               bltin=syslook(argp->argval,commands);
+                                       }
+                                       *argtail = argp;
+                                       argtail = &(argp->argnxt);
+                                       wdset = keywd=is_option(KEYFLG);
+                               }
+#ifdef DEVFD
+                       retry:
+                               word();
+                               if((wdval&STRIP)=='(')
+                               {
+                                       TREPTR t;
+                                       int flag = (wdval==OPROC);
+                                       t = cmd(')',NLFLG|(argno==1&&wdval=='('?MTFLG:0));
+                                       if(t == NULL)
+                                       {
+                                               wdarg = argp;
+                                               goto funct_5_2;
+                                       }
+                                       argp = (ARGPTR)locstak();
+                                       argno = -1;
+                                       *argtail = argp;
+                                       argtail = &(argp->argnxt);
+                                       endstak(movstr(nullstr,argp->argval));
+                                       argp->argchn = (ARGPTR)makefork(flag?FPIN|FAMP|FPCL:FPOU,t);
+                                       argp->argflag =  (A_EXP|flag);
+                                       goto retry;
+                               }
+#else
+                               word();
+                               if(argno==1 && argset==NULL && wdval== '(')
+                               {
+                                       /* SVR2 style function */
+                                       word();
+                                       if(wdval == ')')
+                                       {
+                                               wdarg = argp;
+                                               goto funct_5_2;
+                                       }
+                                       wdval = '(';
+                               }
+#endif /* DEVFD */
+                               if(flag)
+                               {
+                                       if(io)
+                                       {
+                                               while(io->ionxt)
+                                                       io = io->ionxt;
+                                               io->ionxt = inout((IOPTR)0,0);
+                                       }
+                                       else
+                                               ((COMPTR)t)->comio = io = inout((IOPTR)0,0);
+                               }
+                       }
+                       *argtail = 0;
+                       ((COMPTR)t)->comtyp = (TCOM|(bltin<<(COMBITS+1)));
+                       /* expand argument list if possible */
+                       if(argno>0)
+                               ((COMPTR)t)->comarg = qscan(t,argno);
+                       else if(((COMPTR)t)->comarg)
+                               ((COMPTR)t)->comtyp |= COMSCAN;
+                       ((COMPTR)t)->comset=(ARGPTR) argset;
+                       wdset &= ~S_FLAG;
+                       return(t);
+               }
+       }
+       reserv++;
+       word();
+       if(io=inout(io,0))
+       {
+               int type = t->tretyp&COMMSK;
+               t=makefork(0,t);
+               t->treio=io;
+               if(type != TFORK)
+                       t->tretyp = TSETIO;
+       }
+       return(t);
+}
+
+
+/*
+ * skip past newlines but issue prompt if interactive
+ */
+
+static int     skipnl()
+{
+       while((reserv++, word()==NL))
+               chkpr(0);
+       return(wdval);
+}
+
+/*
+ * check for and process and i/o redirections
+ * if flag is set then an alias can be in the next word
+ */
+
+static IOPTR   inout(lastio,flag)
+IOPTR          lastio;
+{
+       register int    iof;
+       register IOPTR  iop;
+       register int c;
+       iof=wdnum;
+       switch(wdval)
+       {
+               case DOCSYM:    /*      <<      */
+                       iof |= IODOC;
+                       heredoc = FTMP;
+                       break;
+
+               case APPSYM:    /*      >>      */
+               case '>':
+                       if(wdnum==0)
+                               iof |= 1;
+                       iof |= IOPUT;
+                       if(wdval==APPSYM)
+                       {
+                               iof |= IOAPP;
+                               break;
+                       }
+
+               case '<':
+                       if((c=nextc())=='&')
+                               iof |= IOMOV;
+                       else if(c=='>')
+                       /*      <> is open for read and write   */
+                       /*      unadvertised feature            */
+                               iof |= IORDW;
+                       else
+                                peekn=c|MARK;
+                       break;
+
+               default:
+                       return(lastio);
+       }
+       chkword();
+       iop=(IOPTR) getstak(IOTYPE);
+       iop->ioname=wdarg->argval;
+       iop->iofile=iof;
+       if(iof&IODOC)
+       {
+               iop->iolst=iopend;
+               iopend=iop;
+       }
+       word();
+       iop->ionxt=inout(lastio,0);
+       /* allow alias substitutions */
+       if(flag)
+               wdset |= S_FLAG;
+       return(iop);
+}
+
+/*
+ * get next token and make sure that it is not a keyword or meta-character
+ */
+
+static void    chkword()
+{
+       if(word())
+               synbad();
+}
+
+/*
+ * see if this token is syntactically correct
+ */
+
+static void    chksym(sym)
+register int sym;
+{
+       register int    x = sym&wdval;
+       if(((x&SYMFLG) ? x : sym) != wdval)
+               synbad();
+}
+
+/*
+ * print the name of a syntactic token
+ */
+
+static void    prsym(sym)
+register int sym;
+{
+       if(sym&SYMFLG)
+       {
+               register SYSPTR sp=reserved;
+               while(sp->sysval && sp->sysval!=sym)
+                       sp++;
+               fputs(sp->sysnam,output);
+       }
+       else if(sym==EOFSYM)
+               fputs(endoffile,output);
+       else
+       {
+               if(sym&SYMREP)
+                       putc(sym,output);
+               if(sym==NL)
+                       fputs("newline or ;",output);
+               else
+                       putc(sym,output);
+       }
+       putc('\'',output);
+}
+
+/*
+ * print a bad syntax message
+ */
+
+void   synbad()
+{
+       register char *cp = unexpected;
+       register int w = wdval;
+       p_setout(stderr);
+       p_prp(synmsg,0);
+       if((states&TTYFLG)==0)
+       {
+               fputs(atline,output);
+               p_num((int)standin->flin,SP);
+       }
+       p_str(colon,'`');
+       if(w)
+               prsym(w);
+       else
+               p_str(wdarg->argval,'\'');
+       if((w&EOFSYM) && w!=EOFSYM)
+               cp = unmatched;
+       p_str(cp,NL);
+       hist_flush();
+       exitsh(SYNBAD);
+}
+
+/*
+ * check argument for possible optimizations
+ * in many cases we can skip macro and file name expansion
+ * The fexp flag is set when file expansion is possible
+ */
+
+#define EXP_MACRO      2       /* macro expansion needed */
+#define EXP_TRIM       4       /* quoted characters in string */
+#define EXP_FILE       8       /* file expansion characters*/
+#define EXP_QUOTE      16      /* string contains " character */
+
+static void chkflags(argp,fexp)
+register ARGPTR argp;
+{
+       register int c;
+       argp->argflag = 0;
+       {
+               register int flag = 0;
+               char nquote = 0;
+               char *sp=argp->argval;
+               while(c= *sp++)
+               {
+                       if(c==ESCAPE)
+                       {
+                               flag |= EXP_TRIM;
+                               sp++;
+                       }
+                       else if(isexp(c))
+                       {
+                               if(c == '$' || c == '`')
+                               {
+                                       flag |= EXP_MACRO;
+                                       if(c=='`')
+                                               subflag++;
+                               }
+                               else if(nquote==0)
+                               {
+                                       /* special case of '[' */
+                                       if(*sp || c!='[')
+                                               flag |= EXP_FILE;
+                               }
+                       }
+                       else if(c == '"')
+                       {
+                               /* toggle the quote count */
+                               nquote = 1 - nquote;
+                               flag |= EXP_QUOTE;
+                       }
+               }
+               if(fexp==0)
+                       flag &= ~EXP_FILE;
+               /* return if no macro expansion, file expansion or trimming required */
+               if(flag==0)
+               {
+                       argp->argflag |= A_RAW;
+                       return;
+               }
+               /* return if macro or command substitution needed */
+               if(flag&EXP_MACRO)
+               {
+                       argp->argflag |= (A_MAC|A_EXP);
+                       return;
+               }
+               /* check to see if file expansion is required */
+               if(flag&EXP_FILE)
+               {
+                       argp->argflag|= A_EXP;
+                       /* return if no quotes otherwise don't optimize */
+                       if(flag&(EXP_QUOTE|EXP_TRIM))
+                       {
+                               argp->argflag= A_MAC;
+                               return;
+                       }
+                       return;
+               }
+               argp->argflag |= A_RAW;
+       }
+       /* just get rid of quoting stuff and consider argument as expanded */
+       {
+               register char *dp,*sp;
+               char nquote = 0;        /* set within quoted string */
+               dp = sp =  argp->argval;
+               while(c= *sp++)
+               {
+                       if(c != '"')
+                       {
+                               if(c==ESCAPE)
+                               {
+                                       /* strip escchar's in double quotes */
+                                       c = *sp++;
+                                       if(nquote && !escchar(c) && c!='"')
+                                               *dp++ = ESCAPE;
+                               }
+                               *dp++ = c;
+                       }
+                       else    /* toggle quote marker */
+                               nquote = 1-nquote;
+               }
+               *dp = 0;
+       }
+}
+
+/*
+ * convert argument chain to argument list when no special arguments
+ */
+
+static ARGPTR qscan(ac,argn)
+COMPTR ac;
+int argn;
+{
+       register char **cp;
+       register ARGPTR ap;
+       register DOLPTR dp;
+       /* leave space for an extra argument at the front */
+       dp = (DOLPTR)getstak((unsigned)DOLTYPE + sizeof(char*) + argn*sizeof(char*));
+       cp = dp->dolarg+1;
+       dp->doluse = argn;
+       ap = ac->comarg;
+       while(ap)
+       {
+               *cp++ = ap->argval;
+               ap = ap->argnxt;
+       }
+       *cp = NULL;
+       return((ARGPTR)dp);
+}
+