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 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 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 */ 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 */ 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 */ 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*); 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 */ 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 */ 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 */ 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 */ 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 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 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 */ 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 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 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 */ 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 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 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 */ 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