14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 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"
4110898Sroland.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
sh_macopen(Shell_t * shp)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 */
sh_mactry(Shell_t * shp,register char * string)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 */
sh_mactrim(Shell_t * shp,char * str,register int mode)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 */
sh_macexpand(Shell_t * shp,register struct argnod * argp,struct argnod ** arghead,int flag)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 */
sh_machere(Shell_t * shp,Sfio_t * infile,Sfio_t * outfile,char * string)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 */
sh_macpat(Shell_t * shp,register struct argnod * arg,int flags)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 */
copyto(register Mac_t * mp,int endch,int newquote)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 */
53310898Sroland.mainz@nrubsig.org if(!mp->lit && !mp->quote)
53410898Sroland.mainz@nrubsig.org {
53510898Sroland.mainz@nrubsig.org if((n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP)))
53610898Sroland.mainz@nrubsig.org break;
53710898Sroland.mainz@nrubsig.org if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp))
53810898Sroland.mainz@nrubsig.org break;
53910898Sroland.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);
65610898Sroland.mainz@nrubsig.org if(mp->assign&1)
65710898Sroland.mainz@nrubsig.org {
65810898Sroland.mainz@nrubsig.org if(first[c-2]=='.')
65910898Sroland.mainz@nrubsig.org offset = stktell(stkp);
66010898Sroland.mainz@nrubsig.org if(isastchar(*cp) && cp[1]==']')
66110898Sroland.mainz@nrubsig.org errormsg(SH_DICT,ERROR_exit(1),
66210898Sroland.mainz@nrubsig.org e_badsubscript,*cp);
66310898Sroland.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');
69310898Sroland.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 */
mac_substitute(Mac_t * mp,register char * cp,char * str,register int subexp[],int subsize)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 */
getdolarg(Shell_t * shp,int n,int * size)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 */
prefix(Shell_t * shp,char * id)9048462SApril.Chin@Sun.COM static char *prefix(Shell_t *shp, char *id)
9054887Schin {
9064887Schin Namval_t *np;
90710898Sroland.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;
92010898Sroland.mainz@nrubsig.org while(nv_isref(np) && np->nvalue.cp)
92110898Sroland.mainz@nrubsig.org {
92210898Sroland.mainz@nrubsig.org sub = nv_refsub(np);
9234887Schin np = nv_refnode(np);
92410898Sroland.mainz@nrubsig.org if(sub)
92510898Sroland.mainz@nrubsig.org nv_putsub(np,sub,0L);
92610898Sroland.mainz@nrubsig.org }
92710898Sroland.mainz@nrubsig.org id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1));
92810898Sroland.mainz@nrubsig.org memcpy(id,sp,n);
92910898Sroland.mainz@nrubsig.org if(sub)
93010898Sroland.mainz@nrubsig.org {
93110898Sroland.mainz@nrubsig.org id[n++] = '[';
93210898Sroland.mainz@nrubsig.org strcpy(&id[n],sub);
93310898Sroland.mainz@nrubsig.org n+= strlen(sub)+1;
93410898Sroland.mainz@nrubsig.org id[n-1] = ']';
93510898Sroland.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 */
subcopy(Mac_t * mp,int flag)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 */
sh_macfun(Shell_t * shp,const char * name,int offset)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;
98810898Sroland.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
namecount(Mac_t * mp,const char * prefix)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
nextname(Mac_t * mp,const char * prefix,int len)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 */
varsub(Mac_t * mp)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;
103610898Sroland.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();
104310898Sroland.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:
108010898Sroland.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:
110910898Sroland.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);
114610898Sroland.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 */
123310898Sroland.mainz@nrubsig.org {
123410898Sroland.mainz@nrubsig.org if(mp->shp->argaddr)
123510898Sroland.mainz@nrubsig.org flag &= ~NV_NOADD;
123610898Sroland.mainz@nrubsig.org np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL);
123710898Sroland.mainz@nrubsig.org }
123810898Sroland.mainz@nrubsig.org if(isastchar(mode))
123910898Sroland.mainz@nrubsig.org var = 0;
124010898Sroland.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 }
124810898Sroland.mainz@nrubsig.org if(np && (flag&NV_NOADD) && nv_isnull(np))
124910898Sroland.mainz@nrubsig.org {
125010898Sroland.mainz@nrubsig.org if(nv_isattr(np,NV_NOFREE))
125110898Sroland.mainz@nrubsig.org nv_offattr(np,NV_NOFREE);
125210898Sroland.mainz@nrubsig.org else
125310898Sroland.mainz@nrubsig.org np = 0;
125410898Sroland.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 {
133910898Sroland.mainz@nrubsig.org if(type && fcpeek(0)=='+')
134010898Sroland.mainz@nrubsig.org {
134110898Sroland.mainz@nrubsig.org if(ap)
134210898Sroland.mainz@nrubsig.org v = nv_arrayisset(np,ap)?(char*)"x":0;
134310898Sroland.mainz@nrubsig.org else
134410898Sroland.mainz@nrubsig.org v = nv_isnull(np)?0:(char*)"x";
134510898Sroland.mainz@nrubsig.org }
134610898Sroland.mainz@nrubsig.org else
134710898Sroland.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 {
139310898Sroland.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;
148110898Sroland.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;
149610898Sroland.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;
151010898Sroland.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*12068SRoger.Faulkner@Oracle.COM else if(var && sh_isoption(SH_NOUNSET) && type<=M_TREE && (!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 */
comsubst(Mac_t * mp,register Shnode_t * t,int type)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 */
mac_copy(register Mac_t * mp,register const char * str,register int size)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 */
endfield(register Mac_t * mp,int split)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 */
substring(register const char * string,const char * pat,int match[],int flag)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
lastchar(const char * string,const char * endstring)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 */
charlen(const char * string,int len)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 */
sh_btilde(int argc,char * argv[],void * context)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 */
tilde_expand2(Shell_t * shp,register int offset)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
sh_tilde(Shell_t * shp,register const char * string)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 */
special(Shell_t * shp,register int c)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:
254810898Sroland.mainz@nrubsig.org if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname)
25498462SApril.Chin@Sun.COM return(shp->shname);
25504887Schin else
255110898Sroland.mainz@nrubsig.org return(shp->st.cmdname);
25524887Schin }
25534887Schin return(NIL(char*));
25544887Schin }
25554887Schin
25564887Schin /*
25574887Schin * Handle macro expansion errors
25584887Schin */
mac_error(Namval_t * np)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 */
mac_getstring(char * pattern)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