14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 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; 103*10898Sroland.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; 200*10898Sroland.mainz@nrubsig.org if(lp->lexd.dolparen && lp->lexd.docword) 201*10898Sroland.mainz@nrubsig.org { 202*10898Sroland.mainz@nrubsig.org int n = size - (lp->lexd.docend-(char*)buff); 203*10898Sroland.mainz@nrubsig.org sfwrite(shp->strbuf,lp->lexd.docend,n); 204*10898Sroland.mainz@nrubsig.org lp->lexd.docextra += n; 205*10898Sroland.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; 232*10898Sroland.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; 238*10898Sroland.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; 248*10898Sroland.mainz@nrubsig.org if(lp->lexd.docword && docextra) 249*10898Sroland.mainz@nrubsig.org { 250*10898Sroland.mainz@nrubsig.org lp->lexd.docextra = docextra; 251*10898Sroland.mainz@nrubsig.org lp->lexd.docend = fcseek(0)-1; 252*10898Sroland.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; 2764887Schin } 2778462SApril.Chin@Sun.COM lp->comsub = 0; 2784887Schin return(lp); 2794887Schin } 2804887Schin 2814887Schin #ifdef DBUG 2828462SApril.Chin@Sun.COM extern int lextoken(Lex_t*); 2838462SApril.Chin@Sun.COM int sh_lex(Lex_t *lp) 2844887Schin { 2858462SApril.Chin@Sun.COM Shell_t *shp = lp->sh; 2864887Schin register int flag; 2874887Schin char *quoted, *macro, *split, *expand; 2884887Schin char tokstr[3]; 2894887Schin register int tok = lextoken(); 2904887Schin quoted = macro = split = expand = ""; 2918462SApril.Chin@Sun.COM if(tok==0 && (flag=lp->arg->argflag)) 2924887Schin { 2934887Schin if(flag&ARG_MAC) 2944887Schin macro = "macro:"; 2954887Schin if(flag&ARG_EXP) 2964887Schin expand = "expand:"; 2974887Schin if(flag&ARG_QUOTED) 2984887Schin quoted = "quoted:"; 2994887Schin } 3004887Schin sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted, 3014887Schin macro, split, expand, fmttoken(lp,tok,tokstr)); 3024887Schin return(tok); 3034887Schin } 3044887Schin #define sh_lex lextoken 3054887Schin #endif 3064887Schin 3074887Schin /* 3084887Schin * Get the next word and put it on the top of the stak 3098462SApril.Chin@Sun.COM * A pointer to the current word is stored in lp->arg 3104887Schin * Returns the token type 3114887Schin */ 3128462SApril.Chin@Sun.COM int sh_lex(Lex_t* lp) 3134887Schin { 3148462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh; 3154887Schin register const char *state; 3168462SApril.Chin@Sun.COM register int n, c, mode=ST_BEGIN, wordflags=0; 3178462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 3188462SApril.Chin@Sun.COM int inlevel=lp->lexd.level, assignment=0, ingrave=0; 3194887Schin Sfio_t *sp; 3204887Schin #if SHOPT_MULTIBYTE 3214887Schin LEN=1; 3224887Schin #endif /* SHOPT_MULTIBYTE */ 3238462SApril.Chin@Sun.COM if(lp->lexd.paren) 3244887Schin { 3258462SApril.Chin@Sun.COM lp->lexd.paren = 0; 3268462SApril.Chin@Sun.COM return(lp->token=LPAREN); 3274887Schin } 3288462SApril.Chin@Sun.COM if(lp->lex.incase) 3298462SApril.Chin@Sun.COM lp->assignok = 0; 3304887Schin else 3318462SApril.Chin@Sun.COM lp->assignok |= lp->lex.reservok; 3328462SApril.Chin@Sun.COM if(lp->comp_assign==2) 3338462SApril.Chin@Sun.COM lp->comp_assign = lp->lex.reservok = 0; 3348462SApril.Chin@Sun.COM lp->lexd.arith = (lp->lexd.nest==1); 3358462SApril.Chin@Sun.COM if(lp->lexd.nest) 3364887Schin { 3378462SApril.Chin@Sun.COM pushlevel(lp,lp->lexd.nest,ST_NONE); 3388462SApril.Chin@Sun.COM lp->lexd.nest = 0; 3398462SApril.Chin@Sun.COM mode = lp->lexd.lex_state; 3404887Schin } 3418462SApril.Chin@Sun.COM else if(lp->lexd.docword) 3424887Schin { 3434887Schin if(fcgetc(c)=='-' || c=='#') 3444887Schin { 3458462SApril.Chin@Sun.COM lp->lexd.docword++; 3468462SApril.Chin@Sun.COM lp->digits=(c=='#'?3:1); 3474887Schin } 3484887Schin else if(c=='<') 3494887Schin { 3508462SApril.Chin@Sun.COM lp->digits=2; 3518462SApril.Chin@Sun.COM lp->lexd.docword=0; 3524887Schin } 3534887Schin else if(c>0) 3544887Schin fcseek(-1); 3554887Schin } 3568462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 3574887Schin { 3588462SApril.Chin@Sun.COM lp->arg = 0; 3594887Schin if(mode!=ST_BEGIN) 3608462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0); 3614887Schin else 3628462SApril.Chin@Sun.COM lp->lexd.first = 0; 3634887Schin } 3648462SApril.Chin@Sun.COM lp->lastline = lp->sh->inlineno; 3654887Schin while(1) 3664887Schin { 3674887Schin /* skip over characters in the current state */ 3684887Schin state = sh_lexstates[mode]; 3694887Schin while((n=STATE(state,c))==0); 3704887Schin switch(n) 3714887Schin { 3724887Schin case S_BREAK: 3734887Schin fcseek(-1); 3744887Schin goto breakloop; 3754887Schin case S_EOF: 3764887Schin sp = fcfile(); 3778462SApril.Chin@Sun.COM if((n=lexfill(lp)) > 0) 3784887Schin { 3794887Schin fcseek(-1); 3804887Schin continue; 3814887Schin } 3824887Schin /* check for zero byte in file */ 3834887Schin if(n==0 && fcfile()) 3844887Schin { 3854887Schin if(shp->readscript) 3864887Schin { 3874887Schin char *cp = error_info.id; 3884887Schin errno = ENOEXEC; 3894887Schin error_info.id = shp->readscript; 3904887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp); 3914887Schin } 3924887Schin else 3934887Schin { 3948462SApril.Chin@Sun.COM lp->token = -1; 3958462SApril.Chin@Sun.COM sh_syntax(lp); 3964887Schin } 3974887Schin } 3984887Schin /* end-of-file */ 3994887Schin if(mode==ST_BEGIN) 4008462SApril.Chin@Sun.COM return(lp->token=EOFSYM); 4018462SApril.Chin@Sun.COM if(mode >ST_NORM && lp->lexd.level>0) 4024887Schin { 4038462SApril.Chin@Sun.COM switch(c=endchar(lp)) 4044887Schin { 4054887Schin case '$': 4064887Schin if(mode==ST_LIT) 4074887Schin { 4084887Schin c = '\''; 4094887Schin break; 4104887Schin } 4118462SApril.Chin@Sun.COM mode = oldmode(lp); 4128462SApril.Chin@Sun.COM poplevel(lp); 4134887Schin continue; 4144887Schin case RBRACT: 4154887Schin c = LBRACT; 4164887Schin break; 4174887Schin case 1: /* for ((...)) */ 4184887Schin case RPAREN: 4194887Schin c = LPAREN; 4204887Schin break; 4214887Schin default: 4224887Schin c = LBRACE; 4234887Schin break; 4244887Schin case '"': case '`': case '\'': 4258462SApril.Chin@Sun.COM lp->lexd.balance = c; 4264887Schin break; 4274887Schin } 4284887Schin if(sp && !(sfset(sp,0,0)&SF_STRING)) 4294887Schin { 4308462SApril.Chin@Sun.COM lp->lasttok = c; 4318462SApril.Chin@Sun.COM lp->token = EOFSYM; 4328462SApril.Chin@Sun.COM sh_syntax(lp); 4334887Schin } 4348462SApril.Chin@Sun.COM lp->lexd.balance = c; 4354887Schin } 4364887Schin goto breakloop; 4374887Schin case S_COM: 4384887Schin /* skip one or more comment line(s) */ 4398462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest; 4408462SApril.Chin@Sun.COM if((n=lp->lexd.nocopy) && lp->lexd.dolparen) 4418462SApril.Chin@Sun.COM lp->lexd.nocopy--; 4424887Schin do 4434887Schin { 4444887Schin while(fcgetc(c)>0 && c!='\n'); 4458462SApril.Chin@Sun.COM if(c<=0 || lp->heredoc) 4464887Schin break; 4474887Schin while(shp->inlineno++,fcpeek(0)=='\n') 4484887Schin fcseek(1); 4494887Schin while(state[c=fcpeek(0)]==0) 4504887Schin fcseek(1); 4514887Schin } 4524887Schin while(c=='#'); 4538462SApril.Chin@Sun.COM lp->lexd.nocopy = n; 4544887Schin if(c<0) 4558462SApril.Chin@Sun.COM return(lp->token=EOFSYM); 4564887Schin n = S_NLTOK; 4574887Schin shp->inlineno--; 4584887Schin /* FALL THRU */ 4594887Schin case S_NLTOK: 4604887Schin /* check for here-document */ 4618462SApril.Chin@Sun.COM if(lp->heredoc) 4624887Schin { 4638462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 4648462SApril.Chin@Sun.COM lp->lexd.nocopy++; 4654887Schin c = shp->inlineno; 4668462SApril.Chin@Sun.COM if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok) 4674887Schin { 4688462SApril.Chin@Sun.COM lp->lasttok = IODOCSYM; 4698462SApril.Chin@Sun.COM lp->token = EOFSYM; 4708462SApril.Chin@Sun.COM lp->lastline = c; 4718462SApril.Chin@Sun.COM sh_syntax(lp); 4724887Schin } 4738462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 4748462SApril.Chin@Sun.COM lp->lexd.nocopy--; 4758462SApril.Chin@Sun.COM lp->heredoc = 0; 4764887Schin } 4778462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest; 4788462SApril.Chin@Sun.COM lp->lex.skipword = 0; 4794887Schin /* FALL THRU */ 4804887Schin case S_NL: 4814887Schin /* skip over new-lines */ 4828462SApril.Chin@Sun.COM lp->lex.last_quote = 0; 4834887Schin while(shp->inlineno++,fcget()=='\n'); 4844887Schin fcseek(-1); 4854887Schin if(n==S_NLTOK) 4864887Schin { 4878462SApril.Chin@Sun.COM lp->comp_assign = 0; 4888462SApril.Chin@Sun.COM return(lp->token='\n'); 4894887Schin } 4904887Schin case S_BLNK: 4918462SApril.Chin@Sun.COM if(lp->lex.incase<=TEST_RE) 4924887Schin continue; 4934887Schin /* implicit RPAREN for =~ test operator */ 4948462SApril.Chin@Sun.COM if(inlevel+1==lp->lexd.level) 4954887Schin { 4968462SApril.Chin@Sun.COM if(lp->lex.intest) 4978462SApril.Chin@Sun.COM fcseek(-1); 4984887Schin c = RPAREN; 4994887Schin goto do_pop; 5004887Schin } 5014887Schin continue; 5024887Schin case S_OP: 5034887Schin /* return operator token */ 5044887Schin if(c=='<' || c=='>') 5054887Schin { 5068462SApril.Chin@Sun.COM if(lp->lex.testop2) 5078462SApril.Chin@Sun.COM lp->lex.testop2 = 0; 5084887Schin else 5094887Schin { 5108462SApril.Chin@Sun.COM lp->digits = (c=='>'); 5118462SApril.Chin@Sun.COM lp->lex.skipword = 1; 5128462SApril.Chin@Sun.COM lp->aliasok = lp->lex.reservok; 5138462SApril.Chin@Sun.COM lp->lex.reservok = 0; 5144887Schin } 5154887Schin } 5164887Schin else 5174887Schin { 5188462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest; 5194887Schin if(c==RPAREN) 5204887Schin { 5218462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 5228462SApril.Chin@Sun.COM lp->lex.incase = 0; 5238462SApril.Chin@Sun.COM return(lp->token=c); 5244887Schin } 5258462SApril.Chin@Sun.COM lp->lex.testop1 = lp->lex.intest; 5264887Schin } 5274887Schin if(fcgetc(n)>0) 5284887Schin fcseek(-1); 5294887Schin if(state[n]==S_OP || n=='#') 5304887Schin { 5314887Schin if(n==c) 5324887Schin { 5334887Schin if(c=='<') 5348462SApril.Chin@Sun.COM lp->lexd.docword=1; 5354887Schin else if(n==LPAREN) 5364887Schin { 5378462SApril.Chin@Sun.COM lp->lexd.nest=1; 5388462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 5398462SApril.Chin@Sun.COM lp->lexd.lex_state = ST_NESTED; 5404887Schin fcseek(1); 5418462SApril.Chin@Sun.COM return(sh_lex(lp)); 5424887Schin } 5434887Schin c |= SYMREP; 5444887Schin } 5454887Schin else if(c=='(' || c==')') 5468462SApril.Chin@Sun.COM return(lp->token=c); 5474887Schin else if(c=='&') 5484887Schin { 549*10898Sroland.mainz@nrubsig.org if(!sh_isoption(SH_POSIX) && n=='>' && (sh_isoption(SH_BASH) || sh_isstate(SH_PROFILE))) 5504887Schin { 551*10898Sroland.mainz@nrubsig.org if(!sh_isoption(SH_BASH) && !lp->nonstandard) 552*10898Sroland.mainz@nrubsig.org { 553*10898Sroland.mainz@nrubsig.org lp->nonstandard = 1; 554*10898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_warn(0),e_lexnonstandard,shp->inlineno); 555*10898Sroland.mainz@nrubsig.org } 5568462SApril.Chin@Sun.COM lp->digits = -1; 5574887Schin c = '>'; 5584887Schin } 5594887Schin else 5604887Schin n = 0; 5614887Schin } 5624887Schin else if(n=='&') 5634887Schin c |= SYMAMP; 5644887Schin else if(c!='<' && c!='>') 5654887Schin n = 0; 5664887Schin else if(n==LPAREN) 5674887Schin { 5684887Schin c |= SYMLPAR; 5698462SApril.Chin@Sun.COM lp->lex.reservok = 1; 5708462SApril.Chin@Sun.COM lp->lex.skipword = 0; 5714887Schin } 5724887Schin else if(n=='|') 5734887Schin c |= SYMPIPE; 5744887Schin else if(c=='<' && n=='>') 575*10898Sroland.mainz@nrubsig.org { 576*10898Sroland.mainz@nrubsig.org lp->digits = 1; 5774887Schin c = IORDWRSYM; 578*10898Sroland.mainz@nrubsig.org fcgetc(n); 579*10898Sroland.mainz@nrubsig.org if(fcgetc(n)==';') 580*10898Sroland.mainz@nrubsig.org { 581*10898Sroland.mainz@nrubsig.org lp->token = c = IORDWRSYMT; 582*10898Sroland.mainz@nrubsig.org if(lp->inexec) 583*10898Sroland.mainz@nrubsig.org sh_syntax(lp); 584*10898Sroland.mainz@nrubsig.org } 585*10898Sroland.mainz@nrubsig.org else if(n>0) 586*10898Sroland.mainz@nrubsig.org fcseek(-1); 587*10898Sroland.mainz@nrubsig.org n= 0; 588*10898Sroland.mainz@nrubsig.org } 5894887Schin else if(n=='#' && (c=='<'||c=='>')) 5904887Schin c |= SYMSHARP; 5918462SApril.Chin@Sun.COM else if(n==';' && c=='>') 5928462SApril.Chin@Sun.COM { 5938462SApril.Chin@Sun.COM c |= SYMSEMI; 5948462SApril.Chin@Sun.COM if(lp->inexec) 5958462SApril.Chin@Sun.COM { 5968462SApril.Chin@Sun.COM lp->token = c; 5978462SApril.Chin@Sun.COM sh_syntax(lp); 5988462SApril.Chin@Sun.COM } 5998462SApril.Chin@Sun.COM } 6004887Schin else 6014887Schin n = 0; 6024887Schin if(n) 6034887Schin { 6044887Schin fcseek(1); 6058462SApril.Chin@Sun.COM lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM); 6064887Schin } 6074887Schin else 6084887Schin { 609*10898Sroland.mainz@nrubsig.org if(lp->lexd.warn && (n=fcpeek(0))!=RPAREN && n!=' ' && n!='\t') 6104887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n); 6114887Schin } 6124887Schin } 6138462SApril.Chin@Sun.COM if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase) 6148462SApril.Chin@Sun.COM lp->comp_assign = 2; 6154887Schin else 6168462SApril.Chin@Sun.COM lp->comp_assign = 0; 6178462SApril.Chin@Sun.COM return(lp->token=c); 6184887Schin case S_ESC: 6194887Schin /* check for \<new-line> */ 6204887Schin fcgetc(n); 6214887Schin c=2; 6224887Schin #if SHOPT_CRNL 6234887Schin if(n=='\r') 6244887Schin { 6254887Schin if(fcgetc(n)=='\n') 6264887Schin c=3; 6274887Schin else 6284887Schin { 6294887Schin n='\r'; 6304887Schin fcseek(-1); 6314887Schin } 6324887Schin } 6334887Schin #endif /* SHOPT_CRNL */ 6344887Schin if(n=='\n') 6354887Schin { 6364887Schin Sfio_t *sp; 6374887Schin struct argnod *ap; 6384887Schin shp->inlineno++; 6394887Schin /* synchronize */ 6404887Schin if(!(sp=fcfile())) 6414887Schin state=fcseek(0); 6424887Schin fcclose(); 6438462SApril.Chin@Sun.COM ap = lp->arg; 6444887Schin if(sp) 6454887Schin fcfopen(sp); 6464887Schin else 6474887Schin fcsopen((char*)state); 6484887Schin /* remove \new-line */ 6498462SApril.Chin@Sun.COM n = stktell(stkp)-c; 6508462SApril.Chin@Sun.COM stkseek(stkp,n); 6518462SApril.Chin@Sun.COM lp->arg = ap; 6524887Schin if(n<=ARGVAL) 6534887Schin { 6544887Schin mode = 0; 6558462SApril.Chin@Sun.COM lp->lexd.first = 0; 6564887Schin } 6574887Schin continue; 6584887Schin } 6594887Schin wordflags |= ARG_QUOTED; 6604887Schin if(mode==ST_DOL) 6614887Schin goto err; 6624887Schin #ifndef STR_MAXIMAL 6638462SApril.Chin@Sun.COM else if(mode==ST_NESTED && lp->lexd.warn && 6648462SApril.Chin@Sun.COM endchar(lp)==RBRACE && 6654887Schin sh_lexstates[ST_DOL][n]==S_DIG 6664887Schin ) 6674887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n); 6684887Schin #endif /* STR_MAXIMAL */ 6694887Schin break; 6704887Schin case S_NAME: 6718462SApril.Chin@Sun.COM if(!lp->lex.skipword) 6728462SApril.Chin@Sun.COM lp->lex.reservok *= 2; 6734887Schin /* FALL THRU */ 6744887Schin case S_TILDE: 6754887Schin case S_RES: 6768462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 6778462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0)-LEN; 6788462SApril.Chin@Sun.COM else if(lp->lexd.docword) 6798462SApril.Chin@Sun.COM lp->lexd.docend = fcseek(0)-LEN; 6804887Schin mode = ST_NAME; 6814887Schin if(c=='.') 6824887Schin fcseek(-1); 6834887Schin if(n!=S_TILDE) 6844887Schin continue; 6854887Schin fcgetc(n); 6864887Schin if(n>0) 6878462SApril.Chin@Sun.COM { 6888462SApril.Chin@Sun.COM if(c=='~' && n==LPAREN && lp->lex.incase) 6898462SApril.Chin@Sun.COM lp->lex.incase = TEST_RE; 6904887Schin fcseek(-1); 6918462SApril.Chin@Sun.COM } 6924887Schin if(n==LPAREN) 6934887Schin goto epat; 6944887Schin wordflags = ARG_MAC; 6954887Schin mode = ST_NORM; 6964887Schin continue; 6974887Schin case S_REG: 6984887Schin if(mode==ST_BEGIN) 6994887Schin { 7008462SApril.Chin@Sun.COM do_reg: 7014887Schin /* skip new-line joining */ 7024887Schin if(c=='\\' && fcpeek(0)=='\n') 7034887Schin { 7044887Schin shp->inlineno++; 7054887Schin fcseek(1); 7064887Schin continue; 7074887Schin } 7084887Schin fcseek(-1); 7098462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 7108462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0); 7118462SApril.Chin@Sun.COM else if(lp->lexd.docword) 7128462SApril.Chin@Sun.COM lp->lexd.docend = fcseek(0); 7138462SApril.Chin@Sun.COM if(c=='[' && lp->assignok>=SH_ASSIGN) 7144887Schin { 7154887Schin mode = ST_NAME; 7164887Schin continue; 7174887Schin } 7184887Schin } 7194887Schin mode = ST_NORM; 7204887Schin continue; 7214887Schin case S_LIT: 7228462SApril.Chin@Sun.COM if(oldmode(lp)==ST_NONE && !lp->lexd.noarg) /* in ((...)) */ 7234887Schin { 7244887Schin if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']') 7254887Schin { 7264887Schin if(fcpeek(1)=='\'') 7274887Schin fcseek(2); 7284887Schin } 7294887Schin continue; 7304887Schin } 7314887Schin wordflags |= ARG_QUOTED; 7324887Schin if(mode==ST_DOL) 7334887Schin { 7348462SApril.Chin@Sun.COM if(endchar(lp)!='$') 7354887Schin goto err; 7368462SApril.Chin@Sun.COM if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */ 7374887Schin { 7388462SApril.Chin@Sun.COM if(lp->lexd.warn) 7394887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno); 7404887Schin mode = ST_LIT; 7414887Schin } 7424887Schin } 7434887Schin if(mode!=ST_LIT) 7444887Schin { 7458462SApril.Chin@Sun.COM if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline) 7468462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote); 7478462SApril.Chin@Sun.COM lp->lex.last_quote = 0; 7488462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 7494887Schin if(mode!=ST_DOL) 7508462SApril.Chin@Sun.COM pushlevel(lp,'\'',mode); 7514887Schin mode = ST_LIT; 7524887Schin continue; 7534887Schin } 7544887Schin /* check for multi-line single-quoted string */ 7558462SApril.Chin@Sun.COM else if(shp->inlineno > lp->lastline) 7568462SApril.Chin@Sun.COM lp->lex.last_quote = '\''; 7578462SApril.Chin@Sun.COM mode = oldmode(lp); 7588462SApril.Chin@Sun.COM poplevel(lp); 7594887Schin break; 7604887Schin case S_ESC2: 7614887Schin /* \ inside '' */ 7628462SApril.Chin@Sun.COM if(endchar(lp)=='$') 7634887Schin { 7644887Schin fcgetc(n); 7654887Schin if(n=='\n') 7664887Schin shp->inlineno++; 7674887Schin } 7684887Schin continue; 7694887Schin case S_GRAVE: 7708462SApril.Chin@Sun.COM if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`')) 7714887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno); 7724887Schin wordflags |=(ARG_MAC|ARG_EXP); 7734887Schin if(mode==ST_QUOTE) 7744887Schin ingrave = !ingrave; 7754887Schin /* FALL THRU */ 7764887Schin case S_QUOTE: 7778462SApril.Chin@Sun.COM if(oldmode(lp)==ST_NONE && lp->lexd.arith) /* in ((...)) */ 7788462SApril.Chin@Sun.COM { 7798462SApril.Chin@Sun.COM if(n!=S_GRAVE || fcpeek(0)=='\'') 7808462SApril.Chin@Sun.COM continue; 7818462SApril.Chin@Sun.COM } 7824887Schin if(n==S_QUOTE) 7834887Schin wordflags |=ARG_QUOTED; 7844887Schin if(mode!=ST_QUOTE) 7854887Schin { 7864887Schin if(c!='"' || mode!=ST_QNEST) 7874887Schin { 7888462SApril.Chin@Sun.COM if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline) 7898462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote); 7908462SApril.Chin@Sun.COM lp->lex.last_quote=0; 7918462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 7928462SApril.Chin@Sun.COM pushlevel(lp,c,mode); 7934887Schin } 794*10898Sroland.mainz@nrubsig.org ingrave ^= (c=='`'); 7954887Schin mode = ST_QUOTE; 7964887Schin continue; 7974887Schin } 7988462SApril.Chin@Sun.COM else if((n=endchar(lp))==c) 7994887Schin { 8008462SApril.Chin@Sun.COM if(shp->inlineno > lp->lastline) 8018462SApril.Chin@Sun.COM lp->lex.last_quote = c; 8028462SApril.Chin@Sun.COM mode = oldmode(lp); 8038462SApril.Chin@Sun.COM poplevel(lp); 8044887Schin } 8054887Schin else if(c=='"' && n==RBRACE) 8064887Schin mode = ST_QNEST; 8074887Schin break; 8084887Schin case S_DOL: 8094887Schin /* don't check syntax inside `` */ 8104887Schin if(mode==ST_QUOTE && ingrave) 8114887Schin continue; 8124887Schin #if SHOPT_KIA 8138462SApril.Chin@Sun.COM if(lp->lexd.first) 8148462SApril.Chin@Sun.COM lp->lexd.kiaoff = fcseek(0)-lp->lexd.first; 8154887Schin else 8168462SApril.Chin@Sun.COM lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst(); 8174887Schin #endif /* SHOPT_KIA */ 8188462SApril.Chin@Sun.COM pushlevel(lp,'$',mode); 8194887Schin mode = ST_DOL; 8204887Schin continue; 8214887Schin case S_PAR: 8228462SApril.Chin@Sun.COM do_comsub: 8234887Schin wordflags |= ARG_MAC; 8248462SApril.Chin@Sun.COM mode = oldmode(lp); 8258462SApril.Chin@Sun.COM poplevel(lp); 8264887Schin fcseek(-1); 8278462SApril.Chin@Sun.COM wordflags |= comsub(lp,c); 8284887Schin continue; 8294887Schin case S_RBRA: 8308462SApril.Chin@Sun.COM if((n=endchar(lp)) == '$') 8314887Schin goto err; 8324887Schin if(mode!=ST_QUOTE || n==RBRACE) 8334887Schin { 8348462SApril.Chin@Sun.COM mode = oldmode(lp); 8358462SApril.Chin@Sun.COM poplevel(lp); 8364887Schin } 8374887Schin break; 8384887Schin case S_EDOL: 8394887Schin /* end $identifier */ 8404887Schin #if SHOPT_KIA 8418462SApril.Chin@Sun.COM if(lp->kiafile) 8428462SApril.Chin@Sun.COM refvar(lp,0); 8434887Schin #endif /* SHOPT_KIA */ 8448462SApril.Chin@Sun.COM if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED) 8454887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno); 8464887Schin fcseek(-1); 8478462SApril.Chin@Sun.COM mode = oldmode(lp); 8488462SApril.Chin@Sun.COM poplevel(lp); 8494887Schin break; 8504887Schin case S_DOT: 8514887Schin /* make sure next character is alpha */ 8524887Schin if(fcgetc(n)>0) 8538462SApril.Chin@Sun.COM { 8548462SApril.Chin@Sun.COM if(n=='.') 8558462SApril.Chin@Sun.COM fcgetc(n); 8568462SApril.Chin@Sun.COM if(n>0) 8578462SApril.Chin@Sun.COM fcseek(-1); 8588462SApril.Chin@Sun.COM } 8594887Schin if(isaletter(n) || n==LBRACT) 8604887Schin continue; 8614887Schin if(mode==ST_NAME) 8624887Schin { 8634887Schin if(n=='=') 8644887Schin continue; 8654887Schin break; 8664887Schin } 8674887Schin else if(n==RBRACE) 8684887Schin continue; 8694887Schin if(isastchar(n)) 8704887Schin continue; 8714887Schin goto err; 8724887Schin case S_SPC1: 8734887Schin wordflags |= ARG_MAC; 8748462SApril.Chin@Sun.COM if(endchar(lp)==RBRACE) 8754887Schin { 8768462SApril.Chin@Sun.COM setchar(lp,c); 8774887Schin continue; 8784887Schin } 8794887Schin /* FALL THRU */ 8804887Schin case S_ALP: 8818462SApril.Chin@Sun.COM if(c=='.' && endchar(lp)=='$') 8824887Schin goto err; 8834887Schin case S_SPC2: 8844887Schin case S_DIG: 8854887Schin wordflags |= ARG_MAC; 8868462SApril.Chin@Sun.COM switch(endchar(lp)) 8874887Schin { 8884887Schin case '$': 8894887Schin if(n==S_ALP) /* $identifier */ 8904887Schin mode = ST_DOLNAME; 8914887Schin else 8924887Schin { 8938462SApril.Chin@Sun.COM mode = oldmode(lp); 8948462SApril.Chin@Sun.COM poplevel(lp); 8954887Schin } 8964887Schin break; 8974887Schin #if SHOPT_TYPEDEF 8984887Schin case '@': 8994887Schin #endif /* SHOPT_TYPEDEF */ 9004887Schin case '!': 9014887Schin if(n!=S_ALP) 9024887Schin goto dolerr; 9034887Schin case '#': 9044887Schin case RBRACE: 9054887Schin if(n==S_ALP) 9064887Schin { 9078462SApril.Chin@Sun.COM setchar(lp,RBRACE); 9084887Schin if(c=='.') 9094887Schin fcseek(-1); 9104887Schin mode = ST_BRACE; 9114887Schin } 9124887Schin else 9134887Schin { 9144887Schin if(fcgetc(c)>0) 9154887Schin fcseek(-1); 9164887Schin if(state[c]==S_ALP) 9174887Schin goto err; 9184887Schin if(n==S_DIG) 9198462SApril.Chin@Sun.COM setchar(lp,'0'); 9204887Schin else 9218462SApril.Chin@Sun.COM setchar(lp,'!'); 9224887Schin } 9234887Schin break; 9244887Schin case '0': 9254887Schin if(n==S_DIG) 9264887Schin break; 9274887Schin default: 9284887Schin goto dolerr; 9294887Schin } 9304887Schin break; 9314887Schin dolerr: 9324887Schin case S_ERR: 9338462SApril.Chin@Sun.COM if((n=endchar(lp)) == '$') 9344887Schin goto err; 9354887Schin if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2) 9364887Schin { 9374887Schin /* see whether inside `...` */ 9388462SApril.Chin@Sun.COM mode = oldmode(lp); 9398462SApril.Chin@Sun.COM poplevel(lp); 9408462SApril.Chin@Sun.COM if((n = endchar(lp)) != '`') 9414887Schin goto err; 9428462SApril.Chin@Sun.COM pushlevel(lp,RBRACE,mode); 9434887Schin } 9444887Schin else 9458462SApril.Chin@Sun.COM setchar(lp,RBRACE); 9464887Schin mode = ST_NESTED; 9474887Schin continue; 9484887Schin case S_MOD1: 9498462SApril.Chin@Sun.COM if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE) 9504887Schin { 9514887Schin /* allow ' inside "${...}" */ 9524887Schin if(c==':' && fcgetc(n)>0) 9534887Schin { 9544887Schin n = state[n]; 9554887Schin fcseek(-1); 9564887Schin } 9574887Schin if(n==S_MOD1) 9584887Schin { 9594887Schin mode = ST_QUOTE; 9604887Schin continue; 9614887Schin } 9624887Schin } 9634887Schin /* FALL THRU */ 9644887Schin case S_MOD2: 9654887Schin #if SHOPT_KIA 9668462SApril.Chin@Sun.COM if(lp->kiafile) 9678462SApril.Chin@Sun.COM refvar(lp,1); 9684887Schin #endif /* SHOPT_KIA */ 9694887Schin if(c!=':' && fcgetc(n)>0) 9704887Schin { 9714887Schin if(n!=c) 9724887Schin c = 0; 9734887Schin if(!c || (fcgetc(n)>0)) 9744887Schin { 9754887Schin fcseek(-1); 9764887Schin if(n==LPAREN) 9774887Schin { 9784887Schin if(c!='%') 9794887Schin { 9808462SApril.Chin@Sun.COM lp->token = n; 9818462SApril.Chin@Sun.COM sh_syntax(lp); 9824887Schin } 9838462SApril.Chin@Sun.COM else if(lp->lexd.warn) 9844887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%'); 9854887Schin } 9864887Schin } 9874887Schin } 9884887Schin mode = ST_NESTED; 9894887Schin continue; 9904887Schin case S_LBRA: 9918462SApril.Chin@Sun.COM if((c=endchar(lp)) == '$') 9924887Schin { 9934887Schin if(fcgetc(c)>0) 9944887Schin fcseek(-1); 9958462SApril.Chin@Sun.COM setchar(lp,RBRACE); 9964887Schin if(state[c]!=S_ERR && c!=RBRACE) 9974887Schin continue; 9988462SApril.Chin@Sun.COM if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK) 9998462SApril.Chin@Sun.COM { 10008462SApril.Chin@Sun.COM c = LBRACE; 10018462SApril.Chin@Sun.COM goto do_comsub; 10028462SApril.Chin@Sun.COM } 10034887Schin } 10044887Schin err: 10058462SApril.Chin@Sun.COM n = endchar(lp); 10068462SApril.Chin@Sun.COM mode = oldmode(lp); 10078462SApril.Chin@Sun.COM poplevel(lp); 10084887Schin if(n!='$') 10094887Schin { 10108462SApril.Chin@Sun.COM lp->token = c; 10118462SApril.Chin@Sun.COM sh_syntax(lp); 10124887Schin } 10134887Schin else 10144887Schin { 10158462SApril.Chin@Sun.COM if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE)) 10164887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno); 1017*10898Sroland.mainz@nrubsig.org else if(c=='"' && mode!=ST_QUOTE && !ingrave) 10184887Schin wordflags |= ARG_MESSAGE; 10194887Schin fcseek(-1); 10204887Schin } 10214887Schin continue; 10224887Schin case S_META: 10238462SApril.Chin@Sun.COM if(lp->lexd.warn && endchar(lp)==RBRACE) 10244887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c); 10254887Schin continue; 10264887Schin case S_PUSH: 10278462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,mode); 10284887Schin mode = ST_NESTED; 10294887Schin continue; 10304887Schin case S_POP: 10314887Schin do_pop: 10328462SApril.Chin@Sun.COM if(lp->lexd.level <= inlevel) 10334887Schin break; 10348462SApril.Chin@Sun.COM if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest) 10358462SApril.Chin@Sun.COM { 10368462SApril.Chin@Sun.COM fcseek(-1); 10378462SApril.Chin@Sun.COM goto breakloop; 10388462SApril.Chin@Sun.COM } 10398462SApril.Chin@Sun.COM n = endchar(lp); 10404887Schin if(c==RBRACT && !(n==RBRACT || n==RPAREN)) 10414887Schin continue; 10424887Schin if((c==RBRACE||c==RPAREN) && n==RPAREN) 10434887Schin { 10444887Schin if(fcgetc(n)==LPAREN) 10454887Schin { 10464887Schin if(c!=RPAREN) 10474887Schin fcseek(-1); 10484887Schin continue; 10494887Schin } 10504887Schin if(n>0) 10514887Schin fcseek(-1); 10524887Schin n = RPAREN; 10534887Schin } 10544887Schin if(c==';' && n!=';') 10554887Schin { 10568462SApril.Chin@Sun.COM if(lp->lexd.warn && n==RBRACE) 10574887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c); 10584887Schin continue; 10594887Schin } 10604887Schin if(mode==ST_QNEST) 10614887Schin { 10628462SApril.Chin@Sun.COM if(lp->lexd.warn) 10634887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c); 10644887Schin continue; 10654887Schin } 10668462SApril.Chin@Sun.COM mode = oldmode(lp); 10678462SApril.Chin@Sun.COM poplevel(lp); 10684887Schin /* quotes in subscript need expansion */ 10694887Schin if(mode==ST_NAME && (wordflags&ARG_QUOTED)) 10704887Schin wordflags |= ARG_MAC; 10714887Schin /* check for ((...)) */ 10724887Schin if(n==1 && c==RPAREN) 10734887Schin { 10744887Schin if(fcgetc(n)==RPAREN) 10754887Schin { 10768462SApril.Chin@Sun.COM if(mode==ST_NONE && !lp->lexd.dolparen) 10774887Schin goto breakloop; 10788462SApril.Chin@Sun.COM lp->lex.reservok = 1; 10798462SApril.Chin@Sun.COM lp->lex.skipword = 0; 10808462SApril.Chin@Sun.COM return(lp->token=EXPRSYM); 10814887Schin } 10824887Schin /* backward compatibility */ 10838462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 10844887Schin fcseek(-1); 10854887Schin else 10864887Schin { 10878462SApril.Chin@Sun.COM if(lp->lexd.warn) 10884887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno); 10898462SApril.Chin@Sun.COM if(!(state=lp->lexd.first)) 10904887Schin state = fcfirst(); 10914887Schin fcseek(state-fcseek(0)); 10928462SApril.Chin@Sun.COM if(lp->arg) 10934887Schin { 10948462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 10958462SApril.Chin@Sun.COM setupalias(lp,lp->arg->argval,NIL(Namval_t*)); 10964887Schin } 10978462SApril.Chin@Sun.COM lp->lexd.paren = 1; 10984887Schin } 10998462SApril.Chin@Sun.COM return(lp->token=LPAREN); 11004887Schin } 11014887Schin if(mode==ST_NONE) 11024887Schin return(0); 11034887Schin if(c!=n) 11044887Schin { 11058462SApril.Chin@Sun.COM lp->token = c; 11068462SApril.Chin@Sun.COM sh_syntax(lp); 11074887Schin } 11084887Schin if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM)) 11094887Schin goto epat; 11104887Schin continue; 11114887Schin case S_EQ: 11128462SApril.Chin@Sun.COM assignment = lp->assignok; 11134887Schin /* FALL THRU */ 11144887Schin case S_COLON: 11154887Schin if(assignment) 11164887Schin { 11174887Schin if((c=fcget())=='~') 11184887Schin wordflags |= ARG_MAC; 11194887Schin else if(c!=LPAREN && assignment==SH_COMPASSIGN) 11204887Schin assignment = 0; 11214887Schin fcseek(-1); 11224887Schin } 11234887Schin break; 11244887Schin case S_LABEL: 11258462SApril.Chin@Sun.COM if(lp->lex.reservok && !lp->lex.incase) 11264887Schin { 11274887Schin c = fcget(); 11284887Schin fcseek(-1); 11294887Schin if(state[c]==S_BREAK) 11304887Schin { 11314887Schin assignment = -1; 11324887Schin goto breakloop; 11334887Schin } 11344887Schin } 11354887Schin break; 11364887Schin case S_BRACT: 11374887Schin /* check for possible subscript */ 11388462SApril.Chin@Sun.COM if((n=endchar(lp))==RBRACT || n==RPAREN || 11394887Schin (mode==ST_BRACE) || 11408462SApril.Chin@Sun.COM (oldmode(lp)==ST_NONE) || 11418462SApril.Chin@Sun.COM (mode==ST_NAME && (lp->assignok||lp->lexd.level))) 11424887Schin { 1143*10898Sroland.mainz@nrubsig.org if(mode==ST_NAME) 1144*10898Sroland.mainz@nrubsig.org { 1145*10898Sroland.mainz@nrubsig.org fcgetc(n); 1146*10898Sroland.mainz@nrubsig.org if(n>0) 1147*10898Sroland.mainz@nrubsig.org { 1148*10898Sroland.mainz@nrubsig.org if(n==']') 1149*10898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript"); 1150*10898Sroland.mainz@nrubsig.org fcseek(-1); 1151*10898Sroland.mainz@nrubsig.org } 1152*10898Sroland.mainz@nrubsig.org } 11538462SApril.Chin@Sun.COM pushlevel(lp,RBRACT,mode); 11544887Schin wordflags |= ARG_QUOTED; 11554887Schin mode = ST_NESTED; 11564887Schin continue; 11574887Schin } 11584887Schin wordflags |= ARG_EXP; 11594887Schin break; 11604887Schin case S_BRACE: 11614887Schin { 11624887Schin int isfirst; 11638462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 11648462SApril.Chin@Sun.COM { 11658462SApril.Chin@Sun.COM if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub)) 11668462SApril.Chin@Sun.COM { 11678462SApril.Chin@Sun.COM fcgetc(n); 11688462SApril.Chin@Sun.COM if(n>0) 11698462SApril.Chin@Sun.COM fcseek(-1); 11708462SApril.Chin@Sun.COM else 11718462SApril.Chin@Sun.COM n = '\n'; 11728462SApril.Chin@Sun.COM if(n==RBRACT || sh_lexstates[ST_NORM][n]) 11738462SApril.Chin@Sun.COM return(lp->token=c); 11748462SApril.Chin@Sun.COM } 11754887Schin break; 11768462SApril.Chin@Sun.COM } 11778462SApril.Chin@Sun.COM else if(mode==ST_BEGIN) 11788462SApril.Chin@Sun.COM { 11798462SApril.Chin@Sun.COM if(lp->comsub && c==RBRACE) 11808462SApril.Chin@Sun.COM return(lp->token=c); 11818462SApril.Chin@Sun.COM goto do_reg; 11828462SApril.Chin@Sun.COM } 11838462SApril.Chin@Sun.COM isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1); 11844887Schin fcgetc(n); 11854887Schin /* check for {} */ 11864887Schin if(c==LBRACE && n==RBRACE) 11874887Schin break; 11884887Schin if(n>0) 11894887Schin fcseek(-1); 11908462SApril.Chin@Sun.COM else if(lp->lex.reservok) 11914887Schin break; 11924887Schin /* check for reserved word { or } */ 11938462SApril.Chin@Sun.COM if(lp->lex.reservok && state[n]==S_BREAK && isfirst) 11944887Schin break; 11954887Schin if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK 11968462SApril.Chin@Sun.COM && !lp->lex.incase && !lp->lex.intest 11978462SApril.Chin@Sun.COM && !lp->lex.skipword) 11984887Schin { 11994887Schin wordflags |= ARG_EXP; 12004887Schin } 12014887Schin if(c==RBRACE && n==LPAREN) 12024887Schin goto epat; 12034887Schin break; 12044887Schin } 12054887Schin case S_PAT: 12064887Schin wordflags |= ARG_EXP; 12074887Schin /* FALL THRU */ 12084887Schin case S_EPAT: 12094887Schin epat: 12104887Schin if(fcgetc(n)==LPAREN) 12114887Schin { 12128462SApril.Chin@Sun.COM if(lp->lex.incase==TEST_RE) 12134887Schin { 12148462SApril.Chin@Sun.COM lp->lex.incase++; 12158462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,ST_NORM); 12164887Schin mode = ST_NESTED; 12174887Schin } 12184887Schin wordflags |= ARG_EXP; 12198462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,mode); 12204887Schin mode = ST_NESTED; 12214887Schin continue; 12224887Schin } 12234887Schin if(n>0) 12244887Schin fcseek(-1); 12254887Schin if(n=='=' && c=='+' && mode==ST_NAME) 12264887Schin continue; 12274887Schin break; 12284887Schin } 12298462SApril.Chin@Sun.COM lp->comp_assign = 0; 12304887Schin if(mode==ST_NAME) 12314887Schin mode = ST_NORM; 12324887Schin else if(mode==ST_NONE) 12334887Schin return(0); 12344887Schin } 12354887Schin breakloop: 12368462SApril.Chin@Sun.COM if(lp->lexd.nocopy) 12374887Schin { 12388462SApril.Chin@Sun.COM lp->lexd.balance = 0; 12398462SApril.Chin@Sun.COM return(0); 12408462SApril.Chin@Sun.COM } 12418462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 12428462SApril.Chin@Sun.COM { 12438462SApril.Chin@Sun.COM lp->lexd.balance = 0; 12448462SApril.Chin@Sun.COM if(lp->lexd.docword) 12454887Schin nested_here(lp); 12468462SApril.Chin@Sun.COM lp->lexd.message = (wordflags&ARG_MESSAGE); 12478462SApril.Chin@Sun.COM return(lp->token=0); 12484887Schin } 12498462SApril.Chin@Sun.COM if(!(state=lp->lexd.first)) 12504887Schin state = fcfirst(); 12514887Schin n = fcseek(0)-(char*)state; 12528462SApril.Chin@Sun.COM if(!lp->arg) 12538462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkseek(stkp,ARGVAL); 12544887Schin if(n>0) 12558462SApril.Chin@Sun.COM sfwrite(stkp,state,n); 12564887Schin /* add balancing character if necessary */ 12578462SApril.Chin@Sun.COM if(lp->lexd.balance) 12584887Schin { 12598462SApril.Chin@Sun.COM sfputc(stkp,lp->lexd.balance); 12608462SApril.Chin@Sun.COM lp->lexd.balance = 0; 12614887Schin } 12628462SApril.Chin@Sun.COM sfputc(stkp,0); 12638462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 12648462SApril.Chin@Sun.COM state = stkptr(stkp,ARGVAL); 12658462SApril.Chin@Sun.COM n = stktell(stkp)-ARGVAL; 12668462SApril.Chin@Sun.COM lp->lexd.first=0; 12674887Schin if(n==1) 12684887Schin { 12694887Schin /* check for numbered redirection */ 12704887Schin n = state[0]; 12714887Schin if((c=='<' || c=='>') && isadigit(n)) 12724887Schin { 12738462SApril.Chin@Sun.COM c = sh_lex(lp); 12748462SApril.Chin@Sun.COM lp->digits = (n-'0'); 12754887Schin return(c); 12764887Schin } 12774887Schin if(n==LBRACT) 12784887Schin c = 0; 12798462SApril.Chin@Sun.COM else if(n==RBRACE && lp->comsub) 12808462SApril.Chin@Sun.COM return(lp->token=n); 12814887Schin else if(n=='~') 12824887Schin c = ARG_MAC; 12834887Schin else 12844887Schin c = (wordflags&ARG_EXP); 12854887Schin n = 1; 12864887Schin } 12878462SApril.Chin@Sun.COM else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND)) 12884887Schin { 12894887Schin if(!strchr(state,',')) 12904887Schin { 12918462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 12928462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 12938462SApril.Chin@Sun.COM return(lp->token=IOVNAME); 12944887Schin } 12954887Schin c = wordflags; 12964887Schin } 12974887Schin else 12984887Schin c = wordflags; 12994887Schin if(assignment<0) 13004887Schin { 13018462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 13028462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 13038462SApril.Chin@Sun.COM lp->lex.reservok = 1; 13048462SApril.Chin@Sun.COM return(lp->token=LABLSYM); 13054887Schin } 13068462SApril.Chin@Sun.COM if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE) 13074887Schin c &= ~ARG_EXP; 13084887Schin if((c&ARG_EXP) && (c&ARG_QUOTED)) 13094887Schin c |= ARG_MAC; 13104887Schin if(mode==ST_NONE) 13114887Schin { 13124887Schin /* eliminate trailing )) */ 13138462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-2); 13144887Schin } 13154887Schin if(c&ARG_MESSAGE) 13164887Schin { 13174887Schin if(sh_isoption(SH_DICTIONARY)) 13188462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,2); 13194887Schin if(!sh_isoption(SH_NOEXEC)) 13204887Schin { 13218462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,1); 13224887Schin c &= ~ARG_MESSAGE; 13234887Schin } 13244887Schin } 13258462SApril.Chin@Sun.COM if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lp->lexd.warn && !lp->lexd.docword)) 13264887Schin { 13278462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 13288462SApril.Chin@Sun.COM lp->arg->argflag = (c?c:ARG_RAW); 13294887Schin } 13304887Schin else if(mode==ST_NONE) 13318462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,-1); 13324887Schin else 13338462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,0); 13348462SApril.Chin@Sun.COM state = lp->arg->argval; 13358462SApril.Chin@Sun.COM lp->comp_assign = assignment; 13364887Schin if(assignment) 13378462SApril.Chin@Sun.COM lp->arg->argflag |= ARG_ASSIGN; 13388462SApril.Chin@Sun.COM else if(!lp->lex.skipword) 13398462SApril.Chin@Sun.COM lp->assignok = 0; 13408462SApril.Chin@Sun.COM lp->arg->argchn.cp = 0; 13418462SApril.Chin@Sun.COM lp->arg->argnxt.ap = 0; 13424887Schin if(mode==ST_NONE) 13438462SApril.Chin@Sun.COM return(lp->token=EXPRSYM); 13448462SApril.Chin@Sun.COM if(lp->lex.intest) 13454887Schin { 13468462SApril.Chin@Sun.COM if(lp->lex.testop1) 13474887Schin { 13488462SApril.Chin@Sun.COM lp->lex.testop1 = 0; 13494887Schin if(n==2 && state[0]=='-' && state[2]==0 && 13504887Schin strchr(test_opchars,state[1])) 13514887Schin { 13528462SApril.Chin@Sun.COM if(lp->lexd.warn && state[1]=='a') 13534887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno); 13548462SApril.Chin@Sun.COM lp->digits = state[1]; 13558462SApril.Chin@Sun.COM lp->token = TESTUNOP; 13564887Schin } 13574887Schin else if(n==1 && state[0]=='!' && state[1]==0) 13584887Schin { 13598462SApril.Chin@Sun.COM lp->lex.testop1 = 1; 13608462SApril.Chin@Sun.COM lp->token = '!'; 13614887Schin } 13624887Schin else 13634887Schin { 13648462SApril.Chin@Sun.COM lp->lex.testop2 = 1; 13658462SApril.Chin@Sun.COM lp->token = 0; 13664887Schin } 13678462SApril.Chin@Sun.COM return(lp->token); 13684887Schin } 13698462SApril.Chin@Sun.COM lp->lex.incase = 0; 13704887Schin c = sh_lookup(state,shtab_testops); 13714887Schin switch(c) 13724887Schin { 13734887Schin case TEST_END: 13748462SApril.Chin@Sun.COM lp->lex.testop2 = lp->lex.intest = 0; 13758462SApril.Chin@Sun.COM lp->lex.reservok = 1; 13768462SApril.Chin@Sun.COM lp->token = ETESTSYM; 13778462SApril.Chin@Sun.COM return(lp->token); 13784887Schin 13794887Schin case TEST_SEQ: 13808462SApril.Chin@Sun.COM if(lp->lexd.warn && state[1]==0) 13814887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno); 13824887Schin /* FALL THRU */ 13834887Schin default: 13848462SApril.Chin@Sun.COM if(lp->lex.testop2) 13854887Schin { 13868462SApril.Chin@Sun.COM if(lp->lexd.warn && (c&TEST_ARITH)) 13874887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state); 13884887Schin if(c&TEST_PATTERN) 13898462SApril.Chin@Sun.COM lp->lex.incase = 1; 13904887Schin else if(c==TEST_REP) 13918462SApril.Chin@Sun.COM lp->lex.incase = TEST_RE; 13928462SApril.Chin@Sun.COM lp->lex.testop2 = 0; 13938462SApril.Chin@Sun.COM lp->digits = c; 13948462SApril.Chin@Sun.COM lp->token = TESTBINOP; 13958462SApril.Chin@Sun.COM return(lp->token); 13964887Schin } 13974887Schin 13984887Schin case TEST_OR: case TEST_AND: 13994887Schin case 0: 14008462SApril.Chin@Sun.COM return(lp->token=0); 14014887Schin } 14024887Schin } 14038462SApril.Chin@Sun.COM if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2) 14044887Schin { 14054887Schin /* check for {, }, ! */ 14064887Schin c = state[0]; 14074887Schin if(n==1 && (c=='{' || c=='}' || c=='!')) 14084887Schin { 14098462SApril.Chin@Sun.COM if(lp->lexd.warn && c=='{' && lp->lex.incase==2) 14104887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno); 14118462SApril.Chin@Sun.COM if(lp->lex.incase==1 && c==RBRACE) 14128462SApril.Chin@Sun.COM lp->lex.incase = 0; 14138462SApril.Chin@Sun.COM return(lp->token=c); 14144887Schin } 14158462SApril.Chin@Sun.COM else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT) 14164887Schin { 14178462SApril.Chin@Sun.COM lp->lex.intest = lp->lex.testop1 = 1; 14188462SApril.Chin@Sun.COM lp->lex.testop2 = lp->lex.reservok = 0; 14198462SApril.Chin@Sun.COM return(lp->token=BTESTSYM); 14204887Schin } 14214887Schin } 14224887Schin c = 0; 14238462SApril.Chin@Sun.COM if(!lp->lex.skipword) 14244887Schin { 14258462SApril.Chin@Sun.COM if(n>1 && lp->lex.reservok==1 && mode==ST_NAME && 14264887Schin (c=sh_lookup(state,shtab_reserved))) 14274887Schin { 14288462SApril.Chin@Sun.COM if(lp->lex.incase) 14294887Schin { 14308462SApril.Chin@Sun.COM if(lp->lex.incase >1) 14318462SApril.Chin@Sun.COM lp->lex.incase = 1; 14324887Schin else if(c==ESACSYM) 14338462SApril.Chin@Sun.COM lp->lex.incase = 0; 14344887Schin else 14354887Schin c = 0; 14364887Schin } 14374887Schin else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM) 14384887Schin { 14398462SApril.Chin@Sun.COM lp->lex.skipword = 1; 14408462SApril.Chin@Sun.COM lp->lex.incase = 2*(c==CASESYM); 14414887Schin } 14424887Schin else 14438462SApril.Chin@Sun.COM lp->lex.skipword = 0; 14444887Schin if(c==INSYM) 14458462SApril.Chin@Sun.COM lp->lex.reservok = 0; 14464887Schin else if(c==TIMESYM) 14474887Schin { 14484887Schin /* yech - POSIX requires time -p */ 14494887Schin while(fcgetc(n)==' ' || n=='\t'); 14504887Schin if(n>0) 14514887Schin fcseek(-1); 14524887Schin if(n=='-') 14534887Schin c=0; 14544887Schin } 14558462SApril.Chin@Sun.COM return(lp->token=c); 14564887Schin } 14578462SApril.Chin@Sun.COM if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok)) 14584887Schin { 14594887Schin /* check for aliases */ 14604887Schin Namval_t* np; 14618462SApril.Chin@Sun.COM if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN && 14624887Schin (np=nv_search(state,shp->alias_tree,HASH_SCOPE)) 14634887Schin && !nv_isattr(np,NV_NOEXPAND) 14644887Schin #if KSHELL 14654887Schin && (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE)) 14664887Schin #endif /* KSHELL */ 14674887Schin && (state=nv_getval(np))) 14684887Schin { 14694887Schin setupalias(lp,state,np); 14704887Schin nv_onattr(np,NV_NOEXPAND); 14718462SApril.Chin@Sun.COM lp->lex.reservok = 1; 14728462SApril.Chin@Sun.COM lp->assignok |= lp->lex.reservok; 14738462SApril.Chin@Sun.COM return(sh_lex(lp)); 14744887Schin } 14754887Schin } 14768462SApril.Chin@Sun.COM lp->lex.reservok = 0; 14774887Schin } 14788462SApril.Chin@Sun.COM lp->lex.skipword = lp->lexd.docword = 0; 14798462SApril.Chin@Sun.COM return(lp->token=c); 14804887Schin } 14814887Schin 14824887Schin /* 14834887Schin * read to end of command substitution 14844887Schin */ 14858462SApril.Chin@Sun.COM static int comsub(register Lex_t *lp, int endtok) 14864887Schin { 14874887Schin register int n,c,count=1; 14888462SApril.Chin@Sun.COM register int line=lp->sh->inlineno; 14894887Schin char word[5]; 14908462SApril.Chin@Sun.COM int messages=0, assignok=lp->assignok, csub; 14914887Schin struct lexstate save; 14928462SApril.Chin@Sun.COM save = lp->lex; 14938462SApril.Chin@Sun.COM csub = lp->comsub; 14948462SApril.Chin@Sun.COM sh_lexopen(lp,lp->sh,1); 14958462SApril.Chin@Sun.COM lp->lexd.dolparen++; 14968462SApril.Chin@Sun.COM lp->lex.incase=0; 14978462SApril.Chin@Sun.COM pushlevel(lp,0,0); 14988462SApril.Chin@Sun.COM lp->comsub = (endtok==LBRACE); 14998462SApril.Chin@Sun.COM if(sh_lex(lp)==endtok) 15004887Schin { 15014887Schin while(1) 15024887Schin { 15034887Schin /* look for case and esac */ 15044887Schin n=0; 15054887Schin while(1) 15064887Schin { 15074887Schin fcgetc(c); 15084887Schin /* skip leading white space */ 15094887Schin if(n==0 && !sh_lexstates[ST_BEGIN][c]) 15104887Schin continue; 15114887Schin if(n==4) 15124887Schin break; 15134887Schin if(sh_lexstates[ST_NAME][c]) 15144887Schin goto skip; 15154887Schin word[n++] = c; 15164887Schin } 15174887Schin if(sh_lexstates[ST_NAME][c]==S_BREAK) 15184887Schin { 15194887Schin if(memcmp(word,"case",4)==0) 15208462SApril.Chin@Sun.COM lp->lex.incase=1; 15214887Schin else if(memcmp(word,"esac",4)==0) 15228462SApril.Chin@Sun.COM lp->lex.incase=0; 15234887Schin } 15244887Schin skip: 15254887Schin if(c && (c!='#' || n==0)) 15264887Schin fcseek(-1); 15278462SApril.Chin@Sun.COM if(c==RBRACE && lp->lex.incase) 15288462SApril.Chin@Sun.COM lp->lex.incase=0; 15298462SApril.Chin@Sun.COM switch(c=sh_lex(lp)) 15304887Schin { 15318462SApril.Chin@Sun.COM case LBRACE: 15328462SApril.Chin@Sun.COM if(endtok==LBRACE && !lp->lex.incase) 15338462SApril.Chin@Sun.COM { 15348462SApril.Chin@Sun.COM lp->comsub = 0; 15358462SApril.Chin@Sun.COM count++; 15368462SApril.Chin@Sun.COM } 15378462SApril.Chin@Sun.COM break; 15388462SApril.Chin@Sun.COM case RBRACE: 15398462SApril.Chin@Sun.COM rbrace: 15408462SApril.Chin@Sun.COM if(endtok==LBRACE && --count<=0) 15418462SApril.Chin@Sun.COM goto done; 15428462SApril.Chin@Sun.COM lp->comsub = (count==1); 15438462SApril.Chin@Sun.COM break; 15448462SApril.Chin@Sun.COM case IPROCSYM: case OPROCSYM: 15458462SApril.Chin@Sun.COM case LPAREN: 15468462SApril.Chin@Sun.COM if(endtok==LPAREN && !lp->lex.incase) 15474887Schin count++; 15484887Schin break; 15494887Schin case RPAREN: 15508462SApril.Chin@Sun.COM if(lp->lex.incase) 15518462SApril.Chin@Sun.COM lp->lex.incase=0; 15528462SApril.Chin@Sun.COM else if(endtok==LPAREN && --count<=0) 15534887Schin goto done; 15544887Schin break; 15554887Schin case EOFSYM: 15568462SApril.Chin@Sun.COM lp->lastline = line; 15578462SApril.Chin@Sun.COM lp->lasttok = endtok; 15588462SApril.Chin@Sun.COM sh_syntax(lp); 15594887Schin case IOSEEKSYM: 15604887Schin if(fcgetc(c)!='#' && c>0) 15614887Schin fcseek(-1); 15624887Schin break; 15634887Schin case IODOCSYM: 1564*10898Sroland.mainz@nrubsig.org lp->lexd.docextra = 0; 15658462SApril.Chin@Sun.COM sh_lex(lp); 15664887Schin break; 15674887Schin case 0: 15688462SApril.Chin@Sun.COM lp->lex.reservok = 0; 15698462SApril.Chin@Sun.COM messages |= lp->lexd.message; 15708462SApril.Chin@Sun.COM break; 15718462SApril.Chin@Sun.COM case ';': 15728462SApril.Chin@Sun.COM fcgetc(c); 15738462SApril.Chin@Sun.COM if(c==RBRACE && endtok==LBRACE) 15748462SApril.Chin@Sun.COM goto rbrace; 15758462SApril.Chin@Sun.COM if(c>0) 15768462SApril.Chin@Sun.COM fcseek(-1); 15778462SApril.Chin@Sun.COM /* fall through*/ 15788462SApril.Chin@Sun.COM default: 15798462SApril.Chin@Sun.COM lp->lex.reservok = 1; 15804887Schin } 15814887Schin } 15824887Schin } 15834887Schin done: 15848462SApril.Chin@Sun.COM poplevel(lp); 15858462SApril.Chin@Sun.COM lp->comsub = csub; 15868462SApril.Chin@Sun.COM lp->lastline = line; 15878462SApril.Chin@Sun.COM lp->lexd.dolparen--; 15888462SApril.Chin@Sun.COM lp->lex = save; 15898462SApril.Chin@Sun.COM lp->assignok = (endchar(lp)==RBRACT?assignok:0); 15904887Schin return(messages); 15914887Schin } 15924887Schin 15934887Schin /* 15944887Schin * here-doc nested in $(...) 15954887Schin * allocate ionode with delimiter filled in without disturbing stak 15964887Schin */ 15974887Schin static void nested_here(register Lex_t *lp) 15984887Schin { 15998462SApril.Chin@Sun.COM register struct ionod *iop; 16008462SApril.Chin@Sun.COM register int n,offset; 16018462SApril.Chin@Sun.COM struct argnod *arg = lp->arg; 16028462SApril.Chin@Sun.COM Stk_t *stkp = lp->sh->stk; 16038462SApril.Chin@Sun.COM char *base; 16048462SApril.Chin@Sun.COM if(offset=stktell(stkp)) 16058462SApril.Chin@Sun.COM base = stkfreeze(stkp,0); 16068462SApril.Chin@Sun.COM n = fcseek(0)-lp->lexd.docend; 1607*10898Sroland.mainz@nrubsig.org iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL); 16088462SApril.Chin@Sun.COM iop->iolst = lp->heredoc; 16098462SApril.Chin@Sun.COM stkseek(stkp,ARGVAL); 1610*10898Sroland.mainz@nrubsig.org if(lp->lexd.docextra) 1611*10898Sroland.mainz@nrubsig.org { 1612*10898Sroland.mainz@nrubsig.org sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET); 1613*10898Sroland.mainz@nrubsig.org sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1); 1614*10898Sroland.mainz@nrubsig.org } 16158462SApril.Chin@Sun.COM sfwrite(stkp,lp->lexd.docend,n); 16168462SApril.Chin@Sun.COM lp->arg = sh_endword(lp->sh,0); 16174887Schin iop->ioname = (char*)(iop+1); 16188462SApril.Chin@Sun.COM strcpy(iop->ioname,lp->arg->argval); 16194887Schin iop->iofile = (IODOC|IORAW); 16208462SApril.Chin@Sun.COM if(lp->lexd.docword>1) 16214887Schin iop->iofile |= IOSTRIP; 16228462SApril.Chin@Sun.COM lp->heredoc = iop; 16238462SApril.Chin@Sun.COM lp->arg = arg; 16248462SApril.Chin@Sun.COM lp->lexd.docword = 0; 16254887Schin if(offset) 16268462SApril.Chin@Sun.COM stkset(stkp,base,offset); 16274887Schin else 16288462SApril.Chin@Sun.COM stkseek(stkp,0); 16294887Schin } 16304887Schin 16314887Schin /* 16324887Schin * skip to <close> character 16334887Schin * if <copy> is non,zero, then the characters are copied to the stack 16344887Schin * <state> is the initial lexical state 16354887Schin */ 16368462SApril.Chin@Sun.COM void sh_lexskip(Lex_t *lp,int close, register int copy, int state) 16374887Schin { 16384887Schin register char *cp; 16398462SApril.Chin@Sun.COM lp->lexd.nest = close; 16408462SApril.Chin@Sun.COM lp->lexd.lex_state = state; 16418462SApril.Chin@Sun.COM lp->lexd.noarg = 1; 16424887Schin if(copy) 16438462SApril.Chin@Sun.COM fcnotify(lex_advance,lp); 16444887Schin else 16458462SApril.Chin@Sun.COM lp->lexd.nocopy++; 16468462SApril.Chin@Sun.COM sh_lex(lp); 16478462SApril.Chin@Sun.COM lp->lexd.noarg = 0; 16484887Schin if(copy) 16494887Schin { 16508462SApril.Chin@Sun.COM fcnotify(0,lp); 16518462SApril.Chin@Sun.COM if(!(cp=lp->lexd.first)) 16524887Schin cp = fcfirst(); 16534887Schin if((copy = fcseek(0)-cp) > 0) 16548462SApril.Chin@Sun.COM sfwrite(lp->sh->stk,cp,copy); 16554887Schin } 16564887Schin else 16578462SApril.Chin@Sun.COM lp->lexd.nocopy--; 16584887Schin } 16594887Schin 16604887Schin #if SHOPT_CRNL 16614887Schin ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n) 16624887Schin { 16634887Schin const char *cp = (const char*)buff, *next=cp, *ep = cp + n; 16644887Schin int m=0,k; 16654887Schin while(next = (const char*)memchr(next,'\r',ep-next)) 16664887Schin if(*++next=='\n') 16674887Schin { 16684887Schin if(k=next-cp-1) 16694887Schin { 16704887Schin if((k=sfwrite(sp,cp,k)) < 0) 16714887Schin return(m>0?m:-1); 16724887Schin m += k; 16734887Schin } 16744887Schin cp = next; 16754887Schin } 16764887Schin if((k=sfwrite(sp,cp,ep-cp)) < 0) 16774887Schin return(m>0?m:-1); 16784887Schin return(m+k); 16794887Schin } 16804887Schin # define sfwrite _sfwrite 16814887Schin #endif /* SHOPT_CRNL */ 16824887Schin 16834887Schin /* 16844887Schin * read in here-document from script 16854887Schin * quoted here documents, and here-documents without special chars are 16864887Schin * noted with the IOQUOTE flag 16874887Schin * returns 1 for complete here-doc, 0 for EOF 16884887Schin */ 16894887Schin 16904887Schin static int here_copy(Lex_t *lp,register struct ionod *iop) 16914887Schin { 16924887Schin register const char *state; 16934887Schin register int c,n; 16944887Schin register char *bufp,*cp; 16958462SApril.Chin@Sun.COM register Sfio_t *sp=lp->sh->heredocs, *funlog; 16964887Schin int stripcol=0,stripflg, nsave, special=0; 16978462SApril.Chin@Sun.COM if(funlog=lp->sh->funlog) 16984887Schin { 16994887Schin if(fcfill()>0) 17004887Schin fcseek(-1); 17018462SApril.Chin@Sun.COM lp->sh->funlog = 0; 17024887Schin } 17034887Schin if(iop->iolst) 17044887Schin here_copy(lp,iop->iolst); 17054887Schin iop->iooffset = sfseek(sp,(off_t)0,SEEK_END); 17064887Schin iop->iosize = 0; 17074887Schin iop->iodelim=iop->ioname; 17084887Schin /* check for and strip quoted characters in delimiter string */ 17094887Schin if(stripflg=iop->iofile&IOSTRIP) 17104887Schin { 17114887Schin while(*iop->iodelim=='\t') 17124887Schin iop->iodelim++; 17134887Schin /* skip over leading tabs in document */ 17144887Schin if(iop->iofile&IOLSEEK) 17154887Schin { 17164887Schin iop->iofile &= ~IOLSEEK; 17174887Schin while(fcgetc(c)=='\t' || c==' ') 17184887Schin { 17194887Schin if(c==' ') 17204887Schin stripcol++; 17214887Schin else 17224887Schin stripcol += 8 - stripcol%8; 17234887Schin } 17244887Schin } 17254887Schin else 17264887Schin while(fcgetc(c)=='\t'); 17274887Schin if(c>0) 17284887Schin fcseek(-1); 17294887Schin } 17304887Schin if(iop->iofile&IOQUOTE) 17314887Schin state = sh_lexstates[ST_LIT]; 17324887Schin else 17334887Schin state = sh_lexstates[ST_QUOTE]; 17344887Schin bufp = fcseek(0); 17354887Schin n = S_NL; 17364887Schin while(1) 17374887Schin { 17384887Schin if(n!=S_NL) 17394887Schin { 17404887Schin /* skip over regular characters */ 17414887Schin while((n=STATE(state,c))==0); 17424887Schin } 17434887Schin if(n==S_EOF || !(c=fcget())) 17444887Schin { 17458462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp)) 17464887Schin { 17474887Schin if(n==S_ESC) 17484887Schin c--; 17494887Schin if((c=sfwrite(sp,bufp,c))>0) 17504887Schin iop->iosize += c; 17514887Schin } 17528462SApril.Chin@Sun.COM if((c=lexfill(lp))<=0) 17534887Schin break; 17544887Schin if(n==S_ESC) 17554887Schin { 17564887Schin #if SHOPT_CRNL 17574887Schin if(c=='\r' && (c=fcget())!=NL) 17584887Schin fcseek(-1); 17594887Schin #endif /* SHOPT_CRNL */ 17604887Schin if(c==NL) 17614887Schin fcseek(1); 17624887Schin else 17634887Schin sfputc(sp,'\\'); 17644887Schin } 17654887Schin bufp = fcseek(-1); 17664887Schin } 17674887Schin else 17684887Schin fcseek(-1); 17694887Schin switch(n) 17704887Schin { 17714887Schin case S_NL: 17728462SApril.Chin@Sun.COM lp->sh->inlineno++; 17734887Schin if((stripcol && c==' ') || (stripflg && c=='\t')) 17744887Schin { 17758462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 17764887Schin { 17774887Schin /* write out line */ 17784887Schin n = fcseek(0)-bufp; 17794887Schin if((n=sfwrite(sp,bufp,n))>0) 17804887Schin iop->iosize += n; 17814887Schin } 17824887Schin /* skip over tabs */ 17834887Schin if(stripcol) 17844887Schin { 17854887Schin int col=0; 17864887Schin do 17874887Schin { 17884887Schin fcgetc(c); 17894887Schin if(c==' ') 17904887Schin col++; 17914887Schin else 17924887Schin col += 8 - col%8; 17934887Schin if(col>stripcol) 17944887Schin break; 17954887Schin } 17964887Schin while (c==' ' || c=='\t'); 17974887Schin } 17984887Schin else while(c=='\t') 17994887Schin fcgetc(c); 18004887Schin if(c<=0) 18014887Schin goto done; 18024887Schin bufp = fcseek(-1); 18034887Schin } 18044887Schin if(c!=iop->iodelim[0]) 18054887Schin break; 18064887Schin cp = fcseek(0); 18074887Schin nsave = n = 0; 18084887Schin while(1) 18094887Schin { 18104887Schin if(!(c=fcget())) 18114887Schin { 18128462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (c=cp-bufp)) 18134887Schin { 18144887Schin if((c=sfwrite(sp,cp=bufp,c))>0) 18154887Schin iop->iosize+=c; 18164887Schin } 18174887Schin nsave = n; 18188462SApril.Chin@Sun.COM if((c=lexfill(lp))<=0) 18194887Schin { 18204887Schin c = iop->iodelim[n]==0; 18214887Schin goto done; 18224887Schin } 18234887Schin } 18244887Schin #if SHOPT_CRNL 18254887Schin if(c=='\r' && (c=fcget())!=NL) 18264887Schin { 18274887Schin if(c) 18284887Schin fcseek(-1); 18294887Schin c='\r'; 18304887Schin } 18314887Schin #endif /* SHOPT_CRNL */ 18324887Schin if(c==NL) 18338462SApril.Chin@Sun.COM lp->sh->inlineno++; 18344887Schin if(iop->iodelim[n]==0 && (c==NL||c==RPAREN)) 18354887Schin { 18368462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (n=cp-bufp)) 18374887Schin { 18384887Schin if((n=sfwrite(sp,bufp,n))>0) 18394887Schin iop->iosize += n; 18404887Schin } 18418462SApril.Chin@Sun.COM lp->sh->inlineno--; 18424887Schin if(c==RPAREN) 18434887Schin fcseek(-1); 18444887Schin goto done; 18454887Schin } 18464887Schin if(iop->iodelim[n++]!=c) 18474887Schin { 18484887Schin /* 18494887Schin * The match for delimiter failed. 18504887Schin * nsave>0 only when a buffer boundary 18514887Schin * was crossed while checking the 18524887Schin * delimiter 18534887Schin */ 18548462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && nsave>0) 18554887Schin { 18564887Schin if((n=sfwrite(sp,bufp,nsave))>0) 18574887Schin iop->iosize += n; 18584887Schin bufp = fcfirst(); 18594887Schin } 18604887Schin if(c==NL) 18614887Schin fcseek(-1); 18624887Schin break; 18634887Schin } 18644887Schin } 18654887Schin break; 18664887Schin case S_ESC: 18674887Schin n=1; 18684887Schin #if SHOPT_CRNL 18694887Schin if(c=='\r') 18704887Schin { 18714887Schin fcseek(1); 18724887Schin if(c=fcget()) 18734887Schin fcseek(-1); 18744887Schin if(c==NL) 18754887Schin n=2; 18764887Schin else 18774887Schin { 18784887Schin special++; 18794887Schin break; 18804887Schin } 18814887Schin } 18824887Schin #endif /* SHOPT_CRNL */ 18834887Schin if(c==NL) 18844887Schin { 18854887Schin /* new-line joining */ 18868462SApril.Chin@Sun.COM lp->sh->inlineno++; 1887*10898Sroland.mainz@nrubsig.org if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0) 18884887Schin { 1889*10898Sroland.mainz@nrubsig.org if(n && (n=sfwrite(sp,bufp,n))>0) 18904887Schin iop->iosize += n; 18914887Schin bufp = fcseek(0)+1; 18924887Schin } 18934887Schin } 18944887Schin else 18954887Schin special++; 18964887Schin fcget(); 18974887Schin break; 18984887Schin 18994887Schin case S_GRAVE: 19004887Schin case S_DOL: 19014887Schin special++; 19024887Schin break; 19034887Schin } 19044887Schin n=0; 19054887Schin } 19064887Schin done: 19078462SApril.Chin@Sun.COM lp->sh->funlog = funlog; 19088462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 19094887Schin free((void*)iop); 19104887Schin else if(!special) 19114887Schin iop->iofile |= IOQUOTE; 19124887Schin return(c); 19134887Schin } 19144887Schin 19154887Schin /* 19164887Schin * generates string for given token 19174887Schin */ 19184887Schin static char *fmttoken(Lex_t *lp, register int sym, char *tok) 19194887Schin { 1920*10898Sroland.mainz@nrubsig.org int n=1; 19214887Schin if(sym < 0) 19224887Schin return((char*)sh_translate(e_lexzerobyte)); 19234887Schin if(sym==0) 19248462SApril.Chin@Sun.COM return(lp->arg?lp->arg->argval:"?"); 19258462SApril.Chin@Sun.COM if(lp->lex.intest && lp->arg && *lp->arg->argval) 19268462SApril.Chin@Sun.COM return(lp->arg->argval); 19274887Schin if(sym&SYMRES) 19284887Schin { 19294887Schin register const Shtable_t *tp=shtab_reserved; 19304887Schin while(tp->sh_number && tp->sh_number!=sym) 19314887Schin tp++; 19324887Schin return((char*)tp->sh_name); 19334887Schin } 19344887Schin if(sym==EOFSYM) 19354887Schin return((char*)sh_translate(e_endoffile)); 19364887Schin if(sym==NL) 19374887Schin return((char*)sh_translate(e_newline)); 19384887Schin tok[0] = sym; 19394887Schin if(sym&SYMREP) 1940*10898Sroland.mainz@nrubsig.org tok[n++] = sym; 19414887Schin else 19424887Schin { 19434887Schin switch(sym&SYMMASK) 19444887Schin { 19454887Schin case SYMAMP: 19464887Schin sym = '&'; 19474887Schin break; 19484887Schin case SYMPIPE: 19494887Schin sym = '|'; 19504887Schin break; 19514887Schin case SYMGT: 19524887Schin sym = '>'; 19534887Schin break; 19544887Schin case SYMLPAR: 19554887Schin sym = LPAREN; 19564887Schin break; 19574887Schin case SYMSHARP: 19584887Schin sym = '#'; 19594887Schin break; 19608462SApril.Chin@Sun.COM case SYMSEMI: 1961*10898Sroland.mainz@nrubsig.org if(tok[0]=='<') 1962*10898Sroland.mainz@nrubsig.org tok[n++] = '>'; 19638462SApril.Chin@Sun.COM sym = ';'; 19648462SApril.Chin@Sun.COM break; 19654887Schin default: 19664887Schin sym = 0; 19674887Schin } 1968*10898Sroland.mainz@nrubsig.org tok[n++] = sym; 19694887Schin } 1970*10898Sroland.mainz@nrubsig.org tok[n] = 0; 19714887Schin return(tok); 19724887Schin } 19734887Schin 19744887Schin /* 19754887Schin * print a bad syntax message 19764887Schin */ 19774887Schin 19788462SApril.Chin@Sun.COM void sh_syntax(Lex_t *lp) 19794887Schin { 19808462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh; 19814887Schin register const char *cp = sh_translate(e_unexpected); 19824887Schin register char *tokstr; 19838462SApril.Chin@Sun.COM register int tok = lp->token; 19844887Schin char tokbuf[3]; 19854887Schin Sfio_t *sp; 19868462SApril.Chin@Sun.COM if((tok==EOFSYM) && lp->lasttok) 19874887Schin { 19888462SApril.Chin@Sun.COM tok = lp->lasttok; 19894887Schin cp = sh_translate(e_unmatched); 19904887Schin } 19914887Schin else 19928462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 19934887Schin tokstr = fmttoken(lp,tok,tokbuf); 19944887Schin if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd]))) 19954887Schin { 19964887Schin /* clear out any pending input */ 19974887Schin register Sfio_t *top; 19984887Schin while(fcget()>0); 19994887Schin fcclose(); 20004887Schin while(top=sfstack(sp,SF_POPSTACK)) 20014887Schin sfclose(top); 20024887Schin } 20034887Schin else 20044887Schin fcclose(); 20058462SApril.Chin@Sun.COM shp->inlineno = lp->inlineno; 20068462SApril.Chin@Sun.COM shp->st.firstline = lp->firstline; 20074887Schin #if KSHELL 20084887Schin if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE)) 20094887Schin #else 20104887Schin if(shp->inlineno!=1) 20114887Schin #endif 20128462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp); 20134887Schin else 20144887Schin errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp); 20154887Schin } 20164887Schin 20178462SApril.Chin@Sun.COM static char *stack_shift(Stk_t *stkp, register char *sp,char *dp) 20184887Schin { 20194887Schin register char *ep; 20208462SApril.Chin@Sun.COM register int offset = stktell(stkp); 20218462SApril.Chin@Sun.COM register int left = offset-(sp-stkptr(stkp,0)); 20224887Schin register int shift = (dp+1-sp); 20234887Schin offset += shift; 20248462SApril.Chin@Sun.COM stkseek(stkp,offset); 20258462SApril.Chin@Sun.COM sp = stkptr(stkp,offset); 20264887Schin ep = sp - shift; 20274887Schin while(left--) 20284887Schin *--sp = *--ep; 20294887Schin return(sp); 20304887Schin } 20314887Schin 20324887Schin /* 20334887Schin * Assumes that current word is unfrozen on top of the stak 20344887Schin * If <mode> is zero, gets rid of quoting and consider argument as string 20354887Schin * and returns pointer to frozen arg 20364887Schin * If mode==1, just replace $"..." strings with international strings 20374887Schin * The result is left on the stak 20384887Schin * If mode==2, the each $"" string is printed on standard output 20394887Schin */ 20408462SApril.Chin@Sun.COM struct argnod *sh_endword(Shell_t *shp,int mode) 20414887Schin { 20424887Schin register const char *state = sh_lexstates[ST_NESTED]; 20434887Schin register int n; 20444887Schin register char *sp,*dp; 20454887Schin register int inquote=0, inlit=0; /* set within quoted strings */ 20464887Schin struct argnod* argp=0; 20474887Schin char *ep=0, *xp=0; 20484887Schin int bracket=0; 20498462SApril.Chin@Sun.COM Stk_t *stkp=shp->stk; 20508462SApril.Chin@Sun.COM sfputc(stkp,0); 20518462SApril.Chin@Sun.COM sp = stkptr(stkp,ARGVAL); 20524887Schin #if SHOPT_MULTIBYTE 20534887Schin if(mbwide()) 20544887Schin { 20554887Schin do 20564887Schin { 20574887Schin int len; 20584887Schin switch(len = mbsize(sp)) 20594887Schin { 20604887Schin case -1: /* illegal multi-byte char */ 20614887Schin case 0: 20624887Schin case 1: 20634887Schin n=state[*sp++]; 20644887Schin break; 20654887Schin default: 20664887Schin /* 20674887Schin * None of the state tables contain 20684887Schin * entries for multibyte characters, 20694887Schin * however, they should be treated 20704887Schin * the same as any other alph 20714887Schin * character. Therefore, we'll use 20724887Schin * the state of the 'a' character. 20734887Schin */ 20744887Schin n=state['a']; 20754887Schin sp += len; 20764887Schin } 20774887Schin } 20784887Schin while(n == 0); 20794887Schin } 20804887Schin else 20814887Schin #endif /* SHOPT_MULTIBYTE */ 20824887Schin while((n=state[*sp++])==0); 20834887Schin dp = sp; 20844887Schin if(mode<0) 20854887Schin inquote = 1; 20864887Schin while(1) 20874887Schin { 20884887Schin switch(n) 20894887Schin { 20904887Schin case S_EOF: 20918462SApril.Chin@Sun.COM stkseek(stkp,dp-stkptr(stkp,0)); 20924887Schin if(mode<=0) 20934887Schin { 20948462SApril.Chin@Sun.COM argp = (struct argnod*)stkfreeze(stkp,0); 20954887Schin argp->argflag = ARG_RAW|ARG_QUOTED; 20964887Schin } 20974887Schin return(argp); 20984887Schin case S_LIT: 20994887Schin if(!(inquote&1)) 21004887Schin { 21014887Schin inlit = !inlit; 21024887Schin if(mode==0 || (mode<0 && bracket)) 21034887Schin { 21044887Schin dp--; 21054887Schin if(ep) 21064887Schin { 21074887Schin *dp = 0; 21084887Schin dp = ep+stresc(ep); 21094887Schin } 21104887Schin ep = 0; 21114887Schin } 21124887Schin } 21134887Schin break; 21144887Schin case S_QUOTE: 21154887Schin if(mode<0 && !bracket) 21164887Schin break; 21174887Schin if(!inlit) 21184887Schin { 21194887Schin if(mode<=0) 21204887Schin dp--; 21214887Schin inquote = inquote^1; 21224887Schin if(ep) 21234887Schin { 21244887Schin char *msg; 21254887Schin if(mode==2) 21264887Schin { 21274887Schin sfprintf(sfstdout,"%.*s\n",dp-ep,ep); 21284887Schin ep = 0; 21294887Schin break; 21304887Schin } 21314887Schin *--dp = 0; 21324887Schin #if ERROR_VERSION >= 20000317L 21334887Schin msg = ERROR_translate(0,error_info.id,0,ep); 21344887Schin #else 21354887Schin # if ERROR_VERSION >= 20000101L 21364887Schin msg = ERROR_translate(error_info.id,ep); 21374887Schin # else 21384887Schin msg = ERROR_translate(ep,2); 21394887Schin # endif 21404887Schin #endif 21414887Schin n = strlen(msg); 21424887Schin dp = ep+n; 21434887Schin if(sp-dp <= 1) 21444887Schin { 21458462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp); 21464887Schin dp = sp-1; 21474887Schin ep = dp-n; 21484887Schin } 21494887Schin memmove(ep,msg,n); 21504887Schin *dp++ = '"'; 21514887Schin } 21524887Schin ep = 0; 21534887Schin } 21544887Schin break; 21554887Schin case S_DOL: /* check for $'...' and $"..." */ 21564887Schin if(inlit) 21574887Schin break; 21584887Schin if(*sp==LPAREN || *sp==LBRACE) 21594887Schin { 21604887Schin inquote <<= 1; 21614887Schin break; 21624887Schin } 21634887Schin if(inquote&1) 21644887Schin break; 21654887Schin if(*sp=='\'' || *sp=='"') 21664887Schin { 21674887Schin if(*sp=='"') 21684887Schin inquote |= 1; 21694887Schin else 21704887Schin inlit = 1; 21714887Schin sp++; 21724887Schin if((mode==0||(mode<0&&bracket)) || (inquote&1)) 21734887Schin { 21744887Schin if(mode==2) 21754887Schin ep = dp++; 21764887Schin else if(mode==1) 21774887Schin (ep=dp)[-1] = '"'; 21784887Schin else 21794887Schin ep = --dp; 21804887Schin } 21814887Schin } 21824887Schin break; 21834887Schin case S_ESC: 21844887Schin #if SHOPT_CRNL 21854887Schin if(*sp=='\r' && sp[1]=='\n') 21864887Schin sp++; 21874887Schin #endif /* SHOPT_CRNL */ 21884887Schin if(inlit || mode>0) 21894887Schin { 21904887Schin if(mode<0) 21914887Schin { 21924887Schin if(dp>=sp) 21934887Schin { 21948462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp+1); 21954887Schin dp = sp-2; 21964887Schin } 21974887Schin *dp++ = '\\'; 21984887Schin } 21994887Schin if(ep) 22004887Schin *dp++ = *sp++; 22014887Schin break; 22024887Schin } 22034887Schin n = *sp; 22044887Schin #if SHOPT_DOS 22054887Schin if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0) 22064887Schin break; 22074887Schin #endif /* SHOPT_DOS */ 22084887Schin if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE)) 22094887Schin { 22104887Schin if(n=='\n') 22114887Schin dp--; 22124887Schin else 22134887Schin dp[-1] = n; 22144887Schin sp++; 22154887Schin } 22164887Schin break; 22174887Schin case S_POP: 22184887Schin if(sp[-1]!=RBRACT) 22194887Schin break; 22204887Schin if(!inlit && !(inquote&1)) 22214887Schin { 22224887Schin inquote >>= 1; 22234887Schin if(xp) 22244887Schin dp = sh_checkid(xp,dp); 22254887Schin xp = 0; 22264887Schin if(--bracket<=0 && mode<0) 22274887Schin inquote = 1; 22284887Schin } 22294887Schin else if((inlit||inquote) && mode<0) 22304887Schin { 22314887Schin dp[-1] = '\\'; 22324887Schin if(dp>=sp) 22334887Schin { 22348462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp); 22354887Schin dp = sp-1; 22364887Schin } 22374887Schin *dp++ = ']'; 22384887Schin } 22394887Schin break; 22404887Schin case S_BRACT: 22414887Schin if(dp[-2]=='.') 22424887Schin xp = dp; 22434887Schin if(mode<0) 22444887Schin { 22454887Schin if(inlit || (bracket&&inquote)) 22464887Schin { 22474887Schin dp[-1] = '\\'; 22484887Schin if(dp>=sp) 22494887Schin { 22508462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp); 22514887Schin dp = sp-1; 22524887Schin } 22534887Schin *dp++ = '['; 22544887Schin } 22554887Schin else if(bracket++==0) 22564887Schin inquote = 0; 22574887Schin } 22584887Schin break; 22594887Schin } 22604887Schin #if SHOPT_MULTIBYTE 22614887Schin if(mbwide()) 22624887Schin { 22634887Schin do 22644887Schin { 22654887Schin int len; 22664887Schin switch(len = mbsize(sp)) 22674887Schin { 22684887Schin case -1: /* illegal multi-byte char */ 22694887Schin case 0: 22704887Schin case 1: 22714887Schin n=state[*dp++ = *sp++]; 22724887Schin break; 22734887Schin default: 22744887Schin /* 22754887Schin * None of the state tables contain 22764887Schin * entries for multibyte characters, 22774887Schin * however, they should be treated 22784887Schin * the same as any other alph 22794887Schin * character. Therefore, we'll use 22804887Schin * the state of the 'a' character. 22814887Schin */ 22824887Schin while(len--) 22834887Schin *dp++ = *sp++; 22844887Schin n=state['a']; 22854887Schin } 22864887Schin } 22874887Schin while(n == 0); 22884887Schin } 22894887Schin else 22904887Schin #endif /* SHOPT_MULTIBYTE */ 22914887Schin while((n=state[*dp++ = *sp++])==0); 22924887Schin } 22934887Schin } 22944887Schin 22954887Schin struct alias 22964887Schin { 22974887Schin Sfdisc_t disc; 22984887Schin Namval_t *np; 22994887Schin int nextc; 23004887Schin int line; 23014887Schin char buf[2]; 23024887Schin Lex_t *lp; 23034887Schin }; 23044887Schin 23054887Schin /* 23064887Schin * This code gets called whenever an end of string is found with alias 23074887Schin */ 23084887Schin 23094887Schin #ifndef SF_ATEXIT 23104887Schin # define SF_ATEXIT 0 23114887Schin #endif 23124887Schin /* 23134887Schin * This code gets called whenever an end of string is found with alias 23144887Schin */ 23154887Schin #ifdef SF_BUFCONST 23164887Schin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle) 23174887Schin #else 23184887Schin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle) 23194887Schin #endif 23204887Schin { 23214887Schin register struct alias *ap = (struct alias*)handle; 23224887Schin register Namval_t *np; 23234887Schin register Lex_t *lp; 23244887Schin if(type==0 || type==SF_ATEXIT || !ap) 23254887Schin return(0); 23264887Schin lp = ap->lp; 23274887Schin np = ap->np; 23284887Schin if(type!=SF_READ) 23294887Schin { 23304887Schin if(type==SF_CLOSING) 23314887Schin { 23324887Schin register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC); 23334887Schin if(dp!=handle) 23344887Schin sfdisc(iop,dp); 23354887Schin } 23364887Schin else if(type==SF_FINAL) 23374887Schin free((void*)ap); 23384887Schin goto done; 23394887Schin } 23404887Schin if(ap->nextc) 23414887Schin { 23424887Schin /* if last character is a blank, then next work can be alias */ 23434887Schin register int c = fcpeek(-1); 23444887Schin if(isblank(c)) 23458462SApril.Chin@Sun.COM lp->aliasok = 1; 23464887Schin *ap->buf = ap->nextc; 23474887Schin ap->nextc = 0; 23484887Schin sfsetbuf(iop,ap->buf,1); 23494887Schin return(1); 23504887Schin } 23514887Schin done: 23524887Schin if(np) 23534887Schin nv_offattr(np,NV_NOEXPAND); 23544887Schin return(0); 23554887Schin } 23564887Schin 23574887Schin 23584887Schin static void setupalias(Lex_t *lp, const char *string,Namval_t *np) 23594887Schin { 23604887Schin register Sfio_t *iop, *base; 23614887Schin struct alias *ap = (struct alias*)malloc(sizeof(struct alias)); 23624887Schin ap->disc = alias_disc; 23634887Schin ap->lp = lp; 23644887Schin ap->buf[1] = 0; 23654887Schin if(ap->np = np) 23664887Schin { 23674887Schin #if SHOPT_KIA 23688462SApril.Chin@Sun.COM if(lp->kiafile) 23694887Schin { 23704887Schin unsigned long r; 23718462SApril.Chin@Sun.COM r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,""); 23728462SApril.Chin@Sun.COM sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno); 23734887Schin } 23744887Schin #endif /* SHOPT_KIA */ 23754887Schin if((ap->nextc=fcget())==0) 23764887Schin ap->nextc = ' '; 23774887Schin } 23784887Schin else 23794887Schin ap->nextc = 0; 23804887Schin iop = sfopen(NIL(Sfio_t*),(char*)string,"s"); 23814887Schin sfdisc(iop, &ap->disc); 23828462SApril.Chin@Sun.COM lp->lexd.nocopy++; 23834887Schin if(!(base=fcfile())) 23844887Schin base = sfopen(NIL(Sfio_t*),fcseek(0),"s"); 23854887Schin fcclose(); 23864887Schin sfstack(base,iop); 23874887Schin fcfopen(base); 23888462SApril.Chin@Sun.COM lp->lexd.nocopy--; 23894887Schin } 23904887Schin 23914887Schin /* 23924887Schin * grow storage stack for nested constructs by STACK_ARRAY 23934887Schin */ 23944887Schin static int stack_grow(Lex_t *lp) 23954887Schin { 23968462SApril.Chin@Sun.COM lp->lexd.lex_max += STACK_ARRAY; 23978462SApril.Chin@Sun.COM if(lp->lexd.lex_match) 23988462SApril.Chin@Sun.COM lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max); 23994887Schin else 24008462SApril.Chin@Sun.COM lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY); 24018462SApril.Chin@Sun.COM return(lp->lexd.lex_match!=0); 24024887Schin } 24034887Schin 2404