14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 48462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * Shell macro expander 234887Schin * expands ~ 244887Schin * expands ${...} 254887Schin * expands $(...) 264887Schin * expands $((...)) 274887Schin * expands `...` 284887Schin * 294887Schin * David Korn 304887Schin * AT&T Labs 314887Schin * 324887Schin */ 334887Schin 344887Schin #include "defs.h" 354887Schin #include <fcin.h> 364887Schin #include <pwd.h> 374887Schin #include "name.h" 384887Schin #include "variables.h" 394887Schin #include "shlex.h" 404887Schin #include "io.h" 414887Schin #include "shnodes.h" 424887Schin #include "path.h" 434887Schin #include "national.h" 444887Schin #include "streval.h" 454887Schin 464887Schin #undef STR_GROUP 474887Schin #ifndef STR_GROUP 484887Schin # define STR_GROUP 0 494887Schin #endif 504887Schin 514887Schin #if !SHOPT_MULTIBYTE 524887Schin #define mbchar(p) (*(unsigned char*)p++) 534887Schin #endif 544887Schin 554887Schin static int _c_; 564887Schin typedef struct _mac_ 574887Schin { 584887Schin Shell_t *shp; /* pointer to shell interpreter */ 594887Schin Sfio_t *sp; /* stream pointer for here-document */ 604887Schin struct argnod **arghead; /* address of head of argument list */ 614887Schin char *ifsp; /* pointer to IFS value */ 624887Schin int fields; /* number of fields */ 634887Schin short quoted; /* set when word has quotes */ 644887Schin unsigned char ifs; /* first char of IFS */ 654887Schin char quote; /* set within double quoted contexts */ 664887Schin char lit; /* set within single quotes */ 674887Schin char split; /* set when word splittin is possible */ 684887Schin char pattern; /* set when file expansion follows */ 694887Schin char patfound; /* set if pattern character found */ 704887Schin char assign; /* set for assignments */ 714887Schin char arith; /* set for ((...)) */ 724887Schin char let; /* set when expanding let arguments */ 734887Schin char zeros; /* strip leading zeros when set */ 748462SApril.Chin@Sun.COM char arrayok; /* $x[] ok for arrays */ 758462SApril.Chin@Sun.COM char subcopy; /* set when copying subscript */ 768462SApril.Chin@Sun.COM int dotdot; /* set for .. in subscript */ 774887Schin void *nvwalk; /* for name space walking*/ 784887Schin } Mac_t; 794887Schin 804887Schin #undef ESCAPE 814887Schin #define ESCAPE '\\' 824887Schin #define isescchar(s) ((s)>S_QUOTE) 834887Schin #define isqescchar(s) ((s)>=S_QUOTE) 844887Schin #define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2) 854887Schin #define ltos(x) fmtbase((long)(x),0,0) 864887Schin 874887Schin /* type of macro expansions */ 884887Schin #define M_BRACE 1 /* ${var} */ 894887Schin #define M_TREE 2 /* ${var.} */ 904887Schin #define M_SIZE 3 /* ${#var} */ 914887Schin #define M_VNAME 4 /* ${!var} */ 924887Schin #define M_SUBNAME 5 /* ${!var[sub]} */ 934887Schin #define M_NAMESCAN 6 /* ${!var*} */ 944887Schin #define M_NAMECOUNT 7 /* ${#var*} */ 954887Schin #define M_TYPE 8 /* ${@var} */ 964887Schin 974887Schin static int substring(const char*, const char*, int[], int); 984887Schin static void copyto(Mac_t*, int, int); 998462SApril.Chin@Sun.COM static void comsubst(Mac_t*, Shnode_t*, int); 1004887Schin static int varsub(Mac_t*); 1014887Schin static void mac_copy(Mac_t*,const char*, int); 1028462SApril.Chin@Sun.COM static void tilde_expand2(Shell_t*,int); 1038462SApril.Chin@Sun.COM static char *sh_tilde(Shell_t*,const char*); 1048462SApril.Chin@Sun.COM static char *special(Shell_t *,int); 1054887Schin static void endfield(Mac_t*,int); 1064887Schin static void mac_error(Namval_t*); 1074887Schin static char *mac_getstring(char*); 1084887Schin static int charlen(const char*,int); 1094887Schin #if SHOPT_MULTIBYTE 1104887Schin static char *lastchar(const char*,const char*); 1114887Schin #endif /* SHOPT_MULTIBYTE */ 1124887Schin 1134887Schin void *sh_macopen(Shell_t *shp) 1144887Schin { 1154887Schin void *addr = newof(0,Mac_t,1,0); 1164887Schin Mac_t *mp = (Mac_t*)addr; 1174887Schin mp->shp = shp; 1184887Schin return(addr); 1194887Schin } 1204887Schin 1214887Schin /* 1224887Schin * perform only parameter substitution and catch failures 1234887Schin */ 1248462SApril.Chin@Sun.COM char *sh_mactry(Shell_t *shp,register char *string) 1254887Schin { 1264887Schin if(string) 1274887Schin { 1284887Schin int jmp_val; 1298462SApril.Chin@Sun.COM int savexit = shp->savexit; 1304887Schin struct checkpt buff; 1314887Schin sh_pushcontext(&buff,SH_JMPSUB); 1324887Schin jmp_val = sigsetjmp(buff.buff,0); 1334887Schin if(jmp_val == 0) 1348462SApril.Chin@Sun.COM string = sh_mactrim(shp,string,0); 1354887Schin sh_popcontext(&buff); 1368462SApril.Chin@Sun.COM shp->savexit = savexit; 1374887Schin return(string); 1384887Schin } 1394887Schin return(""); 1404887Schin } 1414887Schin 1424887Schin /* 1434887Schin * Perform parameter expansion, command substitution, and arithmetic 1444887Schin * expansion on <str>. 1454887Schin * If <mode> greater than 1 file expansion is performed if the result 1464887Schin * yields a single pathname. 1474887Schin * If <mode> negative, than expansion rules for assignment are applied. 1484887Schin */ 1498462SApril.Chin@Sun.COM char *sh_mactrim(Shell_t *shp, char *str, register int mode) 1504887Schin { 1518462SApril.Chin@Sun.COM register Mac_t *mp = (Mac_t*)shp->mac_context; 1528462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 1538462SApril.Chin@Sun.COM Mac_t savemac; 1544887Schin savemac = *mp; 1558462SApril.Chin@Sun.COM stkseek(stkp,0); 1564887Schin mp->arith = (mode==3); 1574887Schin mp->let = 0; 1588462SApril.Chin@Sun.COM shp->argaddr = 0; 1594887Schin mp->pattern = (mode==1||mode==2); 1604887Schin mp->patfound = 0; 1618462SApril.Chin@Sun.COM mp->assign = 0; 1628462SApril.Chin@Sun.COM if(mode<0) 1638462SApril.Chin@Sun.COM mp->assign = -mode; 1644887Schin mp->quoted = mp->lit = mp->split = mp->quote = 0; 1654887Schin mp->sp = 0; 1668462SApril.Chin@Sun.COM if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD))) 1674887Schin mp->ifs = *mp->ifsp; 1684887Schin else 1694887Schin mp->ifs = ' '; 1708462SApril.Chin@Sun.COM stkseek(stkp,0); 1714887Schin fcsopen(str); 1724887Schin copyto(mp,0,mp->arith); 1738462SApril.Chin@Sun.COM str = stkfreeze(stkp,1); 1744887Schin if(mode==2) 1754887Schin { 1764887Schin /* expand only if unique */ 1774887Schin struct argnod *arglist=0; 1784887Schin if((mode=path_expand(str,&arglist))==1) 1794887Schin str = arglist->argval; 1804887Schin else if(mode>1) 1814887Schin errormsg(SH_DICT,ERROR_exit(1),e_ambiguous,str); 1824887Schin sh_trim(str); 1834887Schin } 1844887Schin *mp = savemac; 1854887Schin return(str); 1864887Schin } 1874887Schin 1884887Schin /* 1894887Schin * Perform all the expansions on the argument <argp> 1904887Schin */ 1918462SApril.Chin@Sun.COM int sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag) 1924887Schin { 1938462SApril.Chin@Sun.COM register int flags = argp->argflag; 1948462SApril.Chin@Sun.COM register char *str = argp->argval; 1958462SApril.Chin@Sun.COM register Mac_t *mp = (Mac_t*)shp->mac_context; 1968462SApril.Chin@Sun.COM char **saveargaddr = shp->argaddr; 1978462SApril.Chin@Sun.COM Mac_t savemac; 1988462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 1994887Schin savemac = *mp; 2004887Schin mp->sp = 0; 2018462SApril.Chin@Sun.COM if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD))) 2024887Schin mp->ifs = *mp->ifsp; 2034887Schin else 2044887Schin mp->ifs = ' '; 2058462SApril.Chin@Sun.COM if((flag&ARG_OPTIMIZE) && !shp->indebug) 2068462SApril.Chin@Sun.COM shp->argaddr = (char**)&argp->argchn.ap; 2074887Schin else 2088462SApril.Chin@Sun.COM shp->argaddr = 0; 2094887Schin mp->arghead = arghead; 2104887Schin mp->quoted = mp->lit = mp->quote = 0; 2114887Schin mp->arith = ((flag&ARG_ARITH)!=0); 2124887Schin mp->let = ((flag&ARG_LET)!=0); 2134887Schin mp->split = !(flag&ARG_ASSIGN); 2144887Schin mp->assign = !mp->split; 2154887Schin mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB); 2168462SApril.Chin@Sun.COM mp->arrayok = mp->arith || (flag&ARG_ARRAYOK); 2174887Schin str = argp->argval; 2184887Schin fcsopen(str); 2194887Schin mp->fields = 0; 2204887Schin if(!arghead) 2214887Schin { 2224887Schin mp->split = 0; 2234887Schin mp->pattern = ((flag&ARG_EXP)!=0); 2248462SApril.Chin@Sun.COM stkseek(stkp,0); 2254887Schin } 2264887Schin else 2274887Schin { 2288462SApril.Chin@Sun.COM stkseek(stkp,ARGVAL); 2298462SApril.Chin@Sun.COM *stkptr(stkp,ARGVAL-1) = 0; 2304887Schin } 2314887Schin mp->patfound = 0; 2328462SApril.Chin@Sun.COM if(mp->pattern) 2338462SApril.Chin@Sun.COM mp->arrayok = 0; 2344887Schin copyto(mp,0,mp->arith); 2354887Schin if(!arghead) 2364887Schin { 2378462SApril.Chin@Sun.COM argp->argchn.cp = stkfreeze(stkp,1); 2388462SApril.Chin@Sun.COM if(shp->argaddr) 2394887Schin argp->argflag |= ARG_MAKE; 2404887Schin } 2414887Schin else 2424887Schin { 2434887Schin endfield(mp,mp->quoted); 2444887Schin flags = mp->fields; 2458462SApril.Chin@Sun.COM if(flags==1 && shp->argaddr) 2464887Schin argp->argchn.ap = *arghead; 2474887Schin } 2488462SApril.Chin@Sun.COM shp->argaddr = saveargaddr; 2494887Schin *mp = savemac; 2504887Schin return(flags); 2514887Schin } 2524887Schin 2534887Schin /* 2544887Schin * Expand here document which is stored in <infile> or <string> 2554887Schin * The result is written to <outfile> 2564887Schin */ 2578462SApril.Chin@Sun.COM void sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string) 2584887Schin { 2594887Schin register int c,n; 2604887Schin register const char *state = sh_lexstates[ST_QUOTE]; 2614887Schin register char *cp; 2628462SApril.Chin@Sun.COM register Mac_t *mp = (Mac_t*)shp->mac_context; 2638462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)mp->shp->lex_context; 2644887Schin Fcin_t save; 2654887Schin Mac_t savemac; 2668462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 2674887Schin savemac = *mp; 2688462SApril.Chin@Sun.COM stkseek(stkp,0); 2698462SApril.Chin@Sun.COM shp->argaddr = 0; 2704887Schin mp->sp = outfile; 2714887Schin mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0; 2724887Schin mp->quote = 1; 2738462SApril.Chin@Sun.COM mp->ifsp = nv_getval(sh_scoped(shp,IFSNOD)); 2744887Schin mp->ifs = ' '; 2754887Schin fcsave(&save); 2764887Schin if(infile) 2774887Schin fcfopen(infile); 2784887Schin else 2794887Schin fcsopen(string); 2808462SApril.Chin@Sun.COM fcnotify(0,lp); 2814887Schin cp = fcseek(0); 2824887Schin while(1) 2834887Schin { 2844887Schin #if SHOPT_MULTIBYTE 2854887Schin if(mbwide()) 2864887Schin { 2874887Schin do 2884887Schin { 2894887Schin ssize_t len; 2904887Schin switch(len = mbsize(cp)) 2914887Schin { 2924887Schin case -1: /* illegal multi-byte char */ 2934887Schin case 0: 2944887Schin case 1: 2954887Schin n=state[*(unsigned char*)cp++]; 2964887Schin break; 2974887Schin default: 2988462SApril.Chin@Sun.COM /* use state of alpha character */ 2994887Schin n=state['a']; 3004887Schin cp += len; 3014887Schin } 3024887Schin } 3034887Schin while(n == 0); 3044887Schin } 3054887Schin else 3064887Schin #endif /* SHOPT_MULTIBYTE */ 3074887Schin while((n=state[*(unsigned char*)cp++])==0); 3084887Schin if(n==S_NL || n==S_QUOTE || n==S_RBRA) 3094887Schin continue; 3104887Schin if(c=(cp-1)-fcseek(0)) 3114887Schin sfwrite(outfile,fcseek(0),c); 3124887Schin cp = fcseek(c+1); 3134887Schin switch(n) 3144887Schin { 3154887Schin case S_EOF: 3164887Schin if((n=fcfill()) <=0) 3174887Schin { 3184887Schin /* ignore 0 byte when reading from file */ 3194887Schin if(n==0 && fcfile()) 3204887Schin continue; 3214887Schin fcrestore(&save); 3224887Schin *mp = savemac; 3234887Schin return; 3244887Schin } 3254887Schin cp = fcseek(-1); 3264887Schin continue; 3274887Schin case S_ESC: 3284887Schin fcgetc(c); 3294887Schin cp=fcseek(-1); 3304887Schin if(c>0) 3314887Schin cp++; 3324887Schin if(!isescchar(state[c])) 3334887Schin sfputc(outfile,ESCAPE); 3344887Schin continue; 3354887Schin case S_GRAVE: 3368462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,0); 3374887Schin break; 3384887Schin case S_DOL: 3394887Schin c = fcget(); 3404887Schin if(c=='.') 3414887Schin goto regular; 3424887Schin again: 3434887Schin switch(n=sh_lexstates[ST_DOL][c]) 3444887Schin { 3454887Schin case S_ALP: case S_SPC1: case S_SPC2: 3464887Schin case S_DIG: case S_LBRA: 3474887Schin { 3484887Schin Fcin_t save2; 3498462SApril.Chin@Sun.COM int offset = stktell(stkp); 3504887Schin int offset2; 3518462SApril.Chin@Sun.COM sfputc(stkp,c); 3524887Schin if(n==S_LBRA) 3538462SApril.Chin@Sun.COM { 3548462SApril.Chin@Sun.COM c = fcget(); 3558462SApril.Chin@Sun.COM fcseek(-1); 3568462SApril.Chin@Sun.COM if(sh_lexstates[ST_NORM][c]==S_BREAK) 3578462SApril.Chin@Sun.COM { 3588462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,2); 3598462SApril.Chin@Sun.COM break; 3608462SApril.Chin@Sun.COM } 3618462SApril.Chin@Sun.COM sh_lexskip(lp,RBRACE,1,ST_BRACE); 3628462SApril.Chin@Sun.COM } 3634887Schin else if(n==S_ALP) 3644887Schin { 3654887Schin while(fcgetc(c),isaname(c)) 3668462SApril.Chin@Sun.COM sfputc(stkp,c); 3674887Schin fcseek(-1); 3684887Schin } 3698462SApril.Chin@Sun.COM sfputc(stkp,0); 3708462SApril.Chin@Sun.COM offset2 = stktell(stkp); 3714887Schin fcsave(&save2); 3728462SApril.Chin@Sun.COM fcsopen(stkptr(stkp,offset)); 3734887Schin varsub(mp); 3748462SApril.Chin@Sun.COM if(c=stktell(stkp)-offset2) 3758462SApril.Chin@Sun.COM sfwrite(outfile,(char*)stkptr(stkp,offset2),c); 3764887Schin fcrestore(&save2); 3778462SApril.Chin@Sun.COM stkseek(stkp,offset); 3784887Schin break; 3794887Schin } 3804887Schin case S_PAR: 3818462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,1); 3824887Schin break; 3834887Schin case S_EOF: 3844887Schin if((c=fcfill()) > 0) 3854887Schin goto again; 3864887Schin /* FALL THRU */ 3874887Schin default: 3884887Schin regular: 3894887Schin sfputc(outfile,'$'); 3904887Schin fcseek(-1); 3914887Schin break; 3924887Schin } 3934887Schin } 3944887Schin cp = fcseek(0); 3954887Schin } 3964887Schin } 3974887Schin 3984887Schin /* 3994887Schin * expand argument but do not trim pattern characters 4004887Schin */ 4018462SApril.Chin@Sun.COM char *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags) 4024887Schin { 4034887Schin register char *sp = arg->argval; 4044887Schin if((arg->argflag&ARG_RAW)) 4054887Schin return(sp); 4068462SApril.Chin@Sun.COM sh_stats(STAT_ARGEXPAND); 4074887Schin if(flags&ARG_OPTIMIZE) 4084887Schin arg->argchn.ap=0; 4094887Schin if(!(sp=arg->argchn.cp)) 4104887Schin { 4118462SApril.Chin@Sun.COM sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK); 4124887Schin sp = arg->argchn.cp; 4134887Schin if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE)) 4144887Schin arg->argchn.cp = 0; 4154887Schin arg->argflag &= ~ARG_MAKE; 4164887Schin } 4174887Schin else 4188462SApril.Chin@Sun.COM sh_stats(STAT_ARGHITS); 4194887Schin return(sp); 4204887Schin } 4214887Schin 4224887Schin /* 4234887Schin * Process the characters up to <endch> or end of input string 4244887Schin */ 4254887Schin static void copyto(register Mac_t *mp,int endch, int newquote) 4264887Schin { 4274887Schin register int c,n; 4284887Schin register const char *state = sh_lexstates[ST_MACRO]; 4294887Schin register char *cp,*first; 4308462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)mp->shp->lex_context; 4314887Schin int tilde = -1; 4324887Schin int oldquote = mp->quote; 4334887Schin int ansi_c = 0; 4344887Schin int paren = 0; 4354887Schin int ere = 0; 4364887Schin int brace = 0; 4374887Schin Sfio_t *sp = mp->sp; 4388462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 4394887Schin mp->sp = NIL(Sfio_t*); 4404887Schin mp->quote = newquote; 4414887Schin first = cp = fcseek(0); 442*8900SCasper.Dik@Sun.COM if(!mp->quote && *cp=='~' && cp[1]!=LPAREN) 4438462SApril.Chin@Sun.COM tilde = stktell(stkp); 4444887Schin /* handle // operator specially */ 4454887Schin if(mp->pattern==2 && *cp=='/') 4464887Schin cp++; 4474887Schin while(1) 4484887Schin { 4494887Schin #if SHOPT_MULTIBYTE 4504887Schin if(mbwide()) 4514887Schin { 4524887Schin ssize_t len; 4534887Schin do 4544887Schin { 4554887Schin switch(len = mbsize(cp)) 4564887Schin { 4574887Schin case -1: /* illegal multi-byte char */ 4584887Schin case 0: 4594887Schin len = 1; 4604887Schin case 1: 4614887Schin n = state[*(unsigned char*)cp++]; 4624887Schin break; 4634887Schin default: 4644887Schin /* treat as if alpha */ 4654887Schin cp += len; 4664887Schin n=state['a']; 4674887Schin } 4684887Schin } 4694887Schin while(n == 0); 4704887Schin c = (cp-len) - first; 4714887Schin } 4724887Schin else 4734887Schin #endif /* SHOPT_MULTIBYTE */ 4744887Schin { 4754887Schin while((n=state[*(unsigned char*)cp++])==0); 4764887Schin c = (cp-1) - first; 4774887Schin } 4784887Schin switch(n) 4794887Schin { 4804887Schin case S_ESC: 4814887Schin if(ansi_c) 4824887Schin { 4834887Schin /* process ANSI-C escape character */ 4844887Schin char *addr= --cp; 4854887Schin if(c) 4868462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 4874887Schin c = chresc(cp,&addr); 4884887Schin cp = addr; 4894887Schin first = fcseek(cp-first); 4904887Schin #if SHOPT_MULTIBYTE 4914887Schin if(c > UCHAR_MAX && mbwide()) 4924887Schin { 4934887Schin int i; 4944887Schin unsigned char mb[8]; 4954887Schin 4964887Schin n = wctomb((char*)mb, c); 4974887Schin for(i=0;i<n;i++) 4988462SApril.Chin@Sun.COM sfputc(stkp,mb[i]); 4994887Schin } 5004887Schin else 5014887Schin #endif /* SHOPT_MULTIBYTE */ 5028462SApril.Chin@Sun.COM sfputc(stkp,c); 5034887Schin if(c==ESCAPE && mp->pattern) 5048462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 5054887Schin break; 5064887Schin } 5074887Schin else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.')) 5084887Schin break; 5094887Schin else if(mp->split && endch && !mp->quote && !mp->lit) 5104887Schin { 5114887Schin if(c) 5124887Schin mac_copy(mp,first,c); 5134887Schin cp = fcseek(c+2); 5144887Schin if(c= cp[-1]) 5154887Schin { 5168462SApril.Chin@Sun.COM sfputc(stkp,c); 5174887Schin if(c==ESCAPE) 5188462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 5194887Schin } 5204887Schin else 5214887Schin cp--; 5224887Schin first = cp; 5234887Schin break; 5244887Schin } 5254887Schin n = state[*(unsigned char*)cp]; 5264887Schin if(n==S_ENDCH && *cp!=endch) 5274887Schin n = S_PAT; 5284887Schin if(mp->pattern) 5294887Schin { 5304887Schin /* preserve \digit for pattern matching */ 5314887Schin /* also \alpha for extended patterns */ 5324887Schin if(!mp->lit && !mp->quote && (n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP))) 5334887Schin break; 5344887Schin /* followed by file expansion */ 5354887Schin if(!mp->lit && (n==S_ESC || (!mp->quote && 5364887Schin (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-')))) 5374887Schin { 5384887Schin cp += (n!=S_EOF); 5398462SApril.Chin@Sun.COM if(ere && n==S_ESC && *cp =='\\' && cp[1]=='$') 5408462SApril.Chin@Sun.COM { 5418462SApril.Chin@Sun.COM /* convert \\\$ into \$' */ 5428462SApril.Chin@Sun.COM sfwrite(stkp,first,c+1); 5438462SApril.Chin@Sun.COM cp = first = fcseek(c+3); 5448462SApril.Chin@Sun.COM } 5454887Schin break; 5464887Schin } 5478462SApril.Chin@Sun.COM if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH))) 5484887Schin { 5494887Schin /* add \ for file expansion */ 5508462SApril.Chin@Sun.COM sfwrite(stkp,first,c+1); 5514887Schin first = fcseek(c); 5524887Schin break; 5534887Schin } 5544887Schin } 5554887Schin if(mp->lit) 5564887Schin break; 5574887Schin if(!mp->quote || isqescchar(n) || n==S_ENDCH) 5584887Schin { 5594887Schin /* eliminate \ */ 5604887Schin if(c) 5618462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 5624887Schin /* check new-line joining */ 5634887Schin first = fcseek(c+1); 5644887Schin } 5654887Schin cp += (n!=S_EOF); 5664887Schin break; 5674887Schin case S_GRAVE: case S_DOL: 5684887Schin if(mp->lit) 5694887Schin break; 5704887Schin if(c) 5714887Schin { 5724887Schin if(mp->split && !mp->quote && endch) 5734887Schin mac_copy(mp,first,c); 5744887Schin else 5758462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 5764887Schin } 5774887Schin first = fcseek(c+1); 5784887Schin c = mp->pattern; 5794887Schin if(n==S_GRAVE) 5808462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,0); 5814887Schin else if((n= *cp)==0 || !varsub(mp)) 5824887Schin { 5834887Schin if(n=='\'' && !mp->quote) 5844887Schin ansi_c = 1; 5854887Schin else if(mp->quote || n!='"') 5868462SApril.Chin@Sun.COM sfputc(stkp,'$'); 5874887Schin } 5884887Schin cp = first = fcseek(0); 5894887Schin if(*cp) 5904887Schin mp->pattern = c; 5914887Schin break; 5924887Schin case S_ENDCH: 5934887Schin if((mp->lit || cp[-1]!=endch || mp->quote!=newquote)) 5944887Schin goto pattern; 5954887Schin if(endch==RBRACE && *cp==LPAREN && mp->pattern && brace) 5964887Schin goto pattern; 5974887Schin case S_EOF: 5984887Schin if(c) 5994887Schin { 6004887Schin if(mp->split && !mp->quote && !mp->lit && endch) 6014887Schin mac_copy(mp,first,c); 6024887Schin else 6038462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 6044887Schin } 6054887Schin c += (n!=S_EOF); 6064887Schin first = fcseek(c); 6074887Schin if(tilde>=0) 6088462SApril.Chin@Sun.COM tilde_expand2(mp->shp,tilde); 6094887Schin goto done; 6104887Schin case S_QUOTE: 6114887Schin if(mp->lit || mp->arith) 6124887Schin break; 6134887Schin case S_LIT: 6144887Schin if(mp->arith) 6154887Schin { 6164887Schin if((*cp=='`' || *cp=='[') && cp[1]=='\'') 6174887Schin cp +=2; 6184887Schin break; 6194887Schin } 6204887Schin if(n==S_LIT && mp->quote) 6214887Schin break; 6224887Schin if(c) 6234887Schin { 6244887Schin if(mp->split && endch && !mp->quote && !mp->lit) 6254887Schin mac_copy(mp,first,c); 6264887Schin else 6278462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 6284887Schin } 6294887Schin first = fcseek(c+1); 6304887Schin if(n==S_LIT) 6314887Schin { 6324887Schin if(mp->quote) 6334887Schin continue; 6344887Schin if(mp->lit) 6354887Schin mp->lit = ansi_c = 0; 6364887Schin else 6374887Schin mp->lit = 1; 6384887Schin } 6394887Schin else 6404887Schin mp->quote = !mp->quote; 6414887Schin mp->quoted++; 6424887Schin break; 6434887Schin case S_BRACT: 6448462SApril.Chin@Sun.COM if(mp->arith || (((mp->assign&1) || endch==RBRACT) && 6454887Schin !(mp->quote || mp->lit))) 6464887Schin { 6474887Schin int offset=0,oldpat = mp->pattern; 6488462SApril.Chin@Sun.COM int oldarith = mp->arith, oldsub=mp->subcopy; 6498462SApril.Chin@Sun.COM sfwrite(stkp,first,++c); 6508462SApril.Chin@Sun.COM if((mp->assign&1) && first[c-2]=='.') 6518462SApril.Chin@Sun.COM offset = stktell(stkp); 6524887Schin first = fcseek(c); 6534887Schin mp->pattern = 4; 6544887Schin mp->arith = 0; 6558462SApril.Chin@Sun.COM mp->subcopy = 0; 6564887Schin copyto(mp,RBRACT,0); 6578462SApril.Chin@Sun.COM mp->subcopy = oldsub; 6584887Schin mp->arith = oldarith; 6594887Schin mp->pattern = oldpat; 6608462SApril.Chin@Sun.COM sfputc(stkp,RBRACT); 6614887Schin if(offset) 6624887Schin { 6638462SApril.Chin@Sun.COM cp = stkptr(stkp,stktell(stkp)); 6648462SApril.Chin@Sun.COM if(sh_checkid(stkptr(stkp,offset),cp)!=cp) 6658462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-2); 6664887Schin } 6674887Schin cp = first = fcseek(0); 6684887Schin break; 6694887Schin } 6704887Schin case S_PAT: 6714887Schin if(mp->pattern && !(mp->quote || mp->lit)) 6724887Schin { 6734887Schin mp->patfound = mp->pattern; 6744887Schin if((n=cp[-1])==LPAREN) 6754887Schin { 6764887Schin paren++; 6774887Schin if((cp-first)>1 && cp[-2]=='~') 6784887Schin { 6794887Schin char *p = cp; 6804887Schin while((c=mbchar(p)) && c!=RPAREN && c!='E'); 6814887Schin ere = c=='E'; 6824887Schin } 6834887Schin } 6844887Schin else if(n==RPAREN) 6854887Schin --paren; 6864887Schin } 6874887Schin goto pattern; 6888462SApril.Chin@Sun.COM case S_COM: 6898462SApril.Chin@Sun.COM if(mp->pattern==4 && (mp->quote || mp->lit)) 6908462SApril.Chin@Sun.COM { 6918462SApril.Chin@Sun.COM if(c) 6928462SApril.Chin@Sun.COM { 6938462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 6948462SApril.Chin@Sun.COM first = fcseek(c); 6958462SApril.Chin@Sun.COM } 6968462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 6978462SApril.Chin@Sun.COM } 6988462SApril.Chin@Sun.COM break; 6994887Schin case S_BRACE: 7004887Schin if(!(mp->quote || mp->lit)) 7014887Schin { 7024887Schin mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND); 7034887Schin brace = 1; 7044887Schin } 7054887Schin pattern: 7064887Schin if(!mp->pattern || !(mp->quote || mp->lit)) 7074887Schin { 7084887Schin /* mark beginning of {a,b} */ 7094887Schin if(n==S_BRACE && endch==0 && mp->pattern) 7104887Schin mp->pattern=4; 7114887Schin if(n==S_SLASH && mp->pattern==2) 7124887Schin mp->pattern=3; 7134887Schin break; 7144887Schin } 7154887Schin if(mp->pattern==3) 7164887Schin break; 7174887Schin if(c) 7188462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 7194887Schin first = fcseek(c); 7208462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 7214887Schin break; 7224887Schin case S_EQ: 7234887Schin if(mp->assign==1) 7244887Schin { 7254887Schin if(*cp=='~' && !endch && !mp->quote && !mp->lit) 7268462SApril.Chin@Sun.COM tilde = stktell(stkp)+(c+1); 7274887Schin mp->assign = 2; 7284887Schin } 7294887Schin break; 7304887Schin case S_SLASH: 7314887Schin case S_COLON: 7324887Schin if(tilde >=0) 7334887Schin { 7344887Schin if(c) 7358462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 7364887Schin first = fcseek(c); 7378462SApril.Chin@Sun.COM tilde_expand2(mp->shp,tilde); 7384887Schin tilde = -1; 7394887Schin c=0; 7404887Schin } 7414887Schin if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit) 7428462SApril.Chin@Sun.COM tilde = stktell(stkp)+(c+1); 7434887Schin else if(n==S_SLASH && mp->pattern==2) 7444887Schin #if 0 7454887Schin goto pattern; 7464887Schin #else 7474887Schin { 7484887Schin if(mp->quote || mp->lit) 7494887Schin goto pattern; 7508462SApril.Chin@Sun.COM sfwrite(stkp,first,c+1); 7514887Schin first = fcseek(c+1); 7528462SApril.Chin@Sun.COM c = stktell(stkp); 7538462SApril.Chin@Sun.COM sh_lexskip(lp,RBRACE,0,ST_NESTED); 7548462SApril.Chin@Sun.COM stkseek(stkp,c); 7554887Schin cp = fcseek(-1); 7568462SApril.Chin@Sun.COM sfwrite(stkp,first,cp-first); 7574887Schin first=cp; 7584887Schin } 7594887Schin #endif 7604887Schin break; 7618462SApril.Chin@Sun.COM case S_DOT: 7628462SApril.Chin@Sun.COM if(*cp=='.' && mp->subcopy==1) 7638462SApril.Chin@Sun.COM { 7648462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 7658462SApril.Chin@Sun.COM sfputc(stkp,0); 7668462SApril.Chin@Sun.COM mp->dotdot = stktell(stkp); 7678462SApril.Chin@Sun.COM cp = first = fcseek(c+2); 7688462SApril.Chin@Sun.COM } 7698462SApril.Chin@Sun.COM break; 7704887Schin } 7714887Schin } 7724887Schin done: 7734887Schin mp->sp = sp; 7744887Schin mp->quote = oldquote; 7754887Schin } 7764887Schin 7774887Schin /* 7784887Schin * copy <str> to stack performing sub-expression substitutions 7794887Schin */ 7804887Schin static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize) 7814887Schin { 7828462SApril.Chin@Sun.COM register int c,n; 7834887Schin register char *first=fcseek(0); 7848462SApril.Chin@Sun.COM char *ptr; 7858462SApril.Chin@Sun.COM Mac_t savemac; 7868462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 7878462SApril.Chin@Sun.COM n = stktell(stkp); 7884887Schin savemac = *mp; 7894887Schin mp->pattern = 3; 7904887Schin mp->split = 0; 7914887Schin fcsopen(cp); 7924887Schin copyto(mp,0,0); 7938462SApril.Chin@Sun.COM sfputc(stkp,0); 7948462SApril.Chin@Sun.COM ptr = cp = strdup(stkptr(stkp,n)); 7958462SApril.Chin@Sun.COM stkseek(stkp,n); 7964887Schin *mp = savemac; 7974887Schin fcsopen(first); 7984887Schin first = cp; 7994887Schin while(1) 8004887Schin { 8014887Schin while((c= *cp++) && c!=ESCAPE); 8024887Schin if(c==0) 8034887Schin break; 8044887Schin if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize)) 8054887Schin { 8064887Schin c = cp-first-2; 8074887Schin if(c) 8084887Schin mac_copy(mp,first,c); 8094887Schin first=cp; 8104887Schin if(n=='\\' || n==RBRACE) 8114887Schin { 8124887Schin first--; 8134887Schin continue; 8144887Schin } 8154887Schin if((c=subexp[2*n])>=0) 8164887Schin { 8174887Schin if((n=subexp[2*n+1]-c)>0) 8184887Schin mac_copy(mp,str+c,n); 8194887Schin } 8204887Schin } 8214887Schin else if(n==0) 8224887Schin break; 8234887Schin } 8244887Schin if(n=cp-first-1) 8254887Schin mac_copy(mp,first,n); 8264887Schin free(ptr); 8274887Schin } 8284887Schin 8294887Schin #if SHOPT_FILESCAN 8304887Schin #define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0])) 8314887Schin #define MAX_ARGN (32*1024) 8324887Schin 8334887Schin /* 8344887Schin * compute the arguments $1 ... $n and $# from the current line as needed 8354887Schin * save line offsets in the offsets array. 8364887Schin */ 8374887Schin static char *getdolarg(Shell_t *shp, int n, int *size) 8384887Schin { 8394887Schin register int c=S_DELIM, d=shp->ifstable['\\']; 8404887Schin register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line; 8414887Schin register int m=shp->offsets[0],delim=0; 8424887Schin if(m==0) 8434887Schin return(0); 8444887Schin if(m<0) 8454887Schin m = 0; 8464887Schin else if(n<=m) 8474887Schin m = n-1; 8484887Schin else 8494887Schin m--; 8504887Schin if(m >= MAX_OFFSETS-1) 8514887Schin m = MAX_OFFSETS-2; 8524887Schin cp += shp->offsets[m+1]; 8534887Schin n -= m; 8544887Schin shp->ifstable['\\'] = 0; 8554887Schin shp->ifstable[0] = S_EOF; 8564887Schin while(1) 8574887Schin { 8584887Schin if(c==S_DELIM) 8594887Schin while(shp->ifstable[*cp++]==S_SPACE); 8604887Schin first = --cp; 8614887Schin if(++m < MAX_OFFSETS) 8624887Schin shp->offsets[m] = (first-(unsigned char*)shp->cur_line); 8634887Schin while((c=shp->ifstable[*cp++])==0); 8644887Schin last = cp-1; 8654887Schin if(c==S_SPACE) 8664887Schin while((c=shp->ifstable[*cp++])==S_SPACE); 8674887Schin if(--n==0 || c==S_EOF) 8684887Schin { 8694887Schin if(last==first && c==S_EOF && (!delim || (m>1))) 8704887Schin { 8714887Schin n++; 8724887Schin m--; 8734887Schin } 8744887Schin break; 8754887Schin } 8764887Schin delim = (c==S_DELIM); 8774887Schin } 8784887Schin shp->ifstable['\\'] = d; 8794887Schin if(m > shp->offsets[0]) 8804887Schin shp->offsets[0] = m; 8814887Schin if(n) 8824887Schin first = last = 0; 8834887Schin if(size) 8844887Schin *size = last-first; 8854887Schin return((char*)first); 8864887Schin } 8874887Schin #endif /* SHOPT_FILESCAN */ 8884887Schin 8894887Schin /* 8904887Schin * get the prefix after name reference resolution 8914887Schin */ 8928462SApril.Chin@Sun.COM static char *prefix(Shell_t *shp, char *id) 8934887Schin { 8944887Schin Namval_t *np; 8954887Schin register char *cp = strchr(id,'.'); 8964887Schin if(cp) 8974887Schin { 8984887Schin *cp = 0; 8998462SApril.Chin@Sun.COM np = nv_search(id, shp->var_tree,0); 9004887Schin *cp = '.'; 9014887Schin if(isastchar(cp[1])) 9024887Schin cp[1] = 0; 9034887Schin if(np && nv_isref(np)) 9044887Schin { 9054887Schin int n; 9064887Schin char *sp; 9078462SApril.Chin@Sun.COM shp->argaddr = 0; 9084887Schin while(nv_isref(np)) 9094887Schin np = nv_refnode(np); 9104887Schin id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+1); 9114887Schin strcpy(&id[n],cp); 9124887Schin memcpy(id,sp,n); 9134887Schin return(id); 9144887Schin } 9154887Schin } 9164887Schin return(strdup(id)); 9174887Schin } 9184887Schin 9194887Schin /* 9204887Schin * copy to ']' onto the stack and return offset to it 9214887Schin */ 9224887Schin static int subcopy(Mac_t *mp, int flag) 9234887Schin { 9244887Schin int split = mp->split; 9254887Schin int xpattern = mp->pattern; 9268462SApril.Chin@Sun.COM int loc = stktell(mp->shp->stk); 9274887Schin int xarith = mp->arith; 9288462SApril.Chin@Sun.COM int arrayok = mp->arrayok; 9294887Schin mp->split = 0; 9304887Schin mp->arith = 0; 9314887Schin mp->pattern = flag?4:0; 9328462SApril.Chin@Sun.COM mp->arrayok=1; 9338462SApril.Chin@Sun.COM mp->subcopy++; 9348462SApril.Chin@Sun.COM mp->dotdot = 0; 9354887Schin copyto(mp,RBRACT,0); 9368462SApril.Chin@Sun.COM mp->subcopy = 0; 9374887Schin mp->pattern = xpattern; 9384887Schin mp->split = split; 9394887Schin mp->arith = xarith; 9408462SApril.Chin@Sun.COM mp->arrayok = arrayok; 9414887Schin return(loc); 9424887Schin } 9434887Schin 9448462SApril.Chin@Sun.COM /* 9458462SApril.Chin@Sun.COM * if name is a discipline function, run the function and put the results 9468462SApril.Chin@Sun.COM * on the stack so that ${x.foo} behaves like ${ x.foo;} 9478462SApril.Chin@Sun.COM */ 9488462SApril.Chin@Sun.COM int sh_macfun(Shell_t *shp, const char *name, int offset) 9498462SApril.Chin@Sun.COM { 9508462SApril.Chin@Sun.COM Namval_t *np, *nq; 9518462SApril.Chin@Sun.COM np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0); 9528462SApril.Chin@Sun.COM if(np) 9538462SApril.Chin@Sun.COM { 9548462SApril.Chin@Sun.COM /* treat ${x.foo} as ${x.foo;} */ 9558462SApril.Chin@Sun.COM Shnode_t *tp; 9568462SApril.Chin@Sun.COM char buff[sizeof(struct dolnod)+sizeof(char*)]; 9578462SApril.Chin@Sun.COM struct comnod node; 9588462SApril.Chin@Sun.COM struct dolnod *dp = (struct dolnod*)buff; 9598462SApril.Chin@Sun.COM memset(&node,0,sizeof(node)); 9608462SApril.Chin@Sun.COM memset(&buff,0,sizeof(buff)); 9618462SApril.Chin@Sun.COM tp = (Shnode_t*)&node; 9628462SApril.Chin@Sun.COM tp->com.comarg = (struct argnod*)dp; 9638462SApril.Chin@Sun.COM tp->com.comline = shp->inlineno; 9648462SApril.Chin@Sun.COM dp->dolnum = 2; 9658462SApril.Chin@Sun.COM dp->dolval[0] = strdup(name); 9668462SApril.Chin@Sun.COM stkseek(shp->stk,offset); 9678462SApril.Chin@Sun.COM comsubst((Mac_t*)shp->mac_context,tp,2); 9688462SApril.Chin@Sun.COM free(dp->dolval[0]); 9698462SApril.Chin@Sun.COM return(1); 9708462SApril.Chin@Sun.COM } 9718462SApril.Chin@Sun.COM return(0); 9728462SApril.Chin@Sun.COM } 9738462SApril.Chin@Sun.COM 9744887Schin static int namecount(Mac_t *mp,const char *prefix) 9754887Schin { 9764887Schin int count = 0; 9778462SApril.Chin@Sun.COM mp->nvwalk = nv_diropen((Namval_t*)0,prefix); 9784887Schin while(nv_dirnext(mp->nvwalk)) 9794887Schin count++; 9804887Schin nv_dirclose(mp->nvwalk); 9814887Schin return(count); 9824887Schin } 9834887Schin 9844887Schin static char *nextname(Mac_t *mp,const char *prefix, int len) 9854887Schin { 9864887Schin char *cp; 9874887Schin if(len==0) 9884887Schin { 9898462SApril.Chin@Sun.COM mp->nvwalk = nv_diropen((Namval_t*)0,prefix); 9904887Schin return((char*)mp->nvwalk); 9914887Schin } 9924887Schin if(!(cp=nv_dirnext(mp->nvwalk))) 9934887Schin nv_dirclose(mp->nvwalk); 9944887Schin return(cp); 9954887Schin } 9964887Schin 9974887Schin /* 9984887Schin * This routine handles $param, ${parm}, and ${param op word} 9994887Schin * The input stream is assumed to be a string 10004887Schin */ 10014887Schin static int varsub(Mac_t *mp) 10024887Schin { 10034887Schin register int c; 10044887Schin register int type=0; /* M_xxx */ 10054887Schin register char *v,*argp=0; 10064887Schin register Namval_t *np = NIL(Namval_t*); 10074887Schin register int dolg=0, mode=0; 10088462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)mp->shp->lex_context; 10094887Schin Namarr_t *ap=0; 10104887Schin int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0; 10118462SApril.Chin@Sun.COM char idbuff[3], *id = idbuff, *pattern=0, *repstr, *arrmax=0; 10128462SApril.Chin@Sun.COM int addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d; 10138462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 10144887Schin retry1: 10154887Schin mp->zeros = 0; 10164887Schin idbuff[0] = 0; 10174887Schin idbuff[1] = 0; 10184887Schin c = fcget(); 10194887Schin switch(c>0x7f?S_ALP:sh_lexstates[ST_DOL][c]) 10204887Schin { 10214887Schin case S_RBRA: 10224887Schin if(type<M_SIZE) 10234887Schin goto nosub; 10244887Schin /* This code handles ${#} */ 10254887Schin c = mode; 10264887Schin mode = type = 0; 10274887Schin /* FALL THRU */ 10284887Schin case S_SPC1: 10294887Schin if(type==M_BRACE) 10304887Schin { 10314887Schin if(isaletter(mode=fcpeek(0)) || mode=='.') 10324887Schin { 10334887Schin if(c=='#') 10344887Schin type = M_SIZE; 10354887Schin #ifdef SHOPT_TYPEDEF 10364887Schin else if(c=='@') 10374887Schin { 10384887Schin type = M_TYPE; 10394887Schin goto retry1; 10404887Schin } 10414887Schin #endif /* SHOPT_TYPEDEF */ 10424887Schin else 10434887Schin type = M_VNAME; 10444887Schin mode = c; 10454887Schin goto retry1; 10464887Schin } 10474887Schin else if(c=='#' && (isadigit(mode)||fcpeek(1)==RBRACE)) 10484887Schin { 10494887Schin type = M_SIZE; 10504887Schin mode = c; 10514887Schin goto retry1; 10524887Schin } 10534887Schin } 10544887Schin /* FALL THRU */ 10554887Schin case S_SPC2: 10564887Schin *id = c; 10578462SApril.Chin@Sun.COM v = special(mp->shp,c); 10584887Schin if(isastchar(c)) 10594887Schin { 10604887Schin mode = c; 10614887Schin #if SHOPT_FILESCAN 10628462SApril.Chin@Sun.COM if(mp->shp->cur_line) 10634887Schin { 10644887Schin v = getdolarg(&sh,1,(int*)0); 10654887Schin dolmax = MAX_ARGN; 10664887Schin } 10674887Schin else 10684887Schin #endif /* SHOPT_FILESCAN */ 10698462SApril.Chin@Sun.COM dolmax = mp->shp->st.dolc+1; 10704887Schin dolg = (v!=0); 10714887Schin } 10724887Schin break; 10734887Schin case S_LBRA: 10744887Schin if(type) 10754887Schin goto nosub; 10764887Schin type = M_BRACE; 10774887Schin goto retry1; 10784887Schin case S_PAR: 10794887Schin if(type) 10804887Schin goto nosub; 10818462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,1); 10824887Schin return(1); 10834887Schin case S_DIG: 10844887Schin c -= '0'; 10858462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 10864887Schin if(type) 10874887Schin { 10884887Schin register int d; 10894887Schin while((d=fcget()),isadigit(d)) 10904887Schin c = 10*c + (d-'0'); 10914887Schin fcseek(-1); 10924887Schin } 10934887Schin idnum = c; 10944887Schin if(c==0) 10958462SApril.Chin@Sun.COM v = special(mp->shp,c); 10964887Schin #if SHOPT_FILESCAN 10978462SApril.Chin@Sun.COM else if(mp->shp->cur_line) 10984887Schin { 10998462SApril.Chin@Sun.COM mp->shp->used_pos = 1; 11004887Schin v = getdolarg(&sh,c,&vsize); 11014887Schin } 11024887Schin #endif /* SHOPT_FILESCAN */ 11038462SApril.Chin@Sun.COM else if(c <= mp->shp->st.dolc) 11044887Schin { 11058462SApril.Chin@Sun.COM mp->shp->used_pos = 1; 11068462SApril.Chin@Sun.COM v = mp->shp->st.dolv[c]; 11074887Schin } 11084887Schin else 11094887Schin v = 0; 11104887Schin break; 11114887Schin case S_ALP: 11124887Schin if(c=='.' && type==0) 11134887Schin goto nosub; 11148462SApril.Chin@Sun.COM offset = stktell(stkp); 11154887Schin do 11164887Schin { 11174887Schin np = 0; 11184887Schin do 11198462SApril.Chin@Sun.COM sfputc(stkp,c); 11204887Schin while(((c=fcget()),(c>0x7f||isaname(c)))||type && c=='.'); 11218462SApril.Chin@Sun.COM while(c==LBRACT && (type||mp->arrayok)) 11224887Schin { 11238462SApril.Chin@Sun.COM mp->shp->argaddr=0; 11244887Schin if((c=fcget(),isastchar(c)) && fcpeek(0)==RBRACT) 11254887Schin { 11264887Schin if(type==M_VNAME) 11274887Schin type = M_SUBNAME; 11284887Schin idbuff[0] = mode = c; 11294887Schin fcget(); 11304887Schin c = fcget(); 11314887Schin if(c=='.' || c==LBRACT) 11324887Schin { 11338462SApril.Chin@Sun.COM sfputc(stkp,LBRACT); 11348462SApril.Chin@Sun.COM sfputc(stkp,mode); 11358462SApril.Chin@Sun.COM sfputc(stkp,RBRACT); 11364887Schin } 11374887Schin else 11384887Schin flag = NV_ARRAY; 11394887Schin break; 11404887Schin } 11414887Schin else 11424887Schin { 11434887Schin fcseek(-1); 11448462SApril.Chin@Sun.COM c = stktell(stkp); 11458462SApril.Chin@Sun.COM sfputc(stkp,LBRACT); 11468462SApril.Chin@Sun.COM v = stkptr(stkp,subcopy(mp,1)); 11478462SApril.Chin@Sun.COM if(type && mp->dotdot) 11488462SApril.Chin@Sun.COM { 11498462SApril.Chin@Sun.COM mode = '@'; 11508462SApril.Chin@Sun.COM v[-1] = 0; 11518462SApril.Chin@Sun.COM if(type==M_VNAME) 11528462SApril.Chin@Sun.COM type = M_SUBNAME; 11538462SApril.Chin@Sun.COM else if(type==M_SIZE) 11548462SApril.Chin@Sun.COM goto nosub; 11558462SApril.Chin@Sun.COM } 11568462SApril.Chin@Sun.COM else 11578462SApril.Chin@Sun.COM sfputc(stkp,RBRACT); 11588462SApril.Chin@Sun.COM c = fcget(); 11598462SApril.Chin@Sun.COM if(c==0 && type==M_VNAME) 11604887Schin type = M_SUBNAME; 11614887Schin } 11624887Schin } 11634887Schin } 11644887Schin while(type && c=='.'); 11654887Schin if(c==RBRACE && type && fcpeek(-2)=='.') 11664887Schin { 11678462SApril.Chin@Sun.COM /* ${x.} or ${x..} */ 11688462SApril.Chin@Sun.COM if(fcpeek(-3) == '.') 11698462SApril.Chin@Sun.COM { 11708462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-2); 11718462SApril.Chin@Sun.COM nv_local = 1; 11728462SApril.Chin@Sun.COM } 11738462SApril.Chin@Sun.COM else 11748462SApril.Chin@Sun.COM { 11758462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 11768462SApril.Chin@Sun.COM type = M_TREE; 11778462SApril.Chin@Sun.COM } 11784887Schin } 11798462SApril.Chin@Sun.COM sfputc(stkp,0); 11808462SApril.Chin@Sun.COM id=stkptr(stkp,offset); 11814887Schin if(isastchar(c) && type) 11824887Schin { 11834887Schin if(type==M_VNAME || type==M_SIZE) 11844887Schin { 11854887Schin idbuff[0] = mode = c; 11864887Schin if((d=fcpeek(0))==c) 11874887Schin idbuff[1] = fcget(); 11884887Schin if(type==M_VNAME) 11894887Schin type = M_NAMESCAN; 11904887Schin else 11914887Schin type = M_NAMECOUNT; 11924887Schin break; 11934887Schin } 11944887Schin goto nosub; 11954887Schin } 11964887Schin flag |= NV_NOASSIGN|NV_VARNAME|NV_NOADD; 11974887Schin if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?'))) 11984887Schin flag &= ~NV_NOADD; 11994887Schin #if SHOPT_FILESCAN 12008462SApril.Chin@Sun.COM if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0) 12014887Schin { 12028462SApril.Chin@Sun.COM mp->shp->argaddr=0; 12034887Schin np = REPLYNOD; 12044887Schin } 12054887Schin else 12064887Schin #endif /* SHOPT_FILESCAN */ 12078462SApril.Chin@Sun.COM if(mp->shp->argaddr) 12084887Schin flag &= ~NV_NOADD; 12098462SApril.Chin@Sun.COM np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL); 12108462SApril.Chin@Sun.COM if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY)) 12118462SApril.Chin@Sun.COM { 12128462SApril.Chin@Sun.COM if(sh_macfun(mp->shp,id,offset)) 12138462SApril.Chin@Sun.COM { 12148462SApril.Chin@Sun.COM fcget(); 12158462SApril.Chin@Sun.COM return(1); 12168462SApril.Chin@Sun.COM } 12178462SApril.Chin@Sun.COM } 12184887Schin ap = np?nv_arrayptr(np):0; 12194887Schin if(type) 12204887Schin { 12218462SApril.Chin@Sun.COM if(mp->dotdot) 12228462SApril.Chin@Sun.COM { 12238462SApril.Chin@Sun.COM if(ap) 12248462SApril.Chin@Sun.COM { 12258462SApril.Chin@Sun.COM nv_putsub(np,v,ARRAY_SCAN); 12268462SApril.Chin@Sun.COM v = stkptr(stkp,mp->dotdot); 12278462SApril.Chin@Sun.COM dolmax =1; 12288462SApril.Chin@Sun.COM if(array_assoc(ap)) 12298462SApril.Chin@Sun.COM arrmax = strdup(v); 12308462SApril.Chin@Sun.COM else if((dolmax = (int)sh_arith(v))<0) 12318462SApril.Chin@Sun.COM dolmax += array_maxindex(np); 12328462SApril.Chin@Sun.COM if(type==M_SUBNAME) 12338462SApril.Chin@Sun.COM bysub = 1; 12348462SApril.Chin@Sun.COM } 12358462SApril.Chin@Sun.COM else 12368462SApril.Chin@Sun.COM { 12378462SApril.Chin@Sun.COM if((int)sh_arith(v)) 12388462SApril.Chin@Sun.COM np = 0; 12398462SApril.Chin@Sun.COM } 12408462SApril.Chin@Sun.COM } 12418462SApril.Chin@Sun.COM else if(ap && (isastchar(mode)||type==M_TREE) && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE) 12424887Schin nv_putsub(np,NIL(char*),ARRAY_SCAN); 12434887Schin if(!isbracechar(c)) 12444887Schin goto nosub; 12454887Schin else 12464887Schin fcseek(-1); 12474887Schin } 12484887Schin else 12494887Schin fcseek(-1); 12508462SApril.Chin@Sun.COM if(type<=1 && np && nv_isvtree(np) && mp->pattern==1 && !mp->split) 12518462SApril.Chin@Sun.COM { 12528462SApril.Chin@Sun.COM int peek=1,cc=fcget(); 12538462SApril.Chin@Sun.COM if(type && cc=='}') 12548462SApril.Chin@Sun.COM { 12558462SApril.Chin@Sun.COM cc = fcget(); 12568462SApril.Chin@Sun.COM peek = 2; 12578462SApril.Chin@Sun.COM } 12588462SApril.Chin@Sun.COM if(mp->quote && cc=='"') 12598462SApril.Chin@Sun.COM { 12608462SApril.Chin@Sun.COM cc = fcget(); 12618462SApril.Chin@Sun.COM peek++; 12628462SApril.Chin@Sun.COM } 12638462SApril.Chin@Sun.COM fcseek(-peek); 12648462SApril.Chin@Sun.COM if(cc==0) 12658462SApril.Chin@Sun.COM mp->assign = 1; 12668462SApril.Chin@Sun.COM } 12678462SApril.Chin@Sun.COM if((type==M_VNAME||type==M_SUBNAME) && mp->shp->argaddr && strcmp(nv_name(np),id)) 12688462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 12694887Schin c = (type>M_BRACE && isastchar(mode)); 12708462SApril.Chin@Sun.COM if(np && (type==M_TREE || !c || !ap)) 12714887Schin { 12728462SApril.Chin@Sun.COM char *savptr; 12738462SApril.Chin@Sun.COM c = *((unsigned char*)stkptr(stkp,offset-1)); 12748462SApril.Chin@Sun.COM savptr = stkfreeze(stkp,0); 12758462SApril.Chin@Sun.COM if(type==M_VNAME || (type==M_SUBNAME && ap)) 12764887Schin { 12774887Schin type = M_BRACE; 12784887Schin v = nv_name(np); 12798462SApril.Chin@Sun.COM if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF)) 12808462SApril.Chin@Sun.COM addsub = 1; 12814887Schin } 12824887Schin #ifdef SHOPT_TYPEDEF 12834887Schin else if(type==M_TYPE) 12844887Schin { 12854887Schin Namval_t *nq = nv_type(np); 12864887Schin type = M_BRACE; 12874887Schin if(nq) 12888462SApril.Chin@Sun.COM nv_typename(nq,mp->shp->strbuf); 12894887Schin else 12908462SApril.Chin@Sun.COM nv_attribute(np,mp->shp->strbuf,"typeset",1); 12918462SApril.Chin@Sun.COM v = sfstruse(mp->shp->strbuf); 12924887Schin } 12934887Schin #endif /* SHOPT_TYPEDEF */ 12944887Schin #if SHOPT_FILESCAN 12958462SApril.Chin@Sun.COM else if(mp->shp->cur_line && np==REPLYNOD) 12968462SApril.Chin@Sun.COM v = mp->shp->cur_line; 12974887Schin #endif /* SHOPT_FILESCAN */ 12984887Schin else if(type==M_TREE) 12994887Schin v = nv_getvtree(np,(Namfun_t*)0); 13004887Schin else 13014887Schin { 13024887Schin v = nv_getval(np); 13034887Schin /* special case --- ignore leading zeros */ 13048462SApril.Chin@Sun.COM if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(c))) 13054887Schin mp->zeros = 1; 13064887Schin } 13078462SApril.Chin@Sun.COM if(savptr==stakptr(0)) 13088462SApril.Chin@Sun.COM stkseek(stkp,offset); 13098462SApril.Chin@Sun.COM else 13108462SApril.Chin@Sun.COM stkset(stkp,savptr,offset); 13114887Schin } 13124887Schin else 13138462SApril.Chin@Sun.COM { 13144887Schin v = 0; 13158462SApril.Chin@Sun.COM if(type==M_VNAME) 13168462SApril.Chin@Sun.COM { 13178462SApril.Chin@Sun.COM v = id; 13188462SApril.Chin@Sun.COM type = M_BRACE; 13198462SApril.Chin@Sun.COM } 13208462SApril.Chin@Sun.COM else if(type==M_TYPE) 13218462SApril.Chin@Sun.COM type = M_BRACE; 13228462SApril.Chin@Sun.COM } 13238462SApril.Chin@Sun.COM stkseek(stkp,offset); 13244887Schin if(ap) 13254887Schin { 13264887Schin #if SHOPT_OPTIMIZE 13278462SApril.Chin@Sun.COM if(mp->shp->argaddr) 13284887Schin nv_optimize(np); 13294887Schin #endif 13304887Schin if(isastchar(mode) && array_elem(ap)> !c) 13314887Schin dolg = -1; 13324887Schin else 13334887Schin dolg = 0; 13344887Schin } 13354887Schin break; 13364887Schin case S_EOF: 13374887Schin fcseek(-1); 13384887Schin default: 13394887Schin goto nosub; 13404887Schin } 13414887Schin c = fcget(); 13424887Schin if(type>M_TREE) 13434887Schin { 13444887Schin if(c!=RBRACE) 13454887Schin mac_error(np); 13464887Schin if(type==M_NAMESCAN || type==M_NAMECOUNT) 13474887Schin { 13488462SApril.Chin@Sun.COM id = prefix(mp->shp,id); 13498462SApril.Chin@Sun.COM stkseek(stkp,offset); 13504887Schin if(type==M_NAMECOUNT) 13514887Schin { 13524887Schin c = namecount(mp,id); 13534887Schin v = ltos(c); 13544887Schin } 13554887Schin else 13564887Schin { 13574887Schin dolmax = strlen(id); 13584887Schin dolg = -1; 13594887Schin nextname(mp,id,0); 13604887Schin v = nextname(mp,id,dolmax); 13614887Schin } 13624887Schin } 13634887Schin else if(type==M_SUBNAME) 13644887Schin { 13654887Schin if(dolg<0) 13664887Schin { 13674887Schin v = nv_getsub(np); 13684887Schin bysub=1; 13694887Schin } 13704887Schin else if(v) 13714887Schin { 13724887Schin if(!ap || isastchar(mode)) 13734887Schin v = "0"; 13744887Schin else 13754887Schin v = nv_getsub(np); 13764887Schin } 13774887Schin } 13784887Schin else 13794887Schin { 13804887Schin if(!isastchar(mode)) 13814887Schin c = charlen(v,vsize); 13824887Schin else if(dolg>0) 13834887Schin { 13844887Schin #if SHOPT_FILESCAN 13858462SApril.Chin@Sun.COM if(mp->shp->cur_line) 13864887Schin { 13874887Schin getdolarg(&sh,MAX_ARGN,(int*)0); 13888462SApril.Chin@Sun.COM c = mp->shp->offsets[0]; 13894887Schin } 13904887Schin else 13914887Schin #endif /* SHOPT_FILESCAN */ 13928462SApril.Chin@Sun.COM c = mp->shp->st.dolc; 13934887Schin } 13944887Schin else if(dolg<0) 13954887Schin c = array_elem(ap); 13964887Schin else 13974887Schin c = (v!=0); 13984887Schin dolg = dolmax = 0; 13994887Schin v = ltos(c); 14004887Schin } 14014887Schin c = RBRACE; 14024887Schin } 14034887Schin nulflg = 0; 14044887Schin if(type && c==':') 14054887Schin { 14064887Schin c = fcget(); 14074887Schin if(sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':') 14084887Schin nulflg=1; 14094887Schin else if(c!='%' && c!='#') 14104887Schin { 14114887Schin fcseek(-1); 14124887Schin c = ':'; 14134887Schin } 14144887Schin } 14154887Schin if(type) 14164887Schin { 14174887Schin if(!isbracechar(c)) 14184887Schin { 14194887Schin if(!nulflg) 14204887Schin mac_error(np); 14214887Schin fcseek(-1); 14224887Schin c = ':'; 14234887Schin } 14244887Schin if(c!=RBRACE) 14254887Schin { 14264887Schin int newops = (c=='#' || c == '%' || c=='/'); 14278462SApril.Chin@Sun.COM offset = stktell(stkp); 14284887Schin if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%'))) 14294887Schin { 14304887Schin int newquote = mp->quote; 14314887Schin int split = mp->split; 14324887Schin int quoted = mp->quoted; 14334887Schin int arith = mp->arith; 14344887Schin int zeros = mp->zeros; 14354887Schin if(newops) 14364887Schin { 14374887Schin type = fcget(); 14384887Schin if(type=='%' || type=='#') 14394887Schin { 14404887Schin int d = fcget(); 14414887Schin fcseek(-1); 14424887Schin if(d=='(') 14434887Schin type = 0; 14444887Schin } 14454887Schin fcseek(-1); 14464887Schin mp->pattern = 1+(c=='/'); 14474887Schin mp->split = 0; 14484887Schin mp->quoted = 0; 14494887Schin mp->arith = mp->zeros = 0; 14504887Schin newquote = 0; 14514887Schin } 14524887Schin else if(c=='?' || c=='=') 14534887Schin mp->split = mp->pattern = 0; 14544887Schin copyto(mp,RBRACE,newquote); 14554887Schin if(!oldpat) 14564887Schin mp->patfound = 0; 14574887Schin mp->pattern = oldpat; 14584887Schin mp->split = split; 14594887Schin mp->quoted = quoted; 14604887Schin mp->arith = arith; 14614887Schin mp->zeros = zeros; 14624887Schin /* add null byte */ 14638462SApril.Chin@Sun.COM sfputc(stkp,0); 14648462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 14654887Schin } 14664887Schin else 14674887Schin { 14688462SApril.Chin@Sun.COM sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED); 14698462SApril.Chin@Sun.COM stkseek(stkp,offset); 14704887Schin } 14718462SApril.Chin@Sun.COM argp=stkptr(stkp,offset); 14724887Schin } 14734887Schin } 14744887Schin else 14754887Schin { 14764887Schin fcseek(-1); 14774887Schin c=0; 14784887Schin } 14794887Schin if(c==':') /* ${name:expr1[:expr2]} */ 14804887Schin { 14814887Schin char *ptr; 14824887Schin type = (int)sh_strnum(argp,&ptr,1); 14834887Schin if(isastchar(mode)) 14844887Schin { 14854887Schin if(id==idbuff) /* ${@} or ${*} */ 14864887Schin { 14874887Schin if(type<0 && (type+= dolmax)<0) 14884887Schin type = 0; 14894887Schin if(type==0) 14908462SApril.Chin@Sun.COM v = special(mp->shp,dolg=0); 14914887Schin #if SHOPT_FILESCAN 14928462SApril.Chin@Sun.COM else if(mp->shp->cur_line) 14934887Schin { 14944887Schin v = getdolarg(&sh,dolg=type,&vsize); 14954887Schin if(!v) 14964887Schin dolmax = type; 14974887Schin } 14984887Schin #endif /* SHOPT_FILESCAN */ 14994887Schin else if(type < dolmax) 15008462SApril.Chin@Sun.COM v = mp->shp->st.dolv[dolg=type]; 15014887Schin else 15024887Schin v = 0; 15034887Schin } 15044887Schin else if(ap) 15054887Schin { 15064887Schin if(type<0) 15074887Schin { 15084887Schin if(array_assoc(ap)) 15094887Schin type = -type; 15104887Schin else 15114887Schin type += array_maxindex(np); 15124887Schin } 15134887Schin if(array_assoc(ap)) 15144887Schin { 15154887Schin while(type-- >0 && (v=0,nv_nextsub(np))) 15164887Schin v = nv_getval(np); 15174887Schin } 15184887Schin else if(type > 0) 15194887Schin { 15204887Schin if(nv_putsub(np,NIL(char*),type|ARRAY_SCAN)) 15214887Schin v = nv_getval(np); 15224887Schin else 15234887Schin v = 0; 15244887Schin } 15254887Schin } 15264887Schin else if(type>0) 15274887Schin v = 0; 15284887Schin } 15294887Schin else if(v) 15304887Schin { 15314887Schin vsize = charlen(v,vsize); 15324887Schin if(type<0 && (type += vsize)<0) 15334887Schin type = 0; 15344887Schin if(vsize < type) 15354887Schin v = 0; 15364887Schin #if SHOPT_MULTIBYTE 15374887Schin else if(mbwide()) 15384887Schin { 15394887Schin mbinit(); 15404887Schin while(type-->0) 15414887Schin { 15424887Schin if((c=mbsize(v))<1) 15434887Schin c = 1; 15444887Schin v += c; 15454887Schin } 15464887Schin c = ':'; 15474887Schin } 15484887Schin #endif /* SHOPT_MULTIBYTE */ 15494887Schin else 15504887Schin v += type; 15514887Schin vsize -= type; 15524887Schin } 15534887Schin if(*ptr==':') 15544887Schin { 15554887Schin if((type = (int)sh_strnum(ptr+1,&ptr,1)) <=0) 15564887Schin v = 0; 15574887Schin else if(isastchar(mode)) 15584887Schin { 15594887Schin if(dolg>=0) 15604887Schin { 15614887Schin if(dolg+type < dolmax) 15624887Schin dolmax = dolg+type; 15634887Schin } 15644887Schin else 15654887Schin dolmax = type; 15664887Schin } 15674887Schin else if(type < vsize) 15684887Schin { 15694887Schin #if SHOPT_MULTIBYTE 15704887Schin if(mbwide()) 15714887Schin { 15724887Schin char *vp = v; 15734887Schin mbinit(); 15744887Schin while(type-->0) 15754887Schin { 15764887Schin if((c=mbsize(vp))<1) 15774887Schin c = 1; 15784887Schin vp += c; 15794887Schin } 15804887Schin type = vp-v; 15814887Schin c = ':'; 15824887Schin } 15834887Schin #endif /* SHOPT_MULTIBYTE */ 15844887Schin vsize = type; 15854887Schin } 15864887Schin } 15874887Schin if(*ptr) 15884887Schin mac_error(np); 15898462SApril.Chin@Sun.COM stkseek(stkp,offset); 15904887Schin argp = 0; 15914887Schin } 15924887Schin /* check for substring operations */ 15934887Schin else if(c == '#' || c == '%' || c=='/') 15944887Schin { 15954887Schin if(c=='/') 15964887Schin { 15974887Schin if(type=='/' || type=='#' || type=='%') 15984887Schin { 15994887Schin c = type; 16004887Schin type = '/'; 16014887Schin argp++; 16024887Schin } 16034887Schin else 16044887Schin type = 0; 16054887Schin } 16064887Schin else 16074887Schin { 16084887Schin if(type==c) /* ## or %% */ 16094887Schin argp++; 16104887Schin else 16114887Schin type = 0; 16124887Schin } 16134887Schin pattern = strdup(argp); 16144887Schin if((type=='/' || c=='/') && (repstr = mac_getstring(pattern))) 16154887Schin replen = strlen(repstr); 16164887Schin if(v || c=='/' && offset>=0) 16178462SApril.Chin@Sun.COM stkseek(stkp,offset); 16184887Schin } 16194887Schin /* check for quoted @ */ 16204887Schin if(mode=='@' && mp->quote && !v && c!='-') 16214887Schin mp->quoted-=2; 16224887Schin retry2: 16234887Schin if(v && (!nulflg || *v ) && c!='+') 16244887Schin { 16254887Schin register int d = (mode=='@'?' ':mp->ifs); 16268462SApril.Chin@Sun.COM int match[2*(MATCH_MAX+1)], nmatch, nmatch_prev, vsize_last; 16274887Schin char *vlast; 16284887Schin while(1) 16294887Schin { 16304887Schin if(!v) 16314887Schin v= ""; 16324887Schin if(c=='/' || c=='#' || c== '%') 16334887Schin { 16348462SApril.Chin@Sun.COM flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP; 16354887Schin if(c!='/') 16364887Schin flag |= STR_LEFT; 16378462SApril.Chin@Sun.COM nmatch = 0; 16384887Schin while(1) 16394887Schin { 16404887Schin vsize = strlen(v); 16418462SApril.Chin@Sun.COM nmatch_prev = nmatch; 16424887Schin if(c=='%') 16434887Schin nmatch=substring(v,pattern,match,flag&STR_MAXIMAL); 16444887Schin else 16454887Schin nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag); 16464887Schin if(replen>0) 16474887Schin sh_setmatch(v,vsize,nmatch,match); 16484887Schin if(nmatch) 16494887Schin { 16504887Schin vlast = v; 16514887Schin vsize_last = vsize; 16524887Schin vsize = match[0]; 16534887Schin } 16544887Schin else if(c=='#') 16554887Schin vsize = 0; 16564887Schin if(vsize) 16574887Schin mac_copy(mp,v,vsize); 16588462SApril.Chin@Sun.COM if(nmatch && replen>0 && (match[1] || !nmatch_prev)) 16594887Schin mac_substitute(mp,repstr,v,match,nmatch); 16604887Schin if(nmatch==0) 16614887Schin v += vsize; 16624887Schin else 16634887Schin v += match[1]; 16644887Schin if(*v && c=='/' && type) 16654887Schin { 16664887Schin /* avoid infinite loop */ 16674887Schin if(nmatch && match[1]==0) 16688462SApril.Chin@Sun.COM { 16698462SApril.Chin@Sun.COM nmatch = 0; 16708462SApril.Chin@Sun.COM mac_copy(mp,v,1); 16714887Schin v++; 16728462SApril.Chin@Sun.COM } 16734887Schin continue; 16744887Schin } 16754887Schin vsize = -1; 16764887Schin break; 16774887Schin } 16784887Schin if(replen==0) 16794887Schin sh_setmatch(vlast,vsize_last,nmatch,match); 16804887Schin } 16814887Schin if(vsize) 16824887Schin mac_copy(mp,v,vsize>0?vsize:strlen(v)); 16838462SApril.Chin@Sun.COM if(addsub) 16848462SApril.Chin@Sun.COM { 16858462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"[%s]",nv_getsub(np)); 16868462SApril.Chin@Sun.COM v = sfstruse(mp->shp->strbuf); 16878462SApril.Chin@Sun.COM mac_copy(mp, v, strlen(v)); 16888462SApril.Chin@Sun.COM } 16894887Schin if(dolg==0 && dolmax==0) 16904887Schin break; 16918462SApril.Chin@Sun.COM if(mp->dotdot) 16928462SApril.Chin@Sun.COM { 16938462SApril.Chin@Sun.COM if(nv_nextsub(np) == 0) 16948462SApril.Chin@Sun.COM break; 16958462SApril.Chin@Sun.COM if(bysub) 16968462SApril.Chin@Sun.COM v = nv_getsub(np); 16978462SApril.Chin@Sun.COM else 16988462SApril.Chin@Sun.COM v = nv_getval(np); 16998462SApril.Chin@Sun.COM if(array_assoc(ap)) 17008462SApril.Chin@Sun.COM { 17018462SApril.Chin@Sun.COM if(strcmp(bysub?v:nv_getsub(np),arrmax)>0) 17028462SApril.Chin@Sun.COM break; 17038462SApril.Chin@Sun.COM } 17048462SApril.Chin@Sun.COM else 17058462SApril.Chin@Sun.COM { 17068462SApril.Chin@Sun.COM if(nv_aindex(np) > dolmax) 17078462SApril.Chin@Sun.COM break; 17088462SApril.Chin@Sun.COM } 17098462SApril.Chin@Sun.COM } 17108462SApril.Chin@Sun.COM else if(dolg>=0) 17114887Schin { 17124887Schin if(++dolg >= dolmax) 17134887Schin break; 17144887Schin #if SHOPT_FILESCAN 17158462SApril.Chin@Sun.COM if(mp->shp->cur_line) 17164887Schin { 17174887Schin if(dolmax==MAX_ARGN && isastchar(mode)) 17184887Schin break; 17194887Schin if(!(v=getdolarg(&sh,dolg,&vsize))) 17204887Schin { 17214887Schin dolmax = dolg; 17224887Schin break; 17234887Schin } 17244887Schin } 17254887Schin else 17264887Schin #endif /* SHOPT_FILESCAN */ 17278462SApril.Chin@Sun.COM v = mp->shp->st.dolv[dolg]; 17284887Schin } 17294887Schin else if(!np) 17304887Schin { 17314887Schin if(!(v = nextname(mp,id,dolmax))) 17324887Schin break; 17334887Schin } 17344887Schin else 17354887Schin { 17364887Schin if(dolmax && --dolmax <=0) 17374887Schin { 17384887Schin nv_putsub(np,NIL(char*),ARRAY_UNDEF); 17394887Schin break; 17404887Schin } 17418462SApril.Chin@Sun.COM if(ap) 17428462SApril.Chin@Sun.COM ap->nelem |= ARRAY_SCAN; 17434887Schin if(nv_nextsub(np) == 0) 17444887Schin break; 17454887Schin if(bysub) 17464887Schin v = nv_getsub(np); 17474887Schin else 17484887Schin v = nv_getval(np); 17494887Schin } 17504887Schin if(mp->split && (!mp->quote || mode=='@')) 17514887Schin { 17524887Schin if(!np) 17534887Schin mp->pattern = 0; 17544887Schin endfield(mp,mp->quoted); 17554887Schin mp->pattern = oldpat; 17564887Schin } 17574887Schin else if(d) 17584887Schin { 17594887Schin if(mp->sp) 17604887Schin sfputc(mp->sp,d); 17614887Schin else 17628462SApril.Chin@Sun.COM sfputc(stkp,d); 17634887Schin } 17644887Schin } 17658462SApril.Chin@Sun.COM if(arrmax) 17668462SApril.Chin@Sun.COM free((void*)arrmax); 17674887Schin if(pattern) 17684887Schin free((void*)pattern); 17694887Schin } 17704887Schin else if(argp) 17714887Schin { 17724887Schin if(c=='/' && replen>0 && pattern && strmatch("",pattern)) 17734887Schin mac_substitute(mp,repstr,v,0,0); 17744887Schin if(c=='?') 17754887Schin { 17764887Schin if(np) 17774887Schin id = nv_name(np); 17784887Schin else if(idnum) 17794887Schin id = ltos(idnum); 17804887Schin if(*argp) 17814887Schin { 17828462SApril.Chin@Sun.COM sfputc(stkp,0); 17834887Schin errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp); 17844887Schin } 17854887Schin else if(v) 17864887Schin errormsg(SH_DICT,ERROR_exit(1),e_nullset,id); 17874887Schin else 17884887Schin errormsg(SH_DICT,ERROR_exit(1),e_notset,id); 17894887Schin } 17904887Schin else if(c=='=') 17914887Schin { 17924887Schin if(np) 17934887Schin { 17948462SApril.Chin@Sun.COM if(mp->shp->subshell) 17954887Schin np = sh_assignok(np,1); 17964887Schin nv_putval(np,argp,0); 17974887Schin v = nv_getval(np); 17984887Schin nulflg = 0; 17998462SApril.Chin@Sun.COM stkseek(stkp,offset); 18004887Schin goto retry2; 18014887Schin } 18024887Schin else 18034887Schin mac_error(np); 18044887Schin } 18054887Schin } 18064887Schin else if(sh_isoption(SH_NOUNSET) && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp))) 18074887Schin { 18084887Schin if(np) 18094887Schin { 18104887Schin if(nv_isarray(np)) 18114887Schin { 18128462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np)); 18138462SApril.Chin@Sun.COM id = sfstruse(mp->shp->strbuf); 18144887Schin } 18154887Schin else 18164887Schin id = nv_name(np); 18174887Schin nv_close(np); 18184887Schin } 18194887Schin errormsg(SH_DICT,ERROR_exit(1),e_notset,id); 18204887Schin } 18214887Schin if(np) 18224887Schin nv_close(np); 18234887Schin return(1); 18244887Schin nosub: 18258462SApril.Chin@Sun.COM if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK) 18268462SApril.Chin@Sun.COM { 18278462SApril.Chin@Sun.COM fcseek(-1); 18288462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,2); 18298462SApril.Chin@Sun.COM return(1); 18308462SApril.Chin@Sun.COM } 18314887Schin if(type) 18324887Schin mac_error(np); 18334887Schin fcseek(-1); 18344887Schin nv_close(np); 18354887Schin return(0); 18364887Schin } 18374887Schin 18384887Schin /* 18394887Schin * This routine handles command substitution 18404887Schin * <type> is 0 for older `...` version 18414887Schin */ 18428462SApril.Chin@Sun.COM static void comsubst(Mac_t *mp,register Shnode_t* t, int type) 18434887Schin { 18444887Schin Sfdouble_t num; 18454887Schin register int c; 18464887Schin register char *str; 18474887Schin Sfio_t *sp; 18488462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 18494887Schin Fcin_t save; 18508462SApril.Chin@Sun.COM struct slnod *saveslp = mp->shp->st.staklist; 18514887Schin struct _mac_ savemac; 18528462SApril.Chin@Sun.COM int savtop = stktell(stkp); 18538462SApril.Chin@Sun.COM char lastc, *savptr = stkfreeze(stkp,0); 18544887Schin int was_history = sh_isstate(SH_HISTORY); 18554887Schin int was_verbose = sh_isstate(SH_VERBOSE); 18568462SApril.Chin@Sun.COM int was_interactive = sh_isstate(SH_INTERACTIVE); 18578462SApril.Chin@Sun.COM int newlines,bufsize,nextnewlines; 18584887Schin Namval_t *np; 18598462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 18604887Schin savemac = *mp; 18618462SApril.Chin@Sun.COM mp->shp->st.staklist=0; 18624887Schin if(type) 18634887Schin { 18644887Schin sp = 0; 18654887Schin fcseek(-1); 18668462SApril.Chin@Sun.COM if(!t) 18678462SApril.Chin@Sun.COM t = sh_dolparen((Lex_t*)mp->shp->lex_context); 18684887Schin if(t && t->tre.tretyp==TARITH) 18694887Schin { 18704887Schin fcsave(&save); 18718462SApril.Chin@Sun.COM if((t->ar.arexpr->argflag&ARG_RAW)) 18728462SApril.Chin@Sun.COM num = arith_exec(t->ar.arcomp); 18738462SApril.Chin@Sun.COM else 18748462SApril.Chin@Sun.COM num = sh_arith(sh_mactrim(mp->shp,t->ar.arexpr->argval,3)); 18754887Schin out_offset: 18768462SApril.Chin@Sun.COM stkset(stkp,savptr,savtop); 18774887Schin *mp = savemac; 18788462SApril.Chin@Sun.COM if((Sflong_t)num!=num) 18798462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%.*Lg",LDBL_DIG,num); 18808462SApril.Chin@Sun.COM else if(num) 18818462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%lld",(Sflong_t)num); 18824887Schin else 18838462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%Lg",num); 18848462SApril.Chin@Sun.COM str = sfstruse(mp->shp->strbuf); 18854887Schin mac_copy(mp,str,strlen(str)); 18868462SApril.Chin@Sun.COM mp->shp->st.staklist = saveslp; 18874887Schin fcrestore(&save); 18884887Schin return; 18894887Schin } 18904887Schin } 18914887Schin else 18924887Schin { 18934887Schin while(fcgetc(c)!='`' && c) 18944887Schin { 18954887Schin if(c==ESCAPE) 18964887Schin { 18974887Schin fcgetc(c); 18984887Schin if(!(isescchar(sh_lexstates[ST_QUOTE][c]) || 18998462SApril.Chin@Sun.COM (c=='"' && mp->quote))) 19008462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 19014887Schin } 19028462SApril.Chin@Sun.COM sfputc(stkp,c); 19034887Schin } 19048462SApril.Chin@Sun.COM c = stktell(stkp); 19058462SApril.Chin@Sun.COM str=stkfreeze(stkp,1); 19064887Schin /* disable verbose and don't save in history file */ 19074887Schin sh_offstate(SH_HISTORY); 19084887Schin sh_offstate(SH_VERBOSE); 19094887Schin if(mp->sp) 19104887Schin sfsync(mp->sp); /* flush before executing command */ 19114887Schin sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ); 19128462SApril.Chin@Sun.COM c = mp->shp->inlineno; 19138462SApril.Chin@Sun.COM mp->shp->inlineno = error_info.line+mp->shp->st.firstline; 19144887Schin t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL); 19158462SApril.Chin@Sun.COM mp->shp->inlineno = c; 19168462SApril.Chin@Sun.COM type = 1; 19174887Schin } 19184887Schin #if KSHELL 19194887Schin if(t) 19204887Schin { 19214887Schin fcsave(&save); 19224887Schin sfclose(sp); 19238462SApril.Chin@Sun.COM if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset) 19244887Schin { 19254887Schin /* special case $(<file) and $(<#file) */ 19264887Schin register int fd; 19274887Schin int r; 19284887Schin struct checkpt buff; 19294887Schin struct ionod *ip=0; 19304887Schin sh_pushcontext(&buff,SH_JMPIO); 19314887Schin if((ip=t->tre.treio) && 19324887Schin ((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) && 19334887Schin (r=sigsetjmp(buff.buff,0))==0) 19348462SApril.Chin@Sun.COM fd = sh_redirect(mp->shp,ip,3); 19354887Schin else 19364887Schin fd = sh_chkopen(e_devnull); 19374887Schin sh_popcontext(&buff); 19384887Schin if(r==0 && ip && (ip->iofile&IOLSEEK)) 19394887Schin { 19408462SApril.Chin@Sun.COM if(sp=mp->shp->sftable[fd]) 19414887Schin num = sftell(sp); 19424887Schin else 19434887Schin num = lseek(fd, (off_t)0, SEEK_CUR); 19444887Schin goto out_offset; 19454887Schin } 19464887Schin sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC); 19478462SApril.Chin@Sun.COM type = 3; 19484887Schin } 19494887Schin else 19508462SApril.Chin@Sun.COM sp = sh_subshell(t,sh_isstate(SH_ERREXIT),type); 19514887Schin fcrestore(&save); 19524887Schin } 19534887Schin else 19544887Schin sp = sfopen(NIL(Sfio_t*),"","sr"); 19558462SApril.Chin@Sun.COM sh_freeup(mp->shp); 19568462SApril.Chin@Sun.COM mp->shp->st.staklist = saveslp; 19574887Schin if(was_history) 19584887Schin sh_onstate(SH_HISTORY); 19594887Schin if(was_verbose) 19604887Schin sh_onstate(SH_VERBOSE); 19614887Schin #else 19624887Schin sp = sfpopen(NIL(Sfio_t*),str,"r"); 19634887Schin #endif 19644887Schin *mp = savemac; 19658462SApril.Chin@Sun.COM np = sh_scoped(mp->shp,IFSNOD); 19668462SApril.Chin@Sun.COM nv_putval(np,mp->ifsp,NV_RDONLY); 19674887Schin mp->ifsp = nv_getval(np); 19688462SApril.Chin@Sun.COM stkset(stkp,savptr,savtop); 19694887Schin newlines = 0; 19704887Schin lastc = 0; 19714887Schin sfsetbuf(sp,(void*)sp,0); 19724887Schin bufsize = sfvalue(sp); 19734887Schin /* read command substitution output and put on stack or here-doc */ 19744887Schin sfpool(sp, NIL(Sfio_t*), SF_WRITE); 19758462SApril.Chin@Sun.COM sh_offstate(SH_INTERACTIVE); 19764887Schin while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c = sfvalue(sp))>0) 19774887Schin { 19784887Schin #if SHOPT_CRNL 19794887Schin /* eliminate <cr> */ 19804887Schin register char *dp; 19814887Schin char *buff = str; 19824887Schin while(c>1 && (*str !='\r'|| str[1]!='\n')) 19834887Schin { 19844887Schin c--; 19854887Schin str++; 19864887Schin } 19874887Schin dp = str; 19884887Schin while(c>1) 19894887Schin { 19904887Schin str++; 19914887Schin c--; 19924887Schin while(c>1 && (*str!='\r' || str[1]!='\n')) 19934887Schin { 19944887Schin c--; 19954887Schin *dp++ = *str++; 19964887Schin } 19974887Schin } 19984887Schin if(c) 19994887Schin *dp++ = *str++; 20004887Schin str = buff; 20014887Schin c = dp-str; 20024887Schin #endif /* SHOPT_CRNL */ 20038462SApril.Chin@Sun.COM /* delay appending trailing new-lines */ 20048462SApril.Chin@Sun.COM for(nextnewlines=0; c-->0 && str[c]=='\n'; nextnewlines++); 20058462SApril.Chin@Sun.COM if(c < 0) 20068462SApril.Chin@Sun.COM { 20078462SApril.Chin@Sun.COM newlines += nextnewlines; 20088462SApril.Chin@Sun.COM continue; 20098462SApril.Chin@Sun.COM } 20104887Schin if(newlines >0) 20114887Schin { 20124887Schin if(mp->sp) 20134887Schin sfnputc(mp->sp,'\n',newlines); 20148462SApril.Chin@Sun.COM else if(!mp->quote && mp->split && mp->shp->ifstable['\n']) 20154887Schin endfield(mp,0); 20168462SApril.Chin@Sun.COM else 20178462SApril.Chin@Sun.COM sfnputc(stkp,'\n',newlines); 20184887Schin } 20194887Schin else if(lastc) 20204887Schin { 20214887Schin mac_copy(mp,&lastc,1); 20224887Schin lastc = 0; 20234887Schin } 20248462SApril.Chin@Sun.COM newlines = nextnewlines; 20254887Schin if(++c < bufsize) 20264887Schin str[c] = 0; 20274887Schin else 20284887Schin { 20294887Schin /* can't write past buffer so save last character */ 20304887Schin lastc = str[--c]; 20314887Schin str[c] = 0; 20324887Schin } 20334887Schin mac_copy(mp,str,c); 20344887Schin } 20358462SApril.Chin@Sun.COM if(was_interactive) 20368462SApril.Chin@Sun.COM sh_onstate(SH_INTERACTIVE); 20378462SApril.Chin@Sun.COM if(mp->shp->spid) 20388462SApril.Chin@Sun.COM job_wait(mp->shp->spid); 20398462SApril.Chin@Sun.COM if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM) 20404887Schin { 20414887Schin if(mp->sp) 20424887Schin sfnputc(mp->sp,'\n',newlines); 20438462SApril.Chin@Sun.COM else if(!mp->quote && mp->split) 20448462SApril.Chin@Sun.COM while(newlines--) 20458462SApril.Chin@Sun.COM endfield(mp,1); 20468462SApril.Chin@Sun.COM else 20478462SApril.Chin@Sun.COM sfnputc(stkp,'\n',newlines); 20484887Schin } 20494887Schin if(lastc) 20504887Schin mac_copy(mp,&lastc,1); 20514887Schin sfclose(sp); 20524887Schin return; 20534887Schin } 20544887Schin 20554887Schin /* 20564887Schin * copy <str> onto the stack 20574887Schin */ 20584887Schin static void mac_copy(register Mac_t *mp,register const char *str, register int size) 20594887Schin { 20604887Schin register char *state; 20614887Schin register const char *cp=str; 20628462SApril.Chin@Sun.COM register int c,n,nopat,len; 20638462SApril.Chin@Sun.COM Stk_t *stkp=mp->shp->stk; 20644887Schin nopat = (mp->quote||mp->assign==1||mp->arith); 20654887Schin if(mp->zeros) 20664887Schin { 20674887Schin /* prevent leading 0's from becomming octal constants */ 20684887Schin while(size>1 && *str=='0') 20694887Schin str++,size--; 20704887Schin mp->zeros = 0; 20714887Schin cp = str; 20724887Schin } 20734887Schin if(mp->sp) 20744887Schin sfwrite(mp->sp,str,size); 20754887Schin else if(mp->pattern>=2 || (mp->pattern && nopat)) 20764887Schin { 20774887Schin state = sh_lexstates[ST_MACRO]; 20784887Schin /* insert \ before file expansion characters */ 20794887Schin while(size-->0) 20804887Schin { 20818462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE 20828462SApril.Chin@Sun.COM if(mbwide() && (len=mbsize(cp))>1) 20838462SApril.Chin@Sun.COM { 20848462SApril.Chin@Sun.COM cp += len; 20858462SApril.Chin@Sun.COM size -= (len-1); 20868462SApril.Chin@Sun.COM continue; 20878462SApril.Chin@Sun.COM } 20888462SApril.Chin@Sun.COM #endif 20894887Schin c = state[n= *(unsigned char*)cp++]; 20904887Schin if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3) 20914887Schin c=1; 20924887Schin else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n))) 20934887Schin c=1; 20944887Schin else if(mp->pattern==2 && c==S_SLASH) 20954887Schin c=1; 20964887Schin else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE))) 20974887Schin { 20984887Schin if(!(c=mp->quote)) 20994887Schin cp++; 21004887Schin } 21014887Schin else 21024887Schin c=0; 21034887Schin if(c) 21044887Schin { 21054887Schin if(c = (cp-1) - str) 21068462SApril.Chin@Sun.COM sfwrite(stkp,str,c); 21078462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 21084887Schin str = cp-1; 21094887Schin } 21104887Schin } 21114887Schin if(c = cp-str) 21128462SApril.Chin@Sun.COM sfwrite(stkp,str,c); 21134887Schin } 21144887Schin else if(!mp->quote && mp->split && (mp->ifs||mp->pattern)) 21154887Schin { 21164887Schin /* split words at ifs characters */ 21178462SApril.Chin@Sun.COM state = mp->shp->ifstable; 21184887Schin if(mp->pattern) 21194887Schin { 21204887Schin char *sp = "&|()"; 21214887Schin while(c = *sp++) 21224887Schin { 21234887Schin if(state[c]==0) 21244887Schin state[c] = S_EPAT; 21254887Schin } 21264887Schin sp = "*?[{"; 21274887Schin while(c = *sp++) 21284887Schin { 21294887Schin if(state[c]==0) 21304887Schin state[c] = S_PAT; 21314887Schin } 21324887Schin if(state[ESCAPE]==0) 21334887Schin state[ESCAPE] = S_ESC; 21344887Schin } 21354887Schin while(size-->0) 21364887Schin { 21378462SApril.Chin@Sun.COM n=state[c= *(unsigned char*)cp++]; 21388462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE 21398462SApril.Chin@Sun.COM if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1) 21408462SApril.Chin@Sun.COM { 21418462SApril.Chin@Sun.COM sfwrite(stkp,cp-1, len); 21428462SApril.Chin@Sun.COM cp += --len; 21438462SApril.Chin@Sun.COM size -= len; 21448462SApril.Chin@Sun.COM continue; 21458462SApril.Chin@Sun.COM } 21468462SApril.Chin@Sun.COM #endif 21478462SApril.Chin@Sun.COM if(n==S_ESC || n==S_EPAT) 21484887Schin { 21494887Schin /* don't allow extended patterns in this case */ 21504887Schin mp->patfound = mp->pattern; 21518462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 21524887Schin } 21534887Schin else if(n==S_PAT) 21544887Schin mp->patfound = mp->pattern; 21554887Schin else if(n && mp->ifs) 21564887Schin { 21574887Schin #if SHOPT_MULTIBYTE 21584887Schin if(n==S_MBYTE) 21594887Schin { 21604887Schin if(sh_strchr(mp->ifsp,cp-1)<0) 21614887Schin continue; 21624887Schin n = mbsize(cp-1) - 1; 21634887Schin if(n==-2) 21644887Schin n = 0; 21654887Schin cp += n; 21664887Schin size -= n; 21674887Schin n= S_DELIM; 21684887Schin } 21694887Schin #endif /* SHOPT_MULTIBYTE */ 21704887Schin if(n==S_SPACE || n==S_NL) 21714887Schin { 21724887Schin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL)) 21734887Schin size--; 21744887Schin #if SHOPT_MULTIBYTE 21754887Schin if(n==S_MBYTE && sh_strchr(mp->ifsp,cp-1)>=0) 21764887Schin { 21774887Schin n = mbsize(cp-1) - 1; 21784887Schin if(n==-2) 21794887Schin n = 0; 21804887Schin cp += n; 21814887Schin size -= n; 21824887Schin n=S_DELIM; 21834887Schin } 21844887Schin else 21854887Schin #endif /* SHOPT_MULTIBYTE */ 21864887Schin if(n==S_DELIM) 21874887Schin size--; 21884887Schin } 21894887Schin endfield(mp,n==S_DELIM||mp->quoted); 21904887Schin mp->patfound = 0; 21914887Schin if(n==S_DELIM) 21924887Schin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL)) 21934887Schin size--; 21944887Schin if(size<=0) 21954887Schin break; 21964887Schin cp--; 21974887Schin continue; 21984887Schin 21994887Schin } 22008462SApril.Chin@Sun.COM sfputc(stkp,c); 22014887Schin } 22024887Schin if(mp->pattern) 22034887Schin { 22044887Schin cp = "&|()"; 22054887Schin while(c = *cp++) 22064887Schin { 22074887Schin if(state[c]==S_EPAT) 22084887Schin state[c] = 0; 22094887Schin } 22104887Schin cp = "*?[{"; 22114887Schin while(c = *cp++) 22124887Schin { 22134887Schin if(state[c]==S_PAT) 22144887Schin state[c] = 0; 22154887Schin } 22168462SApril.Chin@Sun.COM if(mp->shp->ifstable[ESCAPE]==S_ESC) 22178462SApril.Chin@Sun.COM mp->shp->ifstable[ESCAPE] = 0; 22184887Schin } 22194887Schin } 22204887Schin else 22218462SApril.Chin@Sun.COM sfwrite(stkp,str,size); 22224887Schin } 22234887Schin 22244887Schin /* 22254887Schin * Terminate field. 22264887Schin * If field is null count field if <split> is non-zero 22274887Schin * Do filename expansion of required 22284887Schin */ 22294887Schin static void endfield(register Mac_t *mp,int split) 22304887Schin { 22318462SApril.Chin@Sun.COM register struct argnod *argp; 22328462SApril.Chin@Sun.COM register int count=0; 22338462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 22348462SApril.Chin@Sun.COM if(stktell(stkp) > ARGVAL || split) 22354887Schin { 22368462SApril.Chin@Sun.COM argp = (struct argnod*)stkfreeze(stkp,1); 22374887Schin argp->argnxt.cp = 0; 22384887Schin argp->argflag = 0; 22394887Schin if(mp->patfound) 22404887Schin { 22418462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 22424887Schin #if SHOPT_BRACEPAT 22434887Schin count = path_generate(argp,mp->arghead); 22444887Schin #else 22454887Schin count = path_expand(argp->argval,mp->arghead); 22464887Schin #endif /* SHOPT_BRACEPAT */ 22474887Schin if(count) 22484887Schin mp->fields += count; 22494887Schin else if(split) /* pattern is null string */ 22504887Schin *argp->argval = 0; 22514887Schin else /* pattern expands to nothing */ 22524887Schin count = -1; 22534887Schin } 22544887Schin if(count==0) 22554887Schin { 22564887Schin argp->argchn.ap = *mp->arghead; 22574887Schin *mp->arghead = argp; 22584887Schin mp->fields++; 22594887Schin } 22604887Schin if(count>=0) 22614887Schin { 22624887Schin (*mp->arghead)->argflag |= ARG_MAKE; 22634887Schin if(mp->assign || sh_isoption(SH_NOGLOB)) 22644887Schin argp->argflag |= ARG_RAW|ARG_EXP; 22654887Schin } 22668462SApril.Chin@Sun.COM stkseek(stkp,ARGVAL); 22674887Schin } 22684887Schin mp->quoted = mp->quote; 22694887Schin } 22704887Schin 22714887Schin /* 22724887Schin * Finds the right substring of STRING using the expression PAT 22734887Schin * the longest substring is found when FLAG is set. 22744887Schin */ 22754887Schin static int substring(register const char *string,const char *pat,int match[], int flag) 22764887Schin { 22774887Schin register const char *sp=string; 22784887Schin register int size,len,nmatch,n; 22794887Schin int smatch[2*(MATCH_MAX+1)]; 22804887Schin if(flag) 22814887Schin { 22824887Schin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL)) 22834887Schin { 22844887Schin memcpy(match,smatch,n*2*sizeof(smatch[0])); 22854887Schin return(n); 22864887Schin } 22874887Schin return(0); 22884887Schin } 22894887Schin size = len = strlen(sp); 22904887Schin sp += size; 22914887Schin while(sp>=string) 22924887Schin { 22934887Schin #if SHOPT_MULTIBYTE 22944887Schin if(mbwide()) 22954887Schin sp = lastchar(string,sp); 22964887Schin #endif /* SHOPT_MULTIBYTE */ 22974887Schin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL)) 22984887Schin { 22994887Schin nmatch = n; 23004887Schin memcpy(match,smatch,n*2*sizeof(smatch[0])); 23014887Schin size = sp-string; 23024887Schin break; 23034887Schin } 23044887Schin sp--; 23054887Schin } 23064887Schin if(size==len) 23074887Schin return(0); 23084887Schin if(nmatch) 23094887Schin { 23104887Schin nmatch *=2; 23114887Schin while(--nmatch>=0) 23124887Schin match[nmatch] += size; 23134887Schin } 23144887Schin return(n); 23154887Schin } 23164887Schin 23174887Schin #if SHOPT_MULTIBYTE 23184887Schin static char *lastchar(const char *string, const char *endstring) 23194887Schin { 23204887Schin register char *str = (char*)string; 23214887Schin register int c; 23224887Schin mbinit(); 23234887Schin while(*str) 23244887Schin { 23254887Schin if((c=mbsize(str))<0) 23264887Schin c = 1; 23274887Schin if(str+c > endstring) 23284887Schin break; 23294887Schin str += c; 23304887Schin } 23314887Schin return(str); 23324887Schin } 23334887Schin #endif /* SHOPT_MULTIBYTE */ 23344887Schin static int charlen(const char *string,int len) 23354887Schin { 23364887Schin if(!string) 23374887Schin return(0); 23384887Schin #if SHOPT_MULTIBYTE 23394887Schin if(mbwide()) 23404887Schin { 23414887Schin register const char *str = string, *strmax=string+len; 23424887Schin register int n=0; 23434887Schin mbinit(); 23444887Schin if(len>0) 23454887Schin { 23464887Schin while(str<strmax && mbchar(str)) 23474887Schin n++; 23484887Schin } 23494887Schin else while(mbchar(str)) 23504887Schin n++; 23514887Schin return(n); 23524887Schin } 23534887Schin else 23544887Schin #endif /* SHOPT_MULTIBYTE */ 23554887Schin { 23564887Schin if(len<0) 23574887Schin return(strlen(string)); 23584887Schin return(len); 23594887Schin } 23604887Schin } 23614887Schin 23624887Schin /* 23634887Schin * This is the default tilde discipline function 23644887Schin */ 23654887Schin static int sh_btilde(int argc, char *argv[], void *context) 23664887Schin { 23678462SApril.Chin@Sun.COM Shell_t *shp = ((Shbltin_t*)context)->shp; 23688462SApril.Chin@Sun.COM char *cp = sh_tilde(shp,argv[1]); 23694887Schin NOT_USED(argc); 23704887Schin if(!cp) 23714887Schin cp = argv[1]; 23724887Schin sfputr(sfstdout, cp, '\n'); 23734887Schin return(0); 23744887Schin } 23754887Schin 23764887Schin /* 23774887Schin * <offset> is byte offset for beginning of tilde string 23784887Schin */ 23798462SApril.Chin@Sun.COM static void tilde_expand2(Shell_t *shp, register int offset) 23804887Schin { 23818462SApril.Chin@Sun.COM char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1); 23824887Schin Sfio_t *iop, *save=sfstdout; 23834887Schin Namval_t *np; 23844887Schin static int beenhere=0; 23854887Schin strcpy(shtilde,".sh.tilde"); 23868462SApril.Chin@Sun.COM np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL); 23874887Schin if(np && !beenhere) 23884887Schin { 23894887Schin beenhere = 1; 23904887Schin sh_addbuiltin(shtilde,sh_btilde,0); 23918462SApril.Chin@Sun.COM nv_onattr(np,NV_EXPORT); 23924887Schin } 23934887Schin av[0] = ".sh.tilde"; 23944887Schin av[1] = &ptr[offset]; 23954887Schin av[2] = 0; 23964887Schin iop = sftmp(IOBSIZE+1);; 23974887Schin sfset(iop,SF_READ,0); 23984887Schin sfstdout = iop; 23994887Schin if(np) 24004887Schin sh_fun(np, (Namval_t*)0, av); 24014887Schin else 24024887Schin sh_btilde(2, av, &sh); 24034887Schin sfstdout = save; 24048462SApril.Chin@Sun.COM stkset(shp->stk,ptr, offset); 24054887Schin sfseek(iop,(Sfoff_t)0,SEEK_SET); 24064887Schin sfset(iop,SF_READ,1); 24074887Schin if(ptr = sfreserve(iop, SF_UNBOUND, -1)) 24084887Schin { 24094887Schin Sfoff_t n = sfvalue(iop); 24104887Schin while(ptr[n-1]=='\n') 24114887Schin n--; 24124887Schin if(n==1 && fcpeek(0)=='/' && ptr[n-1]) 24134887Schin n--; 24144887Schin if(n) 24158462SApril.Chin@Sun.COM sfwrite(shp->stk,ptr,n); 24164887Schin } 24174887Schin else 24188462SApril.Chin@Sun.COM sfputr(shp->stk,av[1],0); 24194887Schin sfclose(iop); 24204887Schin } 24214887Schin 24224887Schin /* 24234887Schin * This routine is used to resolve ~ expansion. 24244887Schin * A ~ by itself is replaced with the users login directory. 24254887Schin * A ~- is replaced by the previous working directory in shell. 24264887Schin * A ~+ is replaced by the present working directory in shell. 24274887Schin * If ~name is replaced with login directory of name. 24284887Schin * If string doesn't start with ~ or ~... not found then 0 returned. 24294887Schin */ 24304887Schin 24318462SApril.Chin@Sun.COM static char *sh_tilde(Shell_t *shp,register const char *string) 24324887Schin { 24334887Schin register char *cp; 24344887Schin register int c; 24354887Schin register struct passwd *pw; 24364887Schin register Namval_t *np=0; 24374887Schin static Dt_t *logins_tree; 24384887Schin if(*string++!='~') 24394887Schin return(NIL(char*)); 24404887Schin if((c = *string)==0) 24414887Schin { 24428462SApril.Chin@Sun.COM if(!(cp=nv_getval(sh_scoped(shp,HOME)))) 24434887Schin cp = getlogin(); 24444887Schin return(cp); 24454887Schin } 24464887Schin if((c=='-' || c=='+') && string[1]==0) 24474887Schin { 24484887Schin if(c=='+') 24498462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,PWDNOD)); 24504887Schin else 24518462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,OLDPWDNOD)); 24524887Schin return(cp); 24534887Schin } 24544887Schin if(logins_tree && (np=nv_search(string,logins_tree,0))) 24554887Schin return(nv_getval(np)); 24564887Schin if(!(pw = getpwnam(string))) 24574887Schin return(NIL(char*)); 24584887Schin if(!logins_tree) 24594887Schin logins_tree = dtopen(&_Nvdisc,Dtbag); 24604887Schin if(np=nv_search(string,logins_tree,NV_ADD)) 24614887Schin nv_putval(np, pw->pw_dir,0); 24624887Schin return(pw->pw_dir); 24634887Schin } 24644887Schin 24654887Schin /* 24664887Schin * return values for special macros 24674887Schin */ 24688462SApril.Chin@Sun.COM static char *special(Shell_t *shp,register int c) 24694887Schin { 24704887Schin register Namval_t *np; 24714887Schin if(c!='$') 24728462SApril.Chin@Sun.COM shp->argaddr = 0; 24734887Schin switch(c) 24744887Schin { 24754887Schin case '@': 24764887Schin case '*': 24778462SApril.Chin@Sun.COM return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*)); 24784887Schin case '#': 24794887Schin #if SHOPT_FILESCAN 24808462SApril.Chin@Sun.COM if(shp->cur_line) 24814887Schin { 24828462SApril.Chin@Sun.COM getdolarg(shp,MAX_ARGN,(int*)0); 24838462SApril.Chin@Sun.COM return(ltos(shp->offsets[0])); 24844887Schin } 24854887Schin #endif /* SHOPT_FILESCAN */ 24868462SApril.Chin@Sun.COM return(ltos(shp->st.dolc)); 24874887Schin case '!': 24888462SApril.Chin@Sun.COM if(shp->bckpid) 24898462SApril.Chin@Sun.COM return(ltos(shp->bckpid)); 24904887Schin break; 24914887Schin case '$': 24924887Schin if(nv_isnull(SH_DOLLARNOD)) 24938462SApril.Chin@Sun.COM return(ltos(shp->pid)); 24944887Schin return(nv_getval(SH_DOLLARNOD)); 24954887Schin case '-': 24968462SApril.Chin@Sun.COM return(sh_argdolminus(shp->arg_context)); 24974887Schin case '?': 24988462SApril.Chin@Sun.COM return(ltos(shp->savexit)); 24994887Schin case 0: 25008462SApril.Chin@Sun.COM if(sh_isstate(SH_PROFILE) || !error_info.id || ((np=nv_search(error_info.id,shp->bltin_tree,0)) && nv_isattr(np,BLT_SPC))) 25018462SApril.Chin@Sun.COM return(shp->shname); 25024887Schin else 25034887Schin return(error_info.id); 25044887Schin } 25054887Schin return(NIL(char*)); 25064887Schin } 25074887Schin 25084887Schin /* 25094887Schin * Handle macro expansion errors 25104887Schin */ 25114887Schin static void mac_error(Namval_t *np) 25124887Schin { 25134887Schin if(np) 25144887Schin nv_close(np); 25154887Schin errormsg(SH_DICT,ERROR_exit(1),e_subst,fcfirst()); 25164887Schin } 25174887Schin 25184887Schin /* 25194887Schin * Given pattern/string, replace / with 0 and return pointer to string 25208462SApril.Chin@Sun.COM * \ characters are stripped from string. The \ are stripped in the 25218462SApril.Chin@Sun.COM * replacement string unless followed by a digit or \. 25224887Schin */ 25234887Schin static char *mac_getstring(char *pattern) 25244887Schin { 25258462SApril.Chin@Sun.COM register char *cp=pattern, *rep=0, *dp; 25268462SApril.Chin@Sun.COM register int c; 25274887Schin while(c = *cp++) 25284887Schin { 25298462SApril.Chin@Sun.COM if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp)))) 25308462SApril.Chin@Sun.COM { 25318462SApril.Chin@Sun.COM c = *cp++; 25328462SApril.Chin@Sun.COM } 25338462SApril.Chin@Sun.COM else if(!rep && c=='/') 25344887Schin { 25354887Schin cp[-1] = 0; 25368462SApril.Chin@Sun.COM rep = dp = cp; 25378462SApril.Chin@Sun.COM continue; 25384887Schin } 25398462SApril.Chin@Sun.COM if(rep) 25408462SApril.Chin@Sun.COM *dp++ = c; 25414887Schin } 25428462SApril.Chin@Sun.COM if(rep) 25438462SApril.Chin@Sun.COM *dp = 0; 25448462SApril.Chin@Sun.COM return(rep); 25454887Schin } 2546