1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * David Korn <dgk@research.att.com> * 18*4887Schin * * 19*4887Schin ***********************************************************************/ 20*4887Schin #pragma prototyped 21*4887Schin /* 22*4887Schin * KornShell lexical analyzer 23*4887Schin * 24*4887Schin * Written by David Korn 25*4887Schin * AT&T Labs 26*4887Schin * 27*4887Schin */ 28*4887Schin 29*4887Schin #include <ast.h> 30*4887Schin #include <stak.h> 31*4887Schin #include <fcin.h> 32*4887Schin #include <nval.h> 33*4887Schin #include "FEATURE/options" 34*4887Schin 35*4887Schin #if KSHELL 36*4887Schin # include "defs.h" 37*4887Schin #else 38*4887Schin # include <shell.h> 39*4887Schin # define nv_getval(np) ((np)->nvalue) 40*4887Schin Shell_t sh = {1}; 41*4887Schin #endif /* KSHELL */ 42*4887Schin 43*4887Schin #include "argnod.h" 44*4887Schin #include "test.h" 45*4887Schin #include "lexstates.h" 46*4887Schin #include "io.h" 47*4887Schin 48*4887Schin #define TEST_RE 3 49*4887Schin #define SYNBAD 3 /* exit value for syntax errors */ 50*4887Schin #define STACK_ARRAY 3 /* size of depth match stack growth */ 51*4887Schin 52*4887Schin #if _lib_iswblank < 0 /* set in lexstates.h to enable this code */ 53*4887Schin 54*4887Schin int 55*4887Schin local_iswblank(wchar_t wc) 56*4887Schin { 57*4887Schin static int initialized; 58*4887Schin static wctype_t wt; 59*4887Schin 60*4887Schin if (!initialized) 61*4887Schin { 62*4887Schin initialized = 1; 63*4887Schin wt = wctype("blank"); 64*4887Schin } 65*4887Schin return(iswctype(wc, wt)); 66*4887Schin } 67*4887Schin 68*4887Schin #endif 69*4887Schin 70*4887Schin /* 71*4887Schin * This structure allows for arbitrary depth nesting of (...), {...}, [...] 72*4887Schin */ 73*4887Schin struct lexstate 74*4887Schin { 75*4887Schin char incase; /* 1 for case pattern, 2 after case */ 76*4887Schin char intest; /* 1 inside [[...]] */ 77*4887Schin char testop1; /* 1 when unary test op legal */ 78*4887Schin char testop2; /* 1 when binary test op legal */ 79*4887Schin char reservok; /* >0 for reserved word legal */ 80*4887Schin char skipword; /* next word can't be reserved */ 81*4887Schin char last_quote; /* last multi-line quote character */ 82*4887Schin char comp_assign; /* inside compound assignment */ 83*4887Schin }; 84*4887Schin 85*4887Schin struct lexdata 86*4887Schin { 87*4887Schin char nocopy; 88*4887Schin char paren; 89*4887Schin char dolparen; 90*4887Schin char nest; 91*4887Schin char docword; 92*4887Schin char *docend; 93*4887Schin char noarg; 94*4887Schin char balance; 95*4887Schin char warn; 96*4887Schin char message; 97*4887Schin char arith; 98*4887Schin char *first; 99*4887Schin int level; 100*4887Schin int lastc; 101*4887Schin int lex_max; 102*4887Schin int *lex_match; 103*4887Schin int lex_state; 104*4887Schin #if SHOPT_KIA 105*4887Schin off_t kiaoff; 106*4887Schin #endif 107*4887Schin }; 108*4887Schin 109*4887Schin #define _SHLEX_PRIVATE \ 110*4887Schin struct lexdata _lexd; \ 111*4887Schin struct lexstate _lex; 112*4887Schin 113*4887Schin #include "shlex.h" 114*4887Schin 115*4887Schin #define lexd lp->_lexd 116*4887Schin #define lex lp->_lex 117*4887Schin #undef shlex 118*4887Schin #define shlex lp->_shlex 119*4887Schin 120*4887Schin 121*4887Schin #define pushlevel(c,s) ((lexd.level>=lexd.lex_max?stack_grow(lp):1) &&\ 122*4887Schin ((lexd.lex_match[lexd.level++]=lexd.lastc),\ 123*4887Schin lexd.lastc=(((s)<<CHAR_BIT)|(c)))) 124*4887Schin #define oldmode() (lexd.lastc>>CHAR_BIT) 125*4887Schin #define endchar() (lexd.lastc&0xff) 126*4887Schin #define setchar(c) (lexd.lastc = ((lexd.lastc&~0xff)|(c))) 127*4887Schin #define poplevel() (lexd.lastc=lexd.lex_match[--lexd.level]) 128*4887Schin 129*4887Schin static char *fmttoken(Lex_t*, int, char*); 130*4887Schin #ifdef SF_BUFCONST 131*4887Schin static int alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*); 132*4887Schin #else 133*4887Schin static int alias_exceptf(Sfio_t*, int, Sfdisc_t*); 134*4887Schin #endif 135*4887Schin static void setupalias(Lex_t*,const char*, Namval_t*); 136*4887Schin static int comsub(Lex_t*); 137*4887Schin static void nested_here(Lex_t*); 138*4887Schin static int here_copy(Lex_t*, struct ionod*); 139*4887Schin static int stack_grow(Lex_t*); 140*4887Schin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL }; 141*4887Schin 142*4887Schin #if SHOPT_KIA 143*4887Schin 144*4887Schin static void refvar(int type) 145*4887Schin { 146*4887Schin register Shell_t *shp = sh_getinterp(); 147*4887Schin register Lex_t *lp = (Lex_t*)shp->lex_context; 148*4887Schin off_t off = (fcseek(0)-(type+1))-(lexd.first?lexd.first:fcfirst()); 149*4887Schin unsigned long r; 150*4887Schin if(lexd.first) 151*4887Schin { 152*4887Schin off = (fcseek(0)-(type+1)) - lexd.first; 153*4887Schin r=kiaentity(lexd.first+lexd.kiaoff+type,off-lexd.kiaoff,'v',-1,-1,shlex.current,'v',0,""); 154*4887Schin } 155*4887Schin else 156*4887Schin { 157*4887Schin int n,offset = staktell(); 158*4887Schin char *savptr,*begin; 159*4887Schin off = offset + (fcseek(0)-(type+1)) - fcfirst(); 160*4887Schin if(lexd.kiaoff < offset) 161*4887Schin { 162*4887Schin /* variable starts on stak, copy remainder */ 163*4887Schin if(off>offset) 164*4887Schin stakwrite(fcfirst()+type,off-offset); 165*4887Schin n = staktell()-lexd.kiaoff; 166*4887Schin begin = stakptr(lexd.kiaoff); 167*4887Schin } 168*4887Schin else 169*4887Schin { 170*4887Schin /* variable in data buffer */ 171*4887Schin begin = fcfirst()+(type+lexd.kiaoff-offset); 172*4887Schin n = off-lexd.kiaoff; 173*4887Schin } 174*4887Schin savptr = stakfreeze(0); 175*4887Schin r=kiaentity(begin,n,'v',-1,-1,shlex.current,'v',0,""); 176*4887Schin stakset(savptr,offset); 177*4887Schin } 178*4887Schin sfprintf(shlex.kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",shlex.current,r,shp->inlineno,shp->inlineno); 179*4887Schin } 180*4887Schin #endif /* SHOPT_KIA */ 181*4887Schin 182*4887Schin /* 183*4887Schin * This routine gets called when reading across a buffer boundary 184*4887Schin * If lexd.nocopy is off, then current token is saved on the stack 185*4887Schin */ 186*4887Schin static void lex_advance(Sfio_t *iop, const char *buff, register int size) 187*4887Schin { 188*4887Schin register Shell_t *shp = sh_getinterp(); 189*4887Schin register Lex_t *lp = (Lex_t*)shp->lex_context; 190*4887Schin register Sfio_t *log= shp->funlog; 191*4887Schin #if KSHELL 192*4887Schin /* write to history file and to stderr if necessary */ 193*4887Schin if(iop && !sfstacked(iop)) 194*4887Schin { 195*4887Schin if(sh_isstate(SH_HISTORY) && shp->hist_ptr) 196*4887Schin log = shp->hist_ptr->histfp; 197*4887Schin sfwrite(log, (void*)buff, size); 198*4887Schin if(sh_isstate(SH_VERBOSE)) 199*4887Schin sfwrite(sfstderr, buff, size); 200*4887Schin } 201*4887Schin #endif 202*4887Schin if(lexd.nocopy) 203*4887Schin return; 204*4887Schin if(lexd.first) 205*4887Schin { 206*4887Schin size -= (lexd.first-(char*)buff); 207*4887Schin buff = lexd.first; 208*4887Schin if(!lexd.noarg) 209*4887Schin shlex.arg = (struct argnod*)stakseek(ARGVAL); 210*4887Schin #if SHOPT_KIA 211*4887Schin lexd.kiaoff += ARGVAL; 212*4887Schin #endif /* SHOPT_KIA */ 213*4887Schin } 214*4887Schin if(size>0 && (shlex.arg||lexd.noarg)) 215*4887Schin { 216*4887Schin stakwrite(buff,size); 217*4887Schin lexd.first = 0; 218*4887Schin } 219*4887Schin } 220*4887Schin 221*4887Schin /* 222*4887Schin * fill up another input buffer 223*4887Schin * preserves lexical state 224*4887Schin */ 225*4887Schin static int lexfill(void) 226*4887Schin { 227*4887Schin Shell_t *shp = sh_getinterp(); 228*4887Schin register int c; 229*4887Schin register Lex_t *lp = (Lex_t*)shp->lex_context; 230*4887Schin struct shlex_t savelex; 231*4887Schin struct lexdata savedata; 232*4887Schin struct lexstate savestate; 233*4887Schin struct argnod *ap; 234*4887Schin int aok; 235*4887Schin savelex = shlex; 236*4887Schin savedata = lexd; 237*4887Schin savestate = lex; 238*4887Schin ap = shlex.arg; 239*4887Schin c = fcfill(); 240*4887Schin if(ap) 241*4887Schin shlex.arg = ap; 242*4887Schin lex = savestate; 243*4887Schin lexd = savedata; 244*4887Schin lexd.first = 0; 245*4887Schin aok= shlex.aliasok; 246*4887Schin ap = shlex.arg; 247*4887Schin shlex = savelex; 248*4887Schin shlex.arg = ap; 249*4887Schin shlex.aliasok = aok; 250*4887Schin return(c); 251*4887Schin } 252*4887Schin 253*4887Schin /* 254*4887Schin * mode=1 for reinitialization 255*4887Schin */ 256*4887Schin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode) 257*4887Schin { 258*4887Schin fcnotify(lex_advance); 259*4887Schin if(!lp) 260*4887Schin { 261*4887Schin lp = (Lex_t*)newof(0,Lex_t,1,0); 262*4887Schin lp->_shlex.sh = sp; 263*4887Schin } 264*4887Schin lex.intest = lex.incase = lex.skipword = lexd.warn = 0; 265*4887Schin lex.comp_assign = 0; 266*4887Schin lex.reservok = 1; 267*4887Schin if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC)) 268*4887Schin lexd.warn=1; 269*4887Schin if(!mode) 270*4887Schin { 271*4887Schin lexd.noarg = lexd.level= lexd.dolparen = 0; 272*4887Schin lexd.nocopy = lexd.docword = lexd.nest = lexd.paren = 0; 273*4887Schin } 274*4887Schin shlex.comsub = 0; 275*4887Schin return(lp); 276*4887Schin } 277*4887Schin 278*4887Schin #ifdef DBUG 279*4887Schin extern int lextoken(void); 280*4887Schin int sh_lex(void) 281*4887Schin { 282*4887Schin Shell_t *shp = sh_getinterp(); 283*4887Schin register Lex_t *lp = (Lex_t*)shp->lex_context; 284*4887Schin register int flag; 285*4887Schin char *quoted, *macro, *split, *expand; 286*4887Schin char tokstr[3]; 287*4887Schin register int tok = lextoken(); 288*4887Schin quoted = macro = split = expand = ""; 289*4887Schin if(tok==0 && (flag=shlex.arg->argflag)) 290*4887Schin { 291*4887Schin if(flag&ARG_MAC) 292*4887Schin macro = "macro:"; 293*4887Schin if(flag&ARG_EXP) 294*4887Schin expand = "expand:"; 295*4887Schin if(flag&ARG_QUOTED) 296*4887Schin quoted = "quoted:"; 297*4887Schin } 298*4887Schin sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted, 299*4887Schin macro, split, expand, fmttoken(lp,tok,tokstr)); 300*4887Schin return(tok); 301*4887Schin } 302*4887Schin #define sh_lex lextoken 303*4887Schin #endif 304*4887Schin 305*4887Schin /* 306*4887Schin * Get the next word and put it on the top of the stak 307*4887Schin * A pointer to the current word is stored in shlex.arg 308*4887Schin * Returns the token type 309*4887Schin */ 310*4887Schin int sh_lex(void) 311*4887Schin { 312*4887Schin register Shell_t *shp = sh_getinterp(); 313*4887Schin register const char *state; 314*4887Schin register int n, c, mode=ST_BEGIN, wordflags=0; 315*4887Schin register Lex_t *lp = (Lex_t*)shp->lex_context; 316*4887Schin int inlevel=lexd.level, assignment=0, ingrave=0; 317*4887Schin Sfio_t *sp; 318*4887Schin #if SHOPT_MULTIBYTE 319*4887Schin LEN=1; 320*4887Schin #endif /* SHOPT_MULTIBYTE */ 321*4887Schin if(lexd.paren) 322*4887Schin { 323*4887Schin lexd.paren = 0; 324*4887Schin return(shlex.token=LPAREN); 325*4887Schin } 326*4887Schin if(lex.incase) 327*4887Schin shlex.assignok = 0; 328*4887Schin else 329*4887Schin shlex.assignok |= lex.reservok; 330*4887Schin if(lex.comp_assign==2) 331*4887Schin lex.comp_assign = lex.reservok = 0; 332*4887Schin lexd.arith = (lexd.nest==1); 333*4887Schin if(lexd.nest) 334*4887Schin { 335*4887Schin pushlevel(lexd.nest,ST_NONE); 336*4887Schin lexd.nest = 0; 337*4887Schin mode = lexd.lex_state; 338*4887Schin } 339*4887Schin else if(lexd.docword) 340*4887Schin { 341*4887Schin if(fcgetc(c)=='-' || c=='#') 342*4887Schin { 343*4887Schin lexd.docword++; 344*4887Schin shlex.digits=(c=='#'?3:1); 345*4887Schin } 346*4887Schin else if(c=='<') 347*4887Schin { 348*4887Schin shlex.digits=2; 349*4887Schin lexd.docword=0; 350*4887Schin } 351*4887Schin else if(c>0) 352*4887Schin fcseek(-1); 353*4887Schin } 354*4887Schin if(!lexd.dolparen) 355*4887Schin { 356*4887Schin shlex.arg = 0; 357*4887Schin if(mode!=ST_BEGIN) 358*4887Schin lexd.first = fcseek(0); 359*4887Schin else 360*4887Schin lexd.first = 0; 361*4887Schin } 362*4887Schin shlex.lastline = sh.inlineno; 363*4887Schin while(1) 364*4887Schin { 365*4887Schin /* skip over characters in the current state */ 366*4887Schin state = sh_lexstates[mode]; 367*4887Schin while((n=STATE(state,c))==0); 368*4887Schin switch(n) 369*4887Schin { 370*4887Schin case S_BREAK: 371*4887Schin fcseek(-1); 372*4887Schin goto breakloop; 373*4887Schin case S_EOF: 374*4887Schin sp = fcfile(); 375*4887Schin if((n=lexfill()) > 0) 376*4887Schin { 377*4887Schin fcseek(-1); 378*4887Schin continue; 379*4887Schin } 380*4887Schin /* check for zero byte in file */ 381*4887Schin if(n==0 && fcfile()) 382*4887Schin { 383*4887Schin if(shp->readscript) 384*4887Schin { 385*4887Schin char *cp = error_info.id; 386*4887Schin errno = ENOEXEC; 387*4887Schin error_info.id = shp->readscript; 388*4887Schin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp); 389*4887Schin } 390*4887Schin else 391*4887Schin { 392*4887Schin shlex.token = -1; 393*4887Schin sh_syntax(); 394*4887Schin } 395*4887Schin } 396*4887Schin /* end-of-file */ 397*4887Schin if(mode==ST_BEGIN) 398*4887Schin return(shlex.token=EOFSYM); 399*4887Schin if(mode >ST_NORM && lexd.level>0) 400*4887Schin { 401*4887Schin switch(c=endchar()) 402*4887Schin { 403*4887Schin case '$': 404*4887Schin if(mode==ST_LIT) 405*4887Schin { 406*4887Schin c = '\''; 407*4887Schin break; 408*4887Schin } 409*4887Schin mode = oldmode(); 410*4887Schin poplevel(); 411*4887Schin continue; 412*4887Schin case RBRACT: 413*4887Schin c = LBRACT; 414*4887Schin break; 415*4887Schin case 1: /* for ((...)) */ 416*4887Schin case RPAREN: 417*4887Schin c = LPAREN; 418*4887Schin break; 419*4887Schin default: 420*4887Schin c = LBRACE; 421*4887Schin break; 422*4887Schin case '"': case '`': case '\'': 423*4887Schin lexd.balance = c; 424*4887Schin break; 425*4887Schin } 426*4887Schin if(sp && !(sfset(sp,0,0)&SF_STRING)) 427*4887Schin { 428*4887Schin shlex.lasttok = c; 429*4887Schin shlex.token = EOFSYM; 430*4887Schin sh_syntax(); 431*4887Schin } 432*4887Schin lexd.balance = c; 433*4887Schin } 434*4887Schin goto breakloop; 435*4887Schin case S_COM: 436*4887Schin /* skip one or more comment line(s) */ 437*4887Schin lex.reservok = !lex.intest; 438*4887Schin if((n=lexd.nocopy) && lexd.dolparen) 439*4887Schin lexd.nocopy--; 440*4887Schin do 441*4887Schin { 442*4887Schin while(fcgetc(c)>0 && c!='\n'); 443*4887Schin if(c<=0 || shlex.heredoc) 444*4887Schin break; 445*4887Schin while(shp->inlineno++,fcpeek(0)=='\n') 446*4887Schin fcseek(1); 447*4887Schin while(state[c=fcpeek(0)]==0) 448*4887Schin fcseek(1); 449*4887Schin } 450*4887Schin while(c=='#'); 451*4887Schin lexd.nocopy = n; 452*4887Schin if(c<0) 453*4887Schin return(shlex.token=EOFSYM); 454*4887Schin n = S_NLTOK; 455*4887Schin shp->inlineno--; 456*4887Schin /* FALL THRU */ 457*4887Schin case S_NLTOK: 458*4887Schin /* check for here-document */ 459*4887Schin if(shlex.heredoc) 460*4887Schin { 461*4887Schin if(!lexd.dolparen) 462*4887Schin lexd.nocopy++; 463*4887Schin c = shp->inlineno; 464*4887Schin if(here_copy(lp,shlex.heredoc)<=0 && shlex.lasttok) 465*4887Schin { 466*4887Schin shlex.lasttok = IODOCSYM; 467*4887Schin shlex.token = EOFSYM; 468*4887Schin shlex.lastline = c; 469*4887Schin sh_syntax(); 470*4887Schin } 471*4887Schin if(!lexd.dolparen) 472*4887Schin lexd.nocopy--; 473*4887Schin shlex.heredoc = 0; 474*4887Schin } 475*4887Schin lex.reservok = !lex.intest; 476*4887Schin lex.skipword = 0; 477*4887Schin /* FALL THRU */ 478*4887Schin case S_NL: 479*4887Schin /* skip over new-lines */ 480*4887Schin lex.last_quote = 0; 481*4887Schin while(shp->inlineno++,fcget()=='\n'); 482*4887Schin fcseek(-1); 483*4887Schin if(n==S_NLTOK) 484*4887Schin { 485*4887Schin lex.comp_assign = 0; 486*4887Schin return(shlex.token='\n'); 487*4887Schin } 488*4887Schin case S_BLNK: 489*4887Schin if(lex.incase<=TEST_RE) 490*4887Schin continue; 491*4887Schin /* implicit RPAREN for =~ test operator */ 492*4887Schin if(inlevel+1==lexd.level) 493*4887Schin { 494*4887Schin fcseek(-1); 495*4887Schin c = RPAREN; 496*4887Schin goto do_pop; 497*4887Schin } 498*4887Schin continue; 499*4887Schin case S_OP: 500*4887Schin /* return operator token */ 501*4887Schin if(c=='<' || c=='>') 502*4887Schin { 503*4887Schin if(lex.testop2) 504*4887Schin lex.testop2 = 0; 505*4887Schin else 506*4887Schin { 507*4887Schin shlex.digits = (c=='>'); 508*4887Schin lex.skipword = 1; 509*4887Schin shlex.aliasok = lex.reservok; 510*4887Schin lex.reservok = 0; 511*4887Schin } 512*4887Schin } 513*4887Schin else 514*4887Schin { 515*4887Schin lex.reservok = !lex.intest; 516*4887Schin if(c==RPAREN) 517*4887Schin { 518*4887Schin if(!lexd.dolparen) 519*4887Schin lex.incase = 0; 520*4887Schin return(shlex.token=c); 521*4887Schin } 522*4887Schin lex.testop1 = lex.intest; 523*4887Schin } 524*4887Schin if(fcgetc(n)>0) 525*4887Schin fcseek(-1); 526*4887Schin if(state[n]==S_OP || n=='#') 527*4887Schin { 528*4887Schin if(n==c) 529*4887Schin { 530*4887Schin if(c=='<') 531*4887Schin lexd.docword=1; 532*4887Schin else if(n==LPAREN) 533*4887Schin { 534*4887Schin lexd.nest=1; 535*4887Schin shlex.lastline = shp->inlineno; 536*4887Schin lexd.lex_state = ST_NESTED; 537*4887Schin fcseek(1); 538*4887Schin return(sh_lex()); 539*4887Schin } 540*4887Schin c |= SYMREP; 541*4887Schin } 542*4887Schin else if(c=='(' || c==')') 543*4887Schin return(shlex.token=c); 544*4887Schin else if(c=='&') 545*4887Schin { 546*4887Schin #if SHOPT_BASH 547*4887Schin if(!sh_isoption(SH_POSIX) && n=='>') 548*4887Schin { 549*4887Schin shlex.digits = -1; 550*4887Schin c = '>'; 551*4887Schin } 552*4887Schin else 553*4887Schin #endif 554*4887Schin n = 0; 555*4887Schin } 556*4887Schin else if(n=='&') 557*4887Schin c |= SYMAMP; 558*4887Schin else if(c!='<' && c!='>') 559*4887Schin n = 0; 560*4887Schin else if(n==LPAREN) 561*4887Schin { 562*4887Schin c |= SYMLPAR; 563*4887Schin lex.reservok = 1; 564*4887Schin lex.skipword = 0; 565*4887Schin } 566*4887Schin else if(n=='|') 567*4887Schin c |= SYMPIPE; 568*4887Schin else if(c=='<' && n=='>') 569*4887Schin c = IORDWRSYM; 570*4887Schin else if(n=='#' && (c=='<'||c=='>')) 571*4887Schin c |= SYMSHARP; 572*4887Schin else 573*4887Schin n = 0; 574*4887Schin if(n) 575*4887Schin { 576*4887Schin fcseek(1); 577*4887Schin lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM); 578*4887Schin } 579*4887Schin else 580*4887Schin { 581*4887Schin if((n=fcpeek(0))!=RPAREN && n!=LPAREN && lexd.warn) 582*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n); 583*4887Schin } 584*4887Schin } 585*4887Schin if(c==LPAREN && lex.comp_assign && !lex.intest && !lex.incase) 586*4887Schin lex.comp_assign = 2; 587*4887Schin else 588*4887Schin lex.comp_assign = 0; 589*4887Schin return(shlex.token=c); 590*4887Schin case S_ESC: 591*4887Schin /* check for \<new-line> */ 592*4887Schin fcgetc(n); 593*4887Schin c=2; 594*4887Schin #if SHOPT_CRNL 595*4887Schin if(n=='\r') 596*4887Schin { 597*4887Schin if(fcgetc(n)=='\n') 598*4887Schin c=3; 599*4887Schin else 600*4887Schin { 601*4887Schin n='\r'; 602*4887Schin fcseek(-1); 603*4887Schin } 604*4887Schin } 605*4887Schin #endif /* SHOPT_CRNL */ 606*4887Schin if(n=='\n') 607*4887Schin { 608*4887Schin Sfio_t *sp; 609*4887Schin struct argnod *ap; 610*4887Schin shp->inlineno++; 611*4887Schin /* synchronize */ 612*4887Schin if(!(sp=fcfile())) 613*4887Schin state=fcseek(0); 614*4887Schin fcclose(); 615*4887Schin ap = shlex.arg; 616*4887Schin if(sp) 617*4887Schin fcfopen(sp); 618*4887Schin else 619*4887Schin fcsopen((char*)state); 620*4887Schin /* remove \new-line */ 621*4887Schin n = staktell()-c; 622*4887Schin stakseek(n); 623*4887Schin shlex.arg = ap; 624*4887Schin if(n<=ARGVAL) 625*4887Schin { 626*4887Schin mode = 0; 627*4887Schin lexd.first = 0; 628*4887Schin } 629*4887Schin continue; 630*4887Schin } 631*4887Schin wordflags |= ARG_QUOTED; 632*4887Schin if(mode==ST_DOL) 633*4887Schin goto err; 634*4887Schin #ifndef STR_MAXIMAL 635*4887Schin else if(mode==ST_NESTED && lexd.warn && 636*4887Schin endchar()==RBRACE && 637*4887Schin sh_lexstates[ST_DOL][n]==S_DIG 638*4887Schin ) 639*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n); 640*4887Schin #endif /* STR_MAXIMAL */ 641*4887Schin break; 642*4887Schin case S_NAME: 643*4887Schin if(!lex.skipword) 644*4887Schin lex.reservok *= 2; 645*4887Schin /* FALL THRU */ 646*4887Schin case S_TILDE: 647*4887Schin case S_RES: 648*4887Schin if(!lexd.dolparen) 649*4887Schin lexd.first = fcseek(0)-LEN; 650*4887Schin else if(lexd.docword) 651*4887Schin lexd.docend = fcseek(0)-LEN; 652*4887Schin mode = ST_NAME; 653*4887Schin if(c=='.') 654*4887Schin fcseek(-1); 655*4887Schin if(n!=S_TILDE) 656*4887Schin continue; 657*4887Schin fcgetc(n); 658*4887Schin if(n>0) 659*4887Schin fcseek(-1); 660*4887Schin if(n==LPAREN) 661*4887Schin goto epat; 662*4887Schin wordflags = ARG_MAC; 663*4887Schin mode = ST_NORM; 664*4887Schin continue; 665*4887Schin case S_REG: 666*4887Schin if(mode==ST_BEGIN) 667*4887Schin { 668*4887Schin /* skip new-line joining */ 669*4887Schin if(c=='\\' && fcpeek(0)=='\n') 670*4887Schin { 671*4887Schin shp->inlineno++; 672*4887Schin fcseek(1); 673*4887Schin continue; 674*4887Schin } 675*4887Schin fcseek(-1); 676*4887Schin if(!lexd.dolparen) 677*4887Schin lexd.first = fcseek(0); 678*4887Schin else if(lexd.docword) 679*4887Schin lexd.docend = fcseek(0); 680*4887Schin if(c=='[' && shlex.assignok>=SH_ASSIGN) 681*4887Schin { 682*4887Schin mode = ST_NAME; 683*4887Schin continue; 684*4887Schin } 685*4887Schin } 686*4887Schin mode = ST_NORM; 687*4887Schin continue; 688*4887Schin case S_LIT: 689*4887Schin if(oldmode()==ST_NONE) /* in ((...)) */ 690*4887Schin { 691*4887Schin if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']') 692*4887Schin { 693*4887Schin if(fcpeek(1)=='\'') 694*4887Schin fcseek(2); 695*4887Schin } 696*4887Schin continue; 697*4887Schin } 698*4887Schin wordflags |= ARG_QUOTED; 699*4887Schin if(mode==ST_DOL) 700*4887Schin { 701*4887Schin if(endchar()!='$') 702*4887Schin goto err; 703*4887Schin if(oldmode()==ST_QUOTE) /* $' within "" or `` */ 704*4887Schin { 705*4887Schin if(lexd.warn) 706*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno); 707*4887Schin mode = ST_LIT; 708*4887Schin } 709*4887Schin } 710*4887Schin if(mode!=ST_LIT) 711*4887Schin { 712*4887Schin if(lexd.warn && lex.last_quote && shp->inlineno > shlex.lastline) 713*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,shlex.lastline,lex.last_quote); 714*4887Schin lex.last_quote = 0; 715*4887Schin shlex.lastline = shp->inlineno; 716*4887Schin if(mode!=ST_DOL) 717*4887Schin pushlevel('\'',mode); 718*4887Schin mode = ST_LIT; 719*4887Schin continue; 720*4887Schin } 721*4887Schin /* check for multi-line single-quoted string */ 722*4887Schin else if(shp->inlineno > shlex.lastline) 723*4887Schin lex.last_quote = '\''; 724*4887Schin mode = oldmode(); 725*4887Schin poplevel(); 726*4887Schin break; 727*4887Schin case S_ESC2: 728*4887Schin /* \ inside '' */ 729*4887Schin if(endchar()=='$') 730*4887Schin { 731*4887Schin fcgetc(n); 732*4887Schin if(n=='\n') 733*4887Schin shp->inlineno++; 734*4887Schin } 735*4887Schin continue; 736*4887Schin case S_GRAVE: 737*4887Schin if(lexd.warn && (mode!=ST_QUOTE || endchar()!='`')) 738*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno); 739*4887Schin wordflags |=(ARG_MAC|ARG_EXP); 740*4887Schin if(mode==ST_QUOTE) 741*4887Schin ingrave = !ingrave; 742*4887Schin /* FALL THRU */ 743*4887Schin case S_QUOTE: 744*4887Schin if(oldmode()==ST_NONE && lexd.arith) /* in ((...)) */ 745*4887Schin continue; 746*4887Schin if(n==S_QUOTE) 747*4887Schin wordflags |=ARG_QUOTED; 748*4887Schin if(mode!=ST_QUOTE) 749*4887Schin { 750*4887Schin if(c!='"' || mode!=ST_QNEST) 751*4887Schin { 752*4887Schin if(lexd.warn && lex.last_quote && shp->inlineno > shlex.lastline) 753*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,shlex.lastline,lex.last_quote); 754*4887Schin lex.last_quote=0; 755*4887Schin shlex.lastline = shp->inlineno; 756*4887Schin pushlevel(c,mode); 757*4887Schin } 758*4887Schin ingrave = (c=='`'); 759*4887Schin mode = ST_QUOTE; 760*4887Schin continue; 761*4887Schin } 762*4887Schin else if((n=endchar())==c) 763*4887Schin { 764*4887Schin if(shp->inlineno > shlex.lastline) 765*4887Schin lex.last_quote = c; 766*4887Schin mode = oldmode(); 767*4887Schin poplevel(); 768*4887Schin } 769*4887Schin else if(c=='"' && n==RBRACE) 770*4887Schin mode = ST_QNEST; 771*4887Schin break; 772*4887Schin case S_DOL: 773*4887Schin /* don't check syntax inside `` */ 774*4887Schin if(mode==ST_QUOTE && ingrave) 775*4887Schin continue; 776*4887Schin #if SHOPT_KIA 777*4887Schin if(lexd.first) 778*4887Schin lexd.kiaoff = fcseek(0)-lexd.first; 779*4887Schin else 780*4887Schin lexd.kiaoff = staktell()+fcseek(0)-fcfirst(); 781*4887Schin #endif /* SHOPT_KIA */ 782*4887Schin pushlevel('$',mode); 783*4887Schin mode = ST_DOL; 784*4887Schin continue; 785*4887Schin case S_PAR: 786*4887Schin wordflags |= ARG_MAC; 787*4887Schin mode = oldmode(); 788*4887Schin poplevel(); 789*4887Schin fcseek(-1); 790*4887Schin wordflags |= comsub(lp); 791*4887Schin continue; 792*4887Schin case S_RBRA: 793*4887Schin if((n=endchar()) == '$') 794*4887Schin goto err; 795*4887Schin if(mode!=ST_QUOTE || n==RBRACE) 796*4887Schin { 797*4887Schin mode = oldmode(); 798*4887Schin poplevel(); 799*4887Schin } 800*4887Schin break; 801*4887Schin case S_EDOL: 802*4887Schin /* end $identifier */ 803*4887Schin #if SHOPT_KIA 804*4887Schin if(shlex.kiafile) 805*4887Schin refvar(0); 806*4887Schin #endif /* SHOPT_KIA */ 807*4887Schin if(lexd.warn && c==LBRACT) 808*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno); 809*4887Schin fcseek(-1); 810*4887Schin mode = oldmode(); 811*4887Schin poplevel(); 812*4887Schin break; 813*4887Schin case S_DOT: 814*4887Schin /* make sure next character is alpha */ 815*4887Schin if(fcgetc(n)>0) 816*4887Schin fcseek(-1); 817*4887Schin if(isaletter(n) || n==LBRACT) 818*4887Schin continue; 819*4887Schin if(mode==ST_NAME) 820*4887Schin { 821*4887Schin if(n=='=') 822*4887Schin continue; 823*4887Schin break; 824*4887Schin } 825*4887Schin else if(n==RBRACE) 826*4887Schin continue; 827*4887Schin if(isastchar(n)) 828*4887Schin continue; 829*4887Schin goto err; 830*4887Schin case S_SPC1: 831*4887Schin wordflags |= ARG_MAC; 832*4887Schin if(endchar()==RBRACE) 833*4887Schin { 834*4887Schin setchar(c); 835*4887Schin continue; 836*4887Schin } 837*4887Schin /* FALL THRU */ 838*4887Schin case S_ALP: 839*4887Schin if(c=='.' && endchar()=='$') 840*4887Schin goto err; 841*4887Schin case S_SPC2: 842*4887Schin case S_DIG: 843*4887Schin wordflags |= ARG_MAC; 844*4887Schin switch(endchar()) 845*4887Schin { 846*4887Schin case '$': 847*4887Schin if(n==S_ALP) /* $identifier */ 848*4887Schin mode = ST_DOLNAME; 849*4887Schin else 850*4887Schin { 851*4887Schin mode = oldmode(); 852*4887Schin poplevel(); 853*4887Schin } 854*4887Schin break; 855*4887Schin #if SHOPT_TYPEDEF 856*4887Schin case '@': 857*4887Schin #endif /* SHOPT_TYPEDEF */ 858*4887Schin case '!': 859*4887Schin if(n!=S_ALP) 860*4887Schin goto dolerr; 861*4887Schin case '#': 862*4887Schin case RBRACE: 863*4887Schin if(n==S_ALP) 864*4887Schin { 865*4887Schin setchar(RBRACE); 866*4887Schin if(c=='.') 867*4887Schin fcseek(-1); 868*4887Schin mode = ST_BRACE; 869*4887Schin } 870*4887Schin else 871*4887Schin { 872*4887Schin if(fcgetc(c)>0) 873*4887Schin fcseek(-1); 874*4887Schin if(state[c]==S_ALP) 875*4887Schin goto err; 876*4887Schin if(n==S_DIG) 877*4887Schin setchar('0'); 878*4887Schin else 879*4887Schin setchar('!'); 880*4887Schin } 881*4887Schin break; 882*4887Schin case '0': 883*4887Schin if(n==S_DIG) 884*4887Schin break; 885*4887Schin default: 886*4887Schin goto dolerr; 887*4887Schin } 888*4887Schin break; 889*4887Schin dolerr: 890*4887Schin case S_ERR: 891*4887Schin if((n=endchar()) == '$') 892*4887Schin goto err; 893*4887Schin if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2) 894*4887Schin { 895*4887Schin /* see whether inside `...` */ 896*4887Schin mode = oldmode(); 897*4887Schin poplevel(); 898*4887Schin if((n = endchar()) != '`') 899*4887Schin goto err; 900*4887Schin pushlevel(RBRACE,mode); 901*4887Schin } 902*4887Schin else 903*4887Schin setchar(RBRACE); 904*4887Schin mode = ST_NESTED; 905*4887Schin continue; 906*4887Schin case S_MOD1: 907*4887Schin if(oldmode()==ST_QUOTE || oldmode()==ST_NONE) 908*4887Schin { 909*4887Schin /* allow ' inside "${...}" */ 910*4887Schin if(c==':' && fcgetc(n)>0) 911*4887Schin { 912*4887Schin n = state[n]; 913*4887Schin fcseek(-1); 914*4887Schin } 915*4887Schin if(n==S_MOD1) 916*4887Schin { 917*4887Schin mode = ST_QUOTE; 918*4887Schin continue; 919*4887Schin } 920*4887Schin } 921*4887Schin /* FALL THRU */ 922*4887Schin case S_MOD2: 923*4887Schin #if SHOPT_KIA 924*4887Schin if(shlex.kiafile) 925*4887Schin refvar(1); 926*4887Schin #endif /* SHOPT_KIA */ 927*4887Schin if(c!=':' && fcgetc(n)>0) 928*4887Schin { 929*4887Schin if(n!=c) 930*4887Schin c = 0; 931*4887Schin if(!c || (fcgetc(n)>0)) 932*4887Schin { 933*4887Schin fcseek(-1); 934*4887Schin if(n==LPAREN) 935*4887Schin { 936*4887Schin if(c!='%') 937*4887Schin { 938*4887Schin shlex.token = n; 939*4887Schin sh_syntax(); 940*4887Schin } 941*4887Schin else if(lexd.warn) 942*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%'); 943*4887Schin } 944*4887Schin } 945*4887Schin } 946*4887Schin mode = ST_NESTED; 947*4887Schin continue; 948*4887Schin case S_LBRA: 949*4887Schin if((c=endchar()) == '$') 950*4887Schin { 951*4887Schin setchar(RBRACE); 952*4887Schin if(fcgetc(c)>0) 953*4887Schin fcseek(-1); 954*4887Schin if(state[c]!=S_ERR && c!=RBRACE) 955*4887Schin continue; 956*4887Schin } 957*4887Schin err: 958*4887Schin n = endchar(); 959*4887Schin mode = oldmode(); 960*4887Schin poplevel(); 961*4887Schin if(n!='$') 962*4887Schin { 963*4887Schin shlex.token = c; 964*4887Schin sh_syntax(); 965*4887Schin } 966*4887Schin else 967*4887Schin { 968*4887Schin if(lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE)) 969*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno); 970*4887Schin else if(c=='"' && mode!=ST_QUOTE) 971*4887Schin wordflags |= ARG_MESSAGE; 972*4887Schin fcseek(-1); 973*4887Schin } 974*4887Schin continue; 975*4887Schin case S_META: 976*4887Schin if(lexd.warn && endchar()==RBRACE) 977*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c); 978*4887Schin continue; 979*4887Schin case S_PUSH: 980*4887Schin pushlevel(RPAREN,mode); 981*4887Schin mode = ST_NESTED; 982*4887Schin continue; 983*4887Schin case S_POP: 984*4887Schin do_pop: 985*4887Schin if(lexd.level <= inlevel) 986*4887Schin break; 987*4887Schin n = endchar(); 988*4887Schin if(c==RBRACT && !(n==RBRACT || n==RPAREN)) 989*4887Schin continue; 990*4887Schin if((c==RBRACE||c==RPAREN) && n==RPAREN) 991*4887Schin { 992*4887Schin if(fcgetc(n)==LPAREN) 993*4887Schin { 994*4887Schin if(c!=RPAREN) 995*4887Schin fcseek(-1); 996*4887Schin continue; 997*4887Schin } 998*4887Schin if(n>0) 999*4887Schin fcseek(-1); 1000*4887Schin n = RPAREN; 1001*4887Schin } 1002*4887Schin if(c==';' && n!=';') 1003*4887Schin { 1004*4887Schin if(lexd.warn && n==RBRACE) 1005*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c); 1006*4887Schin continue; 1007*4887Schin } 1008*4887Schin if(mode==ST_QNEST) 1009*4887Schin { 1010*4887Schin if(lexd.warn) 1011*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c); 1012*4887Schin continue; 1013*4887Schin } 1014*4887Schin mode = oldmode(); 1015*4887Schin poplevel(); 1016*4887Schin /* quotes in subscript need expansion */ 1017*4887Schin if(mode==ST_NAME && (wordflags&ARG_QUOTED)) 1018*4887Schin wordflags |= ARG_MAC; 1019*4887Schin /* check for ((...)) */ 1020*4887Schin if(n==1 && c==RPAREN) 1021*4887Schin { 1022*4887Schin if(fcgetc(n)==RPAREN) 1023*4887Schin { 1024*4887Schin if(mode==ST_NONE && !lexd.dolparen) 1025*4887Schin goto breakloop; 1026*4887Schin lex.reservok = 1; 1027*4887Schin lex.skipword = 0; 1028*4887Schin return(shlex.token=EXPRSYM); 1029*4887Schin } 1030*4887Schin /* backward compatibility */ 1031*4887Schin if(lexd.dolparen) 1032*4887Schin fcseek(-1); 1033*4887Schin else 1034*4887Schin { 1035*4887Schin if(lexd.warn) 1036*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno); 1037*4887Schin if(!(state=lexd.first)) 1038*4887Schin state = fcfirst(); 1039*4887Schin fcseek(state-fcseek(0)); 1040*4887Schin if(shlex.arg) 1041*4887Schin { 1042*4887Schin shlex.arg = (struct argnod*)stakfreeze(1); 1043*4887Schin setupalias(lp,shlex.arg->argval,NIL(Namval_t*)); 1044*4887Schin } 1045*4887Schin lexd.paren = 1; 1046*4887Schin } 1047*4887Schin return(shlex.token=LPAREN); 1048*4887Schin } 1049*4887Schin if(mode==ST_NONE) 1050*4887Schin return(0); 1051*4887Schin if(c!=n) 1052*4887Schin { 1053*4887Schin shlex.token = c; 1054*4887Schin sh_syntax(); 1055*4887Schin } 1056*4887Schin if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM)) 1057*4887Schin goto epat; 1058*4887Schin continue; 1059*4887Schin case S_EQ: 1060*4887Schin assignment = shlex.assignok; 1061*4887Schin /* FALL THRU */ 1062*4887Schin case S_COLON: 1063*4887Schin if(assignment) 1064*4887Schin { 1065*4887Schin if((c=fcget())=='~') 1066*4887Schin wordflags |= ARG_MAC; 1067*4887Schin else if(c!=LPAREN && assignment==SH_COMPASSIGN) 1068*4887Schin assignment = 0; 1069*4887Schin fcseek(-1); 1070*4887Schin } 1071*4887Schin break; 1072*4887Schin case S_LABEL: 1073*4887Schin if(lex.reservok && !lex.incase) 1074*4887Schin { 1075*4887Schin c = fcget(); 1076*4887Schin fcseek(-1); 1077*4887Schin if(state[c]==S_BREAK) 1078*4887Schin { 1079*4887Schin assignment = -1; 1080*4887Schin goto breakloop; 1081*4887Schin } 1082*4887Schin } 1083*4887Schin break; 1084*4887Schin case S_BRACT: 1085*4887Schin /* check for possible subscript */ 1086*4887Schin if((n=endchar())==RBRACT || n==RPAREN || 1087*4887Schin (mode==ST_BRACE) || 1088*4887Schin (oldmode()==ST_NONE) || 1089*4887Schin (mode==ST_NAME && (shlex.assignok||lexd.level))) 1090*4887Schin { 1091*4887Schin pushlevel(RBRACT,mode); 1092*4887Schin wordflags |= ARG_QUOTED; 1093*4887Schin mode = ST_NESTED; 1094*4887Schin continue; 1095*4887Schin } 1096*4887Schin wordflags |= ARG_EXP; 1097*4887Schin break; 1098*4887Schin case S_BRACE: 1099*4887Schin { 1100*4887Schin int isfirst; 1101*4887Schin if(lexd.dolparen) 1102*4887Schin break; 1103*4887Schin isfirst = (lexd.first&&fcseek(0)==lexd.first+1); 1104*4887Schin fcgetc(n); 1105*4887Schin /* check for {} */ 1106*4887Schin if(c==LBRACE && n==RBRACE) 1107*4887Schin break; 1108*4887Schin if(n>0) 1109*4887Schin fcseek(-1); 1110*4887Schin else if(lex.reservok) 1111*4887Schin break; 1112*4887Schin /* check for reserved word { or } */ 1113*4887Schin if(lex.reservok && state[n]==S_BREAK && isfirst) 1114*4887Schin break; 1115*4887Schin if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK 1116*4887Schin && !lex.incase && !lex.intest 1117*4887Schin && !lex.skipword) 1118*4887Schin { 1119*4887Schin wordflags |= ARG_EXP; 1120*4887Schin } 1121*4887Schin if(c==RBRACE && n==LPAREN) 1122*4887Schin goto epat; 1123*4887Schin break; 1124*4887Schin } 1125*4887Schin case S_PAT: 1126*4887Schin wordflags |= ARG_EXP; 1127*4887Schin /* FALL THRU */ 1128*4887Schin case S_EPAT: 1129*4887Schin epat: 1130*4887Schin if(fcgetc(n)==LPAREN) 1131*4887Schin { 1132*4887Schin if(lex.incase==TEST_RE) 1133*4887Schin { 1134*4887Schin lex.incase++; 1135*4887Schin pushlevel(RPAREN,ST_NORM); 1136*4887Schin mode = ST_NESTED; 1137*4887Schin } 1138*4887Schin wordflags |= ARG_EXP; 1139*4887Schin pushlevel(RPAREN,mode); 1140*4887Schin mode = ST_NESTED; 1141*4887Schin continue; 1142*4887Schin } 1143*4887Schin if(n>0) 1144*4887Schin fcseek(-1); 1145*4887Schin if(n=='=' && c=='+' && mode==ST_NAME) 1146*4887Schin continue; 1147*4887Schin break; 1148*4887Schin } 1149*4887Schin lex.comp_assign = 0; 1150*4887Schin if(mode==ST_NAME) 1151*4887Schin mode = ST_NORM; 1152*4887Schin else if(mode==ST_NONE) 1153*4887Schin return(0); 1154*4887Schin } 1155*4887Schin breakloop: 1156*4887Schin if(lexd.dolparen) 1157*4887Schin { 1158*4887Schin lexd.balance = 0; 1159*4887Schin if(lexd.docword) 1160*4887Schin nested_here(lp); 1161*4887Schin lexd.message = (wordflags&ARG_MESSAGE); 1162*4887Schin return(shlex.token=0); 1163*4887Schin } 1164*4887Schin if(!(state=lexd.first)) 1165*4887Schin state = fcfirst(); 1166*4887Schin n = fcseek(0)-(char*)state; 1167*4887Schin if(!shlex.arg) 1168*4887Schin shlex.arg = (struct argnod*)stakseek(ARGVAL); 1169*4887Schin if(n>0) 1170*4887Schin stakwrite(state,n); 1171*4887Schin /* add balancing character if necessary */ 1172*4887Schin if(lexd.balance) 1173*4887Schin { 1174*4887Schin stakputc(lexd.balance); 1175*4887Schin lexd.balance = 0; 1176*4887Schin } 1177*4887Schin stakputc(0); 1178*4887Schin stakseek(staktell()-1); 1179*4887Schin state = stakptr(ARGVAL); 1180*4887Schin n = staktell()-ARGVAL; 1181*4887Schin lexd.first=0; 1182*4887Schin if(n==1) 1183*4887Schin { 1184*4887Schin /* check for numbered redirection */ 1185*4887Schin n = state[0]; 1186*4887Schin if((c=='<' || c=='>') && isadigit(n)) 1187*4887Schin { 1188*4887Schin c = sh_lex(); 1189*4887Schin shlex.digits = (n-'0'); 1190*4887Schin return(c); 1191*4887Schin } 1192*4887Schin if(n==LBRACT) 1193*4887Schin c = 0; 1194*4887Schin else if(n=='~') 1195*4887Schin c = ARG_MAC; 1196*4887Schin else 1197*4887Schin c = (wordflags&ARG_EXP); 1198*4887Schin n = 1; 1199*4887Schin } 1200*4887Schin else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lex.intest && !lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND)) 1201*4887Schin { 1202*4887Schin if(!strchr(state,',')) 1203*4887Schin { 1204*4887Schin stakseek(staktell()-1); 1205*4887Schin shlex.arg = (struct argnod*)stakfreeze(1); 1206*4887Schin return(shlex.token=IOVNAME); 1207*4887Schin } 1208*4887Schin c = wordflags; 1209*4887Schin } 1210*4887Schin else 1211*4887Schin c = wordflags; 1212*4887Schin if(assignment<0) 1213*4887Schin { 1214*4887Schin stakseek(staktell()-1); 1215*4887Schin shlex.arg = (struct argnod*)stakfreeze(1); 1216*4887Schin lex.reservok = 1; 1217*4887Schin return(shlex.token=LABLSYM); 1218*4887Schin } 1219*4887Schin if(assignment || (lex.intest&&!lex.incase) || mode==ST_NONE) 1220*4887Schin c &= ~ARG_EXP; 1221*4887Schin if((c&ARG_EXP) && (c&ARG_QUOTED)) 1222*4887Schin c |= ARG_MAC; 1223*4887Schin if(mode==ST_NONE) 1224*4887Schin { 1225*4887Schin /* eliminate trailing )) */ 1226*4887Schin stakseek(staktell()-2); 1227*4887Schin } 1228*4887Schin if(c&ARG_MESSAGE) 1229*4887Schin { 1230*4887Schin if(sh_isoption(SH_DICTIONARY)) 1231*4887Schin shlex.arg = sh_endword(2); 1232*4887Schin if(!sh_isoption(SH_NOEXEC)) 1233*4887Schin { 1234*4887Schin shlex.arg = sh_endword(1); 1235*4887Schin c &= ~ARG_MESSAGE; 1236*4887Schin } 1237*4887Schin } 1238*4887Schin if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lexd.warn && !lexd.docword)) 1239*4887Schin { 1240*4887Schin shlex.arg = (struct argnod*)stakfreeze(1); 1241*4887Schin shlex.arg->argflag = (c?c:ARG_RAW); 1242*4887Schin } 1243*4887Schin else if(mode==ST_NONE) 1244*4887Schin shlex.arg = sh_endword(-1); 1245*4887Schin else 1246*4887Schin shlex.arg = sh_endword(0); 1247*4887Schin state = shlex.arg->argval; 1248*4887Schin lex.comp_assign = assignment; 1249*4887Schin if(assignment) 1250*4887Schin shlex.arg->argflag |= ARG_ASSIGN; 1251*4887Schin else if(!lex.skipword) 1252*4887Schin shlex.assignok = 0; 1253*4887Schin shlex.arg->argchn.cp = 0; 1254*4887Schin shlex.arg->argnxt.ap = 0; 1255*4887Schin if(mode==ST_NONE) 1256*4887Schin return(shlex.token=EXPRSYM); 1257*4887Schin if(lex.intest) 1258*4887Schin { 1259*4887Schin if(lex.testop1) 1260*4887Schin { 1261*4887Schin lex.testop1 = 0; 1262*4887Schin if(n==2 && state[0]=='-' && state[2]==0 && 1263*4887Schin strchr(test_opchars,state[1])) 1264*4887Schin { 1265*4887Schin if(lexd.warn && state[1]=='a') 1266*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno); 1267*4887Schin shlex.digits = state[1]; 1268*4887Schin shlex.token = TESTUNOP; 1269*4887Schin } 1270*4887Schin else if(n==1 && state[0]=='!' && state[1]==0) 1271*4887Schin { 1272*4887Schin lex.testop1 = 1; 1273*4887Schin shlex.token = '!'; 1274*4887Schin } 1275*4887Schin else 1276*4887Schin { 1277*4887Schin lex.testop2 = 1; 1278*4887Schin shlex.token = 0; 1279*4887Schin } 1280*4887Schin return(shlex.token); 1281*4887Schin } 1282*4887Schin lex.incase = 0; 1283*4887Schin c = sh_lookup(state,shtab_testops); 1284*4887Schin switch(c) 1285*4887Schin { 1286*4887Schin case TEST_END: 1287*4887Schin lex.testop2 = lex.intest = 0; 1288*4887Schin lex.reservok = 1; 1289*4887Schin shlex.token = ETESTSYM; 1290*4887Schin return(shlex.token); 1291*4887Schin 1292*4887Schin case TEST_SEQ: 1293*4887Schin if(lexd.warn && state[1]==0) 1294*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno); 1295*4887Schin /* FALL THRU */ 1296*4887Schin default: 1297*4887Schin if(lex.testop2) 1298*4887Schin { 1299*4887Schin if(lexd.warn && (c&TEST_ARITH)) 1300*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state); 1301*4887Schin if(c&TEST_PATTERN) 1302*4887Schin lex.incase = 1; 1303*4887Schin else if(c==TEST_REP) 1304*4887Schin lex.incase = TEST_RE; 1305*4887Schin lex.testop2 = 0; 1306*4887Schin shlex.digits = c; 1307*4887Schin shlex.token = TESTBINOP; 1308*4887Schin return(shlex.token); 1309*4887Schin } 1310*4887Schin 1311*4887Schin case TEST_OR: case TEST_AND: 1312*4887Schin case 0: 1313*4887Schin return(shlex.token=0); 1314*4887Schin } 1315*4887Schin } 1316*4887Schin if(lex.reservok /* && !lex.incase*/ && n<=2) 1317*4887Schin { 1318*4887Schin /* check for {, }, ! */ 1319*4887Schin c = state[0]; 1320*4887Schin if(n==1 && (c=='{' || c=='}' || c=='!')) 1321*4887Schin { 1322*4887Schin if(lexd.warn && c=='{' && lex.incase==2) 1323*4887Schin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno); 1324*4887Schin if(lex.incase==1 && c==RBRACE) 1325*4887Schin lex.incase = 0; 1326*4887Schin return(shlex.token=c); 1327*4887Schin } 1328*4887Schin else if(!lex.incase && c==LBRACT && state[1]==LBRACT) 1329*4887Schin { 1330*4887Schin lex.intest = lex.testop1 = 1; 1331*4887Schin lex.testop2 = lex.reservok = 0; 1332*4887Schin return(shlex.token=BTESTSYM); 1333*4887Schin } 1334*4887Schin } 1335*4887Schin c = 0; 1336*4887Schin if(!lex.skipword) 1337*4887Schin { 1338*4887Schin if(n>1 && lex.reservok==1 && mode==ST_NAME && 1339*4887Schin (c=sh_lookup(state,shtab_reserved))) 1340*4887Schin { 1341*4887Schin if(lex.incase) 1342*4887Schin { 1343*4887Schin if(lex.incase >1) 1344*4887Schin lex.incase = 1; 1345*4887Schin else if(c==ESACSYM) 1346*4887Schin lex.incase = 0; 1347*4887Schin else 1348*4887Schin c = 0; 1349*4887Schin } 1350*4887Schin else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM) 1351*4887Schin { 1352*4887Schin lex.skipword = 1; 1353*4887Schin lex.incase = 2*(c==CASESYM); 1354*4887Schin } 1355*4887Schin else 1356*4887Schin lex.skipword = 0; 1357*4887Schin if(c==INSYM) 1358*4887Schin lex.reservok = 0; 1359*4887Schin else if(c==TIMESYM) 1360*4887Schin { 1361*4887Schin /* yech - POSIX requires time -p */ 1362*4887Schin while(fcgetc(n)==' ' || n=='\t'); 1363*4887Schin if(n>0) 1364*4887Schin fcseek(-1); 1365*4887Schin if(n=='-') 1366*4887Schin c=0; 1367*4887Schin } 1368*4887Schin return(shlex.token=c); 1369*4887Schin } 1370*4887Schin if(!(wordflags&ARG_QUOTED) && (lex.reservok||shlex.aliasok)) 1371*4887Schin { 1372*4887Schin /* check for aliases */ 1373*4887Schin Namval_t* np; 1374*4887Schin if(!lex.incase && !assignment && fcpeek(0)!=LPAREN && 1375*4887Schin (np=nv_search(state,shp->alias_tree,HASH_SCOPE)) 1376*4887Schin && !nv_isattr(np,NV_NOEXPAND) 1377*4887Schin #if KSHELL 1378*4887Schin && (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE)) 1379*4887Schin #endif /* KSHELL */ 1380*4887Schin && (state=nv_getval(np))) 1381*4887Schin { 1382*4887Schin setupalias(lp,state,np); 1383*4887Schin nv_onattr(np,NV_NOEXPAND); 1384*4887Schin lex.reservok = 1; 1385*4887Schin shlex.assignok |= lex.reservok; 1386*4887Schin return(sh_lex()); 1387*4887Schin } 1388*4887Schin } 1389*4887Schin lex.reservok = 0; 1390*4887Schin } 1391*4887Schin lex.skipword = lexd.docword = 0; 1392*4887Schin return(shlex.token=c); 1393*4887Schin } 1394*4887Schin 1395*4887Schin /* 1396*4887Schin * read to end of command substitution 1397*4887Schin */ 1398*4887Schin static int comsub(register Lex_t *lp) 1399*4887Schin { 1400*4887Schin register int n,c,count=1; 1401*4887Schin register int line=shlex.sh->inlineno; 1402*4887Schin char word[5]; 1403*4887Schin int messages=0, assignok=shlex.assignok; 1404*4887Schin struct lexstate save; 1405*4887Schin save = lex; 1406*4887Schin sh_lexopen(lp,shlex.sh,1); 1407*4887Schin lexd.dolparen++; 1408*4887Schin lex.incase=0; 1409*4887Schin pushlevel(0,0); 1410*4887Schin if(sh_lex()==LPAREN) 1411*4887Schin { 1412*4887Schin while(1) 1413*4887Schin { 1414*4887Schin /* look for case and esac */ 1415*4887Schin n=0; 1416*4887Schin while(1) 1417*4887Schin { 1418*4887Schin fcgetc(c); 1419*4887Schin /* skip leading white space */ 1420*4887Schin if(n==0 && !sh_lexstates[ST_BEGIN][c]) 1421*4887Schin continue; 1422*4887Schin if(n==4) 1423*4887Schin break; 1424*4887Schin if(sh_lexstates[ST_NAME][c]) 1425*4887Schin goto skip; 1426*4887Schin word[n++] = c; 1427*4887Schin } 1428*4887Schin if(sh_lexstates[ST_NAME][c]==S_BREAK) 1429*4887Schin { 1430*4887Schin if(memcmp(word,"case",4)==0) 1431*4887Schin lex.incase=1; 1432*4887Schin else if(memcmp(word,"esac",4)==0) 1433*4887Schin lex.incase=0; 1434*4887Schin } 1435*4887Schin skip: 1436*4887Schin if(c && (c!='#' || n==0)) 1437*4887Schin fcseek(-1); 1438*4887Schin if(c==RBRACE && lex.incase) 1439*4887Schin lex.incase=0; 1440*4887Schin switch(sh_lex()) 1441*4887Schin { 1442*4887Schin case LPAREN: case IPROCSYM: case OPROCSYM: 1443*4887Schin if(!lex.incase) 1444*4887Schin count++; 1445*4887Schin break; 1446*4887Schin case RPAREN: 1447*4887Schin if(lex.incase) 1448*4887Schin lex.incase=0; 1449*4887Schin else if(--count<=0) 1450*4887Schin goto done; 1451*4887Schin break; 1452*4887Schin case EOFSYM: 1453*4887Schin shlex.lastline = line; 1454*4887Schin shlex.lasttok = LPAREN; 1455*4887Schin sh_syntax(); 1456*4887Schin case IOSEEKSYM: 1457*4887Schin if(fcgetc(c)!='#' && c>0) 1458*4887Schin fcseek(-1); 1459*4887Schin break; 1460*4887Schin case IODOCSYM: 1461*4887Schin sh_lex(); 1462*4887Schin break; 1463*4887Schin case 0: 1464*4887Schin messages |= lexd.message; 1465*4887Schin } 1466*4887Schin } 1467*4887Schin } 1468*4887Schin done: 1469*4887Schin poplevel(); 1470*4887Schin shlex.lastline = line; 1471*4887Schin lexd.dolparen--; 1472*4887Schin lex = save; 1473*4887Schin shlex.assignok = (endchar()==RBRACT?assignok:0); 1474*4887Schin return(messages); 1475*4887Schin } 1476*4887Schin 1477*4887Schin /* 1478*4887Schin * here-doc nested in $(...) 1479*4887Schin * allocate ionode with delimiter filled in without disturbing stak 1480*4887Schin */ 1481*4887Schin static void nested_here(register Lex_t *lp) 1482*4887Schin { 1483*4887Schin register struct ionod *iop; 1484*4887Schin register int n,offset; 1485*4887Schin struct argnod *arg = shlex.arg; 1486*4887Schin char *base; 1487*4887Schin if(offset=staktell()) 1488*4887Schin base = stakfreeze(0); 1489*4887Schin n = fcseek(0)-lexd.docend; 1490*4887Schin iop = newof(0,struct ionod,1,n+ARGVAL); 1491*4887Schin iop->iolst = shlex.heredoc; 1492*4887Schin stakseek(ARGVAL); 1493*4887Schin stakwrite(lexd.docend,n); 1494*4887Schin shlex.arg = sh_endword(0); 1495*4887Schin iop->ioname = (char*)(iop+1); 1496*4887Schin strcpy(iop->ioname,shlex.arg->argval); 1497*4887Schin iop->iofile = (IODOC|IORAW); 1498*4887Schin if(lexd.docword>1) 1499*4887Schin iop->iofile |= IOSTRIP; 1500*4887Schin shlex.heredoc = iop; 1501*4887Schin shlex.arg = arg; 1502*4887Schin lexd.docword = 0; 1503*4887Schin if(offset) 1504*4887Schin stakset(base,offset); 1505*4887Schin else 1506*4887Schin stakseek(0); 1507*4887Schin } 1508*4887Schin 1509*4887Schin /* 1510*4887Schin * skip to <close> character 1511*4887Schin * if <copy> is non,zero, then the characters are copied to the stack 1512*4887Schin * <state> is the initial lexical state 1513*4887Schin */ 1514*4887Schin void sh_lexskip(int close, register int copy, int state) 1515*4887Schin { 1516*4887Schin register Lex_t *lp = (Lex_t*)sh.lex_context; 1517*4887Schin register char *cp; 1518*4887Schin lexd.nest = close; 1519*4887Schin lexd.lex_state = state; 1520*4887Schin lexd.noarg = 1; 1521*4887Schin if(copy) 1522*4887Schin fcnotify(lex_advance); 1523*4887Schin else 1524*4887Schin lexd.nocopy++; 1525*4887Schin sh_lex(); 1526*4887Schin lexd.noarg = 0; 1527*4887Schin if(copy) 1528*4887Schin { 1529*4887Schin fcnotify(0); 1530*4887Schin if(!(cp=lexd.first)) 1531*4887Schin cp = fcfirst(); 1532*4887Schin if((copy = fcseek(0)-cp) > 0) 1533*4887Schin stakwrite(cp,copy); 1534*4887Schin } 1535*4887Schin else 1536*4887Schin lexd.nocopy--; 1537*4887Schin } 1538*4887Schin 1539*4887Schin #if SHOPT_CRNL 1540*4887Schin ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n) 1541*4887Schin { 1542*4887Schin const char *cp = (const char*)buff, *next=cp, *ep = cp + n; 1543*4887Schin int m=0,k; 1544*4887Schin while(next = (const char*)memchr(next,'\r',ep-next)) 1545*4887Schin if(*++next=='\n') 1546*4887Schin { 1547*4887Schin if(k=next-cp-1) 1548*4887Schin { 1549*4887Schin if((k=sfwrite(sp,cp,k)) < 0) 1550*4887Schin return(m>0?m:-1); 1551*4887Schin m += k; 1552*4887Schin } 1553*4887Schin cp = next; 1554*4887Schin } 1555*4887Schin if((k=sfwrite(sp,cp,ep-cp)) < 0) 1556*4887Schin return(m>0?m:-1); 1557*4887Schin return(m+k); 1558*4887Schin } 1559*4887Schin # define sfwrite _sfwrite 1560*4887Schin #endif /* SHOPT_CRNL */ 1561*4887Schin 1562*4887Schin /* 1563*4887Schin * read in here-document from script 1564*4887Schin * quoted here documents, and here-documents without special chars are 1565*4887Schin * noted with the IOQUOTE flag 1566*4887Schin * returns 1 for complete here-doc, 0 for EOF 1567*4887Schin */ 1568*4887Schin 1569*4887Schin static int here_copy(Lex_t *lp,register struct ionod *iop) 1570*4887Schin { 1571*4887Schin register const char *state; 1572*4887Schin register int c,n; 1573*4887Schin register char *bufp,*cp; 1574*4887Schin register Sfio_t *sp=shlex.sh->heredocs, *funlog; 1575*4887Schin int stripcol=0,stripflg, nsave, special=0; 1576*4887Schin if(funlog=shlex.sh->funlog) 1577*4887Schin { 1578*4887Schin if(fcfill()>0) 1579*4887Schin fcseek(-1); 1580*4887Schin shlex.sh->funlog = 0; 1581*4887Schin } 1582*4887Schin if(iop->iolst) 1583*4887Schin here_copy(lp,iop->iolst); 1584*4887Schin iop->iooffset = sfseek(sp,(off_t)0,SEEK_END); 1585*4887Schin iop->iosize = 0; 1586*4887Schin iop->iodelim=iop->ioname; 1587*4887Schin /* check for and strip quoted characters in delimiter string */ 1588*4887Schin if(stripflg=iop->iofile&IOSTRIP) 1589*4887Schin { 1590*4887Schin while(*iop->iodelim=='\t') 1591*4887Schin iop->iodelim++; 1592*4887Schin /* skip over leading tabs in document */ 1593*4887Schin if(iop->iofile&IOLSEEK) 1594*4887Schin { 1595*4887Schin iop->iofile &= ~IOLSEEK; 1596*4887Schin while(fcgetc(c)=='\t' || c==' ') 1597*4887Schin { 1598*4887Schin if(c==' ') 1599*4887Schin stripcol++; 1600*4887Schin else 1601*4887Schin stripcol += 8 - stripcol%8; 1602*4887Schin } 1603*4887Schin } 1604*4887Schin else 1605*4887Schin while(fcgetc(c)=='\t'); 1606*4887Schin if(c>0) 1607*4887Schin fcseek(-1); 1608*4887Schin } 1609*4887Schin if(iop->iofile&IOQUOTE) 1610*4887Schin state = sh_lexstates[ST_LIT]; 1611*4887Schin else 1612*4887Schin state = sh_lexstates[ST_QUOTE]; 1613*4887Schin bufp = fcseek(0); 1614*4887Schin n = S_NL; 1615*4887Schin while(1) 1616*4887Schin { 1617*4887Schin if(n!=S_NL) 1618*4887Schin { 1619*4887Schin /* skip over regular characters */ 1620*4887Schin while((n=STATE(state,c))==0); 1621*4887Schin } 1622*4887Schin if(n==S_EOF || !(c=fcget())) 1623*4887Schin { 1624*4887Schin if(!lexd.dolparen && (c=(fcseek(0)-1)-bufp)) 1625*4887Schin { 1626*4887Schin if(n==S_ESC) 1627*4887Schin c--; 1628*4887Schin if((c=sfwrite(sp,bufp,c))>0) 1629*4887Schin iop->iosize += c; 1630*4887Schin } 1631*4887Schin if((c=lexfill())<=0) 1632*4887Schin break; 1633*4887Schin if(n==S_ESC) 1634*4887Schin { 1635*4887Schin #if SHOPT_CRNL 1636*4887Schin if(c=='\r' && (c=fcget())!=NL) 1637*4887Schin fcseek(-1); 1638*4887Schin #endif /* SHOPT_CRNL */ 1639*4887Schin if(c==NL) 1640*4887Schin fcseek(1); 1641*4887Schin else 1642*4887Schin sfputc(sp,'\\'); 1643*4887Schin } 1644*4887Schin bufp = fcseek(-1); 1645*4887Schin } 1646*4887Schin else 1647*4887Schin fcseek(-1); 1648*4887Schin switch(n) 1649*4887Schin { 1650*4887Schin case S_NL: 1651*4887Schin shlex.sh->inlineno++; 1652*4887Schin if((stripcol && c==' ') || (stripflg && c=='\t')) 1653*4887Schin { 1654*4887Schin if(!lexd.dolparen) 1655*4887Schin { 1656*4887Schin /* write out line */ 1657*4887Schin n = fcseek(0)-bufp; 1658*4887Schin if((n=sfwrite(sp,bufp,n))>0) 1659*4887Schin iop->iosize += n; 1660*4887Schin } 1661*4887Schin /* skip over tabs */ 1662*4887Schin if(stripcol) 1663*4887Schin { 1664*4887Schin int col=0; 1665*4887Schin do 1666*4887Schin { 1667*4887Schin fcgetc(c); 1668*4887Schin if(c==' ') 1669*4887Schin col++; 1670*4887Schin else 1671*4887Schin col += 8 - col%8; 1672*4887Schin if(col>stripcol) 1673*4887Schin break; 1674*4887Schin } 1675*4887Schin while (c==' ' || c=='\t'); 1676*4887Schin } 1677*4887Schin else while(c=='\t') 1678*4887Schin fcgetc(c); 1679*4887Schin if(c<=0) 1680*4887Schin goto done; 1681*4887Schin bufp = fcseek(-1); 1682*4887Schin } 1683*4887Schin if(c!=iop->iodelim[0]) 1684*4887Schin break; 1685*4887Schin cp = fcseek(0); 1686*4887Schin nsave = n = 0; 1687*4887Schin while(1) 1688*4887Schin { 1689*4887Schin if(!(c=fcget())) 1690*4887Schin { 1691*4887Schin if(!lexd.dolparen && (c=cp-bufp)) 1692*4887Schin { 1693*4887Schin if((c=sfwrite(sp,cp=bufp,c))>0) 1694*4887Schin iop->iosize+=c; 1695*4887Schin } 1696*4887Schin nsave = n; 1697*4887Schin if((c=lexfill())<=0) 1698*4887Schin { 1699*4887Schin c = iop->iodelim[n]==0; 1700*4887Schin goto done; 1701*4887Schin } 1702*4887Schin } 1703*4887Schin #if SHOPT_CRNL 1704*4887Schin if(c=='\r' && (c=fcget())!=NL) 1705*4887Schin { 1706*4887Schin if(c) 1707*4887Schin fcseek(-1); 1708*4887Schin c='\r'; 1709*4887Schin } 1710*4887Schin #endif /* SHOPT_CRNL */ 1711*4887Schin if(c==NL) 1712*4887Schin shlex.sh->inlineno++; 1713*4887Schin if(iop->iodelim[n]==0 && (c==NL||c==RPAREN)) 1714*4887Schin { 1715*4887Schin if(!lexd.dolparen && (n=cp-bufp)) 1716*4887Schin { 1717*4887Schin if((n=sfwrite(sp,bufp,n))>0) 1718*4887Schin iop->iosize += n; 1719*4887Schin } 1720*4887Schin shlex.sh->inlineno--; 1721*4887Schin if(c==RPAREN) 1722*4887Schin fcseek(-1); 1723*4887Schin goto done; 1724*4887Schin } 1725*4887Schin if(iop->iodelim[n++]!=c) 1726*4887Schin { 1727*4887Schin /* 1728*4887Schin * The match for delimiter failed. 1729*4887Schin * nsave>0 only when a buffer boundary 1730*4887Schin * was crossed while checking the 1731*4887Schin * delimiter 1732*4887Schin */ 1733*4887Schin if(!lexd.dolparen && nsave>0) 1734*4887Schin { 1735*4887Schin if((n=sfwrite(sp,bufp,nsave))>0) 1736*4887Schin iop->iosize += n; 1737*4887Schin bufp = fcfirst(); 1738*4887Schin } 1739*4887Schin if(c==NL) 1740*4887Schin fcseek(-1); 1741*4887Schin break; 1742*4887Schin } 1743*4887Schin } 1744*4887Schin break; 1745*4887Schin case S_ESC: 1746*4887Schin n=1; 1747*4887Schin #if SHOPT_CRNL 1748*4887Schin if(c=='\r') 1749*4887Schin { 1750*4887Schin fcseek(1); 1751*4887Schin if(c=fcget()) 1752*4887Schin fcseek(-1); 1753*4887Schin if(c==NL) 1754*4887Schin n=2; 1755*4887Schin else 1756*4887Schin { 1757*4887Schin special++; 1758*4887Schin break; 1759*4887Schin } 1760*4887Schin } 1761*4887Schin #endif /* SHOPT_CRNL */ 1762*4887Schin if(c==NL) 1763*4887Schin { 1764*4887Schin /* new-line joining */ 1765*4887Schin shlex.sh->inlineno++; 1766*4887Schin if(!lexd.dolparen && (n=(fcseek(0)-bufp)-n)>0) 1767*4887Schin { 1768*4887Schin if((n=sfwrite(sp,bufp,n))>0) 1769*4887Schin iop->iosize += n; 1770*4887Schin bufp = fcseek(0)+1; 1771*4887Schin } 1772*4887Schin } 1773*4887Schin else 1774*4887Schin special++; 1775*4887Schin fcget(); 1776*4887Schin break; 1777*4887Schin 1778*4887Schin case S_GRAVE: 1779*4887Schin case S_DOL: 1780*4887Schin special++; 1781*4887Schin break; 1782*4887Schin } 1783*4887Schin n=0; 1784*4887Schin } 1785*4887Schin done: 1786*4887Schin shlex.sh->funlog = funlog; 1787*4887Schin if(lexd.dolparen) 1788*4887Schin free((void*)iop); 1789*4887Schin else if(!special) 1790*4887Schin iop->iofile |= IOQUOTE; 1791*4887Schin return(c); 1792*4887Schin } 1793*4887Schin 1794*4887Schin /* 1795*4887Schin * generates string for given token 1796*4887Schin */ 1797*4887Schin static char *fmttoken(Lex_t *lp, register int sym, char *tok) 1798*4887Schin { 1799*4887Schin if(sym < 0) 1800*4887Schin return((char*)sh_translate(e_lexzerobyte)); 1801*4887Schin if(sym==0) 1802*4887Schin return(shlex.arg?shlex.arg->argval:"?"); 1803*4887Schin if(lex.intest && shlex.arg && *shlex.arg->argval) 1804*4887Schin return(shlex.arg->argval); 1805*4887Schin if(sym&SYMRES) 1806*4887Schin { 1807*4887Schin register const Shtable_t *tp=shtab_reserved; 1808*4887Schin while(tp->sh_number && tp->sh_number!=sym) 1809*4887Schin tp++; 1810*4887Schin return((char*)tp->sh_name); 1811*4887Schin } 1812*4887Schin if(sym==EOFSYM) 1813*4887Schin return((char*)sh_translate(e_endoffile)); 1814*4887Schin if(sym==NL) 1815*4887Schin return((char*)sh_translate(e_newline)); 1816*4887Schin tok[0] = sym; 1817*4887Schin if(sym&SYMREP) 1818*4887Schin tok[1] = sym; 1819*4887Schin else 1820*4887Schin { 1821*4887Schin switch(sym&SYMMASK) 1822*4887Schin { 1823*4887Schin case SYMAMP: 1824*4887Schin sym = '&'; 1825*4887Schin break; 1826*4887Schin case SYMPIPE: 1827*4887Schin sym = '|'; 1828*4887Schin break; 1829*4887Schin case SYMGT: 1830*4887Schin sym = '>'; 1831*4887Schin break; 1832*4887Schin case SYMLPAR: 1833*4887Schin sym = LPAREN; 1834*4887Schin break; 1835*4887Schin case SYMSHARP: 1836*4887Schin sym = '#'; 1837*4887Schin break; 1838*4887Schin default: 1839*4887Schin sym = 0; 1840*4887Schin } 1841*4887Schin tok[1] = sym; 1842*4887Schin } 1843*4887Schin tok[2] = 0; 1844*4887Schin return(tok); 1845*4887Schin } 1846*4887Schin 1847*4887Schin /* 1848*4887Schin * print a bad syntax message 1849*4887Schin */ 1850*4887Schin 1851*4887Schin void sh_syntax(void) 1852*4887Schin { 1853*4887Schin register Shell_t *shp = sh_getinterp(); 1854*4887Schin register const char *cp = sh_translate(e_unexpected); 1855*4887Schin register char *tokstr; 1856*4887Schin register Lex_t *lp = (Lex_t*)shp->lex_context; 1857*4887Schin register int tok = shlex.token; 1858*4887Schin char tokbuf[3]; 1859*4887Schin Sfio_t *sp; 1860*4887Schin if((tok==EOFSYM) && shlex.lasttok) 1861*4887Schin { 1862*4887Schin tok = shlex.lasttok; 1863*4887Schin cp = sh_translate(e_unmatched); 1864*4887Schin } 1865*4887Schin else 1866*4887Schin shlex.lastline = shp->inlineno; 1867*4887Schin tokstr = fmttoken(lp,tok,tokbuf); 1868*4887Schin if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd]))) 1869*4887Schin { 1870*4887Schin /* clear out any pending input */ 1871*4887Schin register Sfio_t *top; 1872*4887Schin while(fcget()>0); 1873*4887Schin fcclose(); 1874*4887Schin while(top=sfstack(sp,SF_POPSTACK)) 1875*4887Schin sfclose(top); 1876*4887Schin } 1877*4887Schin else 1878*4887Schin fcclose(); 1879*4887Schin shp->inlineno = shlex.inlineno; 1880*4887Schin shp->st.firstline = shlex.firstline; 1881*4887Schin #if KSHELL 1882*4887Schin if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE)) 1883*4887Schin #else 1884*4887Schin if(shp->inlineno!=1) 1885*4887Schin #endif 1886*4887Schin errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,shlex.lastline,tokstr,cp); 1887*4887Schin else 1888*4887Schin errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp); 1889*4887Schin } 1890*4887Schin 1891*4887Schin static char *stack_shift(register char *sp,char *dp) 1892*4887Schin { 1893*4887Schin register char *ep; 1894*4887Schin register int offset = staktell(); 1895*4887Schin register int left = offset-(sp-stakptr(0)); 1896*4887Schin register int shift = (dp+1-sp); 1897*4887Schin offset += shift; 1898*4887Schin stakseek(offset); 1899*4887Schin sp = stakptr(offset); 1900*4887Schin ep = sp - shift; 1901*4887Schin while(left--) 1902*4887Schin *--sp = *--ep; 1903*4887Schin return(sp); 1904*4887Schin } 1905*4887Schin 1906*4887Schin /* 1907*4887Schin * Assumes that current word is unfrozen on top of the stak 1908*4887Schin * If <mode> is zero, gets rid of quoting and consider argument as string 1909*4887Schin * and returns pointer to frozen arg 1910*4887Schin * If mode==1, just replace $"..." strings with international strings 1911*4887Schin * The result is left on the stak 1912*4887Schin * If mode==2, the each $"" string is printed on standard output 1913*4887Schin */ 1914*4887Schin struct argnod *sh_endword(int mode) 1915*4887Schin { 1916*4887Schin register const char *state = sh_lexstates[ST_NESTED]; 1917*4887Schin register int n; 1918*4887Schin register char *sp,*dp; 1919*4887Schin register int inquote=0, inlit=0; /* set within quoted strings */ 1920*4887Schin struct argnod* argp=0; 1921*4887Schin char *ep=0, *xp=0; 1922*4887Schin int bracket=0; 1923*4887Schin stakputc(0); 1924*4887Schin sp = stakptr(ARGVAL); 1925*4887Schin #if SHOPT_MULTIBYTE 1926*4887Schin if(mbwide()) 1927*4887Schin { 1928*4887Schin do 1929*4887Schin { 1930*4887Schin int len; 1931*4887Schin switch(len = mbsize(sp)) 1932*4887Schin { 1933*4887Schin case -1: /* illegal multi-byte char */ 1934*4887Schin case 0: 1935*4887Schin case 1: 1936*4887Schin n=state[*sp++]; 1937*4887Schin break; 1938*4887Schin default: 1939*4887Schin /* 1940*4887Schin * None of the state tables contain 1941*4887Schin * entries for multibyte characters, 1942*4887Schin * however, they should be treated 1943*4887Schin * the same as any other alph 1944*4887Schin * character. Therefore, we'll use 1945*4887Schin * the state of the 'a' character. 1946*4887Schin */ 1947*4887Schin n=state['a']; 1948*4887Schin sp += len; 1949*4887Schin } 1950*4887Schin } 1951*4887Schin while(n == 0); 1952*4887Schin } 1953*4887Schin else 1954*4887Schin #endif /* SHOPT_MULTIBYTE */ 1955*4887Schin while((n=state[*sp++])==0); 1956*4887Schin dp = sp; 1957*4887Schin if(mode<0) 1958*4887Schin inquote = 1; 1959*4887Schin while(1) 1960*4887Schin { 1961*4887Schin switch(n) 1962*4887Schin { 1963*4887Schin case S_EOF: 1964*4887Schin stakseek(dp-stakptr(0)); 1965*4887Schin if(mode<=0) 1966*4887Schin { 1967*4887Schin argp = (struct argnod*)stakfreeze(0); 1968*4887Schin argp->argflag = ARG_RAW|ARG_QUOTED; 1969*4887Schin } 1970*4887Schin return(argp); 1971*4887Schin case S_LIT: 1972*4887Schin if(!(inquote&1)) 1973*4887Schin { 1974*4887Schin inlit = !inlit; 1975*4887Schin if(mode==0 || (mode<0 && bracket)) 1976*4887Schin { 1977*4887Schin dp--; 1978*4887Schin if(ep) 1979*4887Schin { 1980*4887Schin *dp = 0; 1981*4887Schin dp = ep+stresc(ep); 1982*4887Schin } 1983*4887Schin ep = 0; 1984*4887Schin } 1985*4887Schin } 1986*4887Schin break; 1987*4887Schin case S_QUOTE: 1988*4887Schin if(mode<0 && !bracket) 1989*4887Schin break; 1990*4887Schin if(!inlit) 1991*4887Schin { 1992*4887Schin if(mode<=0) 1993*4887Schin dp--; 1994*4887Schin inquote = inquote^1; 1995*4887Schin if(ep) 1996*4887Schin { 1997*4887Schin char *msg; 1998*4887Schin if(mode==2) 1999*4887Schin { 2000*4887Schin sfprintf(sfstdout,"%.*s\n",dp-ep,ep); 2001*4887Schin ep = 0; 2002*4887Schin break; 2003*4887Schin } 2004*4887Schin *--dp = 0; 2005*4887Schin #if ERROR_VERSION >= 20000317L 2006*4887Schin msg = ERROR_translate(0,error_info.id,0,ep); 2007*4887Schin #else 2008*4887Schin # if ERROR_VERSION >= 20000101L 2009*4887Schin msg = ERROR_translate(error_info.id,ep); 2010*4887Schin # else 2011*4887Schin msg = ERROR_translate(ep,2); 2012*4887Schin # endif 2013*4887Schin #endif 2014*4887Schin n = strlen(msg); 2015*4887Schin dp = ep+n; 2016*4887Schin if(sp-dp <= 1) 2017*4887Schin { 2018*4887Schin sp = stack_shift(sp,dp); 2019*4887Schin dp = sp-1; 2020*4887Schin ep = dp-n; 2021*4887Schin } 2022*4887Schin memmove(ep,msg,n); 2023*4887Schin *dp++ = '"'; 2024*4887Schin } 2025*4887Schin ep = 0; 2026*4887Schin } 2027*4887Schin break; 2028*4887Schin case S_DOL: /* check for $'...' and $"..." */ 2029*4887Schin if(inlit) 2030*4887Schin break; 2031*4887Schin if(*sp==LPAREN || *sp==LBRACE) 2032*4887Schin { 2033*4887Schin inquote <<= 1; 2034*4887Schin break; 2035*4887Schin } 2036*4887Schin if(inquote&1) 2037*4887Schin break; 2038*4887Schin if(*sp=='\'' || *sp=='"') 2039*4887Schin { 2040*4887Schin if(*sp=='"') 2041*4887Schin inquote |= 1; 2042*4887Schin else 2043*4887Schin inlit = 1; 2044*4887Schin sp++; 2045*4887Schin if((mode==0||(mode<0&&bracket)) || (inquote&1)) 2046*4887Schin { 2047*4887Schin if(mode==2) 2048*4887Schin ep = dp++; 2049*4887Schin else if(mode==1) 2050*4887Schin (ep=dp)[-1] = '"'; 2051*4887Schin else 2052*4887Schin ep = --dp; 2053*4887Schin } 2054*4887Schin } 2055*4887Schin break; 2056*4887Schin case S_ESC: 2057*4887Schin #if SHOPT_CRNL 2058*4887Schin if(*sp=='\r' && sp[1]=='\n') 2059*4887Schin sp++; 2060*4887Schin #endif /* SHOPT_CRNL */ 2061*4887Schin if(inlit || mode>0) 2062*4887Schin { 2063*4887Schin if(mode<0) 2064*4887Schin { 2065*4887Schin if(dp>=sp) 2066*4887Schin { 2067*4887Schin sp = stack_shift(sp,dp+1); 2068*4887Schin dp = sp-2; 2069*4887Schin } 2070*4887Schin *dp++ = '\\'; 2071*4887Schin } 2072*4887Schin if(ep) 2073*4887Schin *dp++ = *sp++; 2074*4887Schin break; 2075*4887Schin } 2076*4887Schin n = *sp; 2077*4887Schin #if SHOPT_DOS 2078*4887Schin if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0) 2079*4887Schin break; 2080*4887Schin #endif /* SHOPT_DOS */ 2081*4887Schin if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE)) 2082*4887Schin { 2083*4887Schin if(n=='\n') 2084*4887Schin dp--; 2085*4887Schin else 2086*4887Schin dp[-1] = n; 2087*4887Schin sp++; 2088*4887Schin } 2089*4887Schin break; 2090*4887Schin case S_POP: 2091*4887Schin if(sp[-1]!=RBRACT) 2092*4887Schin break; 2093*4887Schin if(!inlit && !(inquote&1)) 2094*4887Schin { 2095*4887Schin inquote >>= 1; 2096*4887Schin if(xp) 2097*4887Schin dp = sh_checkid(xp,dp); 2098*4887Schin xp = 0; 2099*4887Schin if(--bracket<=0 && mode<0) 2100*4887Schin inquote = 1; 2101*4887Schin } 2102*4887Schin else if((inlit||inquote) && mode<0) 2103*4887Schin { 2104*4887Schin dp[-1] = '\\'; 2105*4887Schin if(dp>=sp) 2106*4887Schin { 2107*4887Schin sp = stack_shift(sp,dp); 2108*4887Schin dp = sp-1; 2109*4887Schin } 2110*4887Schin *dp++ = ']'; 2111*4887Schin } 2112*4887Schin break; 2113*4887Schin case S_BRACT: 2114*4887Schin if(dp[-2]=='.') 2115*4887Schin xp = dp; 2116*4887Schin if(mode<0) 2117*4887Schin { 2118*4887Schin if(inlit || (bracket&&inquote)) 2119*4887Schin { 2120*4887Schin dp[-1] = '\\'; 2121*4887Schin if(dp>=sp) 2122*4887Schin { 2123*4887Schin sp = stack_shift(sp,dp); 2124*4887Schin dp = sp-1; 2125*4887Schin } 2126*4887Schin *dp++ = '['; 2127*4887Schin } 2128*4887Schin else if(bracket++==0) 2129*4887Schin inquote = 0; 2130*4887Schin } 2131*4887Schin break; 2132*4887Schin } 2133*4887Schin #if SHOPT_MULTIBYTE 2134*4887Schin if(mbwide()) 2135*4887Schin { 2136*4887Schin do 2137*4887Schin { 2138*4887Schin int len; 2139*4887Schin switch(len = mbsize(sp)) 2140*4887Schin { 2141*4887Schin case -1: /* illegal multi-byte char */ 2142*4887Schin case 0: 2143*4887Schin case 1: 2144*4887Schin n=state[*dp++ = *sp++]; 2145*4887Schin break; 2146*4887Schin default: 2147*4887Schin /* 2148*4887Schin * None of the state tables contain 2149*4887Schin * entries for multibyte characters, 2150*4887Schin * however, they should be treated 2151*4887Schin * the same as any other alph 2152*4887Schin * character. Therefore, we'll use 2153*4887Schin * the state of the 'a' character. 2154*4887Schin */ 2155*4887Schin while(len--) 2156*4887Schin *dp++ = *sp++; 2157*4887Schin n=state['a']; 2158*4887Schin } 2159*4887Schin } 2160*4887Schin while(n == 0); 2161*4887Schin } 2162*4887Schin else 2163*4887Schin #endif /* SHOPT_MULTIBYTE */ 2164*4887Schin while((n=state[*dp++ = *sp++])==0); 2165*4887Schin } 2166*4887Schin } 2167*4887Schin 2168*4887Schin struct alias 2169*4887Schin { 2170*4887Schin Sfdisc_t disc; 2171*4887Schin Namval_t *np; 2172*4887Schin int nextc; 2173*4887Schin int line; 2174*4887Schin char buf[2]; 2175*4887Schin Lex_t *lp; 2176*4887Schin }; 2177*4887Schin 2178*4887Schin /* 2179*4887Schin * This code gets called whenever an end of string is found with alias 2180*4887Schin */ 2181*4887Schin 2182*4887Schin #ifndef SF_ATEXIT 2183*4887Schin # define SF_ATEXIT 0 2184*4887Schin #endif 2185*4887Schin /* 2186*4887Schin * This code gets called whenever an end of string is found with alias 2187*4887Schin */ 2188*4887Schin #ifdef SF_BUFCONST 2189*4887Schin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle) 2190*4887Schin #else 2191*4887Schin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle) 2192*4887Schin #endif 2193*4887Schin { 2194*4887Schin register struct alias *ap = (struct alias*)handle; 2195*4887Schin register Namval_t *np; 2196*4887Schin register Lex_t *lp; 2197*4887Schin if(type==0 || type==SF_ATEXIT || !ap) 2198*4887Schin return(0); 2199*4887Schin lp = ap->lp; 2200*4887Schin np = ap->np; 2201*4887Schin if(type!=SF_READ) 2202*4887Schin { 2203*4887Schin if(type==SF_CLOSING) 2204*4887Schin { 2205*4887Schin register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC); 2206*4887Schin if(dp!=handle) 2207*4887Schin sfdisc(iop,dp); 2208*4887Schin } 2209*4887Schin else if(type==SF_FINAL) 2210*4887Schin free((void*)ap); 2211*4887Schin goto done; 2212*4887Schin } 2213*4887Schin if(ap->nextc) 2214*4887Schin { 2215*4887Schin /* if last character is a blank, then next work can be alias */ 2216*4887Schin register int c = fcpeek(-1); 2217*4887Schin if(isblank(c)) 2218*4887Schin shlex.aliasok = 1; 2219*4887Schin *ap->buf = ap->nextc; 2220*4887Schin ap->nextc = 0; 2221*4887Schin sfsetbuf(iop,ap->buf,1); 2222*4887Schin return(1); 2223*4887Schin } 2224*4887Schin done: 2225*4887Schin if(np) 2226*4887Schin nv_offattr(np,NV_NOEXPAND); 2227*4887Schin return(0); 2228*4887Schin } 2229*4887Schin 2230*4887Schin 2231*4887Schin static void setupalias(Lex_t *lp, const char *string,Namval_t *np) 2232*4887Schin { 2233*4887Schin register Sfio_t *iop, *base; 2234*4887Schin struct alias *ap = (struct alias*)malloc(sizeof(struct alias)); 2235*4887Schin ap->disc = alias_disc; 2236*4887Schin ap->lp = lp; 2237*4887Schin ap->buf[1] = 0; 2238*4887Schin if(ap->np = np) 2239*4887Schin { 2240*4887Schin #if SHOPT_KIA 2241*4887Schin if(shlex.kiafile) 2242*4887Schin { 2243*4887Schin unsigned long r; 2244*4887Schin r=kiaentity(nv_name(np),-1,'p',0,0,shlex.current,'a',0,""); 2245*4887Schin sfprintf(shlex.kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",shlex.current,r,shlex.sh->inlineno,shlex.sh->inlineno); 2246*4887Schin } 2247*4887Schin #endif /* SHOPT_KIA */ 2248*4887Schin if((ap->nextc=fcget())==0) 2249*4887Schin ap->nextc = ' '; 2250*4887Schin } 2251*4887Schin else 2252*4887Schin ap->nextc = 0; 2253*4887Schin iop = sfopen(NIL(Sfio_t*),(char*)string,"s"); 2254*4887Schin sfdisc(iop, &ap->disc); 2255*4887Schin lexd.nocopy++; 2256*4887Schin if(!(base=fcfile())) 2257*4887Schin base = sfopen(NIL(Sfio_t*),fcseek(0),"s"); 2258*4887Schin fcclose(); 2259*4887Schin sfstack(base,iop); 2260*4887Schin fcfopen(base); 2261*4887Schin lexd.nocopy--; 2262*4887Schin } 2263*4887Schin 2264*4887Schin /* 2265*4887Schin * grow storage stack for nested constructs by STACK_ARRAY 2266*4887Schin */ 2267*4887Schin static int stack_grow(Lex_t *lp) 2268*4887Schin { 2269*4887Schin lexd.lex_max += STACK_ARRAY; 2270*4887Schin if(lexd.lex_match) 2271*4887Schin lexd.lex_match = (int*)realloc((char*)lexd.lex_match,sizeof(int)*lexd.lex_max); 2272*4887Schin else 2273*4887Schin lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY); 2274*4887Schin return(lexd.lex_match!=0); 2275*4887Schin } 2276*4887Schin 2277