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 * Shell macro expander 23*4887Schin * expands ~ 24*4887Schin * expands ${...} 25*4887Schin * expands $(...) 26*4887Schin * expands $((...)) 27*4887Schin * expands `...` 28*4887Schin * 29*4887Schin * David Korn 30*4887Schin * AT&T Labs 31*4887Schin * 32*4887Schin */ 33*4887Schin 34*4887Schin #include "defs.h" 35*4887Schin #include <fcin.h> 36*4887Schin #include <pwd.h> 37*4887Schin #include "name.h" 38*4887Schin #include "variables.h" 39*4887Schin #include "shlex.h" 40*4887Schin #include "io.h" 41*4887Schin #include "shnodes.h" 42*4887Schin #include "path.h" 43*4887Schin #include "national.h" 44*4887Schin #include "streval.h" 45*4887Schin 46*4887Schin #undef STR_GROUP 47*4887Schin #ifndef STR_GROUP 48*4887Schin # define STR_GROUP 0 49*4887Schin #endif 50*4887Schin 51*4887Schin #if !SHOPT_MULTIBYTE 52*4887Schin #define mbchar(p) (*(unsigned char*)p++) 53*4887Schin #endif 54*4887Schin 55*4887Schin static int _c_; 56*4887Schin typedef struct _mac_ 57*4887Schin { 58*4887Schin Shell_t *shp; /* pointer to shell interpreter */ 59*4887Schin Sfio_t *sp; /* stream pointer for here-document */ 60*4887Schin struct argnod **arghead; /* address of head of argument list */ 61*4887Schin char *ifsp; /* pointer to IFS value */ 62*4887Schin int fields; /* number of fields */ 63*4887Schin short quoted; /* set when word has quotes */ 64*4887Schin unsigned char ifs; /* first char of IFS */ 65*4887Schin char quote; /* set within double quoted contexts */ 66*4887Schin char lit; /* set within single quotes */ 67*4887Schin char split; /* set when word splittin is possible */ 68*4887Schin char pattern; /* set when file expansion follows */ 69*4887Schin char patfound; /* set if pattern character found */ 70*4887Schin char assign; /* set for assignments */ 71*4887Schin char arith; /* set for ((...)) */ 72*4887Schin char let; /* set when expanding let arguments */ 73*4887Schin char zeros; /* strip leading zeros when set */ 74*4887Schin void *nvwalk; /* for name space walking*/ 75*4887Schin } Mac_t; 76*4887Schin 77*4887Schin #define mac (*((Mac_t*)(sh.mac_context))) 78*4887Schin 79*4887Schin #undef ESCAPE 80*4887Schin #define ESCAPE '\\' 81*4887Schin #define isescchar(s) ((s)>S_QUOTE) 82*4887Schin #define isqescchar(s) ((s)>=S_QUOTE) 83*4887Schin #define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2) 84*4887Schin #define ltos(x) fmtbase((long)(x),0,0) 85*4887Schin 86*4887Schin /* type of macro expansions */ 87*4887Schin #define M_BRACE 1 /* ${var} */ 88*4887Schin #define M_TREE 2 /* ${var.} */ 89*4887Schin #define M_SIZE 3 /* ${#var} */ 90*4887Schin #define M_VNAME 4 /* ${!var} */ 91*4887Schin #define M_SUBNAME 5 /* ${!var[sub]} */ 92*4887Schin #define M_NAMESCAN 6 /* ${!var*} */ 93*4887Schin #define M_NAMECOUNT 7 /* ${#var*} */ 94*4887Schin #define M_TYPE 8 /* ${@var} */ 95*4887Schin 96*4887Schin static int substring(const char*, const char*, int[], int); 97*4887Schin static void copyto(Mac_t*, int, int); 98*4887Schin static void comsubst(Mac_t*,int); 99*4887Schin static int varsub(Mac_t*); 100*4887Schin static void mac_copy(Mac_t*,const char*, int); 101*4887Schin static void tilde_expand2(int); 102*4887Schin static char *sh_tilde(const char*); 103*4887Schin static char *special(int); 104*4887Schin static void endfield(Mac_t*,int); 105*4887Schin static void mac_error(Namval_t*); 106*4887Schin static char *mac_getstring(char*); 107*4887Schin static int charlen(const char*,int); 108*4887Schin #if SHOPT_MULTIBYTE 109*4887Schin static char *lastchar(const char*,const char*); 110*4887Schin #endif /* SHOPT_MULTIBYTE */ 111*4887Schin 112*4887Schin void *sh_macopen(Shell_t *shp) 113*4887Schin { 114*4887Schin void *addr = newof(0,Mac_t,1,0); 115*4887Schin Mac_t *mp = (Mac_t*)addr; 116*4887Schin mp->shp = shp; 117*4887Schin return(addr); 118*4887Schin } 119*4887Schin 120*4887Schin /* 121*4887Schin * perform only parameter substitution and catch failures 122*4887Schin */ 123*4887Schin char *sh_mactry(register char *string) 124*4887Schin { 125*4887Schin if(string) 126*4887Schin { 127*4887Schin int jmp_val; 128*4887Schin int savexit = sh.savexit; 129*4887Schin struct checkpt buff; 130*4887Schin sh_pushcontext(&buff,SH_JMPSUB); 131*4887Schin jmp_val = sigsetjmp(buff.buff,0); 132*4887Schin if(jmp_val == 0) 133*4887Schin string = sh_mactrim(string,0); 134*4887Schin sh_popcontext(&buff); 135*4887Schin sh.savexit = savexit; 136*4887Schin return(string); 137*4887Schin } 138*4887Schin return(""); 139*4887Schin } 140*4887Schin 141*4887Schin /* 142*4887Schin * Perform parameter expansion, command substitution, and arithmetic 143*4887Schin * expansion on <str>. 144*4887Schin * If <mode> greater than 1 file expansion is performed if the result 145*4887Schin * yields a single pathname. 146*4887Schin * If <mode> negative, than expansion rules for assignment are applied. 147*4887Schin */ 148*4887Schin char *sh_mactrim(char *str, register int mode) 149*4887Schin { 150*4887Schin register Mac_t *mp = (Mac_t*)sh.mac_context; 151*4887Schin Mac_t savemac; 152*4887Schin savemac = *mp; 153*4887Schin stakseek(0); 154*4887Schin mp->arith = (mode==3); 155*4887Schin mp->let = 0; 156*4887Schin sh.argaddr = 0; 157*4887Schin mp->pattern = (mode==1||mode==2); 158*4887Schin mp->patfound = 0; 159*4887Schin mp->assign = (mode<0); 160*4887Schin mp->quoted = mp->lit = mp->split = mp->quote = 0; 161*4887Schin mp->sp = 0; 162*4887Schin if(mp->ifsp=nv_getval(nv_scoped(IFSNOD))) 163*4887Schin mp->ifs = *mp->ifsp; 164*4887Schin else 165*4887Schin mp->ifs = ' '; 166*4887Schin stakseek(0); 167*4887Schin fcsopen(str); 168*4887Schin copyto(mp,0,mp->arith); 169*4887Schin str = stakfreeze(1); 170*4887Schin if(mode==2) 171*4887Schin { 172*4887Schin /* expand only if unique */ 173*4887Schin struct argnod *arglist=0; 174*4887Schin if((mode=path_expand(str,&arglist))==1) 175*4887Schin str = arglist->argval; 176*4887Schin else if(mode>1) 177*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_ambiguous,str); 178*4887Schin sh_trim(str); 179*4887Schin } 180*4887Schin *mp = savemac; 181*4887Schin return(str); 182*4887Schin } 183*4887Schin 184*4887Schin /* 185*4887Schin * Perform all the expansions on the argument <argp> 186*4887Schin */ 187*4887Schin int sh_macexpand(register struct argnod *argp, struct argnod **arghead,int flag) 188*4887Schin { 189*4887Schin register int flags = argp->argflag; 190*4887Schin register char *str = argp->argval; 191*4887Schin register Mac_t *mp = (Mac_t*)sh.mac_context; 192*4887Schin char **saveargaddr = sh.argaddr; 193*4887Schin Mac_t savemac; 194*4887Schin savemac = *mp; 195*4887Schin mp->sp = 0; 196*4887Schin if(mp->ifsp=nv_getval(nv_scoped(IFSNOD))) 197*4887Schin mp->ifs = *mp->ifsp; 198*4887Schin else 199*4887Schin mp->ifs = ' '; 200*4887Schin if(flag&ARG_OPTIMIZE) 201*4887Schin sh.argaddr = (char**)&argp->argchn.ap; 202*4887Schin else 203*4887Schin sh.argaddr = 0; 204*4887Schin mp->arghead = arghead; 205*4887Schin mp->quoted = mp->lit = mp->quote = 0; 206*4887Schin mp->arith = ((flag&ARG_ARITH)!=0); 207*4887Schin mp->let = ((flag&ARG_LET)!=0); 208*4887Schin mp->split = !(flag&ARG_ASSIGN); 209*4887Schin mp->assign = !mp->split; 210*4887Schin mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB); 211*4887Schin str = argp->argval; 212*4887Schin fcsopen(str); 213*4887Schin mp->fields = 0; 214*4887Schin if(!arghead) 215*4887Schin { 216*4887Schin mp->split = 0; 217*4887Schin mp->pattern = ((flag&ARG_EXP)!=0); 218*4887Schin stakseek(0); 219*4887Schin } 220*4887Schin else 221*4887Schin { 222*4887Schin stakseek(ARGVAL); 223*4887Schin *stakptr(ARGVAL-1) = 0; 224*4887Schin } 225*4887Schin mp->patfound = 0; 226*4887Schin copyto(mp,0,mp->arith); 227*4887Schin if(!arghead) 228*4887Schin { 229*4887Schin argp->argchn.cp = stakfreeze(1); 230*4887Schin if(sh.argaddr) 231*4887Schin argp->argflag |= ARG_MAKE; 232*4887Schin } 233*4887Schin else 234*4887Schin { 235*4887Schin endfield(mp,mp->quoted); 236*4887Schin flags = mp->fields; 237*4887Schin if(flags==1 && sh.argaddr) 238*4887Schin argp->argchn.ap = *arghead; 239*4887Schin } 240*4887Schin sh.argaddr = saveargaddr; 241*4887Schin *mp = savemac; 242*4887Schin return(flags); 243*4887Schin } 244*4887Schin 245*4887Schin /* 246*4887Schin * Expand here document which is stored in <infile> or <string> 247*4887Schin * The result is written to <outfile> 248*4887Schin */ 249*4887Schin void sh_machere(Sfio_t *infile, Sfio_t *outfile, char *string) 250*4887Schin { 251*4887Schin register int c,n; 252*4887Schin register const char *state = sh_lexstates[ST_QUOTE]; 253*4887Schin register char *cp; 254*4887Schin register Mac_t *mp = (Mac_t*)sh.mac_context; 255*4887Schin Fcin_t save; 256*4887Schin Mac_t savemac; 257*4887Schin savemac = *mp; 258*4887Schin stakseek(0); 259*4887Schin sh.argaddr = 0; 260*4887Schin mp->sp = outfile; 261*4887Schin mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0; 262*4887Schin mp->quote = 1; 263*4887Schin mp->ifsp = nv_getval(nv_scoped(IFSNOD)); 264*4887Schin mp->ifs = ' '; 265*4887Schin fcsave(&save); 266*4887Schin if(infile) 267*4887Schin fcfopen(infile); 268*4887Schin else 269*4887Schin fcsopen(string); 270*4887Schin fcnotify(0); 271*4887Schin cp = fcseek(0); 272*4887Schin while(1) 273*4887Schin { 274*4887Schin #if SHOPT_MULTIBYTE 275*4887Schin if(mbwide()) 276*4887Schin { 277*4887Schin do 278*4887Schin { 279*4887Schin ssize_t len; 280*4887Schin switch(len = mbsize(cp)) 281*4887Schin { 282*4887Schin case -1: /* illegal multi-byte char */ 283*4887Schin case 0: 284*4887Schin case 1: 285*4887Schin n=state[*(unsigned char*)cp++]; 286*4887Schin break; 287*4887Schin default: 288*4887Schin /* use state of alpah character */ 289*4887Schin n=state['a']; 290*4887Schin cp += len; 291*4887Schin } 292*4887Schin } 293*4887Schin while(n == 0); 294*4887Schin } 295*4887Schin else 296*4887Schin #endif /* SHOPT_MULTIBYTE */ 297*4887Schin while((n=state[*(unsigned char*)cp++])==0); 298*4887Schin if(n==S_NL || n==S_QUOTE || n==S_RBRA) 299*4887Schin continue; 300*4887Schin if(c=(cp-1)-fcseek(0)) 301*4887Schin sfwrite(outfile,fcseek(0),c); 302*4887Schin cp = fcseek(c+1); 303*4887Schin switch(n) 304*4887Schin { 305*4887Schin case S_EOF: 306*4887Schin if((n=fcfill()) <=0) 307*4887Schin { 308*4887Schin /* ignore 0 byte when reading from file */ 309*4887Schin if(n==0 && fcfile()) 310*4887Schin continue; 311*4887Schin fcrestore(&save); 312*4887Schin *mp = savemac; 313*4887Schin return; 314*4887Schin } 315*4887Schin cp = fcseek(-1); 316*4887Schin continue; 317*4887Schin case S_ESC: 318*4887Schin fcgetc(c); 319*4887Schin cp=fcseek(-1); 320*4887Schin if(c>0) 321*4887Schin cp++; 322*4887Schin if(!isescchar(state[c])) 323*4887Schin sfputc(outfile,ESCAPE); 324*4887Schin continue; 325*4887Schin case S_GRAVE: 326*4887Schin comsubst(mp,0); 327*4887Schin break; 328*4887Schin case S_DOL: 329*4887Schin c = fcget(); 330*4887Schin if(c=='.') 331*4887Schin goto regular; 332*4887Schin again: 333*4887Schin switch(n=sh_lexstates[ST_DOL][c]) 334*4887Schin { 335*4887Schin case S_ALP: case S_SPC1: case S_SPC2: 336*4887Schin case S_DIG: case S_LBRA: 337*4887Schin { 338*4887Schin Fcin_t save2; 339*4887Schin int offset = staktell(); 340*4887Schin int offset2; 341*4887Schin stakputc(c); 342*4887Schin if(n==S_LBRA) 343*4887Schin sh_lexskip(RBRACE,1,ST_BRACE); 344*4887Schin else if(n==S_ALP) 345*4887Schin { 346*4887Schin while(fcgetc(c),isaname(c)) 347*4887Schin stakputc(c); 348*4887Schin fcseek(-1); 349*4887Schin } 350*4887Schin stakputc(0); 351*4887Schin offset2 = staktell(); 352*4887Schin fcsave(&save2); 353*4887Schin fcsopen(stakptr(offset)); 354*4887Schin varsub(mp); 355*4887Schin if(c=staktell()-offset2) 356*4887Schin sfwrite(outfile,(char*)stakptr(offset2),c); 357*4887Schin fcrestore(&save2); 358*4887Schin stakseek(offset); 359*4887Schin break; 360*4887Schin } 361*4887Schin case S_PAR: 362*4887Schin comsubst(mp,1); 363*4887Schin break; 364*4887Schin case S_EOF: 365*4887Schin if((c=fcfill()) > 0) 366*4887Schin goto again; 367*4887Schin /* FALL THRU */ 368*4887Schin default: 369*4887Schin regular: 370*4887Schin sfputc(outfile,'$'); 371*4887Schin fcseek(-1); 372*4887Schin break; 373*4887Schin } 374*4887Schin } 375*4887Schin cp = fcseek(0); 376*4887Schin } 377*4887Schin } 378*4887Schin 379*4887Schin /* 380*4887Schin * expand argument but do not trim pattern characters 381*4887Schin */ 382*4887Schin char *sh_macpat(register struct argnod *arg, int flags) 383*4887Schin { 384*4887Schin register char *sp = arg->argval; 385*4887Schin if((arg->argflag&ARG_RAW)) 386*4887Schin return(sp); 387*4887Schin if(flags&ARG_OPTIMIZE) 388*4887Schin arg->argchn.ap=0; 389*4887Schin if(!(sp=arg->argchn.cp)) 390*4887Schin { 391*4887Schin sh_macexpand(arg,NIL(struct argnod**),flags); 392*4887Schin sp = arg->argchn.cp; 393*4887Schin if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE)) 394*4887Schin arg->argchn.cp = 0; 395*4887Schin arg->argflag &= ~ARG_MAKE; 396*4887Schin } 397*4887Schin else 398*4887Schin sh.optcount++; 399*4887Schin return(sp); 400*4887Schin } 401*4887Schin 402*4887Schin /* 403*4887Schin * Process the characters up to <endch> or end of input string 404*4887Schin */ 405*4887Schin static void copyto(register Mac_t *mp,int endch, int newquote) 406*4887Schin { 407*4887Schin register int c,n; 408*4887Schin register const char *state = sh_lexstates[ST_MACRO]; 409*4887Schin register char *cp,*first; 410*4887Schin int tilde = -1; 411*4887Schin int oldquote = mp->quote; 412*4887Schin int ansi_c = 0; 413*4887Schin int paren = 0; 414*4887Schin int ere = 0; 415*4887Schin int brace = 0; 416*4887Schin Sfio_t *sp = mp->sp; 417*4887Schin mp->sp = NIL(Sfio_t*); 418*4887Schin mp->quote = newquote; 419*4887Schin first = cp = fcseek(0); 420*4887Schin if(!mp->quote && *cp=='~') 421*4887Schin tilde = staktell(); 422*4887Schin /* handle // operator specially */ 423*4887Schin if(mp->pattern==2 && *cp=='/') 424*4887Schin cp++; 425*4887Schin while(1) 426*4887Schin { 427*4887Schin #if SHOPT_MULTIBYTE 428*4887Schin if(mbwide()) 429*4887Schin { 430*4887Schin ssize_t len; 431*4887Schin do 432*4887Schin { 433*4887Schin switch(len = mbsize(cp)) 434*4887Schin { 435*4887Schin case -1: /* illegal multi-byte char */ 436*4887Schin case 0: 437*4887Schin len = 1; 438*4887Schin case 1: 439*4887Schin n = state[*(unsigned char*)cp++]; 440*4887Schin break; 441*4887Schin default: 442*4887Schin /* treat as if alpha */ 443*4887Schin cp += len; 444*4887Schin n=state['a']; 445*4887Schin } 446*4887Schin } 447*4887Schin while(n == 0); 448*4887Schin c = (cp-len) - first; 449*4887Schin } 450*4887Schin else 451*4887Schin #endif /* SHOPT_MULTIBYTE */ 452*4887Schin { 453*4887Schin while((n=state[*(unsigned char*)cp++])==0); 454*4887Schin c = (cp-1) - first; 455*4887Schin } 456*4887Schin switch(n) 457*4887Schin { 458*4887Schin case S_ESC: 459*4887Schin if(ansi_c) 460*4887Schin { 461*4887Schin /* process ANSI-C escape character */ 462*4887Schin char *addr= --cp; 463*4887Schin if(c) 464*4887Schin stakwrite(first,c); 465*4887Schin c = chresc(cp,&addr); 466*4887Schin cp = addr; 467*4887Schin first = fcseek(cp-first); 468*4887Schin #if SHOPT_MULTIBYTE 469*4887Schin if(c > UCHAR_MAX && mbwide()) 470*4887Schin { 471*4887Schin int i; 472*4887Schin unsigned char mb[8]; 473*4887Schin 474*4887Schin n = wctomb((char*)mb, c); 475*4887Schin for(i=0;i<n;i++) 476*4887Schin stakputc(mb[i]); 477*4887Schin } 478*4887Schin else 479*4887Schin #endif /* SHOPT_MULTIBYTE */ 480*4887Schin stakputc(c); 481*4887Schin if(c==ESCAPE && mp->pattern) 482*4887Schin stakputc(ESCAPE); 483*4887Schin break; 484*4887Schin } 485*4887Schin else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.')) 486*4887Schin break; 487*4887Schin else if(mp->split && endch && !mp->quote && !mp->lit) 488*4887Schin { 489*4887Schin if(c) 490*4887Schin mac_copy(mp,first,c); 491*4887Schin cp = fcseek(c+2); 492*4887Schin if(c= cp[-1]) 493*4887Schin { 494*4887Schin stakputc(c); 495*4887Schin if(c==ESCAPE) 496*4887Schin stakputc(ESCAPE); 497*4887Schin } 498*4887Schin else 499*4887Schin cp--; 500*4887Schin first = cp; 501*4887Schin break; 502*4887Schin } 503*4887Schin n = state[*(unsigned char*)cp]; 504*4887Schin if(n==S_ENDCH && *cp!=endch) 505*4887Schin n = S_PAT; 506*4887Schin if(mp->pattern) 507*4887Schin { 508*4887Schin /* preserve \digit for pattern matching */ 509*4887Schin /* also \alpha for extended patterns */ 510*4887Schin if(!mp->lit && !mp->quote && (n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP))) 511*4887Schin break; 512*4887Schin /* followed by file expansion */ 513*4887Schin if(!mp->lit && (n==S_ESC || (!mp->quote && 514*4887Schin (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-')))) 515*4887Schin { 516*4887Schin cp += (n!=S_EOF); 517*4887Schin break; 518*4887Schin } 519*4887Schin if(mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH)) 520*4887Schin { 521*4887Schin /* add \ for file expansion */ 522*4887Schin stakwrite(first,c+1); 523*4887Schin first = fcseek(c); 524*4887Schin break; 525*4887Schin } 526*4887Schin } 527*4887Schin if(mp->lit) 528*4887Schin break; 529*4887Schin if(!mp->quote || isqescchar(n) || n==S_ENDCH) 530*4887Schin { 531*4887Schin /* eliminate \ */ 532*4887Schin if(c) 533*4887Schin stakwrite(first,c); 534*4887Schin /* check new-line joining */ 535*4887Schin first = fcseek(c+1); 536*4887Schin } 537*4887Schin cp += (n!=S_EOF); 538*4887Schin break; 539*4887Schin case S_GRAVE: case S_DOL: 540*4887Schin if(mp->lit) 541*4887Schin break; 542*4887Schin if(c) 543*4887Schin { 544*4887Schin if(mp->split && !mp->quote && endch) 545*4887Schin mac_copy(mp,first,c); 546*4887Schin else 547*4887Schin stakwrite(first,c); 548*4887Schin } 549*4887Schin first = fcseek(c+1); 550*4887Schin c = mp->pattern; 551*4887Schin if(n==S_GRAVE) 552*4887Schin comsubst(mp,0); 553*4887Schin else if((n= *cp)==0 || !varsub(mp)) 554*4887Schin { 555*4887Schin if(n=='\'' && !mp->quote) 556*4887Schin ansi_c = 1; 557*4887Schin else if(mp->quote || n!='"') 558*4887Schin stakputc('$'); 559*4887Schin } 560*4887Schin cp = first = fcseek(0); 561*4887Schin if(*cp) 562*4887Schin mp->pattern = c; 563*4887Schin break; 564*4887Schin case S_ENDCH: 565*4887Schin if((mp->lit || cp[-1]!=endch || mp->quote!=newquote)) 566*4887Schin goto pattern; 567*4887Schin if(endch==RBRACE && *cp==LPAREN && mp->pattern && brace) 568*4887Schin goto pattern; 569*4887Schin case S_EOF: 570*4887Schin if(c) 571*4887Schin { 572*4887Schin if(mp->split && !mp->quote && !mp->lit && endch) 573*4887Schin mac_copy(mp,first,c); 574*4887Schin else 575*4887Schin stakwrite(first,c); 576*4887Schin } 577*4887Schin c += (n!=S_EOF); 578*4887Schin first = fcseek(c); 579*4887Schin if(tilde>=0) 580*4887Schin tilde_expand2(tilde); 581*4887Schin goto done; 582*4887Schin case S_QUOTE: 583*4887Schin if(mp->lit || mp->arith) 584*4887Schin break; 585*4887Schin case S_LIT: 586*4887Schin if(mp->arith) 587*4887Schin { 588*4887Schin if((*cp=='`' || *cp=='[') && cp[1]=='\'') 589*4887Schin cp +=2; 590*4887Schin break; 591*4887Schin } 592*4887Schin if(n==S_LIT && mp->quote) 593*4887Schin break; 594*4887Schin if(c) 595*4887Schin { 596*4887Schin if(mp->split && endch && !mp->quote && !mp->lit) 597*4887Schin mac_copy(mp,first,c); 598*4887Schin else 599*4887Schin stakwrite(first,c); 600*4887Schin } 601*4887Schin first = fcseek(c+1); 602*4887Schin if(n==S_LIT) 603*4887Schin { 604*4887Schin if(mp->quote) 605*4887Schin continue; 606*4887Schin if(mp->lit) 607*4887Schin mp->lit = ansi_c = 0; 608*4887Schin else 609*4887Schin mp->lit = 1; 610*4887Schin } 611*4887Schin else 612*4887Schin mp->quote = !mp->quote; 613*4887Schin mp->quoted++; 614*4887Schin break; 615*4887Schin case S_BRACT: 616*4887Schin if(mp->arith || ((mp->assign==1 || endch==RBRACT) && 617*4887Schin !(mp->quote || mp->lit))) 618*4887Schin { 619*4887Schin int offset=0,oldpat = mp->pattern; 620*4887Schin int oldarith = mp->arith; 621*4887Schin stakwrite(first,++c); 622*4887Schin if(mp->assign==1 && first[c-2]=='.') 623*4887Schin offset = staktell(); 624*4887Schin first = fcseek(c); 625*4887Schin mp->pattern = 4; 626*4887Schin mp->arith = 0; 627*4887Schin copyto(mp,RBRACT,0); 628*4887Schin mp->arith = oldarith; 629*4887Schin mp->pattern = oldpat; 630*4887Schin stakputc(RBRACT); 631*4887Schin if(offset) 632*4887Schin { 633*4887Schin cp = stakptr(staktell()); 634*4887Schin if(sh_checkid(stakptr(offset),cp)!=cp) 635*4887Schin stakseek(staktell()-2); 636*4887Schin } 637*4887Schin cp = first = fcseek(0); 638*4887Schin break; 639*4887Schin } 640*4887Schin case S_PAT: 641*4887Schin if(mp->pattern && !(mp->quote || mp->lit)) 642*4887Schin { 643*4887Schin mp->patfound = mp->pattern; 644*4887Schin if((n=cp[-1])==LPAREN) 645*4887Schin { 646*4887Schin paren++; 647*4887Schin if((cp-first)>1 && cp[-2]=='~') 648*4887Schin { 649*4887Schin char *p = cp; 650*4887Schin while((c=mbchar(p)) && c!=RPAREN && c!='E'); 651*4887Schin ere = c=='E'; 652*4887Schin } 653*4887Schin } 654*4887Schin else if(n==RPAREN) 655*4887Schin --paren; 656*4887Schin } 657*4887Schin goto pattern; 658*4887Schin case S_BRACE: 659*4887Schin if(!(mp->quote || mp->lit)) 660*4887Schin { 661*4887Schin mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND); 662*4887Schin brace = 1; 663*4887Schin } 664*4887Schin pattern: 665*4887Schin if(!mp->pattern || !(mp->quote || mp->lit)) 666*4887Schin { 667*4887Schin /* mark beginning of {a,b} */ 668*4887Schin if(n==S_BRACE && endch==0 && mp->pattern) 669*4887Schin mp->pattern=4; 670*4887Schin if(n==S_SLASH && mp->pattern==2) 671*4887Schin mp->pattern=3; 672*4887Schin break; 673*4887Schin } 674*4887Schin if(mp->pattern==3) 675*4887Schin break; 676*4887Schin if(c) 677*4887Schin stakwrite(first,c); 678*4887Schin first = fcseek(c); 679*4887Schin stakputc(ESCAPE); 680*4887Schin break; 681*4887Schin case S_EQ: 682*4887Schin if(mp->assign==1) 683*4887Schin { 684*4887Schin if(*cp=='~' && !endch && !mp->quote && !mp->lit) 685*4887Schin tilde = staktell()+(c+1); 686*4887Schin mp->assign = 2; 687*4887Schin } 688*4887Schin break; 689*4887Schin case S_SLASH: 690*4887Schin case S_COLON: 691*4887Schin if(tilde >=0) 692*4887Schin { 693*4887Schin if(c) 694*4887Schin stakwrite(first,c); 695*4887Schin first = fcseek(c); 696*4887Schin tilde_expand2(tilde); 697*4887Schin tilde = -1; 698*4887Schin c=0; 699*4887Schin } 700*4887Schin if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit) 701*4887Schin tilde = staktell()+(c+1); 702*4887Schin else if(n==S_SLASH && mp->pattern==2) 703*4887Schin #if 0 704*4887Schin goto pattern; 705*4887Schin #else 706*4887Schin { 707*4887Schin if(mp->quote || mp->lit) 708*4887Schin goto pattern; 709*4887Schin stakwrite(first,c+1); 710*4887Schin first = fcseek(c+1); 711*4887Schin c = staktell(); 712*4887Schin sh_lexskip(RBRACE,0,ST_NESTED); 713*4887Schin stakseek(c); 714*4887Schin cp = fcseek(-1); 715*4887Schin stakwrite(first,cp-first); 716*4887Schin first=cp; 717*4887Schin } 718*4887Schin #endif 719*4887Schin break; 720*4887Schin } 721*4887Schin } 722*4887Schin done: 723*4887Schin mp->sp = sp; 724*4887Schin mp->quote = oldquote; 725*4887Schin } 726*4887Schin 727*4887Schin /* 728*4887Schin * copy <str> to stack performing sub-expression substitutions 729*4887Schin */ 730*4887Schin static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize) 731*4887Schin { 732*4887Schin register int c,n; 733*4887Schin #if 0 734*4887Schin register char *first=cp; 735*4887Schin #else 736*4887Schin register char *first=fcseek(0); 737*4887Schin char *ptr; 738*4887Schin Mac_t savemac; 739*4887Schin n = staktell(); 740*4887Schin savemac = *mp; 741*4887Schin mp->pattern = 3; 742*4887Schin mp->split = 0; 743*4887Schin fcsopen(cp); 744*4887Schin copyto(mp,0,0); 745*4887Schin stakputc(0); 746*4887Schin ptr = cp = strdup(stakptr(n)); 747*4887Schin stakseek(n); 748*4887Schin *mp = savemac; 749*4887Schin fcsopen(first); 750*4887Schin first = cp; 751*4887Schin #endif 752*4887Schin while(1) 753*4887Schin { 754*4887Schin while((c= *cp++) && c!=ESCAPE); 755*4887Schin if(c==0) 756*4887Schin break; 757*4887Schin if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize)) 758*4887Schin { 759*4887Schin c = cp-first-2; 760*4887Schin if(c) 761*4887Schin mac_copy(mp,first,c); 762*4887Schin first=cp; 763*4887Schin if(n=='\\' || n==RBRACE) 764*4887Schin { 765*4887Schin first--; 766*4887Schin continue; 767*4887Schin } 768*4887Schin if((c=subexp[2*n])>=0) 769*4887Schin { 770*4887Schin if((n=subexp[2*n+1]-c)>0) 771*4887Schin mac_copy(mp,str+c,n); 772*4887Schin } 773*4887Schin } 774*4887Schin else if(n==0) 775*4887Schin break; 776*4887Schin } 777*4887Schin if(n=cp-first-1) 778*4887Schin mac_copy(mp,first,n); 779*4887Schin #if 1 780*4887Schin free(ptr); 781*4887Schin #endif 782*4887Schin } 783*4887Schin 784*4887Schin #if SHOPT_FILESCAN 785*4887Schin #define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0])) 786*4887Schin #define MAX_ARGN (32*1024) 787*4887Schin 788*4887Schin /* 789*4887Schin * compute the arguments $1 ... $n and $# from the current line as needed 790*4887Schin * save line offsets in the offsets array. 791*4887Schin */ 792*4887Schin static char *getdolarg(Shell_t *shp, int n, int *size) 793*4887Schin { 794*4887Schin register int c=S_DELIM, d=shp->ifstable['\\']; 795*4887Schin register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line; 796*4887Schin register int m=shp->offsets[0],delim=0; 797*4887Schin if(m==0) 798*4887Schin return(0); 799*4887Schin if(m<0) 800*4887Schin m = 0; 801*4887Schin else if(n<=m) 802*4887Schin m = n-1; 803*4887Schin else 804*4887Schin m--; 805*4887Schin if(m >= MAX_OFFSETS-1) 806*4887Schin m = MAX_OFFSETS-2; 807*4887Schin cp += shp->offsets[m+1]; 808*4887Schin n -= m; 809*4887Schin shp->ifstable['\\'] = 0; 810*4887Schin shp->ifstable[0] = S_EOF; 811*4887Schin while(1) 812*4887Schin { 813*4887Schin if(c==S_DELIM) 814*4887Schin while(shp->ifstable[*cp++]==S_SPACE); 815*4887Schin first = --cp; 816*4887Schin if(++m < MAX_OFFSETS) 817*4887Schin shp->offsets[m] = (first-(unsigned char*)shp->cur_line); 818*4887Schin while((c=shp->ifstable[*cp++])==0); 819*4887Schin last = cp-1; 820*4887Schin if(c==S_SPACE) 821*4887Schin while((c=shp->ifstable[*cp++])==S_SPACE); 822*4887Schin if(--n==0 || c==S_EOF) 823*4887Schin { 824*4887Schin if(last==first && c==S_EOF && (!delim || (m>1))) 825*4887Schin { 826*4887Schin n++; 827*4887Schin m--; 828*4887Schin } 829*4887Schin break; 830*4887Schin } 831*4887Schin delim = (c==S_DELIM); 832*4887Schin } 833*4887Schin shp->ifstable['\\'] = d; 834*4887Schin if(m > shp->offsets[0]) 835*4887Schin shp->offsets[0] = m; 836*4887Schin if(n) 837*4887Schin first = last = 0; 838*4887Schin if(size) 839*4887Schin *size = last-first; 840*4887Schin return((char*)first); 841*4887Schin } 842*4887Schin #endif /* SHOPT_FILESCAN */ 843*4887Schin 844*4887Schin /* 845*4887Schin * get the prefix after name reference resolution 846*4887Schin */ 847*4887Schin static char *prefix(char *id) 848*4887Schin { 849*4887Schin Namval_t *np; 850*4887Schin register char *cp = strchr(id,'.'); 851*4887Schin if(cp) 852*4887Schin { 853*4887Schin *cp = 0; 854*4887Schin np = nv_search(id, sh.var_tree,0); 855*4887Schin *cp = '.'; 856*4887Schin if(isastchar(cp[1])) 857*4887Schin cp[1] = 0; 858*4887Schin if(np && nv_isref(np)) 859*4887Schin { 860*4887Schin int n; 861*4887Schin char *sp; 862*4887Schin sh.argaddr = 0; 863*4887Schin while(nv_isref(np)) 864*4887Schin np = nv_refnode(np); 865*4887Schin id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+1); 866*4887Schin strcpy(&id[n],cp); 867*4887Schin memcpy(id,sp,n); 868*4887Schin return(id); 869*4887Schin } 870*4887Schin } 871*4887Schin return(strdup(id)); 872*4887Schin } 873*4887Schin 874*4887Schin /* 875*4887Schin * copy to ']' onto the stack and return offset to it 876*4887Schin */ 877*4887Schin static int subcopy(Mac_t *mp, int flag) 878*4887Schin { 879*4887Schin int split = mp->split; 880*4887Schin int xpattern = mp->pattern; 881*4887Schin int loc = staktell(); 882*4887Schin int xarith = mp->arith; 883*4887Schin mp->split = 0; 884*4887Schin mp->arith = 0; 885*4887Schin mp->pattern = flag?4:0; 886*4887Schin copyto(mp,RBRACT,0); 887*4887Schin mp->pattern = xpattern; 888*4887Schin mp->split = split; 889*4887Schin mp->arith = xarith; 890*4887Schin return(loc); 891*4887Schin } 892*4887Schin 893*4887Schin static int namecount(Mac_t *mp,const char *prefix) 894*4887Schin { 895*4887Schin int count = 0; 896*4887Schin mp->nvwalk = nv_diropen(prefix); 897*4887Schin while(nv_dirnext(mp->nvwalk)) 898*4887Schin count++; 899*4887Schin nv_dirclose(mp->nvwalk); 900*4887Schin return(count); 901*4887Schin } 902*4887Schin 903*4887Schin static char *nextname(Mac_t *mp,const char *prefix, int len) 904*4887Schin { 905*4887Schin char *cp; 906*4887Schin if(len==0) 907*4887Schin { 908*4887Schin mp->nvwalk = nv_diropen(prefix); 909*4887Schin return((char*)mp->nvwalk); 910*4887Schin } 911*4887Schin if(!(cp=nv_dirnext(mp->nvwalk))) 912*4887Schin nv_dirclose(mp->nvwalk); 913*4887Schin return(cp); 914*4887Schin } 915*4887Schin 916*4887Schin /* 917*4887Schin * This routine handles $param, ${parm}, and ${param op word} 918*4887Schin * The input stream is assumed to be a string 919*4887Schin */ 920*4887Schin static int varsub(Mac_t *mp) 921*4887Schin { 922*4887Schin register int c; 923*4887Schin register int type=0; /* M_xxx */ 924*4887Schin register char *v,*argp=0; 925*4887Schin register Namval_t *np = NIL(Namval_t*); 926*4887Schin register int dolg=0, mode=0; 927*4887Schin Namarr_t *ap=0; 928*4887Schin int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0; 929*4887Schin char idbuff[3], *id = idbuff, *pattern=0, *repstr; 930*4887Schin int oldpat=mp->pattern,idnum=0,flag=0,d; 931*4887Schin retry1: 932*4887Schin mp->zeros = 0; 933*4887Schin idbuff[0] = 0; 934*4887Schin idbuff[1] = 0; 935*4887Schin c = fcget(); 936*4887Schin switch(c>0x7f?S_ALP:sh_lexstates[ST_DOL][c]) 937*4887Schin { 938*4887Schin case S_RBRA: 939*4887Schin if(type<M_SIZE) 940*4887Schin goto nosub; 941*4887Schin /* This code handles ${#} */ 942*4887Schin c = mode; 943*4887Schin mode = type = 0; 944*4887Schin /* FALL THRU */ 945*4887Schin case S_SPC1: 946*4887Schin if(type==M_BRACE) 947*4887Schin { 948*4887Schin if(isaletter(mode=fcpeek(0)) || mode=='.') 949*4887Schin { 950*4887Schin if(c=='#') 951*4887Schin type = M_SIZE; 952*4887Schin #ifdef SHOPT_TYPEDEF 953*4887Schin else if(c=='@') 954*4887Schin { 955*4887Schin type = M_TYPE; 956*4887Schin goto retry1; 957*4887Schin } 958*4887Schin #endif /* SHOPT_TYPEDEF */ 959*4887Schin else 960*4887Schin type = M_VNAME; 961*4887Schin mode = c; 962*4887Schin goto retry1; 963*4887Schin } 964*4887Schin else if(c=='#' && (isadigit(mode)||fcpeek(1)==RBRACE)) 965*4887Schin { 966*4887Schin type = M_SIZE; 967*4887Schin mode = c; 968*4887Schin goto retry1; 969*4887Schin } 970*4887Schin } 971*4887Schin /* FALL THRU */ 972*4887Schin case S_SPC2: 973*4887Schin *id = c; 974*4887Schin v = special(c); 975*4887Schin if(isastchar(c)) 976*4887Schin { 977*4887Schin mode = c; 978*4887Schin #if SHOPT_FILESCAN 979*4887Schin if(sh.cur_line) 980*4887Schin { 981*4887Schin v = getdolarg(&sh,1,(int*)0); 982*4887Schin dolmax = MAX_ARGN; 983*4887Schin } 984*4887Schin else 985*4887Schin #endif /* SHOPT_FILESCAN */ 986*4887Schin dolmax = sh.st.dolc+1; 987*4887Schin dolg = (v!=0); 988*4887Schin } 989*4887Schin break; 990*4887Schin case S_LBRA: 991*4887Schin if(type) 992*4887Schin goto nosub; 993*4887Schin type = M_BRACE; 994*4887Schin goto retry1; 995*4887Schin case S_PAR: 996*4887Schin if(type) 997*4887Schin goto nosub; 998*4887Schin comsubst(mp,1); 999*4887Schin return(1); 1000*4887Schin case S_DIG: 1001*4887Schin c -= '0'; 1002*4887Schin sh.argaddr = 0; 1003*4887Schin if(type) 1004*4887Schin { 1005*4887Schin register int d; 1006*4887Schin while((d=fcget()),isadigit(d)) 1007*4887Schin c = 10*c + (d-'0'); 1008*4887Schin fcseek(-1); 1009*4887Schin } 1010*4887Schin idnum = c; 1011*4887Schin if(c==0) 1012*4887Schin v = special(c); 1013*4887Schin #if SHOPT_FILESCAN 1014*4887Schin else if(sh.cur_line) 1015*4887Schin { 1016*4887Schin sh.used_pos = 1; 1017*4887Schin v = getdolarg(&sh,c,&vsize); 1018*4887Schin } 1019*4887Schin #endif /* SHOPT_FILESCAN */ 1020*4887Schin else if(c <= sh.st.dolc) 1021*4887Schin { 1022*4887Schin sh.used_pos = 1; 1023*4887Schin v = sh.st.dolv[c]; 1024*4887Schin } 1025*4887Schin else 1026*4887Schin v = 0; 1027*4887Schin break; 1028*4887Schin case S_ALP: 1029*4887Schin if(c=='.' && type==0) 1030*4887Schin goto nosub; 1031*4887Schin offset = staktell(); 1032*4887Schin do 1033*4887Schin { 1034*4887Schin np = 0; 1035*4887Schin do 1036*4887Schin stakputc(c); 1037*4887Schin while(((c=fcget()),(c>0x7f||isaname(c)))||type && c=='.'); 1038*4887Schin while(c==LBRACT && type) 1039*4887Schin { 1040*4887Schin sh.argaddr=0; 1041*4887Schin if((c=fcget(),isastchar(c)) && fcpeek(0)==RBRACT) 1042*4887Schin { 1043*4887Schin if(type==M_VNAME) 1044*4887Schin type = M_SUBNAME; 1045*4887Schin idbuff[0] = mode = c; 1046*4887Schin fcget(); 1047*4887Schin c = fcget(); 1048*4887Schin if(c=='.' || c==LBRACT) 1049*4887Schin { 1050*4887Schin stakputc(LBRACT); 1051*4887Schin stakputc(mode); 1052*4887Schin stakputc(RBRACT); 1053*4887Schin } 1054*4887Schin else 1055*4887Schin flag = NV_ARRAY; 1056*4887Schin break; 1057*4887Schin } 1058*4887Schin else 1059*4887Schin { 1060*4887Schin fcseek(-1); 1061*4887Schin if(type==M_VNAME) 1062*4887Schin type = M_SUBNAME; 1063*4887Schin stakputc(LBRACT); 1064*4887Schin v = stakptr(subcopy(mp,1)); 1065*4887Schin stakputc(RBRACT); 1066*4887Schin c = fcget(); 1067*4887Schin } 1068*4887Schin } 1069*4887Schin } 1070*4887Schin while(type && c=='.'); 1071*4887Schin if(c==RBRACE && type && fcpeek(-2)=='.') 1072*4887Schin { 1073*4887Schin stakseek(staktell()-1); 1074*4887Schin type = M_TREE; 1075*4887Schin } 1076*4887Schin stakputc(0); 1077*4887Schin id=stakptr(offset); 1078*4887Schin if(isastchar(c) && type) 1079*4887Schin { 1080*4887Schin if(type==M_VNAME || type==M_SIZE) 1081*4887Schin { 1082*4887Schin idbuff[0] = mode = c; 1083*4887Schin if((d=fcpeek(0))==c) 1084*4887Schin idbuff[1] = fcget(); 1085*4887Schin if(type==M_VNAME) 1086*4887Schin type = M_NAMESCAN; 1087*4887Schin else 1088*4887Schin type = M_NAMECOUNT; 1089*4887Schin break; 1090*4887Schin } 1091*4887Schin goto nosub; 1092*4887Schin } 1093*4887Schin flag |= NV_NOASSIGN|NV_VARNAME|NV_NOADD; 1094*4887Schin if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?'))) 1095*4887Schin flag &= ~NV_NOADD; 1096*4887Schin #if SHOPT_FILESCAN 1097*4887Schin if(sh.cur_line && *id=='R' && strcmp(id,"REPLY")==0) 1098*4887Schin { 1099*4887Schin sh.argaddr=0; 1100*4887Schin np = REPLYNOD; 1101*4887Schin } 1102*4887Schin else 1103*4887Schin #endif /* SHOPT_FILESCAN */ 1104*4887Schin if(sh.argaddr) 1105*4887Schin flag &= ~NV_NOADD; 1106*4887Schin np = nv_open(id,sh.var_tree,flag|NV_NOFAIL); 1107*4887Schin ap = np?nv_arrayptr(np):0; 1108*4887Schin if(type) 1109*4887Schin { 1110*4887Schin if(ap && isastchar(mode) && !(ap->nelem&ARRAY_SCAN)) 1111*4887Schin nv_putsub(np,NIL(char*),ARRAY_SCAN); 1112*4887Schin if(!isbracechar(c)) 1113*4887Schin goto nosub; 1114*4887Schin else 1115*4887Schin fcseek(-1); 1116*4887Schin } 1117*4887Schin else 1118*4887Schin fcseek(-1); 1119*4887Schin if((type==M_VNAME||type==M_SUBNAME) && sh.argaddr && strcmp(nv_name(np),id)) 1120*4887Schin sh.argaddr = 0; 1121*4887Schin c = (type>M_BRACE && isastchar(mode)); 1122*4887Schin if(np && (!c || !ap)) 1123*4887Schin { 1124*4887Schin if(type==M_VNAME) 1125*4887Schin { 1126*4887Schin type = M_BRACE; 1127*4887Schin v = nv_name(np); 1128*4887Schin } 1129*4887Schin #ifdef SHOPT_TYPEDEF 1130*4887Schin else if(type==M_TYPE) 1131*4887Schin { 1132*4887Schin #if 0 1133*4887Schin Namval_t *nq = nv_type(np); 1134*4887Schin #else 1135*4887Schin Namval_t *nq = 0; 1136*4887Schin #endif 1137*4887Schin type = M_BRACE; 1138*4887Schin if(nq) 1139*4887Schin v = nv_name(nq); 1140*4887Schin else 1141*4887Schin { 1142*4887Schin nv_attribute(np,sh.strbuf,"typeset",1); 1143*4887Schin v = sfstruse(sh.strbuf); 1144*4887Schin } 1145*4887Schin } 1146*4887Schin #endif /* SHOPT_TYPEDEF */ 1147*4887Schin #if SHOPT_FILESCAN 1148*4887Schin else if(sh.cur_line && np==REPLYNOD) 1149*4887Schin v = sh.cur_line; 1150*4887Schin #endif /* SHOPT_FILESCAN */ 1151*4887Schin else if(type==M_TREE) 1152*4887Schin v = nv_getvtree(np,(Namfun_t*)0); 1153*4887Schin else 1154*4887Schin { 1155*4887Schin v = nv_getval(np); 1156*4887Schin /* special case --- ignore leading zeros */ 1157*4887Schin if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(*((unsigned char*)stakptr(offset-1))))) 1158*4887Schin mp->zeros = 1; 1159*4887Schin } 1160*4887Schin } 1161*4887Schin else 1162*4887Schin v = 0; 1163*4887Schin stakseek(offset); 1164*4887Schin if(ap) 1165*4887Schin { 1166*4887Schin #if SHOPT_OPTIMIZE 1167*4887Schin if(sh.argaddr) 1168*4887Schin nv_optimize(np); 1169*4887Schin #endif 1170*4887Schin if(isastchar(mode) && array_elem(ap)> !c) 1171*4887Schin dolg = -1; 1172*4887Schin else 1173*4887Schin dolg = 0; 1174*4887Schin } 1175*4887Schin break; 1176*4887Schin case S_EOF: 1177*4887Schin fcseek(-1); 1178*4887Schin default: 1179*4887Schin goto nosub; 1180*4887Schin } 1181*4887Schin c = fcget(); 1182*4887Schin if(type>M_TREE) 1183*4887Schin { 1184*4887Schin if(c!=RBRACE) 1185*4887Schin mac_error(np); 1186*4887Schin if(type==M_NAMESCAN || type==M_NAMECOUNT) 1187*4887Schin { 1188*4887Schin id = prefix(id); 1189*4887Schin stakseek(offset); 1190*4887Schin if(type==M_NAMECOUNT) 1191*4887Schin { 1192*4887Schin c = namecount(mp,id); 1193*4887Schin v = ltos(c); 1194*4887Schin } 1195*4887Schin else 1196*4887Schin { 1197*4887Schin dolmax = strlen(id); 1198*4887Schin dolg = -1; 1199*4887Schin nextname(mp,id,0); 1200*4887Schin v = nextname(mp,id,dolmax); 1201*4887Schin } 1202*4887Schin } 1203*4887Schin else if(type==M_SUBNAME) 1204*4887Schin { 1205*4887Schin if(dolg<0) 1206*4887Schin { 1207*4887Schin v = nv_getsub(np); 1208*4887Schin bysub=1; 1209*4887Schin } 1210*4887Schin else if(v) 1211*4887Schin { 1212*4887Schin if(!ap || isastchar(mode)) 1213*4887Schin v = "0"; 1214*4887Schin else 1215*4887Schin v = nv_getsub(np); 1216*4887Schin } 1217*4887Schin } 1218*4887Schin else 1219*4887Schin { 1220*4887Schin if(!isastchar(mode)) 1221*4887Schin c = charlen(v,vsize); 1222*4887Schin else if(dolg>0) 1223*4887Schin { 1224*4887Schin #if SHOPT_FILESCAN 1225*4887Schin if(sh.cur_line) 1226*4887Schin { 1227*4887Schin getdolarg(&sh,MAX_ARGN,(int*)0); 1228*4887Schin c = sh.offsets[0]; 1229*4887Schin } 1230*4887Schin else 1231*4887Schin #endif /* SHOPT_FILESCAN */ 1232*4887Schin c = sh.st.dolc; 1233*4887Schin } 1234*4887Schin else if(dolg<0) 1235*4887Schin c = array_elem(ap); 1236*4887Schin else 1237*4887Schin c = (v!=0); 1238*4887Schin dolg = dolmax = 0; 1239*4887Schin v = ltos(c); 1240*4887Schin } 1241*4887Schin c = RBRACE; 1242*4887Schin } 1243*4887Schin nulflg = 0; 1244*4887Schin if(type && c==':') 1245*4887Schin { 1246*4887Schin c = fcget(); 1247*4887Schin if(sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':') 1248*4887Schin nulflg=1; 1249*4887Schin else if(c!='%' && c!='#') 1250*4887Schin { 1251*4887Schin fcseek(-1); 1252*4887Schin c = ':'; 1253*4887Schin } 1254*4887Schin } 1255*4887Schin if(type) 1256*4887Schin { 1257*4887Schin if(!isbracechar(c)) 1258*4887Schin { 1259*4887Schin if(!nulflg) 1260*4887Schin mac_error(np); 1261*4887Schin fcseek(-1); 1262*4887Schin c = ':'; 1263*4887Schin } 1264*4887Schin if(c!=RBRACE) 1265*4887Schin { 1266*4887Schin int newops = (c=='#' || c == '%' || c=='/'); 1267*4887Schin offset = staktell(); 1268*4887Schin if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%'))) 1269*4887Schin { 1270*4887Schin int newquote = mp->quote; 1271*4887Schin int split = mp->split; 1272*4887Schin int quoted = mp->quoted; 1273*4887Schin int arith = mp->arith; 1274*4887Schin int zeros = mp->zeros; 1275*4887Schin if(newops) 1276*4887Schin { 1277*4887Schin type = fcget(); 1278*4887Schin if(type=='%' || type=='#') 1279*4887Schin { 1280*4887Schin int d = fcget(); 1281*4887Schin fcseek(-1); 1282*4887Schin if(d=='(') 1283*4887Schin type = 0; 1284*4887Schin } 1285*4887Schin fcseek(-1); 1286*4887Schin mp->pattern = 1+(c=='/'); 1287*4887Schin mp->split = 0; 1288*4887Schin mp->quoted = 0; 1289*4887Schin mp->arith = mp->zeros = 0; 1290*4887Schin newquote = 0; 1291*4887Schin } 1292*4887Schin else if(c=='?' || c=='=') 1293*4887Schin mp->split = mp->pattern = 0; 1294*4887Schin copyto(mp,RBRACE,newquote); 1295*4887Schin if(!oldpat) 1296*4887Schin mp->patfound = 0; 1297*4887Schin mp->pattern = oldpat; 1298*4887Schin mp->split = split; 1299*4887Schin mp->quoted = quoted; 1300*4887Schin mp->arith = arith; 1301*4887Schin mp->zeros = zeros; 1302*4887Schin /* add null byte */ 1303*4887Schin stakputc(0); 1304*4887Schin stakseek(staktell()-1); 1305*4887Schin } 1306*4887Schin else 1307*4887Schin { 1308*4887Schin sh_lexskip(RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED); 1309*4887Schin stakseek(offset); 1310*4887Schin } 1311*4887Schin argp=stakptr(offset); 1312*4887Schin } 1313*4887Schin } 1314*4887Schin else 1315*4887Schin { 1316*4887Schin fcseek(-1); 1317*4887Schin c=0; 1318*4887Schin } 1319*4887Schin if(c==':') /* ${name:expr1[:expr2]} */ 1320*4887Schin { 1321*4887Schin char *ptr; 1322*4887Schin type = (int)sh_strnum(argp,&ptr,1); 1323*4887Schin if(isastchar(mode)) 1324*4887Schin { 1325*4887Schin if(id==idbuff) /* ${@} or ${*} */ 1326*4887Schin { 1327*4887Schin if(type<0 && (type+= dolmax)<0) 1328*4887Schin type = 0; 1329*4887Schin if(type==0) 1330*4887Schin v = special(dolg=0); 1331*4887Schin #if SHOPT_FILESCAN 1332*4887Schin else if(sh.cur_line) 1333*4887Schin { 1334*4887Schin v = getdolarg(&sh,dolg=type,&vsize); 1335*4887Schin if(!v) 1336*4887Schin dolmax = type; 1337*4887Schin } 1338*4887Schin #endif /* SHOPT_FILESCAN */ 1339*4887Schin else if(type < dolmax) 1340*4887Schin v = sh.st.dolv[dolg=type]; 1341*4887Schin else 1342*4887Schin v = 0; 1343*4887Schin } 1344*4887Schin else if(ap) 1345*4887Schin { 1346*4887Schin if(type<0) 1347*4887Schin { 1348*4887Schin if(array_assoc(ap)) 1349*4887Schin type = -type; 1350*4887Schin else 1351*4887Schin type += array_maxindex(np); 1352*4887Schin } 1353*4887Schin if(array_assoc(ap)) 1354*4887Schin { 1355*4887Schin while(type-- >0 && (v=0,nv_nextsub(np))) 1356*4887Schin v = nv_getval(np); 1357*4887Schin } 1358*4887Schin else if(type > 0) 1359*4887Schin { 1360*4887Schin if(nv_putsub(np,NIL(char*),type|ARRAY_SCAN)) 1361*4887Schin v = nv_getval(np); 1362*4887Schin else 1363*4887Schin v = 0; 1364*4887Schin } 1365*4887Schin } 1366*4887Schin else if(type>0) 1367*4887Schin v = 0; 1368*4887Schin } 1369*4887Schin else if(v) 1370*4887Schin { 1371*4887Schin vsize = charlen(v,vsize); 1372*4887Schin if(type<0 && (type += vsize)<0) 1373*4887Schin type = 0; 1374*4887Schin if(vsize < type) 1375*4887Schin v = 0; 1376*4887Schin #if SHOPT_MULTIBYTE 1377*4887Schin else if(mbwide()) 1378*4887Schin { 1379*4887Schin mbinit(); 1380*4887Schin while(type-->0) 1381*4887Schin { 1382*4887Schin if((c=mbsize(v))<1) 1383*4887Schin c = 1; 1384*4887Schin v += c; 1385*4887Schin } 1386*4887Schin c = ':'; 1387*4887Schin } 1388*4887Schin #endif /* SHOPT_MULTIBYTE */ 1389*4887Schin else 1390*4887Schin v += type; 1391*4887Schin vsize -= type; 1392*4887Schin } 1393*4887Schin if(*ptr==':') 1394*4887Schin { 1395*4887Schin if((type = (int)sh_strnum(ptr+1,&ptr,1)) <=0) 1396*4887Schin v = 0; 1397*4887Schin else if(isastchar(mode)) 1398*4887Schin { 1399*4887Schin if(dolg>=0) 1400*4887Schin { 1401*4887Schin if(dolg+type < dolmax) 1402*4887Schin dolmax = dolg+type; 1403*4887Schin } 1404*4887Schin else 1405*4887Schin dolmax = type; 1406*4887Schin } 1407*4887Schin else if(type < vsize) 1408*4887Schin { 1409*4887Schin #if SHOPT_MULTIBYTE 1410*4887Schin if(mbwide()) 1411*4887Schin { 1412*4887Schin char *vp = v; 1413*4887Schin mbinit(); 1414*4887Schin while(type-->0) 1415*4887Schin { 1416*4887Schin if((c=mbsize(vp))<1) 1417*4887Schin c = 1; 1418*4887Schin vp += c; 1419*4887Schin } 1420*4887Schin type = vp-v; 1421*4887Schin c = ':'; 1422*4887Schin } 1423*4887Schin #endif /* SHOPT_MULTIBYTE */ 1424*4887Schin vsize = type; 1425*4887Schin } 1426*4887Schin } 1427*4887Schin if(*ptr) 1428*4887Schin mac_error(np); 1429*4887Schin stakseek(offset); 1430*4887Schin argp = 0; 1431*4887Schin } 1432*4887Schin /* check for substring operations */ 1433*4887Schin else if(c == '#' || c == '%' || c=='/') 1434*4887Schin { 1435*4887Schin if(c=='/') 1436*4887Schin { 1437*4887Schin if(type=='/' || type=='#' || type=='%') 1438*4887Schin { 1439*4887Schin c = type; 1440*4887Schin type = '/'; 1441*4887Schin argp++; 1442*4887Schin } 1443*4887Schin else 1444*4887Schin type = 0; 1445*4887Schin } 1446*4887Schin else 1447*4887Schin { 1448*4887Schin if(type==c) /* ## or %% */ 1449*4887Schin argp++; 1450*4887Schin else 1451*4887Schin type = 0; 1452*4887Schin } 1453*4887Schin pattern = strdup(argp); 1454*4887Schin if((type=='/' || c=='/') && (repstr = mac_getstring(pattern))) 1455*4887Schin replen = strlen(repstr); 1456*4887Schin if(v || c=='/' && offset>=0) 1457*4887Schin stakseek(offset); 1458*4887Schin } 1459*4887Schin /* check for quoted @ */ 1460*4887Schin if(mode=='@' && mp->quote && !v && c!='-') 1461*4887Schin mp->quoted-=2; 1462*4887Schin retry2: 1463*4887Schin if(v && (!nulflg || *v ) && c!='+') 1464*4887Schin { 1465*4887Schin register int d = (mode=='@'?' ':mp->ifs); 1466*4887Schin int match[2*(MATCH_MAX+1)], nmatch, vsize_last; 1467*4887Schin char *vlast; 1468*4887Schin while(1) 1469*4887Schin { 1470*4887Schin if(!v) 1471*4887Schin v= ""; 1472*4887Schin if(c=='/' || c=='#' || c== '%') 1473*4887Schin { 1474*4887Schin flag = (type || c=='/')?STR_GROUP|STR_MAXIMAL:STR_GROUP; 1475*4887Schin if(c!='/') 1476*4887Schin flag |= STR_LEFT; 1477*4887Schin while(1) 1478*4887Schin { 1479*4887Schin vsize = strlen(v); 1480*4887Schin if(c=='%') 1481*4887Schin nmatch=substring(v,pattern,match,flag&STR_MAXIMAL); 1482*4887Schin else 1483*4887Schin nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag); 1484*4887Schin if(replen>0) 1485*4887Schin sh_setmatch(v,vsize,nmatch,match); 1486*4887Schin if(nmatch) 1487*4887Schin { 1488*4887Schin vlast = v; 1489*4887Schin vsize_last = vsize; 1490*4887Schin vsize = match[0]; 1491*4887Schin } 1492*4887Schin else if(c=='#') 1493*4887Schin vsize = 0; 1494*4887Schin if(vsize) 1495*4887Schin mac_copy(mp,v,vsize); 1496*4887Schin if(nmatch && replen>0) 1497*4887Schin mac_substitute(mp,repstr,v,match,nmatch); 1498*4887Schin if(nmatch==0) 1499*4887Schin v += vsize; 1500*4887Schin else 1501*4887Schin v += match[1]; 1502*4887Schin if(*v && c=='/' && type) 1503*4887Schin { 1504*4887Schin /* avoid infinite loop */ 1505*4887Schin if(nmatch && match[1]==0) 1506*4887Schin v++; 1507*4887Schin continue; 1508*4887Schin } 1509*4887Schin vsize = -1; 1510*4887Schin break; 1511*4887Schin } 1512*4887Schin if(replen==0) 1513*4887Schin sh_setmatch(vlast,vsize_last,nmatch,match); 1514*4887Schin } 1515*4887Schin if(vsize) 1516*4887Schin mac_copy(mp,v,vsize>0?vsize:strlen(v)); 1517*4887Schin if(dolg==0 && dolmax==0) 1518*4887Schin break; 1519*4887Schin if(dolg>=0) 1520*4887Schin { 1521*4887Schin if(++dolg >= dolmax) 1522*4887Schin break; 1523*4887Schin #if SHOPT_FILESCAN 1524*4887Schin if(sh.cur_line) 1525*4887Schin { 1526*4887Schin if(dolmax==MAX_ARGN && isastchar(mode)) 1527*4887Schin break; 1528*4887Schin if(!(v=getdolarg(&sh,dolg,&vsize))) 1529*4887Schin { 1530*4887Schin dolmax = dolg; 1531*4887Schin break; 1532*4887Schin } 1533*4887Schin } 1534*4887Schin else 1535*4887Schin #endif /* SHOPT_FILESCAN */ 1536*4887Schin v = sh.st.dolv[dolg]; 1537*4887Schin } 1538*4887Schin else if(!np) 1539*4887Schin { 1540*4887Schin if(!(v = nextname(mp,id,dolmax))) 1541*4887Schin break; 1542*4887Schin } 1543*4887Schin else 1544*4887Schin { 1545*4887Schin if(dolmax && --dolmax <=0) 1546*4887Schin { 1547*4887Schin nv_putsub(np,NIL(char*),ARRAY_UNDEF); 1548*4887Schin break; 1549*4887Schin } 1550*4887Schin if(nv_nextsub(np) == 0) 1551*4887Schin break; 1552*4887Schin if(bysub) 1553*4887Schin v = nv_getsub(np); 1554*4887Schin else 1555*4887Schin v = nv_getval(np); 1556*4887Schin } 1557*4887Schin if(mp->split && (!mp->quote || mode=='@')) 1558*4887Schin { 1559*4887Schin if(!np) 1560*4887Schin mp->pattern = 0; 1561*4887Schin endfield(mp,mp->quoted); 1562*4887Schin mp->pattern = oldpat; 1563*4887Schin } 1564*4887Schin else if(d) 1565*4887Schin { 1566*4887Schin if(mp->sp) 1567*4887Schin sfputc(mp->sp,d); 1568*4887Schin else 1569*4887Schin stakputc(d); 1570*4887Schin } 1571*4887Schin } 1572*4887Schin if(pattern) 1573*4887Schin free((void*)pattern); 1574*4887Schin } 1575*4887Schin else if(argp) 1576*4887Schin { 1577*4887Schin if(c=='/' && replen>0 && pattern && strmatch("",pattern)) 1578*4887Schin mac_substitute(mp,repstr,v,0,0); 1579*4887Schin if(c=='?') 1580*4887Schin { 1581*4887Schin if(np) 1582*4887Schin id = nv_name(np); 1583*4887Schin else if(idnum) 1584*4887Schin id = ltos(idnum); 1585*4887Schin if(*argp) 1586*4887Schin { 1587*4887Schin stakputc(0); 1588*4887Schin errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp); 1589*4887Schin } 1590*4887Schin else if(v) 1591*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_nullset,id); 1592*4887Schin else 1593*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_notset,id); 1594*4887Schin } 1595*4887Schin else if(c=='=') 1596*4887Schin { 1597*4887Schin if(np) 1598*4887Schin { 1599*4887Schin if(sh.subshell) 1600*4887Schin np = sh_assignok(np,1); 1601*4887Schin nv_putval(np,argp,0); 1602*4887Schin v = nv_getval(np); 1603*4887Schin nulflg = 0; 1604*4887Schin stakseek(offset); 1605*4887Schin goto retry2; 1606*4887Schin } 1607*4887Schin else 1608*4887Schin mac_error(np); 1609*4887Schin } 1610*4887Schin } 1611*4887Schin else if(sh_isoption(SH_NOUNSET) && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp))) 1612*4887Schin { 1613*4887Schin if(np) 1614*4887Schin { 1615*4887Schin if(nv_isarray(np)) 1616*4887Schin { 1617*4887Schin sfprintf(sh.strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np)); 1618*4887Schin id = nv_getsub(np); 1619*4887Schin id = sfstruse(sh.strbuf); 1620*4887Schin } 1621*4887Schin else 1622*4887Schin id = nv_name(np); 1623*4887Schin nv_close(np); 1624*4887Schin } 1625*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_notset,id); 1626*4887Schin } 1627*4887Schin if(np) 1628*4887Schin nv_close(np); 1629*4887Schin return(1); 1630*4887Schin nosub: 1631*4887Schin if(type) 1632*4887Schin mac_error(np); 1633*4887Schin fcseek(-1); 1634*4887Schin nv_close(np); 1635*4887Schin return(0); 1636*4887Schin } 1637*4887Schin 1638*4887Schin /* 1639*4887Schin * This routine handles command substitution 1640*4887Schin * <type> is 0 for older `...` version 1641*4887Schin */ 1642*4887Schin static void comsubst(Mac_t *mp,int type) 1643*4887Schin { 1644*4887Schin Sfdouble_t num; 1645*4887Schin register int c; 1646*4887Schin register char *str; 1647*4887Schin Sfio_t *sp; 1648*4887Schin Fcin_t save; 1649*4887Schin struct slnod *saveslp = sh.st.staklist; 1650*4887Schin struct _mac_ savemac; 1651*4887Schin int savtop = staktell(); 1652*4887Schin char lastc, *savptr = stakfreeze(0); 1653*4887Schin int was_history = sh_isstate(SH_HISTORY); 1654*4887Schin int was_verbose = sh_isstate(SH_VERBOSE); 1655*4887Schin int newlines,bufsize; 1656*4887Schin register Shnode_t *t; 1657*4887Schin Namval_t *np; 1658*4887Schin sh.argaddr = 0; 1659*4887Schin savemac = *mp; 1660*4887Schin sh.st.staklist=0; 1661*4887Schin if(type) 1662*4887Schin { 1663*4887Schin sp = 0; 1664*4887Schin fcseek(-1); 1665*4887Schin t = sh_dolparen(); 1666*4887Schin if(t && t->tre.tretyp==TARITH) 1667*4887Schin { 1668*4887Schin str = t->ar.arexpr->argval; 1669*4887Schin fcsave(&save); 1670*4887Schin if(!(t->ar.arexpr->argflag&ARG_RAW)) 1671*4887Schin str = sh_mactrim(str,3); 1672*4887Schin num = sh_arith(str); 1673*4887Schin out_offset: 1674*4887Schin stakset(savptr,savtop); 1675*4887Schin *mp = savemac; 1676*4887Schin if((Sflong_t)num==num) 1677*4887Schin sfprintf(sh.strbuf,"%lld",(Sflong_t)num); 1678*4887Schin else 1679*4887Schin sfprintf(sh.strbuf,"%.*Lg",LDBL_DIG,num); 1680*4887Schin str = sfstruse(sh.strbuf); 1681*4887Schin mac_copy(mp,str,strlen(str)); 1682*4887Schin sh.st.staklist = saveslp; 1683*4887Schin fcrestore(&save); 1684*4887Schin return; 1685*4887Schin } 1686*4887Schin } 1687*4887Schin else 1688*4887Schin { 1689*4887Schin while(fcgetc(c)!='`' && c) 1690*4887Schin { 1691*4887Schin if(c==ESCAPE) 1692*4887Schin { 1693*4887Schin fcgetc(c); 1694*4887Schin if(!(isescchar(sh_lexstates[ST_QUOTE][c]) || 1695*4887Schin (c=='"' && mp->quote)) || (c=='$' && fcpeek(0)=='\'')) 1696*4887Schin stakputc(ESCAPE); 1697*4887Schin } 1698*4887Schin stakputc(c); 1699*4887Schin } 1700*4887Schin c = staktell(); 1701*4887Schin str=stakfreeze(1); 1702*4887Schin /* disable verbose and don't save in history file */ 1703*4887Schin sh_offstate(SH_HISTORY); 1704*4887Schin sh_offstate(SH_VERBOSE); 1705*4887Schin if(mp->sp) 1706*4887Schin sfsync(mp->sp); /* flush before executing command */ 1707*4887Schin sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ); 1708*4887Schin c = sh.inlineno; 1709*4887Schin sh.inlineno = error_info.line+sh.st.firstline; 1710*4887Schin t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL); 1711*4887Schin sh.inlineno = c; 1712*4887Schin } 1713*4887Schin #if KSHELL 1714*4887Schin if(t) 1715*4887Schin { 1716*4887Schin fcsave(&save); 1717*4887Schin sfclose(sp); 1718*4887Schin if(t->tre.tretyp==0 && !t->com.comarg) 1719*4887Schin { 1720*4887Schin /* special case $(<file) and $(<#file) */ 1721*4887Schin register int fd; 1722*4887Schin int r; 1723*4887Schin struct checkpt buff; 1724*4887Schin struct ionod *ip=0; 1725*4887Schin sh_pushcontext(&buff,SH_JMPIO); 1726*4887Schin if((ip=t->tre.treio) && 1727*4887Schin ((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) && 1728*4887Schin (r=sigsetjmp(buff.buff,0))==0) 1729*4887Schin fd = sh_redirect(ip,3); 1730*4887Schin else 1731*4887Schin fd = sh_chkopen(e_devnull); 1732*4887Schin sh_popcontext(&buff); 1733*4887Schin if(r==0 && ip && (ip->iofile&IOLSEEK)) 1734*4887Schin { 1735*4887Schin if(sp=sh.sftable[fd]) 1736*4887Schin num = sftell(sp); 1737*4887Schin else 1738*4887Schin num = lseek(fd, (off_t)0, SEEK_CUR); 1739*4887Schin goto out_offset; 1740*4887Schin } 1741*4887Schin sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC); 1742*4887Schin } 1743*4887Schin else 1744*4887Schin sp = sh_subshell(t,sh_isstate(SH_ERREXIT),1); 1745*4887Schin fcrestore(&save); 1746*4887Schin } 1747*4887Schin else 1748*4887Schin sp = sfopen(NIL(Sfio_t*),"","sr"); 1749*4887Schin sh_freeup(); 1750*4887Schin sh.st.staklist = saveslp; 1751*4887Schin if(was_history) 1752*4887Schin sh_onstate(SH_HISTORY); 1753*4887Schin if(was_verbose) 1754*4887Schin sh_onstate(SH_VERBOSE); 1755*4887Schin #else 1756*4887Schin sp = sfpopen(NIL(Sfio_t*),str,"r"); 1757*4887Schin #endif 1758*4887Schin *mp = savemac; 1759*4887Schin np = nv_scoped(IFSNOD); 1760*4887Schin nv_putval(np,mp->ifsp,0); 1761*4887Schin mp->ifsp = nv_getval(np); 1762*4887Schin stakset(savptr,savtop); 1763*4887Schin newlines = 0; 1764*4887Schin lastc = 0; 1765*4887Schin sfsetbuf(sp,(void*)sp,0); 1766*4887Schin bufsize = sfvalue(sp); 1767*4887Schin /* read command substitution output and put on stack or here-doc */ 1768*4887Schin sfpool(sp, NIL(Sfio_t*), SF_WRITE); 1769*4887Schin while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c = sfvalue(sp))>0) 1770*4887Schin { 1771*4887Schin #if SHOPT_CRNL 1772*4887Schin /* eliminate <cr> */ 1773*4887Schin register char *dp; 1774*4887Schin char *buff = str; 1775*4887Schin while(c>1 && (*str !='\r'|| str[1]!='\n')) 1776*4887Schin { 1777*4887Schin c--; 1778*4887Schin str++; 1779*4887Schin } 1780*4887Schin dp = str; 1781*4887Schin while(c>1) 1782*4887Schin { 1783*4887Schin str++; 1784*4887Schin c--; 1785*4887Schin while(c>1 && (*str!='\r' || str[1]!='\n')) 1786*4887Schin { 1787*4887Schin c--; 1788*4887Schin *dp++ = *str++; 1789*4887Schin } 1790*4887Schin } 1791*4887Schin if(c) 1792*4887Schin *dp++ = *str++; 1793*4887Schin *dp = 0; 1794*4887Schin str = buff; 1795*4887Schin c = dp-str; 1796*4887Schin #endif /* SHOPT_CRNL */ 1797*4887Schin if(newlines >0) 1798*4887Schin { 1799*4887Schin if(mp->sp) 1800*4887Schin sfnputc(mp->sp,'\n',newlines); 1801*4887Schin else if(!mp->quote && mp->split && sh.ifstable['\n']) 1802*4887Schin endfield(mp,0); 1803*4887Schin else while(newlines--) 1804*4887Schin stakputc('\n'); 1805*4887Schin newlines = 0; 1806*4887Schin } 1807*4887Schin else if(lastc) 1808*4887Schin { 1809*4887Schin mac_copy(mp,&lastc,1); 1810*4887Schin lastc = 0; 1811*4887Schin } 1812*4887Schin /* delay appending trailing new-lines */ 1813*4887Schin while(str[--c]=='\n') 1814*4887Schin newlines++; 1815*4887Schin if(++c < bufsize) 1816*4887Schin str[c] = 0; 1817*4887Schin else 1818*4887Schin { 1819*4887Schin /* can't write past buffer so save last character */ 1820*4887Schin lastc = str[--c]; 1821*4887Schin str[c] = 0; 1822*4887Schin } 1823*4887Schin mac_copy(mp,str,c); 1824*4887Schin } 1825*4887Schin if(--newlines>0 && sh.ifstable['\n']==S_DELIM) 1826*4887Schin { 1827*4887Schin if(mp->sp) 1828*4887Schin sfnputc(mp->sp,'\n',newlines); 1829*4887Schin else if(!mp->quote && mp->split && sh.ifstable['\n']) 1830*4887Schin endfield(mp,0); 1831*4887Schin else while(newlines--) 1832*4887Schin stakputc('\n'); 1833*4887Schin } 1834*4887Schin if(lastc) 1835*4887Schin mac_copy(mp,&lastc,1); 1836*4887Schin sfclose(sp); 1837*4887Schin return; 1838*4887Schin } 1839*4887Schin 1840*4887Schin /* 1841*4887Schin * copy <str> onto the stack 1842*4887Schin */ 1843*4887Schin static void mac_copy(register Mac_t *mp,register const char *str, register int size) 1844*4887Schin { 1845*4887Schin register char *state; 1846*4887Schin register const char *cp=str; 1847*4887Schin register int c,n,nopat; 1848*4887Schin nopat = (mp->quote||mp->assign==1||mp->arith); 1849*4887Schin if(mp->zeros) 1850*4887Schin { 1851*4887Schin /* prevent leading 0's from becomming octal constants */ 1852*4887Schin while(size>1 && *str=='0') 1853*4887Schin str++,size--; 1854*4887Schin mp->zeros = 0; 1855*4887Schin cp = str; 1856*4887Schin } 1857*4887Schin if(mp->sp) 1858*4887Schin sfwrite(mp->sp,str,size); 1859*4887Schin else if(mp->pattern>=2 || (mp->pattern && nopat)) 1860*4887Schin { 1861*4887Schin state = sh_lexstates[ST_MACRO]; 1862*4887Schin /* insert \ before file expansion characters */ 1863*4887Schin while(size-->0) 1864*4887Schin { 1865*4887Schin c = state[n= *(unsigned char*)cp++]; 1866*4887Schin if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3) 1867*4887Schin c=1; 1868*4887Schin else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n))) 1869*4887Schin c=1; 1870*4887Schin else if(mp->pattern==2 && c==S_SLASH) 1871*4887Schin c=1; 1872*4887Schin else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE))) 1873*4887Schin { 1874*4887Schin if(!(c=mp->quote)) 1875*4887Schin cp++; 1876*4887Schin } 1877*4887Schin else 1878*4887Schin c=0; 1879*4887Schin if(c) 1880*4887Schin { 1881*4887Schin if(c = (cp-1) - str) 1882*4887Schin stakwrite(str,c); 1883*4887Schin stakputc(ESCAPE); 1884*4887Schin str = cp-1; 1885*4887Schin } 1886*4887Schin } 1887*4887Schin if(c = cp-str) 1888*4887Schin stakwrite(str,c); 1889*4887Schin } 1890*4887Schin else if(!mp->quote && mp->split && (mp->ifs||mp->pattern)) 1891*4887Schin { 1892*4887Schin /* split words at ifs characters */ 1893*4887Schin state = sh.ifstable; 1894*4887Schin if(mp->pattern) 1895*4887Schin { 1896*4887Schin char *sp = "&|()"; 1897*4887Schin while(c = *sp++) 1898*4887Schin { 1899*4887Schin if(state[c]==0) 1900*4887Schin state[c] = S_EPAT; 1901*4887Schin } 1902*4887Schin sp = "*?[{"; 1903*4887Schin while(c = *sp++) 1904*4887Schin { 1905*4887Schin if(state[c]==0) 1906*4887Schin state[c] = S_PAT; 1907*4887Schin } 1908*4887Schin if(state[ESCAPE]==0) 1909*4887Schin state[ESCAPE] = S_ESC; 1910*4887Schin } 1911*4887Schin while(size-->0) 1912*4887Schin { 1913*4887Schin if((n=state[c= *(unsigned char*)cp++])==S_ESC || n==S_EPAT) 1914*4887Schin { 1915*4887Schin /* don't allow extended patterns in this case */ 1916*4887Schin mp->patfound = mp->pattern; 1917*4887Schin stakputc(ESCAPE); 1918*4887Schin } 1919*4887Schin else if(n==S_PAT) 1920*4887Schin mp->patfound = mp->pattern; 1921*4887Schin else if(n && mp->ifs) 1922*4887Schin { 1923*4887Schin #if SHOPT_MULTIBYTE 1924*4887Schin if(n==S_MBYTE) 1925*4887Schin { 1926*4887Schin if(sh_strchr(mp->ifsp,cp-1)<0) 1927*4887Schin continue; 1928*4887Schin n = mbsize(cp-1) - 1; 1929*4887Schin if(n==-2) 1930*4887Schin n = 0; 1931*4887Schin cp += n; 1932*4887Schin size -= n; 1933*4887Schin n= S_DELIM; 1934*4887Schin } 1935*4887Schin #endif /* SHOPT_MULTIBYTE */ 1936*4887Schin if(n==S_SPACE || n==S_NL) 1937*4887Schin { 1938*4887Schin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL)) 1939*4887Schin size--; 1940*4887Schin #if SHOPT_MULTIBYTE 1941*4887Schin if(n==S_MBYTE && sh_strchr(mp->ifsp,cp-1)>=0) 1942*4887Schin { 1943*4887Schin n = mbsize(cp-1) - 1; 1944*4887Schin if(n==-2) 1945*4887Schin n = 0; 1946*4887Schin cp += n; 1947*4887Schin size -= n; 1948*4887Schin n=S_DELIM; 1949*4887Schin } 1950*4887Schin else 1951*4887Schin #endif /* SHOPT_MULTIBYTE */ 1952*4887Schin if(n==S_DELIM) 1953*4887Schin size--; 1954*4887Schin } 1955*4887Schin endfield(mp,n==S_DELIM||mp->quoted); 1956*4887Schin mp->patfound = 0; 1957*4887Schin if(n==S_DELIM) 1958*4887Schin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL)) 1959*4887Schin size--; 1960*4887Schin if(size<=0) 1961*4887Schin break; 1962*4887Schin cp--; 1963*4887Schin continue; 1964*4887Schin 1965*4887Schin } 1966*4887Schin stakputc(c); 1967*4887Schin } 1968*4887Schin if(mp->pattern) 1969*4887Schin { 1970*4887Schin cp = "&|()"; 1971*4887Schin while(c = *cp++) 1972*4887Schin { 1973*4887Schin if(state[c]==S_EPAT) 1974*4887Schin state[c] = 0; 1975*4887Schin } 1976*4887Schin cp = "*?[{"; 1977*4887Schin while(c = *cp++) 1978*4887Schin { 1979*4887Schin if(state[c]==S_PAT) 1980*4887Schin state[c] = 0; 1981*4887Schin } 1982*4887Schin if(sh.ifstable[ESCAPE]==S_ESC) 1983*4887Schin sh.ifstable[ESCAPE] = 0; 1984*4887Schin } 1985*4887Schin } 1986*4887Schin else 1987*4887Schin stakwrite(str,size); 1988*4887Schin } 1989*4887Schin 1990*4887Schin /* 1991*4887Schin * Terminate field. 1992*4887Schin * If field is null count field if <split> is non-zero 1993*4887Schin * Do filename expansion of required 1994*4887Schin */ 1995*4887Schin static void endfield(register Mac_t *mp,int split) 1996*4887Schin { 1997*4887Schin register struct argnod *argp; 1998*4887Schin register int count=0; 1999*4887Schin if(staktell() > ARGVAL || split) 2000*4887Schin { 2001*4887Schin argp = (struct argnod*)stakfreeze(1); 2002*4887Schin argp->argnxt.cp = 0; 2003*4887Schin argp->argflag = 0; 2004*4887Schin if(mp->patfound) 2005*4887Schin { 2006*4887Schin sh.argaddr = 0; 2007*4887Schin #if SHOPT_BRACEPAT 2008*4887Schin count = path_generate(argp,mp->arghead); 2009*4887Schin #else 2010*4887Schin count = path_expand(argp->argval,mp->arghead); 2011*4887Schin #endif /* SHOPT_BRACEPAT */ 2012*4887Schin if(count) 2013*4887Schin mp->fields += count; 2014*4887Schin else if(split) /* pattern is null string */ 2015*4887Schin *argp->argval = 0; 2016*4887Schin else /* pattern expands to nothing */ 2017*4887Schin count = -1; 2018*4887Schin } 2019*4887Schin if(count==0) 2020*4887Schin { 2021*4887Schin argp->argchn.ap = *mp->arghead; 2022*4887Schin *mp->arghead = argp; 2023*4887Schin mp->fields++; 2024*4887Schin } 2025*4887Schin if(count>=0) 2026*4887Schin { 2027*4887Schin (*mp->arghead)->argflag |= ARG_MAKE; 2028*4887Schin if(mp->assign || sh_isoption(SH_NOGLOB)) 2029*4887Schin argp->argflag |= ARG_RAW|ARG_EXP; 2030*4887Schin } 2031*4887Schin stakseek(ARGVAL); 2032*4887Schin } 2033*4887Schin mp->quoted = mp->quote; 2034*4887Schin } 2035*4887Schin 2036*4887Schin /* 2037*4887Schin * Finds the right substring of STRING using the expression PAT 2038*4887Schin * the longest substring is found when FLAG is set. 2039*4887Schin */ 2040*4887Schin static int substring(register const char *string,const char *pat,int match[], int flag) 2041*4887Schin { 2042*4887Schin register const char *sp=string; 2043*4887Schin register int size,len,nmatch,n; 2044*4887Schin int smatch[2*(MATCH_MAX+1)]; 2045*4887Schin if(flag) 2046*4887Schin { 2047*4887Schin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL)) 2048*4887Schin { 2049*4887Schin memcpy(match,smatch,n*2*sizeof(smatch[0])); 2050*4887Schin return(n); 2051*4887Schin } 2052*4887Schin return(0); 2053*4887Schin } 2054*4887Schin size = len = strlen(sp); 2055*4887Schin sp += size; 2056*4887Schin while(sp>=string) 2057*4887Schin { 2058*4887Schin #if SHOPT_MULTIBYTE 2059*4887Schin if(mbwide()) 2060*4887Schin sp = lastchar(string,sp); 2061*4887Schin #endif /* SHOPT_MULTIBYTE */ 2062*4887Schin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL)) 2063*4887Schin { 2064*4887Schin nmatch = n; 2065*4887Schin memcpy(match,smatch,n*2*sizeof(smatch[0])); 2066*4887Schin size = sp-string; 2067*4887Schin break; 2068*4887Schin } 2069*4887Schin sp--; 2070*4887Schin } 2071*4887Schin if(size==len) 2072*4887Schin return(0); 2073*4887Schin if(nmatch) 2074*4887Schin { 2075*4887Schin nmatch *=2; 2076*4887Schin while(--nmatch>=0) 2077*4887Schin match[nmatch] += size; 2078*4887Schin } 2079*4887Schin return(n); 2080*4887Schin } 2081*4887Schin 2082*4887Schin #if SHOPT_MULTIBYTE 2083*4887Schin static char *lastchar(const char *string, const char *endstring) 2084*4887Schin { 2085*4887Schin register char *str = (char*)string; 2086*4887Schin register int c; 2087*4887Schin mbinit(); 2088*4887Schin while(*str) 2089*4887Schin { 2090*4887Schin if((c=mbsize(str))<0) 2091*4887Schin c = 1; 2092*4887Schin if(str+c > endstring) 2093*4887Schin break; 2094*4887Schin str += c; 2095*4887Schin } 2096*4887Schin return(str); 2097*4887Schin } 2098*4887Schin #endif /* SHOPT_MULTIBYTE */ 2099*4887Schin static int charlen(const char *string,int len) 2100*4887Schin { 2101*4887Schin if(!string) 2102*4887Schin return(0); 2103*4887Schin #if SHOPT_MULTIBYTE 2104*4887Schin if(mbwide()) 2105*4887Schin { 2106*4887Schin register const char *str = string, *strmax=string+len; 2107*4887Schin register int n=0; 2108*4887Schin mbinit(); 2109*4887Schin if(len>0) 2110*4887Schin { 2111*4887Schin while(str<strmax && mbchar(str)) 2112*4887Schin n++; 2113*4887Schin } 2114*4887Schin else while(mbchar(str)) 2115*4887Schin n++; 2116*4887Schin return(n); 2117*4887Schin } 2118*4887Schin else 2119*4887Schin #endif /* SHOPT_MULTIBYTE */ 2120*4887Schin { 2121*4887Schin if(len<0) 2122*4887Schin return(strlen(string)); 2123*4887Schin return(len); 2124*4887Schin } 2125*4887Schin } 2126*4887Schin 2127*4887Schin /* 2128*4887Schin * This is the default tilde discipline function 2129*4887Schin */ 2130*4887Schin static int sh_btilde(int argc, char *argv[], void *context) 2131*4887Schin { 2132*4887Schin char *cp = sh_tilde(argv[1]); 2133*4887Schin NOT_USED(argc); 2134*4887Schin NOT_USED(context); 2135*4887Schin if(!cp) 2136*4887Schin cp = argv[1]; 2137*4887Schin sfputr(sfstdout, cp, '\n'); 2138*4887Schin return(0); 2139*4887Schin } 2140*4887Schin 2141*4887Schin /* 2142*4887Schin * <offset> is byte offset for beginning of tilde string 2143*4887Schin */ 2144*4887Schin static void tilde_expand2(register int offset) 2145*4887Schin { 2146*4887Schin char shtilde[10], *av[3], *ptr=stakfreeze(1); 2147*4887Schin Sfio_t *iop, *save=sfstdout; 2148*4887Schin Namval_t *np; 2149*4887Schin static int beenhere=0; 2150*4887Schin strcpy(shtilde,".sh.tilde"); 2151*4887Schin np = nv_open(shtilde,sh.fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL); 2152*4887Schin if(np && !beenhere) 2153*4887Schin { 2154*4887Schin beenhere = 1; 2155*4887Schin sh_addbuiltin(shtilde,sh_btilde,0); 2156*4887Schin } 2157*4887Schin av[0] = ".sh.tilde"; 2158*4887Schin av[1] = &ptr[offset]; 2159*4887Schin av[2] = 0; 2160*4887Schin iop = sftmp(IOBSIZE+1);; 2161*4887Schin sfset(iop,SF_READ,0); 2162*4887Schin sfstdout = iop; 2163*4887Schin if(np) 2164*4887Schin sh_fun(np, (Namval_t*)0, av); 2165*4887Schin else 2166*4887Schin sh_btilde(2, av, &sh); 2167*4887Schin sfstdout = save; 2168*4887Schin stakset(ptr, offset); 2169*4887Schin sfseek(iop,(Sfoff_t)0,SEEK_SET); 2170*4887Schin sfset(iop,SF_READ,1); 2171*4887Schin if(ptr = sfreserve(iop, SF_UNBOUND, -1)) 2172*4887Schin { 2173*4887Schin Sfoff_t n = sfvalue(iop); 2174*4887Schin while(ptr[n-1]=='\n') 2175*4887Schin n--; 2176*4887Schin if(n==1 && fcpeek(0)=='/' && ptr[n-1]) 2177*4887Schin n--; 2178*4887Schin if(n) 2179*4887Schin stakwrite(ptr,n); 2180*4887Schin } 2181*4887Schin else 2182*4887Schin stakputs(av[1]); 2183*4887Schin sfclose(iop); 2184*4887Schin } 2185*4887Schin 2186*4887Schin /* 2187*4887Schin * This routine is used to resolve ~ expansion. 2188*4887Schin * A ~ by itself is replaced with the users login directory. 2189*4887Schin * A ~- is replaced by the previous working directory in shell. 2190*4887Schin * A ~+ is replaced by the present working directory in shell. 2191*4887Schin * If ~name is replaced with login directory of name. 2192*4887Schin * If string doesn't start with ~ or ~... not found then 0 returned. 2193*4887Schin */ 2194*4887Schin 2195*4887Schin static char *sh_tilde(register const char *string) 2196*4887Schin { 2197*4887Schin register char *cp; 2198*4887Schin register int c; 2199*4887Schin register struct passwd *pw; 2200*4887Schin register Namval_t *np=0; 2201*4887Schin static Dt_t *logins_tree; 2202*4887Schin if(*string++!='~') 2203*4887Schin return(NIL(char*)); 2204*4887Schin if((c = *string)==0) 2205*4887Schin { 2206*4887Schin if(!(cp=nv_getval(nv_scoped(HOME)))) 2207*4887Schin cp = getlogin(); 2208*4887Schin return(cp); 2209*4887Schin } 2210*4887Schin if((c=='-' || c=='+') && string[1]==0) 2211*4887Schin { 2212*4887Schin if(c=='+') 2213*4887Schin cp = nv_getval(nv_scoped(PWDNOD)); 2214*4887Schin else 2215*4887Schin cp = nv_getval(nv_scoped(OLDPWDNOD)); 2216*4887Schin return(cp); 2217*4887Schin } 2218*4887Schin if(logins_tree && (np=nv_search(string,logins_tree,0))) 2219*4887Schin return(nv_getval(np)); 2220*4887Schin if(!(pw = getpwnam(string))) 2221*4887Schin return(NIL(char*)); 2222*4887Schin if(!logins_tree) 2223*4887Schin logins_tree = dtopen(&_Nvdisc,Dtbag); 2224*4887Schin if(np=nv_search(string,logins_tree,NV_ADD)) 2225*4887Schin nv_putval(np, pw->pw_dir,0); 2226*4887Schin return(pw->pw_dir); 2227*4887Schin } 2228*4887Schin 2229*4887Schin /* 2230*4887Schin * return values for special macros 2231*4887Schin */ 2232*4887Schin static char *special(register int c) 2233*4887Schin { 2234*4887Schin register Namval_t *np; 2235*4887Schin if(c!='$') 2236*4887Schin sh.argaddr = 0; 2237*4887Schin switch(c) 2238*4887Schin { 2239*4887Schin case '@': 2240*4887Schin case '*': 2241*4887Schin return(sh.st.dolc>0?sh.st.dolv[1]:NIL(char*)); 2242*4887Schin case '#': 2243*4887Schin #if SHOPT_FILESCAN 2244*4887Schin if(sh.cur_line) 2245*4887Schin { 2246*4887Schin getdolarg(&sh,MAX_ARGN,(int*)0); 2247*4887Schin return(ltos(sh.offsets[0])); 2248*4887Schin } 2249*4887Schin #endif /* SHOPT_FILESCAN */ 2250*4887Schin return(ltos(sh.st.dolc)); 2251*4887Schin case '!': 2252*4887Schin if(sh.bckpid) 2253*4887Schin return(ltos(sh.bckpid)); 2254*4887Schin break; 2255*4887Schin case '$': 2256*4887Schin if(nv_isnull(SH_DOLLARNOD)) 2257*4887Schin return(ltos(sh.pid)); 2258*4887Schin return(nv_getval(SH_DOLLARNOD)); 2259*4887Schin case '-': 2260*4887Schin return(sh_argdolminus()); 2261*4887Schin case '?': 2262*4887Schin return(ltos(sh.savexit)); 2263*4887Schin case 0: 2264*4887Schin if(sh_isstate(SH_PROFILE) || !error_info.id || ((np=nv_search(error_info.id,sh.bltin_tree,0)) && nv_isattr(np,BLT_SPC))) 2265*4887Schin return(sh.shname); 2266*4887Schin else 2267*4887Schin return(error_info.id); 2268*4887Schin } 2269*4887Schin return(NIL(char*)); 2270*4887Schin } 2271*4887Schin 2272*4887Schin /* 2273*4887Schin * Handle macro expansion errors 2274*4887Schin */ 2275*4887Schin static void mac_error(Namval_t *np) 2276*4887Schin { 2277*4887Schin if(np) 2278*4887Schin nv_close(np); 2279*4887Schin errormsg(SH_DICT,ERROR_exit(1),e_subst,fcfirst()); 2280*4887Schin } 2281*4887Schin 2282*4887Schin /* 2283*4887Schin * Given pattern/string, replace / with 0 and return pointer to string 2284*4887Schin * \ characters are stripped from string. 2285*4887Schin */ 2286*4887Schin static char *mac_getstring(char *pattern) 2287*4887Schin { 2288*4887Schin register char *cp = pattern; 2289*4887Schin register int c; 2290*4887Schin while(c = *cp++) 2291*4887Schin { 2292*4887Schin if(c==ESCAPE) 2293*4887Schin cp++; 2294*4887Schin else if(c=='/') 2295*4887Schin { 2296*4887Schin cp[-1] = 0; 2297*4887Schin return(cp); 2298*4887Schin } 2299*4887Schin } 2300*4887Schin return(NIL(char*)); 2301*4887Schin } 2302