1
0
Files
irix-657m-src/eoe/cmd/ksh/sh/word.c
2022-09-29 17:59:04 +03:00

754 lines
14 KiB
C

/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
/* UNIX System Laboratories, Inc. */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)ksh:sh/word.c 1.5.4.1"
/*
* UNIX shell
*
* S. R. Bourne
* Rewritten by David Korn
* AT&T Bell Laboratories
*
*/
#include "defs.h"
#include "sym.h"
#include "builtins.h"
#ifdef NEWTEST
# include "test.h"
#endif /* NEWTEST */
static void setupalias();
static int here_copy();
static int here_tmp();
static int qtrim();
static void qnotrim();
/* This module defines the following routines */
void match_paren();
void match_paren_comsubst();
/* This module references these external routines */
extern char *sh_tilde();
/* ======== character handling for command lines ========*/
/*
* Get the next word and put it on the top of the stak
* Determine the type of word and set sh.wdnum and sh.wdset accordingly
* Returns the token type
*/
sh_lex()
{
register int c;
register int d;
register char *argp;
register int tildp;
int offset;
char chk_keywd;
int alpha = 0;
sh.wdnum=0;
sh.wdval = 0;
/* condition needed to check for keywords, name=value */
chk_keywd = (sh.reserv!=0 && !(sh.wdset&IN_CASE)) || (sh.wdset&KEYFLG);
sh.wdset &= ~KEYFLG;
sh.wdarg = (struct argnod*)stakseek(ARGVAL);
sh.wdarg->argnxt.ap = 0;
offset = staktell();
tildp = -1;
while(1)
{
while((c=io_nextc(), isblank(c)));
if(c==COMCHAR)
{
while((c=io_readc()) != NL && c != ENDOF);
io_unreadc(c);
}
else /* out of comment - white space loop */
break;
}
if(c=='~')
tildp = offset;
if(!ismeta(c))
{
do
{
if(c==LITERAL)
{
match_paren(c,c);
alpha = -1;
}
else
{
if(staktell()==offset && chk_keywd && isalpha(c))
alpha++;
stakputc(c);
if(c == ESCAPE)
stakputc(io_readc());
if(alpha>0)
{
if(c == '[')
match_paren('[',']');
else if(c=='=')
{
sh.wdset |= KEYFLG;
tildp = staktell();
alpha = 0;
}
else if(!isalnum(c))
alpha = 0;
}
if(qotchar(c))
match_paren(c,c);
}
d = c;
c = io_nextc();
if(d==DOLLAR && c==LBRACE)
{
stakputc(c);
match_paren(LBRACE, RBRACE);
c = io_nextc();
}
else if(c==LPAREN && patchar(d))
{
stakputc(c);
if(d==DOLLAR) {
if(nextchar(st.standin) == LPAREN)
match_paren(LPAREN, RPAREN);
else match_paren_comsubst(LPAREN, RPAREN,0);
}
else match_paren(LPAREN, RPAREN);
c = io_nextc();
}
else if(tildp>=0 && (c == '/' || c==':' || ismeta(c)))
{
/* check for tilde expansion */
stakputc(0);
argp=sh_tilde(stakptr(tildp));
if(argp)
{
stakset(stakptr(0),tildp);
stakputs(argp);
}
else
stakset(stakptr(0),staktell()-1);
tildp = -1;
}
/* tilde substitution after : in variable assignment */
/* left in as unadvertised compatibility feature */
if(c==':' && (sh.wdset&KEYFLG))
tildp = staktell()+1;
}
while(!ismeta(c));
sh.wdarg = (struct argnod*)stakfreeze(1);
argp = sh.wdarg->argval;
io_unreadc(c);
#ifdef NEWTEST
if(sh.wdset&IN_TEST)
{
if(sh.wdset&TEST_OP1)
{
if(argp[0]=='-' && argp[2]==0 &&
strchr(test_unops,argp[1]))
{
sh.wdnum = argp[1];
sh.wdval = TESTUNOP;
}
else if(argp[0]=='!' && argp[1]==0)
{
sh.wdval = '!';
}
else
sh.wdval = 0;
sh.wdset &= ~TEST_OP1;
return(sh.wdval);
}
c = sh_lookup(argp, test_optable);
switch(c)
{
case TEST_END:
return(sh.wdval=ETSTSYM);
default:
if(sh.wdset&TEST_OP2)
{
sh.wdset &= ~TEST_OP2;
sh.wdnum = c;
return(sh.wdval=TESTBINOP);
}
case TEST_OR: case TEST_AND:
case 0:
return(sh.wdval = 0);
}
}
#endif /*NEWTEST */
if(argp[1]==0 &&
(d=argp[0],isdigit(d)) &&
(c=='>' || c=='<'))
{
sh_lex();
sh.wdnum |= (d-'0');
}
else
{
/*check for reserved words and aliases */
sh.wdval = (sh.reserv!=0?sh_lookup(argp,tab_reserved):0);
/* for unity database software, allow select to be aliased */
if((sh.reserv!=0 && (sh.wdval==0||sh.wdval==SELSYM)) || (sh.wdset&CAN_ALIAS))
{
/* check for aliases */
struct namnod* np;
if((sh.wdset&(IN_CASE|KEYFLG))==0 &&
(np=nam_search(argp,sh.alias_tree,N_NOSCOPE))
&& !nam_istype(np,M_FLAG)
&& (argp=nam_strval(np)))
{
setupalias(argp,np);
st.peekn = 0;
nam_ontype(np,M_FLAG);
sh.wdset |= KEYFLG;
return(sh_lex());
}
}
}
}
else if(dipchar(c))
{
if(is_option(WORDEXP) && !st.exec_flag)
sh_exit(CTXBAD);
sh.wdval = c;
d = io_nextc();
if(d==c)
{
sh.wdval = c|SYMREP;
if(c=='<')
{
if((d=io_nextc())=='-')
sh.wdnum |= IOSTRIP;
else
io_unreadc(d);
}
/* arithmetic evaluation ((expr)) */
else if(c == LPAREN && sh.reserv != 0)
{
stakputc(DQUOTE);
match_paren(LPAREN, RPAREN);
*stakptr(staktell()-1) = DQUOTE;
c = io_nextc();
if(c != ')')
{
/*
* process as nested () command
* for backward compatibility
*/
stakputc(')');
stakputc(c);
sh.wdarg = (struct argnod*)stakfreeze(1);
if(xpg_compliant())
qtrim(argp = sh.wdarg->argval);
else
qnotrim(argp = sh.wdarg->argval);
setupalias(argp,(struct namnod*)0);
sh.wdval = st.peekn = '(';
}
else
{
sh.wdarg= (struct argnod*)stakfreeze(1);
return(EXPRSYM);
}
}
}
else if(c=='|')
{
if(d=='&')
sh.wdval = COOPSYM;
else
io_unreadc(d);
}
#ifdef DEVFD
else if(d==LPAREN && iochar(c))
sh.wdval = (c=='>'?OPROC:IPROC);
#endif /* DEVFD */
else if(c==';' && d=='&')
sh.wdval = ECASYM;
else
io_unreadc(d);
}
else
{
if((sh.wdval=c)==ENDOF)
{
sh.wdval=EOFSYM;
if(st.standin->ftype==F_ISALIAS)
io_pop(1);
}
if(st.iopend && eolchar(c))
{
if(sh.owdval || is_option(NOEXEC))
c = getlineno(1);
if(here_copy(st.iopend)<=0 && sh.owdval)
{
sh.owdval = ('<'|SYMREP);
sh.wdval = EOFSYM;
sh.olineno = c;
sh_syntax();
}
st.iopend=0;
}
}
sh.reserv=0;
return(sh.wdval);
}
static void setupalias(string,np)
char *string;
struct namnod *np;
{
register struct fileblk *f;
register int line;
f = new_of(struct fileblk,0);
line = st.standin->flin;
io_push(f);
io_sopen(string);
f->flin = line-1;
f->ftype = F_ISALIAS;
f->feval = (char**)np;
f->flast = st.peekn;
}
void match_paren_comsubst(open,close,inquote)
register int open;
{
register int c;
register int count = 1;
register int quoted = 0;
int was_dollar=0;
int empty = 1;
int line = st.standin->flin;
int comsuboff = staktell();
if(open==LITERAL)
stakputc(DQUOTE);
while(count)
{
/* check for unmatched <open> */
if(quoted || open==LITERAL)
c = io_readc();
else
c = io_nextc();
if(empty && !isspace(c) && c != close) empty = 0;
if(c==0)
{
/* eof before matching quote */
/* This keeps old shell scripts running */
if(filenum(st.standin)!=F_STRING || is_option(NOEXEC))
{
sh.olineno = line;
sh.owdval = open;
sh.wdval = EOFSYM;
sh_syntax();
}
io_unreadc(0);
c = close;
}
if(c == NL)
{
if(open=='[')
{
io_unreadc(c);
break;
}
sh_prompt(0);
}
else if(c == close)
{
if(!quoted)
count--;
if(count==0 && !empty)
{
/* Found a closing RPAREN - parse
* the contents like a subshell.
*/
struct fileblk cb;
Stak_t *savstak;
struct sh_static savsh;
struct sh_scoped savscoped;
int savtop;
char *argc, *savptr;
stakputc(c); /* Put RPAREN on */
savtop = staktell();
savptr = stakfreeze(1);
argc = savptr+comsuboff;
savstak = stakcreate(STAK_SMALL);
savstak = stakinstall(savstak, 0);
savsh = sh;
savscoped = st;
io_push(&cb);
io_sopen(argc);
/* Set flag which sh_syntax() will clear for bad parse */
st.states |= COMSUB;
sh_parse(')',MTFLG|NLFLG);
sh_freeup();
io_pop(0);
/* Flag cleared - read more input */
if(!(st.states&COMSUB))
++count;
sh = savsh;
st = savscoped;
/* Reset stak ptrs to before the RPAREN */
stakdelete(stakinstall(savstak, 0));
stakset(savptr,savtop-1);
}
}
else if(c == open && !quoted)
count++;
if(open==LITERAL && (escchar(c) || c=='"'))
stakputc(ESCAPE);
stakputc(c);
if(open==LITERAL)
continue;
if(!quoted)
{
switch(c)
{
case '<':
case '>':
if(open==LBRACE)
{
/* reserved for future use */
sh.wdval = c;
sh_syntax();
}
break;
case '"':
case '`':
/* If we are called by match_paren() in
* the middle of a double or back quoted
* string, pass this char through.
*/
if(c == inquote)
break;
case LITERAL:
/* check for nested '', "", and `` */
if(open==close)
break;
if(c==LITERAL)
stakset(stakptr(0),staktell()-1);
match_paren(c,c);
break;
case LPAREN:
if(was_dollar && open!=LPAREN)
match_paren_comsubst(LPAREN,RPAREN,0);
break;
}
was_dollar = (c==DOLLAR);
}
if(c==ESCAPE)
quoted = 1 - quoted;
else
quoted = 0;
}
if(open==LITERAL)
*stakptr(staktell()-1) = DQUOTE;
return;
}
/*
* read until matching <close>
*/
void match_paren(open,close)
register int open;
{
register int c;
register int count = 1;
register int quoted = 0;
int was_dollar=0;
int line = st.standin->flin;
if(open==LITERAL)
stakputc(DQUOTE);
while(count)
{
/* check for unmatched <open> */
if(quoted || open==LITERAL)
c = io_readc();
else
c = io_nextc();
if(c==0)
{
/* eof before matching quote */
/* This keeps old shell scripts running */
if(filenum(st.standin)!=F_STRING || is_option(NOEXEC))
{
sh.olineno = line;
sh.owdval = open;
sh.wdval = EOFSYM;
sh_syntax();
}
io_unreadc(0);
c = close;
}
if(c == NL)
{
if(open=='[')
{
io_unreadc(c);
break;
}
sh_prompt(0);
}
else if(c == close)
{
if(!quoted)
count--;
}
else if(c == open && !quoted)
count++;
if(open==LITERAL && (escchar(c) || c=='"'))
stakputc(ESCAPE);
stakputc(c);
if(open==LITERAL)
continue;
if(!quoted)
{
switch(c)
{
case '<':
case '>':
if(open==LBRACE)
{
/* reserved for future use */
sh.wdval = c;
sh_syntax();
}
break;
case LITERAL:
case '"':
case '`':
/* check for nested '', "", and `` */
if(open==close)
break;
if(c==LITERAL)
stakset(stakptr(0),staktell()-1);
match_paren(c,c);
break;
case LPAREN:
if(was_dollar && open!=LPAREN){
if(nextchar(st.standin) == LPAREN)
match_paren(LPAREN,RPAREN);
else match_paren_comsubst(LPAREN,RPAREN,open);
}
break;
}
was_dollar = (c==DOLLAR);
}
if(c==ESCAPE)
quoted = 1 - quoted;
else
quoted = 0;
}
if(open==LITERAL)
*stakptr(staktell()-1) = DQUOTE;
return;
}
/*
* read in here-document from script
* small non-quoted here-documents are stored as strings
* quoted here documents, and here-documents without special chars are
* treated like file redirection
*/
static int here_copy(ioparg)
struct ionod *ioparg;
{
register int c;
register char *bufp;
register struct ionod *iop;
register char *dp;
int fd = -1;
int match;
int savec = 0;
int special = 0;
int nosubst;
char obuff[IOBSIZE+1];
if(iop=ioparg)
{
int stripflg = iop->iofile&IOSTRIP;
register int nlflg;
here_copy(iop->iolst);
iop->iodelim=iop->ioname;
/* check for and strip quoted characters in ends */
nosubst = qtrim(iop->iodelim);
if(stripflg)
while(*iop->iodelim=='\t')
iop->iodelim++;
dp = iop->iodelim;
match = 0;
nlflg = stripflg;
bufp = obuff;
sh_prompt(0);
do
{
if(nosubst || savec==ESCAPE)
c = io_readc();
else
c = io_nextc();
if((savec = c)<=0)
break;
else if(c!=ESCAPE || savec==ESCAPE)
special |= escchar(c);
if(c=='\n')
{
if(match>0 && iop->iodelim[match]==0)
{
savec =1;
break;
}
if(match>0)
goto trymatch;
sh_prompt(0);
nlflg = stripflg;
match = 0;
goto copy;
}
else if(c=='\t' && nlflg)
continue;
nlflg = 0;
/* try matching delimiter when match>=0 */
if(match>=0)
{
trymatch:
if(iop->iodelim[match]==c)
{
match++;
continue;
}
else if(--match>=0)
{
io_unreadc(c);
dp = iop->iodelim;
c = *dp++;
}
}
copy:
do
{
*bufp++ = c;
if(bufp >= &obuff[IOBSIZE])
{
if(fd < 0)
fd = here_tmp(iop);
write(fd,bufp=obuff,(unsigned)IOBSIZE);
}
}
while(c!='\n' && --match>=0 && (c= *dp++));
}
while(savec>0);
if(c = (nosubst|!special))
iop->iofile &= ~IODOC;
if(fd < 0)
{
if(c)
fd = here_tmp(iop);
else
{
iop->iofile |= IOSTRG;
*bufp = 0;
iop->ioname = stakcopy(obuff);
return(savec);
}
}
if(bufp > obuff)
write(fd, obuff, (unsigned)(bufp-obuff));
close(fd);
}
return(savec);
}
/*
* create a temporary file for a here document
*/
static int here_tmp(iop)
register struct ionod *iop;
{
register int fd = io_mktmp((char*)0);
iop->ioname = stakcopy(io_tmpname);
iop->iolst=st.iotemp;
st.iotemp=iop;
return(fd);
}
/*
* trim quotes and the escapes
* returns non-zero if string is quoted 0 otherwise
*/
static int qtrim(string)
char *string;
{
register char *sp = string;
register char *dp = sp;
register int c;
register int quote = 0;
while(c= *sp++)
{
if(c == ESCAPE)
{
quote = 1;
c = *sp++;
}
else if(c == '"')
{
quote = 1;
continue;
}
*dp++ = c;
}
*dp = 0;
return(quote);
}
/*
* Like qtrim() only trim beginning and ending quotes
* for Bourne shell backward compatibility.
*/
static void qnotrim(string)
char *string;
{
register char *sp = string;
register char *dp = sp;
register int c;
register char *endquote = strrchr(string,'"');
while(c= *sp++)
{
if(c == '"')
{
if((sp-1) == string || (sp-1) == endquote)
continue;
}
*dp++ = c;
}
*dp = 0;
}