da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1982-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Shell macro expander
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * expands ~
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * expands ${...}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * expands $(...)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * expands $((...))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * expands `...`
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * David Korn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Labs
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct argnod **arghead; /* address of head of argument list */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* type of macro expansions */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int substring(const char*, const char*, int[], int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char *mac_getstring(char*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int charlen(const char*,int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static char *lastchar(const char*,const char*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * perform only parameter substitution and catch failures
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinchar *sh_mactry(Shell_t *shp,register char *string)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return("");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Perform parameter expansion, command substitution, and arithmetic
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * expansion on <str>.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If <mode> greater than 1 file expansion is performed if the result
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * yields a single pathname.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If <mode> negative, than expansion rules for assignment are applied.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinchar *sh_mactrim(Shell_t *shp, char *str, register int mode)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* expand only if unique */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Perform all the expansions on the argument <argp>
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinint sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Expand here document which is stored in <infile> or <string>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The result is written to <outfile>
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinvoid sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c,n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* use state of alpha character */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(n == 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n=fcfill()) <=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* ignore 0 byte when reading from file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n==0 && fcfile())
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='.')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n==S_ALP)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((c=fcfill()) > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* FALL THRU */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * expand argument but do not trim pattern characters
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinchar *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Process the characters up to <endch> or end of input string
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void copyto(register Mac_t *mp,int endch, int newquote)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c,n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* handle // operator specially */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* treat as if alpha */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(n == 0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* process ANSI-C escape character */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for(i=0;i<n;i++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.'))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* preserve \digit for pattern matching */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* also \alpha for extended patterns */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if((n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP)))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* followed by file expansion */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-'))))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* convert \\\$ into \$' */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* add \ for file expansion */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* eliminate \ */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* check new-line joining */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(endch==RBRACE && *cp==LPAREN && mp->pattern && brace)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(mp->arith || (((mp->assign&1) || endch==RBRACT) &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *p = cp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n==RPAREN)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* mark beginning of {a,b} */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy <str> to stack performing sub-expression substitutions
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin register int c,n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0]))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * compute the arguments $1 ... $n and $# from the current line as needed
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * save line offsets in the offsets array.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n<=m)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin shp->offsets[m] = (first-(unsigned char*)shp->cur_line);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(--n==0 || c==S_EOF)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return((char*)first);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * get the prefix after name reference resolution
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy to ']' onto the stack and return offset to it
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * if name is a discipline function, run the function and put the results
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * on the stack so that ${x.foo} behaves like ${ x.foo;}
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinint sh_macfun(Shell_t *shp, const char *name, int offset)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* treat ${x.foo} as ${x.foo;} */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char *nextname(Mac_t *mp,const char *prefix, int len)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine handles $param, ${parm}, and ${param op word}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The input stream is assumed to be a string
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin char idbuff[3], *id = idbuff, *pattern=0, *repstr, *arrmax=0;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz int var=1,addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz switch(isascii(c)?sh_lexstates[ST_DOL][c]:S_ALP)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* This code handles ${#} */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* FALL THRU */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='#')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(c=='@')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_TYPEDEF */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* FALL THRU */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int d;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz while(((c=fcget()),(!isascii(c)||isaname(c)))||type && c=='.');
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* ${x.} or ${x..} */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((d=fcpeek(0))==c)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?')))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY) && strchr(id,'.'))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin else if(ap && (isastchar(mode)||type==M_TREE) && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(type<=1 && np && nv_isvtree(np) && mp->pattern==1 && !mp->split)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((type==M_VNAME||type==M_SUBNAME) && mp->shp->argaddr && strcmp(nv_name(np),id))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_TYPEDEF */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* special case --- ignore leading zeros */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(c)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(v)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(dolg>0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(dolg<0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin c = (v!=0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%')))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(d=='(')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* add null byte */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(type > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(type>0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(v)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(type-->0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(type-->0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* check for substring operations */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((type=='/' || c=='/') && (repstr = mac_getstring(pattern)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* check for quoted @ */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin int match[2*(MATCH_MAX+1)], nmatch, nmatch_prev, vsize_last;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c!='/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='%')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(c=='#')
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(nmatch && replen>0 && (match[1] || !nmatch_prev))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* avoid infinite loop */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(d)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='/' && replen>0 && pattern && strmatch("",pattern))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='?')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(v)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(c=='=')
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner else if(var && sh_isoption(SH_NOUNSET) && type<=M_TREE && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp)))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine handles command substitution
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * <type> is 0 for older `...` version
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic void comsubst(Mac_t *mp,register Shnode_t* t, int type)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin int was_interactive = sh_isstate(SH_INTERACTIVE);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin num = sh_arith(sh_mactrim(mp->shp,t->ar.arexpr->argval,3));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* disable verbose and don't save in history file */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin mp->shp->inlineno = error_info.line+mp->shp->st.firstline;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* special case $(<file) and $(<#file) */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* read command substitution output and put on stack or here-doc */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c = sfvalue(sp))>0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* eliminate <cr> */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(c>1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_CRNL */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /* delay appending trailing new-lines */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin for(nextnewlines=0; c-->0 && str[c]=='\n'; nextnewlines++);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin else if(!mp->quote && mp->split && mp->shp->ifstable['\n'])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* can't write past buffer so save last character */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy <str> onto the stack
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void mac_copy(register Mac_t *mp,register const char *str, register int size)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* prevent leading 0's from becomming octal constants */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* insert \ before file expansion characters */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(size-->0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(!mp->quote && mp->split && (mp->ifs||mp->pattern))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* split words at ifs characters */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(c = *sp++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(c = *sp++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(size-->0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* don't allow extended patterns in this case */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n==S_PAT)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(c = *cp++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(c = *cp++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Terminate field.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If field is null count field if <split> is non-zero
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Do filename expansion of required
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_BRACEPAT */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else /* pattern expands to nothing */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Finds the right substring of STRING using the expression PAT
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the longest substring is found when FLAG is set.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int substring(register const char *string,const char *pat,int match[], int flag)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(--nmatch>=0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static char *lastchar(const char *string, const char *endstring)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int n=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_MULTIBYTE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This is the default tilde discipline function
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int sh_btilde(int argc, char *argv[], void *context)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * <offset> is byte offset for beginning of tilde string
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic void tilde_expand2(Shell_t *shp, register int offset)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine is used to resolve ~ expansion.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * A ~ by itself is replaced with the users login directory.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * A ~- is replaced by the previous working directory in shell.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * A ~+ is replaced by the present working directory in shell.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If ~name is replaced with login directory of name.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If string doesn't start with ~ or ~... not found then 0 returned.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic char *sh_tilde(Shell_t *shp,register const char *string)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(NIL(char*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((c = *string)==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c=='+')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(logins_tree && (np=nv_search(string,logins_tree,0)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(NIL(char*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return values for special macros
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(c!='$')
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FILESCAN */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(NIL(char*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Handle macro expansion errors
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Given pattern/string, replace / with 0 and return pointer to string
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * \ characters are stripped from string. The \ are stripped in the
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * replacement string unless followed by a digit or \.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(c = *cp++)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp))))