14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * 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" 41*10898Sroland.mainz@nrubsig.org #include "jobs.h" 424887Schin #include "shnodes.h" 434887Schin #include "path.h" 444887Schin #include "national.h" 454887Schin #include "streval.h" 464887Schin 474887Schin #undef STR_GROUP 484887Schin #ifndef STR_GROUP 494887Schin # define STR_GROUP 0 504887Schin #endif 514887Schin 524887Schin #if !SHOPT_MULTIBYTE 534887Schin #define mbchar(p) (*(unsigned char*)p++) 544887Schin #endif 554887Schin 564887Schin static int _c_; 574887Schin typedef struct _mac_ 584887Schin { 594887Schin Shell_t *shp; /* pointer to shell interpreter */ 604887Schin Sfio_t *sp; /* stream pointer for here-document */ 614887Schin struct argnod **arghead; /* address of head of argument list */ 624887Schin char *ifsp; /* pointer to IFS value */ 634887Schin int fields; /* number of fields */ 644887Schin short quoted; /* set when word has quotes */ 654887Schin unsigned char ifs; /* first char of IFS */ 664887Schin char quote; /* set within double quoted contexts */ 674887Schin char lit; /* set within single quotes */ 684887Schin char split; /* set when word splittin is possible */ 694887Schin char pattern; /* set when file expansion follows */ 704887Schin char patfound; /* set if pattern character found */ 714887Schin char assign; /* set for assignments */ 724887Schin char arith; /* set for ((...)) */ 734887Schin char let; /* set when expanding let arguments */ 744887Schin char zeros; /* strip leading zeros when set */ 758462SApril.Chin@Sun.COM char arrayok; /* $x[] ok for arrays */ 768462SApril.Chin@Sun.COM char subcopy; /* set when copying subscript */ 778462SApril.Chin@Sun.COM int dotdot; /* set for .. in subscript */ 784887Schin void *nvwalk; /* for name space walking*/ 794887Schin } Mac_t; 804887Schin 814887Schin #undef ESCAPE 824887Schin #define ESCAPE '\\' 834887Schin #define isescchar(s) ((s)>S_QUOTE) 844887Schin #define isqescchar(s) ((s)>=S_QUOTE) 854887Schin #define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2) 864887Schin #define ltos(x) fmtbase((long)(x),0,0) 874887Schin 884887Schin /* type of macro expansions */ 894887Schin #define M_BRACE 1 /* ${var} */ 904887Schin #define M_TREE 2 /* ${var.} */ 914887Schin #define M_SIZE 3 /* ${#var} */ 924887Schin #define M_VNAME 4 /* ${!var} */ 934887Schin #define M_SUBNAME 5 /* ${!var[sub]} */ 944887Schin #define M_NAMESCAN 6 /* ${!var*} */ 954887Schin #define M_NAMECOUNT 7 /* ${#var*} */ 964887Schin #define M_TYPE 8 /* ${@var} */ 974887Schin 984887Schin static int substring(const char*, const char*, int[], int); 994887Schin static void copyto(Mac_t*, int, int); 1008462SApril.Chin@Sun.COM static void comsubst(Mac_t*, Shnode_t*, int); 1014887Schin static int varsub(Mac_t*); 1024887Schin static void mac_copy(Mac_t*,const char*, int); 1038462SApril.Chin@Sun.COM static void tilde_expand2(Shell_t*,int); 1048462SApril.Chin@Sun.COM static char *sh_tilde(Shell_t*,const char*); 1058462SApril.Chin@Sun.COM static char *special(Shell_t *,int); 1064887Schin static void endfield(Mac_t*,int); 1074887Schin static void mac_error(Namval_t*); 1084887Schin static char *mac_getstring(char*); 1094887Schin static int charlen(const char*,int); 1104887Schin #if SHOPT_MULTIBYTE 1114887Schin static char *lastchar(const char*,const char*); 1124887Schin #endif /* SHOPT_MULTIBYTE */ 1134887Schin 1144887Schin void *sh_macopen(Shell_t *shp) 1154887Schin { 1164887Schin void *addr = newof(0,Mac_t,1,0); 1174887Schin Mac_t *mp = (Mac_t*)addr; 1184887Schin mp->shp = shp; 1194887Schin return(addr); 1204887Schin } 1214887Schin 1224887Schin /* 1234887Schin * perform only parameter substitution and catch failures 1244887Schin */ 1258462SApril.Chin@Sun.COM char *sh_mactry(Shell_t *shp,register char *string) 1264887Schin { 1274887Schin if(string) 1284887Schin { 1294887Schin int jmp_val; 1308462SApril.Chin@Sun.COM int savexit = shp->savexit; 1314887Schin struct checkpt buff; 1324887Schin sh_pushcontext(&buff,SH_JMPSUB); 1334887Schin jmp_val = sigsetjmp(buff.buff,0); 1344887Schin if(jmp_val == 0) 1358462SApril.Chin@Sun.COM string = sh_mactrim(shp,string,0); 1364887Schin sh_popcontext(&buff); 1378462SApril.Chin@Sun.COM shp->savexit = savexit; 1384887Schin return(string); 1394887Schin } 1404887Schin return(""); 1414887Schin } 1424887Schin 1434887Schin /* 1444887Schin * Perform parameter expansion, command substitution, and arithmetic 1454887Schin * expansion on <str>. 1464887Schin * If <mode> greater than 1 file expansion is performed if the result 1474887Schin * yields a single pathname. 1484887Schin * If <mode> negative, than expansion rules for assignment are applied. 1494887Schin */ 1508462SApril.Chin@Sun.COM char *sh_mactrim(Shell_t *shp, char *str, register int mode) 1514887Schin { 1528462SApril.Chin@Sun.COM register Mac_t *mp = (Mac_t*)shp->mac_context; 1538462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 1548462SApril.Chin@Sun.COM Mac_t savemac; 1554887Schin savemac = *mp; 1568462SApril.Chin@Sun.COM stkseek(stkp,0); 1574887Schin mp->arith = (mode==3); 1584887Schin mp->let = 0; 1598462SApril.Chin@Sun.COM shp->argaddr = 0; 1604887Schin mp->pattern = (mode==1||mode==2); 1614887Schin mp->patfound = 0; 1628462SApril.Chin@Sun.COM mp->assign = 0; 1638462SApril.Chin@Sun.COM if(mode<0) 1648462SApril.Chin@Sun.COM mp->assign = -mode; 1654887Schin mp->quoted = mp->lit = mp->split = mp->quote = 0; 1664887Schin mp->sp = 0; 1678462SApril.Chin@Sun.COM if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD))) 1684887Schin mp->ifs = *mp->ifsp; 1694887Schin else 1704887Schin mp->ifs = ' '; 1718462SApril.Chin@Sun.COM stkseek(stkp,0); 1724887Schin fcsopen(str); 1734887Schin copyto(mp,0,mp->arith); 1748462SApril.Chin@Sun.COM str = stkfreeze(stkp,1); 1754887Schin if(mode==2) 1764887Schin { 1774887Schin /* expand only if unique */ 1784887Schin struct argnod *arglist=0; 1794887Schin if((mode=path_expand(str,&arglist))==1) 1804887Schin str = arglist->argval; 1814887Schin else if(mode>1) 1824887Schin errormsg(SH_DICT,ERROR_exit(1),e_ambiguous,str); 1834887Schin sh_trim(str); 1844887Schin } 1854887Schin *mp = savemac; 1864887Schin return(str); 1874887Schin } 1884887Schin 1894887Schin /* 1904887Schin * Perform all the expansions on the argument <argp> 1914887Schin */ 1928462SApril.Chin@Sun.COM int sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag) 1934887Schin { 1948462SApril.Chin@Sun.COM register int flags = argp->argflag; 1958462SApril.Chin@Sun.COM register char *str = argp->argval; 1968462SApril.Chin@Sun.COM register Mac_t *mp = (Mac_t*)shp->mac_context; 1978462SApril.Chin@Sun.COM char **saveargaddr = shp->argaddr; 1988462SApril.Chin@Sun.COM Mac_t savemac; 1998462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 2004887Schin savemac = *mp; 2014887Schin mp->sp = 0; 2028462SApril.Chin@Sun.COM if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD))) 2034887Schin mp->ifs = *mp->ifsp; 2044887Schin else 2054887Schin mp->ifs = ' '; 2068462SApril.Chin@Sun.COM if((flag&ARG_OPTIMIZE) && !shp->indebug) 2078462SApril.Chin@Sun.COM shp->argaddr = (char**)&argp->argchn.ap; 2084887Schin else 2098462SApril.Chin@Sun.COM shp->argaddr = 0; 2104887Schin mp->arghead = arghead; 2114887Schin mp->quoted = mp->lit = mp->quote = 0; 2124887Schin mp->arith = ((flag&ARG_ARITH)!=0); 2134887Schin mp->let = ((flag&ARG_LET)!=0); 2144887Schin mp->split = !(flag&ARG_ASSIGN); 2154887Schin mp->assign = !mp->split; 2164887Schin mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB); 2178462SApril.Chin@Sun.COM mp->arrayok = mp->arith || (flag&ARG_ARRAYOK); 2184887Schin str = argp->argval; 2194887Schin fcsopen(str); 2204887Schin mp->fields = 0; 2214887Schin if(!arghead) 2224887Schin { 2234887Schin mp->split = 0; 2244887Schin mp->pattern = ((flag&ARG_EXP)!=0); 2258462SApril.Chin@Sun.COM stkseek(stkp,0); 2264887Schin } 2274887Schin else 2284887Schin { 2298462SApril.Chin@Sun.COM stkseek(stkp,ARGVAL); 2308462SApril.Chin@Sun.COM *stkptr(stkp,ARGVAL-1) = 0; 2314887Schin } 2324887Schin mp->patfound = 0; 2338462SApril.Chin@Sun.COM if(mp->pattern) 2348462SApril.Chin@Sun.COM mp->arrayok = 0; 2354887Schin copyto(mp,0,mp->arith); 2364887Schin if(!arghead) 2374887Schin { 2388462SApril.Chin@Sun.COM argp->argchn.cp = stkfreeze(stkp,1); 2398462SApril.Chin@Sun.COM if(shp->argaddr) 2404887Schin argp->argflag |= ARG_MAKE; 2414887Schin } 2424887Schin else 2434887Schin { 2444887Schin endfield(mp,mp->quoted); 2454887Schin flags = mp->fields; 2468462SApril.Chin@Sun.COM if(flags==1 && shp->argaddr) 2474887Schin argp->argchn.ap = *arghead; 2484887Schin } 2498462SApril.Chin@Sun.COM shp->argaddr = saveargaddr; 2504887Schin *mp = savemac; 2514887Schin return(flags); 2524887Schin } 2534887Schin 2544887Schin /* 2554887Schin * Expand here document which is stored in <infile> or <string> 2564887Schin * The result is written to <outfile> 2574887Schin */ 2588462SApril.Chin@Sun.COM void sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string) 2594887Schin { 2604887Schin register int c,n; 2614887Schin register const char *state = sh_lexstates[ST_QUOTE]; 2624887Schin register char *cp; 2638462SApril.Chin@Sun.COM register Mac_t *mp = (Mac_t*)shp->mac_context; 2648462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)mp->shp->lex_context; 2654887Schin Fcin_t save; 2664887Schin Mac_t savemac; 2678462SApril.Chin@Sun.COM Stk_t *stkp = shp->stk; 2684887Schin savemac = *mp; 2698462SApril.Chin@Sun.COM stkseek(stkp,0); 2708462SApril.Chin@Sun.COM shp->argaddr = 0; 2714887Schin mp->sp = outfile; 2724887Schin mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0; 2734887Schin mp->quote = 1; 2748462SApril.Chin@Sun.COM mp->ifsp = nv_getval(sh_scoped(shp,IFSNOD)); 2754887Schin mp->ifs = ' '; 2764887Schin fcsave(&save); 2774887Schin if(infile) 2784887Schin fcfopen(infile); 2794887Schin else 2804887Schin fcsopen(string); 2818462SApril.Chin@Sun.COM fcnotify(0,lp); 2824887Schin cp = fcseek(0); 2834887Schin while(1) 2844887Schin { 2854887Schin #if SHOPT_MULTIBYTE 2864887Schin if(mbwide()) 2874887Schin { 2884887Schin do 2894887Schin { 2904887Schin ssize_t len; 2914887Schin switch(len = mbsize(cp)) 2924887Schin { 2934887Schin case -1: /* illegal multi-byte char */ 2944887Schin case 0: 2954887Schin case 1: 2964887Schin n=state[*(unsigned char*)cp++]; 2974887Schin break; 2984887Schin default: 2998462SApril.Chin@Sun.COM /* use state of alpha character */ 3004887Schin n=state['a']; 3014887Schin cp += len; 3024887Schin } 3034887Schin } 3044887Schin while(n == 0); 3054887Schin } 3064887Schin else 3074887Schin #endif /* SHOPT_MULTIBYTE */ 3084887Schin while((n=state[*(unsigned char*)cp++])==0); 3094887Schin if(n==S_NL || n==S_QUOTE || n==S_RBRA) 3104887Schin continue; 3114887Schin if(c=(cp-1)-fcseek(0)) 3124887Schin sfwrite(outfile,fcseek(0),c); 3134887Schin cp = fcseek(c+1); 3144887Schin switch(n) 3154887Schin { 3164887Schin case S_EOF: 3174887Schin if((n=fcfill()) <=0) 3184887Schin { 3194887Schin /* ignore 0 byte when reading from file */ 3204887Schin if(n==0 && fcfile()) 3214887Schin continue; 3224887Schin fcrestore(&save); 3234887Schin *mp = savemac; 3244887Schin return; 3254887Schin } 3264887Schin cp = fcseek(-1); 3274887Schin continue; 3284887Schin case S_ESC: 3294887Schin fcgetc(c); 3304887Schin cp=fcseek(-1); 3314887Schin if(c>0) 3324887Schin cp++; 3334887Schin if(!isescchar(state[c])) 3344887Schin sfputc(outfile,ESCAPE); 3354887Schin continue; 3364887Schin case S_GRAVE: 3378462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,0); 3384887Schin break; 3394887Schin case S_DOL: 3404887Schin c = fcget(); 3414887Schin if(c=='.') 3424887Schin goto regular; 3434887Schin again: 3444887Schin switch(n=sh_lexstates[ST_DOL][c]) 3454887Schin { 3464887Schin case S_ALP: case S_SPC1: case S_SPC2: 3474887Schin case S_DIG: case S_LBRA: 3484887Schin { 3494887Schin Fcin_t save2; 3508462SApril.Chin@Sun.COM int offset = stktell(stkp); 3514887Schin int offset2; 3528462SApril.Chin@Sun.COM sfputc(stkp,c); 3534887Schin if(n==S_LBRA) 3548462SApril.Chin@Sun.COM { 3558462SApril.Chin@Sun.COM c = fcget(); 3568462SApril.Chin@Sun.COM fcseek(-1); 3578462SApril.Chin@Sun.COM if(sh_lexstates[ST_NORM][c]==S_BREAK) 3588462SApril.Chin@Sun.COM { 3598462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,2); 3608462SApril.Chin@Sun.COM break; 3618462SApril.Chin@Sun.COM } 3628462SApril.Chin@Sun.COM sh_lexskip(lp,RBRACE,1,ST_BRACE); 3638462SApril.Chin@Sun.COM } 3644887Schin else if(n==S_ALP) 3654887Schin { 3664887Schin while(fcgetc(c),isaname(c)) 3678462SApril.Chin@Sun.COM sfputc(stkp,c); 3684887Schin fcseek(-1); 3694887Schin } 3708462SApril.Chin@Sun.COM sfputc(stkp,0); 3718462SApril.Chin@Sun.COM offset2 = stktell(stkp); 3724887Schin fcsave(&save2); 3738462SApril.Chin@Sun.COM fcsopen(stkptr(stkp,offset)); 3744887Schin varsub(mp); 3758462SApril.Chin@Sun.COM if(c=stktell(stkp)-offset2) 3768462SApril.Chin@Sun.COM sfwrite(outfile,(char*)stkptr(stkp,offset2),c); 3774887Schin fcrestore(&save2); 3788462SApril.Chin@Sun.COM stkseek(stkp,offset); 3794887Schin break; 3804887Schin } 3814887Schin case S_PAR: 3828462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,1); 3834887Schin break; 3844887Schin case S_EOF: 3854887Schin if((c=fcfill()) > 0) 3864887Schin goto again; 3874887Schin /* FALL THRU */ 3884887Schin default: 3894887Schin regular: 3904887Schin sfputc(outfile,'$'); 3914887Schin fcseek(-1); 3924887Schin break; 3934887Schin } 3944887Schin } 3954887Schin cp = fcseek(0); 3964887Schin } 3974887Schin } 3984887Schin 3994887Schin /* 4004887Schin * expand argument but do not trim pattern characters 4014887Schin */ 4028462SApril.Chin@Sun.COM char *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags) 4034887Schin { 4044887Schin register char *sp = arg->argval; 4054887Schin if((arg->argflag&ARG_RAW)) 4064887Schin return(sp); 4078462SApril.Chin@Sun.COM sh_stats(STAT_ARGEXPAND); 4084887Schin if(flags&ARG_OPTIMIZE) 4094887Schin arg->argchn.ap=0; 4104887Schin if(!(sp=arg->argchn.cp)) 4114887Schin { 4128462SApril.Chin@Sun.COM sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK); 4134887Schin sp = arg->argchn.cp; 4144887Schin if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE)) 4154887Schin arg->argchn.cp = 0; 4164887Schin arg->argflag &= ~ARG_MAKE; 4174887Schin } 4184887Schin else 4198462SApril.Chin@Sun.COM sh_stats(STAT_ARGHITS); 4204887Schin return(sp); 4214887Schin } 4224887Schin 4234887Schin /* 4244887Schin * Process the characters up to <endch> or end of input string 4254887Schin */ 4264887Schin static void copyto(register Mac_t *mp,int endch, int newquote) 4274887Schin { 4284887Schin register int c,n; 4294887Schin register const char *state = sh_lexstates[ST_MACRO]; 4304887Schin register char *cp,*first; 4318462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)mp->shp->lex_context; 4324887Schin int tilde = -1; 4334887Schin int oldquote = mp->quote; 4344887Schin int ansi_c = 0; 4354887Schin int paren = 0; 4364887Schin int ere = 0; 4374887Schin int brace = 0; 4384887Schin Sfio_t *sp = mp->sp; 4398462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 4404887Schin mp->sp = NIL(Sfio_t*); 4414887Schin mp->quote = newquote; 4424887Schin first = cp = fcseek(0); 4438900SCasper.Dik@Sun.COM if(!mp->quote && *cp=='~' && cp[1]!=LPAREN) 4448462SApril.Chin@Sun.COM tilde = stktell(stkp); 4454887Schin /* handle // operator specially */ 4464887Schin if(mp->pattern==2 && *cp=='/') 4474887Schin cp++; 4484887Schin while(1) 4494887Schin { 4504887Schin #if SHOPT_MULTIBYTE 4514887Schin if(mbwide()) 4524887Schin { 4534887Schin ssize_t len; 4544887Schin do 4554887Schin { 4564887Schin switch(len = mbsize(cp)) 4574887Schin { 4584887Schin case -1: /* illegal multi-byte char */ 4594887Schin case 0: 4604887Schin len = 1; 4614887Schin case 1: 4624887Schin n = state[*(unsigned char*)cp++]; 4634887Schin break; 4644887Schin default: 4654887Schin /* treat as if alpha */ 4664887Schin cp += len; 4674887Schin n=state['a']; 4684887Schin } 4694887Schin } 4704887Schin while(n == 0); 4714887Schin c = (cp-len) - first; 4724887Schin } 4734887Schin else 4744887Schin #endif /* SHOPT_MULTIBYTE */ 4754887Schin { 4764887Schin while((n=state[*(unsigned char*)cp++])==0); 4774887Schin c = (cp-1) - first; 4784887Schin } 4794887Schin switch(n) 4804887Schin { 4814887Schin case S_ESC: 4824887Schin if(ansi_c) 4834887Schin { 4844887Schin /* process ANSI-C escape character */ 4854887Schin char *addr= --cp; 4864887Schin if(c) 4878462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 4884887Schin c = chresc(cp,&addr); 4894887Schin cp = addr; 4904887Schin first = fcseek(cp-first); 4914887Schin #if SHOPT_MULTIBYTE 4924887Schin if(c > UCHAR_MAX && mbwide()) 4934887Schin { 4944887Schin int i; 4954887Schin unsigned char mb[8]; 4964887Schin 4974887Schin n = wctomb((char*)mb, c); 4984887Schin for(i=0;i<n;i++) 4998462SApril.Chin@Sun.COM sfputc(stkp,mb[i]); 5004887Schin } 5014887Schin else 5024887Schin #endif /* SHOPT_MULTIBYTE */ 5038462SApril.Chin@Sun.COM sfputc(stkp,c); 5044887Schin if(c==ESCAPE && mp->pattern) 5058462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 5064887Schin break; 5074887Schin } 5084887Schin else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.')) 5094887Schin break; 5104887Schin else if(mp->split && endch && !mp->quote && !mp->lit) 5114887Schin { 5124887Schin if(c) 5134887Schin mac_copy(mp,first,c); 5144887Schin cp = fcseek(c+2); 5154887Schin if(c= cp[-1]) 5164887Schin { 5178462SApril.Chin@Sun.COM sfputc(stkp,c); 5184887Schin if(c==ESCAPE) 5198462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 5204887Schin } 5214887Schin else 5224887Schin cp--; 5234887Schin first = cp; 5244887Schin break; 5254887Schin } 5264887Schin n = state[*(unsigned char*)cp]; 5274887Schin if(n==S_ENDCH && *cp!=endch) 5284887Schin n = S_PAT; 5294887Schin if(mp->pattern) 5304887Schin { 5314887Schin /* preserve \digit for pattern matching */ 5324887Schin /* also \alpha for extended patterns */ 533*10898Sroland.mainz@nrubsig.org if(!mp->lit && !mp->quote) 534*10898Sroland.mainz@nrubsig.org { 535*10898Sroland.mainz@nrubsig.org if((n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP))) 536*10898Sroland.mainz@nrubsig.org break; 537*10898Sroland.mainz@nrubsig.org if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp)) 538*10898Sroland.mainz@nrubsig.org break; 539*10898Sroland.mainz@nrubsig.org } 5404887Schin /* followed by file expansion */ 5414887Schin if(!mp->lit && (n==S_ESC || (!mp->quote && 5424887Schin (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-')))) 5434887Schin { 5444887Schin cp += (n!=S_EOF); 5458462SApril.Chin@Sun.COM if(ere && n==S_ESC && *cp =='\\' && cp[1]=='$') 5468462SApril.Chin@Sun.COM { 5478462SApril.Chin@Sun.COM /* convert \\\$ into \$' */ 5488462SApril.Chin@Sun.COM sfwrite(stkp,first,c+1); 5498462SApril.Chin@Sun.COM cp = first = fcseek(c+3); 5508462SApril.Chin@Sun.COM } 5514887Schin break; 5524887Schin } 5538462SApril.Chin@Sun.COM if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH))) 5544887Schin { 5554887Schin /* add \ for file expansion */ 5568462SApril.Chin@Sun.COM sfwrite(stkp,first,c+1); 5574887Schin first = fcseek(c); 5584887Schin break; 5594887Schin } 5604887Schin } 5614887Schin if(mp->lit) 5624887Schin break; 5634887Schin if(!mp->quote || isqescchar(n) || n==S_ENDCH) 5644887Schin { 5654887Schin /* eliminate \ */ 5664887Schin if(c) 5678462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 5684887Schin /* check new-line joining */ 5694887Schin first = fcseek(c+1); 5704887Schin } 5714887Schin cp += (n!=S_EOF); 5724887Schin break; 5734887Schin case S_GRAVE: case S_DOL: 5744887Schin if(mp->lit) 5754887Schin break; 5764887Schin if(c) 5774887Schin { 5784887Schin if(mp->split && !mp->quote && endch) 5794887Schin mac_copy(mp,first,c); 5804887Schin else 5818462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 5824887Schin } 5834887Schin first = fcseek(c+1); 5844887Schin c = mp->pattern; 5854887Schin if(n==S_GRAVE) 5868462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,0); 5874887Schin else if((n= *cp)==0 || !varsub(mp)) 5884887Schin { 5894887Schin if(n=='\'' && !mp->quote) 5904887Schin ansi_c = 1; 5914887Schin else if(mp->quote || n!='"') 5928462SApril.Chin@Sun.COM sfputc(stkp,'$'); 5934887Schin } 5944887Schin cp = first = fcseek(0); 5954887Schin if(*cp) 5964887Schin mp->pattern = c; 5974887Schin break; 5984887Schin case S_ENDCH: 5994887Schin if((mp->lit || cp[-1]!=endch || mp->quote!=newquote)) 6004887Schin goto pattern; 6014887Schin if(endch==RBRACE && *cp==LPAREN && mp->pattern && brace) 6024887Schin goto pattern; 6034887Schin case S_EOF: 6044887Schin if(c) 6054887Schin { 6064887Schin if(mp->split && !mp->quote && !mp->lit && endch) 6074887Schin mac_copy(mp,first,c); 6084887Schin else 6098462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 6104887Schin } 6114887Schin c += (n!=S_EOF); 6124887Schin first = fcseek(c); 6134887Schin if(tilde>=0) 6148462SApril.Chin@Sun.COM tilde_expand2(mp->shp,tilde); 6154887Schin goto done; 6164887Schin case S_QUOTE: 6174887Schin if(mp->lit || mp->arith) 6184887Schin break; 6194887Schin case S_LIT: 6204887Schin if(mp->arith) 6214887Schin { 6224887Schin if((*cp=='`' || *cp=='[') && cp[1]=='\'') 6234887Schin cp +=2; 6244887Schin break; 6254887Schin } 6264887Schin if(n==S_LIT && mp->quote) 6274887Schin break; 6284887Schin if(c) 6294887Schin { 6304887Schin if(mp->split && endch && !mp->quote && !mp->lit) 6314887Schin mac_copy(mp,first,c); 6324887Schin else 6338462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 6344887Schin } 6354887Schin first = fcseek(c+1); 6364887Schin if(n==S_LIT) 6374887Schin { 6384887Schin if(mp->quote) 6394887Schin continue; 6404887Schin if(mp->lit) 6414887Schin mp->lit = ansi_c = 0; 6424887Schin else 6434887Schin mp->lit = 1; 6444887Schin } 6454887Schin else 6464887Schin mp->quote = !mp->quote; 6474887Schin mp->quoted++; 6484887Schin break; 6494887Schin case S_BRACT: 6508462SApril.Chin@Sun.COM if(mp->arith || (((mp->assign&1) || endch==RBRACT) && 6514887Schin !(mp->quote || mp->lit))) 6524887Schin { 6534887Schin int offset=0,oldpat = mp->pattern; 6548462SApril.Chin@Sun.COM int oldarith = mp->arith, oldsub=mp->subcopy; 6558462SApril.Chin@Sun.COM sfwrite(stkp,first,++c); 656*10898Sroland.mainz@nrubsig.org if(mp->assign&1) 657*10898Sroland.mainz@nrubsig.org { 658*10898Sroland.mainz@nrubsig.org if(first[c-2]=='.') 659*10898Sroland.mainz@nrubsig.org offset = stktell(stkp); 660*10898Sroland.mainz@nrubsig.org if(isastchar(*cp) && cp[1]==']') 661*10898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_exit(1), 662*10898Sroland.mainz@nrubsig.org e_badsubscript,*cp); 663*10898Sroland.mainz@nrubsig.org } 6644887Schin first = fcseek(c); 6654887Schin mp->pattern = 4; 6664887Schin mp->arith = 0; 6678462SApril.Chin@Sun.COM mp->subcopy = 0; 6684887Schin copyto(mp,RBRACT,0); 6698462SApril.Chin@Sun.COM mp->subcopy = oldsub; 6704887Schin mp->arith = oldarith; 6714887Schin mp->pattern = oldpat; 6728462SApril.Chin@Sun.COM sfputc(stkp,RBRACT); 6734887Schin if(offset) 6744887Schin { 6758462SApril.Chin@Sun.COM cp = stkptr(stkp,stktell(stkp)); 6768462SApril.Chin@Sun.COM if(sh_checkid(stkptr(stkp,offset),cp)!=cp) 6778462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-2); 6784887Schin } 6794887Schin cp = first = fcseek(0); 6804887Schin break; 6814887Schin } 6824887Schin case S_PAT: 6834887Schin if(mp->pattern && !(mp->quote || mp->lit)) 6844887Schin { 6854887Schin mp->patfound = mp->pattern; 6864887Schin if((n=cp[-1])==LPAREN) 6874887Schin { 6884887Schin paren++; 6894887Schin if((cp-first)>1 && cp[-2]=='~') 6904887Schin { 6914887Schin char *p = cp; 6924887Schin while((c=mbchar(p)) && c!=RPAREN && c!='E'); 693*10898Sroland.mainz@nrubsig.org ere = (c=='E'||c=='A'); 6944887Schin } 6954887Schin } 6964887Schin else if(n==RPAREN) 6974887Schin --paren; 6984887Schin } 6994887Schin goto pattern; 7008462SApril.Chin@Sun.COM case S_COM: 7018462SApril.Chin@Sun.COM if(mp->pattern==4 && (mp->quote || mp->lit)) 7028462SApril.Chin@Sun.COM { 7038462SApril.Chin@Sun.COM if(c) 7048462SApril.Chin@Sun.COM { 7058462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 7068462SApril.Chin@Sun.COM first = fcseek(c); 7078462SApril.Chin@Sun.COM } 7088462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 7098462SApril.Chin@Sun.COM } 7108462SApril.Chin@Sun.COM break; 7114887Schin case S_BRACE: 7124887Schin if(!(mp->quote || mp->lit)) 7134887Schin { 7144887Schin mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND); 7154887Schin brace = 1; 7164887Schin } 7174887Schin pattern: 7184887Schin if(!mp->pattern || !(mp->quote || mp->lit)) 7194887Schin { 7204887Schin /* mark beginning of {a,b} */ 7214887Schin if(n==S_BRACE && endch==0 && mp->pattern) 7224887Schin mp->pattern=4; 7234887Schin if(n==S_SLASH && mp->pattern==2) 7244887Schin mp->pattern=3; 7254887Schin break; 7264887Schin } 7274887Schin if(mp->pattern==3) 7284887Schin break; 7294887Schin if(c) 7308462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 7314887Schin first = fcseek(c); 7328462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 7334887Schin break; 7344887Schin case S_EQ: 7354887Schin if(mp->assign==1) 7364887Schin { 7374887Schin if(*cp=='~' && !endch && !mp->quote && !mp->lit) 7388462SApril.Chin@Sun.COM tilde = stktell(stkp)+(c+1); 7394887Schin mp->assign = 2; 7404887Schin } 7414887Schin break; 7424887Schin case S_SLASH: 7434887Schin case S_COLON: 7444887Schin if(tilde >=0) 7454887Schin { 7464887Schin if(c) 7478462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 7484887Schin first = fcseek(c); 7498462SApril.Chin@Sun.COM tilde_expand2(mp->shp,tilde); 7504887Schin tilde = -1; 7514887Schin c=0; 7524887Schin } 7534887Schin if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit) 7548462SApril.Chin@Sun.COM tilde = stktell(stkp)+(c+1); 7554887Schin else if(n==S_SLASH && mp->pattern==2) 7564887Schin #if 0 7574887Schin goto pattern; 7584887Schin #else 7594887Schin { 7604887Schin if(mp->quote || mp->lit) 7614887Schin goto pattern; 7628462SApril.Chin@Sun.COM sfwrite(stkp,first,c+1); 7634887Schin first = fcseek(c+1); 7648462SApril.Chin@Sun.COM c = stktell(stkp); 7658462SApril.Chin@Sun.COM sh_lexskip(lp,RBRACE,0,ST_NESTED); 7668462SApril.Chin@Sun.COM stkseek(stkp,c); 7674887Schin cp = fcseek(-1); 7688462SApril.Chin@Sun.COM sfwrite(stkp,first,cp-first); 7694887Schin first=cp; 7704887Schin } 7714887Schin #endif 7724887Schin break; 7738462SApril.Chin@Sun.COM case S_DOT: 7748462SApril.Chin@Sun.COM if(*cp=='.' && mp->subcopy==1) 7758462SApril.Chin@Sun.COM { 7768462SApril.Chin@Sun.COM sfwrite(stkp,first,c); 7778462SApril.Chin@Sun.COM sfputc(stkp,0); 7788462SApril.Chin@Sun.COM mp->dotdot = stktell(stkp); 7798462SApril.Chin@Sun.COM cp = first = fcseek(c+2); 7808462SApril.Chin@Sun.COM } 7818462SApril.Chin@Sun.COM break; 7824887Schin } 7834887Schin } 7844887Schin done: 7854887Schin mp->sp = sp; 7864887Schin mp->quote = oldquote; 7874887Schin } 7884887Schin 7894887Schin /* 7904887Schin * copy <str> to stack performing sub-expression substitutions 7914887Schin */ 7924887Schin static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize) 7934887Schin { 7948462SApril.Chin@Sun.COM register int c,n; 7954887Schin register char *first=fcseek(0); 7968462SApril.Chin@Sun.COM char *ptr; 7978462SApril.Chin@Sun.COM Mac_t savemac; 7988462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 7998462SApril.Chin@Sun.COM n = stktell(stkp); 8004887Schin savemac = *mp; 8014887Schin mp->pattern = 3; 8024887Schin mp->split = 0; 8034887Schin fcsopen(cp); 8044887Schin copyto(mp,0,0); 8058462SApril.Chin@Sun.COM sfputc(stkp,0); 8068462SApril.Chin@Sun.COM ptr = cp = strdup(stkptr(stkp,n)); 8078462SApril.Chin@Sun.COM stkseek(stkp,n); 8084887Schin *mp = savemac; 8094887Schin fcsopen(first); 8104887Schin first = cp; 8114887Schin while(1) 8124887Schin { 8134887Schin while((c= *cp++) && c!=ESCAPE); 8144887Schin if(c==0) 8154887Schin break; 8164887Schin if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize)) 8174887Schin { 8184887Schin c = cp-first-2; 8194887Schin if(c) 8204887Schin mac_copy(mp,first,c); 8214887Schin first=cp; 8224887Schin if(n=='\\' || n==RBRACE) 8234887Schin { 8244887Schin first--; 8254887Schin continue; 8264887Schin } 8274887Schin if((c=subexp[2*n])>=0) 8284887Schin { 8294887Schin if((n=subexp[2*n+1]-c)>0) 8304887Schin mac_copy(mp,str+c,n); 8314887Schin } 8324887Schin } 8334887Schin else if(n==0) 8344887Schin break; 8354887Schin } 8364887Schin if(n=cp-first-1) 8374887Schin mac_copy(mp,first,n); 8384887Schin free(ptr); 8394887Schin } 8404887Schin 8414887Schin #if SHOPT_FILESCAN 8424887Schin #define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0])) 8434887Schin #define MAX_ARGN (32*1024) 8444887Schin 8454887Schin /* 8464887Schin * compute the arguments $1 ... $n and $# from the current line as needed 8474887Schin * save line offsets in the offsets array. 8484887Schin */ 8494887Schin static char *getdolarg(Shell_t *shp, int n, int *size) 8504887Schin { 8514887Schin register int c=S_DELIM, d=shp->ifstable['\\']; 8524887Schin register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line; 8534887Schin register int m=shp->offsets[0],delim=0; 8544887Schin if(m==0) 8554887Schin return(0); 8564887Schin if(m<0) 8574887Schin m = 0; 8584887Schin else if(n<=m) 8594887Schin m = n-1; 8604887Schin else 8614887Schin m--; 8624887Schin if(m >= MAX_OFFSETS-1) 8634887Schin m = MAX_OFFSETS-2; 8644887Schin cp += shp->offsets[m+1]; 8654887Schin n -= m; 8664887Schin shp->ifstable['\\'] = 0; 8674887Schin shp->ifstable[0] = S_EOF; 8684887Schin while(1) 8694887Schin { 8704887Schin if(c==S_DELIM) 8714887Schin while(shp->ifstable[*cp++]==S_SPACE); 8724887Schin first = --cp; 8734887Schin if(++m < MAX_OFFSETS) 8744887Schin shp->offsets[m] = (first-(unsigned char*)shp->cur_line); 8754887Schin while((c=shp->ifstable[*cp++])==0); 8764887Schin last = cp-1; 8774887Schin if(c==S_SPACE) 8784887Schin while((c=shp->ifstable[*cp++])==S_SPACE); 8794887Schin if(--n==0 || c==S_EOF) 8804887Schin { 8814887Schin if(last==first && c==S_EOF && (!delim || (m>1))) 8824887Schin { 8834887Schin n++; 8844887Schin m--; 8854887Schin } 8864887Schin break; 8874887Schin } 8884887Schin delim = (c==S_DELIM); 8894887Schin } 8904887Schin shp->ifstable['\\'] = d; 8914887Schin if(m > shp->offsets[0]) 8924887Schin shp->offsets[0] = m; 8934887Schin if(n) 8944887Schin first = last = 0; 8954887Schin if(size) 8964887Schin *size = last-first; 8974887Schin return((char*)first); 8984887Schin } 8994887Schin #endif /* SHOPT_FILESCAN */ 9004887Schin 9014887Schin /* 9024887Schin * get the prefix after name reference resolution 9034887Schin */ 9048462SApril.Chin@Sun.COM static char *prefix(Shell_t *shp, char *id) 9054887Schin { 9064887Schin Namval_t *np; 907*10898Sroland.mainz@nrubsig.org register char *sub=0, *cp = strchr(id,'.'); 9084887Schin if(cp) 9094887Schin { 9104887Schin *cp = 0; 9118462SApril.Chin@Sun.COM np = nv_search(id, shp->var_tree,0); 9124887Schin *cp = '.'; 9134887Schin if(isastchar(cp[1])) 9144887Schin cp[1] = 0; 9154887Schin if(np && nv_isref(np)) 9164887Schin { 9174887Schin int n; 9184887Schin char *sp; 9198462SApril.Chin@Sun.COM shp->argaddr = 0; 920*10898Sroland.mainz@nrubsig.org while(nv_isref(np) && np->nvalue.cp) 921*10898Sroland.mainz@nrubsig.org { 922*10898Sroland.mainz@nrubsig.org sub = nv_refsub(np); 9234887Schin np = nv_refnode(np); 924*10898Sroland.mainz@nrubsig.org if(sub) 925*10898Sroland.mainz@nrubsig.org nv_putsub(np,sub,0L); 926*10898Sroland.mainz@nrubsig.org } 927*10898Sroland.mainz@nrubsig.org id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1)); 928*10898Sroland.mainz@nrubsig.org memcpy(id,sp,n); 929*10898Sroland.mainz@nrubsig.org if(sub) 930*10898Sroland.mainz@nrubsig.org { 931*10898Sroland.mainz@nrubsig.org id[n++] = '['; 932*10898Sroland.mainz@nrubsig.org strcpy(&id[n],sub); 933*10898Sroland.mainz@nrubsig.org n+= strlen(sub)+1; 934*10898Sroland.mainz@nrubsig.org id[n-1] = ']'; 935*10898Sroland.mainz@nrubsig.org } 9364887Schin strcpy(&id[n],cp); 9374887Schin return(id); 9384887Schin } 9394887Schin } 9404887Schin return(strdup(id)); 9414887Schin } 9424887Schin 9434887Schin /* 9444887Schin * copy to ']' onto the stack and return offset to it 9454887Schin */ 9464887Schin static int subcopy(Mac_t *mp, int flag) 9474887Schin { 9484887Schin int split = mp->split; 9494887Schin int xpattern = mp->pattern; 9508462SApril.Chin@Sun.COM int loc = stktell(mp->shp->stk); 9514887Schin int xarith = mp->arith; 9528462SApril.Chin@Sun.COM int arrayok = mp->arrayok; 9534887Schin mp->split = 0; 9544887Schin mp->arith = 0; 9554887Schin mp->pattern = flag?4:0; 9568462SApril.Chin@Sun.COM mp->arrayok=1; 9578462SApril.Chin@Sun.COM mp->subcopy++; 9588462SApril.Chin@Sun.COM mp->dotdot = 0; 9594887Schin copyto(mp,RBRACT,0); 9608462SApril.Chin@Sun.COM mp->subcopy = 0; 9614887Schin mp->pattern = xpattern; 9624887Schin mp->split = split; 9634887Schin mp->arith = xarith; 9648462SApril.Chin@Sun.COM mp->arrayok = arrayok; 9654887Schin return(loc); 9664887Schin } 9674887Schin 9688462SApril.Chin@Sun.COM /* 9698462SApril.Chin@Sun.COM * if name is a discipline function, run the function and put the results 9708462SApril.Chin@Sun.COM * on the stack so that ${x.foo} behaves like ${ x.foo;} 9718462SApril.Chin@Sun.COM */ 9728462SApril.Chin@Sun.COM int sh_macfun(Shell_t *shp, const char *name, int offset) 9738462SApril.Chin@Sun.COM { 9748462SApril.Chin@Sun.COM Namval_t *np, *nq; 9758462SApril.Chin@Sun.COM np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0); 9768462SApril.Chin@Sun.COM if(np) 9778462SApril.Chin@Sun.COM { 9788462SApril.Chin@Sun.COM /* treat ${x.foo} as ${x.foo;} */ 9798462SApril.Chin@Sun.COM Shnode_t *tp; 9808462SApril.Chin@Sun.COM char buff[sizeof(struct dolnod)+sizeof(char*)]; 9818462SApril.Chin@Sun.COM struct comnod node; 9828462SApril.Chin@Sun.COM struct dolnod *dp = (struct dolnod*)buff; 9838462SApril.Chin@Sun.COM memset(&node,0,sizeof(node)); 9848462SApril.Chin@Sun.COM memset(&buff,0,sizeof(buff)); 9858462SApril.Chin@Sun.COM tp = (Shnode_t*)&node; 9868462SApril.Chin@Sun.COM tp->com.comarg = (struct argnod*)dp; 9878462SApril.Chin@Sun.COM tp->com.comline = shp->inlineno; 988*10898Sroland.mainz@nrubsig.org dp->dolnum = 1; 9898462SApril.Chin@Sun.COM dp->dolval[0] = strdup(name); 9908462SApril.Chin@Sun.COM stkseek(shp->stk,offset); 9918462SApril.Chin@Sun.COM comsubst((Mac_t*)shp->mac_context,tp,2); 9928462SApril.Chin@Sun.COM free(dp->dolval[0]); 9938462SApril.Chin@Sun.COM return(1); 9948462SApril.Chin@Sun.COM } 9958462SApril.Chin@Sun.COM return(0); 9968462SApril.Chin@Sun.COM } 9978462SApril.Chin@Sun.COM 9984887Schin static int namecount(Mac_t *mp,const char *prefix) 9994887Schin { 10004887Schin int count = 0; 10018462SApril.Chin@Sun.COM mp->nvwalk = nv_diropen((Namval_t*)0,prefix); 10024887Schin while(nv_dirnext(mp->nvwalk)) 10034887Schin count++; 10044887Schin nv_dirclose(mp->nvwalk); 10054887Schin return(count); 10064887Schin } 10074887Schin 10084887Schin static char *nextname(Mac_t *mp,const char *prefix, int len) 10094887Schin { 10104887Schin char *cp; 10114887Schin if(len==0) 10124887Schin { 10138462SApril.Chin@Sun.COM mp->nvwalk = nv_diropen((Namval_t*)0,prefix); 10144887Schin return((char*)mp->nvwalk); 10154887Schin } 10164887Schin if(!(cp=nv_dirnext(mp->nvwalk))) 10174887Schin nv_dirclose(mp->nvwalk); 10184887Schin return(cp); 10194887Schin } 10204887Schin 10214887Schin /* 10224887Schin * This routine handles $param, ${parm}, and ${param op word} 10234887Schin * The input stream is assumed to be a string 10244887Schin */ 10254887Schin static int varsub(Mac_t *mp) 10264887Schin { 10274887Schin register int c; 10284887Schin register int type=0; /* M_xxx */ 10294887Schin register char *v,*argp=0; 10304887Schin register Namval_t *np = NIL(Namval_t*); 10314887Schin register int dolg=0, mode=0; 10328462SApril.Chin@Sun.COM Lex_t *lp = (Lex_t*)mp->shp->lex_context; 10334887Schin Namarr_t *ap=0; 10344887Schin int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0; 10358462SApril.Chin@Sun.COM char idbuff[3], *id = idbuff, *pattern=0, *repstr, *arrmax=0; 1036*10898Sroland.mainz@nrubsig.org int var=1,addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d; 10378462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 10384887Schin retry1: 10394887Schin mp->zeros = 0; 10404887Schin idbuff[0] = 0; 10414887Schin idbuff[1] = 0; 10424887Schin c = fcget(); 1043*10898Sroland.mainz@nrubsig.org switch(isascii(c)?sh_lexstates[ST_DOL][c]:S_ALP) 10444887Schin { 10454887Schin case S_RBRA: 10464887Schin if(type<M_SIZE) 10474887Schin goto nosub; 10484887Schin /* This code handles ${#} */ 10494887Schin c = mode; 10504887Schin mode = type = 0; 10514887Schin /* FALL THRU */ 10524887Schin case S_SPC1: 10534887Schin if(type==M_BRACE) 10544887Schin { 10554887Schin if(isaletter(mode=fcpeek(0)) || mode=='.') 10564887Schin { 10574887Schin if(c=='#') 10584887Schin type = M_SIZE; 10594887Schin #ifdef SHOPT_TYPEDEF 10604887Schin else if(c=='@') 10614887Schin { 10624887Schin type = M_TYPE; 10634887Schin goto retry1; 10644887Schin } 10654887Schin #endif /* SHOPT_TYPEDEF */ 10664887Schin else 10674887Schin type = M_VNAME; 10684887Schin mode = c; 10694887Schin goto retry1; 10704887Schin } 10714887Schin else if(c=='#' && (isadigit(mode)||fcpeek(1)==RBRACE)) 10724887Schin { 10734887Schin type = M_SIZE; 10744887Schin mode = c; 10754887Schin goto retry1; 10764887Schin } 10774887Schin } 10784887Schin /* FALL THRU */ 10794887Schin case S_SPC2: 1080*10898Sroland.mainz@nrubsig.org var = 0; 10814887Schin *id = c; 10828462SApril.Chin@Sun.COM v = special(mp->shp,c); 10834887Schin if(isastchar(c)) 10844887Schin { 10854887Schin mode = c; 10864887Schin #if SHOPT_FILESCAN 10878462SApril.Chin@Sun.COM if(mp->shp->cur_line) 10884887Schin { 10894887Schin v = getdolarg(&sh,1,(int*)0); 10904887Schin dolmax = MAX_ARGN; 10914887Schin } 10924887Schin else 10934887Schin #endif /* SHOPT_FILESCAN */ 10948462SApril.Chin@Sun.COM dolmax = mp->shp->st.dolc+1; 10954887Schin dolg = (v!=0); 10964887Schin } 10974887Schin break; 10984887Schin case S_LBRA: 10994887Schin if(type) 11004887Schin goto nosub; 11014887Schin type = M_BRACE; 11024887Schin goto retry1; 11034887Schin case S_PAR: 11044887Schin if(type) 11054887Schin goto nosub; 11068462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,1); 11074887Schin return(1); 11084887Schin case S_DIG: 1109*10898Sroland.mainz@nrubsig.org var = 0; 11104887Schin c -= '0'; 11118462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 11124887Schin if(type) 11134887Schin { 11144887Schin register int d; 11154887Schin while((d=fcget()),isadigit(d)) 11164887Schin c = 10*c + (d-'0'); 11174887Schin fcseek(-1); 11184887Schin } 11194887Schin idnum = c; 11204887Schin if(c==0) 11218462SApril.Chin@Sun.COM v = special(mp->shp,c); 11224887Schin #if SHOPT_FILESCAN 11238462SApril.Chin@Sun.COM else if(mp->shp->cur_line) 11244887Schin { 11258462SApril.Chin@Sun.COM mp->shp->used_pos = 1; 11264887Schin v = getdolarg(&sh,c,&vsize); 11274887Schin } 11284887Schin #endif /* SHOPT_FILESCAN */ 11298462SApril.Chin@Sun.COM else if(c <= mp->shp->st.dolc) 11304887Schin { 11318462SApril.Chin@Sun.COM mp->shp->used_pos = 1; 11328462SApril.Chin@Sun.COM v = mp->shp->st.dolv[c]; 11334887Schin } 11344887Schin else 11354887Schin v = 0; 11364887Schin break; 11374887Schin case S_ALP: 11384887Schin if(c=='.' && type==0) 11394887Schin goto nosub; 11408462SApril.Chin@Sun.COM offset = stktell(stkp); 11414887Schin do 11424887Schin { 11434887Schin np = 0; 11444887Schin do 11458462SApril.Chin@Sun.COM sfputc(stkp,c); 1146*10898Sroland.mainz@nrubsig.org while(((c=fcget()),(!isascii(c)||isaname(c)))||type && c=='.'); 11478462SApril.Chin@Sun.COM while(c==LBRACT && (type||mp->arrayok)) 11484887Schin { 11498462SApril.Chin@Sun.COM mp->shp->argaddr=0; 11504887Schin if((c=fcget(),isastchar(c)) && fcpeek(0)==RBRACT) 11514887Schin { 11524887Schin if(type==M_VNAME) 11534887Schin type = M_SUBNAME; 11544887Schin idbuff[0] = mode = c; 11554887Schin fcget(); 11564887Schin c = fcget(); 11574887Schin if(c=='.' || c==LBRACT) 11584887Schin { 11598462SApril.Chin@Sun.COM sfputc(stkp,LBRACT); 11608462SApril.Chin@Sun.COM sfputc(stkp,mode); 11618462SApril.Chin@Sun.COM sfputc(stkp,RBRACT); 11624887Schin } 11634887Schin else 11644887Schin flag = NV_ARRAY; 11654887Schin break; 11664887Schin } 11674887Schin else 11684887Schin { 11694887Schin fcseek(-1); 11708462SApril.Chin@Sun.COM c = stktell(stkp); 11718462SApril.Chin@Sun.COM sfputc(stkp,LBRACT); 11728462SApril.Chin@Sun.COM v = stkptr(stkp,subcopy(mp,1)); 11738462SApril.Chin@Sun.COM if(type && mp->dotdot) 11748462SApril.Chin@Sun.COM { 11758462SApril.Chin@Sun.COM mode = '@'; 11768462SApril.Chin@Sun.COM v[-1] = 0; 11778462SApril.Chin@Sun.COM if(type==M_VNAME) 11788462SApril.Chin@Sun.COM type = M_SUBNAME; 11798462SApril.Chin@Sun.COM else if(type==M_SIZE) 11808462SApril.Chin@Sun.COM goto nosub; 11818462SApril.Chin@Sun.COM } 11828462SApril.Chin@Sun.COM else 11838462SApril.Chin@Sun.COM sfputc(stkp,RBRACT); 11848462SApril.Chin@Sun.COM c = fcget(); 11858462SApril.Chin@Sun.COM if(c==0 && type==M_VNAME) 11864887Schin type = M_SUBNAME; 11874887Schin } 11884887Schin } 11894887Schin } 11904887Schin while(type && c=='.'); 11914887Schin if(c==RBRACE && type && fcpeek(-2)=='.') 11924887Schin { 11938462SApril.Chin@Sun.COM /* ${x.} or ${x..} */ 11948462SApril.Chin@Sun.COM if(fcpeek(-3) == '.') 11958462SApril.Chin@Sun.COM { 11968462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-2); 11978462SApril.Chin@Sun.COM nv_local = 1; 11988462SApril.Chin@Sun.COM } 11998462SApril.Chin@Sun.COM else 12008462SApril.Chin@Sun.COM { 12018462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 12028462SApril.Chin@Sun.COM type = M_TREE; 12038462SApril.Chin@Sun.COM } 12044887Schin } 12058462SApril.Chin@Sun.COM sfputc(stkp,0); 12068462SApril.Chin@Sun.COM id=stkptr(stkp,offset); 12074887Schin if(isastchar(c) && type) 12084887Schin { 12094887Schin if(type==M_VNAME || type==M_SIZE) 12104887Schin { 12114887Schin idbuff[0] = mode = c; 12124887Schin if((d=fcpeek(0))==c) 12134887Schin idbuff[1] = fcget(); 12144887Schin if(type==M_VNAME) 12154887Schin type = M_NAMESCAN; 12164887Schin else 12174887Schin type = M_NAMECOUNT; 12184887Schin break; 12194887Schin } 12204887Schin goto nosub; 12214887Schin } 12224887Schin flag |= NV_NOASSIGN|NV_VARNAME|NV_NOADD; 12234887Schin if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?'))) 12244887Schin flag &= ~NV_NOADD; 12254887Schin #if SHOPT_FILESCAN 12268462SApril.Chin@Sun.COM if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0) 12274887Schin { 12288462SApril.Chin@Sun.COM mp->shp->argaddr=0; 12294887Schin np = REPLYNOD; 12304887Schin } 12314887Schin else 12324887Schin #endif /* SHOPT_FILESCAN */ 1233*10898Sroland.mainz@nrubsig.org { 1234*10898Sroland.mainz@nrubsig.org if(mp->shp->argaddr) 1235*10898Sroland.mainz@nrubsig.org flag &= ~NV_NOADD; 1236*10898Sroland.mainz@nrubsig.org np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL); 1237*10898Sroland.mainz@nrubsig.org } 1238*10898Sroland.mainz@nrubsig.org if(isastchar(mode)) 1239*10898Sroland.mainz@nrubsig.org var = 0; 1240*10898Sroland.mainz@nrubsig.org if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY) && strchr(id,'.')) 12418462SApril.Chin@Sun.COM { 12428462SApril.Chin@Sun.COM if(sh_macfun(mp->shp,id,offset)) 12438462SApril.Chin@Sun.COM { 12448462SApril.Chin@Sun.COM fcget(); 12458462SApril.Chin@Sun.COM return(1); 12468462SApril.Chin@Sun.COM } 12478462SApril.Chin@Sun.COM } 1248*10898Sroland.mainz@nrubsig.org if(np && (flag&NV_NOADD) && nv_isnull(np)) 1249*10898Sroland.mainz@nrubsig.org { 1250*10898Sroland.mainz@nrubsig.org if(nv_isattr(np,NV_NOFREE)) 1251*10898Sroland.mainz@nrubsig.org nv_offattr(np,NV_NOFREE); 1252*10898Sroland.mainz@nrubsig.org else 1253*10898Sroland.mainz@nrubsig.org np = 0; 1254*10898Sroland.mainz@nrubsig.org } 12554887Schin ap = np?nv_arrayptr(np):0; 12564887Schin if(type) 12574887Schin { 12588462SApril.Chin@Sun.COM if(mp->dotdot) 12598462SApril.Chin@Sun.COM { 12608462SApril.Chin@Sun.COM if(ap) 12618462SApril.Chin@Sun.COM { 12628462SApril.Chin@Sun.COM nv_putsub(np,v,ARRAY_SCAN); 12638462SApril.Chin@Sun.COM v = stkptr(stkp,mp->dotdot); 12648462SApril.Chin@Sun.COM dolmax =1; 12658462SApril.Chin@Sun.COM if(array_assoc(ap)) 12668462SApril.Chin@Sun.COM arrmax = strdup(v); 12678462SApril.Chin@Sun.COM else if((dolmax = (int)sh_arith(v))<0) 12688462SApril.Chin@Sun.COM dolmax += array_maxindex(np); 12698462SApril.Chin@Sun.COM if(type==M_SUBNAME) 12708462SApril.Chin@Sun.COM bysub = 1; 12718462SApril.Chin@Sun.COM } 12728462SApril.Chin@Sun.COM else 12738462SApril.Chin@Sun.COM { 12748462SApril.Chin@Sun.COM if((int)sh_arith(v)) 12758462SApril.Chin@Sun.COM np = 0; 12768462SApril.Chin@Sun.COM } 12778462SApril.Chin@Sun.COM } 12788462SApril.Chin@Sun.COM else if(ap && (isastchar(mode)||type==M_TREE) && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE) 12794887Schin nv_putsub(np,NIL(char*),ARRAY_SCAN); 12804887Schin if(!isbracechar(c)) 12814887Schin goto nosub; 12824887Schin else 12834887Schin fcseek(-1); 12844887Schin } 12854887Schin else 12864887Schin fcseek(-1); 12878462SApril.Chin@Sun.COM if(type<=1 && np && nv_isvtree(np) && mp->pattern==1 && !mp->split) 12888462SApril.Chin@Sun.COM { 12898462SApril.Chin@Sun.COM int peek=1,cc=fcget(); 12908462SApril.Chin@Sun.COM if(type && cc=='}') 12918462SApril.Chin@Sun.COM { 12928462SApril.Chin@Sun.COM cc = fcget(); 12938462SApril.Chin@Sun.COM peek = 2; 12948462SApril.Chin@Sun.COM } 12958462SApril.Chin@Sun.COM if(mp->quote && cc=='"') 12968462SApril.Chin@Sun.COM { 12978462SApril.Chin@Sun.COM cc = fcget(); 12988462SApril.Chin@Sun.COM peek++; 12998462SApril.Chin@Sun.COM } 13008462SApril.Chin@Sun.COM fcseek(-peek); 13018462SApril.Chin@Sun.COM if(cc==0) 13028462SApril.Chin@Sun.COM mp->assign = 1; 13038462SApril.Chin@Sun.COM } 13048462SApril.Chin@Sun.COM if((type==M_VNAME||type==M_SUBNAME) && mp->shp->argaddr && strcmp(nv_name(np),id)) 13058462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 13064887Schin c = (type>M_BRACE && isastchar(mode)); 13078462SApril.Chin@Sun.COM if(np && (type==M_TREE || !c || !ap)) 13084887Schin { 13098462SApril.Chin@Sun.COM char *savptr; 13108462SApril.Chin@Sun.COM c = *((unsigned char*)stkptr(stkp,offset-1)); 13118462SApril.Chin@Sun.COM savptr = stkfreeze(stkp,0); 13128462SApril.Chin@Sun.COM if(type==M_VNAME || (type==M_SUBNAME && ap)) 13134887Schin { 13144887Schin type = M_BRACE; 13154887Schin v = nv_name(np); 13168462SApril.Chin@Sun.COM if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF)) 13178462SApril.Chin@Sun.COM addsub = 1; 13184887Schin } 13194887Schin #ifdef SHOPT_TYPEDEF 13204887Schin else if(type==M_TYPE) 13214887Schin { 13224887Schin Namval_t *nq = nv_type(np); 13234887Schin type = M_BRACE; 13244887Schin if(nq) 13258462SApril.Chin@Sun.COM nv_typename(nq,mp->shp->strbuf); 13264887Schin else 13278462SApril.Chin@Sun.COM nv_attribute(np,mp->shp->strbuf,"typeset",1); 13288462SApril.Chin@Sun.COM v = sfstruse(mp->shp->strbuf); 13294887Schin } 13304887Schin #endif /* SHOPT_TYPEDEF */ 13314887Schin #if SHOPT_FILESCAN 13328462SApril.Chin@Sun.COM else if(mp->shp->cur_line && np==REPLYNOD) 13338462SApril.Chin@Sun.COM v = mp->shp->cur_line; 13344887Schin #endif /* SHOPT_FILESCAN */ 13354887Schin else if(type==M_TREE) 13364887Schin v = nv_getvtree(np,(Namfun_t*)0); 13374887Schin else 13384887Schin { 1339*10898Sroland.mainz@nrubsig.org if(type && fcpeek(0)=='+') 1340*10898Sroland.mainz@nrubsig.org { 1341*10898Sroland.mainz@nrubsig.org if(ap) 1342*10898Sroland.mainz@nrubsig.org v = nv_arrayisset(np,ap)?(char*)"x":0; 1343*10898Sroland.mainz@nrubsig.org else 1344*10898Sroland.mainz@nrubsig.org v = nv_isnull(np)?0:(char*)"x"; 1345*10898Sroland.mainz@nrubsig.org } 1346*10898Sroland.mainz@nrubsig.org else 1347*10898Sroland.mainz@nrubsig.org v = nv_getval(np); 13484887Schin /* special case --- ignore leading zeros */ 13498462SApril.Chin@Sun.COM if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(c))) 13504887Schin mp->zeros = 1; 13514887Schin } 13528462SApril.Chin@Sun.COM if(savptr==stakptr(0)) 13538462SApril.Chin@Sun.COM stkseek(stkp,offset); 13548462SApril.Chin@Sun.COM else 13558462SApril.Chin@Sun.COM stkset(stkp,savptr,offset); 13564887Schin } 13574887Schin else 13588462SApril.Chin@Sun.COM { 13594887Schin v = 0; 13608462SApril.Chin@Sun.COM if(type==M_VNAME) 13618462SApril.Chin@Sun.COM { 13628462SApril.Chin@Sun.COM v = id; 13638462SApril.Chin@Sun.COM type = M_BRACE; 13648462SApril.Chin@Sun.COM } 13658462SApril.Chin@Sun.COM else if(type==M_TYPE) 13668462SApril.Chin@Sun.COM type = M_BRACE; 13678462SApril.Chin@Sun.COM } 13688462SApril.Chin@Sun.COM stkseek(stkp,offset); 13694887Schin if(ap) 13704887Schin { 13714887Schin #if SHOPT_OPTIMIZE 13728462SApril.Chin@Sun.COM if(mp->shp->argaddr) 13734887Schin nv_optimize(np); 13744887Schin #endif 13754887Schin if(isastchar(mode) && array_elem(ap)> !c) 13764887Schin dolg = -1; 13774887Schin else 13784887Schin dolg = 0; 13794887Schin } 13804887Schin break; 13814887Schin case S_EOF: 13824887Schin fcseek(-1); 13834887Schin default: 13844887Schin goto nosub; 13854887Schin } 13864887Schin c = fcget(); 13874887Schin if(type>M_TREE) 13884887Schin { 13894887Schin if(c!=RBRACE) 13904887Schin mac_error(np); 13914887Schin if(type==M_NAMESCAN || type==M_NAMECOUNT) 13924887Schin { 1393*10898Sroland.mainz@nrubsig.org mp->shp->last_root = mp->shp->var_tree; 13948462SApril.Chin@Sun.COM id = prefix(mp->shp,id); 13958462SApril.Chin@Sun.COM stkseek(stkp,offset); 13964887Schin if(type==M_NAMECOUNT) 13974887Schin { 13984887Schin c = namecount(mp,id); 13994887Schin v = ltos(c); 14004887Schin } 14014887Schin else 14024887Schin { 14034887Schin dolmax = strlen(id); 14044887Schin dolg = -1; 14054887Schin nextname(mp,id,0); 14064887Schin v = nextname(mp,id,dolmax); 14074887Schin } 14084887Schin } 14094887Schin else if(type==M_SUBNAME) 14104887Schin { 14114887Schin if(dolg<0) 14124887Schin { 14134887Schin v = nv_getsub(np); 14144887Schin bysub=1; 14154887Schin } 14164887Schin else if(v) 14174887Schin { 14184887Schin if(!ap || isastchar(mode)) 14194887Schin v = "0"; 14204887Schin else 14214887Schin v = nv_getsub(np); 14224887Schin } 14234887Schin } 14244887Schin else 14254887Schin { 14264887Schin if(!isastchar(mode)) 14274887Schin c = charlen(v,vsize); 14284887Schin else if(dolg>0) 14294887Schin { 14304887Schin #if SHOPT_FILESCAN 14318462SApril.Chin@Sun.COM if(mp->shp->cur_line) 14324887Schin { 14334887Schin getdolarg(&sh,MAX_ARGN,(int*)0); 14348462SApril.Chin@Sun.COM c = mp->shp->offsets[0]; 14354887Schin } 14364887Schin else 14374887Schin #endif /* SHOPT_FILESCAN */ 14388462SApril.Chin@Sun.COM c = mp->shp->st.dolc; 14394887Schin } 14404887Schin else if(dolg<0) 14414887Schin c = array_elem(ap); 14424887Schin else 14434887Schin c = (v!=0); 14444887Schin dolg = dolmax = 0; 14454887Schin v = ltos(c); 14464887Schin } 14474887Schin c = RBRACE; 14484887Schin } 14494887Schin nulflg = 0; 14504887Schin if(type && c==':') 14514887Schin { 14524887Schin c = fcget(); 14534887Schin if(sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':') 14544887Schin nulflg=1; 14554887Schin else if(c!='%' && c!='#') 14564887Schin { 14574887Schin fcseek(-1); 14584887Schin c = ':'; 14594887Schin } 14604887Schin } 14614887Schin if(type) 14624887Schin { 14634887Schin if(!isbracechar(c)) 14644887Schin { 14654887Schin if(!nulflg) 14664887Schin mac_error(np); 14674887Schin fcseek(-1); 14684887Schin c = ':'; 14694887Schin } 14704887Schin if(c!=RBRACE) 14714887Schin { 14724887Schin int newops = (c=='#' || c == '%' || c=='/'); 14738462SApril.Chin@Sun.COM offset = stktell(stkp); 14744887Schin if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%'))) 14754887Schin { 14764887Schin int newquote = mp->quote; 14774887Schin int split = mp->split; 14784887Schin int quoted = mp->quoted; 14794887Schin int arith = mp->arith; 14804887Schin int zeros = mp->zeros; 1481*10898Sroland.mainz@nrubsig.org int assign = mp->assign; 14824887Schin if(newops) 14834887Schin { 14844887Schin type = fcget(); 14854887Schin if(type=='%' || type=='#') 14864887Schin { 14874887Schin int d = fcget(); 14884887Schin fcseek(-1); 14894887Schin if(d=='(') 14904887Schin type = 0; 14914887Schin } 14924887Schin fcseek(-1); 14934887Schin mp->pattern = 1+(c=='/'); 14944887Schin mp->split = 0; 14954887Schin mp->quoted = 0; 1496*10898Sroland.mainz@nrubsig.org mp->assign &= ~1; 14974887Schin mp->arith = mp->zeros = 0; 14984887Schin newquote = 0; 14994887Schin } 15004887Schin else if(c=='?' || c=='=') 15014887Schin mp->split = mp->pattern = 0; 15024887Schin copyto(mp,RBRACE,newquote); 15034887Schin if(!oldpat) 15044887Schin mp->patfound = 0; 15054887Schin mp->pattern = oldpat; 15064887Schin mp->split = split; 15074887Schin mp->quoted = quoted; 15084887Schin mp->arith = arith; 15094887Schin mp->zeros = zeros; 1510*10898Sroland.mainz@nrubsig.org mp->assign = assign; 15114887Schin /* add null byte */ 15128462SApril.Chin@Sun.COM sfputc(stkp,0); 15138462SApril.Chin@Sun.COM stkseek(stkp,stktell(stkp)-1); 15144887Schin } 15154887Schin else 15164887Schin { 15178462SApril.Chin@Sun.COM sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED); 15188462SApril.Chin@Sun.COM stkseek(stkp,offset); 15194887Schin } 15208462SApril.Chin@Sun.COM argp=stkptr(stkp,offset); 15214887Schin } 15224887Schin } 15234887Schin else 15244887Schin { 15254887Schin fcseek(-1); 15264887Schin c=0; 15274887Schin } 15284887Schin if(c==':') /* ${name:expr1[:expr2]} */ 15294887Schin { 15304887Schin char *ptr; 15314887Schin type = (int)sh_strnum(argp,&ptr,1); 15324887Schin if(isastchar(mode)) 15334887Schin { 15344887Schin if(id==idbuff) /* ${@} or ${*} */ 15354887Schin { 15364887Schin if(type<0 && (type+= dolmax)<0) 15374887Schin type = 0; 15384887Schin if(type==0) 15398462SApril.Chin@Sun.COM v = special(mp->shp,dolg=0); 15404887Schin #if SHOPT_FILESCAN 15418462SApril.Chin@Sun.COM else if(mp->shp->cur_line) 15424887Schin { 15434887Schin v = getdolarg(&sh,dolg=type,&vsize); 15444887Schin if(!v) 15454887Schin dolmax = type; 15464887Schin } 15474887Schin #endif /* SHOPT_FILESCAN */ 15484887Schin else if(type < dolmax) 15498462SApril.Chin@Sun.COM v = mp->shp->st.dolv[dolg=type]; 15504887Schin else 15514887Schin v = 0; 15524887Schin } 15534887Schin else if(ap) 15544887Schin { 15554887Schin if(type<0) 15564887Schin { 15574887Schin if(array_assoc(ap)) 15584887Schin type = -type; 15594887Schin else 15604887Schin type += array_maxindex(np); 15614887Schin } 15624887Schin if(array_assoc(ap)) 15634887Schin { 15644887Schin while(type-- >0 && (v=0,nv_nextsub(np))) 15654887Schin v = nv_getval(np); 15664887Schin } 15674887Schin else if(type > 0) 15684887Schin { 15694887Schin if(nv_putsub(np,NIL(char*),type|ARRAY_SCAN)) 15704887Schin v = nv_getval(np); 15714887Schin else 15724887Schin v = 0; 15734887Schin } 15744887Schin } 15754887Schin else if(type>0) 15764887Schin v = 0; 15774887Schin } 15784887Schin else if(v) 15794887Schin { 15804887Schin vsize = charlen(v,vsize); 15814887Schin if(type<0 && (type += vsize)<0) 15824887Schin type = 0; 15834887Schin if(vsize < type) 15844887Schin v = 0; 15854887Schin #if SHOPT_MULTIBYTE 15864887Schin else if(mbwide()) 15874887Schin { 15884887Schin mbinit(); 15894887Schin while(type-->0) 15904887Schin { 15914887Schin if((c=mbsize(v))<1) 15924887Schin c = 1; 15934887Schin v += c; 15944887Schin } 15954887Schin c = ':'; 15964887Schin } 15974887Schin #endif /* SHOPT_MULTIBYTE */ 15984887Schin else 15994887Schin v += type; 16004887Schin vsize -= type; 16014887Schin } 16024887Schin if(*ptr==':') 16034887Schin { 16044887Schin if((type = (int)sh_strnum(ptr+1,&ptr,1)) <=0) 16054887Schin v = 0; 16064887Schin else if(isastchar(mode)) 16074887Schin { 16084887Schin if(dolg>=0) 16094887Schin { 16104887Schin if(dolg+type < dolmax) 16114887Schin dolmax = dolg+type; 16124887Schin } 16134887Schin else 16144887Schin dolmax = type; 16154887Schin } 16164887Schin else if(type < vsize) 16174887Schin { 16184887Schin #if SHOPT_MULTIBYTE 16194887Schin if(mbwide()) 16204887Schin { 16214887Schin char *vp = v; 16224887Schin mbinit(); 16234887Schin while(type-->0) 16244887Schin { 16254887Schin if((c=mbsize(vp))<1) 16264887Schin c = 1; 16274887Schin vp += c; 16284887Schin } 16294887Schin type = vp-v; 16304887Schin c = ':'; 16314887Schin } 16324887Schin #endif /* SHOPT_MULTIBYTE */ 16334887Schin vsize = type; 16344887Schin } 16354887Schin } 16364887Schin if(*ptr) 16374887Schin mac_error(np); 16388462SApril.Chin@Sun.COM stkseek(stkp,offset); 16394887Schin argp = 0; 16404887Schin } 16414887Schin /* check for substring operations */ 16424887Schin else if(c == '#' || c == '%' || c=='/') 16434887Schin { 16444887Schin if(c=='/') 16454887Schin { 16464887Schin if(type=='/' || type=='#' || type=='%') 16474887Schin { 16484887Schin c = type; 16494887Schin type = '/'; 16504887Schin argp++; 16514887Schin } 16524887Schin else 16534887Schin type = 0; 16544887Schin } 16554887Schin else 16564887Schin { 16574887Schin if(type==c) /* ## or %% */ 16584887Schin argp++; 16594887Schin else 16604887Schin type = 0; 16614887Schin } 16624887Schin pattern = strdup(argp); 16634887Schin if((type=='/' || c=='/') && (repstr = mac_getstring(pattern))) 16644887Schin replen = strlen(repstr); 16654887Schin if(v || c=='/' && offset>=0) 16668462SApril.Chin@Sun.COM stkseek(stkp,offset); 16674887Schin } 16684887Schin /* check for quoted @ */ 16694887Schin if(mode=='@' && mp->quote && !v && c!='-') 16704887Schin mp->quoted-=2; 16714887Schin retry2: 16724887Schin if(v && (!nulflg || *v ) && c!='+') 16734887Schin { 16744887Schin register int d = (mode=='@'?' ':mp->ifs); 16758462SApril.Chin@Sun.COM int match[2*(MATCH_MAX+1)], nmatch, nmatch_prev, vsize_last; 16764887Schin char *vlast; 16774887Schin while(1) 16784887Schin { 16794887Schin if(!v) 16804887Schin v= ""; 16814887Schin if(c=='/' || c=='#' || c== '%') 16824887Schin { 16838462SApril.Chin@Sun.COM flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP; 16844887Schin if(c!='/') 16854887Schin flag |= STR_LEFT; 16868462SApril.Chin@Sun.COM nmatch = 0; 16874887Schin while(1) 16884887Schin { 16894887Schin vsize = strlen(v); 16908462SApril.Chin@Sun.COM nmatch_prev = nmatch; 16914887Schin if(c=='%') 16924887Schin nmatch=substring(v,pattern,match,flag&STR_MAXIMAL); 16934887Schin else 16944887Schin nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag); 16954887Schin if(replen>0) 16964887Schin sh_setmatch(v,vsize,nmatch,match); 16974887Schin if(nmatch) 16984887Schin { 16994887Schin vlast = v; 17004887Schin vsize_last = vsize; 17014887Schin vsize = match[0]; 17024887Schin } 17034887Schin else if(c=='#') 17044887Schin vsize = 0; 17054887Schin if(vsize) 17064887Schin mac_copy(mp,v,vsize); 17078462SApril.Chin@Sun.COM if(nmatch && replen>0 && (match[1] || !nmatch_prev)) 17084887Schin mac_substitute(mp,repstr,v,match,nmatch); 17094887Schin if(nmatch==0) 17104887Schin v += vsize; 17114887Schin else 17124887Schin v += match[1]; 17134887Schin if(*v && c=='/' && type) 17144887Schin { 17154887Schin /* avoid infinite loop */ 17164887Schin if(nmatch && match[1]==0) 17178462SApril.Chin@Sun.COM { 17188462SApril.Chin@Sun.COM nmatch = 0; 17198462SApril.Chin@Sun.COM mac_copy(mp,v,1); 17204887Schin v++; 17218462SApril.Chin@Sun.COM } 17224887Schin continue; 17234887Schin } 17244887Schin vsize = -1; 17254887Schin break; 17264887Schin } 17274887Schin if(replen==0) 17284887Schin sh_setmatch(vlast,vsize_last,nmatch,match); 17294887Schin } 17304887Schin if(vsize) 17314887Schin mac_copy(mp,v,vsize>0?vsize:strlen(v)); 17328462SApril.Chin@Sun.COM if(addsub) 17338462SApril.Chin@Sun.COM { 17348462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"[%s]",nv_getsub(np)); 17358462SApril.Chin@Sun.COM v = sfstruse(mp->shp->strbuf); 17368462SApril.Chin@Sun.COM mac_copy(mp, v, strlen(v)); 17378462SApril.Chin@Sun.COM } 17384887Schin if(dolg==0 && dolmax==0) 17394887Schin break; 17408462SApril.Chin@Sun.COM if(mp->dotdot) 17418462SApril.Chin@Sun.COM { 17428462SApril.Chin@Sun.COM if(nv_nextsub(np) == 0) 17438462SApril.Chin@Sun.COM break; 17448462SApril.Chin@Sun.COM if(bysub) 17458462SApril.Chin@Sun.COM v = nv_getsub(np); 17468462SApril.Chin@Sun.COM else 17478462SApril.Chin@Sun.COM v = nv_getval(np); 17488462SApril.Chin@Sun.COM if(array_assoc(ap)) 17498462SApril.Chin@Sun.COM { 17508462SApril.Chin@Sun.COM if(strcmp(bysub?v:nv_getsub(np),arrmax)>0) 17518462SApril.Chin@Sun.COM break; 17528462SApril.Chin@Sun.COM } 17538462SApril.Chin@Sun.COM else 17548462SApril.Chin@Sun.COM { 17558462SApril.Chin@Sun.COM if(nv_aindex(np) > dolmax) 17568462SApril.Chin@Sun.COM break; 17578462SApril.Chin@Sun.COM } 17588462SApril.Chin@Sun.COM } 17598462SApril.Chin@Sun.COM else if(dolg>=0) 17604887Schin { 17614887Schin if(++dolg >= dolmax) 17624887Schin break; 17634887Schin #if SHOPT_FILESCAN 17648462SApril.Chin@Sun.COM if(mp->shp->cur_line) 17654887Schin { 17664887Schin if(dolmax==MAX_ARGN && isastchar(mode)) 17674887Schin break; 17684887Schin if(!(v=getdolarg(&sh,dolg,&vsize))) 17694887Schin { 17704887Schin dolmax = dolg; 17714887Schin break; 17724887Schin } 17734887Schin } 17744887Schin else 17754887Schin #endif /* SHOPT_FILESCAN */ 17768462SApril.Chin@Sun.COM v = mp->shp->st.dolv[dolg]; 17774887Schin } 17784887Schin else if(!np) 17794887Schin { 17804887Schin if(!(v = nextname(mp,id,dolmax))) 17814887Schin break; 17824887Schin } 17834887Schin else 17844887Schin { 17854887Schin if(dolmax && --dolmax <=0) 17864887Schin { 17874887Schin nv_putsub(np,NIL(char*),ARRAY_UNDEF); 17884887Schin break; 17894887Schin } 17908462SApril.Chin@Sun.COM if(ap) 17918462SApril.Chin@Sun.COM ap->nelem |= ARRAY_SCAN; 17924887Schin if(nv_nextsub(np) == 0) 17934887Schin break; 17944887Schin if(bysub) 17954887Schin v = nv_getsub(np); 17964887Schin else 17974887Schin v = nv_getval(np); 17984887Schin } 17994887Schin if(mp->split && (!mp->quote || mode=='@')) 18004887Schin { 18014887Schin if(!np) 18024887Schin mp->pattern = 0; 18034887Schin endfield(mp,mp->quoted); 18044887Schin mp->pattern = oldpat; 18054887Schin } 18064887Schin else if(d) 18074887Schin { 18084887Schin if(mp->sp) 18094887Schin sfputc(mp->sp,d); 18104887Schin else 18118462SApril.Chin@Sun.COM sfputc(stkp,d); 18124887Schin } 18134887Schin } 18148462SApril.Chin@Sun.COM if(arrmax) 18158462SApril.Chin@Sun.COM free((void*)arrmax); 18164887Schin if(pattern) 18174887Schin free((void*)pattern); 18184887Schin } 18194887Schin else if(argp) 18204887Schin { 18214887Schin if(c=='/' && replen>0 && pattern && strmatch("",pattern)) 18224887Schin mac_substitute(mp,repstr,v,0,0); 18234887Schin if(c=='?') 18244887Schin { 18254887Schin if(np) 18264887Schin id = nv_name(np); 18274887Schin else if(idnum) 18284887Schin id = ltos(idnum); 18294887Schin if(*argp) 18304887Schin { 18318462SApril.Chin@Sun.COM sfputc(stkp,0); 18324887Schin errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp); 18334887Schin } 18344887Schin else if(v) 18354887Schin errormsg(SH_DICT,ERROR_exit(1),e_nullset,id); 18364887Schin else 18374887Schin errormsg(SH_DICT,ERROR_exit(1),e_notset,id); 18384887Schin } 18394887Schin else if(c=='=') 18404887Schin { 18414887Schin if(np) 18424887Schin { 18438462SApril.Chin@Sun.COM if(mp->shp->subshell) 18444887Schin np = sh_assignok(np,1); 18454887Schin nv_putval(np,argp,0); 18464887Schin v = nv_getval(np); 18474887Schin nulflg = 0; 18488462SApril.Chin@Sun.COM stkseek(stkp,offset); 18494887Schin goto retry2; 18504887Schin } 18514887Schin else 18524887Schin mac_error(np); 18534887Schin } 18544887Schin } 1855*10898Sroland.mainz@nrubsig.org else if(var && sh_isoption(SH_NOUNSET) && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp))) 18564887Schin { 18574887Schin if(np) 18584887Schin { 18594887Schin if(nv_isarray(np)) 18604887Schin { 18618462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np)); 18628462SApril.Chin@Sun.COM id = sfstruse(mp->shp->strbuf); 18634887Schin } 18644887Schin else 18654887Schin id = nv_name(np); 18664887Schin nv_close(np); 18674887Schin } 18684887Schin errormsg(SH_DICT,ERROR_exit(1),e_notset,id); 18694887Schin } 18704887Schin if(np) 18714887Schin nv_close(np); 18724887Schin return(1); 18734887Schin nosub: 18748462SApril.Chin@Sun.COM if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK) 18758462SApril.Chin@Sun.COM { 18768462SApril.Chin@Sun.COM fcseek(-1); 18778462SApril.Chin@Sun.COM comsubst(mp,(Shnode_t*)0,2); 18788462SApril.Chin@Sun.COM return(1); 18798462SApril.Chin@Sun.COM } 18804887Schin if(type) 18814887Schin mac_error(np); 18824887Schin fcseek(-1); 18834887Schin nv_close(np); 18844887Schin return(0); 18854887Schin } 18864887Schin 18874887Schin /* 18884887Schin * This routine handles command substitution 18894887Schin * <type> is 0 for older `...` version 18904887Schin */ 18918462SApril.Chin@Sun.COM static void comsubst(Mac_t *mp,register Shnode_t* t, int type) 18924887Schin { 18934887Schin Sfdouble_t num; 18944887Schin register int c; 18954887Schin register char *str; 18964887Schin Sfio_t *sp; 18978462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 18984887Schin Fcin_t save; 18998462SApril.Chin@Sun.COM struct slnod *saveslp = mp->shp->st.staklist; 19004887Schin struct _mac_ savemac; 19018462SApril.Chin@Sun.COM int savtop = stktell(stkp); 19028462SApril.Chin@Sun.COM char lastc, *savptr = stkfreeze(stkp,0); 19034887Schin int was_history = sh_isstate(SH_HISTORY); 19044887Schin int was_verbose = sh_isstate(SH_VERBOSE); 19058462SApril.Chin@Sun.COM int was_interactive = sh_isstate(SH_INTERACTIVE); 19068462SApril.Chin@Sun.COM int newlines,bufsize,nextnewlines; 19074887Schin Namval_t *np; 19088462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 19094887Schin savemac = *mp; 19108462SApril.Chin@Sun.COM mp->shp->st.staklist=0; 19114887Schin if(type) 19124887Schin { 19134887Schin sp = 0; 19144887Schin fcseek(-1); 19158462SApril.Chin@Sun.COM if(!t) 19168462SApril.Chin@Sun.COM t = sh_dolparen((Lex_t*)mp->shp->lex_context); 19174887Schin if(t && t->tre.tretyp==TARITH) 19184887Schin { 19194887Schin fcsave(&save); 19208462SApril.Chin@Sun.COM if((t->ar.arexpr->argflag&ARG_RAW)) 19218462SApril.Chin@Sun.COM num = arith_exec(t->ar.arcomp); 19228462SApril.Chin@Sun.COM else 19238462SApril.Chin@Sun.COM num = sh_arith(sh_mactrim(mp->shp,t->ar.arexpr->argval,3)); 19244887Schin out_offset: 19258462SApril.Chin@Sun.COM stkset(stkp,savptr,savtop); 19264887Schin *mp = savemac; 19278462SApril.Chin@Sun.COM if((Sflong_t)num!=num) 19288462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%.*Lg",LDBL_DIG,num); 19298462SApril.Chin@Sun.COM else if(num) 19308462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%lld",(Sflong_t)num); 19314887Schin else 19328462SApril.Chin@Sun.COM sfprintf(mp->shp->strbuf,"%Lg",num); 19338462SApril.Chin@Sun.COM str = sfstruse(mp->shp->strbuf); 19344887Schin mac_copy(mp,str,strlen(str)); 19358462SApril.Chin@Sun.COM mp->shp->st.staklist = saveslp; 19364887Schin fcrestore(&save); 19374887Schin return; 19384887Schin } 19394887Schin } 19404887Schin else 19414887Schin { 19424887Schin while(fcgetc(c)!='`' && c) 19434887Schin { 19444887Schin if(c==ESCAPE) 19454887Schin { 19464887Schin fcgetc(c); 19474887Schin if(!(isescchar(sh_lexstates[ST_QUOTE][c]) || 19488462SApril.Chin@Sun.COM (c=='"' && mp->quote))) 19498462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 19504887Schin } 19518462SApril.Chin@Sun.COM sfputc(stkp,c); 19524887Schin } 19538462SApril.Chin@Sun.COM c = stktell(stkp); 19548462SApril.Chin@Sun.COM str=stkfreeze(stkp,1); 19554887Schin /* disable verbose and don't save in history file */ 19564887Schin sh_offstate(SH_HISTORY); 19574887Schin sh_offstate(SH_VERBOSE); 19584887Schin if(mp->sp) 19594887Schin sfsync(mp->sp); /* flush before executing command */ 19604887Schin sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ); 19618462SApril.Chin@Sun.COM c = mp->shp->inlineno; 19628462SApril.Chin@Sun.COM mp->shp->inlineno = error_info.line+mp->shp->st.firstline; 19634887Schin t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL); 19648462SApril.Chin@Sun.COM mp->shp->inlineno = c; 19658462SApril.Chin@Sun.COM type = 1; 19664887Schin } 19674887Schin #if KSHELL 19684887Schin if(t) 19694887Schin { 19704887Schin fcsave(&save); 19714887Schin sfclose(sp); 19728462SApril.Chin@Sun.COM if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset) 19734887Schin { 19744887Schin /* special case $(<file) and $(<#file) */ 19754887Schin register int fd; 19764887Schin int r; 19774887Schin struct checkpt buff; 19784887Schin struct ionod *ip=0; 19794887Schin sh_pushcontext(&buff,SH_JMPIO); 19804887Schin if((ip=t->tre.treio) && 19814887Schin ((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) && 19824887Schin (r=sigsetjmp(buff.buff,0))==0) 19838462SApril.Chin@Sun.COM fd = sh_redirect(mp->shp,ip,3); 19844887Schin else 19854887Schin fd = sh_chkopen(e_devnull); 19864887Schin sh_popcontext(&buff); 19874887Schin if(r==0 && ip && (ip->iofile&IOLSEEK)) 19884887Schin { 19898462SApril.Chin@Sun.COM if(sp=mp->shp->sftable[fd]) 19904887Schin num = sftell(sp); 19914887Schin else 19924887Schin num = lseek(fd, (off_t)0, SEEK_CUR); 19934887Schin goto out_offset; 19944887Schin } 19954887Schin sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC); 19968462SApril.Chin@Sun.COM type = 3; 19974887Schin } 19984887Schin else 19998462SApril.Chin@Sun.COM sp = sh_subshell(t,sh_isstate(SH_ERREXIT),type); 20004887Schin fcrestore(&save); 20014887Schin } 20024887Schin else 20034887Schin sp = sfopen(NIL(Sfio_t*),"","sr"); 20048462SApril.Chin@Sun.COM sh_freeup(mp->shp); 20058462SApril.Chin@Sun.COM mp->shp->st.staklist = saveslp; 20064887Schin if(was_history) 20074887Schin sh_onstate(SH_HISTORY); 20084887Schin if(was_verbose) 20094887Schin sh_onstate(SH_VERBOSE); 20104887Schin #else 20114887Schin sp = sfpopen(NIL(Sfio_t*),str,"r"); 20124887Schin #endif 20134887Schin *mp = savemac; 20148462SApril.Chin@Sun.COM np = sh_scoped(mp->shp,IFSNOD); 20158462SApril.Chin@Sun.COM nv_putval(np,mp->ifsp,NV_RDONLY); 20164887Schin mp->ifsp = nv_getval(np); 20178462SApril.Chin@Sun.COM stkset(stkp,savptr,savtop); 20184887Schin newlines = 0; 20194887Schin lastc = 0; 20204887Schin sfsetbuf(sp,(void*)sp,0); 20214887Schin bufsize = sfvalue(sp); 20224887Schin /* read command substitution output and put on stack or here-doc */ 20234887Schin sfpool(sp, NIL(Sfio_t*), SF_WRITE); 20248462SApril.Chin@Sun.COM sh_offstate(SH_INTERACTIVE); 20254887Schin while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c = sfvalue(sp))>0) 20264887Schin { 20274887Schin #if SHOPT_CRNL 20284887Schin /* eliminate <cr> */ 20294887Schin register char *dp; 20304887Schin char *buff = str; 20314887Schin while(c>1 && (*str !='\r'|| str[1]!='\n')) 20324887Schin { 20334887Schin c--; 20344887Schin str++; 20354887Schin } 20364887Schin dp = str; 20374887Schin while(c>1) 20384887Schin { 20394887Schin str++; 20404887Schin c--; 20414887Schin while(c>1 && (*str!='\r' || str[1]!='\n')) 20424887Schin { 20434887Schin c--; 20444887Schin *dp++ = *str++; 20454887Schin } 20464887Schin } 20474887Schin if(c) 20484887Schin *dp++ = *str++; 20494887Schin str = buff; 20504887Schin c = dp-str; 20514887Schin #endif /* SHOPT_CRNL */ 20528462SApril.Chin@Sun.COM /* delay appending trailing new-lines */ 20538462SApril.Chin@Sun.COM for(nextnewlines=0; c-->0 && str[c]=='\n'; nextnewlines++); 20548462SApril.Chin@Sun.COM if(c < 0) 20558462SApril.Chin@Sun.COM { 20568462SApril.Chin@Sun.COM newlines += nextnewlines; 20578462SApril.Chin@Sun.COM continue; 20588462SApril.Chin@Sun.COM } 20594887Schin if(newlines >0) 20604887Schin { 20614887Schin if(mp->sp) 20624887Schin sfnputc(mp->sp,'\n',newlines); 20638462SApril.Chin@Sun.COM else if(!mp->quote && mp->split && mp->shp->ifstable['\n']) 20644887Schin endfield(mp,0); 20658462SApril.Chin@Sun.COM else 20668462SApril.Chin@Sun.COM sfnputc(stkp,'\n',newlines); 20674887Schin } 20684887Schin else if(lastc) 20694887Schin { 20704887Schin mac_copy(mp,&lastc,1); 20714887Schin lastc = 0; 20724887Schin } 20738462SApril.Chin@Sun.COM newlines = nextnewlines; 20744887Schin if(++c < bufsize) 20754887Schin str[c] = 0; 20764887Schin else 20774887Schin { 20784887Schin /* can't write past buffer so save last character */ 20794887Schin lastc = str[--c]; 20804887Schin str[c] = 0; 20814887Schin } 20824887Schin mac_copy(mp,str,c); 20834887Schin } 20848462SApril.Chin@Sun.COM if(was_interactive) 20858462SApril.Chin@Sun.COM sh_onstate(SH_INTERACTIVE); 20868462SApril.Chin@Sun.COM if(mp->shp->spid) 20878462SApril.Chin@Sun.COM job_wait(mp->shp->spid); 20888462SApril.Chin@Sun.COM if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM) 20894887Schin { 20904887Schin if(mp->sp) 20914887Schin sfnputc(mp->sp,'\n',newlines); 20928462SApril.Chin@Sun.COM else if(!mp->quote && mp->split) 20938462SApril.Chin@Sun.COM while(newlines--) 20948462SApril.Chin@Sun.COM endfield(mp,1); 20958462SApril.Chin@Sun.COM else 20968462SApril.Chin@Sun.COM sfnputc(stkp,'\n',newlines); 20974887Schin } 20984887Schin if(lastc) 20994887Schin mac_copy(mp,&lastc,1); 21004887Schin sfclose(sp); 21014887Schin return; 21024887Schin } 21034887Schin 21044887Schin /* 21054887Schin * copy <str> onto the stack 21064887Schin */ 21074887Schin static void mac_copy(register Mac_t *mp,register const char *str, register int size) 21084887Schin { 21094887Schin register char *state; 21104887Schin register const char *cp=str; 21118462SApril.Chin@Sun.COM register int c,n,nopat,len; 21128462SApril.Chin@Sun.COM Stk_t *stkp=mp->shp->stk; 21134887Schin nopat = (mp->quote||mp->assign==1||mp->arith); 21144887Schin if(mp->zeros) 21154887Schin { 21164887Schin /* prevent leading 0's from becomming octal constants */ 21174887Schin while(size>1 && *str=='0') 21184887Schin str++,size--; 21194887Schin mp->zeros = 0; 21204887Schin cp = str; 21214887Schin } 21224887Schin if(mp->sp) 21234887Schin sfwrite(mp->sp,str,size); 21244887Schin else if(mp->pattern>=2 || (mp->pattern && nopat)) 21254887Schin { 21264887Schin state = sh_lexstates[ST_MACRO]; 21274887Schin /* insert \ before file expansion characters */ 21284887Schin while(size-->0) 21294887Schin { 21308462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE 21318462SApril.Chin@Sun.COM if(mbwide() && (len=mbsize(cp))>1) 21328462SApril.Chin@Sun.COM { 21338462SApril.Chin@Sun.COM cp += len; 21348462SApril.Chin@Sun.COM size -= (len-1); 21358462SApril.Chin@Sun.COM continue; 21368462SApril.Chin@Sun.COM } 21378462SApril.Chin@Sun.COM #endif 21384887Schin c = state[n= *(unsigned char*)cp++]; 21394887Schin if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3) 21404887Schin c=1; 21414887Schin else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n))) 21424887Schin c=1; 21434887Schin else if(mp->pattern==2 && c==S_SLASH) 21444887Schin c=1; 21454887Schin else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE))) 21464887Schin { 21474887Schin if(!(c=mp->quote)) 21484887Schin cp++; 21494887Schin } 21504887Schin else 21514887Schin c=0; 21524887Schin if(c) 21534887Schin { 21544887Schin if(c = (cp-1) - str) 21558462SApril.Chin@Sun.COM sfwrite(stkp,str,c); 21568462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 21574887Schin str = cp-1; 21584887Schin } 21594887Schin } 21604887Schin if(c = cp-str) 21618462SApril.Chin@Sun.COM sfwrite(stkp,str,c); 21624887Schin } 21634887Schin else if(!mp->quote && mp->split && (mp->ifs||mp->pattern)) 21644887Schin { 21654887Schin /* split words at ifs characters */ 21668462SApril.Chin@Sun.COM state = mp->shp->ifstable; 21674887Schin if(mp->pattern) 21684887Schin { 21694887Schin char *sp = "&|()"; 21704887Schin while(c = *sp++) 21714887Schin { 21724887Schin if(state[c]==0) 21734887Schin state[c] = S_EPAT; 21744887Schin } 21754887Schin sp = "*?[{"; 21764887Schin while(c = *sp++) 21774887Schin { 21784887Schin if(state[c]==0) 21794887Schin state[c] = S_PAT; 21804887Schin } 21814887Schin if(state[ESCAPE]==0) 21824887Schin state[ESCAPE] = S_ESC; 21834887Schin } 21844887Schin while(size-->0) 21854887Schin { 21868462SApril.Chin@Sun.COM n=state[c= *(unsigned char*)cp++]; 21878462SApril.Chin@Sun.COM #if SHOPT_MULTIBYTE 21888462SApril.Chin@Sun.COM if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1) 21898462SApril.Chin@Sun.COM { 21908462SApril.Chin@Sun.COM sfwrite(stkp,cp-1, len); 21918462SApril.Chin@Sun.COM cp += --len; 21928462SApril.Chin@Sun.COM size -= len; 21938462SApril.Chin@Sun.COM continue; 21948462SApril.Chin@Sun.COM } 21958462SApril.Chin@Sun.COM #endif 21968462SApril.Chin@Sun.COM if(n==S_ESC || n==S_EPAT) 21974887Schin { 21984887Schin /* don't allow extended patterns in this case */ 21994887Schin mp->patfound = mp->pattern; 22008462SApril.Chin@Sun.COM sfputc(stkp,ESCAPE); 22014887Schin } 22024887Schin else if(n==S_PAT) 22034887Schin mp->patfound = mp->pattern; 22044887Schin else if(n && mp->ifs) 22054887Schin { 22064887Schin #if SHOPT_MULTIBYTE 22074887Schin if(n==S_MBYTE) 22084887Schin { 22094887Schin if(sh_strchr(mp->ifsp,cp-1)<0) 22104887Schin continue; 22114887Schin n = mbsize(cp-1) - 1; 22124887Schin if(n==-2) 22134887Schin n = 0; 22144887Schin cp += n; 22154887Schin size -= n; 22164887Schin n= S_DELIM; 22174887Schin } 22184887Schin #endif /* SHOPT_MULTIBYTE */ 22194887Schin if(n==S_SPACE || n==S_NL) 22204887Schin { 22214887Schin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL)) 22224887Schin size--; 22234887Schin #if SHOPT_MULTIBYTE 22244887Schin if(n==S_MBYTE && sh_strchr(mp->ifsp,cp-1)>=0) 22254887Schin { 22264887Schin n = mbsize(cp-1) - 1; 22274887Schin if(n==-2) 22284887Schin n = 0; 22294887Schin cp += n; 22304887Schin size -= n; 22314887Schin n=S_DELIM; 22324887Schin } 22334887Schin else 22344887Schin #endif /* SHOPT_MULTIBYTE */ 22354887Schin if(n==S_DELIM) 22364887Schin size--; 22374887Schin } 22384887Schin endfield(mp,n==S_DELIM||mp->quoted); 22394887Schin mp->patfound = 0; 22404887Schin if(n==S_DELIM) 22414887Schin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL)) 22424887Schin size--; 22434887Schin if(size<=0) 22444887Schin break; 22454887Schin cp--; 22464887Schin continue; 22474887Schin 22484887Schin } 22498462SApril.Chin@Sun.COM sfputc(stkp,c); 22504887Schin } 22514887Schin if(mp->pattern) 22524887Schin { 22534887Schin cp = "&|()"; 22544887Schin while(c = *cp++) 22554887Schin { 22564887Schin if(state[c]==S_EPAT) 22574887Schin state[c] = 0; 22584887Schin } 22594887Schin cp = "*?[{"; 22604887Schin while(c = *cp++) 22614887Schin { 22624887Schin if(state[c]==S_PAT) 22634887Schin state[c] = 0; 22644887Schin } 22658462SApril.Chin@Sun.COM if(mp->shp->ifstable[ESCAPE]==S_ESC) 22668462SApril.Chin@Sun.COM mp->shp->ifstable[ESCAPE] = 0; 22674887Schin } 22684887Schin } 22694887Schin else 22708462SApril.Chin@Sun.COM sfwrite(stkp,str,size); 22714887Schin } 22724887Schin 22734887Schin /* 22744887Schin * Terminate field. 22754887Schin * If field is null count field if <split> is non-zero 22764887Schin * Do filename expansion of required 22774887Schin */ 22784887Schin static void endfield(register Mac_t *mp,int split) 22794887Schin { 22808462SApril.Chin@Sun.COM register struct argnod *argp; 22818462SApril.Chin@Sun.COM register int count=0; 22828462SApril.Chin@Sun.COM Stk_t *stkp = mp->shp->stk; 22838462SApril.Chin@Sun.COM if(stktell(stkp) > ARGVAL || split) 22844887Schin { 22858462SApril.Chin@Sun.COM argp = (struct argnod*)stkfreeze(stkp,1); 22864887Schin argp->argnxt.cp = 0; 22874887Schin argp->argflag = 0; 22884887Schin if(mp->patfound) 22894887Schin { 22908462SApril.Chin@Sun.COM mp->shp->argaddr = 0; 22914887Schin #if SHOPT_BRACEPAT 22924887Schin count = path_generate(argp,mp->arghead); 22934887Schin #else 22944887Schin count = path_expand(argp->argval,mp->arghead); 22954887Schin #endif /* SHOPT_BRACEPAT */ 22964887Schin if(count) 22974887Schin mp->fields += count; 22984887Schin else if(split) /* pattern is null string */ 22994887Schin *argp->argval = 0; 23004887Schin else /* pattern expands to nothing */ 23014887Schin count = -1; 23024887Schin } 23034887Schin if(count==0) 23044887Schin { 23054887Schin argp->argchn.ap = *mp->arghead; 23064887Schin *mp->arghead = argp; 23074887Schin mp->fields++; 23084887Schin } 23094887Schin if(count>=0) 23104887Schin { 23114887Schin (*mp->arghead)->argflag |= ARG_MAKE; 23124887Schin if(mp->assign || sh_isoption(SH_NOGLOB)) 23134887Schin argp->argflag |= ARG_RAW|ARG_EXP; 23144887Schin } 23158462SApril.Chin@Sun.COM stkseek(stkp,ARGVAL); 23164887Schin } 23174887Schin mp->quoted = mp->quote; 23184887Schin } 23194887Schin 23204887Schin /* 23214887Schin * Finds the right substring of STRING using the expression PAT 23224887Schin * the longest substring is found when FLAG is set. 23234887Schin */ 23244887Schin static int substring(register const char *string,const char *pat,int match[], int flag) 23254887Schin { 23264887Schin register const char *sp=string; 23274887Schin register int size,len,nmatch,n; 23284887Schin int smatch[2*(MATCH_MAX+1)]; 23294887Schin if(flag) 23304887Schin { 23314887Schin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL)) 23324887Schin { 23334887Schin memcpy(match,smatch,n*2*sizeof(smatch[0])); 23344887Schin return(n); 23354887Schin } 23364887Schin return(0); 23374887Schin } 23384887Schin size = len = strlen(sp); 23394887Schin sp += size; 23404887Schin while(sp>=string) 23414887Schin { 23424887Schin #if SHOPT_MULTIBYTE 23434887Schin if(mbwide()) 23444887Schin sp = lastchar(string,sp); 23454887Schin #endif /* SHOPT_MULTIBYTE */ 23464887Schin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL)) 23474887Schin { 23484887Schin nmatch = n; 23494887Schin memcpy(match,smatch,n*2*sizeof(smatch[0])); 23504887Schin size = sp-string; 23514887Schin break; 23524887Schin } 23534887Schin sp--; 23544887Schin } 23554887Schin if(size==len) 23564887Schin return(0); 23574887Schin if(nmatch) 23584887Schin { 23594887Schin nmatch *=2; 23604887Schin while(--nmatch>=0) 23614887Schin match[nmatch] += size; 23624887Schin } 23634887Schin return(n); 23644887Schin } 23654887Schin 23664887Schin #if SHOPT_MULTIBYTE 23674887Schin static char *lastchar(const char *string, const char *endstring) 23684887Schin { 23694887Schin register char *str = (char*)string; 23704887Schin register int c; 23714887Schin mbinit(); 23724887Schin while(*str) 23734887Schin { 23744887Schin if((c=mbsize(str))<0) 23754887Schin c = 1; 23764887Schin if(str+c > endstring) 23774887Schin break; 23784887Schin str += c; 23794887Schin } 23804887Schin return(str); 23814887Schin } 23824887Schin #endif /* SHOPT_MULTIBYTE */ 23834887Schin static int charlen(const char *string,int len) 23844887Schin { 23854887Schin if(!string) 23864887Schin return(0); 23874887Schin #if SHOPT_MULTIBYTE 23884887Schin if(mbwide()) 23894887Schin { 23904887Schin register const char *str = string, *strmax=string+len; 23914887Schin register int n=0; 23924887Schin mbinit(); 23934887Schin if(len>0) 23944887Schin { 23954887Schin while(str<strmax && mbchar(str)) 23964887Schin n++; 23974887Schin } 23984887Schin else while(mbchar(str)) 23994887Schin n++; 24004887Schin return(n); 24014887Schin } 24024887Schin else 24034887Schin #endif /* SHOPT_MULTIBYTE */ 24044887Schin { 24054887Schin if(len<0) 24064887Schin return(strlen(string)); 24074887Schin return(len); 24084887Schin } 24094887Schin } 24104887Schin 24114887Schin /* 24124887Schin * This is the default tilde discipline function 24134887Schin */ 24144887Schin static int sh_btilde(int argc, char *argv[], void *context) 24154887Schin { 24168462SApril.Chin@Sun.COM Shell_t *shp = ((Shbltin_t*)context)->shp; 24178462SApril.Chin@Sun.COM char *cp = sh_tilde(shp,argv[1]); 24184887Schin NOT_USED(argc); 24194887Schin if(!cp) 24204887Schin cp = argv[1]; 24214887Schin sfputr(sfstdout, cp, '\n'); 24224887Schin return(0); 24234887Schin } 24244887Schin 24254887Schin /* 24264887Schin * <offset> is byte offset for beginning of tilde string 24274887Schin */ 24288462SApril.Chin@Sun.COM static void tilde_expand2(Shell_t *shp, register int offset) 24294887Schin { 24308462SApril.Chin@Sun.COM char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1); 24314887Schin Sfio_t *iop, *save=sfstdout; 24324887Schin Namval_t *np; 24334887Schin static int beenhere=0; 24344887Schin strcpy(shtilde,".sh.tilde"); 24358462SApril.Chin@Sun.COM np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL); 24364887Schin if(np && !beenhere) 24374887Schin { 24384887Schin beenhere = 1; 24394887Schin sh_addbuiltin(shtilde,sh_btilde,0); 24408462SApril.Chin@Sun.COM nv_onattr(np,NV_EXPORT); 24414887Schin } 24424887Schin av[0] = ".sh.tilde"; 24434887Schin av[1] = &ptr[offset]; 24444887Schin av[2] = 0; 24454887Schin iop = sftmp(IOBSIZE+1);; 24464887Schin sfset(iop,SF_READ,0); 24474887Schin sfstdout = iop; 24484887Schin if(np) 24494887Schin sh_fun(np, (Namval_t*)0, av); 24504887Schin else 24514887Schin sh_btilde(2, av, &sh); 24524887Schin sfstdout = save; 24538462SApril.Chin@Sun.COM stkset(shp->stk,ptr, offset); 24544887Schin sfseek(iop,(Sfoff_t)0,SEEK_SET); 24554887Schin sfset(iop,SF_READ,1); 24564887Schin if(ptr = sfreserve(iop, SF_UNBOUND, -1)) 24574887Schin { 24584887Schin Sfoff_t n = sfvalue(iop); 24594887Schin while(ptr[n-1]=='\n') 24604887Schin n--; 24614887Schin if(n==1 && fcpeek(0)=='/' && ptr[n-1]) 24624887Schin n--; 24634887Schin if(n) 24648462SApril.Chin@Sun.COM sfwrite(shp->stk,ptr,n); 24654887Schin } 24664887Schin else 24678462SApril.Chin@Sun.COM sfputr(shp->stk,av[1],0); 24684887Schin sfclose(iop); 24694887Schin } 24704887Schin 24714887Schin /* 24724887Schin * This routine is used to resolve ~ expansion. 24734887Schin * A ~ by itself is replaced with the users login directory. 24744887Schin * A ~- is replaced by the previous working directory in shell. 24754887Schin * A ~+ is replaced by the present working directory in shell. 24764887Schin * If ~name is replaced with login directory of name. 24774887Schin * If string doesn't start with ~ or ~... not found then 0 returned. 24784887Schin */ 24794887Schin 24808462SApril.Chin@Sun.COM static char *sh_tilde(Shell_t *shp,register const char *string) 24814887Schin { 24824887Schin register char *cp; 24834887Schin register int c; 24844887Schin register struct passwd *pw; 24854887Schin register Namval_t *np=0; 24864887Schin static Dt_t *logins_tree; 24874887Schin if(*string++!='~') 24884887Schin return(NIL(char*)); 24894887Schin if((c = *string)==0) 24904887Schin { 24918462SApril.Chin@Sun.COM if(!(cp=nv_getval(sh_scoped(shp,HOME)))) 24924887Schin cp = getlogin(); 24934887Schin return(cp); 24944887Schin } 24954887Schin if((c=='-' || c=='+') && string[1]==0) 24964887Schin { 24974887Schin if(c=='+') 24988462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,PWDNOD)); 24994887Schin else 25008462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,OLDPWDNOD)); 25014887Schin return(cp); 25024887Schin } 25034887Schin if(logins_tree && (np=nv_search(string,logins_tree,0))) 25044887Schin return(nv_getval(np)); 25054887Schin if(!(pw = getpwnam(string))) 25064887Schin return(NIL(char*)); 25074887Schin if(!logins_tree) 25084887Schin logins_tree = dtopen(&_Nvdisc,Dtbag); 25094887Schin if(np=nv_search(string,logins_tree,NV_ADD)) 25104887Schin nv_putval(np, pw->pw_dir,0); 25114887Schin return(pw->pw_dir); 25124887Schin } 25134887Schin 25144887Schin /* 25154887Schin * return values for special macros 25164887Schin */ 25178462SApril.Chin@Sun.COM static char *special(Shell_t *shp,register int c) 25184887Schin { 25194887Schin if(c!='$') 25208462SApril.Chin@Sun.COM shp->argaddr = 0; 25214887Schin switch(c) 25224887Schin { 25234887Schin case '@': 25244887Schin case '*': 25258462SApril.Chin@Sun.COM return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*)); 25264887Schin case '#': 25274887Schin #if SHOPT_FILESCAN 25288462SApril.Chin@Sun.COM if(shp->cur_line) 25294887Schin { 25308462SApril.Chin@Sun.COM getdolarg(shp,MAX_ARGN,(int*)0); 25318462SApril.Chin@Sun.COM return(ltos(shp->offsets[0])); 25324887Schin } 25334887Schin #endif /* SHOPT_FILESCAN */ 25348462SApril.Chin@Sun.COM return(ltos(shp->st.dolc)); 25354887Schin case '!': 25368462SApril.Chin@Sun.COM if(shp->bckpid) 25378462SApril.Chin@Sun.COM return(ltos(shp->bckpid)); 25384887Schin break; 25394887Schin case '$': 25404887Schin if(nv_isnull(SH_DOLLARNOD)) 25418462SApril.Chin@Sun.COM return(ltos(shp->pid)); 25424887Schin return(nv_getval(SH_DOLLARNOD)); 25434887Schin case '-': 25448462SApril.Chin@Sun.COM return(sh_argdolminus(shp->arg_context)); 25454887Schin case '?': 25468462SApril.Chin@Sun.COM return(ltos(shp->savexit)); 25474887Schin case 0: 2548*10898Sroland.mainz@nrubsig.org if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname) 25498462SApril.Chin@Sun.COM return(shp->shname); 25504887Schin else 2551*10898Sroland.mainz@nrubsig.org return(shp->st.cmdname); 25524887Schin } 25534887Schin return(NIL(char*)); 25544887Schin } 25554887Schin 25564887Schin /* 25574887Schin * Handle macro expansion errors 25584887Schin */ 25594887Schin static void mac_error(Namval_t *np) 25604887Schin { 25614887Schin if(np) 25624887Schin nv_close(np); 25634887Schin errormsg(SH_DICT,ERROR_exit(1),e_subst,fcfirst()); 25644887Schin } 25654887Schin 25664887Schin /* 25674887Schin * Given pattern/string, replace / with 0 and return pointer to string 25688462SApril.Chin@Sun.COM * \ characters are stripped from string. The \ are stripped in the 25698462SApril.Chin@Sun.COM * replacement string unless followed by a digit or \. 25704887Schin */ 25714887Schin static char *mac_getstring(char *pattern) 25724887Schin { 25738462SApril.Chin@Sun.COM register char *cp=pattern, *rep=0, *dp; 25748462SApril.Chin@Sun.COM register int c; 25754887Schin while(c = *cp++) 25764887Schin { 25778462SApril.Chin@Sun.COM if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp)))) 25788462SApril.Chin@Sun.COM { 25798462SApril.Chin@Sun.COM c = *cp++; 25808462SApril.Chin@Sun.COM } 25818462SApril.Chin@Sun.COM else if(!rep && c=='/') 25824887Schin { 25834887Schin cp[-1] = 0; 25848462SApril.Chin@Sun.COM rep = dp = cp; 25858462SApril.Chin@Sun.COM continue; 25864887Schin } 25878462SApril.Chin@Sun.COM if(rep) 25888462SApril.Chin@Sun.COM *dp++ = c; 25894887Schin } 25908462SApril.Chin@Sun.COM if(rep) 25918462SApril.Chin@Sun.COM *dp = 0; 25928462SApril.Chin@Sun.COM return(rep); 25934887Schin } 2594