14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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; 1034887Schin #if SHOPT_KIA 1044887Schin off_t kiaoff; 1054887Schin #endif 1064887Schin }; 1074887Schin 1084887Schin #define _SHLEX_PRIVATE \ 109*8462SApril.Chin@Sun.COM struct lexdata lexd; \ 110*8462SApril.Chin@Sun.COM struct lexstate lex; 1114887Schin 1124887Schin #include "shlex.h" 1134887Schin 1144887Schin 115*8462SApril.Chin@Sun.COM #define pushlevel(lp,c,s) ((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\ 116*8462SApril.Chin@Sun.COM ((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\ 117*8462SApril.Chin@Sun.COM lp->lexd.lastc=(((s)<<CHAR_BIT)|(c)))) 118*8462SApril.Chin@Sun.COM #define oldmode(lp) (lp->lexd.lastc>>CHAR_BIT) 119*8462SApril.Chin@Sun.COM #define endchar(lp) (lp->lexd.lastc&0xff) 120*8462SApril.Chin@Sun.COM #define setchar(lp,c) (lp->lexd.lastc = ((lp->lexd.lastc&~0xff)|(c))) 121*8462SApril.Chin@Sun.COM #define poplevel(lp) (lp->lexd.lastc=lp->lexd.lex_match[--lp->lexd.level]) 1224887Schin 1234887Schin static char *fmttoken(Lex_t*, int, char*); 1244887Schin #ifdef SF_BUFCONST 1254887Schin static int alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*); 1264887Schin #else 1274887Schin static int alias_exceptf(Sfio_t*, int, Sfdisc_t*); 1284887Schin #endif 1294887Schin static void setupalias(Lex_t*,const char*, Namval_t*); 130*8462SApril.Chin@Sun.COM static int comsub(Lex_t*,int); 1314887Schin static void nested_here(Lex_t*); 1324887Schin static int here_copy(Lex_t*, struct ionod*); 1334887Schin static int stack_grow(Lex_t*); 1344887Schin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL }; 1354887Schin 1364887Schin #if SHOPT_KIA 1374887Schin 138*8462SApril.Chin@Sun.COM static void refvar(Lex_t *lp, int type) 1394887Schin { 140*8462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh; 141*8462SApril.Chin@Sun.COM register Stk_t *stkp = shp->stk; 142*8462SApril.Chin@Sun.COM off_t off = (fcseek(0)-(type+1))-(lp->lexd.first?lp->lexd.first:fcfirst()); 1434887Schin unsigned long r; 144*8462SApril.Chin@Sun.COM if(lp->lexd.first) 1454887Schin { 146*8462SApril.Chin@Sun.COM off = (fcseek(0)-(type+1)) - lp->lexd.first; 147*8462SApril.Chin@Sun.COM r=kiaentity(lp,lp->lexd.first+lp->lexd.kiaoff+type,off-lp->lexd.kiaoff,'v',-1,-1,lp->current,'v',0,""); 1484887Schin } 1494887Schin else 1504887Schin { 151*8462SApril.Chin@Sun.COM int n,offset = stktell(stkp); 1524887Schin char *savptr,*begin; 1534887Schin off = offset + (fcseek(0)-(type+1)) - fcfirst(); 154*8462SApril.Chin@Sun.COM if(lp->lexd.kiaoff < offset) 1554887Schin { 1564887Schin /* variable starts on stak, copy remainder */ 1574887Schin if(off>offset) 158*8462SApril.Chin@Sun.COM sfwrite(stkp,fcfirst()+type,off-offset); 159*8462SApril.Chin@Sun.COM n = stktell(stkp)-lp->lexd.kiaoff; 160*8462SApril.Chin@Sun.COM begin = stkptr(stkp,lp->lexd.kiaoff); 1614887Schin } 1624887Schin else 1634887Schin { 1644887Schin /* variable in data buffer */ 165*8462SApril.Chin@Sun.COM begin = fcfirst()+(type+lp->lexd.kiaoff-offset); 166*8462SApril.Chin@Sun.COM n = off-lp->lexd.kiaoff; 1674887Schin } 168*8462SApril.Chin@Sun.COM savptr = stkfreeze(stkp,0); 169*8462SApril.Chin@Sun.COM r=kiaentity(lp,begin,n,'v',-1,-1,lp->current,'v',0,""); 170*8462SApril.Chin@Sun.COM stkset(stkp,savptr,offset); 1714887Schin } 172*8462SApril.Chin@Sun.COM sfprintf(lp->kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",lp->current,r,shp->inlineno,shp->inlineno); 1734887Schin } 1744887Schin #endif /* SHOPT_KIA */ 1754887Schin 1764887Schin /* 1774887Schin * This routine gets called when reading across a buffer boundary 1784887Schin * If lexd.nocopy is off, then current token is saved on the stack 1794887Schin */ 180*8462SApril.Chin@Sun.COM static void lex_advance(Sfio_t *iop, const char *buff, register int size, void *context) 1814887Schin { 182*8462SApril.Chin@Sun.COM register Lex_t *lp = (Lex_t*)context; 183*8462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh; 184*8462SApril.Chin@Sun.COM register Sfio_t *log= shp->funlog; 185*8462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 1864887Schin #if KSHELL 1874887Schin /* write to history file and to stderr if necessary */ 1884887Schin if(iop && !sfstacked(iop)) 1894887Schin { 1904887Schin if(sh_isstate(SH_HISTORY) && shp->hist_ptr) 1914887Schin log = shp->hist_ptr->histfp; 1924887Schin sfwrite(log, (void*)buff, size); 1934887Schin if(sh_isstate(SH_VERBOSE)) 1944887Schin sfwrite(sfstderr, buff, size); 1954887Schin } 1964887Schin #endif 197*8462SApril.Chin@Sun.COM if(lp->lexd.nocopy) 1984887Schin return; 199*8462SApril.Chin@Sun.COM if(lp->lexd.first) 2004887Schin { 201*8462SApril.Chin@Sun.COM size -= (lp->lexd.first-(char*)buff); 202*8462SApril.Chin@Sun.COM buff = lp->lexd.first; 203*8462SApril.Chin@Sun.COM if(!lp->lexd.noarg) 204*8462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkseek(stkp,ARGVAL); 2054887Schin #if SHOPT_KIA 206*8462SApril.Chin@Sun.COM lp->lexd.kiaoff += ARGVAL; 2074887Schin #endif /* SHOPT_KIA */ 2084887Schin } 209*8462SApril.Chin@Sun.COM if(size>0 && (lp->arg||lp->lexd.noarg)) 2104887Schin { 211*8462SApril.Chin@Sun.COM sfwrite(stkp,buff,size); 212*8462SApril.Chin@Sun.COM lp->lexd.first = 0; 2134887Schin } 2144887Schin } 2154887Schin 2164887Schin /* 2174887Schin * fill up another input buffer 2184887Schin * preserves lexical state 2194887Schin */ 220*8462SApril.Chin@Sun.COM static int lexfill(Lex_t *lp) 2214887Schin { 2224887Schin register int c; 223*8462SApril.Chin@Sun.COM Lex_t savelex; 2244887Schin struct argnod *ap; 2254887Schin int aok; 226*8462SApril.Chin@Sun.COM savelex = *lp; 227*8462SApril.Chin@Sun.COM ap = lp->arg; 2284887Schin c = fcfill(); 2294887Schin if(ap) 230*8462SApril.Chin@Sun.COM lp->arg = ap; 231*8462SApril.Chin@Sun.COM lp->lex = savelex.lex; 232*8462SApril.Chin@Sun.COM lp->lexd = savelex.lexd; 233*8462SApril.Chin@Sun.COM if(fcfile() || c) 234*8462SApril.Chin@Sun.COM lp->lexd.first = 0; 235*8462SApril.Chin@Sun.COM aok= lp->aliasok; 236*8462SApril.Chin@Sun.COM ap = lp->arg; 237*8462SApril.Chin@Sun.COM memcpy(lp, &savelex, offsetof(Lex_t,lexd)); 238*8462SApril.Chin@Sun.COM lp->arg = ap; 239*8462SApril.Chin@Sun.COM lp->aliasok = aok; 2404887Schin return(c); 2414887Schin } 2424887Schin 2434887Schin /* 2444887Schin * mode=1 for reinitialization 2454887Schin */ 2464887Schin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode) 2474887Schin { 2484887Schin if(!lp) 2494887Schin { 2504887Schin lp = (Lex_t*)newof(0,Lex_t,1,0); 251*8462SApril.Chin@Sun.COM lp->sh = sp; 2524887Schin } 253*8462SApril.Chin@Sun.COM fcnotify(lex_advance,lp); 254*8462SApril.Chin@Sun.COM lp->lex.intest = lp->lex.incase = lp->lex.skipword = lp->lexd.warn = 0; 255*8462SApril.Chin@Sun.COM lp->comp_assign = 0; 256*8462SApril.Chin@Sun.COM lp->lex.reservok = 1; 2574887Schin if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC)) 258*8462SApril.Chin@Sun.COM lp->lexd.warn=1; 2594887Schin if(!mode) 2604887Schin { 261*8462SApril.Chin@Sun.COM lp->lexd.noarg = lp->lexd.level= lp->lexd.dolparen = lp->lexd.balance = 0; 262*8462SApril.Chin@Sun.COM lp->lexd.nocopy = lp->lexd.docword = lp->lexd.nest = lp->lexd.paren = 0; 2634887Schin } 264*8462SApril.Chin@Sun.COM lp->comsub = 0; 2654887Schin return(lp); 2664887Schin } 2674887Schin 2684887Schin #ifdef DBUG 269*8462SApril.Chin@Sun.COM extern int lextoken(Lex_t*); 270*8462SApril.Chin@Sun.COM int sh_lex(Lex_t *lp) 2714887Schin { 272*8462SApril.Chin@Sun.COM Shell_t *shp = lp->sh; 2734887Schin register int flag; 2744887Schin char *quoted, *macro, *split, *expand; 2754887Schin char tokstr[3]; 2764887Schin register int tok = lextoken(); 2774887Schin quoted = macro = split = expand = ""; 278*8462SApril.Chin@Sun.COM if(tok==0 && (flag=lp->arg->argflag)) 2794887Schin { 2804887Schin if(flag&ARG_MAC) 2814887Schin macro = "macro:"; 2824887Schin if(flag&ARG_EXP) 2834887Schin expand = "expand:"; 2844887Schin if(flag&ARG_QUOTED) 2854887Schin quoted = "quoted:"; 2864887Schin } 2874887Schin sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted, 2884887Schin macro, split, expand, fmttoken(lp,tok,tokstr)); 2894887Schin return(tok); 2904887Schin } 2914887Schin #define sh_lex lextoken 2924887Schin #endif 2934887Schin 2944887Schin /* 2954887Schin * Get the next word and put it on the top of the stak 296*8462SApril.Chin@Sun.COM * A pointer to the current word is stored in lp->arg 2974887Schin * Returns the token type 2984887Schin */ 299*8462SApril.Chin@Sun.COM int sh_lex(Lex_t* lp) 3004887Schin { 301*8462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh; 3024887Schin register const char *state; 303*8462SApril.Chin@Sun.COM register int n, c, mode=ST_BEGIN, wordflags=0; 304*8462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 305*8462SApril.Chin@Sun.COM int inlevel=lp->lexd.level, assignment=0, ingrave=0; 3064887Schin Sfio_t *sp; 3074887Schin #if SHOPT_MULTIBYTE 3084887Schin LEN=1; 3094887Schin #endif /* SHOPT_MULTIBYTE */ 310*8462SApril.Chin@Sun.COM if(lp->lexd.paren) 3114887Schin { 312*8462SApril.Chin@Sun.COM lp->lexd.paren = 0; 313*8462SApril.Chin@Sun.COM return(lp->token=LPAREN); 3144887Schin } 315*8462SApril.Chin@Sun.COM if(lp->lex.incase) 316*8462SApril.Chin@Sun.COM lp->assignok = 0; 3174887Schin else 318*8462SApril.Chin@Sun.COM lp->assignok |= lp->lex.reservok; 319*8462SApril.Chin@Sun.COM if(lp->comp_assign==2) 320*8462SApril.Chin@Sun.COM lp->comp_assign = lp->lex.reservok = 0; 321*8462SApril.Chin@Sun.COM lp->lexd.arith = (lp->lexd.nest==1); 322*8462SApril.Chin@Sun.COM if(lp->lexd.nest) 3234887Schin { 324*8462SApril.Chin@Sun.COM pushlevel(lp,lp->lexd.nest,ST_NONE); 325*8462SApril.Chin@Sun.COM lp->lexd.nest = 0; 326*8462SApril.Chin@Sun.COM mode = lp->lexd.lex_state; 3274887Schin } 328*8462SApril.Chin@Sun.COM else if(lp->lexd.docword) 3294887Schin { 3304887Schin if(fcgetc(c)=='-' || c=='#') 3314887Schin { 332*8462SApril.Chin@Sun.COM lp->lexd.docword++; 333*8462SApril.Chin@Sun.COM lp->digits=(c=='#'?3:1); 3344887Schin } 3354887Schin else if(c=='<') 3364887Schin { 337*8462SApril.Chin@Sun.COM lp->digits=2; 338*8462SApril.Chin@Sun.COM lp->lexd.docword=0; 3394887Schin } 3404887Schin else if(c>0) 3414887Schin fcseek(-1); 3424887Schin } 343*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 3444887Schin { 345*8462SApril.Chin@Sun.COM lp->arg = 0; 3464887Schin if(mode!=ST_BEGIN) 347*8462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0); 3484887Schin else 349*8462SApril.Chin@Sun.COM lp->lexd.first = 0; 3504887Schin } 351*8462SApril.Chin@Sun.COM lp->lastline = lp->sh->inlineno; 3524887Schin while(1) 3534887Schin { 3544887Schin /* skip over characters in the current state */ 3554887Schin state = sh_lexstates[mode]; 3564887Schin while((n=STATE(state,c))==0); 3574887Schin switch(n) 3584887Schin { 3594887Schin case S_BREAK: 3604887Schin fcseek(-1); 3614887Schin goto breakloop; 3624887Schin case S_EOF: 3634887Schin sp = fcfile(); 364*8462SApril.Chin@Sun.COM if((n=lexfill(lp)) > 0) 3654887Schin { 3664887Schin fcseek(-1); 3674887Schin continue; 3684887Schin } 3694887Schin /* check for zero byte in file */ 3704887Schin if(n==0 && fcfile()) 3714887Schin { 3724887Schin if(shp->readscript) 3734887Schin { 3744887Schin char *cp = error_info.id; 3754887Schin errno = ENOEXEC; 3764887Schin error_info.id = shp->readscript; 3774887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp); 3784887Schin } 3794887Schin else 3804887Schin { 381*8462SApril.Chin@Sun.COM lp->token = -1; 382*8462SApril.Chin@Sun.COM sh_syntax(lp); 3834887Schin } 3844887Schin } 3854887Schin /* end-of-file */ 3864887Schin if(mode==ST_BEGIN) 387*8462SApril.Chin@Sun.COM return(lp->token=EOFSYM); 388*8462SApril.Chin@Sun.COM if(mode >ST_NORM && lp->lexd.level>0) 3894887Schin { 390*8462SApril.Chin@Sun.COM switch(c=endchar(lp)) 3914887Schin { 3924887Schin case '$': 3934887Schin if(mode==ST_LIT) 3944887Schin { 3954887Schin c = '\''; 3964887Schin break; 3974887Schin } 398*8462SApril.Chin@Sun.COM mode = oldmode(lp); 399*8462SApril.Chin@Sun.COM poplevel(lp); 4004887Schin continue; 4014887Schin case RBRACT: 4024887Schin c = LBRACT; 4034887Schin break; 4044887Schin case 1: /* for ((...)) */ 4054887Schin case RPAREN: 4064887Schin c = LPAREN; 4074887Schin break; 4084887Schin default: 4094887Schin c = LBRACE; 4104887Schin break; 4114887Schin case '"': case '`': case '\'': 412*8462SApril.Chin@Sun.COM lp->lexd.balance = c; 4134887Schin break; 4144887Schin } 4154887Schin if(sp && !(sfset(sp,0,0)&SF_STRING)) 4164887Schin { 417*8462SApril.Chin@Sun.COM lp->lasttok = c; 418*8462SApril.Chin@Sun.COM lp->token = EOFSYM; 419*8462SApril.Chin@Sun.COM sh_syntax(lp); 4204887Schin } 421*8462SApril.Chin@Sun.COM lp->lexd.balance = c; 4224887Schin } 4234887Schin goto breakloop; 4244887Schin case S_COM: 4254887Schin /* skip one or more comment line(s) */ 426*8462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest; 427*8462SApril.Chin@Sun.COM if((n=lp->lexd.nocopy) && lp->lexd.dolparen) 428*8462SApril.Chin@Sun.COM lp->lexd.nocopy--; 4294887Schin do 4304887Schin { 4314887Schin while(fcgetc(c)>0 && c!='\n'); 432*8462SApril.Chin@Sun.COM if(c<=0 || lp->heredoc) 4334887Schin break; 4344887Schin while(shp->inlineno++,fcpeek(0)=='\n') 4354887Schin fcseek(1); 4364887Schin while(state[c=fcpeek(0)]==0) 4374887Schin fcseek(1); 4384887Schin } 4394887Schin while(c=='#'); 440*8462SApril.Chin@Sun.COM lp->lexd.nocopy = n; 4414887Schin if(c<0) 442*8462SApril.Chin@Sun.COM return(lp->token=EOFSYM); 4434887Schin n = S_NLTOK; 4444887Schin shp->inlineno--; 4454887Schin /* FALL THRU */ 4464887Schin case S_NLTOK: 4474887Schin /* check for here-document */ 448*8462SApril.Chin@Sun.COM if(lp->heredoc) 4494887Schin { 450*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 451*8462SApril.Chin@Sun.COM lp->lexd.nocopy++; 4524887Schin c = shp->inlineno; 453*8462SApril.Chin@Sun.COM if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok) 4544887Schin { 455*8462SApril.Chin@Sun.COM lp->lasttok = IODOCSYM; 456*8462SApril.Chin@Sun.COM lp->token = EOFSYM; 457*8462SApril.Chin@Sun.COM lp->lastline = c; 458*8462SApril.Chin@Sun.COM sh_syntax(lp); 4594887Schin } 460*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 461*8462SApril.Chin@Sun.COM lp->lexd.nocopy--; 462*8462SApril.Chin@Sun.COM lp->heredoc = 0; 4634887Schin } 464*8462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest; 465*8462SApril.Chin@Sun.COM lp->lex.skipword = 0; 4664887Schin /* FALL THRU */ 4674887Schin case S_NL: 4684887Schin /* skip over new-lines */ 469*8462SApril.Chin@Sun.COM lp->lex.last_quote = 0; 4704887Schin while(shp->inlineno++,fcget()=='\n'); 4714887Schin fcseek(-1); 4724887Schin if(n==S_NLTOK) 4734887Schin { 474*8462SApril.Chin@Sun.COM lp->comp_assign = 0; 475*8462SApril.Chin@Sun.COM return(lp->token='\n'); 4764887Schin } 4774887Schin case S_BLNK: 478*8462SApril.Chin@Sun.COM if(lp->lex.incase<=TEST_RE) 4794887Schin continue; 4804887Schin /* implicit RPAREN for =~ test operator */ 481*8462SApril.Chin@Sun.COM if(inlevel+1==lp->lexd.level) 4824887Schin { 483*8462SApril.Chin@Sun.COM if(lp->lex.intest) 484*8462SApril.Chin@Sun.COM fcseek(-1); 4854887Schin c = RPAREN; 4864887Schin goto do_pop; 4874887Schin } 4884887Schin continue; 4894887Schin case S_OP: 4904887Schin /* return operator token */ 4914887Schin if(c=='<' || c=='>') 4924887Schin { 493*8462SApril.Chin@Sun.COM if(lp->lex.testop2) 494*8462SApril.Chin@Sun.COM lp->lex.testop2 = 0; 4954887Schin else 4964887Schin { 497*8462SApril.Chin@Sun.COM lp->digits = (c=='>'); 498*8462SApril.Chin@Sun.COM lp->lex.skipword = 1; 499*8462SApril.Chin@Sun.COM lp->aliasok = lp->lex.reservok; 500*8462SApril.Chin@Sun.COM lp->lex.reservok = 0; 5014887Schin } 5024887Schin } 5034887Schin else 5044887Schin { 505*8462SApril.Chin@Sun.COM lp->lex.reservok = !lp->lex.intest; 5064887Schin if(c==RPAREN) 5074887Schin { 508*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 509*8462SApril.Chin@Sun.COM lp->lex.incase = 0; 510*8462SApril.Chin@Sun.COM return(lp->token=c); 5114887Schin } 512*8462SApril.Chin@Sun.COM lp->lex.testop1 = lp->lex.intest; 5134887Schin } 5144887Schin if(fcgetc(n)>0) 5154887Schin fcseek(-1); 5164887Schin if(state[n]==S_OP || n=='#') 5174887Schin { 5184887Schin if(n==c) 5194887Schin { 5204887Schin if(c=='<') 521*8462SApril.Chin@Sun.COM lp->lexd.docword=1; 5224887Schin else if(n==LPAREN) 5234887Schin { 524*8462SApril.Chin@Sun.COM lp->lexd.nest=1; 525*8462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 526*8462SApril.Chin@Sun.COM lp->lexd.lex_state = ST_NESTED; 5274887Schin fcseek(1); 528*8462SApril.Chin@Sun.COM return(sh_lex(lp)); 5294887Schin } 5304887Schin c |= SYMREP; 5314887Schin } 5324887Schin else if(c=='(' || c==')') 533*8462SApril.Chin@Sun.COM return(lp->token=c); 5344887Schin else if(c=='&') 5354887Schin { 5364887Schin #if SHOPT_BASH 5374887Schin if(!sh_isoption(SH_POSIX) && n=='>') 5384887Schin { 539*8462SApril.Chin@Sun.COM lp->digits = -1; 5404887Schin c = '>'; 5414887Schin } 5424887Schin else 5434887Schin #endif 5444887Schin n = 0; 5454887Schin } 5464887Schin else if(n=='&') 5474887Schin c |= SYMAMP; 5484887Schin else if(c!='<' && c!='>') 5494887Schin n = 0; 5504887Schin else if(n==LPAREN) 5514887Schin { 5524887Schin c |= SYMLPAR; 553*8462SApril.Chin@Sun.COM lp->lex.reservok = 1; 554*8462SApril.Chin@Sun.COM lp->lex.skipword = 0; 5554887Schin } 5564887Schin else if(n=='|') 5574887Schin c |= SYMPIPE; 5584887Schin else if(c=='<' && n=='>') 5594887Schin c = IORDWRSYM; 5604887Schin else if(n=='#' && (c=='<'||c=='>')) 5614887Schin c |= SYMSHARP; 562*8462SApril.Chin@Sun.COM else if(n==';' && c=='>') 563*8462SApril.Chin@Sun.COM { 564*8462SApril.Chin@Sun.COM c |= SYMSEMI; 565*8462SApril.Chin@Sun.COM if(lp->inexec) 566*8462SApril.Chin@Sun.COM { 567*8462SApril.Chin@Sun.COM lp->token = c; 568*8462SApril.Chin@Sun.COM sh_syntax(lp); 569*8462SApril.Chin@Sun.COM } 570*8462SApril.Chin@Sun.COM } 5714887Schin else 5724887Schin n = 0; 5734887Schin if(n) 5744887Schin { 5754887Schin fcseek(1); 576*8462SApril.Chin@Sun.COM lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM); 5774887Schin } 5784887Schin else 5794887Schin { 580*8462SApril.Chin@Sun.COM if((n=fcpeek(0))!=RPAREN && n!=LPAREN && lp->lexd.warn) 5814887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n); 5824887Schin } 5834887Schin } 584*8462SApril.Chin@Sun.COM if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase) 585*8462SApril.Chin@Sun.COM lp->comp_assign = 2; 5864887Schin else 587*8462SApril.Chin@Sun.COM lp->comp_assign = 0; 588*8462SApril.Chin@Sun.COM return(lp->token=c); 5894887Schin case S_ESC: 5904887Schin /* check for \<new-line> */ 5914887Schin fcgetc(n); 5924887Schin c=2; 5934887Schin #if SHOPT_CRNL 5944887Schin if(n=='\r') 5954887Schin { 5964887Schin if(fcgetc(n)=='\n') 5974887Schin c=3; 5984887Schin else 5994887Schin { 6004887Schin n='\r'; 6014887Schin fcseek(-1); 6024887Schin } 6034887Schin } 6044887Schin #endif /* SHOPT_CRNL */ 6054887Schin if(n=='\n') 6064887Schin { 6074887Schin Sfio_t *sp; 6084887Schin struct argnod *ap; 6094887Schin shp->inlineno++; 6104887Schin /* synchronize */ 6114887Schin if(!(sp=fcfile())) 6124887Schin state=fcseek(0); 6134887Schin fcclose(); 614*8462SApril.Chin@Sun.COM ap = lp->arg; 6154887Schin if(sp) 6164887Schin fcfopen(sp); 6174887Schin else 6184887Schin fcsopen((char*)state); 6194887Schin /* remove \new-line */ 620*8462SApril.Chin@Sun.COM n = stktell(stkp)-c; 621*8462SApril.Chin@Sun.COM stkseek(stkp,n); 622*8462SApril.Chin@Sun.COM lp->arg = ap; 6234887Schin if(n<=ARGVAL) 6244887Schin { 6254887Schin mode = 0; 626*8462SApril.Chin@Sun.COM lp->lexd.first = 0; 6274887Schin } 6284887Schin continue; 6294887Schin } 6304887Schin wordflags |= ARG_QUOTED; 6314887Schin if(mode==ST_DOL) 6324887Schin goto err; 6334887Schin #ifndef STR_MAXIMAL 634*8462SApril.Chin@Sun.COM else if(mode==ST_NESTED && lp->lexd.warn && 635*8462SApril.Chin@Sun.COM endchar(lp)==RBRACE && 6364887Schin sh_lexstates[ST_DOL][n]==S_DIG 6374887Schin ) 6384887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n); 6394887Schin #endif /* STR_MAXIMAL */ 6404887Schin break; 6414887Schin case S_NAME: 642*8462SApril.Chin@Sun.COM if(!lp->lex.skipword) 643*8462SApril.Chin@Sun.COM lp->lex.reservok *= 2; 6444887Schin /* FALL THRU */ 6454887Schin case S_TILDE: 6464887Schin case S_RES: 647*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 648*8462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0)-LEN; 649*8462SApril.Chin@Sun.COM else if(lp->lexd.docword) 650*8462SApril.Chin@Sun.COM lp->lexd.docend = fcseek(0)-LEN; 6514887Schin mode = ST_NAME; 6524887Schin if(c=='.') 6534887Schin fcseek(-1); 6544887Schin if(n!=S_TILDE) 6554887Schin continue; 6564887Schin fcgetc(n); 6574887Schin if(n>0) 658*8462SApril.Chin@Sun.COM { 659*8462SApril.Chin@Sun.COM if(c=='~' && n==LPAREN && lp->lex.incase) 660*8462SApril.Chin@Sun.COM lp->lex.incase = TEST_RE; 6614887Schin fcseek(-1); 662*8462SApril.Chin@Sun.COM } 6634887Schin if(n==LPAREN) 6644887Schin goto epat; 6654887Schin wordflags = ARG_MAC; 6664887Schin mode = ST_NORM; 6674887Schin continue; 6684887Schin case S_REG: 6694887Schin if(mode==ST_BEGIN) 6704887Schin { 671*8462SApril.Chin@Sun.COM do_reg: 6724887Schin /* skip new-line joining */ 6734887Schin if(c=='\\' && fcpeek(0)=='\n') 6744887Schin { 6754887Schin shp->inlineno++; 6764887Schin fcseek(1); 6774887Schin continue; 6784887Schin } 6794887Schin fcseek(-1); 680*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 681*8462SApril.Chin@Sun.COM lp->lexd.first = fcseek(0); 682*8462SApril.Chin@Sun.COM else if(lp->lexd.docword) 683*8462SApril.Chin@Sun.COM lp->lexd.docend = fcseek(0); 684*8462SApril.Chin@Sun.COM if(c=='[' && lp->assignok>=SH_ASSIGN) 6854887Schin { 6864887Schin mode = ST_NAME; 6874887Schin continue; 6884887Schin } 6894887Schin } 6904887Schin mode = ST_NORM; 6914887Schin continue; 6924887Schin case S_LIT: 693*8462SApril.Chin@Sun.COM if(oldmode(lp)==ST_NONE && !lp->lexd.noarg) /* in ((...)) */ 6944887Schin { 6954887Schin if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']') 6964887Schin { 6974887Schin if(fcpeek(1)=='\'') 6984887Schin fcseek(2); 6994887Schin } 7004887Schin continue; 7014887Schin } 7024887Schin wordflags |= ARG_QUOTED; 7034887Schin if(mode==ST_DOL) 7044887Schin { 705*8462SApril.Chin@Sun.COM if(endchar(lp)!='$') 7064887Schin goto err; 707*8462SApril.Chin@Sun.COM if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */ 7084887Schin { 709*8462SApril.Chin@Sun.COM if(lp->lexd.warn) 7104887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno); 7114887Schin mode = ST_LIT; 7124887Schin } 7134887Schin } 7144887Schin if(mode!=ST_LIT) 7154887Schin { 716*8462SApril.Chin@Sun.COM if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline) 717*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote); 718*8462SApril.Chin@Sun.COM lp->lex.last_quote = 0; 719*8462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 7204887Schin if(mode!=ST_DOL) 721*8462SApril.Chin@Sun.COM pushlevel(lp,'\'',mode); 7224887Schin mode = ST_LIT; 7234887Schin continue; 7244887Schin } 7254887Schin /* check for multi-line single-quoted string */ 726*8462SApril.Chin@Sun.COM else if(shp->inlineno > lp->lastline) 727*8462SApril.Chin@Sun.COM lp->lex.last_quote = '\''; 728*8462SApril.Chin@Sun.COM mode = oldmode(lp); 729*8462SApril.Chin@Sun.COM poplevel(lp); 7304887Schin break; 7314887Schin case S_ESC2: 7324887Schin /* \ inside '' */ 733*8462SApril.Chin@Sun.COM if(endchar(lp)=='$') 7344887Schin { 7354887Schin fcgetc(n); 7364887Schin if(n=='\n') 7374887Schin shp->inlineno++; 7384887Schin } 7394887Schin continue; 7404887Schin case S_GRAVE: 741*8462SApril.Chin@Sun.COM if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`')) 7424887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno); 7434887Schin wordflags |=(ARG_MAC|ARG_EXP); 7444887Schin if(mode==ST_QUOTE) 7454887Schin ingrave = !ingrave; 7464887Schin /* FALL THRU */ 7474887Schin case S_QUOTE: 748*8462SApril.Chin@Sun.COM if(oldmode(lp)==ST_NONE && lp->lexd.arith) /* in ((...)) */ 749*8462SApril.Chin@Sun.COM { 750*8462SApril.Chin@Sun.COM if(n!=S_GRAVE || fcpeek(0)=='\'') 751*8462SApril.Chin@Sun.COM continue; 752*8462SApril.Chin@Sun.COM } 7534887Schin if(n==S_QUOTE) 7544887Schin wordflags |=ARG_QUOTED; 7554887Schin if(mode!=ST_QUOTE) 7564887Schin { 7574887Schin if(c!='"' || mode!=ST_QNEST) 7584887Schin { 759*8462SApril.Chin@Sun.COM if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline) 760*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote); 761*8462SApril.Chin@Sun.COM lp->lex.last_quote=0; 762*8462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 763*8462SApril.Chin@Sun.COM pushlevel(lp,c,mode); 7644887Schin } 7654887Schin ingrave = (c=='`'); 7664887Schin mode = ST_QUOTE; 7674887Schin continue; 7684887Schin } 769*8462SApril.Chin@Sun.COM else if((n=endchar(lp))==c) 7704887Schin { 771*8462SApril.Chin@Sun.COM if(shp->inlineno > lp->lastline) 772*8462SApril.Chin@Sun.COM lp->lex.last_quote = c; 773*8462SApril.Chin@Sun.COM mode = oldmode(lp); 774*8462SApril.Chin@Sun.COM poplevel(lp); 7754887Schin } 7764887Schin else if(c=='"' && n==RBRACE) 7774887Schin mode = ST_QNEST; 7784887Schin break; 7794887Schin case S_DOL: 7804887Schin /* don't check syntax inside `` */ 7814887Schin if(mode==ST_QUOTE && ingrave) 7824887Schin continue; 7834887Schin #if SHOPT_KIA 784*8462SApril.Chin@Sun.COM if(lp->lexd.first) 785*8462SApril.Chin@Sun.COM lp->lexd.kiaoff = fcseek(0)-lp->lexd.first; 7864887Schin else 787*8462SApril.Chin@Sun.COM lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst(); 7884887Schin #endif /* SHOPT_KIA */ 789*8462SApril.Chin@Sun.COM pushlevel(lp,'$',mode); 7904887Schin mode = ST_DOL; 7914887Schin continue; 7924887Schin case S_PAR: 793*8462SApril.Chin@Sun.COM do_comsub: 7944887Schin wordflags |= ARG_MAC; 795*8462SApril.Chin@Sun.COM mode = oldmode(lp); 796*8462SApril.Chin@Sun.COM poplevel(lp); 7974887Schin fcseek(-1); 798*8462SApril.Chin@Sun.COM wordflags |= comsub(lp,c); 7994887Schin continue; 8004887Schin case S_RBRA: 801*8462SApril.Chin@Sun.COM if((n=endchar(lp)) == '$') 8024887Schin goto err; 8034887Schin if(mode!=ST_QUOTE || n==RBRACE) 8044887Schin { 805*8462SApril.Chin@Sun.COM mode = oldmode(lp); 806*8462SApril.Chin@Sun.COM poplevel(lp); 8074887Schin } 8084887Schin break; 8094887Schin case S_EDOL: 8104887Schin /* end $identifier */ 8114887Schin #if SHOPT_KIA 812*8462SApril.Chin@Sun.COM if(lp->kiafile) 813*8462SApril.Chin@Sun.COM refvar(lp,0); 8144887Schin #endif /* SHOPT_KIA */ 815*8462SApril.Chin@Sun.COM if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED) 8164887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno); 8174887Schin fcseek(-1); 818*8462SApril.Chin@Sun.COM mode = oldmode(lp); 819*8462SApril.Chin@Sun.COM poplevel(lp); 8204887Schin break; 8214887Schin case S_DOT: 8224887Schin /* make sure next character is alpha */ 8234887Schin if(fcgetc(n)>0) 824*8462SApril.Chin@Sun.COM { 825*8462SApril.Chin@Sun.COM if(n=='.') 826*8462SApril.Chin@Sun.COM fcgetc(n); 827*8462SApril.Chin@Sun.COM if(n>0) 828*8462SApril.Chin@Sun.COM fcseek(-1); 829*8462SApril.Chin@Sun.COM } 8304887Schin if(isaletter(n) || n==LBRACT) 8314887Schin continue; 8324887Schin if(mode==ST_NAME) 8334887Schin { 8344887Schin if(n=='=') 8354887Schin continue; 8364887Schin break; 8374887Schin } 8384887Schin else if(n==RBRACE) 8394887Schin continue; 8404887Schin if(isastchar(n)) 8414887Schin continue; 8424887Schin goto err; 8434887Schin case S_SPC1: 8444887Schin wordflags |= ARG_MAC; 845*8462SApril.Chin@Sun.COM if(endchar(lp)==RBRACE) 8464887Schin { 847*8462SApril.Chin@Sun.COM setchar(lp,c); 8484887Schin continue; 8494887Schin } 8504887Schin /* FALL THRU */ 8514887Schin case S_ALP: 852*8462SApril.Chin@Sun.COM if(c=='.' && endchar(lp)=='$') 8534887Schin goto err; 8544887Schin case S_SPC2: 8554887Schin case S_DIG: 8564887Schin wordflags |= ARG_MAC; 857*8462SApril.Chin@Sun.COM switch(endchar(lp)) 8584887Schin { 8594887Schin case '$': 8604887Schin if(n==S_ALP) /* $identifier */ 8614887Schin mode = ST_DOLNAME; 8624887Schin else 8634887Schin { 864*8462SApril.Chin@Sun.COM mode = oldmode(lp); 865*8462SApril.Chin@Sun.COM poplevel(lp); 8664887Schin } 8674887Schin break; 8684887Schin #if SHOPT_TYPEDEF 8694887Schin case '@': 8704887Schin #endif /* SHOPT_TYPEDEF */ 8714887Schin case '!': 8724887Schin if(n!=S_ALP) 8734887Schin goto dolerr; 8744887Schin case '#': 8754887Schin case RBRACE: 8764887Schin if(n==S_ALP) 8774887Schin { 878*8462SApril.Chin@Sun.COM setchar(lp,RBRACE); 8794887Schin if(c=='.') 8804887Schin fcseek(-1); 8814887Schin mode = ST_BRACE; 8824887Schin } 8834887Schin else 8844887Schin { 8854887Schin if(fcgetc(c)>0) 8864887Schin fcseek(-1); 8874887Schin if(state[c]==S_ALP) 8884887Schin goto err; 8894887Schin if(n==S_DIG) 890*8462SApril.Chin@Sun.COM setchar(lp,'0'); 8914887Schin else 892*8462SApril.Chin@Sun.COM setchar(lp,'!'); 8934887Schin } 8944887Schin break; 8954887Schin case '0': 8964887Schin if(n==S_DIG) 8974887Schin break; 8984887Schin default: 8994887Schin goto dolerr; 9004887Schin } 9014887Schin break; 9024887Schin dolerr: 9034887Schin case S_ERR: 904*8462SApril.Chin@Sun.COM if((n=endchar(lp)) == '$') 9054887Schin goto err; 9064887Schin if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2) 9074887Schin { 9084887Schin /* see whether inside `...` */ 909*8462SApril.Chin@Sun.COM mode = oldmode(lp); 910*8462SApril.Chin@Sun.COM poplevel(lp); 911*8462SApril.Chin@Sun.COM if((n = endchar(lp)) != '`') 9124887Schin goto err; 913*8462SApril.Chin@Sun.COM pushlevel(lp,RBRACE,mode); 9144887Schin } 9154887Schin else 916*8462SApril.Chin@Sun.COM setchar(lp,RBRACE); 9174887Schin mode = ST_NESTED; 9184887Schin continue; 9194887Schin case S_MOD1: 920*8462SApril.Chin@Sun.COM if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE) 9214887Schin { 9224887Schin /* allow ' inside "${...}" */ 9234887Schin if(c==':' && fcgetc(n)>0) 9244887Schin { 9254887Schin n = state[n]; 9264887Schin fcseek(-1); 9274887Schin } 9284887Schin if(n==S_MOD1) 9294887Schin { 9304887Schin mode = ST_QUOTE; 9314887Schin continue; 9324887Schin } 9334887Schin } 9344887Schin /* FALL THRU */ 9354887Schin case S_MOD2: 9364887Schin #if SHOPT_KIA 937*8462SApril.Chin@Sun.COM if(lp->kiafile) 938*8462SApril.Chin@Sun.COM refvar(lp,1); 9394887Schin #endif /* SHOPT_KIA */ 9404887Schin if(c!=':' && fcgetc(n)>0) 9414887Schin { 9424887Schin if(n!=c) 9434887Schin c = 0; 9444887Schin if(!c || (fcgetc(n)>0)) 9454887Schin { 9464887Schin fcseek(-1); 9474887Schin if(n==LPAREN) 9484887Schin { 9494887Schin if(c!='%') 9504887Schin { 951*8462SApril.Chin@Sun.COM lp->token = n; 952*8462SApril.Chin@Sun.COM sh_syntax(lp); 9534887Schin } 954*8462SApril.Chin@Sun.COM else if(lp->lexd.warn) 9554887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%'); 9564887Schin } 9574887Schin } 9584887Schin } 9594887Schin mode = ST_NESTED; 9604887Schin continue; 9614887Schin case S_LBRA: 962*8462SApril.Chin@Sun.COM if((c=endchar(lp)) == '$') 9634887Schin { 9644887Schin if(fcgetc(c)>0) 9654887Schin fcseek(-1); 966*8462SApril.Chin@Sun.COM setchar(lp,RBRACE); 9674887Schin if(state[c]!=S_ERR && c!=RBRACE) 9684887Schin continue; 969*8462SApril.Chin@Sun.COM if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK) 970*8462SApril.Chin@Sun.COM { 971*8462SApril.Chin@Sun.COM c = LBRACE; 972*8462SApril.Chin@Sun.COM goto do_comsub; 973*8462SApril.Chin@Sun.COM } 9744887Schin } 9754887Schin err: 976*8462SApril.Chin@Sun.COM n = endchar(lp); 977*8462SApril.Chin@Sun.COM mode = oldmode(lp); 978*8462SApril.Chin@Sun.COM poplevel(lp); 9794887Schin if(n!='$') 9804887Schin { 981*8462SApril.Chin@Sun.COM lp->token = c; 982*8462SApril.Chin@Sun.COM sh_syntax(lp); 9834887Schin } 9844887Schin else 9854887Schin { 986*8462SApril.Chin@Sun.COM if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE)) 9874887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno); 9884887Schin else if(c=='"' && mode!=ST_QUOTE) 9894887Schin wordflags |= ARG_MESSAGE; 9904887Schin fcseek(-1); 9914887Schin } 9924887Schin continue; 9934887Schin case S_META: 994*8462SApril.Chin@Sun.COM if(lp->lexd.warn && endchar(lp)==RBRACE) 9954887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c); 9964887Schin continue; 9974887Schin case S_PUSH: 998*8462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,mode); 9994887Schin mode = ST_NESTED; 10004887Schin continue; 10014887Schin case S_POP: 10024887Schin do_pop: 1003*8462SApril.Chin@Sun.COM if(lp->lexd.level <= inlevel) 10044887Schin break; 1005*8462SApril.Chin@Sun.COM if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest) 1006*8462SApril.Chin@Sun.COM { 1007*8462SApril.Chin@Sun.COM fcseek(-1); 1008*8462SApril.Chin@Sun.COM goto breakloop; 1009*8462SApril.Chin@Sun.COM } 1010*8462SApril.Chin@Sun.COM n = endchar(lp); 10114887Schin if(c==RBRACT && !(n==RBRACT || n==RPAREN)) 10124887Schin continue; 10134887Schin if((c==RBRACE||c==RPAREN) && n==RPAREN) 10144887Schin { 10154887Schin if(fcgetc(n)==LPAREN) 10164887Schin { 10174887Schin if(c!=RPAREN) 10184887Schin fcseek(-1); 10194887Schin continue; 10204887Schin } 10214887Schin if(n>0) 10224887Schin fcseek(-1); 10234887Schin n = RPAREN; 10244887Schin } 10254887Schin if(c==';' && n!=';') 10264887Schin { 1027*8462SApril.Chin@Sun.COM if(lp->lexd.warn && n==RBRACE) 10284887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c); 10294887Schin continue; 10304887Schin } 10314887Schin if(mode==ST_QNEST) 10324887Schin { 1033*8462SApril.Chin@Sun.COM if(lp->lexd.warn) 10344887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c); 10354887Schin continue; 10364887Schin } 1037*8462SApril.Chin@Sun.COM mode = oldmode(lp); 1038*8462SApril.Chin@Sun.COM poplevel(lp); 10394887Schin /* quotes in subscript need expansion */ 10404887Schin if(mode==ST_NAME && (wordflags&ARG_QUOTED)) 10414887Schin wordflags |= ARG_MAC; 10424887Schin /* check for ((...)) */ 10434887Schin if(n==1 && c==RPAREN) 10444887Schin { 10454887Schin if(fcgetc(n)==RPAREN) 10464887Schin { 1047*8462SApril.Chin@Sun.COM if(mode==ST_NONE && !lp->lexd.dolparen) 10484887Schin goto breakloop; 1049*8462SApril.Chin@Sun.COM lp->lex.reservok = 1; 1050*8462SApril.Chin@Sun.COM lp->lex.skipword = 0; 1051*8462SApril.Chin@Sun.COM return(lp->token=EXPRSYM); 10524887Schin } 10534887Schin /* backward compatibility */ 1054*8462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 10554887Schin fcseek(-1); 10564887Schin else 10574887Schin { 1058*8462SApril.Chin@Sun.COM if(lp->lexd.warn) 10594887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno); 1060*8462SApril.Chin@Sun.COM if(!(state=lp->lexd.first)) 10614887Schin state = fcfirst(); 10624887Schin fcseek(state-fcseek(0)); 1063*8462SApril.Chin@Sun.COM if(lp->arg) 10644887Schin { 1065*8462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 1066*8462SApril.Chin@Sun.COM setupalias(lp,lp->arg->argval,NIL(Namval_t*)); 10674887Schin } 1068*8462SApril.Chin@Sun.COM lp->lexd.paren = 1; 10694887Schin } 1070*8462SApril.Chin@Sun.COM return(lp->token=LPAREN); 10714887Schin } 10724887Schin if(mode==ST_NONE) 10734887Schin return(0); 10744887Schin if(c!=n) 10754887Schin { 1076*8462SApril.Chin@Sun.COM lp->token = c; 1077*8462SApril.Chin@Sun.COM sh_syntax(lp); 10784887Schin } 10794887Schin if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM)) 10804887Schin goto epat; 10814887Schin continue; 10824887Schin case S_EQ: 1083*8462SApril.Chin@Sun.COM assignment = lp->assignok; 10844887Schin /* FALL THRU */ 10854887Schin case S_COLON: 10864887Schin if(assignment) 10874887Schin { 10884887Schin if((c=fcget())=='~') 10894887Schin wordflags |= ARG_MAC; 10904887Schin else if(c!=LPAREN && assignment==SH_COMPASSIGN) 10914887Schin assignment = 0; 10924887Schin fcseek(-1); 10934887Schin } 10944887Schin break; 10954887Schin case S_LABEL: 1096*8462SApril.Chin@Sun.COM if(lp->lex.reservok && !lp->lex.incase) 10974887Schin { 10984887Schin c = fcget(); 10994887Schin fcseek(-1); 11004887Schin if(state[c]==S_BREAK) 11014887Schin { 11024887Schin assignment = -1; 11034887Schin goto breakloop; 11044887Schin } 11054887Schin } 11064887Schin break; 11074887Schin case S_BRACT: 11084887Schin /* check for possible subscript */ 1109*8462SApril.Chin@Sun.COM if((n=endchar(lp))==RBRACT || n==RPAREN || 11104887Schin (mode==ST_BRACE) || 1111*8462SApril.Chin@Sun.COM (oldmode(lp)==ST_NONE) || 1112*8462SApril.Chin@Sun.COM (mode==ST_NAME && (lp->assignok||lp->lexd.level))) 11134887Schin { 1114*8462SApril.Chin@Sun.COM pushlevel(lp,RBRACT,mode); 11154887Schin wordflags |= ARG_QUOTED; 11164887Schin mode = ST_NESTED; 11174887Schin continue; 11184887Schin } 11194887Schin wordflags |= ARG_EXP; 11204887Schin break; 11214887Schin case S_BRACE: 11224887Schin { 11234887Schin int isfirst; 1124*8462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 1125*8462SApril.Chin@Sun.COM { 1126*8462SApril.Chin@Sun.COM if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub)) 1127*8462SApril.Chin@Sun.COM { 1128*8462SApril.Chin@Sun.COM fcgetc(n); 1129*8462SApril.Chin@Sun.COM if(n>0) 1130*8462SApril.Chin@Sun.COM fcseek(-1); 1131*8462SApril.Chin@Sun.COM else 1132*8462SApril.Chin@Sun.COM n = '\n'; 1133*8462SApril.Chin@Sun.COM if(n==RBRACT || sh_lexstates[ST_NORM][n]) 1134*8462SApril.Chin@Sun.COM return(lp->token=c); 1135*8462SApril.Chin@Sun.COM } 11364887Schin break; 1137*8462SApril.Chin@Sun.COM } 1138*8462SApril.Chin@Sun.COM else if(mode==ST_BEGIN) 1139*8462SApril.Chin@Sun.COM { 1140*8462SApril.Chin@Sun.COM if(lp->comsub && c==RBRACE) 1141*8462SApril.Chin@Sun.COM return(lp->token=c); 1142*8462SApril.Chin@Sun.COM goto do_reg; 1143*8462SApril.Chin@Sun.COM } 1144*8462SApril.Chin@Sun.COM isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1); 11454887Schin fcgetc(n); 11464887Schin /* check for {} */ 11474887Schin if(c==LBRACE && n==RBRACE) 11484887Schin break; 11494887Schin if(n>0) 11504887Schin fcseek(-1); 1151*8462SApril.Chin@Sun.COM else if(lp->lex.reservok) 11524887Schin break; 11534887Schin /* check for reserved word { or } */ 1154*8462SApril.Chin@Sun.COM if(lp->lex.reservok && state[n]==S_BREAK && isfirst) 11554887Schin break; 11564887Schin if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK 1157*8462SApril.Chin@Sun.COM && !lp->lex.incase && !lp->lex.intest 1158*8462SApril.Chin@Sun.COM && !lp->lex.skipword) 11594887Schin { 11604887Schin wordflags |= ARG_EXP; 11614887Schin } 11624887Schin if(c==RBRACE && n==LPAREN) 11634887Schin goto epat; 11644887Schin break; 11654887Schin } 11664887Schin case S_PAT: 11674887Schin wordflags |= ARG_EXP; 11684887Schin /* FALL THRU */ 11694887Schin case S_EPAT: 11704887Schin epat: 11714887Schin if(fcgetc(n)==LPAREN) 11724887Schin { 1173*8462SApril.Chin@Sun.COM if(lp->lex.incase==TEST_RE) 11744887Schin { 1175*8462SApril.Chin@Sun.COM lp->lex.incase++; 1176*8462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,ST_NORM); 11774887Schin mode = ST_NESTED; 11784887Schin } 11794887Schin wordflags |= ARG_EXP; 1180*8462SApril.Chin@Sun.COM pushlevel(lp,RPAREN,mode); 11814887Schin mode = ST_NESTED; 11824887Schin continue; 11834887Schin } 11844887Schin if(n>0) 11854887Schin fcseek(-1); 11864887Schin if(n=='=' && c=='+' && mode==ST_NAME) 11874887Schin continue; 11884887Schin break; 11894887Schin } 1190*8462SApril.Chin@Sun.COM lp->comp_assign = 0; 11914887Schin if(mode==ST_NAME) 11924887Schin mode = ST_NORM; 11934887Schin else if(mode==ST_NONE) 11944887Schin return(0); 11954887Schin } 11964887Schin breakloop: 1197*8462SApril.Chin@Sun.COM if(lp->lexd.nocopy) 11984887Schin { 1199*8462SApril.Chin@Sun.COM lp->lexd.balance = 0; 1200*8462SApril.Chin@Sun.COM return(0); 1201*8462SApril.Chin@Sun.COM } 1202*8462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 1203*8462SApril.Chin@Sun.COM { 1204*8462SApril.Chin@Sun.COM lp->lexd.balance = 0; 1205*8462SApril.Chin@Sun.COM if(lp->lexd.docword) 12064887Schin nested_here(lp); 1207*8462SApril.Chin@Sun.COM lp->lexd.message = (wordflags&ARG_MESSAGE); 1208*8462SApril.Chin@Sun.COM return(lp->token=0); 12094887Schin } 1210*8462SApril.Chin@Sun.COM if(!(state=lp->lexd.first)) 12114887Schin state = fcfirst(); 12124887Schin n = fcseek(0)-(char*)state; 1213*8462SApril.Chin@Sun.COM if(!lp->arg) 1214*8462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkseek(stkp,ARGVAL); 12154887Schin if(n>0) 1216*8462SApril.Chin@Sun.COM sfwrite(stkp,state,n); 12174887Schin /* add balancing character if necessary */ 1218*8462SApril.Chin@Sun.COM if(lp->lexd.balance) 12194887Schin { 1220*8462SApril.Chin@Sun.COM sfputc(stkp,lp->lexd.balance); 1221*8462SApril.Chin@Sun.COM lp->lexd.balance = 0; 12224887Schin } 1223*8462SApril.Chin@Sun.COM sfputc(stkp,0); 1224*8462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 1225*8462SApril.Chin@Sun.COM state = stkptr(stkp,ARGVAL); 1226*8462SApril.Chin@Sun.COM n = stktell(stkp)-ARGVAL; 1227*8462SApril.Chin@Sun.COM lp->lexd.first=0; 12284887Schin if(n==1) 12294887Schin { 12304887Schin /* check for numbered redirection */ 12314887Schin n = state[0]; 12324887Schin if((c=='<' || c=='>') && isadigit(n)) 12334887Schin { 1234*8462SApril.Chin@Sun.COM c = sh_lex(lp); 1235*8462SApril.Chin@Sun.COM lp->digits = (n-'0'); 12364887Schin return(c); 12374887Schin } 12384887Schin if(n==LBRACT) 12394887Schin c = 0; 1240*8462SApril.Chin@Sun.COM else if(n==RBRACE && lp->comsub) 1241*8462SApril.Chin@Sun.COM return(lp->token=n); 12424887Schin else if(n=='~') 12434887Schin c = ARG_MAC; 12444887Schin else 12454887Schin c = (wordflags&ARG_EXP); 12464887Schin n = 1; 12474887Schin } 1248*8462SApril.Chin@Sun.COM else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND)) 12494887Schin { 12504887Schin if(!strchr(state,',')) 12514887Schin { 1252*8462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 1253*8462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 1254*8462SApril.Chin@Sun.COM return(lp->token=IOVNAME); 12554887Schin } 12564887Schin c = wordflags; 12574887Schin } 12584887Schin else 12594887Schin c = wordflags; 12604887Schin if(assignment<0) 12614887Schin { 1262*8462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 1263*8462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 1264*8462SApril.Chin@Sun.COM lp->lex.reservok = 1; 1265*8462SApril.Chin@Sun.COM return(lp->token=LABLSYM); 12664887Schin } 1267*8462SApril.Chin@Sun.COM if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE) 12684887Schin c &= ~ARG_EXP; 12694887Schin if((c&ARG_EXP) && (c&ARG_QUOTED)) 12704887Schin c |= ARG_MAC; 12714887Schin if(mode==ST_NONE) 12724887Schin { 12734887Schin /* eliminate trailing )) */ 1274*8462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-2); 12754887Schin } 12764887Schin if(c&ARG_MESSAGE) 12774887Schin { 12784887Schin if(sh_isoption(SH_DICTIONARY)) 1279*8462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,2); 12804887Schin if(!sh_isoption(SH_NOEXEC)) 12814887Schin { 1282*8462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,1); 12834887Schin c &= ~ARG_MESSAGE; 12844887Schin } 12854887Schin } 1286*8462SApril.Chin@Sun.COM if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lp->lexd.warn && !lp->lexd.docword)) 12874887Schin { 1288*8462SApril.Chin@Sun.COM lp->arg = (struct argnod*)stkfreeze(stkp,1); 1289*8462SApril.Chin@Sun.COM lp->arg->argflag = (c?c:ARG_RAW); 12904887Schin } 12914887Schin else if(mode==ST_NONE) 1292*8462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,-1); 12934887Schin else 1294*8462SApril.Chin@Sun.COM lp->arg = sh_endword(shp,0); 1295*8462SApril.Chin@Sun.COM state = lp->arg->argval; 1296*8462SApril.Chin@Sun.COM lp->comp_assign = assignment; 12974887Schin if(assignment) 1298*8462SApril.Chin@Sun.COM lp->arg->argflag |= ARG_ASSIGN; 1299*8462SApril.Chin@Sun.COM else if(!lp->lex.skipword) 1300*8462SApril.Chin@Sun.COM lp->assignok = 0; 1301*8462SApril.Chin@Sun.COM lp->arg->argchn.cp = 0; 1302*8462SApril.Chin@Sun.COM lp->arg->argnxt.ap = 0; 13034887Schin if(mode==ST_NONE) 1304*8462SApril.Chin@Sun.COM return(lp->token=EXPRSYM); 1305*8462SApril.Chin@Sun.COM if(lp->lex.intest) 13064887Schin { 1307*8462SApril.Chin@Sun.COM if(lp->lex.testop1) 13084887Schin { 1309*8462SApril.Chin@Sun.COM lp->lex.testop1 = 0; 13104887Schin if(n==2 && state[0]=='-' && state[2]==0 && 13114887Schin strchr(test_opchars,state[1])) 13124887Schin { 1313*8462SApril.Chin@Sun.COM if(lp->lexd.warn && state[1]=='a') 13144887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno); 1315*8462SApril.Chin@Sun.COM lp->digits = state[1]; 1316*8462SApril.Chin@Sun.COM lp->token = TESTUNOP; 13174887Schin } 13184887Schin else if(n==1 && state[0]=='!' && state[1]==0) 13194887Schin { 1320*8462SApril.Chin@Sun.COM lp->lex.testop1 = 1; 1321*8462SApril.Chin@Sun.COM lp->token = '!'; 13224887Schin } 13234887Schin else 13244887Schin { 1325*8462SApril.Chin@Sun.COM lp->lex.testop2 = 1; 1326*8462SApril.Chin@Sun.COM lp->token = 0; 13274887Schin } 1328*8462SApril.Chin@Sun.COM return(lp->token); 13294887Schin } 1330*8462SApril.Chin@Sun.COM lp->lex.incase = 0; 13314887Schin c = sh_lookup(state,shtab_testops); 13324887Schin switch(c) 13334887Schin { 13344887Schin case TEST_END: 1335*8462SApril.Chin@Sun.COM lp->lex.testop2 = lp->lex.intest = 0; 1336*8462SApril.Chin@Sun.COM lp->lex.reservok = 1; 1337*8462SApril.Chin@Sun.COM lp->token = ETESTSYM; 1338*8462SApril.Chin@Sun.COM return(lp->token); 13394887Schin 13404887Schin case TEST_SEQ: 1341*8462SApril.Chin@Sun.COM if(lp->lexd.warn && state[1]==0) 13424887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno); 13434887Schin /* FALL THRU */ 13444887Schin default: 1345*8462SApril.Chin@Sun.COM if(lp->lex.testop2) 13464887Schin { 1347*8462SApril.Chin@Sun.COM if(lp->lexd.warn && (c&TEST_ARITH)) 13484887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state); 13494887Schin if(c&TEST_PATTERN) 1350*8462SApril.Chin@Sun.COM lp->lex.incase = 1; 13514887Schin else if(c==TEST_REP) 1352*8462SApril.Chin@Sun.COM lp->lex.incase = TEST_RE; 1353*8462SApril.Chin@Sun.COM lp->lex.testop2 = 0; 1354*8462SApril.Chin@Sun.COM lp->digits = c; 1355*8462SApril.Chin@Sun.COM lp->token = TESTBINOP; 1356*8462SApril.Chin@Sun.COM return(lp->token); 13574887Schin } 13584887Schin 13594887Schin case TEST_OR: case TEST_AND: 13604887Schin case 0: 1361*8462SApril.Chin@Sun.COM return(lp->token=0); 13624887Schin } 13634887Schin } 1364*8462SApril.Chin@Sun.COM if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2) 13654887Schin { 13664887Schin /* check for {, }, ! */ 13674887Schin c = state[0]; 13684887Schin if(n==1 && (c=='{' || c=='}' || c=='!')) 13694887Schin { 1370*8462SApril.Chin@Sun.COM if(lp->lexd.warn && c=='{' && lp->lex.incase==2) 13714887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno); 1372*8462SApril.Chin@Sun.COM if(lp->lex.incase==1 && c==RBRACE) 1373*8462SApril.Chin@Sun.COM lp->lex.incase = 0; 1374*8462SApril.Chin@Sun.COM return(lp->token=c); 13754887Schin } 1376*8462SApril.Chin@Sun.COM else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT) 13774887Schin { 1378*8462SApril.Chin@Sun.COM lp->lex.intest = lp->lex.testop1 = 1; 1379*8462SApril.Chin@Sun.COM lp->lex.testop2 = lp->lex.reservok = 0; 1380*8462SApril.Chin@Sun.COM return(lp->token=BTESTSYM); 13814887Schin } 13824887Schin } 13834887Schin c = 0; 1384*8462SApril.Chin@Sun.COM if(!lp->lex.skipword) 13854887Schin { 1386*8462SApril.Chin@Sun.COM if(n>1 && lp->lex.reservok==1 && mode==ST_NAME && 13874887Schin (c=sh_lookup(state,shtab_reserved))) 13884887Schin { 1389*8462SApril.Chin@Sun.COM if(lp->lex.incase) 13904887Schin { 1391*8462SApril.Chin@Sun.COM if(lp->lex.incase >1) 1392*8462SApril.Chin@Sun.COM lp->lex.incase = 1; 13934887Schin else if(c==ESACSYM) 1394*8462SApril.Chin@Sun.COM lp->lex.incase = 0; 13954887Schin else 13964887Schin c = 0; 13974887Schin } 13984887Schin else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM) 13994887Schin { 1400*8462SApril.Chin@Sun.COM lp->lex.skipword = 1; 1401*8462SApril.Chin@Sun.COM lp->lex.incase = 2*(c==CASESYM); 14024887Schin } 14034887Schin else 1404*8462SApril.Chin@Sun.COM lp->lex.skipword = 0; 14054887Schin if(c==INSYM) 1406*8462SApril.Chin@Sun.COM lp->lex.reservok = 0; 14074887Schin else if(c==TIMESYM) 14084887Schin { 14094887Schin /* yech - POSIX requires time -p */ 14104887Schin while(fcgetc(n)==' ' || n=='\t'); 14114887Schin if(n>0) 14124887Schin fcseek(-1); 14134887Schin if(n=='-') 14144887Schin c=0; 14154887Schin } 1416*8462SApril.Chin@Sun.COM return(lp->token=c); 14174887Schin } 1418*8462SApril.Chin@Sun.COM if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok)) 14194887Schin { 14204887Schin /* check for aliases */ 14214887Schin Namval_t* np; 1422*8462SApril.Chin@Sun.COM if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN && 14234887Schin (np=nv_search(state,shp->alias_tree,HASH_SCOPE)) 14244887Schin && !nv_isattr(np,NV_NOEXPAND) 14254887Schin #if KSHELL 14264887Schin && (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE)) 14274887Schin #endif /* KSHELL */ 14284887Schin && (state=nv_getval(np))) 14294887Schin { 14304887Schin setupalias(lp,state,np); 14314887Schin nv_onattr(np,NV_NOEXPAND); 1432*8462SApril.Chin@Sun.COM lp->lex.reservok = 1; 1433*8462SApril.Chin@Sun.COM lp->assignok |= lp->lex.reservok; 1434*8462SApril.Chin@Sun.COM return(sh_lex(lp)); 14354887Schin } 14364887Schin } 1437*8462SApril.Chin@Sun.COM lp->lex.reservok = 0; 14384887Schin } 1439*8462SApril.Chin@Sun.COM lp->lex.skipword = lp->lexd.docword = 0; 1440*8462SApril.Chin@Sun.COM return(lp->token=c); 14414887Schin } 14424887Schin 14434887Schin /* 14444887Schin * read to end of command substitution 14454887Schin */ 1446*8462SApril.Chin@Sun.COM static int comsub(register Lex_t *lp, int endtok) 14474887Schin { 14484887Schin register int n,c,count=1; 1449*8462SApril.Chin@Sun.COM register int line=lp->sh->inlineno; 14504887Schin char word[5]; 1451*8462SApril.Chin@Sun.COM int messages=0, assignok=lp->assignok, csub; 14524887Schin struct lexstate save; 1453*8462SApril.Chin@Sun.COM save = lp->lex; 1454*8462SApril.Chin@Sun.COM csub = lp->comsub; 1455*8462SApril.Chin@Sun.COM sh_lexopen(lp,lp->sh,1); 1456*8462SApril.Chin@Sun.COM lp->lexd.dolparen++; 1457*8462SApril.Chin@Sun.COM lp->lex.incase=0; 1458*8462SApril.Chin@Sun.COM pushlevel(lp,0,0); 1459*8462SApril.Chin@Sun.COM lp->comsub = (endtok==LBRACE); 1460*8462SApril.Chin@Sun.COM if(sh_lex(lp)==endtok) 14614887Schin { 14624887Schin while(1) 14634887Schin { 14644887Schin /* look for case and esac */ 14654887Schin n=0; 14664887Schin while(1) 14674887Schin { 14684887Schin fcgetc(c); 14694887Schin /* skip leading white space */ 14704887Schin if(n==0 && !sh_lexstates[ST_BEGIN][c]) 14714887Schin continue; 14724887Schin if(n==4) 14734887Schin break; 14744887Schin if(sh_lexstates[ST_NAME][c]) 14754887Schin goto skip; 14764887Schin word[n++] = c; 14774887Schin } 14784887Schin if(sh_lexstates[ST_NAME][c]==S_BREAK) 14794887Schin { 14804887Schin if(memcmp(word,"case",4)==0) 1481*8462SApril.Chin@Sun.COM lp->lex.incase=1; 14824887Schin else if(memcmp(word,"esac",4)==0) 1483*8462SApril.Chin@Sun.COM lp->lex.incase=0; 14844887Schin } 14854887Schin skip: 14864887Schin if(c && (c!='#' || n==0)) 14874887Schin fcseek(-1); 1488*8462SApril.Chin@Sun.COM if(c==RBRACE && lp->lex.incase) 1489*8462SApril.Chin@Sun.COM lp->lex.incase=0; 1490*8462SApril.Chin@Sun.COM switch(c=sh_lex(lp)) 14914887Schin { 1492*8462SApril.Chin@Sun.COM case LBRACE: 1493*8462SApril.Chin@Sun.COM if(endtok==LBRACE && !lp->lex.incase) 1494*8462SApril.Chin@Sun.COM { 1495*8462SApril.Chin@Sun.COM lp->comsub = 0; 1496*8462SApril.Chin@Sun.COM count++; 1497*8462SApril.Chin@Sun.COM } 1498*8462SApril.Chin@Sun.COM break; 1499*8462SApril.Chin@Sun.COM case RBRACE: 1500*8462SApril.Chin@Sun.COM rbrace: 1501*8462SApril.Chin@Sun.COM if(endtok==LBRACE && --count<=0) 1502*8462SApril.Chin@Sun.COM goto done; 1503*8462SApril.Chin@Sun.COM lp->comsub = (count==1); 1504*8462SApril.Chin@Sun.COM break; 1505*8462SApril.Chin@Sun.COM case IPROCSYM: case OPROCSYM: 1506*8462SApril.Chin@Sun.COM case LPAREN: 1507*8462SApril.Chin@Sun.COM if(endtok==LPAREN && !lp->lex.incase) 15084887Schin count++; 15094887Schin break; 15104887Schin case RPAREN: 1511*8462SApril.Chin@Sun.COM if(lp->lex.incase) 1512*8462SApril.Chin@Sun.COM lp->lex.incase=0; 1513*8462SApril.Chin@Sun.COM else if(endtok==LPAREN && --count<=0) 15144887Schin goto done; 15154887Schin break; 15164887Schin case EOFSYM: 1517*8462SApril.Chin@Sun.COM lp->lastline = line; 1518*8462SApril.Chin@Sun.COM lp->lasttok = endtok; 1519*8462SApril.Chin@Sun.COM sh_syntax(lp); 15204887Schin case IOSEEKSYM: 15214887Schin if(fcgetc(c)!='#' && c>0) 15224887Schin fcseek(-1); 15234887Schin break; 15244887Schin case IODOCSYM: 1525*8462SApril.Chin@Sun.COM sh_lex(lp); 15264887Schin break; 15274887Schin case 0: 1528*8462SApril.Chin@Sun.COM lp->lex.reservok = 0; 1529*8462SApril.Chin@Sun.COM messages |= lp->lexd.message; 1530*8462SApril.Chin@Sun.COM break; 1531*8462SApril.Chin@Sun.COM case ';': 1532*8462SApril.Chin@Sun.COM fcgetc(c); 1533*8462SApril.Chin@Sun.COM if(c==RBRACE && endtok==LBRACE) 1534*8462SApril.Chin@Sun.COM goto rbrace; 1535*8462SApril.Chin@Sun.COM if(c>0) 1536*8462SApril.Chin@Sun.COM fcseek(-1); 1537*8462SApril.Chin@Sun.COM /* fall through*/ 1538*8462SApril.Chin@Sun.COM default: 1539*8462SApril.Chin@Sun.COM lp->lex.reservok = 1; 15404887Schin } 15414887Schin } 15424887Schin } 15434887Schin done: 1544*8462SApril.Chin@Sun.COM poplevel(lp); 1545*8462SApril.Chin@Sun.COM lp->comsub = csub; 1546*8462SApril.Chin@Sun.COM lp->lastline = line; 1547*8462SApril.Chin@Sun.COM lp->lexd.dolparen--; 1548*8462SApril.Chin@Sun.COM lp->lex = save; 1549*8462SApril.Chin@Sun.COM lp->assignok = (endchar(lp)==RBRACT?assignok:0); 15504887Schin return(messages); 15514887Schin } 15524887Schin 15534887Schin /* 15544887Schin * here-doc nested in $(...) 15554887Schin * allocate ionode with delimiter filled in without disturbing stak 15564887Schin */ 15574887Schin static void nested_here(register Lex_t *lp) 15584887Schin { 1559*8462SApril.Chin@Sun.COM register struct ionod *iop; 1560*8462SApril.Chin@Sun.COM register int n,offset; 1561*8462SApril.Chin@Sun.COM struct argnod *arg = lp->arg; 1562*8462SApril.Chin@Sun.COM Stk_t *stkp = lp->sh->stk; 1563*8462SApril.Chin@Sun.COM char *base; 1564*8462SApril.Chin@Sun.COM if(offset=stktell(stkp)) 1565*8462SApril.Chin@Sun.COM base = stkfreeze(stkp,0); 1566*8462SApril.Chin@Sun.COM n = fcseek(0)-lp->lexd.docend; 15674887Schin iop = newof(0,struct ionod,1,n+ARGVAL); 1568*8462SApril.Chin@Sun.COM iop->iolst = lp->heredoc; 1569*8462SApril.Chin@Sun.COM stkseek(stkp,ARGVAL); 1570*8462SApril.Chin@Sun.COM sfwrite(stkp,lp->lexd.docend,n); 1571*8462SApril.Chin@Sun.COM lp->arg = sh_endword(lp->sh,0); 15724887Schin iop->ioname = (char*)(iop+1); 1573*8462SApril.Chin@Sun.COM strcpy(iop->ioname,lp->arg->argval); 15744887Schin iop->iofile = (IODOC|IORAW); 1575*8462SApril.Chin@Sun.COM if(lp->lexd.docword>1) 15764887Schin iop->iofile |= IOSTRIP; 1577*8462SApril.Chin@Sun.COM lp->heredoc = iop; 1578*8462SApril.Chin@Sun.COM lp->arg = arg; 1579*8462SApril.Chin@Sun.COM lp->lexd.docword = 0; 15804887Schin if(offset) 1581*8462SApril.Chin@Sun.COM stkset(stkp,base,offset); 15824887Schin else 1583*8462SApril.Chin@Sun.COM stkseek(stkp,0); 15844887Schin } 15854887Schin 15864887Schin /* 15874887Schin * skip to <close> character 15884887Schin * if <copy> is non,zero, then the characters are copied to the stack 15894887Schin * <state> is the initial lexical state 15904887Schin */ 1591*8462SApril.Chin@Sun.COM void sh_lexskip(Lex_t *lp,int close, register int copy, int state) 15924887Schin { 15934887Schin register char *cp; 1594*8462SApril.Chin@Sun.COM lp->lexd.nest = close; 1595*8462SApril.Chin@Sun.COM lp->lexd.lex_state = state; 1596*8462SApril.Chin@Sun.COM lp->lexd.noarg = 1; 15974887Schin if(copy) 1598*8462SApril.Chin@Sun.COM fcnotify(lex_advance,lp); 15994887Schin else 1600*8462SApril.Chin@Sun.COM lp->lexd.nocopy++; 1601*8462SApril.Chin@Sun.COM sh_lex(lp); 1602*8462SApril.Chin@Sun.COM lp->lexd.noarg = 0; 16034887Schin if(copy) 16044887Schin { 1605*8462SApril.Chin@Sun.COM fcnotify(0,lp); 1606*8462SApril.Chin@Sun.COM if(!(cp=lp->lexd.first)) 16074887Schin cp = fcfirst(); 16084887Schin if((copy = fcseek(0)-cp) > 0) 1609*8462SApril.Chin@Sun.COM sfwrite(lp->sh->stk,cp,copy); 16104887Schin } 16114887Schin else 1612*8462SApril.Chin@Sun.COM lp->lexd.nocopy--; 16134887Schin } 16144887Schin 16154887Schin #if SHOPT_CRNL 16164887Schin ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n) 16174887Schin { 16184887Schin const char *cp = (const char*)buff, *next=cp, *ep = cp + n; 16194887Schin int m=0,k; 16204887Schin while(next = (const char*)memchr(next,'\r',ep-next)) 16214887Schin if(*++next=='\n') 16224887Schin { 16234887Schin if(k=next-cp-1) 16244887Schin { 16254887Schin if((k=sfwrite(sp,cp,k)) < 0) 16264887Schin return(m>0?m:-1); 16274887Schin m += k; 16284887Schin } 16294887Schin cp = next; 16304887Schin } 16314887Schin if((k=sfwrite(sp,cp,ep-cp)) < 0) 16324887Schin return(m>0?m:-1); 16334887Schin return(m+k); 16344887Schin } 16354887Schin # define sfwrite _sfwrite 16364887Schin #endif /* SHOPT_CRNL */ 16374887Schin 16384887Schin /* 16394887Schin * read in here-document from script 16404887Schin * quoted here documents, and here-documents without special chars are 16414887Schin * noted with the IOQUOTE flag 16424887Schin * returns 1 for complete here-doc, 0 for EOF 16434887Schin */ 16444887Schin 16454887Schin static int here_copy(Lex_t *lp,register struct ionod *iop) 16464887Schin { 16474887Schin register const char *state; 16484887Schin register int c,n; 16494887Schin register char *bufp,*cp; 1650*8462SApril.Chin@Sun.COM register Sfio_t *sp=lp->sh->heredocs, *funlog; 16514887Schin int stripcol=0,stripflg, nsave, special=0; 1652*8462SApril.Chin@Sun.COM if(funlog=lp->sh->funlog) 16534887Schin { 16544887Schin if(fcfill()>0) 16554887Schin fcseek(-1); 1656*8462SApril.Chin@Sun.COM lp->sh->funlog = 0; 16574887Schin } 16584887Schin if(iop->iolst) 16594887Schin here_copy(lp,iop->iolst); 16604887Schin iop->iooffset = sfseek(sp,(off_t)0,SEEK_END); 16614887Schin iop->iosize = 0; 16624887Schin iop->iodelim=iop->ioname; 16634887Schin /* check for and strip quoted characters in delimiter string */ 16644887Schin if(stripflg=iop->iofile&IOSTRIP) 16654887Schin { 16664887Schin while(*iop->iodelim=='\t') 16674887Schin iop->iodelim++; 16684887Schin /* skip over leading tabs in document */ 16694887Schin if(iop->iofile&IOLSEEK) 16704887Schin { 16714887Schin iop->iofile &= ~IOLSEEK; 16724887Schin while(fcgetc(c)=='\t' || c==' ') 16734887Schin { 16744887Schin if(c==' ') 16754887Schin stripcol++; 16764887Schin else 16774887Schin stripcol += 8 - stripcol%8; 16784887Schin } 16794887Schin } 16804887Schin else 16814887Schin while(fcgetc(c)=='\t'); 16824887Schin if(c>0) 16834887Schin fcseek(-1); 16844887Schin } 16854887Schin if(iop->iofile&IOQUOTE) 16864887Schin state = sh_lexstates[ST_LIT]; 16874887Schin else 16884887Schin state = sh_lexstates[ST_QUOTE]; 16894887Schin bufp = fcseek(0); 16904887Schin n = S_NL; 16914887Schin while(1) 16924887Schin { 16934887Schin if(n!=S_NL) 16944887Schin { 16954887Schin /* skip over regular characters */ 16964887Schin while((n=STATE(state,c))==0); 16974887Schin } 16984887Schin if(n==S_EOF || !(c=fcget())) 16994887Schin { 1700*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp)) 17014887Schin { 17024887Schin if(n==S_ESC) 17034887Schin c--; 17044887Schin if((c=sfwrite(sp,bufp,c))>0) 17054887Schin iop->iosize += c; 17064887Schin } 1707*8462SApril.Chin@Sun.COM if((c=lexfill(lp))<=0) 17084887Schin break; 17094887Schin if(n==S_ESC) 17104887Schin { 17114887Schin #if SHOPT_CRNL 17124887Schin if(c=='\r' && (c=fcget())!=NL) 17134887Schin fcseek(-1); 17144887Schin #endif /* SHOPT_CRNL */ 17154887Schin if(c==NL) 17164887Schin fcseek(1); 17174887Schin else 17184887Schin sfputc(sp,'\\'); 17194887Schin } 17204887Schin bufp = fcseek(-1); 17214887Schin } 17224887Schin else 17234887Schin fcseek(-1); 17244887Schin switch(n) 17254887Schin { 17264887Schin case S_NL: 1727*8462SApril.Chin@Sun.COM lp->sh->inlineno++; 17284887Schin if((stripcol && c==' ') || (stripflg && c=='\t')) 17294887Schin { 1730*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen) 17314887Schin { 17324887Schin /* write out line */ 17334887Schin n = fcseek(0)-bufp; 17344887Schin if((n=sfwrite(sp,bufp,n))>0) 17354887Schin iop->iosize += n; 17364887Schin } 17374887Schin /* skip over tabs */ 17384887Schin if(stripcol) 17394887Schin { 17404887Schin int col=0; 17414887Schin do 17424887Schin { 17434887Schin fcgetc(c); 17444887Schin if(c==' ') 17454887Schin col++; 17464887Schin else 17474887Schin col += 8 - col%8; 17484887Schin if(col>stripcol) 17494887Schin break; 17504887Schin } 17514887Schin while (c==' ' || c=='\t'); 17524887Schin } 17534887Schin else while(c=='\t') 17544887Schin fcgetc(c); 17554887Schin if(c<=0) 17564887Schin goto done; 17574887Schin bufp = fcseek(-1); 17584887Schin } 17594887Schin if(c!=iop->iodelim[0]) 17604887Schin break; 17614887Schin cp = fcseek(0); 17624887Schin nsave = n = 0; 17634887Schin while(1) 17644887Schin { 17654887Schin if(!(c=fcget())) 17664887Schin { 1767*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (c=cp-bufp)) 17684887Schin { 17694887Schin if((c=sfwrite(sp,cp=bufp,c))>0) 17704887Schin iop->iosize+=c; 17714887Schin } 17724887Schin nsave = n; 1773*8462SApril.Chin@Sun.COM if((c=lexfill(lp))<=0) 17744887Schin { 17754887Schin c = iop->iodelim[n]==0; 17764887Schin goto done; 17774887Schin } 17784887Schin } 17794887Schin #if SHOPT_CRNL 17804887Schin if(c=='\r' && (c=fcget())!=NL) 17814887Schin { 17824887Schin if(c) 17834887Schin fcseek(-1); 17844887Schin c='\r'; 17854887Schin } 17864887Schin #endif /* SHOPT_CRNL */ 17874887Schin if(c==NL) 1788*8462SApril.Chin@Sun.COM lp->sh->inlineno++; 17894887Schin if(iop->iodelim[n]==0 && (c==NL||c==RPAREN)) 17904887Schin { 1791*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (n=cp-bufp)) 17924887Schin { 17934887Schin if((n=sfwrite(sp,bufp,n))>0) 17944887Schin iop->iosize += n; 17954887Schin } 1796*8462SApril.Chin@Sun.COM lp->sh->inlineno--; 17974887Schin if(c==RPAREN) 17984887Schin fcseek(-1); 17994887Schin goto done; 18004887Schin } 18014887Schin if(iop->iodelim[n++]!=c) 18024887Schin { 18034887Schin /* 18044887Schin * The match for delimiter failed. 18054887Schin * nsave>0 only when a buffer boundary 18064887Schin * was crossed while checking the 18074887Schin * delimiter 18084887Schin */ 1809*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && nsave>0) 18104887Schin { 18114887Schin if((n=sfwrite(sp,bufp,nsave))>0) 18124887Schin iop->iosize += n; 18134887Schin bufp = fcfirst(); 18144887Schin } 18154887Schin if(c==NL) 18164887Schin fcseek(-1); 18174887Schin break; 18184887Schin } 18194887Schin } 18204887Schin break; 18214887Schin case S_ESC: 18224887Schin n=1; 18234887Schin #if SHOPT_CRNL 18244887Schin if(c=='\r') 18254887Schin { 18264887Schin fcseek(1); 18274887Schin if(c=fcget()) 18284887Schin fcseek(-1); 18294887Schin if(c==NL) 18304887Schin n=2; 18314887Schin else 18324887Schin { 18334887Schin special++; 18344887Schin break; 18354887Schin } 18364887Schin } 18374887Schin #endif /* SHOPT_CRNL */ 18384887Schin if(c==NL) 18394887Schin { 18404887Schin /* new-line joining */ 1841*8462SApril.Chin@Sun.COM lp->sh->inlineno++; 1842*8462SApril.Chin@Sun.COM if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>0) 18434887Schin { 18444887Schin if((n=sfwrite(sp,bufp,n))>0) 18454887Schin iop->iosize += n; 18464887Schin bufp = fcseek(0)+1; 18474887Schin } 18484887Schin } 18494887Schin else 18504887Schin special++; 18514887Schin fcget(); 18524887Schin break; 18534887Schin 18544887Schin case S_GRAVE: 18554887Schin case S_DOL: 18564887Schin special++; 18574887Schin break; 18584887Schin } 18594887Schin n=0; 18604887Schin } 18614887Schin done: 1862*8462SApril.Chin@Sun.COM lp->sh->funlog = funlog; 1863*8462SApril.Chin@Sun.COM if(lp->lexd.dolparen) 18644887Schin free((void*)iop); 18654887Schin else if(!special) 18664887Schin iop->iofile |= IOQUOTE; 18674887Schin return(c); 18684887Schin } 18694887Schin 18704887Schin /* 18714887Schin * generates string for given token 18724887Schin */ 18734887Schin static char *fmttoken(Lex_t *lp, register int sym, char *tok) 18744887Schin { 18754887Schin if(sym < 0) 18764887Schin return((char*)sh_translate(e_lexzerobyte)); 18774887Schin if(sym==0) 1878*8462SApril.Chin@Sun.COM return(lp->arg?lp->arg->argval:"?"); 1879*8462SApril.Chin@Sun.COM if(lp->lex.intest && lp->arg && *lp->arg->argval) 1880*8462SApril.Chin@Sun.COM return(lp->arg->argval); 18814887Schin if(sym&SYMRES) 18824887Schin { 18834887Schin register const Shtable_t *tp=shtab_reserved; 18844887Schin while(tp->sh_number && tp->sh_number!=sym) 18854887Schin tp++; 18864887Schin return((char*)tp->sh_name); 18874887Schin } 18884887Schin if(sym==EOFSYM) 18894887Schin return((char*)sh_translate(e_endoffile)); 18904887Schin if(sym==NL) 18914887Schin return((char*)sh_translate(e_newline)); 18924887Schin tok[0] = sym; 18934887Schin if(sym&SYMREP) 18944887Schin tok[1] = sym; 18954887Schin else 18964887Schin { 18974887Schin switch(sym&SYMMASK) 18984887Schin { 18994887Schin case SYMAMP: 19004887Schin sym = '&'; 19014887Schin break; 19024887Schin case SYMPIPE: 19034887Schin sym = '|'; 19044887Schin break; 19054887Schin case SYMGT: 19064887Schin sym = '>'; 19074887Schin break; 19084887Schin case SYMLPAR: 19094887Schin sym = LPAREN; 19104887Schin break; 19114887Schin case SYMSHARP: 19124887Schin sym = '#'; 19134887Schin break; 1914*8462SApril.Chin@Sun.COM case SYMSEMI: 1915*8462SApril.Chin@Sun.COM sym = ';'; 1916*8462SApril.Chin@Sun.COM break; 19174887Schin default: 19184887Schin sym = 0; 19194887Schin } 19204887Schin tok[1] = sym; 19214887Schin } 19224887Schin tok[2] = 0; 19234887Schin return(tok); 19244887Schin } 19254887Schin 19264887Schin /* 19274887Schin * print a bad syntax message 19284887Schin */ 19294887Schin 1930*8462SApril.Chin@Sun.COM void sh_syntax(Lex_t *lp) 19314887Schin { 1932*8462SApril.Chin@Sun.COM register Shell_t *shp = lp->sh; 19334887Schin register const char *cp = sh_translate(e_unexpected); 19344887Schin register char *tokstr; 1935*8462SApril.Chin@Sun.COM register int tok = lp->token; 19364887Schin char tokbuf[3]; 19374887Schin Sfio_t *sp; 1938*8462SApril.Chin@Sun.COM if((tok==EOFSYM) && lp->lasttok) 19394887Schin { 1940*8462SApril.Chin@Sun.COM tok = lp->lasttok; 19414887Schin cp = sh_translate(e_unmatched); 19424887Schin } 19434887Schin else 1944*8462SApril.Chin@Sun.COM lp->lastline = shp->inlineno; 19454887Schin tokstr = fmttoken(lp,tok,tokbuf); 19464887Schin if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd]))) 19474887Schin { 19484887Schin /* clear out any pending input */ 19494887Schin register Sfio_t *top; 19504887Schin while(fcget()>0); 19514887Schin fcclose(); 19524887Schin while(top=sfstack(sp,SF_POPSTACK)) 19534887Schin sfclose(top); 19544887Schin } 19554887Schin else 19564887Schin fcclose(); 1957*8462SApril.Chin@Sun.COM shp->inlineno = lp->inlineno; 1958*8462SApril.Chin@Sun.COM shp->st.firstline = lp->firstline; 19594887Schin #if KSHELL 19604887Schin if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE)) 19614887Schin #else 19624887Schin if(shp->inlineno!=1) 19634887Schin #endif 1964*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp); 19654887Schin else 19664887Schin errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp); 19674887Schin } 19684887Schin 1969*8462SApril.Chin@Sun.COM static char *stack_shift(Stk_t *stkp, register char *sp,char *dp) 19704887Schin { 19714887Schin register char *ep; 1972*8462SApril.Chin@Sun.COM register int offset = stktell(stkp); 1973*8462SApril.Chin@Sun.COM register int left = offset-(sp-stkptr(stkp,0)); 19744887Schin register int shift = (dp+1-sp); 19754887Schin offset += shift; 1976*8462SApril.Chin@Sun.COM stkseek(stkp,offset); 1977*8462SApril.Chin@Sun.COM sp = stkptr(stkp,offset); 19784887Schin ep = sp - shift; 19794887Schin while(left--) 19804887Schin *--sp = *--ep; 19814887Schin return(sp); 19824887Schin } 19834887Schin 19844887Schin /* 19854887Schin * Assumes that current word is unfrozen on top of the stak 19864887Schin * If <mode> is zero, gets rid of quoting and consider argument as string 19874887Schin * and returns pointer to frozen arg 19884887Schin * If mode==1, just replace $"..." strings with international strings 19894887Schin * The result is left on the stak 19904887Schin * If mode==2, the each $"" string is printed on standard output 19914887Schin */ 1992*8462SApril.Chin@Sun.COM struct argnod *sh_endword(Shell_t *shp,int mode) 19934887Schin { 19944887Schin register const char *state = sh_lexstates[ST_NESTED]; 19954887Schin register int n; 19964887Schin register char *sp,*dp; 19974887Schin register int inquote=0, inlit=0; /* set within quoted strings */ 19984887Schin struct argnod* argp=0; 19994887Schin char *ep=0, *xp=0; 20004887Schin int bracket=0; 2001*8462SApril.Chin@Sun.COM Stk_t *stkp=shp->stk; 2002*8462SApril.Chin@Sun.COM sfputc(stkp,0); 2003*8462SApril.Chin@Sun.COM sp = stkptr(stkp,ARGVAL); 20044887Schin #if SHOPT_MULTIBYTE 20054887Schin if(mbwide()) 20064887Schin { 20074887Schin do 20084887Schin { 20094887Schin int len; 20104887Schin switch(len = mbsize(sp)) 20114887Schin { 20124887Schin case -1: /* illegal multi-byte char */ 20134887Schin case 0: 20144887Schin case 1: 20154887Schin n=state[*sp++]; 20164887Schin break; 20174887Schin default: 20184887Schin /* 20194887Schin * None of the state tables contain 20204887Schin * entries for multibyte characters, 20214887Schin * however, they should be treated 20224887Schin * the same as any other alph 20234887Schin * character. Therefore, we'll use 20244887Schin * the state of the 'a' character. 20254887Schin */ 20264887Schin n=state['a']; 20274887Schin sp += len; 20284887Schin } 20294887Schin } 20304887Schin while(n == 0); 20314887Schin } 20324887Schin else 20334887Schin #endif /* SHOPT_MULTIBYTE */ 20344887Schin while((n=state[*sp++])==0); 20354887Schin dp = sp; 20364887Schin if(mode<0) 20374887Schin inquote = 1; 20384887Schin while(1) 20394887Schin { 20404887Schin switch(n) 20414887Schin { 20424887Schin case S_EOF: 2043*8462SApril.Chin@Sun.COM stkseek(stkp,dp-stkptr(stkp,0)); 20444887Schin if(mode<=0) 20454887Schin { 2046*8462SApril.Chin@Sun.COM argp = (struct argnod*)stkfreeze(stkp,0); 20474887Schin argp->argflag = ARG_RAW|ARG_QUOTED; 20484887Schin } 20494887Schin return(argp); 20504887Schin case S_LIT: 20514887Schin if(!(inquote&1)) 20524887Schin { 20534887Schin inlit = !inlit; 20544887Schin if(mode==0 || (mode<0 && bracket)) 20554887Schin { 20564887Schin dp--; 20574887Schin if(ep) 20584887Schin { 20594887Schin *dp = 0; 20604887Schin dp = ep+stresc(ep); 20614887Schin } 20624887Schin ep = 0; 20634887Schin } 20644887Schin } 20654887Schin break; 20664887Schin case S_QUOTE: 20674887Schin if(mode<0 && !bracket) 20684887Schin break; 20694887Schin if(!inlit) 20704887Schin { 20714887Schin if(mode<=0) 20724887Schin dp--; 20734887Schin inquote = inquote^1; 20744887Schin if(ep) 20754887Schin { 20764887Schin char *msg; 20774887Schin if(mode==2) 20784887Schin { 20794887Schin sfprintf(sfstdout,"%.*s\n",dp-ep,ep); 20804887Schin ep = 0; 20814887Schin break; 20824887Schin } 20834887Schin *--dp = 0; 20844887Schin #if ERROR_VERSION >= 20000317L 20854887Schin msg = ERROR_translate(0,error_info.id,0,ep); 20864887Schin #else 20874887Schin # if ERROR_VERSION >= 20000101L 20884887Schin msg = ERROR_translate(error_info.id,ep); 20894887Schin # else 20904887Schin msg = ERROR_translate(ep,2); 20914887Schin # endif 20924887Schin #endif 20934887Schin n = strlen(msg); 20944887Schin dp = ep+n; 20954887Schin if(sp-dp <= 1) 20964887Schin { 2097*8462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp); 20984887Schin dp = sp-1; 20994887Schin ep = dp-n; 21004887Schin } 21014887Schin memmove(ep,msg,n); 21024887Schin *dp++ = '"'; 21034887Schin } 21044887Schin ep = 0; 21054887Schin } 21064887Schin break; 21074887Schin case S_DOL: /* check for $'...' and $"..." */ 21084887Schin if(inlit) 21094887Schin break; 21104887Schin if(*sp==LPAREN || *sp==LBRACE) 21114887Schin { 21124887Schin inquote <<= 1; 21134887Schin break; 21144887Schin } 21154887Schin if(inquote&1) 21164887Schin break; 21174887Schin if(*sp=='\'' || *sp=='"') 21184887Schin { 21194887Schin if(*sp=='"') 21204887Schin inquote |= 1; 21214887Schin else 21224887Schin inlit = 1; 21234887Schin sp++; 21244887Schin if((mode==0||(mode<0&&bracket)) || (inquote&1)) 21254887Schin { 21264887Schin if(mode==2) 21274887Schin ep = dp++; 21284887Schin else if(mode==1) 21294887Schin (ep=dp)[-1] = '"'; 21304887Schin else 21314887Schin ep = --dp; 21324887Schin } 21334887Schin } 21344887Schin break; 21354887Schin case S_ESC: 21364887Schin #if SHOPT_CRNL 21374887Schin if(*sp=='\r' && sp[1]=='\n') 21384887Schin sp++; 21394887Schin #endif /* SHOPT_CRNL */ 21404887Schin if(inlit || mode>0) 21414887Schin { 21424887Schin if(mode<0) 21434887Schin { 21444887Schin if(dp>=sp) 21454887Schin { 2146*8462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp+1); 21474887Schin dp = sp-2; 21484887Schin } 21494887Schin *dp++ = '\\'; 21504887Schin } 21514887Schin if(ep) 21524887Schin *dp++ = *sp++; 21534887Schin break; 21544887Schin } 21554887Schin n = *sp; 21564887Schin #if SHOPT_DOS 21574887Schin if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0) 21584887Schin break; 21594887Schin #endif /* SHOPT_DOS */ 21604887Schin if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE)) 21614887Schin { 21624887Schin if(n=='\n') 21634887Schin dp--; 21644887Schin else 21654887Schin dp[-1] = n; 21664887Schin sp++; 21674887Schin } 21684887Schin break; 21694887Schin case S_POP: 21704887Schin if(sp[-1]!=RBRACT) 21714887Schin break; 21724887Schin if(!inlit && !(inquote&1)) 21734887Schin { 21744887Schin inquote >>= 1; 21754887Schin if(xp) 21764887Schin dp = sh_checkid(xp,dp); 21774887Schin xp = 0; 21784887Schin if(--bracket<=0 && mode<0) 21794887Schin inquote = 1; 21804887Schin } 21814887Schin else if((inlit||inquote) && mode<0) 21824887Schin { 21834887Schin dp[-1] = '\\'; 21844887Schin if(dp>=sp) 21854887Schin { 2186*8462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp); 21874887Schin dp = sp-1; 21884887Schin } 21894887Schin *dp++ = ']'; 21904887Schin } 21914887Schin break; 21924887Schin case S_BRACT: 21934887Schin if(dp[-2]=='.') 21944887Schin xp = dp; 21954887Schin if(mode<0) 21964887Schin { 21974887Schin if(inlit || (bracket&&inquote)) 21984887Schin { 21994887Schin dp[-1] = '\\'; 22004887Schin if(dp>=sp) 22014887Schin { 2202*8462SApril.Chin@Sun.COM sp = stack_shift(stkp,sp,dp); 22034887Schin dp = sp-1; 22044887Schin } 22054887Schin *dp++ = '['; 22064887Schin } 22074887Schin else if(bracket++==0) 22084887Schin inquote = 0; 22094887Schin } 22104887Schin break; 22114887Schin } 22124887Schin #if SHOPT_MULTIBYTE 22134887Schin if(mbwide()) 22144887Schin { 22154887Schin do 22164887Schin { 22174887Schin int len; 22184887Schin switch(len = mbsize(sp)) 22194887Schin { 22204887Schin case -1: /* illegal multi-byte char */ 22214887Schin case 0: 22224887Schin case 1: 22234887Schin n=state[*dp++ = *sp++]; 22244887Schin break; 22254887Schin default: 22264887Schin /* 22274887Schin * None of the state tables contain 22284887Schin * entries for multibyte characters, 22294887Schin * however, they should be treated 22304887Schin * the same as any other alph 22314887Schin * character. Therefore, we'll use 22324887Schin * the state of the 'a' character. 22334887Schin */ 22344887Schin while(len--) 22354887Schin *dp++ = *sp++; 22364887Schin n=state['a']; 22374887Schin } 22384887Schin } 22394887Schin while(n == 0); 22404887Schin } 22414887Schin else 22424887Schin #endif /* SHOPT_MULTIBYTE */ 22434887Schin while((n=state[*dp++ = *sp++])==0); 22444887Schin } 22454887Schin } 22464887Schin 22474887Schin struct alias 22484887Schin { 22494887Schin Sfdisc_t disc; 22504887Schin Namval_t *np; 22514887Schin int nextc; 22524887Schin int line; 22534887Schin char buf[2]; 22544887Schin Lex_t *lp; 22554887Schin }; 22564887Schin 22574887Schin /* 22584887Schin * This code gets called whenever an end of string is found with alias 22594887Schin */ 22604887Schin 22614887Schin #ifndef SF_ATEXIT 22624887Schin # define SF_ATEXIT 0 22634887Schin #endif 22644887Schin /* 22654887Schin * This code gets called whenever an end of string is found with alias 22664887Schin */ 22674887Schin #ifdef SF_BUFCONST 22684887Schin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle) 22694887Schin #else 22704887Schin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle) 22714887Schin #endif 22724887Schin { 22734887Schin register struct alias *ap = (struct alias*)handle; 22744887Schin register Namval_t *np; 22754887Schin register Lex_t *lp; 22764887Schin if(type==0 || type==SF_ATEXIT || !ap) 22774887Schin return(0); 22784887Schin lp = ap->lp; 22794887Schin np = ap->np; 22804887Schin if(type!=SF_READ) 22814887Schin { 22824887Schin if(type==SF_CLOSING) 22834887Schin { 22844887Schin register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC); 22854887Schin if(dp!=handle) 22864887Schin sfdisc(iop,dp); 22874887Schin } 22884887Schin else if(type==SF_FINAL) 22894887Schin free((void*)ap); 22904887Schin goto done; 22914887Schin } 22924887Schin if(ap->nextc) 22934887Schin { 22944887Schin /* if last character is a blank, then next work can be alias */ 22954887Schin register int c = fcpeek(-1); 22964887Schin if(isblank(c)) 2297*8462SApril.Chin@Sun.COM lp->aliasok = 1; 22984887Schin *ap->buf = ap->nextc; 22994887Schin ap->nextc = 0; 23004887Schin sfsetbuf(iop,ap->buf,1); 23014887Schin return(1); 23024887Schin } 23034887Schin done: 23044887Schin if(np) 23054887Schin nv_offattr(np,NV_NOEXPAND); 23064887Schin return(0); 23074887Schin } 23084887Schin 23094887Schin 23104887Schin static void setupalias(Lex_t *lp, const char *string,Namval_t *np) 23114887Schin { 23124887Schin register Sfio_t *iop, *base; 23134887Schin struct alias *ap = (struct alias*)malloc(sizeof(struct alias)); 23144887Schin ap->disc = alias_disc; 23154887Schin ap->lp = lp; 23164887Schin ap->buf[1] = 0; 23174887Schin if(ap->np = np) 23184887Schin { 23194887Schin #if SHOPT_KIA 2320*8462SApril.Chin@Sun.COM if(lp->kiafile) 23214887Schin { 23224887Schin unsigned long r; 2323*8462SApril.Chin@Sun.COM r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,""); 2324*8462SApril.Chin@Sun.COM sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno); 23254887Schin } 23264887Schin #endif /* SHOPT_KIA */ 23274887Schin if((ap->nextc=fcget())==0) 23284887Schin ap->nextc = ' '; 23294887Schin } 23304887Schin else 23314887Schin ap->nextc = 0; 23324887Schin iop = sfopen(NIL(Sfio_t*),(char*)string,"s"); 23334887Schin sfdisc(iop, &ap->disc); 2334*8462SApril.Chin@Sun.COM lp->lexd.nocopy++; 23354887Schin if(!(base=fcfile())) 23364887Schin base = sfopen(NIL(Sfio_t*),fcseek(0),"s"); 23374887Schin fcclose(); 23384887Schin sfstack(base,iop); 23394887Schin fcfopen(base); 2340*8462SApril.Chin@Sun.COM lp->lexd.nocopy--; 23414887Schin } 23424887Schin 23434887Schin /* 23444887Schin * grow storage stack for nested constructs by STACK_ARRAY 23454887Schin */ 23464887Schin static int stack_grow(Lex_t *lp) 23474887Schin { 2348*8462SApril.Chin@Sun.COM lp->lexd.lex_max += STACK_ARRAY; 2349*8462SApril.Chin@Sun.COM if(lp->lexd.lex_match) 2350*8462SApril.Chin@Sun.COM lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max); 23514887Schin else 2352*8462SApril.Chin@Sun.COM lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY); 2353*8462SApril.Chin@Sun.COM return(lp->lexd.lex_match!=0); 23544887Schin } 23554887Schin 2356