1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin * Shell macro expander
23da2e3ebdSchin * expands ~
24da2e3ebdSchin * expands ${...}
25da2e3ebdSchin * expands $(...)
26da2e3ebdSchin * expands $((...))
27da2e3ebdSchin * expands `...`
28da2e3ebdSchin *
29da2e3ebdSchin * David Korn
30da2e3ebdSchin * AT&T Labs
31da2e3ebdSchin *
32da2e3ebdSchin */
33da2e3ebdSchin
34da2e3ebdSchin #include "defs.h"
35da2e3ebdSchin #include <fcin.h>
36da2e3ebdSchin #include <pwd.h>
37da2e3ebdSchin #include "name.h"
38da2e3ebdSchin #include "variables.h"
39da2e3ebdSchin #include "shlex.h"
40da2e3ebdSchin #include "io.h"
4134f9b3eeSRoland Mainz #include "jobs.h"
42da2e3ebdSchin #include "shnodes.h"
43da2e3ebdSchin #include "path.h"
44da2e3ebdSchin #include "national.h"
45da2e3ebdSchin #include "streval.h"
46da2e3ebdSchin
47da2e3ebdSchin #undef STR_GROUP
48da2e3ebdSchin #ifndef STR_GROUP
49da2e3ebdSchin # define STR_GROUP 0
50da2e3ebdSchin #endif
51da2e3ebdSchin
52da2e3ebdSchin #if !SHOPT_MULTIBYTE
53da2e3ebdSchin #define mbchar(p) (*(unsigned char*)p++)
54da2e3ebdSchin #endif
55da2e3ebdSchin
56da2e3ebdSchin static int _c_;
57da2e3ebdSchin typedef struct _mac_
58da2e3ebdSchin {
59da2e3ebdSchin Shell_t *shp; /* pointer to shell interpreter */
60da2e3ebdSchin Sfio_t *sp; /* stream pointer for here-document */
61da2e3ebdSchin struct argnod **arghead; /* address of head of argument list */
62da2e3ebdSchin char *ifsp; /* pointer to IFS value */
63da2e3ebdSchin int fields; /* number of fields */
64da2e3ebdSchin short quoted; /* set when word has quotes */
65da2e3ebdSchin unsigned char ifs; /* first char of IFS */
66da2e3ebdSchin char quote; /* set within double quoted contexts */
67da2e3ebdSchin char lit; /* set within single quotes */
68da2e3ebdSchin char split; /* set when word splittin is possible */
69da2e3ebdSchin char pattern; /* set when file expansion follows */
70da2e3ebdSchin char patfound; /* set if pattern character found */
71da2e3ebdSchin char assign; /* set for assignments */
72da2e3ebdSchin char arith; /* set for ((...)) */
73da2e3ebdSchin char let; /* set when expanding let arguments */
74da2e3ebdSchin char zeros; /* strip leading zeros when set */
757c2fbfb3SApril Chin char arrayok; /* $x[] ok for arrays */
767c2fbfb3SApril Chin char subcopy; /* set when copying subscript */
777c2fbfb3SApril Chin int dotdot; /* set for .. in subscript */
78da2e3ebdSchin void *nvwalk; /* for name space walking*/
79da2e3ebdSchin } Mac_t;
80da2e3ebdSchin
81da2e3ebdSchin #undef ESCAPE
82da2e3ebdSchin #define ESCAPE '\\'
83da2e3ebdSchin #define isescchar(s) ((s)>S_QUOTE)
84da2e3ebdSchin #define isqescchar(s) ((s)>=S_QUOTE)
85da2e3ebdSchin #define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2)
86da2e3ebdSchin #define ltos(x) fmtbase((long)(x),0,0)
87da2e3ebdSchin
88da2e3ebdSchin /* type of macro expansions */
89da2e3ebdSchin #define M_BRACE 1 /* ${var} */
90da2e3ebdSchin #define M_TREE 2 /* ${var.} */
91da2e3ebdSchin #define M_SIZE 3 /* ${#var} */
92da2e3ebdSchin #define M_VNAME 4 /* ${!var} */
93da2e3ebdSchin #define M_SUBNAME 5 /* ${!var[sub]} */
94da2e3ebdSchin #define M_NAMESCAN 6 /* ${!var*} */
95da2e3ebdSchin #define M_NAMECOUNT 7 /* ${#var*} */
96da2e3ebdSchin #define M_TYPE 8 /* ${@var} */
97da2e3ebdSchin
98da2e3ebdSchin static int substring(const char*, const char*, int[], int);
99da2e3ebdSchin static void copyto(Mac_t*, int, int);
1007c2fbfb3SApril Chin static void comsubst(Mac_t*, Shnode_t*, int);
101da2e3ebdSchin static int varsub(Mac_t*);
102da2e3ebdSchin static void mac_copy(Mac_t*,const char*, int);
1037c2fbfb3SApril Chin static void tilde_expand2(Shell_t*,int);
1047c2fbfb3SApril Chin static char *sh_tilde(Shell_t*,const char*);
1057c2fbfb3SApril Chin static char *special(Shell_t *,int);
106da2e3ebdSchin static void endfield(Mac_t*,int);
107da2e3ebdSchin static void mac_error(Namval_t*);
108da2e3ebdSchin static char *mac_getstring(char*);
109da2e3ebdSchin static int charlen(const char*,int);
110da2e3ebdSchin #if SHOPT_MULTIBYTE
111da2e3ebdSchin static char *lastchar(const char*,const char*);
112da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
113da2e3ebdSchin
sh_macopen(Shell_t * shp)114da2e3ebdSchin void *sh_macopen(Shell_t *shp)
115da2e3ebdSchin {
116da2e3ebdSchin void *addr = newof(0,Mac_t,1,0);
117da2e3ebdSchin Mac_t *mp = (Mac_t*)addr;
118da2e3ebdSchin mp->shp = shp;
119da2e3ebdSchin return(addr);
120da2e3ebdSchin }
121da2e3ebdSchin
122da2e3ebdSchin /*
123da2e3ebdSchin * perform only parameter substitution and catch failures
124da2e3ebdSchin */
sh_mactry(Shell_t * shp,register char * string)1257c2fbfb3SApril Chin char *sh_mactry(Shell_t *shp,register char *string)
126da2e3ebdSchin {
127da2e3ebdSchin if(string)
128da2e3ebdSchin {
129da2e3ebdSchin int jmp_val;
1307c2fbfb3SApril Chin int savexit = shp->savexit;
131da2e3ebdSchin struct checkpt buff;
132da2e3ebdSchin sh_pushcontext(&buff,SH_JMPSUB);
133da2e3ebdSchin jmp_val = sigsetjmp(buff.buff,0);
134da2e3ebdSchin if(jmp_val == 0)
1357c2fbfb3SApril Chin string = sh_mactrim(shp,string,0);
136da2e3ebdSchin sh_popcontext(&buff);
1377c2fbfb3SApril Chin shp->savexit = savexit;
138da2e3ebdSchin return(string);
139da2e3ebdSchin }
140da2e3ebdSchin return("");
141da2e3ebdSchin }
142da2e3ebdSchin
143da2e3ebdSchin /*
144da2e3ebdSchin * Perform parameter expansion, command substitution, and arithmetic
145da2e3ebdSchin * expansion on <str>.
146da2e3ebdSchin * If <mode> greater than 1 file expansion is performed if the result
147da2e3ebdSchin * yields a single pathname.
148da2e3ebdSchin * If <mode> negative, than expansion rules for assignment are applied.
149da2e3ebdSchin */
sh_mactrim(Shell_t * shp,char * str,register int mode)1507c2fbfb3SApril Chin char *sh_mactrim(Shell_t *shp, char *str, register int mode)
151da2e3ebdSchin {
1527c2fbfb3SApril Chin register Mac_t *mp = (Mac_t*)shp->mac_context;
1537c2fbfb3SApril Chin Stk_t *stkp = shp->stk;
154da2e3ebdSchin Mac_t savemac;
155da2e3ebdSchin savemac = *mp;
1567c2fbfb3SApril Chin stkseek(stkp,0);
157da2e3ebdSchin mp->arith = (mode==3);
158da2e3ebdSchin mp->let = 0;
1597c2fbfb3SApril Chin shp->argaddr = 0;
160da2e3ebdSchin mp->pattern = (mode==1||mode==2);
161da2e3ebdSchin mp->patfound = 0;
1627c2fbfb3SApril Chin mp->assign = 0;
1637c2fbfb3SApril Chin if(mode<0)
1647c2fbfb3SApril Chin mp->assign = -mode;
165da2e3ebdSchin mp->quoted = mp->lit = mp->split = mp->quote = 0;
166da2e3ebdSchin mp->sp = 0;
1677c2fbfb3SApril Chin if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
168da2e3ebdSchin mp->ifs = *mp->ifsp;
169da2e3ebdSchin else
170da2e3ebdSchin mp->ifs = ' ';
1717c2fbfb3SApril Chin stkseek(stkp,0);
172da2e3ebdSchin fcsopen(str);
173da2e3ebdSchin copyto(mp,0,mp->arith);
1747c2fbfb3SApril Chin str = stkfreeze(stkp,1);
175da2e3ebdSchin if(mode==2)
176da2e3ebdSchin {
177da2e3ebdSchin /* expand only if unique */
178da2e3ebdSchin struct argnod *arglist=0;
179da2e3ebdSchin if((mode=path_expand(str,&arglist))==1)
180da2e3ebdSchin str = arglist->argval;
181da2e3ebdSchin else if(mode>1)
182da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_ambiguous,str);
183da2e3ebdSchin sh_trim(str);
184da2e3ebdSchin }
185da2e3ebdSchin *mp = savemac;
186da2e3ebdSchin return(str);
187da2e3ebdSchin }
188da2e3ebdSchin
189da2e3ebdSchin /*
190da2e3ebdSchin * Perform all the expansions on the argument <argp>
191da2e3ebdSchin */
sh_macexpand(Shell_t * shp,register struct argnod * argp,struct argnod ** arghead,int flag)1927c2fbfb3SApril Chin int sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag)
193da2e3ebdSchin {
194da2e3ebdSchin register int flags = argp->argflag;
195da2e3ebdSchin register char *str = argp->argval;
1967c2fbfb3SApril Chin register Mac_t *mp = (Mac_t*)shp->mac_context;
1977c2fbfb3SApril Chin char **saveargaddr = shp->argaddr;
198da2e3ebdSchin Mac_t savemac;
1997c2fbfb3SApril Chin Stk_t *stkp = shp->stk;
200da2e3ebdSchin savemac = *mp;
201da2e3ebdSchin mp->sp = 0;
2027c2fbfb3SApril Chin if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
203da2e3ebdSchin mp->ifs = *mp->ifsp;
204da2e3ebdSchin else
205da2e3ebdSchin mp->ifs = ' ';
2067c2fbfb3SApril Chin if((flag&ARG_OPTIMIZE) && !shp->indebug)
2077c2fbfb3SApril Chin shp->argaddr = (char**)&argp->argchn.ap;
208da2e3ebdSchin else
2097c2fbfb3SApril Chin shp->argaddr = 0;
210da2e3ebdSchin mp->arghead = arghead;
211da2e3ebdSchin mp->quoted = mp->lit = mp->quote = 0;
212da2e3ebdSchin mp->arith = ((flag&ARG_ARITH)!=0);
213da2e3ebdSchin mp->let = ((flag&ARG_LET)!=0);
214da2e3ebdSchin mp->split = !(flag&ARG_ASSIGN);
215da2e3ebdSchin mp->assign = !mp->split;
216da2e3ebdSchin mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB);
2177c2fbfb3SApril Chin mp->arrayok = mp->arith || (flag&ARG_ARRAYOK);
218da2e3ebdSchin str = argp->argval;
219da2e3ebdSchin fcsopen(str);
220da2e3ebdSchin mp->fields = 0;
221da2e3ebdSchin if(!arghead)
222da2e3ebdSchin {
223da2e3ebdSchin mp->split = 0;
224da2e3ebdSchin mp->pattern = ((flag&ARG_EXP)!=0);
2257c2fbfb3SApril Chin stkseek(stkp,0);
226da2e3ebdSchin }
227da2e3ebdSchin else
228da2e3ebdSchin {
2297c2fbfb3SApril Chin stkseek(stkp,ARGVAL);
2307c2fbfb3SApril Chin *stkptr(stkp,ARGVAL-1) = 0;
231da2e3ebdSchin }
232da2e3ebdSchin mp->patfound = 0;
2337c2fbfb3SApril Chin if(mp->pattern)
2347c2fbfb3SApril Chin mp->arrayok = 0;
235da2e3ebdSchin copyto(mp,0,mp->arith);
236da2e3ebdSchin if(!arghead)
237da2e3ebdSchin {
2387c2fbfb3SApril Chin argp->argchn.cp = stkfreeze(stkp,1);
2397c2fbfb3SApril Chin if(shp->argaddr)
240da2e3ebdSchin argp->argflag |= ARG_MAKE;
241da2e3ebdSchin }
242da2e3ebdSchin else
243da2e3ebdSchin {
244da2e3ebdSchin endfield(mp,mp->quoted);
245da2e3ebdSchin flags = mp->fields;
2467c2fbfb3SApril Chin if(flags==1 && shp->argaddr)
247da2e3ebdSchin argp->argchn.ap = *arghead;
248da2e3ebdSchin }
2497c2fbfb3SApril Chin shp->argaddr = saveargaddr;
250da2e3ebdSchin *mp = savemac;
251da2e3ebdSchin return(flags);
252da2e3ebdSchin }
253da2e3ebdSchin
254da2e3ebdSchin /*
255da2e3ebdSchin * Expand here document which is stored in <infile> or <string>
256da2e3ebdSchin * The result is written to <outfile>
257da2e3ebdSchin */
sh_machere(Shell_t * shp,Sfio_t * infile,Sfio_t * outfile,char * string)2587c2fbfb3SApril Chin void sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string)
259da2e3ebdSchin {
260da2e3ebdSchin register int c,n;
261da2e3ebdSchin register const char *state = sh_lexstates[ST_QUOTE];
262da2e3ebdSchin register char *cp;
2637c2fbfb3SApril Chin register Mac_t *mp = (Mac_t*)shp->mac_context;
2647c2fbfb3SApril Chin Lex_t *lp = (Lex_t*)mp->shp->lex_context;
265da2e3ebdSchin Fcin_t save;
266da2e3ebdSchin Mac_t savemac;
2677c2fbfb3SApril Chin Stk_t *stkp = shp->stk;
268da2e3ebdSchin savemac = *mp;
2697c2fbfb3SApril Chin stkseek(stkp,0);
2707c2fbfb3SApril Chin shp->argaddr = 0;
271da2e3ebdSchin mp->sp = outfile;
272da2e3ebdSchin mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0;
273da2e3ebdSchin mp->quote = 1;
2747c2fbfb3SApril Chin mp->ifsp = nv_getval(sh_scoped(shp,IFSNOD));
275da2e3ebdSchin mp->ifs = ' ';
276da2e3ebdSchin fcsave(&save);
277da2e3ebdSchin if(infile)
278da2e3ebdSchin fcfopen(infile);
279da2e3ebdSchin else
280da2e3ebdSchin fcsopen(string);
2817c2fbfb3SApril Chin fcnotify(0,lp);
282da2e3ebdSchin cp = fcseek(0);
283da2e3ebdSchin while(1)
284da2e3ebdSchin {
285da2e3ebdSchin #if SHOPT_MULTIBYTE
286da2e3ebdSchin if(mbwide())
287da2e3ebdSchin {
288da2e3ebdSchin do
289da2e3ebdSchin {
290da2e3ebdSchin ssize_t len;
291da2e3ebdSchin switch(len = mbsize(cp))
292da2e3ebdSchin {
293da2e3ebdSchin case -1: /* illegal multi-byte char */
294da2e3ebdSchin case 0:
295da2e3ebdSchin case 1:
296da2e3ebdSchin n=state[*(unsigned char*)cp++];
297da2e3ebdSchin break;
298da2e3ebdSchin default:
2997c2fbfb3SApril Chin /* use state of alpha character */
300da2e3ebdSchin n=state['a'];
301da2e3ebdSchin cp += len;
302da2e3ebdSchin }
303da2e3ebdSchin }
304da2e3ebdSchin while(n == 0);
305da2e3ebdSchin }
306da2e3ebdSchin else
307da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
308da2e3ebdSchin while((n=state[*(unsigned char*)cp++])==0);
309da2e3ebdSchin if(n==S_NL || n==S_QUOTE || n==S_RBRA)
310da2e3ebdSchin continue;
311da2e3ebdSchin if(c=(cp-1)-fcseek(0))
312da2e3ebdSchin sfwrite(outfile,fcseek(0),c);
313da2e3ebdSchin cp = fcseek(c+1);
314da2e3ebdSchin switch(n)
315da2e3ebdSchin {
316da2e3ebdSchin case S_EOF:
317da2e3ebdSchin if((n=fcfill()) <=0)
318da2e3ebdSchin {
319da2e3ebdSchin /* ignore 0 byte when reading from file */
320da2e3ebdSchin if(n==0 && fcfile())
321da2e3ebdSchin continue;
322da2e3ebdSchin fcrestore(&save);
323da2e3ebdSchin *mp = savemac;
324da2e3ebdSchin return;
325da2e3ebdSchin }
326da2e3ebdSchin cp = fcseek(-1);
327da2e3ebdSchin continue;
328da2e3ebdSchin case S_ESC:
329da2e3ebdSchin fcgetc(c);
330da2e3ebdSchin cp=fcseek(-1);
331da2e3ebdSchin if(c>0)
332da2e3ebdSchin cp++;
333da2e3ebdSchin if(!isescchar(state[c]))
334da2e3ebdSchin sfputc(outfile,ESCAPE);
335da2e3ebdSchin continue;
336da2e3ebdSchin case S_GRAVE:
3377c2fbfb3SApril Chin comsubst(mp,(Shnode_t*)0,0);
338da2e3ebdSchin break;
339da2e3ebdSchin case S_DOL:
340da2e3ebdSchin c = fcget();
341da2e3ebdSchin if(c=='.')
342da2e3ebdSchin goto regular;
343da2e3ebdSchin again:
344da2e3ebdSchin switch(n=sh_lexstates[ST_DOL][c])
345da2e3ebdSchin {
346da2e3ebdSchin case S_ALP: case S_SPC1: case S_SPC2:
347da2e3ebdSchin case S_DIG: case S_LBRA:
348da2e3ebdSchin {
349da2e3ebdSchin Fcin_t save2;
3507c2fbfb3SApril Chin int offset = stktell(stkp);
351da2e3ebdSchin int offset2;
3527c2fbfb3SApril Chin sfputc(stkp,c);
353da2e3ebdSchin if(n==S_LBRA)
3547c2fbfb3SApril Chin {
3557c2fbfb3SApril Chin c = fcget();
3567c2fbfb3SApril Chin fcseek(-1);
3577c2fbfb3SApril Chin if(sh_lexstates[ST_NORM][c]==S_BREAK)
3587c2fbfb3SApril Chin {
3597c2fbfb3SApril Chin comsubst(mp,(Shnode_t*)0,2);
3607c2fbfb3SApril Chin break;
3617c2fbfb3SApril Chin }
3627c2fbfb3SApril Chin sh_lexskip(lp,RBRACE,1,ST_BRACE);
3637c2fbfb3SApril Chin }
364da2e3ebdSchin else if(n==S_ALP)
365da2e3ebdSchin {
366da2e3ebdSchin while(fcgetc(c),isaname(c))
3677c2fbfb3SApril Chin sfputc(stkp,c);
368da2e3ebdSchin fcseek(-1);
369da2e3ebdSchin }
3707c2fbfb3SApril Chin sfputc(stkp,0);
3717c2fbfb3SApril Chin offset2 = stktell(stkp);
372da2e3ebdSchin fcsave(&save2);
3737c2fbfb3SApril Chin fcsopen(stkptr(stkp,offset));
374da2e3ebdSchin varsub(mp);
3757c2fbfb3SApril Chin if(c=stktell(stkp)-offset2)
3767c2fbfb3SApril Chin sfwrite(outfile,(char*)stkptr(stkp,offset2),c);
377da2e3ebdSchin fcrestore(&save2);
3787c2fbfb3SApril Chin stkseek(stkp,offset);
379da2e3ebdSchin break;
380da2e3ebdSchin }
381da2e3ebdSchin case S_PAR:
3827c2fbfb3SApril Chin comsubst(mp,(Shnode_t*)0,1);
383da2e3ebdSchin break;
384da2e3ebdSchin case S_EOF:
385da2e3ebdSchin if((c=fcfill()) > 0)
386da2e3ebdSchin goto again;
387da2e3ebdSchin /* FALL THRU */
388da2e3ebdSchin default:
389da2e3ebdSchin regular:
390da2e3ebdSchin sfputc(outfile,'$');
391da2e3ebdSchin fcseek(-1);
392da2e3ebdSchin break;
393da2e3ebdSchin }
394da2e3ebdSchin }
395da2e3ebdSchin cp = fcseek(0);
396da2e3ebdSchin }
397da2e3ebdSchin }
398da2e3ebdSchin
399da2e3ebdSchin /*
400da2e3ebdSchin * expand argument but do not trim pattern characters
401da2e3ebdSchin */
sh_macpat(Shell_t * shp,register struct argnod * arg,int flags)4027c2fbfb3SApril Chin char *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags)
403da2e3ebdSchin {
404da2e3ebdSchin register char *sp = arg->argval;
405da2e3ebdSchin if((arg->argflag&ARG_RAW))
406da2e3ebdSchin return(sp);
4077c2fbfb3SApril Chin sh_stats(STAT_ARGEXPAND);
408da2e3ebdSchin if(flags&ARG_OPTIMIZE)
409da2e3ebdSchin arg->argchn.ap=0;
410da2e3ebdSchin if(!(sp=arg->argchn.cp))
411da2e3ebdSchin {
4127c2fbfb3SApril Chin sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK);
413da2e3ebdSchin sp = arg->argchn.cp;
414da2e3ebdSchin if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE))
415da2e3ebdSchin arg->argchn.cp = 0;
416da2e3ebdSchin arg->argflag &= ~ARG_MAKE;
417da2e3ebdSchin }
418da2e3ebdSchin else
4197c2fbfb3SApril Chin sh_stats(STAT_ARGHITS);
420da2e3ebdSchin return(sp);
421da2e3ebdSchin }
422da2e3ebdSchin
423da2e3ebdSchin /*
424da2e3ebdSchin * Process the characters up to <endch> or end of input string
425da2e3ebdSchin */
copyto(register Mac_t * mp,int endch,int newquote)426da2e3ebdSchin static void copyto(register Mac_t *mp,int endch, int newquote)
427da2e3ebdSchin {
428da2e3ebdSchin register int c,n;
429da2e3ebdSchin register const char *state = sh_lexstates[ST_MACRO];
430da2e3ebdSchin register char *cp,*first;
4317c2fbfb3SApril Chin Lex_t *lp = (Lex_t*)mp->shp->lex_context;
432da2e3ebdSchin int tilde = -1;
433da2e3ebdSchin int oldquote = mp->quote;
434da2e3ebdSchin int ansi_c = 0;
435da2e3ebdSchin int paren = 0;
436da2e3ebdSchin int ere = 0;
437da2e3ebdSchin int brace = 0;
438da2e3ebdSchin Sfio_t *sp = mp->sp;
4397c2fbfb3SApril Chin Stk_t *stkp = mp->shp->stk;
440da2e3ebdSchin mp->sp = NIL(Sfio_t*);
441da2e3ebdSchin mp->quote = newquote;
442da2e3ebdSchin first = cp = fcseek(0);
4439a6f360eSCasper H.S. Dik if(!mp->quote && *cp=='~' && cp[1]!=LPAREN)
4447c2fbfb3SApril Chin tilde = stktell(stkp);
445da2e3ebdSchin /* handle // operator specially */
446da2e3ebdSchin if(mp->pattern==2 && *cp=='/')
447da2e3ebdSchin cp++;
448da2e3ebdSchin while(1)
449da2e3ebdSchin {
450da2e3ebdSchin #if SHOPT_MULTIBYTE
451da2e3ebdSchin if(mbwide())
452da2e3ebdSchin {
453da2e3ebdSchin ssize_t len;
454da2e3ebdSchin do
455da2e3ebdSchin {
456da2e3ebdSchin switch(len = mbsize(cp))
457da2e3ebdSchin {
458da2e3ebdSchin case -1: /* illegal multi-byte char */
459da2e3ebdSchin case 0:
460da2e3ebdSchin len = 1;
461da2e3ebdSchin case 1:
462da2e3ebdSchin n = state[*(unsigned char*)cp++];
463da2e3ebdSchin break;
464da2e3ebdSchin default:
465da2e3ebdSchin /* treat as if alpha */
466da2e3ebdSchin cp += len;
467da2e3ebdSchin n=state['a'];
468da2e3ebdSchin }
469da2e3ebdSchin }
470da2e3ebdSchin while(n == 0);
471da2e3ebdSchin c = (cp-len) - first;
472da2e3ebdSchin }
473da2e3ebdSchin else
474da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
475da2e3ebdSchin {
476da2e3ebdSchin while((n=state[*(unsigned char*)cp++])==0);
477da2e3ebdSchin c = (cp-1) - first;
478da2e3ebdSchin }
479da2e3ebdSchin switch(n)
480da2e3ebdSchin {
481da2e3ebdSchin case S_ESC:
482da2e3ebdSchin if(ansi_c)
483da2e3ebdSchin {
484da2e3ebdSchin /* process ANSI-C escape character */
485da2e3ebdSchin char *addr= --cp;
486da2e3ebdSchin if(c)
4877c2fbfb3SApril Chin sfwrite(stkp,first,c);
488da2e3ebdSchin c = chresc(cp,&addr);
489da2e3ebdSchin cp = addr;
490da2e3ebdSchin first = fcseek(cp-first);
491da2e3ebdSchin #if SHOPT_MULTIBYTE
492da2e3ebdSchin if(c > UCHAR_MAX && mbwide())
493da2e3ebdSchin {
494da2e3ebdSchin int i;
495da2e3ebdSchin unsigned char mb[8];
496da2e3ebdSchin
497da2e3ebdSchin n = wctomb((char*)mb, c);
498da2e3ebdSchin for(i=0;i<n;i++)
4997c2fbfb3SApril Chin sfputc(stkp,mb[i]);
500da2e3ebdSchin }
501da2e3ebdSchin else
502da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
5037c2fbfb3SApril Chin sfputc(stkp,c);
504da2e3ebdSchin if(c==ESCAPE && mp->pattern)
5057c2fbfb3SApril Chin sfputc(stkp,ESCAPE);
506da2e3ebdSchin break;
507da2e3ebdSchin }
508da2e3ebdSchin else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.'))
509da2e3ebdSchin break;
510da2e3ebdSchin else if(mp->split && endch && !mp->quote && !mp->lit)
511da2e3ebdSchin {
512da2e3ebdSchin if(c)
513da2e3ebdSchin mac_copy(mp,first,c);
514da2e3ebdSchin cp = fcseek(c+2);
515da2e3ebdSchin if(c= cp[-1])
516da2e3ebdSchin {
5177c2fbfb3SApril Chin sfputc(stkp,c);
518da2e3ebdSchin if(c==ESCAPE)
5197c2fbfb3SApril Chin sfputc(stkp,ESCAPE);
520da2e3ebdSchin }
521da2e3ebdSchin else
522da2e3ebdSchin cp--;
523da2e3ebdSchin first = cp;
524da2e3ebdSchin break;
525da2e3ebdSchin }
526da2e3ebdSchin n = state[*(unsigned char*)cp];
527da2e3ebdSchin if(n==S_ENDCH && *cp!=endch)
528da2e3ebdSchin n = S_PAT;
529da2e3ebdSchin if(mp->pattern)
530da2e3ebdSchin {
531da2e3ebdSchin /* preserve \digit for pattern matching */
532da2e3ebdSchin /* also \alpha for extended patterns */
53334f9b3eeSRoland Mainz if(!mp->lit && !mp->quote)
53434f9b3eeSRoland Mainz {
53534f9b3eeSRoland Mainz if((n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP)))
536da2e3ebdSchin break;
53734f9b3eeSRoland Mainz if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp))
53834f9b3eeSRoland Mainz break;
53934f9b3eeSRoland Mainz }
540da2e3ebdSchin /* followed by file expansion */
541da2e3ebdSchin if(!mp->lit && (n==S_ESC || (!mp->quote &&
542da2e3ebdSchin (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-'))))
543da2e3ebdSchin {
544da2e3ebdSchin cp += (n!=S_EOF);
5457c2fbfb3SApril Chin if(ere && n==S_ESC && *cp =='\\' && cp[1]=='$')
5467c2fbfb3SApril Chin {
5477c2fbfb3SApril Chin /* convert \\\$ into \$' */
5487c2fbfb3SApril Chin sfwrite(stkp,first,c+1);
5497c2fbfb3SApril Chin cp = first = fcseek(c+3);
5507c2fbfb3SApril Chin }
551da2e3ebdSchin break;
552da2e3ebdSchin }
5537c2fbfb3SApril Chin if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH)))
554da2e3ebdSchin {
555da2e3ebdSchin /* add \ for file expansion */
5567c2fbfb3SApril Chin sfwrite(stkp,first,c+1);
557da2e3ebdSchin first = fcseek(c);
558da2e3ebdSchin break;
559da2e3ebdSchin }
560da2e3ebdSchin }
561da2e3ebdSchin if(mp->lit)
562da2e3ebdSchin break;
563da2e3ebdSchin if(!mp->quote || isqescchar(n) || n==S_ENDCH)
564da2e3ebdSchin {
565da2e3ebdSchin /* eliminate \ */
566da2e3ebdSchin if(c)
5677c2fbfb3SApril Chin sfwrite(stkp,first,c);
568da2e3ebdSchin /* check new-line joining */
569da2e3ebdSchin first = fcseek(c+1);
570da2e3ebdSchin }
571da2e3ebdSchin cp += (n!=S_EOF);
572da2e3ebdSchin break;
573da2e3ebdSchin case S_GRAVE: case S_DOL:
574da2e3ebdSchin if(mp->lit)
575da2e3ebdSchin break;
576da2e3ebdSchin if(c)
577da2e3ebdSchin {
578da2e3ebdSchin if(mp->split && !mp->quote && endch)
579da2e3ebdSchin mac_copy(mp,first,c);
580da2e3ebdSchin else
5817c2fbfb3SApril Chin sfwrite(stkp,first,c);
582da2e3ebdSchin }
583da2e3ebdSchin first = fcseek(c+1);
584da2e3ebdSchin c = mp->pattern;
585da2e3ebdSchin if(n==S_GRAVE)
5867c2fbfb3SApril Chin comsubst(mp,(Shnode_t*)0,0);
587da2e3ebdSchin else if((n= *cp)==0 || !varsub(mp))
588da2e3ebdSchin {
589da2e3ebdSchin if(n=='\'' && !mp->quote)
590da2e3ebdSchin ansi_c = 1;
591da2e3ebdSchin else if(mp->quote || n!='"')
5927c2fbfb3SApril Chin sfputc(stkp,'$');
593da2e3ebdSchin }
594da2e3ebdSchin cp = first = fcseek(0);
595da2e3ebdSchin if(*cp)
596da2e3ebdSchin mp->pattern = c;
597da2e3ebdSchin break;
598da2e3ebdSchin case S_ENDCH:
599da2e3ebdSchin if((mp->lit || cp[-1]!=endch || mp->quote!=newquote))
600da2e3ebdSchin goto pattern;
601da2e3ebdSchin if(endch==RBRACE && *cp==LPAREN && mp->pattern && brace)
602da2e3ebdSchin goto pattern;
603da2e3ebdSchin case S_EOF:
604da2e3ebdSchin if(c)
605da2e3ebdSchin {
606da2e3ebdSchin if(mp->split && !mp->quote && !mp->lit && endch)
607da2e3ebdSchin mac_copy(mp,first,c);
608da2e3ebdSchin else
6097c2fbfb3SApril Chin sfwrite(stkp,first,c);
610da2e3ebdSchin }
611da2e3ebdSchin c += (n!=S_EOF);
612da2e3ebdSchin first = fcseek(c);
613da2e3ebdSchin if(tilde>=0)
6147c2fbfb3SApril Chin tilde_expand2(mp->shp,tilde);
615da2e3ebdSchin goto done;
616da2e3ebdSchin case S_QUOTE:
617da2e3ebdSchin if(mp->lit || mp->arith)
618da2e3ebdSchin break;
619da2e3ebdSchin case S_LIT:
620da2e3ebdSchin if(mp->arith)
621da2e3ebdSchin {
622da2e3ebdSchin if((*cp=='`' || *cp=='[') && cp[1]=='\'')
623da2e3ebdSchin cp +=2;
624da2e3ebdSchin break;
625da2e3ebdSchin }
626da2e3ebdSchin if(n==S_LIT && mp->quote)
627da2e3ebdSchin break;
628da2e3ebdSchin if(c)
629da2e3ebdSchin {
630da2e3ebdSchin if(mp->split && endch && !mp->quote && !mp->lit)
631da2e3ebdSchin mac_copy(mp,first,c);
632da2e3ebdSchin else
6337c2fbfb3SApril Chin sfwrite(stkp,first,c);
634da2e3ebdSchin }
635da2e3ebdSchin first = fcseek(c+1);
636da2e3ebdSchin if(n==S_LIT)
637da2e3ebdSchin {
638da2e3ebdSchin if(mp->quote)
639da2e3ebdSchin continue;
640da2e3ebdSchin if(mp->lit)
641da2e3ebdSchin mp->lit = ansi_c = 0;
642da2e3ebdSchin else
643da2e3ebdSchin mp->lit = 1;
644da2e3ebdSchin }
645da2e3ebdSchin else
646da2e3ebdSchin mp->quote = !mp->quote;
647da2e3ebdSchin mp->quoted++;
648da2e3ebdSchin break;
649da2e3ebdSchin case S_BRACT:
6507c2fbfb3SApril Chin if(mp->arith || (((mp->assign&1) || endch==RBRACT) &&
651da2e3ebdSchin !(mp->quote || mp->lit)))
652da2e3ebdSchin {
653da2e3ebdSchin int offset=0,oldpat = mp->pattern;
6547c2fbfb3SApril Chin int oldarith = mp->arith, oldsub=mp->subcopy;
6557c2fbfb3SApril Chin sfwrite(stkp,first,++c);
65634f9b3eeSRoland Mainz if(mp->assign&1)
65734f9b3eeSRoland Mainz {
65834f9b3eeSRoland Mainz if(first[c-2]=='.')
6597c2fbfb3SApril Chin offset = stktell(stkp);
66034f9b3eeSRoland Mainz if(isastchar(*cp) && cp[1]==']')
66134f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_exit(1),
66234f9b3eeSRoland Mainz e_badsubscript,*cp);
66334f9b3eeSRoland Mainz }
664da2e3ebdSchin first = fcseek(c);
665da2e3ebdSchin mp->pattern = 4;
666da2e3ebdSchin mp->arith = 0;
6677c2fbfb3SApril Chin mp->subcopy = 0;
668da2e3ebdSchin copyto(mp,RBRACT,0);
6697c2fbfb3SApril Chin mp->subcopy = oldsub;
670da2e3ebdSchin mp->arith = oldarith;
671da2e3ebdSchin mp->pattern = oldpat;
6727c2fbfb3SApril Chin sfputc(stkp,RBRACT);
673da2e3ebdSchin if(offset)
674da2e3ebdSchin {
6757c2fbfb3SApril Chin cp = stkptr(stkp,stktell(stkp));
6767c2fbfb3SApril Chin if(sh_checkid(stkptr(stkp,offset),cp)!=cp)
6777c2fbfb3SApril Chin stkseek(stkp,stktell(stkp)-2);
678da2e3ebdSchin }
679da2e3ebdSchin cp = first = fcseek(0);
680da2e3ebdSchin break;
681da2e3ebdSchin }
682da2e3ebdSchin case S_PAT:
683da2e3ebdSchin if(mp->pattern && !(mp->quote || mp->lit))
684da2e3ebdSchin {
685da2e3ebdSchin mp->patfound = mp->pattern;
686da2e3ebdSchin if((n=cp[-1])==LPAREN)
687da2e3ebdSchin {
688da2e3ebdSchin paren++;
689da2e3ebdSchin if((cp-first)>1 && cp[-2]=='~')
690da2e3ebdSchin {
691da2e3ebdSchin char *p = cp;
692da2e3ebdSchin while((c=mbchar(p)) && c!=RPAREN && c!='E');
69334f9b3eeSRoland Mainz ere = (c=='E'||c=='A');
694da2e3ebdSchin }
695da2e3ebdSchin }
696da2e3ebdSchin else if(n==RPAREN)
697da2e3ebdSchin --paren;
698da2e3ebdSchin }
699da2e3ebdSchin goto pattern;
7007c2fbfb3SApril Chin case S_COM:
7017c2fbfb3SApril Chin if(mp->pattern==4 && (mp->quote || mp->lit))
7027c2fbfb3SApril Chin {
7037c2fbfb3SApril Chin if(c)
7047c2fbfb3SApril Chin {
7057c2fbfb3SApril Chin sfwrite(stkp,first,c);
7067c2fbfb3SApril Chin first = fcseek(c);
7077c2fbfb3SApril Chin }
7087c2fbfb3SApril Chin sfputc(stkp,ESCAPE);
7097c2fbfb3SApril Chin }
7107c2fbfb3SApril Chin break;
711da2e3ebdSchin case S_BRACE:
712da2e3ebdSchin if(!(mp->quote || mp->lit))
713da2e3ebdSchin {
714da2e3ebdSchin mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND);
715da2e3ebdSchin brace = 1;
716da2e3ebdSchin }
717da2e3ebdSchin pattern:
718da2e3ebdSchin if(!mp->pattern || !(mp->quote || mp->lit))
719da2e3ebdSchin {
720da2e3ebdSchin /* mark beginning of {a,b} */
721da2e3ebdSchin if(n==S_BRACE && endch==0 && mp->pattern)
722da2e3ebdSchin mp->pattern=4;
723da2e3ebdSchin if(n==S_SLASH && mp->pattern==2)
724da2e3ebdSchin mp->pattern=3;
725da2e3ebdSchin break;
726da2e3ebdSchin }
727da2e3ebdSchin if(mp->pattern==3)
728da2e3ebdSchin break;
729da2e3ebdSchin if(c)
7307c2fbfb3SApril Chin sfwrite(stkp,first,c);
731da2e3ebdSchin first = fcseek(c);
7327c2fbfb3SApril Chin sfputc(stkp,ESCAPE);
733da2e3ebdSchin break;
734da2e3ebdSchin case S_EQ:
735da2e3ebdSchin if(mp->assign==1)
736da2e3ebdSchin {
737da2e3ebdSchin if(*cp=='~' && !endch && !mp->quote && !mp->lit)
7387c2fbfb3SApril Chin tilde = stktell(stkp)+(c+1);
739da2e3ebdSchin mp->assign = 2;
740da2e3ebdSchin }
741da2e3ebdSchin break;
742da2e3ebdSchin case S_SLASH:
743da2e3ebdSchin case S_COLON:
744da2e3ebdSchin if(tilde >=0)
745da2e3ebdSchin {
746da2e3ebdSchin if(c)
7477c2fbfb3SApril Chin sfwrite(stkp,first,c);
748da2e3ebdSchin first = fcseek(c);
7497c2fbfb3SApril Chin tilde_expand2(mp->shp,tilde);
750da2e3ebdSchin tilde = -1;
751da2e3ebdSchin c=0;
752da2e3ebdSchin }
753da2e3ebdSchin if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit)
7547c2fbfb3SApril Chin tilde = stktell(stkp)+(c+1);
755da2e3ebdSchin else if(n==S_SLASH && mp->pattern==2)
756da2e3ebdSchin #if 0
757da2e3ebdSchin goto pattern;
758da2e3ebdSchin #else
759da2e3ebdSchin {
760da2e3ebdSchin if(mp->quote || mp->lit)
761da2e3ebdSchin goto pattern;
7627c2fbfb3SApril Chin sfwrite(stkp,first,c+1);
763da2e3ebdSchin first = fcseek(c+1);
7647c2fbfb3SApril Chin c = stktell(stkp);
7657c2fbfb3SApril Chin sh_lexskip(lp,RBRACE,0,ST_NESTED);
7667c2fbfb3SApril Chin stkseek(stkp,c);
767da2e3ebdSchin cp = fcseek(-1);
7687c2fbfb3SApril Chin sfwrite(stkp,first,cp-first);
769da2e3ebdSchin first=cp;
770da2e3ebdSchin }
771da2e3ebdSchin #endif
772da2e3ebdSchin break;
7737c2fbfb3SApril Chin case S_DOT:
7747c2fbfb3SApril Chin if(*cp=='.' && mp->subcopy==1)
7757c2fbfb3SApril Chin {
7767c2fbfb3SApril Chin sfwrite(stkp,first,c);
7777c2fbfb3SApril Chin sfputc(stkp,0);
7787c2fbfb3SApril Chin mp->dotdot = stktell(stkp);
7797c2fbfb3SApril Chin cp = first = fcseek(c+2);
7807c2fbfb3SApril Chin }
7817c2fbfb3SApril Chin break;
782da2e3ebdSchin }
783da2e3ebdSchin }
784da2e3ebdSchin done:
785da2e3ebdSchin mp->sp = sp;
786da2e3ebdSchin mp->quote = oldquote;
787da2e3ebdSchin }
788da2e3ebdSchin
789da2e3ebdSchin /*
790da2e3ebdSchin * copy <str> to stack performing sub-expression substitutions
791da2e3ebdSchin */
mac_substitute(Mac_t * mp,register char * cp,char * str,register int subexp[],int subsize)792da2e3ebdSchin static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize)
793da2e3ebdSchin {
794da2e3ebdSchin register int c,n;
795da2e3ebdSchin register char *first=fcseek(0);
796da2e3ebdSchin char *ptr;
797da2e3ebdSchin Mac_t savemac;
7987c2fbfb3SApril Chin Stk_t *stkp = mp->shp->stk;
7997c2fbfb3SApril Chin n = stktell(stkp);
800da2e3ebdSchin savemac = *mp;
801da2e3ebdSchin mp->pattern = 3;
802da2e3ebdSchin mp->split = 0;
803da2e3ebdSchin fcsopen(cp);
804da2e3ebdSchin copyto(mp,0,0);
8057c2fbfb3SApril Chin sfputc(stkp,0);
8067c2fbfb3SApril Chin ptr = cp = strdup(stkptr(stkp,n));
8077c2fbfb3SApril Chin stkseek(stkp,n);
808da2e3ebdSchin *mp = savemac;
809da2e3ebdSchin fcsopen(first);
810da2e3ebdSchin first = cp;
811da2e3ebdSchin while(1)
812da2e3ebdSchin {
813da2e3ebdSchin while((c= *cp++) && c!=ESCAPE);
814da2e3ebdSchin if(c==0)
815da2e3ebdSchin break;
816da2e3ebdSchin if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize))
817da2e3ebdSchin {
818da2e3ebdSchin c = cp-first-2;
819da2e3ebdSchin if(c)
820da2e3ebdSchin mac_copy(mp,first,c);
821da2e3ebdSchin first=cp;
822da2e3ebdSchin if(n=='\\' || n==RBRACE)
823da2e3ebdSchin {
824da2e3ebdSchin first--;
825da2e3ebdSchin continue;
826da2e3ebdSchin }
827da2e3ebdSchin if((c=subexp[2*n])>=0)
828da2e3ebdSchin {
829da2e3ebdSchin if((n=subexp[2*n+1]-c)>0)
830da2e3ebdSchin mac_copy(mp,str+c,n);
831da2e3ebdSchin }
832da2e3ebdSchin }
833da2e3ebdSchin else if(n==0)
834da2e3ebdSchin break;
835da2e3ebdSchin }
836da2e3ebdSchin if(n=cp-first-1)
837da2e3ebdSchin mac_copy(mp,first,n);
838da2e3ebdSchin free(ptr);
839da2e3ebdSchin }
840da2e3ebdSchin
841da2e3ebdSchin #if SHOPT_FILESCAN
842da2e3ebdSchin #define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0]))
843da2e3ebdSchin #define MAX_ARGN (32*1024)
844da2e3ebdSchin
845da2e3ebdSchin /*
846da2e3ebdSchin * compute the arguments $1 ... $n and $# from the current line as needed
847da2e3ebdSchin * save line offsets in the offsets array.
848da2e3ebdSchin */
getdolarg(Shell_t * shp,int n,int * size)849da2e3ebdSchin static char *getdolarg(Shell_t *shp, int n, int *size)
850da2e3ebdSchin {
851da2e3ebdSchin register int c=S_DELIM, d=shp->ifstable['\\'];
852da2e3ebdSchin register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line;
853da2e3ebdSchin register int m=shp->offsets[0],delim=0;
854da2e3ebdSchin if(m==0)
855da2e3ebdSchin return(0);
856da2e3ebdSchin if(m<0)
857da2e3ebdSchin m = 0;
858da2e3ebdSchin else if(n<=m)
859da2e3ebdSchin m = n-1;
860da2e3ebdSchin else
861da2e3ebdSchin m--;
862da2e3ebdSchin if(m >= MAX_OFFSETS-1)
863da2e3ebdSchin m = MAX_OFFSETS-2;
864da2e3ebdSchin cp += shp->offsets[m+1];
865da2e3ebdSchin n -= m;
866da2e3ebdSchin shp->ifstable['\\'] = 0;
867da2e3ebdSchin shp->ifstable[0] = S_EOF;
868da2e3ebdSchin while(1)
869da2e3ebdSchin {
870da2e3ebdSchin if(c==S_DELIM)
871da2e3ebdSchin while(shp->ifstable[*cp++]==S_SPACE);
872da2e3ebdSchin first = --cp;
873da2e3ebdSchin if(++m < MAX_OFFSETS)
874da2e3ebdSchin shp->offsets[m] = (first-(unsigned char*)shp->cur_line);
875da2e3ebdSchin while((c=shp->ifstable[*cp++])==0);
876da2e3ebdSchin last = cp-1;
877da2e3ebdSchin if(c==S_SPACE)
878da2e3ebdSchin while((c=shp->ifstable[*cp++])==S_SPACE);
879da2e3ebdSchin if(--n==0 || c==S_EOF)
880da2e3ebdSchin {
881da2e3ebdSchin if(last==first && c==S_EOF && (!delim || (m>1)))
882da2e3ebdSchin {
883da2e3ebdSchin n++;
884da2e3ebdSchin m--;
885da2e3ebdSchin }
886da2e3ebdSchin break;
887da2e3ebdSchin }
888da2e3ebdSchin delim = (c==S_DELIM);
889da2e3ebdSchin }
890da2e3ebdSchin shp->ifstable['\\'] = d;
891da2e3ebdSchin if(m > shp->offsets[0])
892da2e3ebdSchin shp->offsets[0] = m;
893da2e3ebdSchin if(n)
894da2e3ebdSchin first = last = 0;
895da2e3ebdSchin if(size)
896da2e3ebdSchin *size = last-first;
897da2e3ebdSchin return((char*)first);
898da2e3ebdSchin }
899da2e3ebdSchin #endif /* SHOPT_FILESCAN */
900da2e3ebdSchin
901da2e3ebdSchin /*
902da2e3ebdSchin * get the prefix after name reference resolution
903da2e3ebdSchin */
prefix(Shell_t * shp,char * id)9047c2fbfb3SApril Chin static char *prefix(Shell_t *shp, char *id)
905da2e3ebdSchin {
906da2e3ebdSchin Namval_t *np;
90734f9b3eeSRoland Mainz register char *sub=0, *cp = strchr(id,'.');
908da2e3ebdSchin if(cp)
909da2e3ebdSchin {
910da2e3ebdSchin *cp = 0;
9117c2fbfb3SApril Chin np = nv_search(id, shp->var_tree,0);
912da2e3ebdSchin *cp = '.';
913da2e3ebdSchin if(isastchar(cp[1]))
914da2e3ebdSchin cp[1] = 0;
915da2e3ebdSchin if(np && nv_isref(np))
916da2e3ebdSchin {
917da2e3ebdSchin int n;
918da2e3ebdSchin char *sp;
9197c2fbfb3SApril Chin shp->argaddr = 0;
92034f9b3eeSRoland Mainz while(nv_isref(np) && np->nvalue.cp)
92134f9b3eeSRoland Mainz {
92234f9b3eeSRoland Mainz sub = nv_refsub(np);
923da2e3ebdSchin np = nv_refnode(np);
92434f9b3eeSRoland Mainz if(sub)
92534f9b3eeSRoland Mainz nv_putsub(np,sub,0L);
92634f9b3eeSRoland Mainz }
92734f9b3eeSRoland Mainz id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1));
928da2e3ebdSchin memcpy(id,sp,n);
92934f9b3eeSRoland Mainz if(sub)
93034f9b3eeSRoland Mainz {
93134f9b3eeSRoland Mainz id[n++] = '[';
93234f9b3eeSRoland Mainz strcpy(&id[n],sub);
93334f9b3eeSRoland Mainz n+= strlen(sub)+1;
93434f9b3eeSRoland Mainz id[n-1] = ']';
93534f9b3eeSRoland Mainz }
93634f9b3eeSRoland Mainz strcpy(&id[n],cp);
937da2e3ebdSchin return(id);
938da2e3ebdSchin }
939da2e3ebdSchin }
940da2e3ebdSchin return(strdup(id));
941da2e3ebdSchin }
942da2e3ebdSchin
943da2e3ebdSchin /*
944da2e3ebdSchin * copy to ']' onto the stack and return offset to it
945da2e3ebdSchin */
subcopy(Mac_t * mp,int flag)946da2e3ebdSchin static int subcopy(Mac_t *mp, int flag)
947da2e3ebdSchin {
948da2e3ebdSchin int split = mp->split;
949da2e3ebdSchin int xpattern = mp->pattern;
9507c2fbfb3SApril Chin int loc = stktell(mp->shp->stk);
951da2e3ebdSchin int xarith = mp->arith;
9527c2fbfb3SApril Chin int arrayok = mp->arrayok;
953da2e3ebdSchin mp->split = 0;
954da2e3ebdSchin mp->arith = 0;
955da2e3ebdSchin mp->pattern = flag?4:0;
9567c2fbfb3SApril Chin mp->arrayok=1;
9577c2fbfb3SApril Chin mp->subcopy++;
9587c2fbfb3SApril Chin mp->dotdot = 0;
959da2e3ebdSchin copyto(mp,RBRACT,0);
9607c2fbfb3SApril Chin mp->subcopy = 0;
961da2e3ebdSchin mp->pattern = xpattern;
962da2e3ebdSchin mp->split = split;
963da2e3ebdSchin mp->arith = xarith;
9647c2fbfb3SApril Chin mp->arrayok = arrayok;
965da2e3ebdSchin return(loc);
966da2e3ebdSchin }
967da2e3ebdSchin
9687c2fbfb3SApril Chin /*
9697c2fbfb3SApril Chin * if name is a discipline function, run the function and put the results
9707c2fbfb3SApril Chin * on the stack so that ${x.foo} behaves like ${ x.foo;}
9717c2fbfb3SApril Chin */
sh_macfun(Shell_t * shp,const char * name,int offset)9727c2fbfb3SApril Chin int sh_macfun(Shell_t *shp, const char *name, int offset)
9737c2fbfb3SApril Chin {
9747c2fbfb3SApril Chin Namval_t *np, *nq;
9757c2fbfb3SApril Chin np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0);
9767c2fbfb3SApril Chin if(np)
9777c2fbfb3SApril Chin {
9787c2fbfb3SApril Chin /* treat ${x.foo} as ${x.foo;} */
9797c2fbfb3SApril Chin Shnode_t *tp;
9807c2fbfb3SApril Chin char buff[sizeof(struct dolnod)+sizeof(char*)];
9817c2fbfb3SApril Chin struct comnod node;
9827c2fbfb3SApril Chin struct dolnod *dp = (struct dolnod*)buff;
9837c2fbfb3SApril Chin memset(&node,0,sizeof(node));
9847c2fbfb3SApril Chin memset(&buff,0,sizeof(buff));
9857c2fbfb3SApril Chin tp = (Shnode_t*)&node;
9867c2fbfb3SApril Chin tp->com.comarg = (struct argnod*)dp;
9877c2fbfb3SApril Chin tp->com.comline = shp->inlineno;
98834f9b3eeSRoland Mainz dp->dolnum = 1;
9897c2fbfb3SApril Chin dp->dolval[0] = strdup(name);
9907c2fbfb3SApril Chin stkseek(shp->stk,offset);
9917c2fbfb3SApril Chin comsubst((Mac_t*)shp->mac_context,tp,2);
9927c2fbfb3SApril Chin free(dp->dolval[0]);
9937c2fbfb3SApril Chin return(1);
9947c2fbfb3SApril Chin }
9957c2fbfb3SApril Chin return(0);
9967c2fbfb3SApril Chin }
9977c2fbfb3SApril Chin
namecount(Mac_t * mp,const char * prefix)998da2e3ebdSchin static int namecount(Mac_t *mp,const char *prefix)
999da2e3ebdSchin {
1000da2e3ebdSchin int count = 0;
10017c2fbfb3SApril Chin mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1002da2e3ebdSchin while(nv_dirnext(mp->nvwalk))
1003da2e3ebdSchin count++;
1004da2e3ebdSchin nv_dirclose(mp->nvwalk);
1005da2e3ebdSchin return(count);
1006da2e3ebdSchin }
1007da2e3ebdSchin
nextname(Mac_t * mp,const char * prefix,int len)1008da2e3ebdSchin static char *nextname(Mac_t *mp,const char *prefix, int len)
1009da2e3ebdSchin {
1010da2e3ebdSchin char *cp;
1011da2e3ebdSchin if(len==0)
1012da2e3ebdSchin {
10137c2fbfb3SApril Chin mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1014da2e3ebdSchin return((char*)mp->nvwalk);
1015da2e3ebdSchin }
1016da2e3ebdSchin if(!(cp=nv_dirnext(mp->nvwalk)))
1017da2e3ebdSchin nv_dirclose(mp->nvwalk);
1018da2e3ebdSchin return(cp);
1019da2e3ebdSchin }
1020da2e3ebdSchin
1021da2e3ebdSchin /*
1022da2e3ebdSchin * This routine handles $param, ${parm}, and ${param op word}
1023da2e3ebdSchin * The input stream is assumed to be a string
1024da2e3ebdSchin */
varsub(Mac_t * mp)1025da2e3ebdSchin static int varsub(Mac_t *mp)
1026da2e3ebdSchin {
1027da2e3ebdSchin register int c;
1028da2e3ebdSchin register int type=0; /* M_xxx */
1029da2e3ebdSchin register char *v,*argp=0;
1030da2e3ebdSchin register Namval_t *np = NIL(Namval_t*);
1031da2e3ebdSchin register int dolg=0, mode=0;
10327c2fbfb3SApril Chin Lex_t *lp = (Lex_t*)mp->shp->lex_context;
1033da2e3ebdSchin Namarr_t *ap=0;
1034da2e3ebdSchin int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0;
10357c2fbfb3SApril Chin char idbuff[3], *id = idbuff, *pattern=0, *repstr, *arrmax=0;
103634f9b3eeSRoland Mainz int var=1,addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d;
10377c2fbfb3SApril Chin Stk_t *stkp = mp->shp->stk;
1038da2e3ebdSchin retry1:
1039da2e3ebdSchin mp->zeros = 0;
1040da2e3ebdSchin idbuff[0] = 0;
1041da2e3ebdSchin idbuff[1] = 0;
1042da2e3ebdSchin c = fcget();
104334f9b3eeSRoland Mainz switch(isascii(c)?sh_lexstates[ST_DOL][c]:S_ALP)
1044da2e3ebdSchin {
1045da2e3ebdSchin case S_RBRA:
1046da2e3ebdSchin if(type<M_SIZE)
1047da2e3ebdSchin goto nosub;
1048da2e3ebdSchin /* This code handles ${#} */
1049da2e3ebdSchin c = mode;
1050da2e3ebdSchin mode = type = 0;
1051da2e3ebdSchin /* FALL THRU */
1052da2e3ebdSchin case S_SPC1:
1053da2e3ebdSchin if(type==M_BRACE)
1054da2e3ebdSchin {
1055da2e3ebdSchin if(isaletter(mode=fcpeek(0)) || mode=='.')
1056da2e3ebdSchin {
1057da2e3ebdSchin if(c=='#')
1058da2e3ebdSchin type = M_SIZE;
1059da2e3ebdSchin #ifdef SHOPT_TYPEDEF
1060da2e3ebdSchin else if(c=='@')
1061da2e3ebdSchin {
1062da2e3ebdSchin type = M_TYPE;
1063da2e3ebdSchin goto retry1;
1064da2e3ebdSchin }
1065da2e3ebdSchin #endif /* SHOPT_TYPEDEF */
1066da2e3ebdSchin else
1067da2e3ebdSchin type = M_VNAME;
1068da2e3ebdSchin mode = c;
1069da2e3ebdSchin goto retry1;
1070da2e3ebdSchin }
1071da2e3ebdSchin else if(c=='#' && (isadigit(mode)||fcpeek(1)==RBRACE))
1072da2e3ebdSchin {
1073da2e3ebdSchin type = M_SIZE;
1074da2e3ebdSchin mode = c;
1075da2e3ebdSchin goto retry1;
1076da2e3ebdSchin }
1077da2e3ebdSchin }
1078da2e3ebdSchin /* FALL THRU */
1079da2e3ebdSchin case S_SPC2:
108034f9b3eeSRoland Mainz var = 0;
1081da2e3ebdSchin *id = c;
10827c2fbfb3SApril Chin v = special(mp->shp,c);
1083da2e3ebdSchin if(isastchar(c))
1084da2e3ebdSchin {
1085da2e3ebdSchin mode = c;
1086da2e3ebdSchin #if SHOPT_FILESCAN
10877c2fbfb3SApril Chin if(mp->shp->cur_line)
1088da2e3ebdSchin {
1089da2e3ebdSchin v = getdolarg(&sh,1,(int*)0);
1090da2e3ebdSchin dolmax = MAX_ARGN;
1091da2e3ebdSchin }
1092da2e3ebdSchin else
1093da2e3ebdSchin #endif /* SHOPT_FILESCAN */
10947c2fbfb3SApril Chin dolmax = mp->shp->st.dolc+1;
1095da2e3ebdSchin dolg = (v!=0);
1096da2e3ebdSchin }
1097da2e3ebdSchin break;
1098da2e3ebdSchin case S_LBRA:
1099da2e3ebdSchin if(type)
1100da2e3ebdSchin goto nosub;
1101da2e3ebdSchin type = M_BRACE;
1102da2e3ebdSchin goto retry1;
1103da2e3ebdSchin case S_PAR:
1104da2e3ebdSchin if(type)
1105da2e3ebdSchin goto nosub;
11067c2fbfb3SApril Chin comsubst(mp,(Shnode_t*)0,1);
1107da2e3ebdSchin return(1);
1108da2e3ebdSchin case S_DIG:
110934f9b3eeSRoland Mainz var = 0;
1110da2e3ebdSchin c -= '0';
11117c2fbfb3SApril Chin mp->shp->argaddr = 0;
1112da2e3ebdSchin if(type)
1113da2e3ebdSchin {
1114da2e3ebdSchin register int d;
1115da2e3ebdSchin while((d=fcget()),isadigit(d))
1116da2e3ebdSchin c = 10*c + (d-'0');
1117da2e3ebdSchin fcseek(-1);
1118da2e3ebdSchin }
1119da2e3ebdSchin idnum = c;
1120da2e3ebdSchin if(c==0)
11217c2fbfb3SApril Chin v = special(mp->shp,c);
1122da2e3ebdSchin #if SHOPT_FILESCAN
11237c2fbfb3SApril Chin else if(mp->shp->cur_line)
1124da2e3ebdSchin {
11257c2fbfb3SApril Chin mp->shp->used_pos = 1;
1126da2e3ebdSchin v = getdolarg(&sh,c,&vsize);
1127da2e3ebdSchin }
1128da2e3ebdSchin #endif /* SHOPT_FILESCAN */
11297c2fbfb3SApril Chin else if(c <= mp->shp->st.dolc)
1130da2e3ebdSchin {
11317c2fbfb3SApril Chin mp->shp->used_pos = 1;
11327c2fbfb3SApril Chin v = mp->shp->st.dolv[c];
1133da2e3ebdSchin }
1134da2e3ebdSchin else
1135da2e3ebdSchin v = 0;
1136da2e3ebdSchin break;
1137da2e3ebdSchin case S_ALP:
1138da2e3ebdSchin if(c=='.' && type==0)
1139da2e3ebdSchin goto nosub;
11407c2fbfb3SApril Chin offset = stktell(stkp);
1141da2e3ebdSchin do
1142da2e3ebdSchin {
1143da2e3ebdSchin np = 0;
1144da2e3ebdSchin do
11457c2fbfb3SApril Chin sfputc(stkp,c);
114634f9b3eeSRoland Mainz while(((c=fcget()),(!isascii(c)||isaname(c)))||type && c=='.');
11477c2fbfb3SApril Chin while(c==LBRACT && (type||mp->arrayok))
1148da2e3ebdSchin {
11497c2fbfb3SApril Chin mp->shp->argaddr=0;
1150da2e3ebdSchin if((c=fcget(),isastchar(c)) && fcpeek(0)==RBRACT)
1151da2e3ebdSchin {
1152da2e3ebdSchin if(type==M_VNAME)
1153da2e3ebdSchin type = M_SUBNAME;
1154da2e3ebdSchin idbuff[0] = mode = c;
1155da2e3ebdSchin fcget();
1156da2e3ebdSchin c = fcget();
1157da2e3ebdSchin if(c=='.' || c==LBRACT)
1158da2e3ebdSchin {
11597c2fbfb3SApril Chin sfputc(stkp,LBRACT);
11607c2fbfb3SApril Chin sfputc(stkp,mode);
11617c2fbfb3SApril Chin sfputc(stkp,RBRACT);
1162da2e3ebdSchin }
1163da2e3ebdSchin else
1164da2e3ebdSchin flag = NV_ARRAY;
1165da2e3ebdSchin break;
1166da2e3ebdSchin }
1167da2e3ebdSchin else
1168da2e3ebdSchin {
1169da2e3ebdSchin fcseek(-1);
11707c2fbfb3SApril Chin c = stktell(stkp);
11717c2fbfb3SApril Chin sfputc(stkp,LBRACT);
11727c2fbfb3SApril Chin v = stkptr(stkp,subcopy(mp,1));
11737c2fbfb3SApril Chin if(type && mp->dotdot)
11747c2fbfb3SApril Chin {
11757c2fbfb3SApril Chin mode = '@';
11767c2fbfb3SApril Chin v[-1] = 0;
1177da2e3ebdSchin if(type==M_VNAME)
1178da2e3ebdSchin type = M_SUBNAME;
11797c2fbfb3SApril Chin else if(type==M_SIZE)
11807c2fbfb3SApril Chin goto nosub;
11817c2fbfb3SApril Chin }
11827c2fbfb3SApril Chin else
11837c2fbfb3SApril Chin sfputc(stkp,RBRACT);
1184da2e3ebdSchin c = fcget();
11857c2fbfb3SApril Chin if(c==0 && type==M_VNAME)
11867c2fbfb3SApril Chin type = M_SUBNAME;
1187da2e3ebdSchin }
1188da2e3ebdSchin }
1189da2e3ebdSchin }
1190da2e3ebdSchin while(type && c=='.');
1191da2e3ebdSchin if(c==RBRACE && type && fcpeek(-2)=='.')
1192da2e3ebdSchin {
11937c2fbfb3SApril Chin /* ${x.} or ${x..} */
11947c2fbfb3SApril Chin if(fcpeek(-3) == '.')
11957c2fbfb3SApril Chin {
11967c2fbfb3SApril Chin stkseek(stkp,stktell(stkp)-2);
11977c2fbfb3SApril Chin nv_local = 1;
11987c2fbfb3SApril Chin }
11997c2fbfb3SApril Chin else
12007c2fbfb3SApril Chin {
12017c2fbfb3SApril Chin stkseek(stkp,stktell(stkp)-1);
1202da2e3ebdSchin type = M_TREE;
1203da2e3ebdSchin }
12047c2fbfb3SApril Chin }
12057c2fbfb3SApril Chin sfputc(stkp,0);
12067c2fbfb3SApril Chin id=stkptr(stkp,offset);
1207da2e3ebdSchin if(isastchar(c) && type)
1208da2e3ebdSchin {
1209da2e3ebdSchin if(type==M_VNAME || type==M_SIZE)
1210da2e3ebdSchin {
1211da2e3ebdSchin idbuff[0] = mode = c;
1212da2e3ebdSchin if((d=fcpeek(0))==c)
1213da2e3ebdSchin idbuff[1] = fcget();
1214da2e3ebdSchin if(type==M_VNAME)
1215da2e3ebdSchin type = M_NAMESCAN;
1216da2e3ebdSchin else
1217da2e3ebdSchin type = M_NAMECOUNT;
1218da2e3ebdSchin break;
1219da2e3ebdSchin }
1220da2e3ebdSchin goto nosub;
1221da2e3ebdSchin }
1222da2e3ebdSchin flag |= NV_NOASSIGN|NV_VARNAME|NV_NOADD;
1223da2e3ebdSchin if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?')))
1224da2e3ebdSchin flag &= ~NV_NOADD;
1225da2e3ebdSchin #if SHOPT_FILESCAN
12267c2fbfb3SApril Chin if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0)
1227da2e3ebdSchin {
12287c2fbfb3SApril Chin mp->shp->argaddr=0;
1229da2e3ebdSchin np = REPLYNOD;
1230da2e3ebdSchin }
1231da2e3ebdSchin else
1232da2e3ebdSchin #endif /* SHOPT_FILESCAN */
123334f9b3eeSRoland Mainz {
12347c2fbfb3SApril Chin if(mp->shp->argaddr)
1235da2e3ebdSchin flag &= ~NV_NOADD;
12367c2fbfb3SApril Chin np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL);
123734f9b3eeSRoland Mainz }
123834f9b3eeSRoland Mainz if(isastchar(mode))
123934f9b3eeSRoland Mainz var = 0;
124034f9b3eeSRoland Mainz if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY) && strchr(id,'.'))
12417c2fbfb3SApril Chin {
12427c2fbfb3SApril Chin if(sh_macfun(mp->shp,id,offset))
12437c2fbfb3SApril Chin {
12447c2fbfb3SApril Chin fcget();
12457c2fbfb3SApril Chin return(1);
12467c2fbfb3SApril Chin }
12477c2fbfb3SApril Chin }
124834f9b3eeSRoland Mainz if(np && (flag&NV_NOADD) && nv_isnull(np))
124934f9b3eeSRoland Mainz {
125034f9b3eeSRoland Mainz if(nv_isattr(np,NV_NOFREE))
125134f9b3eeSRoland Mainz nv_offattr(np,NV_NOFREE);
125234f9b3eeSRoland Mainz else
125334f9b3eeSRoland Mainz np = 0;
125434f9b3eeSRoland Mainz }
1255da2e3ebdSchin ap = np?nv_arrayptr(np):0;
1256da2e3ebdSchin if(type)
1257da2e3ebdSchin {
12587c2fbfb3SApril Chin if(mp->dotdot)
12597c2fbfb3SApril Chin {
12607c2fbfb3SApril Chin if(ap)
12617c2fbfb3SApril Chin {
12627c2fbfb3SApril Chin nv_putsub(np,v,ARRAY_SCAN);
12637c2fbfb3SApril Chin v = stkptr(stkp,mp->dotdot);
12647c2fbfb3SApril Chin dolmax =1;
12657c2fbfb3SApril Chin if(array_assoc(ap))
12667c2fbfb3SApril Chin arrmax = strdup(v);
12677c2fbfb3SApril Chin else if((dolmax = (int)sh_arith(v))<0)
12687c2fbfb3SApril Chin dolmax += array_maxindex(np);
12697c2fbfb3SApril Chin if(type==M_SUBNAME)
12707c2fbfb3SApril Chin bysub = 1;
12717c2fbfb3SApril Chin }
12727c2fbfb3SApril Chin else
12737c2fbfb3SApril Chin {
12747c2fbfb3SApril Chin if((int)sh_arith(v))
12757c2fbfb3SApril Chin np = 0;
12767c2fbfb3SApril Chin }
12777c2fbfb3SApril Chin }
12787c2fbfb3SApril Chin else if(ap && (isastchar(mode)||type==M_TREE) && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE)
1279da2e3ebdSchin nv_putsub(np,NIL(char*),ARRAY_SCAN);
1280da2e3ebdSchin if(!isbracechar(c))
1281da2e3ebdSchin goto nosub;
1282da2e3ebdSchin else
1283da2e3ebdSchin fcseek(-1);
1284da2e3ebdSchin }
1285da2e3ebdSchin else
1286da2e3ebdSchin fcseek(-1);
12877c2fbfb3SApril Chin if(type<=1 && np && nv_isvtree(np) && mp->pattern==1 && !mp->split)
1288da2e3ebdSchin {
12897c2fbfb3SApril Chin int peek=1,cc=fcget();
12907c2fbfb3SApril Chin if(type && cc=='}')
12917c2fbfb3SApril Chin {
12927c2fbfb3SApril Chin cc = fcget();
12937c2fbfb3SApril Chin peek = 2;
12947c2fbfb3SApril Chin }
12957c2fbfb3SApril Chin if(mp->quote && cc=='"')
12967c2fbfb3SApril Chin {
12977c2fbfb3SApril Chin cc = fcget();
12987c2fbfb3SApril Chin peek++;
12997c2fbfb3SApril Chin }
13007c2fbfb3SApril Chin fcseek(-peek);
13017c2fbfb3SApril Chin if(cc==0)
13027c2fbfb3SApril Chin mp->assign = 1;
13037c2fbfb3SApril Chin }
13047c2fbfb3SApril Chin if((type==M_VNAME||type==M_SUBNAME) && mp->shp->argaddr && strcmp(nv_name(np),id))
13057c2fbfb3SApril Chin mp->shp->argaddr = 0;
13067c2fbfb3SApril Chin c = (type>M_BRACE && isastchar(mode));
13077c2fbfb3SApril Chin if(np && (type==M_TREE || !c || !ap))
13087c2fbfb3SApril Chin {
13097c2fbfb3SApril Chin char *savptr;
13107c2fbfb3SApril Chin c = *((unsigned char*)stkptr(stkp,offset-1));
13117c2fbfb3SApril Chin savptr = stkfreeze(stkp,0);
13127c2fbfb3SApril Chin if(type==M_VNAME || (type==M_SUBNAME && ap))
1313da2e3ebdSchin {
1314da2e3ebdSchin type = M_BRACE;
1315da2e3ebdSchin v = nv_name(np);
13167c2fbfb3SApril Chin if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF))
13177c2fbfb3SApril Chin addsub = 1;
1318da2e3ebdSchin }
1319da2e3ebdSchin #ifdef SHOPT_TYPEDEF
1320da2e3ebdSchin else if(type==M_TYPE)
1321da2e3ebdSchin {
1322da2e3ebdSchin Namval_t *nq = nv_type(np);
1323da2e3ebdSchin type = M_BRACE;
1324da2e3ebdSchin if(nq)
13257c2fbfb3SApril Chin nv_typename(nq,mp->shp->strbuf);
1326da2e3ebdSchin else
13277c2fbfb3SApril Chin nv_attribute(np,mp->shp->strbuf,"typeset",1);
13287c2fbfb3SApril Chin v = sfstruse(mp->shp->strbuf);
1329da2e3ebdSchin }
1330da2e3ebdSchin #endif /* SHOPT_TYPEDEF */
1331da2e3ebdSchin #if SHOPT_FILESCAN
13327c2fbfb3SApril Chin else if(mp->shp->cur_line && np==REPLYNOD)
13337c2fbfb3SApril Chin v = mp->shp->cur_line;
1334da2e3ebdSchin #endif /* SHOPT_FILESCAN */
1335da2e3ebdSchin else if(type==M_TREE)
1336da2e3ebdSchin v = nv_getvtree(np,(Namfun_t*)0);
1337da2e3ebdSchin else
1338da2e3ebdSchin {
133934f9b3eeSRoland Mainz if(type && fcpeek(0)=='+')
134034f9b3eeSRoland Mainz {
134134f9b3eeSRoland Mainz if(ap)
134234f9b3eeSRoland Mainz v = nv_arrayisset(np,ap)?(char*)"x":0;
134334f9b3eeSRoland Mainz else
134434f9b3eeSRoland Mainz v = nv_isnull(np)?0:(char*)"x";
134534f9b3eeSRoland Mainz }
134634f9b3eeSRoland Mainz else
1347da2e3ebdSchin v = nv_getval(np);
1348da2e3ebdSchin /* special case --- ignore leading zeros */
13497c2fbfb3SApril Chin if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(c)))
1350da2e3ebdSchin mp->zeros = 1;
1351da2e3ebdSchin }
13527c2fbfb3SApril Chin if(savptr==stakptr(0))
13537c2fbfb3SApril Chin stkseek(stkp,offset);
13547c2fbfb3SApril Chin else
13557c2fbfb3SApril Chin stkset(stkp,savptr,offset);
1356da2e3ebdSchin }
1357da2e3ebdSchin else
13587c2fbfb3SApril Chin {
1359da2e3ebdSchin v = 0;
13607c2fbfb3SApril Chin if(type==M_VNAME)
13617c2fbfb3SApril Chin {
13627c2fbfb3SApril Chin v = id;
13637c2fbfb3SApril Chin type = M_BRACE;
13647c2fbfb3SApril Chin }
13657c2fbfb3SApril Chin else if(type==M_TYPE)
13667c2fbfb3SApril Chin type = M_BRACE;
13677c2fbfb3SApril Chin }
13687c2fbfb3SApril Chin stkseek(stkp,offset);
1369da2e3ebdSchin if(ap)
1370da2e3ebdSchin {
1371da2e3ebdSchin #if SHOPT_OPTIMIZE
13727c2fbfb3SApril Chin if(mp->shp->argaddr)
1373da2e3ebdSchin nv_optimize(np);
1374da2e3ebdSchin #endif
1375da2e3ebdSchin if(isastchar(mode) && array_elem(ap)> !c)
1376da2e3ebdSchin dolg = -1;
1377da2e3ebdSchin else
1378da2e3ebdSchin dolg = 0;
1379da2e3ebdSchin }
1380da2e3ebdSchin break;
1381da2e3ebdSchin case S_EOF:
1382da2e3ebdSchin fcseek(-1);
1383da2e3ebdSchin default:
1384da2e3ebdSchin goto nosub;
1385da2e3ebdSchin }
1386da2e3ebdSchin c = fcget();
1387da2e3ebdSchin if(type>M_TREE)
1388da2e3ebdSchin {
1389da2e3ebdSchin if(c!=RBRACE)
1390da2e3ebdSchin mac_error(np);
1391da2e3ebdSchin if(type==M_NAMESCAN || type==M_NAMECOUNT)
1392da2e3ebdSchin {
139334f9b3eeSRoland Mainz mp->shp->last_root = mp->shp->var_tree;
13947c2fbfb3SApril Chin id = prefix(mp->shp,id);
13957c2fbfb3SApril Chin stkseek(stkp,offset);
1396da2e3ebdSchin if(type==M_NAMECOUNT)
1397da2e3ebdSchin {
1398da2e3ebdSchin c = namecount(mp,id);
1399da2e3ebdSchin v = ltos(c);
1400da2e3ebdSchin }
1401da2e3ebdSchin else
1402da2e3ebdSchin {
1403da2e3ebdSchin dolmax = strlen(id);
1404da2e3ebdSchin dolg = -1;
1405da2e3ebdSchin nextname(mp,id,0);
1406da2e3ebdSchin v = nextname(mp,id,dolmax);
1407da2e3ebdSchin }
1408da2e3ebdSchin }
1409da2e3ebdSchin else if(type==M_SUBNAME)
1410da2e3ebdSchin {
1411da2e3ebdSchin if(dolg<0)
1412da2e3ebdSchin {
1413da2e3ebdSchin v = nv_getsub(np);
1414da2e3ebdSchin bysub=1;
1415da2e3ebdSchin }
1416da2e3ebdSchin else if(v)
1417da2e3ebdSchin {
1418da2e3ebdSchin if(!ap || isastchar(mode))
1419da2e3ebdSchin v = "0";
1420da2e3ebdSchin else
1421da2e3ebdSchin v = nv_getsub(np);
1422da2e3ebdSchin }
1423da2e3ebdSchin }
1424da2e3ebdSchin else
1425da2e3ebdSchin {
1426da2e3ebdSchin if(!isastchar(mode))
1427da2e3ebdSchin c = charlen(v,vsize);
1428da2e3ebdSchin else if(dolg>0)
1429da2e3ebdSchin {
1430da2e3ebdSchin #if SHOPT_FILESCAN
14317c2fbfb3SApril Chin if(mp->shp->cur_line)
1432da2e3ebdSchin {
1433da2e3ebdSchin getdolarg(&sh,MAX_ARGN,(int*)0);
14347c2fbfb3SApril Chin c = mp->shp->offsets[0];
1435da2e3ebdSchin }
1436da2e3ebdSchin else
1437da2e3ebdSchin #endif /* SHOPT_FILESCAN */
14387c2fbfb3SApril Chin c = mp->shp->st.dolc;
1439da2e3ebdSchin }
1440da2e3ebdSchin else if(dolg<0)
1441da2e3ebdSchin c = array_elem(ap);
1442da2e3ebdSchin else
1443da2e3ebdSchin c = (v!=0);
1444da2e3ebdSchin dolg = dolmax = 0;
1445da2e3ebdSchin v = ltos(c);
1446da2e3ebdSchin }
1447da2e3ebdSchin c = RBRACE;
1448da2e3ebdSchin }
1449da2e3ebdSchin nulflg = 0;
1450da2e3ebdSchin if(type && c==':')
1451da2e3ebdSchin {
1452da2e3ebdSchin c = fcget();
1453da2e3ebdSchin if(sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':')
1454da2e3ebdSchin nulflg=1;
1455da2e3ebdSchin else if(c!='%' && c!='#')
1456da2e3ebdSchin {
1457da2e3ebdSchin fcseek(-1);
1458da2e3ebdSchin c = ':';
1459da2e3ebdSchin }
1460da2e3ebdSchin }
1461da2e3ebdSchin if(type)
1462da2e3ebdSchin {
1463da2e3ebdSchin if(!isbracechar(c))
1464da2e3ebdSchin {
1465da2e3ebdSchin if(!nulflg)
1466da2e3ebdSchin mac_error(np);
1467da2e3ebdSchin fcseek(-1);
1468da2e3ebdSchin c = ':';
1469da2e3ebdSchin }
1470da2e3ebdSchin if(c!=RBRACE)
1471da2e3ebdSchin {
1472da2e3ebdSchin int newops = (c=='#' || c == '%' || c=='/');
14737c2fbfb3SApril Chin offset = stktell(stkp);
1474da2e3ebdSchin if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%')))
1475da2e3ebdSchin {
1476da2e3ebdSchin int newquote = mp->quote;
1477da2e3ebdSchin int split = mp->split;
1478da2e3ebdSchin int quoted = mp->quoted;
1479da2e3ebdSchin int arith = mp->arith;
1480da2e3ebdSchin int zeros = mp->zeros;
148134f9b3eeSRoland Mainz int assign = mp->assign;
1482da2e3ebdSchin if(newops)
1483da2e3ebdSchin {
1484da2e3ebdSchin type = fcget();
1485da2e3ebdSchin if(type=='%' || type=='#')
1486da2e3ebdSchin {
1487da2e3ebdSchin int d = fcget();
1488da2e3ebdSchin fcseek(-1);
1489da2e3ebdSchin if(d=='(')
1490da2e3ebdSchin type = 0;
1491da2e3ebdSchin }
1492da2e3ebdSchin fcseek(-1);
1493da2e3ebdSchin mp->pattern = 1+(c=='/');
1494da2e3ebdSchin mp->split = 0;
1495da2e3ebdSchin mp->quoted = 0;
149634f9b3eeSRoland Mainz mp->assign &= ~1;
1497da2e3ebdSchin mp->arith = mp->zeros = 0;
1498da2e3ebdSchin newquote = 0;
1499da2e3ebdSchin }
1500da2e3ebdSchin else if(c=='?' || c=='=')
1501da2e3ebdSchin mp->split = mp->pattern = 0;
1502da2e3ebdSchin copyto(mp,RBRACE,newquote);
1503da2e3ebdSchin if(!oldpat)
1504da2e3ebdSchin mp->patfound = 0;
1505da2e3ebdSchin mp->pattern = oldpat;
1506da2e3ebdSchin mp->split = split;
1507da2e3ebdSchin mp->quoted = quoted;
1508da2e3ebdSchin mp->arith = arith;
1509da2e3ebdSchin mp->zeros = zeros;
151034f9b3eeSRoland Mainz mp->assign = assign;
1511da2e3ebdSchin /* add null byte */
15127c2fbfb3SApril Chin sfputc(stkp,0);
15137c2fbfb3SApril Chin stkseek(stkp,stktell(stkp)-1);
1514da2e3ebdSchin }
1515da2e3ebdSchin else
1516da2e3ebdSchin {
15177c2fbfb3SApril Chin sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED);
15187c2fbfb3SApril Chin stkseek(stkp,offset);
1519da2e3ebdSchin }
15207c2fbfb3SApril Chin argp=stkptr(stkp,offset);
1521da2e3ebdSchin }
1522da2e3ebdSchin }
1523da2e3ebdSchin else
1524da2e3ebdSchin {
1525da2e3ebdSchin fcseek(-1);
1526da2e3ebdSchin c=0;
1527da2e3ebdSchin }
1528da2e3ebdSchin if(c==':') /* ${name:expr1[:expr2]} */
1529da2e3ebdSchin {
1530da2e3ebdSchin char *ptr;
1531da2e3ebdSchin type = (int)sh_strnum(argp,&ptr,1);
1532da2e3ebdSchin if(isastchar(mode))
1533da2e3ebdSchin {
1534da2e3ebdSchin if(id==idbuff) /* ${@} or ${*} */
1535da2e3ebdSchin {
1536da2e3ebdSchin if(type<0 && (type+= dolmax)<0)
1537da2e3ebdSchin type = 0;
1538da2e3ebdSchin if(type==0)
15397c2fbfb3SApril Chin v = special(mp->shp,dolg=0);
1540da2e3ebdSchin #if SHOPT_FILESCAN
15417c2fbfb3SApril Chin else if(mp->shp->cur_line)
1542da2e3ebdSchin {
1543da2e3ebdSchin v = getdolarg(&sh,dolg=type,&vsize);
1544da2e3ebdSchin if(!v)
1545da2e3ebdSchin dolmax = type;
1546da2e3ebdSchin }
1547da2e3ebdSchin #endif /* SHOPT_FILESCAN */
1548da2e3ebdSchin else if(type < dolmax)
15497c2fbfb3SApril Chin v = mp->shp->st.dolv[dolg=type];
1550da2e3ebdSchin else
1551da2e3ebdSchin v = 0;
1552da2e3ebdSchin }
1553da2e3ebdSchin else if(ap)
1554da2e3ebdSchin {
1555da2e3ebdSchin if(type<0)
1556da2e3ebdSchin {
1557da2e3ebdSchin if(array_assoc(ap))
1558da2e3ebdSchin type = -type;
1559da2e3ebdSchin else
1560da2e3ebdSchin type += array_maxindex(np);
1561da2e3ebdSchin }
1562da2e3ebdSchin if(array_assoc(ap))
1563da2e3ebdSchin {
1564da2e3ebdSchin while(type-- >0 && (v=0,nv_nextsub(np)))
1565da2e3ebdSchin v = nv_getval(np);
1566da2e3ebdSchin }
1567da2e3ebdSchin else if(type > 0)
1568da2e3ebdSchin {
1569da2e3ebdSchin if(nv_putsub(np,NIL(char*),type|ARRAY_SCAN))
1570da2e3ebdSchin v = nv_getval(np);
1571da2e3ebdSchin else
1572da2e3ebdSchin v = 0;
1573da2e3ebdSchin }
1574da2e3ebdSchin }
1575da2e3ebdSchin else if(type>0)
1576da2e3ebdSchin v = 0;
1577da2e3ebdSchin }
1578da2e3ebdSchin else if(v)
1579da2e3ebdSchin {
1580da2e3ebdSchin vsize = charlen(v,vsize);
1581da2e3ebdSchin if(type<0 && (type += vsize)<0)
1582da2e3ebdSchin type = 0;
1583da2e3ebdSchin if(vsize < type)
1584da2e3ebdSchin v = 0;
1585da2e3ebdSchin #if SHOPT_MULTIBYTE
1586da2e3ebdSchin else if(mbwide())
1587da2e3ebdSchin {
1588da2e3ebdSchin mbinit();
1589da2e3ebdSchin while(type-->0)
1590da2e3ebdSchin {
1591da2e3ebdSchin if((c=mbsize(v))<1)
1592da2e3ebdSchin c = 1;
1593da2e3ebdSchin v += c;
1594da2e3ebdSchin }
1595da2e3ebdSchin c = ':';
1596da2e3ebdSchin }
1597da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1598da2e3ebdSchin else
1599da2e3ebdSchin v += type;
1600da2e3ebdSchin vsize -= type;
1601da2e3ebdSchin }
1602da2e3ebdSchin if(*ptr==':')
1603da2e3ebdSchin {
1604da2e3ebdSchin if((type = (int)sh_strnum(ptr+1,&ptr,1)) <=0)
1605da2e3ebdSchin v = 0;
1606da2e3ebdSchin else if(isastchar(mode))
1607da2e3ebdSchin {
1608da2e3ebdSchin if(dolg>=0)
1609da2e3ebdSchin {
1610da2e3ebdSchin if(dolg+type < dolmax)
1611da2e3ebdSchin dolmax = dolg+type;
1612da2e3ebdSchin }
1613da2e3ebdSchin else
1614da2e3ebdSchin dolmax = type;
1615da2e3ebdSchin }
1616da2e3ebdSchin else if(type < vsize)
1617da2e3ebdSchin {
1618da2e3ebdSchin #if SHOPT_MULTIBYTE
1619da2e3ebdSchin if(mbwide())
1620da2e3ebdSchin {
1621da2e3ebdSchin char *vp = v;
1622da2e3ebdSchin mbinit();
1623da2e3ebdSchin while(type-->0)
1624da2e3ebdSchin {
1625da2e3ebdSchin if((c=mbsize(vp))<1)
1626da2e3ebdSchin c = 1;
1627da2e3ebdSchin vp += c;
1628da2e3ebdSchin }
1629da2e3ebdSchin type = vp-v;
1630da2e3ebdSchin c = ':';
1631da2e3ebdSchin }
1632da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
1633da2e3ebdSchin vsize = type;
1634da2e3ebdSchin }
1635da2e3ebdSchin }
1636da2e3ebdSchin if(*ptr)
1637da2e3ebdSchin mac_error(np);
16387c2fbfb3SApril Chin stkseek(stkp,offset);
1639da2e3ebdSchin argp = 0;
1640da2e3ebdSchin }
1641da2e3ebdSchin /* check for substring operations */
1642da2e3ebdSchin else if(c == '#' || c == '%' || c=='/')
1643da2e3ebdSchin {
1644da2e3ebdSchin if(c=='/')
1645da2e3ebdSchin {
1646da2e3ebdSchin if(type=='/' || type=='#' || type=='%')
1647da2e3ebdSchin {
1648da2e3ebdSchin c = type;
1649da2e3ebdSchin type = '/';
1650da2e3ebdSchin argp++;
1651da2e3ebdSchin }
1652da2e3ebdSchin else
1653da2e3ebdSchin type = 0;
1654da2e3ebdSchin }
1655da2e3ebdSchin else
1656da2e3ebdSchin {
1657da2e3ebdSchin if(type==c) /* ## or %% */
1658da2e3ebdSchin argp++;
1659da2e3ebdSchin else
1660da2e3ebdSchin type = 0;
1661da2e3ebdSchin }
1662da2e3ebdSchin pattern = strdup(argp);
1663da2e3ebdSchin if((type=='/' || c=='/') && (repstr = mac_getstring(pattern)))
1664da2e3ebdSchin replen = strlen(repstr);
1665da2e3ebdSchin if(v || c=='/' && offset>=0)
16667c2fbfb3SApril Chin stkseek(stkp,offset);
1667da2e3ebdSchin }
1668da2e3ebdSchin /* check for quoted @ */
1669da2e3ebdSchin if(mode=='@' && mp->quote && !v && c!='-')
1670da2e3ebdSchin mp->quoted-=2;
1671da2e3ebdSchin retry2:
1672da2e3ebdSchin if(v && (!nulflg || *v ) && c!='+')
1673da2e3ebdSchin {
1674da2e3ebdSchin register int d = (mode=='@'?' ':mp->ifs);
16757c2fbfb3SApril Chin int match[2*(MATCH_MAX+1)], nmatch, nmatch_prev, vsize_last;
1676da2e3ebdSchin char *vlast;
1677da2e3ebdSchin while(1)
1678da2e3ebdSchin {
1679da2e3ebdSchin if(!v)
1680da2e3ebdSchin v= "";
1681da2e3ebdSchin if(c=='/' || c=='#' || c== '%')
1682da2e3ebdSchin {
16837c2fbfb3SApril Chin flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP;
1684da2e3ebdSchin if(c!='/')
1685da2e3ebdSchin flag |= STR_LEFT;
16867c2fbfb3SApril Chin nmatch = 0;
1687da2e3ebdSchin while(1)
1688da2e3ebdSchin {
1689da2e3ebdSchin vsize = strlen(v);
16907c2fbfb3SApril Chin nmatch_prev = nmatch;
1691da2e3ebdSchin if(c=='%')
1692da2e3ebdSchin nmatch=substring(v,pattern,match,flag&STR_MAXIMAL);
1693da2e3ebdSchin else
1694da2e3ebdSchin nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag);
1695da2e3ebdSchin if(replen>0)
1696da2e3ebdSchin sh_setmatch(v,vsize,nmatch,match);
1697da2e3ebdSchin if(nmatch)
1698da2e3ebdSchin {
1699da2e3ebdSchin vlast = v;
1700da2e3ebdSchin vsize_last = vsize;
1701da2e3ebdSchin vsize = match[0];
1702da2e3ebdSchin }
1703da2e3ebdSchin else if(c=='#')
1704da2e3ebdSchin vsize = 0;
1705da2e3ebdSchin if(vsize)
1706da2e3ebdSchin mac_copy(mp,v,vsize);
17077c2fbfb3SApril Chin if(nmatch && replen>0 && (match[1] || !nmatch_prev))
1708da2e3ebdSchin mac_substitute(mp,repstr,v,match,nmatch);
1709da2e3ebdSchin if(nmatch==0)
1710da2e3ebdSchin v += vsize;
1711da2e3ebdSchin else
1712da2e3ebdSchin v += match[1];
1713da2e3ebdSchin if(*v && c=='/' && type)
1714da2e3ebdSchin {
1715da2e3ebdSchin /* avoid infinite loop */
1716da2e3ebdSchin if(nmatch && match[1]==0)
17177c2fbfb3SApril Chin {
17187c2fbfb3SApril Chin nmatch = 0;
17197c2fbfb3SApril Chin mac_copy(mp,v,1);
1720da2e3ebdSchin v++;
17217c2fbfb3SApril Chin }
1722da2e3ebdSchin continue;
1723da2e3ebdSchin }
1724da2e3ebdSchin vsize = -1;
1725da2e3ebdSchin break;
1726da2e3ebdSchin }
1727da2e3ebdSchin if(replen==0)
1728da2e3ebdSchin sh_setmatch(vlast,vsize_last,nmatch,match);
1729da2e3ebdSchin }
1730da2e3ebdSchin if(vsize)
1731da2e3ebdSchin mac_copy(mp,v,vsize>0?vsize:strlen(v));
17327c2fbfb3SApril Chin if(addsub)
17337c2fbfb3SApril Chin {
17347c2fbfb3SApril Chin sfprintf(mp->shp->strbuf,"[%s]",nv_getsub(np));
17357c2fbfb3SApril Chin v = sfstruse(mp->shp->strbuf);
17367c2fbfb3SApril Chin mac_copy(mp, v, strlen(v));
17377c2fbfb3SApril Chin }
1738da2e3ebdSchin if(dolg==0 && dolmax==0)
1739da2e3ebdSchin break;
17407c2fbfb3SApril Chin if(mp->dotdot)
17417c2fbfb3SApril Chin {
17427c2fbfb3SApril Chin if(nv_nextsub(np) == 0)
17437c2fbfb3SApril Chin break;
17447c2fbfb3SApril Chin if(bysub)
17457c2fbfb3SApril Chin v = nv_getsub(np);
17467c2fbfb3SApril Chin else
17477c2fbfb3SApril Chin v = nv_getval(np);
17487c2fbfb3SApril Chin if(array_assoc(ap))
17497c2fbfb3SApril Chin {
17507c2fbfb3SApril Chin if(strcmp(bysub?v:nv_getsub(np),arrmax)>0)
17517c2fbfb3SApril Chin break;
17527c2fbfb3SApril Chin }
17537c2fbfb3SApril Chin else
17547c2fbfb3SApril Chin {
17557c2fbfb3SApril Chin if(nv_aindex(np) > dolmax)
17567c2fbfb3SApril Chin break;
17577c2fbfb3SApril Chin }
17587c2fbfb3SApril Chin }
17597c2fbfb3SApril Chin else if(dolg>=0)
1760da2e3ebdSchin {
1761da2e3ebdSchin if(++dolg >= dolmax)
1762da2e3ebdSchin break;
1763da2e3ebdSchin #if SHOPT_FILESCAN
17647c2fbfb3SApril Chin if(mp->shp->cur_line)
1765da2e3ebdSchin {
1766da2e3ebdSchin if(dolmax==MAX_ARGN && isastchar(mode))
1767da2e3ebdSchin break;
1768da2e3ebdSchin if(!(v=getdolarg(&sh,dolg,&vsize)))
1769da2e3ebdSchin {
1770da2e3ebdSchin dolmax = dolg;
1771da2e3ebdSchin break;
1772da2e3ebdSchin }
1773da2e3ebdSchin }
1774da2e3ebdSchin else
1775da2e3ebdSchin #endif /* SHOPT_FILESCAN */
17767c2fbfb3SApril Chin v = mp->shp->st.dolv[dolg];
1777da2e3ebdSchin }
1778da2e3ebdSchin else if(!np)
1779da2e3ebdSchin {
1780da2e3ebdSchin if(!(v = nextname(mp,id,dolmax)))
1781da2e3ebdSchin break;
1782da2e3ebdSchin }
1783da2e3ebdSchin else
1784da2e3ebdSchin {
1785da2e3ebdSchin if(dolmax && --dolmax <=0)
1786da2e3ebdSchin {
1787da2e3ebdSchin nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1788da2e3ebdSchin break;
1789da2e3ebdSchin }
17907c2fbfb3SApril Chin if(ap)
17917c2fbfb3SApril Chin ap->nelem |= ARRAY_SCAN;
1792da2e3ebdSchin if(nv_nextsub(np) == 0)
1793da2e3ebdSchin break;
1794da2e3ebdSchin if(bysub)
1795da2e3ebdSchin v = nv_getsub(np);
1796da2e3ebdSchin else
1797da2e3ebdSchin v = nv_getval(np);
1798da2e3ebdSchin }
1799da2e3ebdSchin if(mp->split && (!mp->quote || mode=='@'))
1800da2e3ebdSchin {
1801da2e3ebdSchin if(!np)
1802da2e3ebdSchin mp->pattern = 0;
1803da2e3ebdSchin endfield(mp,mp->quoted);
1804da2e3ebdSchin mp->pattern = oldpat;
1805da2e3ebdSchin }
1806da2e3ebdSchin else if(d)
1807da2e3ebdSchin {
1808da2e3ebdSchin if(mp->sp)
1809da2e3ebdSchin sfputc(mp->sp,d);
1810da2e3ebdSchin else
18117c2fbfb3SApril Chin sfputc(stkp,d);
1812da2e3ebdSchin }
1813da2e3ebdSchin }
18147c2fbfb3SApril Chin if(arrmax)
18157c2fbfb3SApril Chin free((void*)arrmax);
1816da2e3ebdSchin if(pattern)
1817da2e3ebdSchin free((void*)pattern);
1818da2e3ebdSchin }
1819da2e3ebdSchin else if(argp)
1820da2e3ebdSchin {
1821da2e3ebdSchin if(c=='/' && replen>0 && pattern && strmatch("",pattern))
1822da2e3ebdSchin mac_substitute(mp,repstr,v,0,0);
1823da2e3ebdSchin if(c=='?')
1824da2e3ebdSchin {
1825da2e3ebdSchin if(np)
1826da2e3ebdSchin id = nv_name(np);
1827da2e3ebdSchin else if(idnum)
1828da2e3ebdSchin id = ltos(idnum);
1829da2e3ebdSchin if(*argp)
1830da2e3ebdSchin {
18317c2fbfb3SApril Chin sfputc(stkp,0);
1832da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp);
1833da2e3ebdSchin }
1834da2e3ebdSchin else if(v)
1835da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_nullset,id);
1836da2e3ebdSchin else
1837da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1838da2e3ebdSchin }
1839da2e3ebdSchin else if(c=='=')
1840da2e3ebdSchin {
1841da2e3ebdSchin if(np)
1842da2e3ebdSchin {
18437c2fbfb3SApril Chin if(mp->shp->subshell)
1844da2e3ebdSchin np = sh_assignok(np,1);
1845da2e3ebdSchin nv_putval(np,argp,0);
1846da2e3ebdSchin v = nv_getval(np);
1847da2e3ebdSchin nulflg = 0;
18487c2fbfb3SApril Chin stkseek(stkp,offset);
1849da2e3ebdSchin goto retry2;
1850da2e3ebdSchin }
1851da2e3ebdSchin else
1852da2e3ebdSchin mac_error(np);
1853da2e3ebdSchin }
1854da2e3ebdSchin }
1855*3e14f97fSRoger A. Faulkner else if(var && sh_isoption(SH_NOUNSET) && type<=M_TREE && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp)))
1856da2e3ebdSchin {
1857da2e3ebdSchin if(np)
1858da2e3ebdSchin {
1859da2e3ebdSchin if(nv_isarray(np))
1860da2e3ebdSchin {
18617c2fbfb3SApril Chin sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np));
18627c2fbfb3SApril Chin id = sfstruse(mp->shp->strbuf);
1863da2e3ebdSchin }
1864da2e3ebdSchin else
1865da2e3ebdSchin id = nv_name(np);
1866da2e3ebdSchin nv_close(np);
1867da2e3ebdSchin }
1868da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1869da2e3ebdSchin }
1870da2e3ebdSchin if(np)
1871da2e3ebdSchin nv_close(np);
1872da2e3ebdSchin return(1);
1873da2e3ebdSchin nosub:
18747c2fbfb3SApril Chin if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK)
18757c2fbfb3SApril Chin {
18767c2fbfb3SApril Chin fcseek(-1);
18777c2fbfb3SApril Chin comsubst(mp,(Shnode_t*)0,2);
18787c2fbfb3SApril Chin return(1);
18797c2fbfb3SApril Chin }
1880da2e3ebdSchin if(type)
1881da2e3ebdSchin mac_error(np);
1882da2e3ebdSchin fcseek(-1);
1883da2e3ebdSchin nv_close(np);
1884da2e3ebdSchin return(0);
1885da2e3ebdSchin }
1886da2e3ebdSchin
1887da2e3ebdSchin /*
1888da2e3ebdSchin * This routine handles command substitution
1889da2e3ebdSchin * <type> is 0 for older `...` version
1890da2e3ebdSchin */
comsubst(Mac_t * mp,register Shnode_t * t,int type)18917c2fbfb3SApril Chin static void comsubst(Mac_t *mp,register Shnode_t* t, int type)
1892da2e3ebdSchin {
1893da2e3ebdSchin Sfdouble_t num;
1894da2e3ebdSchin register int c;
1895da2e3ebdSchin register char *str;
1896da2e3ebdSchin Sfio_t *sp;
18977c2fbfb3SApril Chin Stk_t *stkp = mp->shp->stk;
1898da2e3ebdSchin Fcin_t save;
18997c2fbfb3SApril Chin struct slnod *saveslp = mp->shp->st.staklist;
1900da2e3ebdSchin struct _mac_ savemac;
19017c2fbfb3SApril Chin int savtop = stktell(stkp);
19027c2fbfb3SApril Chin char lastc, *savptr = stkfreeze(stkp,0);
1903da2e3ebdSchin int was_history = sh_isstate(SH_HISTORY);
1904da2e3ebdSchin int was_verbose = sh_isstate(SH_VERBOSE);
19057c2fbfb3SApril Chin int was_interactive = sh_isstate(SH_INTERACTIVE);
19067c2fbfb3SApril Chin int newlines,bufsize,nextnewlines;
1907da2e3ebdSchin Namval_t *np;
19087c2fbfb3SApril Chin mp->shp->argaddr = 0;
1909da2e3ebdSchin savemac = *mp;
19107c2fbfb3SApril Chin mp->shp->st.staklist=0;
1911da2e3ebdSchin if(type)
1912da2e3ebdSchin {
1913da2e3ebdSchin sp = 0;
1914da2e3ebdSchin fcseek(-1);
19157c2fbfb3SApril Chin if(!t)
19167c2fbfb3SApril Chin t = sh_dolparen((Lex_t*)mp->shp->lex_context);
1917da2e3ebdSchin if(t && t->tre.tretyp==TARITH)
1918da2e3ebdSchin {
1919da2e3ebdSchin fcsave(&save);
19207c2fbfb3SApril Chin if((t->ar.arexpr->argflag&ARG_RAW))
19217c2fbfb3SApril Chin num = arith_exec(t->ar.arcomp);
1922da2e3ebdSchin else
19237c2fbfb3SApril Chin num = sh_arith(sh_mactrim(mp->shp,t->ar.arexpr->argval,3));
19247c2fbfb3SApril Chin out_offset:
19257c2fbfb3SApril Chin stkset(stkp,savptr,savtop);
19267c2fbfb3SApril Chin *mp = savemac;
19277c2fbfb3SApril Chin if((Sflong_t)num!=num)
19287c2fbfb3SApril Chin sfprintf(mp->shp->strbuf,"%.*Lg",LDBL_DIG,num);
19297c2fbfb3SApril Chin else if(num)
19307c2fbfb3SApril Chin sfprintf(mp->shp->strbuf,"%lld",(Sflong_t)num);
19317c2fbfb3SApril Chin else
19327c2fbfb3SApril Chin sfprintf(mp->shp->strbuf,"%Lg",num);
19337c2fbfb3SApril Chin str = sfstruse(mp->shp->strbuf);
1934da2e3ebdSchin mac_copy(mp,str,strlen(str));
19357c2fbfb3SApril Chin mp->shp->st.staklist = saveslp;
1936da2e3ebdSchin fcrestore(&save);
1937da2e3ebdSchin return;
1938da2e3ebdSchin }
1939da2e3ebdSchin }
1940da2e3ebdSchin else
1941da2e3ebdSchin {
1942da2e3ebdSchin while(fcgetc(c)!='`' && c)
1943da2e3ebdSchin {
1944da2e3ebdSchin if(c==ESCAPE)
1945da2e3ebdSchin {
1946da2e3ebdSchin fcgetc(c);
1947da2e3ebdSchin if(!(isescchar(sh_lexstates[ST_QUOTE][c]) ||
19487c2fbfb3SApril Chin (c=='"' && mp->quote)))
19497c2fbfb3SApril Chin sfputc(stkp,ESCAPE);
1950da2e3ebdSchin }
19517c2fbfb3SApril Chin sfputc(stkp,c);
1952da2e3ebdSchin }
19537c2fbfb3SApril Chin c = stktell(stkp);
19547c2fbfb3SApril Chin str=stkfreeze(stkp,1);
1955da2e3ebdSchin /* disable verbose and don't save in history file */
1956da2e3ebdSchin sh_offstate(SH_HISTORY);
1957da2e3ebdSchin sh_offstate(SH_VERBOSE);
1958da2e3ebdSchin if(mp->sp)
1959da2e3ebdSchin sfsync(mp->sp); /* flush before executing command */
1960da2e3ebdSchin sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ);
19617c2fbfb3SApril Chin c = mp->shp->inlineno;
19627c2fbfb3SApril Chin mp->shp->inlineno = error_info.line+mp->shp->st.firstline;
1963da2e3ebdSchin t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL);
19647c2fbfb3SApril Chin mp->shp->inlineno = c;
19657c2fbfb3SApril Chin type = 1;
1966da2e3ebdSchin }
1967da2e3ebdSchin #if KSHELL
1968da2e3ebdSchin if(t)
1969da2e3ebdSchin {
1970da2e3ebdSchin fcsave(&save);
1971da2e3ebdSchin sfclose(sp);
19727c2fbfb3SApril Chin if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset)
1973da2e3ebdSchin {
1974da2e3ebdSchin /* special case $(<file) and $(<#file) */
1975da2e3ebdSchin register int fd;
1976da2e3ebdSchin int r;
1977da2e3ebdSchin struct checkpt buff;
1978da2e3ebdSchin struct ionod *ip=0;
1979da2e3ebdSchin sh_pushcontext(&buff,SH_JMPIO);
1980da2e3ebdSchin if((ip=t->tre.treio) &&
1981da2e3ebdSchin ((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) &&
1982da2e3ebdSchin (r=sigsetjmp(buff.buff,0))==0)
19837c2fbfb3SApril Chin fd = sh_redirect(mp->shp,ip,3);
1984da2e3ebdSchin else
1985da2e3ebdSchin fd = sh_chkopen(e_devnull);
1986da2e3ebdSchin sh_popcontext(&buff);
1987da2e3ebdSchin if(r==0 && ip && (ip->iofile&IOLSEEK))
1988da2e3ebdSchin {
19897c2fbfb3SApril Chin if(sp=mp->shp->sftable[fd])
1990da2e3ebdSchin num = sftell(sp);
1991da2e3ebdSchin else
1992da2e3ebdSchin num = lseek(fd, (off_t)0, SEEK_CUR);
1993da2e3ebdSchin goto out_offset;
1994da2e3ebdSchin }
1995da2e3ebdSchin sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC);
19967c2fbfb3SApril Chin type = 3;
1997da2e3ebdSchin }
1998da2e3ebdSchin else
19997c2fbfb3SApril Chin sp = sh_subshell(t,sh_isstate(SH_ERREXIT),type);
2000da2e3ebdSchin fcrestore(&save);
2001da2e3ebdSchin }
2002da2e3ebdSchin else
2003da2e3ebdSchin sp = sfopen(NIL(Sfio_t*),"","sr");
20047c2fbfb3SApril Chin sh_freeup(mp->shp);
20057c2fbfb3SApril Chin mp->shp->st.staklist = saveslp;
2006da2e3ebdSchin if(was_history)
2007da2e3ebdSchin sh_onstate(SH_HISTORY);
2008da2e3ebdSchin if(was_verbose)
2009da2e3ebdSchin sh_onstate(SH_VERBOSE);
2010da2e3ebdSchin #else
2011da2e3ebdSchin sp = sfpopen(NIL(Sfio_t*),str,"r");
2012da2e3ebdSchin #endif
2013da2e3ebdSchin *mp = savemac;
20147c2fbfb3SApril Chin np = sh_scoped(mp->shp,IFSNOD);
20157c2fbfb3SApril Chin nv_putval(np,mp->ifsp,NV_RDONLY);
2016da2e3ebdSchin mp->ifsp = nv_getval(np);
20177c2fbfb3SApril Chin stkset(stkp,savptr,savtop);
2018da2e3ebdSchin newlines = 0;
2019da2e3ebdSchin lastc = 0;
2020da2e3ebdSchin sfsetbuf(sp,(void*)sp,0);
2021da2e3ebdSchin bufsize = sfvalue(sp);
2022da2e3ebdSchin /* read command substitution output and put on stack or here-doc */
2023da2e3ebdSchin sfpool(sp, NIL(Sfio_t*), SF_WRITE);
20247c2fbfb3SApril Chin sh_offstate(SH_INTERACTIVE);
2025da2e3ebdSchin while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c = sfvalue(sp))>0)
2026da2e3ebdSchin {
2027da2e3ebdSchin #if SHOPT_CRNL
2028da2e3ebdSchin /* eliminate <cr> */
2029da2e3ebdSchin register char *dp;
2030da2e3ebdSchin char *buff = str;
2031da2e3ebdSchin while(c>1 && (*str !='\r'|| str[1]!='\n'))
2032da2e3ebdSchin {
2033da2e3ebdSchin c--;
2034da2e3ebdSchin str++;
2035da2e3ebdSchin }
2036da2e3ebdSchin dp = str;
2037da2e3ebdSchin while(c>1)
2038da2e3ebdSchin {
2039da2e3ebdSchin str++;
2040da2e3ebdSchin c--;
2041da2e3ebdSchin while(c>1 && (*str!='\r' || str[1]!='\n'))
2042da2e3ebdSchin {
2043da2e3ebdSchin c--;
2044da2e3ebdSchin *dp++ = *str++;
2045da2e3ebdSchin }
2046da2e3ebdSchin }
2047da2e3ebdSchin if(c)
2048da2e3ebdSchin *dp++ = *str++;
2049da2e3ebdSchin str = buff;
2050da2e3ebdSchin c = dp-str;
2051da2e3ebdSchin #endif /* SHOPT_CRNL */
20527c2fbfb3SApril Chin /* delay appending trailing new-lines */
20537c2fbfb3SApril Chin for(nextnewlines=0; c-->0 && str[c]=='\n'; nextnewlines++);
20547c2fbfb3SApril Chin if(c < 0)
20557c2fbfb3SApril Chin {
20567c2fbfb3SApril Chin newlines += nextnewlines;
20577c2fbfb3SApril Chin continue;
20587c2fbfb3SApril Chin }
2059da2e3ebdSchin if(newlines >0)
2060da2e3ebdSchin {
2061da2e3ebdSchin if(mp->sp)
2062da2e3ebdSchin sfnputc(mp->sp,'\n',newlines);
20637c2fbfb3SApril Chin else if(!mp->quote && mp->split && mp->shp->ifstable['\n'])
2064da2e3ebdSchin endfield(mp,0);
20657c2fbfb3SApril Chin else
20667c2fbfb3SApril Chin sfnputc(stkp,'\n',newlines);
2067da2e3ebdSchin }
2068da2e3ebdSchin else if(lastc)
2069da2e3ebdSchin {
2070da2e3ebdSchin mac_copy(mp,&lastc,1);
2071da2e3ebdSchin lastc = 0;
2072da2e3ebdSchin }
20737c2fbfb3SApril Chin newlines = nextnewlines;
2074da2e3ebdSchin if(++c < bufsize)
2075da2e3ebdSchin str[c] = 0;
2076da2e3ebdSchin else
2077da2e3ebdSchin {
2078da2e3ebdSchin /* can't write past buffer so save last character */
2079da2e3ebdSchin lastc = str[--c];
2080da2e3ebdSchin str[c] = 0;
2081da2e3ebdSchin }
2082da2e3ebdSchin mac_copy(mp,str,c);
2083da2e3ebdSchin }
20847c2fbfb3SApril Chin if(was_interactive)
20857c2fbfb3SApril Chin sh_onstate(SH_INTERACTIVE);
20867c2fbfb3SApril Chin if(mp->shp->spid)
20877c2fbfb3SApril Chin job_wait(mp->shp->spid);
20887c2fbfb3SApril Chin if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM)
2089da2e3ebdSchin {
2090da2e3ebdSchin if(mp->sp)
2091da2e3ebdSchin sfnputc(mp->sp,'\n',newlines);
20927c2fbfb3SApril Chin else if(!mp->quote && mp->split)
20937c2fbfb3SApril Chin while(newlines--)
20947c2fbfb3SApril Chin endfield(mp,1);
20957c2fbfb3SApril Chin else
20967c2fbfb3SApril Chin sfnputc(stkp,'\n',newlines);
2097da2e3ebdSchin }
2098da2e3ebdSchin if(lastc)
2099da2e3ebdSchin mac_copy(mp,&lastc,1);
2100da2e3ebdSchin sfclose(sp);
2101da2e3ebdSchin return;
2102da2e3ebdSchin }
2103da2e3ebdSchin
2104da2e3ebdSchin /*
2105da2e3ebdSchin * copy <str> onto the stack
2106da2e3ebdSchin */
mac_copy(register Mac_t * mp,register const char * str,register int size)2107da2e3ebdSchin static void mac_copy(register Mac_t *mp,register const char *str, register int size)
2108da2e3ebdSchin {
2109da2e3ebdSchin register char *state;
2110da2e3ebdSchin register const char *cp=str;
21117c2fbfb3SApril Chin register int c,n,nopat,len;
21127c2fbfb3SApril Chin Stk_t *stkp=mp->shp->stk;
2113da2e3ebdSchin nopat = (mp->quote||mp->assign==1||mp->arith);
2114da2e3ebdSchin if(mp->zeros)
2115da2e3ebdSchin {
2116da2e3ebdSchin /* prevent leading 0's from becomming octal constants */
2117da2e3ebdSchin while(size>1 && *str=='0')
2118da2e3ebdSchin str++,size--;
2119da2e3ebdSchin mp->zeros = 0;
2120da2e3ebdSchin cp = str;
2121da2e3ebdSchin }
2122da2e3ebdSchin if(mp->sp)
2123da2e3ebdSchin sfwrite(mp->sp,str,size);
2124da2e3ebdSchin else if(mp->pattern>=2 || (mp->pattern && nopat))
2125da2e3ebdSchin {
2126da2e3ebdSchin state = sh_lexstates[ST_MACRO];
2127da2e3ebdSchin /* insert \ before file expansion characters */
2128da2e3ebdSchin while(size-->0)
2129da2e3ebdSchin {
21307c2fbfb3SApril Chin #if SHOPT_MULTIBYTE
21317c2fbfb3SApril Chin if(mbwide() && (len=mbsize(cp))>1)
21327c2fbfb3SApril Chin {
21337c2fbfb3SApril Chin cp += len;
21347c2fbfb3SApril Chin size -= (len-1);
21357c2fbfb3SApril Chin continue;
21367c2fbfb3SApril Chin }
21377c2fbfb3SApril Chin #endif
2138da2e3ebdSchin c = state[n= *(unsigned char*)cp++];
2139da2e3ebdSchin if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3)
2140da2e3ebdSchin c=1;
2141da2e3ebdSchin else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n)))
2142da2e3ebdSchin c=1;
2143da2e3ebdSchin else if(mp->pattern==2 && c==S_SLASH)
2144da2e3ebdSchin c=1;
2145da2e3ebdSchin else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE)))
2146da2e3ebdSchin {
2147da2e3ebdSchin if(!(c=mp->quote))
2148da2e3ebdSchin cp++;
2149da2e3ebdSchin }
2150da2e3ebdSchin else
2151da2e3ebdSchin c=0;
2152da2e3ebdSchin if(c)
2153da2e3ebdSchin {
2154da2e3ebdSchin if(c = (cp-1) - str)
21557c2fbfb3SApril Chin sfwrite(stkp,str,c);
21567c2fbfb3SApril Chin sfputc(stkp,ESCAPE);
2157da2e3ebdSchin str = cp-1;
2158da2e3ebdSchin }
2159da2e3ebdSchin }
2160da2e3ebdSchin if(c = cp-str)
21617c2fbfb3SApril Chin sfwrite(stkp,str,c);
2162da2e3ebdSchin }
2163da2e3ebdSchin else if(!mp->quote && mp->split && (mp->ifs||mp->pattern))
2164da2e3ebdSchin {
2165da2e3ebdSchin /* split words at ifs characters */
21667c2fbfb3SApril Chin state = mp->shp->ifstable;
2167da2e3ebdSchin if(mp->pattern)
2168da2e3ebdSchin {
2169da2e3ebdSchin char *sp = "&|()";
2170da2e3ebdSchin while(c = *sp++)
2171da2e3ebdSchin {
2172da2e3ebdSchin if(state[c]==0)
2173da2e3ebdSchin state[c] = S_EPAT;
2174da2e3ebdSchin }
2175da2e3ebdSchin sp = "*?[{";
2176da2e3ebdSchin while(c = *sp++)
2177da2e3ebdSchin {
2178da2e3ebdSchin if(state[c]==0)
2179da2e3ebdSchin state[c] = S_PAT;
2180da2e3ebdSchin }
2181da2e3ebdSchin if(state[ESCAPE]==0)
2182da2e3ebdSchin state[ESCAPE] = S_ESC;
2183da2e3ebdSchin }
2184da2e3ebdSchin while(size-->0)
2185da2e3ebdSchin {
21867c2fbfb3SApril Chin n=state[c= *(unsigned char*)cp++];
21877c2fbfb3SApril Chin #if SHOPT_MULTIBYTE
21887c2fbfb3SApril Chin if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1)
21897c2fbfb3SApril Chin {
21907c2fbfb3SApril Chin sfwrite(stkp,cp-1, len);
21917c2fbfb3SApril Chin cp += --len;
21927c2fbfb3SApril Chin size -= len;
21937c2fbfb3SApril Chin continue;
21947c2fbfb3SApril Chin }
21957c2fbfb3SApril Chin #endif
21967c2fbfb3SApril Chin if(n==S_ESC || n==S_EPAT)
2197da2e3ebdSchin {
2198da2e3ebdSchin /* don't allow extended patterns in this case */
2199da2e3ebdSchin mp->patfound = mp->pattern;
22007c2fbfb3SApril Chin sfputc(stkp,ESCAPE);
2201da2e3ebdSchin }
2202da2e3ebdSchin else if(n==S_PAT)
2203da2e3ebdSchin mp->patfound = mp->pattern;
2204da2e3ebdSchin else if(n && mp->ifs)
2205da2e3ebdSchin {
2206da2e3ebdSchin #if SHOPT_MULTIBYTE
2207da2e3ebdSchin if(n==S_MBYTE)
2208da2e3ebdSchin {
2209da2e3ebdSchin if(sh_strchr(mp->ifsp,cp-1)<0)
2210da2e3ebdSchin continue;
2211da2e3ebdSchin n = mbsize(cp-1) - 1;
2212da2e3ebdSchin if(n==-2)
2213da2e3ebdSchin n = 0;
2214da2e3ebdSchin cp += n;
2215da2e3ebdSchin size -= n;
2216da2e3ebdSchin n= S_DELIM;
2217da2e3ebdSchin }
2218da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2219da2e3ebdSchin if(n==S_SPACE || n==S_NL)
2220da2e3ebdSchin {
2221da2e3ebdSchin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2222da2e3ebdSchin size--;
2223da2e3ebdSchin #if SHOPT_MULTIBYTE
2224da2e3ebdSchin if(n==S_MBYTE && sh_strchr(mp->ifsp,cp-1)>=0)
2225da2e3ebdSchin {
2226da2e3ebdSchin n = mbsize(cp-1) - 1;
2227da2e3ebdSchin if(n==-2)
2228da2e3ebdSchin n = 0;
2229da2e3ebdSchin cp += n;
2230da2e3ebdSchin size -= n;
2231da2e3ebdSchin n=S_DELIM;
2232da2e3ebdSchin }
2233da2e3ebdSchin else
2234da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2235da2e3ebdSchin if(n==S_DELIM)
2236da2e3ebdSchin size--;
2237da2e3ebdSchin }
2238da2e3ebdSchin endfield(mp,n==S_DELIM||mp->quoted);
2239da2e3ebdSchin mp->patfound = 0;
2240da2e3ebdSchin if(n==S_DELIM)
2241da2e3ebdSchin while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2242da2e3ebdSchin size--;
2243da2e3ebdSchin if(size<=0)
2244da2e3ebdSchin break;
2245da2e3ebdSchin cp--;
2246da2e3ebdSchin continue;
2247da2e3ebdSchin
2248da2e3ebdSchin }
22497c2fbfb3SApril Chin sfputc(stkp,c);
2250da2e3ebdSchin }
2251da2e3ebdSchin if(mp->pattern)
2252da2e3ebdSchin {
2253da2e3ebdSchin cp = "&|()";
2254da2e3ebdSchin while(c = *cp++)
2255da2e3ebdSchin {
2256da2e3ebdSchin if(state[c]==S_EPAT)
2257da2e3ebdSchin state[c] = 0;
2258da2e3ebdSchin }
2259da2e3ebdSchin cp = "*?[{";
2260da2e3ebdSchin while(c = *cp++)
2261da2e3ebdSchin {
2262da2e3ebdSchin if(state[c]==S_PAT)
2263da2e3ebdSchin state[c] = 0;
2264da2e3ebdSchin }
22657c2fbfb3SApril Chin if(mp->shp->ifstable[ESCAPE]==S_ESC)
22667c2fbfb3SApril Chin mp->shp->ifstable[ESCAPE] = 0;
2267da2e3ebdSchin }
2268da2e3ebdSchin }
2269da2e3ebdSchin else
22707c2fbfb3SApril Chin sfwrite(stkp,str,size);
2271da2e3ebdSchin }
2272da2e3ebdSchin
2273da2e3ebdSchin /*
2274da2e3ebdSchin * Terminate field.
2275da2e3ebdSchin * If field is null count field if <split> is non-zero
2276da2e3ebdSchin * Do filename expansion of required
2277da2e3ebdSchin */
endfield(register Mac_t * mp,int split)2278da2e3ebdSchin static void endfield(register Mac_t *mp,int split)
2279da2e3ebdSchin {
2280da2e3ebdSchin register struct argnod *argp;
2281da2e3ebdSchin register int count=0;
22827c2fbfb3SApril Chin Stk_t *stkp = mp->shp->stk;
22837c2fbfb3SApril Chin if(stktell(stkp) > ARGVAL || split)
2284da2e3ebdSchin {
22857c2fbfb3SApril Chin argp = (struct argnod*)stkfreeze(stkp,1);
2286da2e3ebdSchin argp->argnxt.cp = 0;
2287da2e3ebdSchin argp->argflag = 0;
2288da2e3ebdSchin if(mp->patfound)
2289da2e3ebdSchin {
22907c2fbfb3SApril Chin mp->shp->argaddr = 0;
2291da2e3ebdSchin #if SHOPT_BRACEPAT
2292da2e3ebdSchin count = path_generate(argp,mp->arghead);
2293da2e3ebdSchin #else
2294da2e3ebdSchin count = path_expand(argp->argval,mp->arghead);
2295da2e3ebdSchin #endif /* SHOPT_BRACEPAT */
2296da2e3ebdSchin if(count)
2297da2e3ebdSchin mp->fields += count;
2298da2e3ebdSchin else if(split) /* pattern is null string */
2299da2e3ebdSchin *argp->argval = 0;
2300da2e3ebdSchin else /* pattern expands to nothing */
2301da2e3ebdSchin count = -1;
2302da2e3ebdSchin }
2303da2e3ebdSchin if(count==0)
2304da2e3ebdSchin {
2305da2e3ebdSchin argp->argchn.ap = *mp->arghead;
2306da2e3ebdSchin *mp->arghead = argp;
2307da2e3ebdSchin mp->fields++;
2308da2e3ebdSchin }
2309da2e3ebdSchin if(count>=0)
2310da2e3ebdSchin {
2311da2e3ebdSchin (*mp->arghead)->argflag |= ARG_MAKE;
2312da2e3ebdSchin if(mp->assign || sh_isoption(SH_NOGLOB))
2313da2e3ebdSchin argp->argflag |= ARG_RAW|ARG_EXP;
2314da2e3ebdSchin }
23157c2fbfb3SApril Chin stkseek(stkp,ARGVAL);
2316da2e3ebdSchin }
2317da2e3ebdSchin mp->quoted = mp->quote;
2318da2e3ebdSchin }
2319da2e3ebdSchin
2320da2e3ebdSchin /*
2321da2e3ebdSchin * Finds the right substring of STRING using the expression PAT
2322da2e3ebdSchin * the longest substring is found when FLAG is set.
2323da2e3ebdSchin */
substring(register const char * string,const char * pat,int match[],int flag)2324da2e3ebdSchin static int substring(register const char *string,const char *pat,int match[], int flag)
2325da2e3ebdSchin {
2326da2e3ebdSchin register const char *sp=string;
2327da2e3ebdSchin register int size,len,nmatch,n;
2328da2e3ebdSchin int smatch[2*(MATCH_MAX+1)];
2329da2e3ebdSchin if(flag)
2330da2e3ebdSchin {
2331da2e3ebdSchin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL))
2332da2e3ebdSchin {
2333da2e3ebdSchin memcpy(match,smatch,n*2*sizeof(smatch[0]));
2334da2e3ebdSchin return(n);
2335da2e3ebdSchin }
2336da2e3ebdSchin return(0);
2337da2e3ebdSchin }
2338da2e3ebdSchin size = len = strlen(sp);
2339da2e3ebdSchin sp += size;
2340da2e3ebdSchin while(sp>=string)
2341da2e3ebdSchin {
2342da2e3ebdSchin #if SHOPT_MULTIBYTE
2343da2e3ebdSchin if(mbwide())
2344da2e3ebdSchin sp = lastchar(string,sp);
2345da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2346da2e3ebdSchin if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL))
2347da2e3ebdSchin {
2348da2e3ebdSchin nmatch = n;
2349da2e3ebdSchin memcpy(match,smatch,n*2*sizeof(smatch[0]));
2350da2e3ebdSchin size = sp-string;
2351da2e3ebdSchin break;
2352da2e3ebdSchin }
2353da2e3ebdSchin sp--;
2354da2e3ebdSchin }
2355da2e3ebdSchin if(size==len)
2356da2e3ebdSchin return(0);
2357da2e3ebdSchin if(nmatch)
2358da2e3ebdSchin {
2359da2e3ebdSchin nmatch *=2;
2360da2e3ebdSchin while(--nmatch>=0)
2361da2e3ebdSchin match[nmatch] += size;
2362da2e3ebdSchin }
2363da2e3ebdSchin return(n);
2364da2e3ebdSchin }
2365da2e3ebdSchin
2366da2e3ebdSchin #if SHOPT_MULTIBYTE
lastchar(const char * string,const char * endstring)2367da2e3ebdSchin static char *lastchar(const char *string, const char *endstring)
2368da2e3ebdSchin {
2369da2e3ebdSchin register char *str = (char*)string;
2370da2e3ebdSchin register int c;
2371da2e3ebdSchin mbinit();
2372da2e3ebdSchin while(*str)
2373da2e3ebdSchin {
2374da2e3ebdSchin if((c=mbsize(str))<0)
2375da2e3ebdSchin c = 1;
2376da2e3ebdSchin if(str+c > endstring)
2377da2e3ebdSchin break;
2378da2e3ebdSchin str += c;
2379da2e3ebdSchin }
2380da2e3ebdSchin return(str);
2381da2e3ebdSchin }
2382da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
charlen(const char * string,int len)2383da2e3ebdSchin static int charlen(const char *string,int len)
2384da2e3ebdSchin {
2385da2e3ebdSchin if(!string)
2386da2e3ebdSchin return(0);
2387da2e3ebdSchin #if SHOPT_MULTIBYTE
2388da2e3ebdSchin if(mbwide())
2389da2e3ebdSchin {
2390da2e3ebdSchin register const char *str = string, *strmax=string+len;
2391da2e3ebdSchin register int n=0;
2392da2e3ebdSchin mbinit();
2393da2e3ebdSchin if(len>0)
2394da2e3ebdSchin {
2395da2e3ebdSchin while(str<strmax && mbchar(str))
2396da2e3ebdSchin n++;
2397da2e3ebdSchin }
2398da2e3ebdSchin else while(mbchar(str))
2399da2e3ebdSchin n++;
2400da2e3ebdSchin return(n);
2401da2e3ebdSchin }
2402da2e3ebdSchin else
2403da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2404da2e3ebdSchin {
2405da2e3ebdSchin if(len<0)
2406da2e3ebdSchin return(strlen(string));
2407da2e3ebdSchin return(len);
2408da2e3ebdSchin }
2409da2e3ebdSchin }
2410da2e3ebdSchin
2411da2e3ebdSchin /*
2412da2e3ebdSchin * This is the default tilde discipline function
2413da2e3ebdSchin */
sh_btilde(int argc,char * argv[],void * context)2414da2e3ebdSchin static int sh_btilde(int argc, char *argv[], void *context)
2415da2e3ebdSchin {
24167c2fbfb3SApril Chin Shell_t *shp = ((Shbltin_t*)context)->shp;
24177c2fbfb3SApril Chin char *cp = sh_tilde(shp,argv[1]);
2418da2e3ebdSchin NOT_USED(argc);
2419da2e3ebdSchin if(!cp)
2420da2e3ebdSchin cp = argv[1];
2421da2e3ebdSchin sfputr(sfstdout, cp, '\n');
2422da2e3ebdSchin return(0);
2423da2e3ebdSchin }
2424da2e3ebdSchin
2425da2e3ebdSchin /*
2426da2e3ebdSchin * <offset> is byte offset for beginning of tilde string
2427da2e3ebdSchin */
tilde_expand2(Shell_t * shp,register int offset)24287c2fbfb3SApril Chin static void tilde_expand2(Shell_t *shp, register int offset)
2429da2e3ebdSchin {
24307c2fbfb3SApril Chin char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1);
2431da2e3ebdSchin Sfio_t *iop, *save=sfstdout;
2432da2e3ebdSchin Namval_t *np;
2433da2e3ebdSchin static int beenhere=0;
2434da2e3ebdSchin strcpy(shtilde,".sh.tilde");
24357c2fbfb3SApril Chin np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL);
2436da2e3ebdSchin if(np && !beenhere)
2437da2e3ebdSchin {
2438da2e3ebdSchin beenhere = 1;
2439da2e3ebdSchin sh_addbuiltin(shtilde,sh_btilde,0);
24407c2fbfb3SApril Chin nv_onattr(np,NV_EXPORT);
2441da2e3ebdSchin }
2442da2e3ebdSchin av[0] = ".sh.tilde";
2443da2e3ebdSchin av[1] = &ptr[offset];
2444da2e3ebdSchin av[2] = 0;
2445da2e3ebdSchin iop = sftmp(IOBSIZE+1);;
2446da2e3ebdSchin sfset(iop,SF_READ,0);
2447da2e3ebdSchin sfstdout = iop;
2448da2e3ebdSchin if(np)
2449da2e3ebdSchin sh_fun(np, (Namval_t*)0, av);
2450da2e3ebdSchin else
2451da2e3ebdSchin sh_btilde(2, av, &sh);
2452da2e3ebdSchin sfstdout = save;
24537c2fbfb3SApril Chin stkset(shp->stk,ptr, offset);
2454da2e3ebdSchin sfseek(iop,(Sfoff_t)0,SEEK_SET);
2455da2e3ebdSchin sfset(iop,SF_READ,1);
2456da2e3ebdSchin if(ptr = sfreserve(iop, SF_UNBOUND, -1))
2457da2e3ebdSchin {
2458da2e3ebdSchin Sfoff_t n = sfvalue(iop);
2459da2e3ebdSchin while(ptr[n-1]=='\n')
2460da2e3ebdSchin n--;
2461da2e3ebdSchin if(n==1 && fcpeek(0)=='/' && ptr[n-1])
2462da2e3ebdSchin n--;
2463da2e3ebdSchin if(n)
24647c2fbfb3SApril Chin sfwrite(shp->stk,ptr,n);
2465da2e3ebdSchin }
2466da2e3ebdSchin else
24677c2fbfb3SApril Chin sfputr(shp->stk,av[1],0);
2468da2e3ebdSchin sfclose(iop);
2469da2e3ebdSchin }
2470da2e3ebdSchin
2471da2e3ebdSchin /*
2472da2e3ebdSchin * This routine is used to resolve ~ expansion.
2473da2e3ebdSchin * A ~ by itself is replaced with the users login directory.
2474da2e3ebdSchin * A ~- is replaced by the previous working directory in shell.
2475da2e3ebdSchin * A ~+ is replaced by the present working directory in shell.
2476da2e3ebdSchin * If ~name is replaced with login directory of name.
2477da2e3ebdSchin * If string doesn't start with ~ or ~... not found then 0 returned.
2478da2e3ebdSchin */
2479da2e3ebdSchin
sh_tilde(Shell_t * shp,register const char * string)24807c2fbfb3SApril Chin static char *sh_tilde(Shell_t *shp,register const char *string)
2481da2e3ebdSchin {
2482da2e3ebdSchin register char *cp;
2483da2e3ebdSchin register int c;
2484da2e3ebdSchin register struct passwd *pw;
2485da2e3ebdSchin register Namval_t *np=0;
2486da2e3ebdSchin static Dt_t *logins_tree;
2487da2e3ebdSchin if(*string++!='~')
2488da2e3ebdSchin return(NIL(char*));
2489da2e3ebdSchin if((c = *string)==0)
2490da2e3ebdSchin {
24917c2fbfb3SApril Chin if(!(cp=nv_getval(sh_scoped(shp,HOME))))
2492da2e3ebdSchin cp = getlogin();
2493da2e3ebdSchin return(cp);
2494da2e3ebdSchin }
2495da2e3ebdSchin if((c=='-' || c=='+') && string[1]==0)
2496da2e3ebdSchin {
2497da2e3ebdSchin if(c=='+')
24987c2fbfb3SApril Chin cp = nv_getval(sh_scoped(shp,PWDNOD));
2499da2e3ebdSchin else
25007c2fbfb3SApril Chin cp = nv_getval(sh_scoped(shp,OLDPWDNOD));
2501da2e3ebdSchin return(cp);
2502da2e3ebdSchin }
2503da2e3ebdSchin if(logins_tree && (np=nv_search(string,logins_tree,0)))
2504da2e3ebdSchin return(nv_getval(np));
2505da2e3ebdSchin if(!(pw = getpwnam(string)))
2506da2e3ebdSchin return(NIL(char*));
2507da2e3ebdSchin if(!logins_tree)
2508da2e3ebdSchin logins_tree = dtopen(&_Nvdisc,Dtbag);
2509da2e3ebdSchin if(np=nv_search(string,logins_tree,NV_ADD))
2510da2e3ebdSchin nv_putval(np, pw->pw_dir,0);
2511da2e3ebdSchin return(pw->pw_dir);
2512da2e3ebdSchin }
2513da2e3ebdSchin
2514da2e3ebdSchin /*
2515da2e3ebdSchin * return values for special macros
2516da2e3ebdSchin */
special(Shell_t * shp,register int c)25177c2fbfb3SApril Chin static char *special(Shell_t *shp,register int c)
2518da2e3ebdSchin {
2519da2e3ebdSchin if(c!='$')
25207c2fbfb3SApril Chin shp->argaddr = 0;
2521da2e3ebdSchin switch(c)
2522da2e3ebdSchin {
2523da2e3ebdSchin case '@':
2524da2e3ebdSchin case '*':
25257c2fbfb3SApril Chin return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*));
2526da2e3ebdSchin case '#':
2527da2e3ebdSchin #if SHOPT_FILESCAN
25287c2fbfb3SApril Chin if(shp->cur_line)
2529da2e3ebdSchin {
25307c2fbfb3SApril Chin getdolarg(shp,MAX_ARGN,(int*)0);
25317c2fbfb3SApril Chin return(ltos(shp->offsets[0]));
2532da2e3ebdSchin }
2533da2e3ebdSchin #endif /* SHOPT_FILESCAN */
25347c2fbfb3SApril Chin return(ltos(shp->st.dolc));
2535da2e3ebdSchin case '!':
25367c2fbfb3SApril Chin if(shp->bckpid)
25377c2fbfb3SApril Chin return(ltos(shp->bckpid));
2538da2e3ebdSchin break;
2539da2e3ebdSchin case '$':
2540da2e3ebdSchin if(nv_isnull(SH_DOLLARNOD))
25417c2fbfb3SApril Chin return(ltos(shp->pid));
2542da2e3ebdSchin return(nv_getval(SH_DOLLARNOD));
2543da2e3ebdSchin case '-':
25447c2fbfb3SApril Chin return(sh_argdolminus(shp->arg_context));
2545da2e3ebdSchin case '?':
25467c2fbfb3SApril Chin return(ltos(shp->savexit));
2547da2e3ebdSchin case 0:
254834f9b3eeSRoland Mainz if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname)
25497c2fbfb3SApril Chin return(shp->shname);
2550da2e3ebdSchin else
255134f9b3eeSRoland Mainz return(shp->st.cmdname);
2552da2e3ebdSchin }
2553da2e3ebdSchin return(NIL(char*));
2554da2e3ebdSchin }
2555da2e3ebdSchin
2556da2e3ebdSchin /*
2557da2e3ebdSchin * Handle macro expansion errors
2558da2e3ebdSchin */
mac_error(Namval_t * np)2559da2e3ebdSchin static void mac_error(Namval_t *np)
2560da2e3ebdSchin {
2561da2e3ebdSchin if(np)
2562da2e3ebdSchin nv_close(np);
2563da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_subst,fcfirst());
2564da2e3ebdSchin }
2565da2e3ebdSchin
2566da2e3ebdSchin /*
2567da2e3ebdSchin * Given pattern/string, replace / with 0 and return pointer to string
25687c2fbfb3SApril Chin * \ characters are stripped from string. The \ are stripped in the
25697c2fbfb3SApril Chin * replacement string unless followed by a digit or \.
2570da2e3ebdSchin */
mac_getstring(char * pattern)2571da2e3ebdSchin static char *mac_getstring(char *pattern)
2572da2e3ebdSchin {
25737c2fbfb3SApril Chin register char *cp=pattern, *rep=0, *dp;
2574da2e3ebdSchin register int c;
2575da2e3ebdSchin while(c = *cp++)
2576da2e3ebdSchin {
25777c2fbfb3SApril Chin if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp))))
25787c2fbfb3SApril Chin {
25797c2fbfb3SApril Chin c = *cp++;
25807c2fbfb3SApril Chin }
25817c2fbfb3SApril Chin else if(!rep && c=='/')
2582da2e3ebdSchin {
2583da2e3ebdSchin cp[-1] = 0;
25847c2fbfb3SApril Chin rep = dp = cp;
25857c2fbfb3SApril Chin continue;
2586da2e3ebdSchin }
25877c2fbfb3SApril Chin if(rep)
25887c2fbfb3SApril Chin *dp++ = c;
2589da2e3ebdSchin }
25907c2fbfb3SApril Chin if(rep)
25917c2fbfb3SApril Chin *dp = 0;
25927c2fbfb3SApril Chin return(rep);
2593da2e3ebdSchin }
2594