14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin * KornShell lexical analyzer
234887Schin *
244887Schin * Written by David Korn
254887Schin * AT&T Labs
264887Schin *
274887Schin */
284887Schin
294887Schin #include <ast.h>
304887Schin #include <stak.h>
314887Schin #include <fcin.h>
324887Schin #include <nval.h>
334887Schin #include "FEATURE/options"
344887Schin
354887Schin #if KSHELL
364887Schin # include "defs.h"
374887Schin #else
384887Schin # include <shell.h>
394887Schin # define nv_getval(np) ((np)->nvalue)
404887Schin Shell_t sh = {1};
414887Schin #endif /* KSHELL */
424887Schin
434887Schin #include "argnod.h"
444887Schin #include "test.h"
454887Schin #include "lexstates.h"
464887Schin #include "io.h"
474887Schin
484887Schin #define TEST_RE 3
494887Schin #define SYNBAD 3 /* exit value for syntax errors */
504887Schin #define STACK_ARRAY 3 /* size of depth match stack growth */
514887Schin
524887Schin #if _lib_iswblank < 0 /* set in lexstates.h to enable this code */
534887Schin
544887Schin int
local_iswblank(wchar_t wc)554887Schin local_iswblank(wchar_t wc)
564887Schin {
574887Schin static int initialized;
584887Schin static wctype_t wt;
594887Schin
604887Schin if (!initialized)
614887Schin {
624887Schin initialized = 1;
634887Schin wt = wctype("blank");
644887Schin }
654887Schin return(iswctype(wc, wt));
664887Schin }
674887Schin
684887Schin #endif
694887Schin
704887Schin /*
714887Schin * This structure allows for arbitrary depth nesting of (...), {...}, [...]
724887Schin */
734887Schin struct lexstate
744887Schin {
754887Schin char incase; /* 1 for case pattern, 2 after case */
764887Schin char intest; /* 1 inside [[...]] */
774887Schin char testop1; /* 1 when unary test op legal */
784887Schin char testop2; /* 1 when binary test op legal */
794887Schin char reservok; /* >0 for reserved word legal */
804887Schin char skipword; /* next word can't be reserved */
814887Schin char last_quote; /* last multi-line quote character */
824887Schin };
834887Schin
844887Schin struct lexdata
854887Schin {
864887Schin char nocopy;
874887Schin char paren;
884887Schin char dolparen;
894887Schin char nest;
904887Schin char docword;
914887Schin char *docend;
924887Schin char noarg;
934887Schin char balance;
944887Schin char warn;
954887Schin char message;
964887Schin char arith;
974887Schin char *first;
984887Schin int level;
994887Schin int lastc;
1004887Schin int lex_max;
1014887Schin int *lex_match;
1024887Schin int lex_state;
10310898Sroland.mainz@nrubsig.org int docextra;
1044887Schin #if SHOPT_KIA
1054887Schin off_t kiaoff;
1064887Schin #endif
1074887Schin };
1084887Schin
1094887Schin #define _SHLEX_PRIVATE \
1108462SApril.Chin@Sun.COM struct lexdata lexd; \
1118462SApril.Chin@Sun.COM struct lexstate lex;
1124887Schin
1134887Schin #include "shlex.h"
1144887Schin
1154887Schin
1168462SApril.Chin@Sun.COM #define pushlevel(lp,c,s) ((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\
1178462SApril.Chin@Sun.COM ((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\
1188462SApril.Chin@Sun.COM lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
1198462SApril.Chin@Sun.COM #define oldmode(lp) (lp->lexd.lastc>>CHAR_BIT)
1208462SApril.Chin@Sun.COM #define endchar(lp) (lp->lexd.lastc&0xff)
1218462SApril.Chin@Sun.COM #define setchar(lp,c) (lp->lexd.lastc = ((lp->lexd.lastc&~0xff)|(c)))
1228462SApril.Chin@Sun.COM #define poplevel(lp) (lp->lexd.lastc=lp->lexd.lex_match[--lp->lexd.level])
1234887Schin
1244887Schin static char *fmttoken(Lex_t*, int, char*);
1254887Schin #ifdef SF_BUFCONST
1264887Schin static int alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
1274887Schin #else
1284887Schin static int alias_exceptf(Sfio_t*, int, Sfdisc_t*);
1294887Schin #endif
1304887Schin static void setupalias(Lex_t*,const char*, Namval_t*);
1318462SApril.Chin@Sun.COM static int comsub(Lex_t*,int);
1324887Schin static void nested_here(Lex_t*);
1334887Schin static int here_copy(Lex_t*, struct ionod*);
1344887Schin static int stack_grow(Lex_t*);
1354887Schin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL };
1364887Schin
1374887Schin #if SHOPT_KIA
1384887Schin
refvar(Lex_t * lp,int type)1398462SApril.Chin@Sun.COM static void refvar(Lex_t *lp, int type)
1404887Schin {
1418462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh;
1428462SApril.Chin@Sun.COM register Stk_t *stkp = shp->stk;
1438462SApril.Chin@Sun.COM off_t off = (fcseek(0)-(type+1))-(lp->lexd.first?lp->lexd.first:fcfirst());
1444887Schin unsigned long r;
1458462SApril.Chin@Sun.COM if(lp->lexd.first)
1464887Schin {
1478462SApril.Chin@Sun.COM off = (fcseek(0)-(type+1)) - lp->lexd.first;
1488462SApril.Chin@Sun.COM r=kiaentity(lp,lp->lexd.first+lp->lexd.kiaoff+type,off-lp->lexd.kiaoff,'v',-1,-1,lp->current,'v',0,"");
1494887Schin }
1504887Schin else
1514887Schin {
1528462SApril.Chin@Sun.COM int n,offset = stktell(stkp);
1534887Schin char *savptr,*begin;
1544887Schin off = offset + (fcseek(0)-(type+1)) - fcfirst();
1558462SApril.Chin@Sun.COM if(lp->lexd.kiaoff < offset)
1564887Schin {
1574887Schin /* variable starts on stak, copy remainder */
1584887Schin if(off>offset)
1598462SApril.Chin@Sun.COM sfwrite(stkp,fcfirst()+type,off-offset);
1608462SApril.Chin@Sun.COM n = stktell(stkp)-lp->lexd.kiaoff;
1618462SApril.Chin@Sun.COM begin = stkptr(stkp,lp->lexd.kiaoff);
1624887Schin }
1634887Schin else
1644887Schin {
1654887Schin /* variable in data buffer */
1668462SApril.Chin@Sun.COM begin = fcfirst()+(type+lp->lexd.kiaoff-offset);
1678462SApril.Chin@Sun.COM n = off-lp->lexd.kiaoff;
1684887Schin }
1698462SApril.Chin@Sun.COM savptr = stkfreeze(stkp,0);
1708462SApril.Chin@Sun.COM r=kiaentity(lp,begin,n,'v',-1,-1,lp->current,'v',0,"");
1718462SApril.Chin@Sun.COM stkset(stkp,savptr,offset);
1724887Schin }
1738462SApril.Chin@Sun.COM sfprintf(lp->kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",lp->current,r,shp->inlineno,shp->inlineno);
1744887Schin }
1754887Schin #endif /* SHOPT_KIA */
1764887Schin
1774887Schin /*
1784887Schin * This routine gets called when reading across a buffer boundary
1794887Schin * If lexd.nocopy is off, then current token is saved on the stack
1804887Schin */
lex_advance(Sfio_t * iop,const char * buff,register int size,void * context)1818462SApril.Chin@Sun.COM static void lex_advance(Sfio_t *iop, const char *buff, register int size, void *context)
1824887Schin {
1838462SApril.Chin@Sun.COM register Lex_t *lp = (Lex_t*)context;
1848462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh;
1858462SApril.Chin@Sun.COM register Sfio_t *log= shp->funlog;
1868462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk;
1874887Schin #if KSHELL
1884887Schin /* write to history file and to stderr if necessary */
1894887Schin if(iop && !sfstacked(iop))
1904887Schin {
1914887Schin if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
1924887Schin log = shp->hist_ptr->histfp;
1934887Schin sfwrite(log, (void*)buff, size);
1944887Schin if(sh_isstate(SH_VERBOSE))
1954887Schin sfwrite(sfstderr, buff, size);
1964887Schin }
1974887Schin #endif
1988462SApril.Chin@Sun.COM if(lp->lexd.nocopy)
1994887Schin return;
20010898Sroland.mainz@nrubsig.org if(lp->lexd.dolparen && lp->lexd.docword)
20110898Sroland.mainz@nrubsig.org {
20210898Sroland.mainz@nrubsig.org int n = size - (lp->lexd.docend-(char*)buff);
20310898Sroland.mainz@nrubsig.org sfwrite(shp->strbuf,lp->lexd.docend,n);
20410898Sroland.mainz@nrubsig.org lp->lexd.docextra += n;
20510898Sroland.mainz@nrubsig.org }
2068462SApril.Chin@Sun.COM if(lp->lexd.first)
2074887Schin {
2088462SApril.Chin@Sun.COM size -= (lp->lexd.first-(char*)buff);
2098462SApril.Chin@Sun.COM buff = lp->lexd.first;
2108462SApril.Chin@Sun.COM if(!lp->lexd.noarg)
2118462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
2124887Schin #if SHOPT_KIA
2138462SApril.Chin@Sun.COM lp->lexd.kiaoff += ARGVAL;
2144887Schin #endif /* SHOPT_KIA */
2154887Schin }
2168462SApril.Chin@Sun.COM if(size>0 && (lp->arg||lp->lexd.noarg))
2174887Schin {
2188462SApril.Chin@Sun.COM sfwrite(stkp,buff,size);
2198462SApril.Chin@Sun.COM lp->lexd.first = 0;
2204887Schin }
2214887Schin }
2224887Schin
2234887Schin /*
2244887Schin * fill up another input buffer
2254887Schin * preserves lexical state
2264887Schin */
lexfill(Lex_t * lp)2278462SApril.Chin@Sun.COM static int lexfill(Lex_t *lp)
2284887Schin {
2294887Schin register int c;
2308462SApril.Chin@Sun.COM Lex_t savelex;
2314887Schin struct argnod *ap;
23210898Sroland.mainz@nrubsig.org int aok,docextra;
2338462SApril.Chin@Sun.COM savelex = *lp;
2348462SApril.Chin@Sun.COM ap = lp->arg;
2354887Schin c = fcfill();
2364887Schin if(ap)
2378462SApril.Chin@Sun.COM lp->arg = ap;
23810898Sroland.mainz@nrubsig.org docextra = lp->lexd.docextra;
2398462SApril.Chin@Sun.COM lp->lex = savelex.lex;
2408462SApril.Chin@Sun.COM lp->lexd = savelex.lexd;
2418462SApril.Chin@Sun.COM if(fcfile() || c)
2428462SApril.Chin@Sun.COM lp->lexd.first = 0;
2438462SApril.Chin@Sun.COM aok= lp->aliasok;
2448462SApril.Chin@Sun.COM ap = lp->arg;
2458462SApril.Chin@Sun.COM memcpy(lp, &savelex, offsetof(Lex_t,lexd));
2468462SApril.Chin@Sun.COM lp->arg = ap;
2478462SApril.Chin@Sun.COM lp->aliasok = aok;
24810898Sroland.mainz@nrubsig.org if(lp->lexd.docword && docextra)
24910898Sroland.mainz@nrubsig.org {
25010898Sroland.mainz@nrubsig.org lp->lexd.docextra = docextra;
25110898Sroland.mainz@nrubsig.org lp->lexd.docend = fcseek(0)-1;
25210898Sroland.mainz@nrubsig.org }
2534887Schin return(c);
2544887Schin }
2554887Schin
2564887Schin /*
2574887Schin * mode=1 for reinitialization
2584887Schin */
sh_lexopen(Lex_t * lp,Shell_t * sp,int mode)2594887Schin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode)
2604887Schin {
2614887Schin if(!lp)
2624887Schin {
2634887Schin lp = (Lex_t*)newof(0,Lex_t,1,0);
2648462SApril.Chin@Sun.COM lp->sh = sp;
2654887Schin }
2668462SApril.Chin@Sun.COM fcnotify(lex_advance,lp);
2678462SApril.Chin@Sun.COM lp->lex.intest = lp->lex.incase = lp->lex.skipword = lp->lexd.warn = 0;
2688462SApril.Chin@Sun.COM lp->comp_assign = 0;
2698462SApril.Chin@Sun.COM lp->lex.reservok = 1;
2704887Schin if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC))
2718462SApril.Chin@Sun.COM lp->lexd.warn=1;
2724887Schin if(!mode)
2734887Schin {
2748462SApril.Chin@Sun.COM lp->lexd.noarg = lp->lexd.level= lp->lexd.dolparen = lp->lexd.balance = 0;
2758462SApril.Chin@Sun.COM lp->lexd.nocopy = lp->lexd.docword = lp->lexd.nest = lp->lexd.paren = 0;
276*12068SRoger.Faulkner@Oracle.COM lp->lexd.lex_state = lp->lexd.lastc=0;
2774887Schin }
2788462SApril.Chin@Sun.COM lp->comsub = 0;
2794887Schin return(lp);
2804887Schin }
2814887Schin
2824887Schin #ifdef DBUG
2838462SApril.Chin@Sun.COM extern int lextoken(Lex_t*);
sh_lex(Lex_t * lp)2848462SApril.Chin@Sun.COM int sh_lex(Lex_t *lp)
2854887Schin {
2868462SApril.Chin@Sun.COM Shell_t *shp = lp->sh;
2874887Schin register int flag;
2884887Schin char *quoted, *macro, *split, *expand;
2894887Schin char tokstr[3];
2904887Schin register int tok = lextoken();
2914887Schin quoted = macro = split = expand = "";
2928462SApril.Chin@Sun.COM if(tok==0 && (flag=lp->arg->argflag))
2934887Schin {
2944887Schin if(flag&ARG_MAC)
2954887Schin macro = "macro:";
2964887Schin if(flag&ARG_EXP)
2974887Schin expand = "expand:";
2984887Schin if(flag&ARG_QUOTED)
2994887Schin quoted = "quoted:";
3004887Schin }
3014887Schin sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted,
3024887Schin macro, split, expand, fmttoken(lp,tok,tokstr));
3034887Schin return(tok);
3044887Schin }
3054887Schin #define sh_lex lextoken
3064887Schin #endif
3074887Schin
3084887Schin /*
3094887Schin * Get the next word and put it on the top of the stak
3108462SApril.Chin@Sun.COM * A pointer to the current word is stored in lp->arg
3114887Schin * Returns the token type
3124887Schin */
sh_lex(Lex_t * lp)3138462SApril.Chin@Sun.COM int sh_lex(Lex_t* lp)
3144887Schin {
3158462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh;
3164887Schin register const char *state;
3178462SApril.Chin@Sun.COM register int n, c, mode=ST_BEGIN, wordflags=0;
3188462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk;
3198462SApril.Chin@Sun.COM int inlevel=lp->lexd.level, assignment=0, ingrave=0;
3204887Schin Sfio_t *sp;
3214887Schin #if SHOPT_MULTIBYTE
3224887Schin LEN=1;
3234887Schin #endif /* SHOPT_MULTIBYTE */
3248462SApril.Chin@Sun.COM if(lp->lexd.paren)
3254887Schin {
3268462SApril.Chin@Sun.COM lp->lexd.paren = 0;
3278462SApril.Chin@Sun.COM return(lp->token=LPAREN);
3284887Schin }
3298462SApril.Chin@Sun.COM if(lp->lex.incase)
3308462SApril.Chin@Sun.COM lp->assignok = 0;
3314887Schin else
3328462SApril.Chin@Sun.COM lp->assignok |= lp->lex.reservok;
3338462SApril.Chin@Sun.COM if(lp->comp_assign==2)
3348462SApril.Chin@Sun.COM lp->comp_assign = lp->lex.reservok = 0;
3358462SApril.Chin@Sun.COM lp->lexd.arith = (lp->lexd.nest==1);
3368462SApril.Chin@Sun.COM if(lp->lexd.nest)
3374887Schin {
3388462SApril.Chin@Sun.COM pushlevel(lp,lp->lexd.nest,ST_NONE);
3398462SApril.Chin@Sun.COM lp->lexd.nest = 0;
3408462SApril.Chin@Sun.COM mode = lp->lexd.lex_state;
3414887Schin }
3428462SApril.Chin@Sun.COM else if(lp->lexd.docword)
3434887Schin {
3444887Schin if(fcgetc(c)=='-' || c=='#')
3454887Schin {
3468462SApril.Chin@Sun.COM lp->lexd.docword++;
3478462SApril.Chin@Sun.COM lp->digits=(c=='#'?3:1);
3484887Schin }
3494887Schin else if(c=='<')
3504887Schin {
3518462SApril.Chin@Sun.COM lp->digits=2;
3528462SApril.Chin@Sun.COM lp->lexd.docword=0;
3534887Schin }
3544887Schin else if(c>0)
3554887Schin fcseek(-1);
3564887Schin }
3578462SApril.Chin@Sun.COM if(!lp->lexd.dolparen)
3584887Schin {
3598462SApril.Chin@Sun.COM lp->arg = 0;
3604887Schin if(mode!=ST_BEGIN)
3618462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0);
3624887Schin else
3638462SApril.Chin@Sun.COM lp->lexd.first = 0;
3644887Schin }
3658462SApril.Chin@Sun.COM lp->lastline = lp->sh->inlineno;
3664887Schin while(1)
3674887Schin {
3684887Schin /* skip over characters in the current state */
3694887Schin state = sh_lexstates[mode];
3704887Schin while((n=STATE(state,c))==0);
3714887Schin switch(n)
3724887Schin {
3734887Schin case S_BREAK:
3744887Schin fcseek(-1);
3754887Schin goto breakloop;
3764887Schin case S_EOF:
3774887Schin sp = fcfile();
3788462SApril.Chin@Sun.COM if((n=lexfill(lp)) > 0)
3794887Schin {
3804887Schin fcseek(-1);
3814887Schin continue;
3824887Schin }
3834887Schin /* check for zero byte in file */
3844887Schin if(n==0 && fcfile())
3854887Schin {
3864887Schin if(shp->readscript)
3874887Schin {
3884887Schin char *cp = error_info.id;
3894887Schin errno = ENOEXEC;
3904887Schin error_info.id = shp->readscript;
3914887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp);
3924887Schin }
3934887Schin else
3944887Schin {
3958462SApril.Chin@Sun.COM lp->token = -1;
3968462SApril.Chin@Sun.COM sh_syntax(lp);
3974887Schin }
3984887Schin }
3994887Schin /* end-of-file */
4004887Schin if(mode==ST_BEGIN)
4018462SApril.Chin@Sun.COM return(lp->token=EOFSYM);
4028462SApril.Chin@Sun.COM if(mode >ST_NORM && lp->lexd.level>0)
4034887Schin {
4048462SApril.Chin@Sun.COM switch(c=endchar(lp))
4054887Schin {
4064887Schin case '$':
4074887Schin if(mode==ST_LIT)
4084887Schin {
4094887Schin c = '\'';
4104887Schin break;
4114887Schin }
4128462SApril.Chin@Sun.COM mode = oldmode(lp);
4138462SApril.Chin@Sun.COM poplevel(lp);
4144887Schin continue;
4154887Schin case RBRACT:
4164887Schin c = LBRACT;
4174887Schin break;
4184887Schin case 1: /* for ((...)) */
4194887Schin case RPAREN:
4204887Schin c = LPAREN;
4214887Schin break;
4224887Schin default:
4234887Schin c = LBRACE;
4244887Schin break;
4254887Schin case '"': case '`': case '\'':
4268462SApril.Chin@Sun.COM lp->lexd.balance = c;
4274887Schin break;
4284887Schin }
4294887Schin if(sp && !(sfset(sp,0,0)&SF_STRING))
4304887Schin {
4318462SApril.Chin@Sun.COM lp->lasttok = c;
4328462SApril.Chin@Sun.COM lp->token = EOFSYM;
4338462SApril.Chin@Sun.COM sh_syntax(lp);
4344887Schin }
4358462SApril.Chin@Sun.COM lp->lexd.balance = c;
4364887Schin }
4374887Schin goto breakloop;
4384887Schin case S_COM:
4394887Schin /* skip one or more comment line(s) */
4408462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest;
4418462SApril.Chin@Sun.COM if((n=lp->lexd.nocopy) && lp->lexd.dolparen)
4428462SApril.Chin@Sun.COM lp->lexd.nocopy--;
4434887Schin do
4444887Schin {
4454887Schin while(fcgetc(c)>0 && c!='\n');
4468462SApril.Chin@Sun.COM if(c<=0 || lp->heredoc)
4474887Schin break;
4484887Schin while(shp->inlineno++,fcpeek(0)=='\n')
4494887Schin fcseek(1);
4504887Schin while(state[c=fcpeek(0)]==0)
4514887Schin fcseek(1);
4524887Schin }
4534887Schin while(c=='#');
4548462SApril.Chin@Sun.COM lp->lexd.nocopy = n;
4554887Schin if(c<0)
4568462SApril.Chin@Sun.COM return(lp->token=EOFSYM);
4574887Schin n = S_NLTOK;
4584887Schin shp->inlineno--;
4594887Schin /* FALL THRU */
4604887Schin case S_NLTOK:
4614887Schin /* check for here-document */
4628462SApril.Chin@Sun.COM if(lp->heredoc)
4634887Schin {
4648462SApril.Chin@Sun.COM if(!lp->lexd.dolparen)
4658462SApril.Chin@Sun.COM lp->lexd.nocopy++;
4664887Schin c = shp->inlineno;
4678462SApril.Chin@Sun.COM if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok)
4684887Schin {
4698462SApril.Chin@Sun.COM lp->lasttok = IODOCSYM;
4708462SApril.Chin@Sun.COM lp->token = EOFSYM;
4718462SApril.Chin@Sun.COM lp->lastline = c;
4728462SApril.Chin@Sun.COM sh_syntax(lp);
4734887Schin }
4748462SApril.Chin@Sun.COM if(!lp->lexd.dolparen)
4758462SApril.Chin@Sun.COM lp->lexd.nocopy--;
4768462SApril.Chin@Sun.COM lp->heredoc = 0;
4774887Schin }
4788462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest;
4798462SApril.Chin@Sun.COM lp->lex.skipword = 0;
4804887Schin /* FALL THRU */
4814887Schin case S_NL:
4824887Schin /* skip over new-lines */
4838462SApril.Chin@Sun.COM lp->lex.last_quote = 0;
4844887Schin while(shp->inlineno++,fcget()=='\n');
4854887Schin fcseek(-1);
4864887Schin if(n==S_NLTOK)
4874887Schin {
4888462SApril.Chin@Sun.COM lp->comp_assign = 0;
4898462SApril.Chin@Sun.COM return(lp->token='\n');
4904887Schin }
4914887Schin case S_BLNK:
4928462SApril.Chin@Sun.COM if(lp->lex.incase<=TEST_RE)
4934887Schin continue;
4944887Schin /* implicit RPAREN for =~ test operator */
4958462SApril.Chin@Sun.COM if(inlevel+1==lp->lexd.level)
4964887Schin {
4978462SApril.Chin@Sun.COM if(lp->lex.intest)
4988462SApril.Chin@Sun.COM fcseek(-1);
4994887Schin c = RPAREN;
5004887Schin goto do_pop;
5014887Schin }
5024887Schin continue;
5034887Schin case S_OP:
5044887Schin /* return operator token */
5054887Schin if(c=='<' || c=='>')
5064887Schin {
5078462SApril.Chin@Sun.COM if(lp->lex.testop2)
5088462SApril.Chin@Sun.COM lp->lex.testop2 = 0;
5094887Schin else
5104887Schin {
5118462SApril.Chin@Sun.COM lp->digits = (c=='>');
5128462SApril.Chin@Sun.COM lp->lex.skipword = 1;
5138462SApril.Chin@Sun.COM lp->aliasok = lp->lex.reservok;
5148462SApril.Chin@Sun.COM lp->lex.reservok = 0;
5154887Schin }
5164887Schin }
5174887Schin else
5184887Schin {
5198462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest;
5204887Schin if(c==RPAREN)
5214887Schin {
5228462SApril.Chin@Sun.COM if(!lp->lexd.dolparen)
5238462SApril.Chin@Sun.COM lp->lex.incase = 0;
5248462SApril.Chin@Sun.COM return(lp->token=c);
5254887Schin }
5268462SApril.Chin@Sun.COM lp->lex.testop1 = lp->lex.intest;
5274887Schin }
5284887Schin if(fcgetc(n)>0)
5294887Schin fcseek(-1);
5304887Schin if(state[n]==S_OP || n=='#')
5314887Schin {
5324887Schin if(n==c)
5334887Schin {
5344887Schin if(c=='<')
5358462SApril.Chin@Sun.COM lp->lexd.docword=1;
5364887Schin else if(n==LPAREN)
5374887Schin {
5388462SApril.Chin@Sun.COM lp->lexd.nest=1;
5398462SApril.Chin@Sun.COM lp->lastline = shp->inlineno;
5408462SApril.Chin@Sun.COM lp->lexd.lex_state = ST_NESTED;
5414887Schin fcseek(1);
5428462SApril.Chin@Sun.COM return(sh_lex(lp));
5434887Schin }
5444887Schin c |= SYMREP;
5454887Schin }
5464887Schin else if(c=='(' || c==')')
5478462SApril.Chin@Sun.COM return(lp->token=c);
5484887Schin else if(c=='&')
5494887Schin {
55010898Sroland.mainz@nrubsig.org if(!sh_isoption(SH_POSIX) && n=='>' && (sh_isoption(SH_BASH) || sh_isstate(SH_PROFILE)))
5514887Schin {
55210898Sroland.mainz@nrubsig.org if(!sh_isoption(SH_BASH) && !lp->nonstandard)
55310898Sroland.mainz@nrubsig.org {
55410898Sroland.mainz@nrubsig.org lp->nonstandard = 1;
55510898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_warn(0),e_lexnonstandard,shp->inlineno);
55610898Sroland.mainz@nrubsig.org }
5578462SApril.Chin@Sun.COM lp->digits = -1;
5584887Schin c = '>';
5594887Schin }
5604887Schin else
5614887Schin n = 0;
5624887Schin }
5634887Schin else if(n=='&')
5644887Schin c |= SYMAMP;
5654887Schin else if(c!='<' && c!='>')
5664887Schin n = 0;
5674887Schin else if(n==LPAREN)
5684887Schin {
5694887Schin c |= SYMLPAR;
5708462SApril.Chin@Sun.COM lp->lex.reservok = 1;
5718462SApril.Chin@Sun.COM lp->lex.skipword = 0;
5724887Schin }
5734887Schin else if(n=='|')
5744887Schin c |= SYMPIPE;
5754887Schin else if(c=='<' && n=='>')
57610898Sroland.mainz@nrubsig.org {
57710898Sroland.mainz@nrubsig.org lp->digits = 1;
5784887Schin c = IORDWRSYM;
57910898Sroland.mainz@nrubsig.org fcgetc(n);
58010898Sroland.mainz@nrubsig.org if(fcgetc(n)==';')
58110898Sroland.mainz@nrubsig.org {
58210898Sroland.mainz@nrubsig.org lp->token = c = IORDWRSYMT;
58310898Sroland.mainz@nrubsig.org if(lp->inexec)
58410898Sroland.mainz@nrubsig.org sh_syntax(lp);
58510898Sroland.mainz@nrubsig.org }
58610898Sroland.mainz@nrubsig.org else if(n>0)
58710898Sroland.mainz@nrubsig.org fcseek(-1);
58810898Sroland.mainz@nrubsig.org n= 0;
58910898Sroland.mainz@nrubsig.org }
5904887Schin else if(n=='#' && (c=='<'||c=='>'))
5914887Schin c |= SYMSHARP;
5928462SApril.Chin@Sun.COM else if(n==';' && c=='>')
5938462SApril.Chin@Sun.COM {
5948462SApril.Chin@Sun.COM c |= SYMSEMI;
5958462SApril.Chin@Sun.COM if(lp->inexec)
5968462SApril.Chin@Sun.COM {
5978462SApril.Chin@Sun.COM lp->token = c;
5988462SApril.Chin@Sun.COM sh_syntax(lp);
5998462SApril.Chin@Sun.COM }
6008462SApril.Chin@Sun.COM }
6014887Schin else
6024887Schin n = 0;
6034887Schin if(n)
6044887Schin {
6054887Schin fcseek(1);
6068462SApril.Chin@Sun.COM lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM);
6074887Schin }
6084887Schin else
6094887Schin {
61010898Sroland.mainz@nrubsig.org if(lp->lexd.warn && (n=fcpeek(0))!=RPAREN && n!=' ' && n!='\t')
6114887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n);
6124887Schin }
6134887Schin }
6148462SApril.Chin@Sun.COM if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase)
6158462SApril.Chin@Sun.COM lp->comp_assign = 2;
6164887Schin else
6178462SApril.Chin@Sun.COM lp->comp_assign = 0;
6188462SApril.Chin@Sun.COM return(lp->token=c);
6194887Schin case S_ESC:
6204887Schin /* check for \<new-line> */
6214887Schin fcgetc(n);
6224887Schin c=2;
6234887Schin #if SHOPT_CRNL
6244887Schin if(n=='\r')
6254887Schin {
6264887Schin if(fcgetc(n)=='\n')
6274887Schin c=3;
6284887Schin else
6294887Schin {
6304887Schin n='\r';
6314887Schin fcseek(-1);
6324887Schin }
6334887Schin }
6344887Schin #endif /* SHOPT_CRNL */
6354887Schin if(n=='\n')
6364887Schin {
6374887Schin Sfio_t *sp;
6384887Schin struct argnod *ap;
6394887Schin shp->inlineno++;
6404887Schin /* synchronize */
6414887Schin if(!(sp=fcfile()))
6424887Schin state=fcseek(0);
6434887Schin fcclose();
6448462SApril.Chin@Sun.COM ap = lp->arg;
6454887Schin if(sp)
6464887Schin fcfopen(sp);
6474887Schin else
6484887Schin fcsopen((char*)state);
6494887Schin /* remove \new-line */
6508462SApril.Chin@Sun.COM n = stktell(stkp)-c;
6518462SApril.Chin@Sun.COM stkseek(stkp,n);
6528462SApril.Chin@Sun.COM lp->arg = ap;
6534887Schin if(n<=ARGVAL)
6544887Schin {
6554887Schin mode = 0;
6568462SApril.Chin@Sun.COM lp->lexd.first = 0;
6574887Schin }
6584887Schin continue;
6594887Schin }
6604887Schin wordflags |= ARG_QUOTED;
6614887Schin if(mode==ST_DOL)
6624887Schin goto err;
6634887Schin #ifndef STR_MAXIMAL
6648462SApril.Chin@Sun.COM else if(mode==ST_NESTED && lp->lexd.warn &&
6658462SApril.Chin@Sun.COM endchar(lp)==RBRACE &&
6664887Schin sh_lexstates[ST_DOL][n]==S_DIG
6674887Schin )
6684887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n);
6694887Schin #endif /* STR_MAXIMAL */
6704887Schin break;
6714887Schin case S_NAME:
6728462SApril.Chin@Sun.COM if(!lp->lex.skipword)
6738462SApril.Chin@Sun.COM lp->lex.reservok *= 2;
6744887Schin /* FALL THRU */
6754887Schin case S_TILDE:
6764887Schin case S_RES:
6778462SApril.Chin@Sun.COM if(!lp->lexd.dolparen)
6788462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0)-LEN;
6798462SApril.Chin@Sun.COM else if(lp->lexd.docword)
6808462SApril.Chin@Sun.COM lp->lexd.docend = fcseek(0)-LEN;
6814887Schin mode = ST_NAME;
6824887Schin if(c=='.')
6834887Schin fcseek(-1);
6844887Schin if(n!=S_TILDE)
6854887Schin continue;
6864887Schin fcgetc(n);
6874887Schin if(n>0)
6888462SApril.Chin@Sun.COM {
6898462SApril.Chin@Sun.COM if(c=='~' && n==LPAREN && lp->lex.incase)
6908462SApril.Chin@Sun.COM lp->lex.incase = TEST_RE;
6914887Schin fcseek(-1);
6928462SApril.Chin@Sun.COM }
6934887Schin if(n==LPAREN)
6944887Schin goto epat;
6954887Schin wordflags = ARG_MAC;
6964887Schin mode = ST_NORM;
6974887Schin continue;
6984887Schin case S_REG:
6994887Schin if(mode==ST_BEGIN)
7004887Schin {
7018462SApril.Chin@Sun.COM do_reg:
7024887Schin /* skip new-line joining */
7034887Schin if(c=='\\' && fcpeek(0)=='\n')
7044887Schin {
7054887Schin shp->inlineno++;
7064887Schin fcseek(1);
7074887Schin continue;
7084887Schin }
7094887Schin fcseek(-1);
7108462SApril.Chin@Sun.COM if(!lp->lexd.dolparen)
7118462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0);
7128462SApril.Chin@Sun.COM else if(lp->lexd.docword)
7138462SApril.Chin@Sun.COM lp->lexd.docend = fcseek(0);
7148462SApril.Chin@Sun.COM if(c=='[' && lp->assignok>=SH_ASSIGN)
7154887Schin {
7164887Schin mode = ST_NAME;
7174887Schin continue;
7184887Schin }
7194887Schin }
7204887Schin mode = ST_NORM;
7214887Schin continue;
7224887Schin case S_LIT:
7238462SApril.Chin@Sun.COM if(oldmode(lp)==ST_NONE && !lp->lexd.noarg) /* in ((...)) */
7244887Schin {
7254887Schin if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']')
7264887Schin {
7274887Schin if(fcpeek(1)=='\'')
7284887Schin fcseek(2);
7294887Schin }
7304887Schin continue;
7314887Schin }
7324887Schin wordflags |= ARG_QUOTED;
7334887Schin if(mode==ST_DOL)
7344887Schin {
7358462SApril.Chin@Sun.COM if(endchar(lp)!='$')
7364887Schin goto err;
7378462SApril.Chin@Sun.COM if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */
7384887Schin {
7398462SApril.Chin@Sun.COM if(lp->lexd.warn)
7404887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
7414887Schin mode = ST_LIT;
7424887Schin }
7434887Schin }
7444887Schin if(mode!=ST_LIT)
7454887Schin {
7468462SApril.Chin@Sun.COM if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
7478462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
7488462SApril.Chin@Sun.COM lp->lex.last_quote = 0;
7498462SApril.Chin@Sun.COM lp->lastline = shp->inlineno;
7504887Schin if(mode!=ST_DOL)
7518462SApril.Chin@Sun.COM pushlevel(lp,'\'',mode);
7524887Schin mode = ST_LIT;
7534887Schin continue;
7544887Schin }
7554887Schin /* check for multi-line single-quoted string */
7568462SApril.Chin@Sun.COM else if(shp->inlineno > lp->lastline)
7578462SApril.Chin@Sun.COM lp->lex.last_quote = '\'';
7588462SApril.Chin@Sun.COM mode = oldmode(lp);
7598462SApril.Chin@Sun.COM poplevel(lp);
7604887Schin break;
7614887Schin case S_ESC2:
7624887Schin /* \ inside '' */
7638462SApril.Chin@Sun.COM if(endchar(lp)=='$')
7644887Schin {
7654887Schin fcgetc(n);
7664887Schin if(n=='\n')
7674887Schin shp->inlineno++;
7684887Schin }
7694887Schin continue;
7704887Schin case S_GRAVE:
7718462SApril.Chin@Sun.COM if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`'))
7724887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno);
7734887Schin wordflags |=(ARG_MAC|ARG_EXP);
7744887Schin if(mode==ST_QUOTE)
7754887Schin ingrave = !ingrave;
7764887Schin /* FALL THRU */
7774887Schin case S_QUOTE:
7788462SApril.Chin@Sun.COM if(oldmode(lp)==ST_NONE && lp->lexd.arith) /* in ((...)) */
7798462SApril.Chin@Sun.COM {
7808462SApril.Chin@Sun.COM if(n!=S_GRAVE || fcpeek(0)=='\'')
7818462SApril.Chin@Sun.COM continue;
7828462SApril.Chin@Sun.COM }
7834887Schin if(n==S_QUOTE)
7844887Schin wordflags |=ARG_QUOTED;
7854887Schin if(mode!=ST_QUOTE)
7864887Schin {
7874887Schin if(c!='"' || mode!=ST_QNEST)
7884887Schin {
7898462SApril.Chin@Sun.COM if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
7908462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
7918462SApril.Chin@Sun.COM lp->lex.last_quote=0;
7928462SApril.Chin@Sun.COM lp->lastline = shp->inlineno;
7938462SApril.Chin@Sun.COM pushlevel(lp,c,mode);
7944887Schin }
79510898Sroland.mainz@nrubsig.org ingrave ^= (c=='`');
7964887Schin mode = ST_QUOTE;
7974887Schin continue;
7984887Schin }
7998462SApril.Chin@Sun.COM else if((n=endchar(lp))==c)
8004887Schin {
8018462SApril.Chin@Sun.COM if(shp->inlineno > lp->lastline)
8028462SApril.Chin@Sun.COM lp->lex.last_quote = c;
8038462SApril.Chin@Sun.COM mode = oldmode(lp);
8048462SApril.Chin@Sun.COM poplevel(lp);
8054887Schin }
8064887Schin else if(c=='"' && n==RBRACE)
8074887Schin mode = ST_QNEST;
8084887Schin break;
8094887Schin case S_DOL:
8104887Schin /* don't check syntax inside `` */
8114887Schin if(mode==ST_QUOTE && ingrave)
8124887Schin continue;
8134887Schin #if SHOPT_KIA
8148462SApril.Chin@Sun.COM if(lp->lexd.first)
8158462SApril.Chin@Sun.COM lp->lexd.kiaoff = fcseek(0)-lp->lexd.first;
8164887Schin else
8178462SApril.Chin@Sun.COM lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst();
8184887Schin #endif /* SHOPT_KIA */
8198462SApril.Chin@Sun.COM pushlevel(lp,'$',mode);
8204887Schin mode = ST_DOL;
8214887Schin continue;
8224887Schin case S_PAR:
8238462SApril.Chin@Sun.COM do_comsub:
8244887Schin wordflags |= ARG_MAC;
8258462SApril.Chin@Sun.COM mode = oldmode(lp);
8268462SApril.Chin@Sun.COM poplevel(lp);
8274887Schin fcseek(-1);
8288462SApril.Chin@Sun.COM wordflags |= comsub(lp,c);
8294887Schin continue;
8304887Schin case S_RBRA:
8318462SApril.Chin@Sun.COM if((n=endchar(lp)) == '$')
8324887Schin goto err;
8334887Schin if(mode!=ST_QUOTE || n==RBRACE)
8344887Schin {
8358462SApril.Chin@Sun.COM mode = oldmode(lp);
8368462SApril.Chin@Sun.COM poplevel(lp);
8374887Schin }
8384887Schin break;
8394887Schin case S_EDOL:
8404887Schin /* end $identifier */
8414887Schin #if SHOPT_KIA
8428462SApril.Chin@Sun.COM if(lp->kiafile)
8438462SApril.Chin@Sun.COM refvar(lp,0);
8444887Schin #endif /* SHOPT_KIA */
8458462SApril.Chin@Sun.COM if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED)
8464887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno);
8474887Schin fcseek(-1);
8488462SApril.Chin@Sun.COM mode = oldmode(lp);
8498462SApril.Chin@Sun.COM poplevel(lp);
8504887Schin break;
8514887Schin case S_DOT:
8524887Schin /* make sure next character is alpha */
8534887Schin if(fcgetc(n)>0)
8548462SApril.Chin@Sun.COM {
8558462SApril.Chin@Sun.COM if(n=='.')
8568462SApril.Chin@Sun.COM fcgetc(n);
8578462SApril.Chin@Sun.COM if(n>0)
8588462SApril.Chin@Sun.COM fcseek(-1);
8598462SApril.Chin@Sun.COM }
8604887Schin if(isaletter(n) || n==LBRACT)
8614887Schin continue;
8624887Schin if(mode==ST_NAME)
8634887Schin {
8644887Schin if(n=='=')
8654887Schin continue;
8664887Schin break;
8674887Schin }
8684887Schin else if(n==RBRACE)
8694887Schin continue;
8704887Schin if(isastchar(n))
8714887Schin continue;
8724887Schin goto err;
8734887Schin case S_SPC1:
8744887Schin wordflags |= ARG_MAC;
8758462SApril.Chin@Sun.COM if(endchar(lp)==RBRACE)
8764887Schin {
8778462SApril.Chin@Sun.COM setchar(lp,c);
8784887Schin continue;
8794887Schin }
8804887Schin /* FALL THRU */
8814887Schin case S_ALP:
8828462SApril.Chin@Sun.COM if(c=='.' && endchar(lp)=='$')
8834887Schin goto err;
8844887Schin case S_SPC2:
8854887Schin case S_DIG:
8864887Schin wordflags |= ARG_MAC;
8878462SApril.Chin@Sun.COM switch(endchar(lp))
8884887Schin {
8894887Schin case '$':
8904887Schin if(n==S_ALP) /* $identifier */
8914887Schin mode = ST_DOLNAME;
8924887Schin else
8934887Schin {
8948462SApril.Chin@Sun.COM mode = oldmode(lp);
8958462SApril.Chin@Sun.COM poplevel(lp);
8964887Schin }
8974887Schin break;
8984887Schin #if SHOPT_TYPEDEF
8994887Schin case '@':
9004887Schin #endif /* SHOPT_TYPEDEF */
9014887Schin case '!':
9024887Schin if(n!=S_ALP)
9034887Schin goto dolerr;
9044887Schin case '#':
9054887Schin case RBRACE:
9064887Schin if(n==S_ALP)
9074887Schin {
9088462SApril.Chin@Sun.COM setchar(lp,RBRACE);
9094887Schin if(c=='.')
9104887Schin fcseek(-1);
9114887Schin mode = ST_BRACE;
9124887Schin }
9134887Schin else
9144887Schin {
9154887Schin if(fcgetc(c)>0)
9164887Schin fcseek(-1);
9174887Schin if(state[c]==S_ALP)
9184887Schin goto err;
9194887Schin if(n==S_DIG)
9208462SApril.Chin@Sun.COM setchar(lp,'0');
9214887Schin else
9228462SApril.Chin@Sun.COM setchar(lp,'!');
9234887Schin }
9244887Schin break;
9254887Schin case '0':
9264887Schin if(n==S_DIG)
9274887Schin break;
9284887Schin default:
9294887Schin goto dolerr;
9304887Schin }
9314887Schin break;
9324887Schin dolerr:
9334887Schin case S_ERR:
9348462SApril.Chin@Sun.COM if((n=endchar(lp)) == '$')
9354887Schin goto err;
9364887Schin if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2)
9374887Schin {
9384887Schin /* see whether inside `...` */
9398462SApril.Chin@Sun.COM mode = oldmode(lp);
9408462SApril.Chin@Sun.COM poplevel(lp);
9418462SApril.Chin@Sun.COM if((n = endchar(lp)) != '`')
9424887Schin goto err;
9438462SApril.Chin@Sun.COM pushlevel(lp,RBRACE,mode);
9444887Schin }
9454887Schin else
9468462SApril.Chin@Sun.COM setchar(lp,RBRACE);
9474887Schin mode = ST_NESTED;
9484887Schin continue;
9494887Schin case S_MOD1:
9508462SApril.Chin@Sun.COM if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE)
9514887Schin {
9524887Schin /* allow ' inside "${...}" */
9534887Schin if(c==':' && fcgetc(n)>0)
9544887Schin {
9554887Schin n = state[n];
9564887Schin fcseek(-1);
9574887Schin }
9584887Schin if(n==S_MOD1)
9594887Schin {
9604887Schin mode = ST_QUOTE;
9614887Schin continue;
9624887Schin }
9634887Schin }
9644887Schin /* FALL THRU */
9654887Schin case S_MOD2:
9664887Schin #if SHOPT_KIA
9678462SApril.Chin@Sun.COM if(lp->kiafile)
9688462SApril.Chin@Sun.COM refvar(lp,1);
9694887Schin #endif /* SHOPT_KIA */
9704887Schin if(c!=':' && fcgetc(n)>0)
9714887Schin {
9724887Schin if(n!=c)
9734887Schin c = 0;
9744887Schin if(!c || (fcgetc(n)>0))
9754887Schin {
9764887Schin fcseek(-1);
9774887Schin if(n==LPAREN)
9784887Schin {
9794887Schin if(c!='%')
9804887Schin {
9818462SApril.Chin@Sun.COM lp->token = n;
9828462SApril.Chin@Sun.COM sh_syntax(lp);
9834887Schin }
9848462SApril.Chin@Sun.COM else if(lp->lexd.warn)
9854887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%');
9864887Schin }
9874887Schin }
9884887Schin }
9894887Schin mode = ST_NESTED;
9904887Schin continue;
9914887Schin case S_LBRA:
9928462SApril.Chin@Sun.COM if((c=endchar(lp)) == '$')
9934887Schin {
9944887Schin if(fcgetc(c)>0)
9954887Schin fcseek(-1);
9968462SApril.Chin@Sun.COM setchar(lp,RBRACE);
9974887Schin if(state[c]!=S_ERR && c!=RBRACE)
9984887Schin continue;
9998462SApril.Chin@Sun.COM if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK)
10008462SApril.Chin@Sun.COM {
10018462SApril.Chin@Sun.COM c = LBRACE;
10028462SApril.Chin@Sun.COM goto do_comsub;
10038462SApril.Chin@Sun.COM }
10044887Schin }
10054887Schin err:
10068462SApril.Chin@Sun.COM n = endchar(lp);
10078462SApril.Chin@Sun.COM mode = oldmode(lp);
10088462SApril.Chin@Sun.COM poplevel(lp);
10094887Schin if(n!='$')
10104887Schin {
10118462SApril.Chin@Sun.COM lp->token = c;
10128462SApril.Chin@Sun.COM sh_syntax(lp);
10134887Schin }
10144887Schin else
10154887Schin {
10168462SApril.Chin@Sun.COM if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE))
10174887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
101810898Sroland.mainz@nrubsig.org else if(c=='"' && mode!=ST_QUOTE && !ingrave)
10194887Schin wordflags |= ARG_MESSAGE;
10204887Schin fcseek(-1);
10214887Schin }
10224887Schin continue;
10234887Schin case S_META:
10248462SApril.Chin@Sun.COM if(lp->lexd.warn && endchar(lp)==RBRACE)
10254887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
10264887Schin continue;
10274887Schin case S_PUSH:
10288462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,mode);
10294887Schin mode = ST_NESTED;
10304887Schin continue;
10314887Schin case S_POP:
10324887Schin do_pop:
10338462SApril.Chin@Sun.COM if(lp->lexd.level <= inlevel)
10344887Schin break;
10358462SApril.Chin@Sun.COM if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest)
10368462SApril.Chin@Sun.COM {
10378462SApril.Chin@Sun.COM fcseek(-1);
10388462SApril.Chin@Sun.COM goto breakloop;
10398462SApril.Chin@Sun.COM }
10408462SApril.Chin@Sun.COM n = endchar(lp);
10414887Schin if(c==RBRACT && !(n==RBRACT || n==RPAREN))
10424887Schin continue;
10434887Schin if((c==RBRACE||c==RPAREN) && n==RPAREN)
10444887Schin {
10454887Schin if(fcgetc(n)==LPAREN)
10464887Schin {
10474887Schin if(c!=RPAREN)
10484887Schin fcseek(-1);
10494887Schin continue;
10504887Schin }
10514887Schin if(n>0)
10524887Schin fcseek(-1);
10534887Schin n = RPAREN;
10544887Schin }
10554887Schin if(c==';' && n!=';')
10564887Schin {
10578462SApril.Chin@Sun.COM if(lp->lexd.warn && n==RBRACE)
10584887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
10594887Schin continue;
10604887Schin }
10614887Schin if(mode==ST_QNEST)
10624887Schin {
10638462SApril.Chin@Sun.COM if(lp->lexd.warn)
10644887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c);
10654887Schin continue;
10664887Schin }
10678462SApril.Chin@Sun.COM mode = oldmode(lp);
10688462SApril.Chin@Sun.COM poplevel(lp);
10694887Schin /* quotes in subscript need expansion */
10704887Schin if(mode==ST_NAME && (wordflags&ARG_QUOTED))
10714887Schin wordflags |= ARG_MAC;
10724887Schin /* check for ((...)) */
10734887Schin if(n==1 && c==RPAREN)
10744887Schin {
10754887Schin if(fcgetc(n)==RPAREN)
10764887Schin {
10778462SApril.Chin@Sun.COM if(mode==ST_NONE && !lp->lexd.dolparen)
10784887Schin goto breakloop;
10798462SApril.Chin@Sun.COM lp->lex.reservok = 1;
10808462SApril.Chin@Sun.COM lp->lex.skipword = 0;
10818462SApril.Chin@Sun.COM return(lp->token=EXPRSYM);
10824887Schin }
10834887Schin /* backward compatibility */
10844887Schin {
10858462SApril.Chin@Sun.COM if(lp->lexd.warn)
10864887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
10878462SApril.Chin@Sun.COM if(!(state=lp->lexd.first))
10884887Schin state = fcfirst();
10894887Schin fcseek(state-fcseek(0));
10908462SApril.Chin@Sun.COM if(lp->arg)
10914887Schin {
10928462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1);
10938462SApril.Chin@Sun.COM setupalias(lp,lp->arg->argval,NIL(Namval_t*));
10944887Schin }
10958462SApril.Chin@Sun.COM lp->lexd.paren = 1;
10964887Schin }
10978462SApril.Chin@Sun.COM return(lp->token=LPAREN);
10984887Schin }
10994887Schin if(mode==ST_NONE)
11004887Schin return(0);
11014887Schin if(c!=n)
11024887Schin {
11038462SApril.Chin@Sun.COM lp->token = c;
11048462SApril.Chin@Sun.COM sh_syntax(lp);
11054887Schin }
11064887Schin if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
11074887Schin goto epat;
11084887Schin continue;
11094887Schin case S_EQ:
11108462SApril.Chin@Sun.COM assignment = lp->assignok;
11114887Schin /* FALL THRU */
11124887Schin case S_COLON:
11134887Schin if(assignment)
11144887Schin {
11154887Schin if((c=fcget())=='~')
11164887Schin wordflags |= ARG_MAC;
11174887Schin else if(c!=LPAREN && assignment==SH_COMPASSIGN)
11184887Schin assignment = 0;
11194887Schin fcseek(-1);
11204887Schin }
11214887Schin break;
11224887Schin case S_LABEL:
11238462SApril.Chin@Sun.COM if(lp->lex.reservok && !lp->lex.incase)
11244887Schin {
11254887Schin c = fcget();
11264887Schin fcseek(-1);
11274887Schin if(state[c]==S_BREAK)
11284887Schin {
11294887Schin assignment = -1;
11304887Schin goto breakloop;
11314887Schin }
11324887Schin }
11334887Schin break;
11344887Schin case S_BRACT:
11354887Schin /* check for possible subscript */
11368462SApril.Chin@Sun.COM if((n=endchar(lp))==RBRACT || n==RPAREN ||
11374887Schin (mode==ST_BRACE) ||
11388462SApril.Chin@Sun.COM (oldmode(lp)==ST_NONE) ||
11398462SApril.Chin@Sun.COM (mode==ST_NAME && (lp->assignok||lp->lexd.level)))
11404887Schin {
114110898Sroland.mainz@nrubsig.org if(mode==ST_NAME)
114210898Sroland.mainz@nrubsig.org {
114310898Sroland.mainz@nrubsig.org fcgetc(n);
114410898Sroland.mainz@nrubsig.org if(n>0)
114510898Sroland.mainz@nrubsig.org {
114610898Sroland.mainz@nrubsig.org if(n==']')
114710898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript");
114810898Sroland.mainz@nrubsig.org fcseek(-1);
114910898Sroland.mainz@nrubsig.org }
115010898Sroland.mainz@nrubsig.org }
11518462SApril.Chin@Sun.COM pushlevel(lp,RBRACT,mode);
11524887Schin wordflags |= ARG_QUOTED;
11534887Schin mode = ST_NESTED;
11544887Schin continue;
11554887Schin }
11564887Schin wordflags |= ARG_EXP;
11574887Schin break;
11584887Schin case S_BRACE:
11594887Schin {
11604887Schin int isfirst;
11618462SApril.Chin@Sun.COM if(lp->lexd.dolparen)
11628462SApril.Chin@Sun.COM {
11638462SApril.Chin@Sun.COM if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub))
11648462SApril.Chin@Sun.COM {
11658462SApril.Chin@Sun.COM fcgetc(n);
11668462SApril.Chin@Sun.COM if(n>0)
11678462SApril.Chin@Sun.COM fcseek(-1);
11688462SApril.Chin@Sun.COM else
11698462SApril.Chin@Sun.COM n = '\n';
11708462SApril.Chin@Sun.COM if(n==RBRACT || sh_lexstates[ST_NORM][n])
11718462SApril.Chin@Sun.COM return(lp->token=c);
11728462SApril.Chin@Sun.COM }
11734887Schin break;
11748462SApril.Chin@Sun.COM }
11758462SApril.Chin@Sun.COM else if(mode==ST_BEGIN)
11768462SApril.Chin@Sun.COM {
11778462SApril.Chin@Sun.COM if(lp->comsub && c==RBRACE)
11788462SApril.Chin@Sun.COM return(lp->token=c);
11798462SApril.Chin@Sun.COM goto do_reg;
11808462SApril.Chin@Sun.COM }
11818462SApril.Chin@Sun.COM isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1);
11824887Schin fcgetc(n);
11834887Schin /* check for {} */
11844887Schin if(c==LBRACE && n==RBRACE)
11854887Schin break;
11864887Schin if(n>0)
11874887Schin fcseek(-1);
11888462SApril.Chin@Sun.COM else if(lp->lex.reservok)
11894887Schin break;
11904887Schin /* check for reserved word { or } */
11918462SApril.Chin@Sun.COM if(lp->lex.reservok && state[n]==S_BREAK && isfirst)
11924887Schin break;
11934887Schin if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
11948462SApril.Chin@Sun.COM && !lp->lex.incase && !lp->lex.intest
11958462SApril.Chin@Sun.COM && !lp->lex.skipword)
11964887Schin {
11974887Schin wordflags |= ARG_EXP;
11984887Schin }
11994887Schin if(c==RBRACE && n==LPAREN)
12004887Schin goto epat;
12014887Schin break;
12024887Schin }
12034887Schin case S_PAT:
12044887Schin wordflags |= ARG_EXP;
12054887Schin /* FALL THRU */
12064887Schin case S_EPAT:
12074887Schin epat:
12084887Schin if(fcgetc(n)==LPAREN)
12094887Schin {
12108462SApril.Chin@Sun.COM if(lp->lex.incase==TEST_RE)
12114887Schin {
12128462SApril.Chin@Sun.COM lp->lex.incase++;
12138462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,ST_NORM);
12144887Schin mode = ST_NESTED;
12154887Schin }
12164887Schin wordflags |= ARG_EXP;
12178462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,mode);
12184887Schin mode = ST_NESTED;
12194887Schin continue;
12204887Schin }
12214887Schin if(n>0)
12224887Schin fcseek(-1);
12234887Schin if(n=='=' && c=='+' && mode==ST_NAME)
12244887Schin continue;
12254887Schin break;
12264887Schin }
12278462SApril.Chin@Sun.COM lp->comp_assign = 0;
12284887Schin if(mode==ST_NAME)
12294887Schin mode = ST_NORM;
12304887Schin else if(mode==ST_NONE)
12314887Schin return(0);
12324887Schin }
12334887Schin breakloop:
12348462SApril.Chin@Sun.COM if(lp->lexd.nocopy)
12354887Schin {
12368462SApril.Chin@Sun.COM lp->lexd.balance = 0;
12378462SApril.Chin@Sun.COM return(0);
12388462SApril.Chin@Sun.COM }
12398462SApril.Chin@Sun.COM if(lp->lexd.dolparen)
12408462SApril.Chin@Sun.COM {
12418462SApril.Chin@Sun.COM lp->lexd.balance = 0;
12428462SApril.Chin@Sun.COM if(lp->lexd.docword)
12434887Schin nested_here(lp);
12448462SApril.Chin@Sun.COM lp->lexd.message = (wordflags&ARG_MESSAGE);
12458462SApril.Chin@Sun.COM return(lp->token=0);
12464887Schin }
12478462SApril.Chin@Sun.COM if(!(state=lp->lexd.first))
12484887Schin state = fcfirst();
12494887Schin n = fcseek(0)-(char*)state;
12508462SApril.Chin@Sun.COM if(!lp->arg)
12518462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
12524887Schin if(n>0)
12538462SApril.Chin@Sun.COM sfwrite(stkp,state,n);
12544887Schin /* add balancing character if necessary */
12558462SApril.Chin@Sun.COM if(lp->lexd.balance)
12564887Schin {
12578462SApril.Chin@Sun.COM sfputc(stkp,lp->lexd.balance);
12588462SApril.Chin@Sun.COM lp->lexd.balance = 0;
12594887Schin }
12608462SApril.Chin@Sun.COM sfputc(stkp,0);
12618462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1);
12628462SApril.Chin@Sun.COM state = stkptr(stkp,ARGVAL);
12638462SApril.Chin@Sun.COM n = stktell(stkp)-ARGVAL;
12648462SApril.Chin@Sun.COM lp->lexd.first=0;
12654887Schin if(n==1)
12664887Schin {
12674887Schin /* check for numbered redirection */
12684887Schin n = state[0];
12694887Schin if((c=='<' || c=='>') && isadigit(n))
12704887Schin {
12718462SApril.Chin@Sun.COM c = sh_lex(lp);
12728462SApril.Chin@Sun.COM lp->digits = (n-'0');
12734887Schin return(c);
12744887Schin }
12754887Schin if(n==LBRACT)
12764887Schin c = 0;
12778462SApril.Chin@Sun.COM else if(n==RBRACE && lp->comsub)
12788462SApril.Chin@Sun.COM return(lp->token=n);
12794887Schin else if(n=='~')
12804887Schin c = ARG_MAC;
12814887Schin else
12824887Schin c = (wordflags&ARG_EXP);
12834887Schin n = 1;
12844887Schin }
12858462SApril.Chin@Sun.COM else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
12864887Schin {
12874887Schin if(!strchr(state,','))
12884887Schin {
12898462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1);
12908462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1);
12918462SApril.Chin@Sun.COM return(lp->token=IOVNAME);
12924887Schin }
12934887Schin c = wordflags;
12944887Schin }
12954887Schin else
12964887Schin c = wordflags;
12974887Schin if(assignment<0)
12984887Schin {
12998462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1);
13008462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1);
13018462SApril.Chin@Sun.COM lp->lex.reservok = 1;
13028462SApril.Chin@Sun.COM return(lp->token=LABLSYM);
13034887Schin }
13048462SApril.Chin@Sun.COM if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE)
13054887Schin c &= ~ARG_EXP;
13064887Schin if((c&ARG_EXP) && (c&ARG_QUOTED))
13074887Schin c |= ARG_MAC;
13084887Schin if(mode==ST_NONE)
13094887Schin {
13104887Schin /* eliminate trailing )) */
13118462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-2);
13124887Schin }
13134887Schin if(c&ARG_MESSAGE)
13144887Schin {
13154887Schin if(sh_isoption(SH_DICTIONARY))
13168462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,2);
13174887Schin if(!sh_isoption(SH_NOEXEC))
13184887Schin {
13198462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,1);
13204887Schin c &= ~ARG_MESSAGE;
13214887Schin }
13224887Schin }
13238462SApril.Chin@Sun.COM if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lp->lexd.warn && !lp->lexd.docword))
13244887Schin {
13258462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1);
13268462SApril.Chin@Sun.COM lp->arg->argflag = (c?c:ARG_RAW);
13274887Schin }
13284887Schin else if(mode==ST_NONE)
13298462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,-1);
13304887Schin else
13318462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,0);
13328462SApril.Chin@Sun.COM state = lp->arg->argval;
13338462SApril.Chin@Sun.COM lp->comp_assign = assignment;
13344887Schin if(assignment)
13358462SApril.Chin@Sun.COM lp->arg->argflag |= ARG_ASSIGN;
13368462SApril.Chin@Sun.COM else if(!lp->lex.skipword)
13378462SApril.Chin@Sun.COM lp->assignok = 0;
13388462SApril.Chin@Sun.COM lp->arg->argchn.cp = 0;
13398462SApril.Chin@Sun.COM lp->arg->argnxt.ap = 0;
13404887Schin if(mode==ST_NONE)
13418462SApril.Chin@Sun.COM return(lp->token=EXPRSYM);
13428462SApril.Chin@Sun.COM if(lp->lex.intest)
13434887Schin {
13448462SApril.Chin@Sun.COM if(lp->lex.testop1)
13454887Schin {
13468462SApril.Chin@Sun.COM lp->lex.testop1 = 0;
13474887Schin if(n==2 && state[0]=='-' && state[2]==0 &&
13484887Schin strchr(test_opchars,state[1]))
13494887Schin {
13508462SApril.Chin@Sun.COM if(lp->lexd.warn && state[1]=='a')
13514887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
13528462SApril.Chin@Sun.COM lp->digits = state[1];
13538462SApril.Chin@Sun.COM lp->token = TESTUNOP;
13544887Schin }
13554887Schin else if(n==1 && state[0]=='!' && state[1]==0)
13564887Schin {
13578462SApril.Chin@Sun.COM lp->lex.testop1 = 1;
13588462SApril.Chin@Sun.COM lp->token = '!';
13594887Schin }
13604887Schin else
13614887Schin {
13628462SApril.Chin@Sun.COM lp->lex.testop2 = 1;
13638462SApril.Chin@Sun.COM lp->token = 0;
13644887Schin }
13658462SApril.Chin@Sun.COM return(lp->token);
13664887Schin }
13678462SApril.Chin@Sun.COM lp->lex.incase = 0;
13684887Schin c = sh_lookup(state,shtab_testops);
13694887Schin switch(c)
13704887Schin {
13714887Schin case TEST_END:
13728462SApril.Chin@Sun.COM lp->lex.testop2 = lp->lex.intest = 0;
13738462SApril.Chin@Sun.COM lp->lex.reservok = 1;
13748462SApril.Chin@Sun.COM lp->token = ETESTSYM;
13758462SApril.Chin@Sun.COM return(lp->token);
13764887Schin
13774887Schin case TEST_SEQ:
13788462SApril.Chin@Sun.COM if(lp->lexd.warn && state[1]==0)
13794887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
13804887Schin /* FALL THRU */
13814887Schin default:
13828462SApril.Chin@Sun.COM if(lp->lex.testop2)
13834887Schin {
13848462SApril.Chin@Sun.COM if(lp->lexd.warn && (c&TEST_ARITH))
13854887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
13864887Schin if(c&TEST_PATTERN)
13878462SApril.Chin@Sun.COM lp->lex.incase = 1;
13884887Schin else if(c==TEST_REP)
13898462SApril.Chin@Sun.COM lp->lex.incase = TEST_RE;
13908462SApril.Chin@Sun.COM lp->lex.testop2 = 0;
13918462SApril.Chin@Sun.COM lp->digits = c;
13928462SApril.Chin@Sun.COM lp->token = TESTBINOP;
13938462SApril.Chin@Sun.COM return(lp->token);
13944887Schin }
13954887Schin
13964887Schin case TEST_OR: case TEST_AND:
13974887Schin case 0:
13988462SApril.Chin@Sun.COM return(lp->token=0);
13994887Schin }
14004887Schin }
14018462SApril.Chin@Sun.COM if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2)
14024887Schin {
14034887Schin /* check for {, }, ! */
14044887Schin c = state[0];
14054887Schin if(n==1 && (c=='{' || c=='}' || c=='!'))
14064887Schin {
14078462SApril.Chin@Sun.COM if(lp->lexd.warn && c=='{' && lp->lex.incase==2)
14084887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
14098462SApril.Chin@Sun.COM if(lp->lex.incase==1 && c==RBRACE)
14108462SApril.Chin@Sun.COM lp->lex.incase = 0;
14118462SApril.Chin@Sun.COM return(lp->token=c);
14124887Schin }
14138462SApril.Chin@Sun.COM else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT)
14144887Schin {
14158462SApril.Chin@Sun.COM lp->lex.intest = lp->lex.testop1 = 1;
14168462SApril.Chin@Sun.COM lp->lex.testop2 = lp->lex.reservok = 0;
14178462SApril.Chin@Sun.COM return(lp->token=BTESTSYM);
14184887Schin }
14194887Schin }
14204887Schin c = 0;
14218462SApril.Chin@Sun.COM if(!lp->lex.skipword)
14224887Schin {
14238462SApril.Chin@Sun.COM if(n>1 && lp->lex.reservok==1 && mode==ST_NAME &&
14244887Schin (c=sh_lookup(state,shtab_reserved)))
14254887Schin {
14268462SApril.Chin@Sun.COM if(lp->lex.incase)
14274887Schin {
14288462SApril.Chin@Sun.COM if(lp->lex.incase >1)
14298462SApril.Chin@Sun.COM lp->lex.incase = 1;
14304887Schin else if(c==ESACSYM)
14318462SApril.Chin@Sun.COM lp->lex.incase = 0;
14324887Schin else
14334887Schin c = 0;
14344887Schin }
14354887Schin else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
14364887Schin {
14378462SApril.Chin@Sun.COM lp->lex.skipword = 1;
14388462SApril.Chin@Sun.COM lp->lex.incase = 2*(c==CASESYM);
14394887Schin }
14404887Schin else
14418462SApril.Chin@Sun.COM lp->lex.skipword = 0;
14424887Schin if(c==INSYM)
14438462SApril.Chin@Sun.COM lp->lex.reservok = 0;
14444887Schin else if(c==TIMESYM)
14454887Schin {
14464887Schin /* yech - POSIX requires time -p */
14474887Schin while(fcgetc(n)==' ' || n=='\t');
14484887Schin if(n>0)
14494887Schin fcseek(-1);
14504887Schin if(n=='-')
14514887Schin c=0;
14524887Schin }
14538462SApril.Chin@Sun.COM return(lp->token=c);
14544887Schin }
14558462SApril.Chin@Sun.COM if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok))
14564887Schin {
14574887Schin /* check for aliases */
14584887Schin Namval_t* np;
14598462SApril.Chin@Sun.COM if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN &&
14604887Schin (np=nv_search(state,shp->alias_tree,HASH_SCOPE))
14614887Schin && !nv_isattr(np,NV_NOEXPAND)
14624887Schin #if KSHELL
14634887Schin && (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
14644887Schin #endif /* KSHELL */
14654887Schin && (state=nv_getval(np)))
14664887Schin {
14674887Schin setupalias(lp,state,np);
14684887Schin nv_onattr(np,NV_NOEXPAND);
14698462SApril.Chin@Sun.COM lp->lex.reservok = 1;
14708462SApril.Chin@Sun.COM lp->assignok |= lp->lex.reservok;
14718462SApril.Chin@Sun.COM return(sh_lex(lp));
14724887Schin }
14734887Schin }
14748462SApril.Chin@Sun.COM lp->lex.reservok = 0;
14754887Schin }
14768462SApril.Chin@Sun.COM lp->lex.skipword = lp->lexd.docword = 0;
14778462SApril.Chin@Sun.COM return(lp->token=c);
14784887Schin }
14794887Schin
14804887Schin /*
14814887Schin * read to end of command substitution
14824887Schin */
comsub(register Lex_t * lp,int endtok)14838462SApril.Chin@Sun.COM static int comsub(register Lex_t *lp, int endtok)
14844887Schin {
14854887Schin register int n,c,count=1;
14868462SApril.Chin@Sun.COM register int line=lp->sh->inlineno;
14874887Schin char word[5];
1488*12068SRoger.Faulkner@Oracle.COM int off, messages=0, assignok=lp->assignok, csub;
14894887Schin struct lexstate save;
14908462SApril.Chin@Sun.COM save = lp->lex;
14918462SApril.Chin@Sun.COM csub = lp->comsub;
14928462SApril.Chin@Sun.COM sh_lexopen(lp,lp->sh,1);
14938462SApril.Chin@Sun.COM lp->lexd.dolparen++;
14948462SApril.Chin@Sun.COM lp->lex.incase=0;
14958462SApril.Chin@Sun.COM pushlevel(lp,0,0);
14968462SApril.Chin@Sun.COM lp->comsub = (endtok==LBRACE);
1497*12068SRoger.Faulkner@Oracle.COM off = fcseek(0) - lp->lexd.first;
14988462SApril.Chin@Sun.COM if(sh_lex(lp)==endtok)
14994887Schin {
1500*12068SRoger.Faulkner@Oracle.COM if(endtok==LPAREN && fcseek(0)==lp->lexd.first)
1501*12068SRoger.Faulkner@Oracle.COM {
1502*12068SRoger.Faulkner@Oracle.COM count++;
1503*12068SRoger.Faulkner@Oracle.COM lp->lexd.paren = 0;
1504*12068SRoger.Faulkner@Oracle.COM fcseek(off+2);
1505*12068SRoger.Faulkner@Oracle.COM }
15064887Schin while(1)
15074887Schin {
15084887Schin /* look for case and esac */
15094887Schin n=0;
15104887Schin while(1)
15114887Schin {
15124887Schin fcgetc(c);
15134887Schin /* skip leading white space */
15144887Schin if(n==0 && !sh_lexstates[ST_BEGIN][c])
15154887Schin continue;
15164887Schin if(n==4)
15174887Schin break;
15184887Schin if(sh_lexstates[ST_NAME][c])
15194887Schin goto skip;
15204887Schin word[n++] = c;
15214887Schin }
15224887Schin if(sh_lexstates[ST_NAME][c]==S_BREAK)
15234887Schin {
15244887Schin if(memcmp(word,"case",4)==0)
15258462SApril.Chin@Sun.COM lp->lex.incase=1;
15264887Schin else if(memcmp(word,"esac",4)==0)
15278462SApril.Chin@Sun.COM lp->lex.incase=0;
15284887Schin }
15294887Schin skip:
15304887Schin if(c && (c!='#' || n==0))
15314887Schin fcseek(-1);
15328462SApril.Chin@Sun.COM if(c==RBRACE && lp->lex.incase)
15338462SApril.Chin@Sun.COM lp->lex.incase=0;
15348462SApril.Chin@Sun.COM switch(c=sh_lex(lp))
15354887Schin {
15368462SApril.Chin@Sun.COM case LBRACE:
15378462SApril.Chin@Sun.COM if(endtok==LBRACE && !lp->lex.incase)
15388462SApril.Chin@Sun.COM {
15398462SApril.Chin@Sun.COM lp->comsub = 0;
15408462SApril.Chin@Sun.COM count++;
15418462SApril.Chin@Sun.COM }
15428462SApril.Chin@Sun.COM break;
15438462SApril.Chin@Sun.COM case RBRACE:
15448462SApril.Chin@Sun.COM rbrace:
15458462SApril.Chin@Sun.COM if(endtok==LBRACE && --count<=0)
15468462SApril.Chin@Sun.COM goto done;
15478462SApril.Chin@Sun.COM lp->comsub = (count==1);
15488462SApril.Chin@Sun.COM break;
15498462SApril.Chin@Sun.COM case IPROCSYM: case OPROCSYM:
15508462SApril.Chin@Sun.COM case LPAREN:
15518462SApril.Chin@Sun.COM if(endtok==LPAREN && !lp->lex.incase)
15524887Schin count++;
15534887Schin break;
15544887Schin case RPAREN:
15558462SApril.Chin@Sun.COM if(lp->lex.incase)
15568462SApril.Chin@Sun.COM lp->lex.incase=0;
15578462SApril.Chin@Sun.COM else if(endtok==LPAREN && --count<=0)
15584887Schin goto done;
15594887Schin break;
15604887Schin case EOFSYM:
15618462SApril.Chin@Sun.COM lp->lastline = line;
15628462SApril.Chin@Sun.COM lp->lasttok = endtok;
15638462SApril.Chin@Sun.COM sh_syntax(lp);
15644887Schin case IOSEEKSYM:
15654887Schin if(fcgetc(c)!='#' && c>0)
15664887Schin fcseek(-1);
15674887Schin break;
15684887Schin case IODOCSYM:
156910898Sroland.mainz@nrubsig.org lp->lexd.docextra = 0;
15708462SApril.Chin@Sun.COM sh_lex(lp);
15714887Schin break;
15724887Schin case 0:
15738462SApril.Chin@Sun.COM lp->lex.reservok = 0;
15748462SApril.Chin@Sun.COM messages |= lp->lexd.message;
15758462SApril.Chin@Sun.COM break;
15768462SApril.Chin@Sun.COM case ';':
15778462SApril.Chin@Sun.COM fcgetc(c);
15788462SApril.Chin@Sun.COM if(c==RBRACE && endtok==LBRACE)
15798462SApril.Chin@Sun.COM goto rbrace;
15808462SApril.Chin@Sun.COM if(c>0)
15818462SApril.Chin@Sun.COM fcseek(-1);
15828462SApril.Chin@Sun.COM /* fall through*/
15838462SApril.Chin@Sun.COM default:
15848462SApril.Chin@Sun.COM lp->lex.reservok = 1;
15854887Schin }
15864887Schin }
15874887Schin }
15884887Schin done:
15898462SApril.Chin@Sun.COM poplevel(lp);
15908462SApril.Chin@Sun.COM lp->comsub = csub;
15918462SApril.Chin@Sun.COM lp->lastline = line;
15928462SApril.Chin@Sun.COM lp->lexd.dolparen--;
15938462SApril.Chin@Sun.COM lp->lex = save;
15948462SApril.Chin@Sun.COM lp->assignok = (endchar(lp)==RBRACT?assignok:0);
15954887Schin return(messages);
15964887Schin }
15974887Schin
15984887Schin /*
15994887Schin * here-doc nested in $(...)
16004887Schin * allocate ionode with delimiter filled in without disturbing stak
16014887Schin */
nested_here(register Lex_t * lp)16024887Schin static void nested_here(register Lex_t *lp)
16034887Schin {
16048462SApril.Chin@Sun.COM register struct ionod *iop;
16058462SApril.Chin@Sun.COM register int n,offset;
16068462SApril.Chin@Sun.COM struct argnod *arg = lp->arg;
16078462SApril.Chin@Sun.COM Stk_t *stkp = lp->sh->stk;
16088462SApril.Chin@Sun.COM char *base;
16098462SApril.Chin@Sun.COM if(offset=stktell(stkp))
16108462SApril.Chin@Sun.COM base = stkfreeze(stkp,0);
16118462SApril.Chin@Sun.COM n = fcseek(0)-lp->lexd.docend;
161210898Sroland.mainz@nrubsig.org iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL);
16138462SApril.Chin@Sun.COM iop->iolst = lp->heredoc;
16148462SApril.Chin@Sun.COM stkseek(stkp,ARGVAL);
161510898Sroland.mainz@nrubsig.org if(lp->lexd.docextra)
161610898Sroland.mainz@nrubsig.org {
161710898Sroland.mainz@nrubsig.org sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
161810898Sroland.mainz@nrubsig.org sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1);
161910898Sroland.mainz@nrubsig.org }
16208462SApril.Chin@Sun.COM sfwrite(stkp,lp->lexd.docend,n);
16218462SApril.Chin@Sun.COM lp->arg = sh_endword(lp->sh,0);
16224887Schin iop->ioname = (char*)(iop+1);
16238462SApril.Chin@Sun.COM strcpy(iop->ioname,lp->arg->argval);
16244887Schin iop->iofile = (IODOC|IORAW);
16258462SApril.Chin@Sun.COM if(lp->lexd.docword>1)
16264887Schin iop->iofile |= IOSTRIP;
16278462SApril.Chin@Sun.COM lp->heredoc = iop;
16288462SApril.Chin@Sun.COM lp->arg = arg;
16298462SApril.Chin@Sun.COM lp->lexd.docword = 0;
16304887Schin if(offset)
16318462SApril.Chin@Sun.COM stkset(stkp,base,offset);
16324887Schin else
16338462SApril.Chin@Sun.COM stkseek(stkp,0);
16344887Schin }
16354887Schin
16364887Schin /*
16374887Schin * skip to <close> character
16384887Schin * if <copy> is non,zero, then the characters are copied to the stack
16394887Schin * <state> is the initial lexical state
16404887Schin */
sh_lexskip(Lex_t * lp,int close,register int copy,int state)16418462SApril.Chin@Sun.COM void sh_lexskip(Lex_t *lp,int close, register int copy, int state)
16424887Schin {
16434887Schin register char *cp;
16448462SApril.Chin@Sun.COM lp->lexd.nest = close;
16458462SApril.Chin@Sun.COM lp->lexd.lex_state = state;
16468462SApril.Chin@Sun.COM lp->lexd.noarg = 1;
16474887Schin if(copy)
16488462SApril.Chin@Sun.COM fcnotify(lex_advance,lp);
16494887Schin else
16508462SApril.Chin@Sun.COM lp->lexd.nocopy++;
16518462SApril.Chin@Sun.COM sh_lex(lp);
16528462SApril.Chin@Sun.COM lp->lexd.noarg = 0;
16534887Schin if(copy)
16544887Schin {
16558462SApril.Chin@Sun.COM fcnotify(0,lp);
16568462SApril.Chin@Sun.COM if(!(cp=lp->lexd.first))
16574887Schin cp = fcfirst();
16584887Schin if((copy = fcseek(0)-cp) > 0)
16598462SApril.Chin@Sun.COM sfwrite(lp->sh->stk,cp,copy);
16604887Schin }
16614887Schin else
16628462SApril.Chin@Sun.COM lp->lexd.nocopy--;
16634887Schin }
16644887Schin
16654887Schin #if SHOPT_CRNL
_sfwrite(Sfio_t * sp,const Void_t * buff,size_t n)16664887Schin ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
16674887Schin {
16684887Schin const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
16694887Schin int m=0,k;
16704887Schin while(next = (const char*)memchr(next,'\r',ep-next))
16714887Schin if(*++next=='\n')
16724887Schin {
16734887Schin if(k=next-cp-1)
16744887Schin {
16754887Schin if((k=sfwrite(sp,cp,k)) < 0)
16764887Schin return(m>0?m:-1);
16774887Schin m += k;
16784887Schin }
16794887Schin cp = next;
16804887Schin }
16814887Schin if((k=sfwrite(sp,cp,ep-cp)) < 0)
16824887Schin return(m>0?m:-1);
16834887Schin return(m+k);
16844887Schin }
16854887Schin # define sfwrite _sfwrite
16864887Schin #endif /* SHOPT_CRNL */
16874887Schin
16884887Schin /*
16894887Schin * read in here-document from script
16904887Schin * quoted here documents, and here-documents without special chars are
16914887Schin * noted with the IOQUOTE flag
16924887Schin * returns 1 for complete here-doc, 0 for EOF
16934887Schin */
16944887Schin
here_copy(Lex_t * lp,register struct ionod * iop)16954887Schin static int here_copy(Lex_t *lp,register struct ionod *iop)
16964887Schin {
16974887Schin register const char *state;
16984887Schin register int c,n;
16994887Schin register char *bufp,*cp;
17008462SApril.Chin@Sun.COM register Sfio_t *sp=lp->sh->heredocs, *funlog;
17014887Schin int stripcol=0,stripflg, nsave, special=0;
17028462SApril.Chin@Sun.COM if(funlog=lp->sh->funlog)
17034887Schin {
17044887Schin if(fcfill()>0)
17054887Schin fcseek(-1);
17068462SApril.Chin@Sun.COM lp->sh->funlog = 0;
17074887Schin }
17084887Schin if(iop->iolst)
17094887Schin here_copy(lp,iop->iolst);
17104887Schin iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
17114887Schin iop->iosize = 0;
17124887Schin iop->iodelim=iop->ioname;
17134887Schin /* check for and strip quoted characters in delimiter string */
17144887Schin if(stripflg=iop->iofile&IOSTRIP)
17154887Schin {
17164887Schin while(*iop->iodelim=='\t')
17174887Schin iop->iodelim++;
17184887Schin /* skip over leading tabs in document */
17194887Schin if(iop->iofile&IOLSEEK)
17204887Schin {
17214887Schin iop->iofile &= ~IOLSEEK;
17224887Schin while(fcgetc(c)=='\t' || c==' ')
17234887Schin {
17244887Schin if(c==' ')
17254887Schin stripcol++;
17264887Schin else
17274887Schin stripcol += 8 - stripcol%8;
17284887Schin }
17294887Schin }
17304887Schin else
17314887Schin while(fcgetc(c)=='\t');
17324887Schin if(c>0)
17334887Schin fcseek(-1);
17344887Schin }
17354887Schin if(iop->iofile&IOQUOTE)
17364887Schin state = sh_lexstates[ST_LIT];
17374887Schin else
17384887Schin state = sh_lexstates[ST_QUOTE];
17394887Schin bufp = fcseek(0);
17404887Schin n = S_NL;
17414887Schin while(1)
17424887Schin {
17434887Schin if(n!=S_NL)
17444887Schin {
17454887Schin /* skip over regular characters */
17464887Schin while((n=STATE(state,c))==0);
17474887Schin }
17484887Schin if(n==S_EOF || !(c=fcget()))
17494887Schin {
17508462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp))
17514887Schin {
17524887Schin if(n==S_ESC)
17534887Schin c--;
17544887Schin if((c=sfwrite(sp,bufp,c))>0)
17554887Schin iop->iosize += c;
17564887Schin }
17578462SApril.Chin@Sun.COM if((c=lexfill(lp))<=0)
17584887Schin break;
17594887Schin if(n==S_ESC)
17604887Schin {
17614887Schin #if SHOPT_CRNL
17624887Schin if(c=='\r' && (c=fcget())!=NL)
17634887Schin fcseek(-1);
17644887Schin #endif /* SHOPT_CRNL */
17654887Schin if(c==NL)
17664887Schin fcseek(1);
17674887Schin else
17684887Schin sfputc(sp,'\\');
17694887Schin }
17704887Schin bufp = fcseek(-1);
17714887Schin }
17724887Schin else
17734887Schin fcseek(-1);
17744887Schin switch(n)
17754887Schin {
17764887Schin case S_NL:
17778462SApril.Chin@Sun.COM lp->sh->inlineno++;
17784887Schin if((stripcol && c==' ') || (stripflg && c=='\t'))
17794887Schin {
17808462SApril.Chin@Sun.COM if(!lp->lexd.dolparen)
17814887Schin {
17824887Schin /* write out line */
17834887Schin n = fcseek(0)-bufp;
17844887Schin if((n=sfwrite(sp,bufp,n))>0)
17854887Schin iop->iosize += n;
17864887Schin }
17874887Schin /* skip over tabs */
17884887Schin if(stripcol)
17894887Schin {
17904887Schin int col=0;
17914887Schin do
17924887Schin {
17934887Schin fcgetc(c);
17944887Schin if(c==' ')
17954887Schin col++;
17964887Schin else
17974887Schin col += 8 - col%8;
17984887Schin if(col>stripcol)
17994887Schin break;
18004887Schin }
18014887Schin while (c==' ' || c=='\t');
18024887Schin }
18034887Schin else while(c=='\t')
18044887Schin fcgetc(c);
18054887Schin if(c<=0)
18064887Schin goto done;
18074887Schin bufp = fcseek(-1);
18084887Schin }
18094887Schin if(c!=iop->iodelim[0])
18104887Schin break;
18114887Schin cp = fcseek(0);
18124887Schin nsave = n = 0;
18134887Schin while(1)
18144887Schin {
18154887Schin if(!(c=fcget()))
18164887Schin {
18178462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (c=cp-bufp))
18184887Schin {
18194887Schin if((c=sfwrite(sp,cp=bufp,c))>0)
18204887Schin iop->iosize+=c;
18214887Schin }
18224887Schin nsave = n;
18238462SApril.Chin@Sun.COM if((c=lexfill(lp))<=0)
18244887Schin {
18254887Schin c = iop->iodelim[n]==0;
18264887Schin goto done;
18274887Schin }
18284887Schin }
18294887Schin #if SHOPT_CRNL
18304887Schin if(c=='\r' && (c=fcget())!=NL)
18314887Schin {
18324887Schin if(c)
18334887Schin fcseek(-1);
18344887Schin c='\r';
18354887Schin }
18364887Schin #endif /* SHOPT_CRNL */
18374887Schin if(c==NL)
18388462SApril.Chin@Sun.COM lp->sh->inlineno++;
18394887Schin if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
18404887Schin {
18418462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (n=cp-bufp))
18424887Schin {
18434887Schin if((n=sfwrite(sp,bufp,n))>0)
18444887Schin iop->iosize += n;
18454887Schin }
18468462SApril.Chin@Sun.COM lp->sh->inlineno--;
18474887Schin if(c==RPAREN)
18484887Schin fcseek(-1);
18494887Schin goto done;
18504887Schin }
18514887Schin if(iop->iodelim[n++]!=c)
18524887Schin {
18534887Schin /*
18544887Schin * The match for delimiter failed.
18554887Schin * nsave>0 only when a buffer boundary
18564887Schin * was crossed while checking the
18574887Schin * delimiter
18584887Schin */
18598462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && nsave>0)
18604887Schin {
18614887Schin if((n=sfwrite(sp,bufp,nsave))>0)
18624887Schin iop->iosize += n;
18634887Schin bufp = fcfirst();
18644887Schin }
18654887Schin if(c==NL)
18664887Schin fcseek(-1);
18674887Schin break;
18684887Schin }
18694887Schin }
18704887Schin break;
18714887Schin case S_ESC:
18724887Schin n=1;
18734887Schin #if SHOPT_CRNL
18744887Schin if(c=='\r')
18754887Schin {
18764887Schin fcseek(1);
18774887Schin if(c=fcget())
18784887Schin fcseek(-1);
18794887Schin if(c==NL)
18804887Schin n=2;
18814887Schin else
18824887Schin {
18834887Schin special++;
18844887Schin break;
18854887Schin }
18864887Schin }
18874887Schin #endif /* SHOPT_CRNL */
18884887Schin if(c==NL)
18894887Schin {
18904887Schin /* new-line joining */
18918462SApril.Chin@Sun.COM lp->sh->inlineno++;
189210898Sroland.mainz@nrubsig.org if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0)
18934887Schin {
189410898Sroland.mainz@nrubsig.org if(n && (n=sfwrite(sp,bufp,n))>0)
18954887Schin iop->iosize += n;
18964887Schin bufp = fcseek(0)+1;
18974887Schin }
18984887Schin }
18994887Schin else
19004887Schin special++;
19014887Schin fcget();
19024887Schin break;
19034887Schin
19044887Schin case S_GRAVE:
19054887Schin case S_DOL:
19064887Schin special++;
19074887Schin break;
19084887Schin }
19094887Schin n=0;
19104887Schin }
19114887Schin done:
19128462SApril.Chin@Sun.COM lp->sh->funlog = funlog;
19138462SApril.Chin@Sun.COM if(lp->lexd.dolparen)
19144887Schin free((void*)iop);
19154887Schin else if(!special)
19164887Schin iop->iofile |= IOQUOTE;
19174887Schin return(c);
19184887Schin }
19194887Schin
19204887Schin /*
19214887Schin * generates string for given token
19224887Schin */
fmttoken(Lex_t * lp,register int sym,char * tok)19234887Schin static char *fmttoken(Lex_t *lp, register int sym, char *tok)
19244887Schin {
192510898Sroland.mainz@nrubsig.org int n=1;
19264887Schin if(sym < 0)
19274887Schin return((char*)sh_translate(e_lexzerobyte));
19284887Schin if(sym==0)
19298462SApril.Chin@Sun.COM return(lp->arg?lp->arg->argval:"?");
19308462SApril.Chin@Sun.COM if(lp->lex.intest && lp->arg && *lp->arg->argval)
19318462SApril.Chin@Sun.COM return(lp->arg->argval);
19324887Schin if(sym&SYMRES)
19334887Schin {
19344887Schin register const Shtable_t *tp=shtab_reserved;
19354887Schin while(tp->sh_number && tp->sh_number!=sym)
19364887Schin tp++;
19374887Schin return((char*)tp->sh_name);
19384887Schin }
19394887Schin if(sym==EOFSYM)
19404887Schin return((char*)sh_translate(e_endoffile));
19414887Schin if(sym==NL)
19424887Schin return((char*)sh_translate(e_newline));
19434887Schin tok[0] = sym;
19444887Schin if(sym&SYMREP)
194510898Sroland.mainz@nrubsig.org tok[n++] = sym;
19464887Schin else
19474887Schin {
19484887Schin switch(sym&SYMMASK)
19494887Schin {
19504887Schin case SYMAMP:
19514887Schin sym = '&';
19524887Schin break;
19534887Schin case SYMPIPE:
19544887Schin sym = '|';
19554887Schin break;
19564887Schin case SYMGT:
19574887Schin sym = '>';
19584887Schin break;
19594887Schin case SYMLPAR:
19604887Schin sym = LPAREN;
19614887Schin break;
19624887Schin case SYMSHARP:
19634887Schin sym = '#';
19644887Schin break;
19658462SApril.Chin@Sun.COM case SYMSEMI:
196610898Sroland.mainz@nrubsig.org if(tok[0]=='<')
196710898Sroland.mainz@nrubsig.org tok[n++] = '>';
19688462SApril.Chin@Sun.COM sym = ';';
19698462SApril.Chin@Sun.COM break;
19704887Schin default:
19714887Schin sym = 0;
19724887Schin }
197310898Sroland.mainz@nrubsig.org tok[n++] = sym;
19744887Schin }
197510898Sroland.mainz@nrubsig.org tok[n] = 0;
19764887Schin return(tok);
19774887Schin }
19784887Schin
19794887Schin /*
19804887Schin * print a bad syntax message
19814887Schin */
19824887Schin
sh_syntax(Lex_t * lp)19838462SApril.Chin@Sun.COM void sh_syntax(Lex_t *lp)
19844887Schin {
19858462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh;
19864887Schin register const char *cp = sh_translate(e_unexpected);
19874887Schin register char *tokstr;
19888462SApril.Chin@Sun.COM register int tok = lp->token;
19894887Schin char tokbuf[3];
19904887Schin Sfio_t *sp;
19918462SApril.Chin@Sun.COM if((tok==EOFSYM) && lp->lasttok)
19924887Schin {
19938462SApril.Chin@Sun.COM tok = lp->lasttok;
19944887Schin cp = sh_translate(e_unmatched);
19954887Schin }
19964887Schin else
19978462SApril.Chin@Sun.COM lp->lastline = shp->inlineno;
19984887Schin tokstr = fmttoken(lp,tok,tokbuf);
19994887Schin if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
20004887Schin {
20014887Schin /* clear out any pending input */
20024887Schin register Sfio_t *top;
20034887Schin while(fcget()>0);
20044887Schin fcclose();
20054887Schin while(top=sfstack(sp,SF_POPSTACK))
20064887Schin sfclose(top);
20074887Schin }
20084887Schin else
20094887Schin fcclose();
20108462SApril.Chin@Sun.COM shp->inlineno = lp->inlineno;
20118462SApril.Chin@Sun.COM shp->st.firstline = lp->firstline;
20124887Schin #if KSHELL
20134887Schin if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
20144887Schin #else
20154887Schin if(shp->inlineno!=1)
20164887Schin #endif
20178462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
20184887Schin else
20194887Schin errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
20204887Schin }
20214887Schin
stack_shift(Stk_t * stkp,register char * sp,char * dp)20228462SApril.Chin@Sun.COM static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
20234887Schin {
20244887Schin register char *ep;
20258462SApril.Chin@Sun.COM register int offset = stktell(stkp);
20268462SApril.Chin@Sun.COM register int left = offset-(sp-stkptr(stkp,0));
20274887Schin register int shift = (dp+1-sp);
20284887Schin offset += shift;
20298462SApril.Chin@Sun.COM stkseek(stkp,offset);
20308462SApril.Chin@Sun.COM sp = stkptr(stkp,offset);
20314887Schin ep = sp - shift;
20324887Schin while(left--)
20334887Schin *--sp = *--ep;
20344887Schin return(sp);
20354887Schin }
20364887Schin
20374887Schin /*
20384887Schin * Assumes that current word is unfrozen on top of the stak
20394887Schin * If <mode> is zero, gets rid of quoting and consider argument as string
20404887Schin * and returns pointer to frozen arg
20414887Schin * If mode==1, just replace $"..." strings with international strings
20424887Schin * The result is left on the stak
20434887Schin * If mode==2, the each $"" string is printed on standard output
20444887Schin */
sh_endword(Shell_t * shp,int mode)20458462SApril.Chin@Sun.COM struct argnod *sh_endword(Shell_t *shp,int mode)
20464887Schin {
20474887Schin register const char *state = sh_lexstates[ST_NESTED];
20484887Schin register int n;
20494887Schin register char *sp,*dp;
20504887Schin register int inquote=0, inlit=0; /* set within quoted strings */
20514887Schin struct argnod* argp=0;
20524887Schin char *ep=0, *xp=0;
20534887Schin int bracket=0;
20548462SApril.Chin@Sun.COM Stk_t *stkp=shp->stk;
20558462SApril.Chin@Sun.COM sfputc(stkp,0);
20568462SApril.Chin@Sun.COM sp = stkptr(stkp,ARGVAL);
20574887Schin #if SHOPT_MULTIBYTE
20584887Schin if(mbwide())
20594887Schin {
20604887Schin do
20614887Schin {
20624887Schin int len;
20634887Schin switch(len = mbsize(sp))
20644887Schin {
20654887Schin case -1: /* illegal multi-byte char */
20664887Schin case 0:
20674887Schin case 1:
20684887Schin n=state[*sp++];
20694887Schin break;
20704887Schin default:
20714887Schin /*
20724887Schin * None of the state tables contain
20734887Schin * entries for multibyte characters,
20744887Schin * however, they should be treated
20754887Schin * the same as any other alph
20764887Schin * character. Therefore, we'll use
20774887Schin * the state of the 'a' character.
20784887Schin */
20794887Schin n=state['a'];
20804887Schin sp += len;
20814887Schin }
20824887Schin }
20834887Schin while(n == 0);
20844887Schin }
20854887Schin else
20864887Schin #endif /* SHOPT_MULTIBYTE */
20874887Schin while((n=state[*sp++])==0);
20884887Schin dp = sp;
20894887Schin if(mode<0)
20904887Schin inquote = 1;
20914887Schin while(1)
20924887Schin {
20934887Schin switch(n)
20944887Schin {
20954887Schin case S_EOF:
20968462SApril.Chin@Sun.COM stkseek(stkp,dp-stkptr(stkp,0));
20974887Schin if(mode<=0)
20984887Schin {
20998462SApril.Chin@Sun.COM argp = (struct argnod*)stkfreeze(stkp,0);
21004887Schin argp->argflag = ARG_RAW|ARG_QUOTED;
21014887Schin }
21024887Schin return(argp);
21034887Schin case S_LIT:
21044887Schin if(!(inquote&1))
21054887Schin {
21064887Schin inlit = !inlit;
21074887Schin if(mode==0 || (mode<0 && bracket))
21084887Schin {
21094887Schin dp--;
21104887Schin if(ep)
21114887Schin {
21124887Schin *dp = 0;
21134887Schin dp = ep+stresc(ep);
21144887Schin }
21154887Schin ep = 0;
21164887Schin }
21174887Schin }
21184887Schin break;
21194887Schin case S_QUOTE:
21204887Schin if(mode<0 && !bracket)
21214887Schin break;
21224887Schin if(!inlit)
21234887Schin {
21244887Schin if(mode<=0)
21254887Schin dp--;
21264887Schin inquote = inquote^1;
21274887Schin if(ep)
21284887Schin {
21294887Schin char *msg;
21304887Schin if(mode==2)
21314887Schin {
21324887Schin sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
21334887Schin ep = 0;
21344887Schin break;
21354887Schin }
21364887Schin *--dp = 0;
21374887Schin #if ERROR_VERSION >= 20000317L
21384887Schin msg = ERROR_translate(0,error_info.id,0,ep);
21394887Schin #else
21404887Schin # if ERROR_VERSION >= 20000101L
21414887Schin msg = ERROR_translate(error_info.id,ep);
21424887Schin # else
21434887Schin msg = ERROR_translate(ep,2);
21444887Schin # endif
21454887Schin #endif
21464887Schin n = strlen(msg);
21474887Schin dp = ep+n;
21484887Schin if(sp-dp <= 1)
21494887Schin {
21508462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp);
21514887Schin dp = sp-1;
21524887Schin ep = dp-n;
21534887Schin }
21544887Schin memmove(ep,msg,n);
21554887Schin *dp++ = '"';
21564887Schin }
21574887Schin ep = 0;
21584887Schin }
21594887Schin break;
21604887Schin case S_DOL: /* check for $'...' and $"..." */
21614887Schin if(inlit)
21624887Schin break;
21634887Schin if(*sp==LPAREN || *sp==LBRACE)
21644887Schin {
21654887Schin inquote <<= 1;
21664887Schin break;
21674887Schin }
21684887Schin if(inquote&1)
21694887Schin break;
21704887Schin if(*sp=='\'' || *sp=='"')
21714887Schin {
21724887Schin if(*sp=='"')
21734887Schin inquote |= 1;
21744887Schin else
21754887Schin inlit = 1;
21764887Schin sp++;
21774887Schin if((mode==0||(mode<0&&bracket)) || (inquote&1))
21784887Schin {
21794887Schin if(mode==2)
21804887Schin ep = dp++;
21814887Schin else if(mode==1)
21824887Schin (ep=dp)[-1] = '"';
21834887Schin else
21844887Schin ep = --dp;
21854887Schin }
21864887Schin }
21874887Schin break;
21884887Schin case S_ESC:
21894887Schin #if SHOPT_CRNL
21904887Schin if(*sp=='\r' && sp[1]=='\n')
21914887Schin sp++;
21924887Schin #endif /* SHOPT_CRNL */
21934887Schin if(inlit || mode>0)
21944887Schin {
21954887Schin if(mode<0)
21964887Schin {
21974887Schin if(dp>=sp)
21984887Schin {
21998462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp+1);
22004887Schin dp = sp-2;
22014887Schin }
22024887Schin *dp++ = '\\';
22034887Schin }
22044887Schin if(ep)
22054887Schin *dp++ = *sp++;
22064887Schin break;
22074887Schin }
22084887Schin n = *sp;
22094887Schin #if SHOPT_DOS
22104887Schin if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
22114887Schin break;
22124887Schin #endif /* SHOPT_DOS */
22134887Schin if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
22144887Schin {
22154887Schin if(n=='\n')
22164887Schin dp--;
22174887Schin else
22184887Schin dp[-1] = n;
22194887Schin sp++;
22204887Schin }
22214887Schin break;
22224887Schin case S_POP:
22234887Schin if(sp[-1]!=RBRACT)
22244887Schin break;
22254887Schin if(!inlit && !(inquote&1))
22264887Schin {
22274887Schin inquote >>= 1;
22284887Schin if(xp)
22294887Schin dp = sh_checkid(xp,dp);
22304887Schin xp = 0;
22314887Schin if(--bracket<=0 && mode<0)
22324887Schin inquote = 1;
22334887Schin }
22344887Schin else if((inlit||inquote) && mode<0)
22354887Schin {
22364887Schin dp[-1] = '\\';
22374887Schin if(dp>=sp)
22384887Schin {
22398462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp);
22404887Schin dp = sp-1;
22414887Schin }
22424887Schin *dp++ = ']';
22434887Schin }
22444887Schin break;
22454887Schin case S_BRACT:
22464887Schin if(dp[-2]=='.')
22474887Schin xp = dp;
22484887Schin if(mode<0)
22494887Schin {
22504887Schin if(inlit || (bracket&&inquote))
22514887Schin {
22524887Schin dp[-1] = '\\';
22534887Schin if(dp>=sp)
22544887Schin {
22558462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp);
22564887Schin dp = sp-1;
22574887Schin }
22584887Schin *dp++ = '[';
22594887Schin }
22604887Schin else if(bracket++==0)
22614887Schin inquote = 0;
22624887Schin }
22634887Schin break;
22644887Schin }
22654887Schin #if SHOPT_MULTIBYTE
22664887Schin if(mbwide())
22674887Schin {
22684887Schin do
22694887Schin {
22704887Schin int len;
22714887Schin switch(len = mbsize(sp))
22724887Schin {
22734887Schin case -1: /* illegal multi-byte char */
22744887Schin case 0:
22754887Schin case 1:
22764887Schin n=state[*dp++ = *sp++];
22774887Schin break;
22784887Schin default:
22794887Schin /*
22804887Schin * None of the state tables contain
22814887Schin * entries for multibyte characters,
22824887Schin * however, they should be treated
22834887Schin * the same as any other alph
22844887Schin * character. Therefore, we'll use
22854887Schin * the state of the 'a' character.
22864887Schin */
22874887Schin while(len--)
22884887Schin *dp++ = *sp++;
22894887Schin n=state['a'];
22904887Schin }
22914887Schin }
22924887Schin while(n == 0);
22934887Schin }
22944887Schin else
22954887Schin #endif /* SHOPT_MULTIBYTE */
22964887Schin while((n=state[*dp++ = *sp++])==0);
22974887Schin }
22984887Schin }
22994887Schin
23004887Schin struct alias
23014887Schin {
23024887Schin Sfdisc_t disc;
23034887Schin Namval_t *np;
23044887Schin int nextc;
23054887Schin int line;
23064887Schin char buf[2];
23074887Schin Lex_t *lp;
23084887Schin };
23094887Schin
23104887Schin /*
23114887Schin * This code gets called whenever an end of string is found with alias
23124887Schin */
23134887Schin
23144887Schin #ifndef SF_ATEXIT
23154887Schin # define SF_ATEXIT 0
23164887Schin #endif
23174887Schin /*
23184887Schin * This code gets called whenever an end of string is found with alias
23194887Schin */
23204887Schin #ifdef SF_BUFCONST
alias_exceptf(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)23214887Schin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
23224887Schin #else
23234887Schin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
23244887Schin #endif
23254887Schin {
23264887Schin register struct alias *ap = (struct alias*)handle;
23274887Schin register Namval_t *np;
23284887Schin register Lex_t *lp;
23294887Schin if(type==0 || type==SF_ATEXIT || !ap)
23304887Schin return(0);
23314887Schin lp = ap->lp;
23324887Schin np = ap->np;
23334887Schin if(type!=SF_READ)
23344887Schin {
23354887Schin if(type==SF_CLOSING)
23364887Schin {
23374887Schin register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
23384887Schin if(dp!=handle)
23394887Schin sfdisc(iop,dp);
23404887Schin }
23414887Schin else if(type==SF_FINAL)
23424887Schin free((void*)ap);
23434887Schin goto done;
23444887Schin }
23454887Schin if(ap->nextc)
23464887Schin {
23474887Schin /* if last character is a blank, then next work can be alias */
23484887Schin register int c = fcpeek(-1);
23494887Schin if(isblank(c))
23508462SApril.Chin@Sun.COM lp->aliasok = 1;
23514887Schin *ap->buf = ap->nextc;
23524887Schin ap->nextc = 0;
23534887Schin sfsetbuf(iop,ap->buf,1);
23544887Schin return(1);
23554887Schin }
23564887Schin done:
23574887Schin if(np)
23584887Schin nv_offattr(np,NV_NOEXPAND);
23594887Schin return(0);
23604887Schin }
23614887Schin
23624887Schin
setupalias(Lex_t * lp,const char * string,Namval_t * np)23634887Schin static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
23644887Schin {
23654887Schin register Sfio_t *iop, *base;
23664887Schin struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
23674887Schin ap->disc = alias_disc;
23684887Schin ap->lp = lp;
23694887Schin ap->buf[1] = 0;
23704887Schin if(ap->np = np)
23714887Schin {
23724887Schin #if SHOPT_KIA
23738462SApril.Chin@Sun.COM if(lp->kiafile)
23744887Schin {
23754887Schin unsigned long r;
23768462SApril.Chin@Sun.COM r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
23778462SApril.Chin@Sun.COM sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
23784887Schin }
23794887Schin #endif /* SHOPT_KIA */
23804887Schin if((ap->nextc=fcget())==0)
23814887Schin ap->nextc = ' ';
23824887Schin }
23834887Schin else
23844887Schin ap->nextc = 0;
23854887Schin iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
23864887Schin sfdisc(iop, &ap->disc);
23878462SApril.Chin@Sun.COM lp->lexd.nocopy++;
23884887Schin if(!(base=fcfile()))
23894887Schin base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
23904887Schin fcclose();
23914887Schin sfstack(base,iop);
23924887Schin fcfopen(base);
23938462SApril.Chin@Sun.COM lp->lexd.nocopy--;
23944887Schin }
23954887Schin
23964887Schin /*
23974887Schin * grow storage stack for nested constructs by STACK_ARRAY
23984887Schin */
stack_grow(Lex_t * lp)23994887Schin static int stack_grow(Lex_t *lp)
24004887Schin {
24018462SApril.Chin@Sun.COM lp->lexd.lex_max += STACK_ARRAY;
24028462SApril.Chin@Sun.COM if(lp->lexd.lex_match)
24038462SApril.Chin@Sun.COM lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
24044887Schin else
24058462SApril.Chin@Sun.COM lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
24068462SApril.Chin@Sun.COM return(lp->lexd.lex_match!=0);
24074887Schin }
24084887Schin
2409