/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* UNIX shell
*
* S. R. Bourne
* Rewritten by David Korn
* AT&T Labs
*
* This is the parser for a shell language
*/
#if KSHELL
#include "defs.h"
#else
#include <shell.h>
#include <ctype.h>
#endif
#include <fcin.h>
#include <error.h>
#include "shlex.h"
#include "history.h"
#include "builtins.h"
#include "test.h"
#include "history.h"
#if CDT_VERSION < 20111111L
#else
#endif
/* These routines are local to this module */
#ifndef NIL
#endif /* NIL */
#if !KSHELL
static struct stdata
{
int cmdline;
} st;
#endif
static int opt_get;
static int loop_level;
#if SHOPT_KIA
#include "path.h"
/*
* write out entities for each item in the list
* type=='V' for variable assignment lists
* Otherwise type is determined by the command */
static unsigned long writedefs(Lex_t *lexp,struct argnod *arglist, int line, int type, struct argnod *cmd)
{
register char *cp;
register int n,eline;
int width=0;
unsigned long r=0;
int justify=0;
if(type==0)
{
type = 'v';
{
case 'a':
type='p';
justify = 'a';
break;
case 'e':
*attribute++ = 'x';
break;
case 'r':
*attribute++ = 'r';
break;
case 'l':
break;
}
{
break;
if(cp[1]==n)
break;
while((n= *++cp))
{
if(isdigit(n))
else if(n=='L' || n=='R' || n =='Z')
justify=n;
else
*attribute++ = n;
}
}
}
else if(cmd)
*attribute = 0;
while(argp)
{
else
}
return(r);
}
#endif /* SHOPT_KIA */
{
register int c,n=0;
static unsigned char *table;
return;
if(!table)
{
table[c] = 1;
table[c] = 2;
for(c='0'; c <='9'; c++)
table[c] = 3;
}
{
if(table[c] < n)
}
}
/*
* add type definitions when compiling with -n
*/
{
char *cp=0;
{
{
break;
if(sh_isoption(SH_NOEXEC))
{
if(cp)
break;
}
}
}
else
{
{
if(sh_isoption(SH_NOEXEC))
{
if(cp[2])
else
break;
}
}
}
if(cp)
{
}
}
/*
* Make a parent node for fork() or io-redirection
*/
{
return(par);
}
{
while(c= *str++)
{
if(c=='$' && !lit)
{
if(*str=='(')
return(0);
if(sub)
continue;
if(*str=='{')
str++;
return(1);
}
else if(c=='`')
return(0);
else if(c=='[' && !lit)
sub++;
else if(c==']' && !lit)
sub--;
else if(c=='\'')
}
return(0);
}
{
else
{
}
return(t);
}
/*
* Make a node corresponding to a command list
*/
{
register Shnode_t *t;
if(!l || !r)
else
{
else
}
return(t);
}
/*
* entry to shell parser
* Flag can be the union of SH_EOF|SH_NL
*/
{
register Shnode_t *t;
loop_level = 0;
label_list = label_last = 0;
if(sh_isoption(SH_VERBOSE))
return(NIL(void*));
if(fcfile())
{
{
int version;
fcseek(4);
fcclose();
if(version > 3)
{
while(1)
{
break;
}
}
return((void*)t);
}
}
flag &= ~SH_FUNEVAL;
#if KSHELL
#endif
fcclose();
/* unstack any completed alias expansions */
{
if(sp)
}
{
}
return((void*)t);
}
/*
* This routine parses up the matching right parenthesis and returns
* the parse tree
*/
{
register Shnode_t *t=0;
{
/* ((...)) arithmetic expression */
case EXPRSYM:
break;
case LPAREN:
break;
case LBRACE:
break;
}
{
/*
* This code handles the case where string has been converted
* to a file by an alias setup
*/
register int c;
char *cp;
if(fcgetc(c) > 0)
fcseek(-1);
fcclose();
}
return(t);
}
/*
* remove temporary files and stacks
*/
{
}
/*
* increase reference count for each stack in function list when flag>0
* decrease reference count for each stack in function list when flag<=0
* stack is freed when reference count is zero
*/
{
{
if(flag<=0)
else
}
}
/*
* cmd
* empty
* list
* list & [ cmd ]
* list [ ; cmd ]
*/
{
{
}
{
case COOPSYM: /* set up a cooperating process */
/* FALL THRU */
case '&':
if(left)
{
/* (...)& -> {...;} & */
}
/* FALL THRU */
case ';':
if(!left)
break;
case EOFSYM:
break;
default:
{
}
}
return(left);
}
/*
* list
* term
* list && term
* list || term
* unfortunately, these are equal precedence
*/
{
register int token;
return(t);
}
/*
* term
* item
* item | term
*/
{
register Shnode_t *t;
register int token;
else
/* check to see if pipeline is to be timed */
{
}
#if SHOPT_COSHELL
else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && (lexp->token=='|' || lexp->token==PIPESYM2))
#else
#endif /* SHOPT_COSHELL */
{
#if SHOPT_COSHELL
#endif /* SHOPT_COSHELL */
{
{
case TFORK:
break;
case TFIL:
break;
default:
}
}
}
return(t);
}
/*
* case statement
*/
{
register struct regnod *r;
r->regptr=0;
r->regflag=0;
while(1)
{
break;
else if(tok=='|')
else
}
else if(tok==FALLTHRUSYM)
{
r->regflag++;
}
else
{
r->regnxt=0;
}
return(r);
}
/*
* This routine creates the parse tree for the arithmetic for
* When called, shlex.arg contains the string inside ((...))
* When the first argument is missing, a while node is returned
* Otherise a list containing an arithmetic command and a while
* is returned.
*/
{
register int offset;
register int n;
/* save current input */
/* split ((...)) into three expressions */
for(n=0; ; n++)
{
register int c;
if(n==2)
break;
/* copy up to ; onto the stack */
break;
/* remove trailing white space */
offset--;
/* check for empty initialization expression */
continue;
/* check for empty condition and treat as while((1)) */
if(n==0)
else
}
fcseek(1);
if(n<2)
{
}
/* check whether the increment is present */
{
}
else
else if(n==';')
return(tf);
}
{
register Shnode_t *t;
register int flag;
#if SHOPT_KIA
#endif /* SHOPT_KIA */
opt_get = 0;
{
fcclose();
}
{
if(fcfill() >= 0)
fcseek(-1);
else
{
/* copy source to temporary file */
else
}
}
#if SHOPT_KIA
#endif /* SHOPT_KIA */
if(flag)
{
#if SHOPT_BASH
{
else
}
#endif
}
else
{
{
int c;
{
}
if(c)
{
}
}
}
if(jmpval == 0)
{
/* create a new stak frame to compile the command */
/*
* store the pathname of function definition file on stack
* in name field of fake for node
*/
loop_level = 0;
if(size)
{
{
}
*argv = 0;
}
{
/* copy current word token to current stak frame */
}
}
exit(1);
/* restore the old stack */
if(slp)
{
}
#if SHOPT_KIA
#endif /* SHOPT_KIA */
if(jmpval)
{
{
}
}
{
if(fcfill()>0)
fcseek(-1);
}
#if SHOPT_KIA
#endif /* SHOPT_KIA */
return(t);
}
/*
* Compound assignment
*/
{
register int n;
{
array = ARG_APPEND;
}
/* shift right */
while(n > 0)
{
n--;
}
{
}
else
{
while(n==LPAREN)
{
{
}
if(!aq)
if(aq)
continue;
{
}
}
}
else if(n && n!=FUNCTSYM)
else if(type!=NV_ARRAY && n!=FUNCTSYM && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)|| np==SYSDOT)))
{
{
int c;
{
array = 0;
}
else
fcseek(-2);
}
else if(n>0)
fcseek(-1);
{
if(path_search(lexp->sh,lexp->arg->argval,NIL(Pathcomp_t**),1) && (np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && nv_isattr(np,BLT_DCL))
{
array = 0;
}
else
}
}
while(1)
{
break;
else
break;
if(n!=NL && n!=';')
{
goto comarray;
}
{
if(n==RPAREN)
break;
}
if((n!=FUNCTSYM) && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)||np==SYSDOT)))
{
if(n!=0)
/* check for sys5 style function */
{
}
}
*tp = t;
}
return(ap);
}
/*
* item
*
* ( cmd ) [ < in ] [ > out ]
* word word* [ < in ] [ > out ]
* if ... then ... else ... fi
* for ... while ... do ... done
* case ... in ... esac
* begin ... end
*/
{
register Shnode_t *t;
else
io=0;
{
}
switch(tok)
{
/* [[ ... ]] test expression */
case BTESTSYM:
break;
/* ((...)) arithmetic expression */
case EXPRSYM:
goto done;
/* case statement */
case CASESYM:
{
{
}
break;
}
/* if statement */
case IFSYM:
{
{
goto done;
t = tt;
goto done;
}
break;
}
/* for and select statement */
case FORSYM:
case SELECTSYM:
{
{
/* arithmetic for */
break;
}
#if SHOPT_KIA
#endif /* SHOPT_KIA */
{
{
/* some Linux scripts assume this */
if(sh_isoption(SH_NOEXEC))
}
else
}
/* 'for i;do cmd' is valid syntax */
else if(tok==';')
loop_level++;
if(--loop_level==0)
break;
}
/* This is the code for parsing function definitions */
case FUNCTSYM:
#if SHOPT_NAMESPACE
case NSPACESYM:
break;
#endif /* SHOPT_NAMESPACE */
/* while and until */
case WHILESYM:
case UNTILSYM:
loop_level++;
if(--loop_level==0)
break;
case LABLSYM:
{
while(argp)
{
}
return(t);
}
/* command group with {...} */
case LBRACE:
break;
case LPAREN:
break;
#if SHOPT_COSHELL
case '&':
{
}
else
return(t);
break;
#endif /* SHOPT_COSHELL */
default:
if(io==0)
return(0);
case ';':
if(io==0)
{
return(0);
}
/* simple command */
case 0:
check_typedef(&t->com);
return(t);
}
{
}
done:
return(t);
}
{
Shnode_t *t;
return(argp);
}
/*
* This is for a simple command, for list, or compound assignment
*/
{
register struct comnod *t;
register int tok;
int cmdarg=0;
int argno = 0;
int assignment = 0;
int associative=0;
{
associative = 1;
}
/* set command line number for error messages */
t->comset = 0;
t->comnamp = 0;
t->comnamq = 0;
t->comstate = 0;
{
{
break;
}
/* check for assignment argument */
{
if(assignment)
{
if(assignment==1)
{
if(last && (last[-1]==']'|| (last[-1]=='+' && last[-2]==']')) && (cp=strchr(argp->argval,'[')) && (cp < last) && cp[-1]!='.')
}
if(argno>=0)
argno++;
}
else /* alias substitutions allowed */
}
else
{
argno = -1;
{
/* check for builtin command */
if(cmdarg==0)
{
{
if(np==SYSTYPESET)
key_on = 1;
}
else if(np==SYSCOMMAND)
cmdarg++;
}
}
}
{
argno = -1;
goto retry;
}
{
{
int type = 0;
if(t->comnamp==SYSTYPESET)
{
{
break;
else
continue;
break;
}
}
if(associative)
goto retry;
}
{
/* SVR2 style function */
{
}
}
}
{
break;
{
goto retry;
}
}
{
if(io)
{
}
else
}
}
*argtail = 0;
#if SHOPT_KIA
{
unsigned long r=0;
if(np)
else if(argp)
if(r>0)
#if 0
#endif
{
}
}
#endif /* SHOPT_KIA */
{
{
tok = 0;
{
continue;
if(tok>=1)
{
if(tok>9)
{
tok /= 10;
}
else
}
break;
}
}
}
/* expand argument list if possible */
else if(t->comarg)
return((Shnode_t*)t);
}
/*
* skip past newlines but issue prompt if interactive
*/
{
register int token;
return(token);
}
/*
* check for and process and i/o redirections
* if flag>0 then an alias can be in the next word
* if flag<0 only one redirection will be processed
*/
{
char *iovname=0;
register int errout=0;
{
iof = 0;
}
switch(token&0xff)
{
case '<':
else if(token==IORDWRSYMT)
{
int n;
if(fcgetc(n)=='#')
else if(n>0)
fcseek(-1);
}
break;
case '>':
if(iof<0)
{
errout = 1;
iof = 1;
}
break;
default:
return(lastio);
}
{
{
fcseek(-1);
}
else if(((token==IPROCSYM && !(iof&IOPUT)) || (token==OPROCSYM && (iof&IOPUT))) && !(iof&(IOLSEEK|IOREWRITE|IOMOV|IODOC)))
{
}
else
}
else
{
{
}
else
{
}
}
else
{
}
if(flag>0)
/* allow alias substitutions and parameter assignments */
#if SHOPT_KIA
{
{
unsigned long r=kiaentity(lexp,(iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,lexp->script,'f',0,"");
sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;%c;%d\n",lexp->current,r,n,n,(iof&IOPUT)?((iof&IOAPP)?'a':'w'):((iof&IODOC)?'h':'r'),iof&IOUFD);
}
}
#endif /* SHOPT_KIA */
if(flag>=0)
{
if(errout)
{
/* redirect standard output to standard error */
}
}
else
return(iop);
}
/*
* convert argument chain to argument list when no special arguments
*/
{
register char **cp;
register int special=0;
/* special hack for test -t compatibility */
special = 2;
special = 3;
if(special)
{
special=0;
}
if(special)
{
const char *message;
{
message = "line %d: Invariant test";
special=0;
}
else
{
message = "line %d: -t requires argument";
argn++;
}
if(sh_isoption(SH_NOEXEC))
}
/* leave space for an extra argument at the front */
dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
while(ap)
{
}
if(special==3)
{
cp++;
}
else if(special)
*cp++ = "1";
*cp = 0;
}
{
return(t);
}
{
return(t);
}
{
return(t);
}
/*
* convert =~ into == ~(E)
*/
static void ere_match(void)
{
register int c;
if(c)
fcseek(-1);
fcclose();
}
{
register Shnode_t *t;
switch(token)
{
case '(':
break;
case '!':
if(!(t = test_primary(lexp)))
return(t);
case TESTUNOP:
#if SHOPT_KIA
{
unsigned long r;
}
#endif /* SHOPT_KIA */
break;
/* binary test operators */
case 0:
{
{
ere_match();
}
}
else if(token=='<')
else if(token=='>')
{
return(t);
}
else
#if SHOPT_KIA
{
unsigned long r;
}
#endif /* SHOPT_KIA */
if(num&TEST_PATTERN)
{
num &= ~TEST_PATTERN;
}
#if SHOPT_KIA
{
unsigned long r;
}
#endif /* SHOPT_KIA */
break;
default:
return(0);
}
return(t);
}
#if SHOPT_KIA
/*
* return an entity checksum
* The entity is created if it doesn't exist
*/
unsigned long kiaentity(Lex_t *lexp,const char *name,int len,int type,int first,int last,unsigned long parent, int pkind, int width, const char *attr)
{
if(len>0)
else
{
if(type=='p')
else
}
{
if(!pkind)
pkind = '0';
if(len>0)
sfprintf(lexp->kiafile,"%..64d;%c;%.*s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,len,name,first,last,parent,lexp->fscript,pkind,width,attr);
else
sfprintf(lexp->kiafile,"%..64d;%c;%s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,name,first,last,parent,lexp->fscript,pkind,width,attr);
}
}
{
}
{
register int n;
{
#ifdef SF_BUFCONST
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin));
else
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nRELATIONSHIP;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin),(Sflong_t)off1,(size_t)(off2-off1));
off2 = -(n+12);
#else
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin);
else
n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin,off1,off2-off1);
#endif
}
}
#endif /* SHOPT_KIA */