1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                  David Korn <dgk@research.att.com>                   *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * Shell macro expander
23 * expands ~
24 * expands ${...}
25 * expands $(...)
26 * expands $((...))
27 * expands `...`
28 *
29 *   David Korn
30 *   AT&T Labs
31 *
32 */
33
34#include	"defs.h"
35#include	<fcin.h>
36#include	<pwd.h>
37#include	<ctype.h>
38#include	<regex.h>
39#include	"name.h"
40#include	"variables.h"
41#include	"shlex.h"
42#include	"io.h"
43#include	"jobs.h"
44#include	"shnodes.h"
45#include	"path.h"
46#include	"national.h"
47#include	"streval.h"
48
49#undef STR_GROUP
50#ifndef STR_GROUP
51#   define STR_GROUP	0
52#endif
53
54#if SHOPT_MULTIBYTE
55#   undef isascii
56#   define isacii(c)	((c)<=UCHAR_MAX)
57#else
58#   define mbchar(p)       (*(unsigned char*)p++)
59#endif /* SHOPT_MULTIBYTE */
60
61#if _WINIX
62    static int Skip;
63#endif /*_WINIX */
64
65static int	_c_;
66typedef struct  _mac_
67{
68	Shell_t		*shp;		/* pointer to shell interpreter */
69	Sfio_t		*sp;		/* stream pointer for here-document */
70	struct argnod	**arghead;	/* address of head of argument list */
71	char		*ifsp;		/* pointer to IFS value */
72	int		fields;		/* number of fields */
73	short		quoted;		/* set when word has quotes */
74	unsigned char	ifs;		/* first char of IFS */
75	char		atmode;		/* when processing $@ */
76	char		quote;		/* set within double quoted contexts */
77	char		lit;		/* set within single quotes */
78	char		split;		/* set when word splittin is possible */
79	char		pattern;	/* set when file expansion follows */
80	char		patfound;	/* set if pattern character found */
81	char		assign;		/* set for assignments */
82	char		arith;		/* set for ((...)) */
83	char		let;		/* set when expanding let arguments */
84	char		zeros;		/* strip leading zeros when set */
85	char		arrayok;	/* $x[] ok for arrays */
86	char		subcopy;	/* set when copying subscript */
87	int		dotdot;		/* set for .. in subscript */
88	void		*nvwalk;	/* for name space walking*/
89} Mac_t;
90
91#undef ESCAPE
92#define ESCAPE		'\\'
93#define isescchar(s)	((s)>S_QUOTE)
94#define isqescchar(s)	((s)>=S_QUOTE)
95#define isbracechar(c)	((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2)
96#define ltos(x)		fmtbase((long)(x),0,0)
97
98/* type of macro expansions */
99#define M_BRACE		1	/* ${var}	*/
100#define M_TREE		2	/* ${var.}	*/
101#define M_SIZE		3	/* ${#var}	*/
102#define M_VNAME		4	/* ${!var}	*/
103#define M_SUBNAME	5	/* ${!var[sub]}	*/
104#define M_NAMESCAN	6	/* ${!var*}	*/
105#define M_NAMECOUNT	7	/* ${#var*}	*/
106#define M_TYPE		8	/* ${@var}	*/
107
108static int	substring(const char*, const char*, int[], int);
109static void	copyto(Mac_t*, int, int);
110static void	comsubst(Mac_t*, Shnode_t*, int);
111static int	varsub(Mac_t*);
112static void	mac_copy(Mac_t*,const char*, int);
113static void	tilde_expand2(Shell_t*,int);
114static char 	*sh_tilde(Shell_t*,const char*);
115static char	*special(Shell_t *,int);
116static void	endfield(Mac_t*,int);
117static void	mac_error(Namval_t*);
118static char	*mac_getstring(char*);
119static int	charlen(const char*,int);
120#if SHOPT_MULTIBYTE
121    static char	*lastchar(const char*,const char*);
122#endif /* SHOPT_MULTIBYTE */
123
124void *sh_macopen(Shell_t *shp)
125{
126	void *addr = newof(0,Mac_t,1,0);
127	Mac_t *mp = (Mac_t*)addr;
128	mp->shp = shp;
129	return(addr);
130}
131
132/*
133 * perform only parameter substitution and catch failures
134 */
135char *sh_mactry(Shell_t *shp,register char *string)
136{
137	if(string)
138	{
139		int		jmp_val;
140		int		savexit = shp->savexit;
141		struct checkpt	buff;
142		sh_pushcontext(shp,&buff,SH_JMPSUB);
143		jmp_val = sigsetjmp(buff.buff,0);
144		if(jmp_val == 0)
145			string = sh_mactrim(shp,string,0);
146		sh_popcontext(shp,&buff);
147		shp->savexit = savexit;
148		return(string);
149	}
150	return("");
151}
152
153/*
154 * Perform parameter expansion, command substitution, and arithmetic
155 * expansion on <str>.
156 * If <mode> greater than 1 file expansion is performed if the result
157 * yields a single pathname.
158 * If <mode> negative, than expansion rules for assignment are applied.
159 */
160char *sh_mactrim(Shell_t *shp, char *str, register int mode)
161{
162	register Mac_t	*mp = (Mac_t*)shp->mac_context;
163	Stk_t		*stkp = shp->stk;
164	Mac_t		savemac;
165	savemac = *mp;
166	stkseek(stkp,0);
167	mp->arith = (mode==3);
168	mp->let = 0;
169	shp->argaddr = 0;
170	mp->pattern = (mode==1||mode==2);
171	mp->patfound = 0;
172	mp->assign = 0;
173	if(mode<0)
174		mp->assign = -mode;
175	mp->quoted = mp->lit = mp->split = mp->quote = 0;
176	mp->sp = 0;
177	if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
178		mp->ifs = *mp->ifsp;
179	else
180		mp->ifs = ' ';
181	stkseek(stkp,0);
182	fcsopen(str);
183	copyto(mp,0,mp->arith);
184	str = stkfreeze(stkp,1);
185	if(mode==2)
186	{
187		/* expand only if unique */
188		struct argnod *arglist=0;
189		if((mode=path_expand(shp,str,&arglist))==1)
190			str = arglist->argval;
191		else if(mode>1)
192			errormsg(SH_DICT,ERROR_exit(1),e_ambiguous,str);
193		sh_trim(str);
194	}
195	*mp = savemac;
196	return(str);
197}
198
199/*
200 * Perform all the expansions on the argument <argp>
201 */
202int sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag)
203{
204	register int	flags = argp->argflag;
205	register char	*str = argp->argval;
206	register Mac_t  *mp = (Mac_t*)shp->mac_context;
207	char		**saveargaddr = shp->argaddr;
208	Mac_t		savemac;
209	Stk_t		*stkp = shp->stk;
210	savemac = *mp;
211	mp->sp = 0;
212	if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
213		mp->ifs = *mp->ifsp;
214	else
215		mp->ifs = ' ';
216	if((flag&ARG_OPTIMIZE) && !shp->indebug && !(flags&ARG_MESSAGE))
217		shp->argaddr = (char**)&argp->argchn.ap;
218	else
219		shp->argaddr = 0;
220	mp->arghead = arghead;
221	mp->quoted = mp->lit = mp->quote = 0;
222	mp->arith = ((flag&ARG_ARITH)!=0);
223	mp->let = ((flag&ARG_LET)!=0);
224	mp->split = !(flag&ARG_ASSIGN);
225	mp->assign = !mp->split;
226	mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB);
227	mp->arrayok = mp->arith || (flag&ARG_ARRAYOK);
228	str = argp->argval;
229	fcsopen(str);
230	mp->fields = 0;
231	mp->atmode = 0;
232	if(!arghead)
233	{
234		mp->split = 0;
235		mp->pattern = ((flag&ARG_EXP)!=0);
236		stkseek(stkp,0);
237	}
238	else
239	{
240		stkseek(stkp,ARGVAL);
241		*stkptr(stkp,ARGVAL-1) = 0;
242	}
243	mp->patfound = 0;
244	if(mp->pattern)
245		mp->arrayok = 0;
246	copyto(mp,0,mp->arith);
247	if(!arghead)
248	{
249		argp->argchn.cp = stkfreeze(stkp,1);
250		if(shp->argaddr)
251			argp->argflag |= ARG_MAKE;
252	}
253	else
254	{
255		endfield(mp,mp->quoted|mp->atmode);
256		flags = mp->fields;
257		if(flags==1 && shp->argaddr)
258			argp->argchn.ap = *arghead;
259	}
260	shp->argaddr = saveargaddr;
261	*mp = savemac;
262	return(flags);
263}
264
265/*
266 * Expand here document which is stored in <infile> or <string>
267 * The result is written to <outfile>
268 */
269void sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string)
270{
271	register int	c,n;
272	register const char	*state = sh_lexstates[ST_QUOTE];
273	register char	*cp;
274	register Mac_t	*mp = (Mac_t*)shp->mac_context;
275	Lex_t		*lp = (Lex_t*)mp->shp->lex_context;
276	Fcin_t		save;
277	Mac_t		savemac;
278	Stk_t		*stkp = shp->stk;
279	savemac = *mp;
280	stkseek(stkp,0);
281	shp->argaddr = 0;
282	mp->sp = outfile;
283	mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0;
284	mp->quote = 1;
285	mp->ifsp = nv_getval(sh_scoped(shp,IFSNOD));
286	mp->ifs = ' ';
287	fcsave(&save);
288	if(infile)
289		fcfopen(infile);
290	else
291		fcsopen(string);
292	fcnotify(0,lp);
293	cp = fcseek(0);
294	while(1)
295	{
296#if SHOPT_MULTIBYTE
297		if(mbwide())
298		{
299			do
300			{
301				ssize_t len;
302				switch(len = mbsize(cp))
303				{
304				    case -1:	/* illegal multi-byte char */
305				    case 0:
306				    case 1:
307					n=state[*(unsigned char*)cp++];
308					break;
309				    default:
310					/* use state of alpha character */
311					n=state['a'];
312					cp += len;
313				}
314			}
315			while(n == 0);
316		}
317		else
318#endif /* SHOPT_MULTIBYTE */
319		while((n=state[*(unsigned char*)cp++])==0);
320		if(n==S_NL || n==S_QUOTE || n==S_RBRA)
321			continue;
322		if(c=(cp-1)-fcseek(0))
323			sfwrite(outfile,fcseek(0),c);
324		cp = fcseek(c+1);
325		switch(n)
326		{
327		    case S_EOF:
328			if((n=fcfill()) <=0)
329			{
330				/* ignore 0 byte when reading from file */
331				if(n==0 && fcfile())
332					continue;
333				fcrestore(&save);
334				*mp = savemac;
335				return;
336			}
337			cp = fcseek(-1);
338			continue;
339		    case S_ESC:
340			fcgetc(c);
341			cp=fcseek(-1);
342			if(c>0)
343				cp++;
344			if(!isescchar(state[c]))
345				sfputc(outfile,ESCAPE);
346			continue;
347		    case S_GRAVE:
348			comsubst(mp,(Shnode_t*)0,0);
349			break;
350		    case S_DOL:
351			c = fcget();
352			if(c=='.')
353				goto regular;
354		    again:
355			switch(n=sh_lexstates[ST_DOL][c])
356			{
357			    case S_ALP: case S_SPC1: case S_SPC2:
358			    case S_DIG: case S_LBRA:
359			    {
360				Fcin_t	save2;
361				int	offset = stktell(stkp);
362				int	offset2;
363				fcnotify(0,lp);
364				sfputc(stkp,c);
365				if(n==S_LBRA)
366				{
367					c = fcget();
368					fcseek(-1);
369					if(sh_lexstates[ST_NORM][c]==S_BREAK)
370					{
371						comsubst(mp,(Shnode_t*)0,2);
372						break;
373					}
374					sh_lexskip(lp,RBRACE,1,ST_BRACE);
375				}
376				else if(n==S_ALP)
377				{
378					while(fcgetc(c),isaname(c))
379						sfputc(stkp,c);
380					fcseek(-1);
381				}
382				sfputc(stkp,0);
383				offset2 = stktell(stkp);
384				fcsave(&save2);
385				fcsopen(stkptr(stkp,offset));
386				varsub(mp);
387				if(c=stktell(stkp)-offset2)
388					sfwrite(outfile,(char*)stkptr(stkp,offset2),c);
389				fcrestore(&save2);
390				stkseek(stkp,offset);
391				break;
392			    }
393			    case S_PAR:
394				comsubst(mp,(Shnode_t*)0,1);
395				break;
396			    case S_EOF:
397				if((c=fcfill()) > 0)
398					goto again;
399				/* FALL THRU */
400			    default:
401			    regular:
402				sfputc(outfile,'$');
403				fcseek(-1);
404				break;
405			}
406		}
407		cp = fcseek(0);
408	}
409}
410
411/*
412 * expand argument but do not trim pattern characters
413 */
414char *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags)
415{
416	register char *sp = arg->argval;
417	if((arg->argflag&ARG_RAW))
418		return(sp);
419	sh_stats(STAT_ARGEXPAND);
420	if(flags&ARG_OPTIMIZE)
421		arg->argchn.ap=0;
422	if(!(sp=arg->argchn.cp))
423	{
424		sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK);
425		sp = arg->argchn.cp;
426		if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE))
427			arg->argchn.cp = 0;
428		arg->argflag &= ~ARG_MAKE;
429	}
430	else
431		sh_stats(STAT_ARGHITS);
432	return(sp);
433}
434
435/*
436 * Process the characters up to <endch> or end of input string
437 */
438static void copyto(register Mac_t *mp,int endch, int newquote)
439{
440	register int	c,n;
441	register const char	*state = sh_lexstates[ST_MACRO];
442	register char	*cp,*first;
443	Lex_t		*lp = (Lex_t*)mp->shp->lex_context;
444	int		tilde = -1;
445	int		oldquote = mp->quote;
446	int		ansi_c = 0;
447	int		paren = 0;
448	int		ere = 0;
449	int		brace = 0;
450	Sfio_t		*sp = mp->sp;
451	Stk_t		*stkp = mp->shp->stk;
452	char		*resume = 0;
453	mp->sp = NIL(Sfio_t*);
454	mp->quote = newquote;
455	first = cp = fcseek(0);
456	if(!mp->quote && *cp=='~' && cp[1]!=LPAREN)
457		tilde = stktell(stkp);
458	/* handle // operator specially */
459	if(mp->pattern==2 && *cp=='/')
460		cp++;
461	while(1)
462	{
463#if SHOPT_MULTIBYTE
464		if(mbwide())
465		{
466			ssize_t len;
467			do
468			{
469				switch(len = mbsize(cp))
470				{
471				    case -1:	/* illegal multi-byte char */
472				    case 0:
473					len = 1;
474				    case 1:
475					n = state[*(unsigned char*)cp++];
476					break;
477				    default:
478					/* treat as if alpha */
479					cp += len;
480					n=state['a'];
481				}
482			}
483			while(n == 0);
484			c = (cp-len) - first;
485		}
486		else
487#endif /* SHOPT_MULTIBYTE */
488		{
489			while((n=state[*(unsigned char*)cp++])==0);
490			c = (cp-1) - first;
491		}
492		switch(n)
493		{
494		    case S_ESC:
495			if(ansi_c)
496			{
497				/* process ANSI-C escape character */
498				char *addr= --cp;
499				if(c)
500					sfwrite(stkp,first,c);
501				c = chresc(cp,&addr);
502				cp = addr;
503				first = fcseek(cp-first);
504#if SHOPT_MULTIBYTE
505				if(c > UCHAR_MAX && mbwide())
506				{
507					int		i;
508					unsigned char	mb[8];
509
510					n = mbconv((char*)mb, c);
511					for(i=0;i<n;i++)
512						sfputc(stkp,mb[i]);
513				}
514				else
515#endif /* SHOPT_MULTIBYTE */
516				sfputc(stkp,c);
517				if(c==ESCAPE && mp->pattern)
518					sfputc(stkp,ESCAPE);
519				break;
520			}
521			else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.'))
522				break;
523			else if(mp->split && endch && !mp->quote && !mp->lit)
524			{
525				if(c)
526					mac_copy(mp,first,c);
527				cp = fcseek(c+2);
528				if(c= cp[-1])
529				{
530					sfputc(stkp,c);
531					if(c==ESCAPE)
532						sfputc(stkp,ESCAPE);
533				}
534				else
535					cp--;
536				first = cp;
537				break;
538			}
539			n = state[*(unsigned char*)cp];
540			if(n==S_ENDCH && *cp!=endch)
541				n = S_PAT;
542			if(mp->pattern)
543			{
544				/* preserve \digit for pattern matching */
545				/* also \alpha for extended patterns */
546				if(!mp->lit && !mp->quote)
547				{
548					int nc = *(unsigned char*)cp;
549					if((n==S_DIG || ((paren+ere) && (sh_lexstates[ST_DOL][nc]==S_ALP) || nc=='<' || nc=='>')))
550						break;
551					if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp))
552						break;
553				}
554				/* followed by file expansion */
555				if(!mp->lit && (n==S_ESC || (!mp->quote &&
556					(n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-'))))
557				{
558					cp += (n!=S_EOF);
559					if(ere && n==S_ESC && *cp =='\\' && cp[1]=='$')
560					{
561						/* convert \\\$ into \$' */
562						sfwrite(stkp,first,c+1);
563						cp = first = fcseek(c+3);
564					}
565					break;
566				}
567				if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH)))
568				{
569					/* add \ for file expansion */
570					sfwrite(stkp,first,c+1);
571					first = fcseek(c);
572					break;
573				}
574			}
575			if(mp->lit)
576				break;
577			if(!mp->quote || isqescchar(n) || n==S_ENDCH)
578			{
579				/* eliminate \ */
580				if(c)
581					sfwrite(stkp,first,c);
582				/* check new-line joining */
583				first = fcseek(c+1);
584			}
585			cp += (n!=S_EOF);
586			break;
587		    case S_GRAVE: case S_DOL:
588			if(mp->lit)
589				break;
590			if(c)
591			{
592				if(mp->split && !mp->quote && endch)
593					mac_copy(mp,first,c);
594				else
595					sfwrite(stkp,first,c);
596			}
597			first = fcseek(c+1);
598			c = mp->pattern;
599			if(n==S_GRAVE)
600				comsubst(mp,(Shnode_t*)0,0);
601			else if((n= *cp) == '"' && !mp->quote)
602			{
603				int off = stktell(stkp);
604				char	*dp;
605				cp = first = fcseek(1);
606				mp->quote = 1;
607				if(!ERROR_translating())
608					break;
609				while(n=c, c= *++cp)
610				{
611					if(c=='\\' && n==c)
612						c = 0;
613					else if(c=='"' && n!='\\')
614						break;
615				}
616				n = cp-first;
617				sfwrite(stkp,first,n);
618				sfputc(stkp,0);
619				cp = stkptr(stkp,off);
620				dp = (char*)sh_translate(cp);
621				stkseek(stkp,off);
622				if(dp==cp)
623				{
624					cp = first;
625					break;
626				}
627				resume = fcseek(n);
628				fcclose();
629				fcsopen(dp);
630				cp = first = fcseek(0);
631				break;
632			}
633			else if(n==0 || !varsub(mp))
634			{
635				if(n=='\'' && !mp->quote)
636					ansi_c = 1;
637				else if(mp->quote || n!='"')
638					sfputc(stkp,'$');
639			}
640			cp = first = fcseek(0);
641			if(mp->quote && cp)
642				mp->pattern = c;
643			break;
644		    case S_ENDCH:
645			if((mp->lit || cp[-1]!=endch || mp->quote!=newquote))
646				goto pattern;
647			if(endch==RBRACE && mp->pattern && brace)
648			{
649				brace--;
650				if(*cp==LPAREN && mp->pattern!=2)
651					goto pattern;
652				continue;
653			}
654		    case S_EOF:
655			if(c)
656			{
657				if(mp->split && !mp->quote && !mp->lit && endch)
658					mac_copy(mp,first,c);
659				else
660					sfwrite(stkp,first,c);
661			}
662			if(n==S_EOF && resume)
663			{
664				fcclose();
665				fcsopen(resume);
666				resume = 0;
667				cp = first = fcseek(0);
668				continue;
669			}
670			c += (n!=S_EOF);
671			first = fcseek(c);
672			if(tilde>=0)
673				tilde_expand2(mp->shp,tilde);
674			goto done;
675		    case S_QUOTE:
676			if(mp->lit || mp->arith)
677				break;
678		    case S_LIT:
679			if(mp->arith)
680			{
681				if((*cp=='`' || *cp=='[') && cp[1]=='\'')
682					cp +=2;
683				break;
684			}
685			if(n==S_LIT && mp->quote)
686				break;
687			if(c)
688			{
689				if(mp->split && endch && !mp->quote && !mp->lit)
690					mac_copy(mp,first,c);
691				else
692					sfwrite(stkp,first,c);
693			}
694			first = fcseek(c+1);
695			if(n==S_LIT)
696			{
697				if(mp->quote)
698					continue;
699				if(mp->lit)
700					mp->lit = ansi_c = 0;
701				else
702					mp->lit = 1;
703			}
704			else
705				mp->quote = !mp->quote;
706			mp->quoted++;
707			break;
708		    case S_BRACT:
709			if(mp->arith || (((mp->assign&1) || endch==RBRACT) &&
710				!(mp->quote || mp->lit)))
711			{
712				int offset=0,oldpat = mp->pattern;
713				int oldarith = mp->arith, oldsub=mp->subcopy;
714				sfwrite(stkp,first,++c);
715				if(mp->assign&1)
716				{
717					if(first[c-2]=='.')
718						offset = stktell(stkp);
719					if(isastchar(*cp) && cp[1]==']')
720						errormsg(SH_DICT,ERROR_exit(1),
721e_badsubscript,*cp);
722				}
723				first = fcseek(c);
724				mp->pattern = 4;
725				mp->arith = 0;
726				mp->subcopy = 0;
727				copyto(mp,RBRACT,0);
728				mp->subcopy = oldsub;
729				mp->arith = oldarith;
730				mp->pattern = oldpat;
731				sfputc(stkp,RBRACT);
732				if(offset)
733				{
734					cp = stkptr(stkp,stktell(stkp));
735					if(sh_checkid(stkptr(stkp,offset),cp)!=cp)
736						stkseek(stkp,stktell(stkp)-2);
737				}
738				cp = first = fcseek(0);
739				break;
740			}
741		    case S_PAT:
742			if(mp->pattern && !(mp->quote || mp->lit))
743			{
744				mp->patfound = mp->pattern;
745				if((n=cp[-1])==LPAREN)
746				{
747					paren++;
748					if((cp-first)>1 && cp[-2]=='~')
749					{
750						char *p = cp;
751						while((c=mbchar(p)) && c!=RPAREN)
752							if(c=='A'||c=='E'||c=='K'||c=='P'||c=='X')
753							{
754								ere = 1;
755								break;
756							}
757					}
758				}
759				else if(n==RPAREN)
760					--paren;
761			}
762			goto pattern;
763		    case S_COM:
764			if(mp->pattern==4 && (mp->quote || mp->lit))
765			{
766				if(c)
767				{
768					sfwrite(stkp,first,c);
769					first = fcseek(c);
770				}
771				sfputc(stkp,ESCAPE);
772			}
773			break;
774		    case S_BRACE:
775			if(!(mp->quote || mp->lit))
776			{
777				mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND);
778				brace++;
779			}
780		    pattern:
781			if(!mp->pattern || !(mp->quote || mp->lit))
782			{
783				/* mark beginning of {a,b} */
784				if(n==S_BRACE && endch==0 && mp->pattern)
785					mp->pattern=4;
786				if(n==S_SLASH && mp->pattern==2)
787					mp->pattern=3;
788				break;
789			}
790			if(mp->pattern==3)
791				break;
792			if(c)
793				sfwrite(stkp,first,c);
794			first = fcseek(c);
795			sfputc(stkp,ESCAPE);
796			break;
797		    case S_EQ:
798			if(mp->assign==1)
799			{
800				if(*cp=='~' && !endch && !mp->quote && !mp->lit)
801					tilde = stktell(stkp)+(c+1);
802				mp->assign = 2;
803			}
804			break;
805		    case S_SLASH:
806		    case S_COLON:
807			if(tilde >=0)
808			{
809				if(c)
810					sfwrite(stkp,first,c);
811				first = fcseek(c);
812				tilde_expand2(mp->shp,tilde);
813#if _WINIX
814				if(Skip)
815				{
816					first = cp = fcseek(Skip);
817					Skip = 0;
818				}
819#endif /*_WINIX */
820				tilde = -1;
821				c=0;
822			}
823			if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit)
824				tilde = stktell(stkp)+(c+1);
825			else if(n==S_SLASH && mp->pattern==2)
826#if 0
827				goto pattern;
828#else
829			{
830				if(mp->quote || mp->lit)
831					goto pattern;
832				sfwrite(stkp,first,c+1);
833				first = fcseek(c+1);
834				c = stktell(stkp);
835				sh_lexskip(lp,RBRACE,0,ST_NESTED);
836				stkseek(stkp,c);
837				cp = fcseek(-1);
838				sfwrite(stkp,first,cp-first);
839				first=cp;
840			}
841#endif
842			break;
843		    case S_DOT:
844			if(*cp=='.' && mp->subcopy==1)
845			{
846				sfwrite(stkp,first,c);
847				sfputc(stkp,0);
848				mp->dotdot = stktell(stkp);
849				cp = first = fcseek(c+2);
850			}
851			break;
852		}
853	}
854done:
855	mp->sp = sp;
856	mp->quote = oldquote;
857}
858
859/*
860 * copy <str> to stack performing sub-expression substitutions
861 */
862static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize)
863{
864	register int	c,n;
865	register char *first=cp;
866	while(1)
867	{
868		while((c= *cp++) && c!=ESCAPE);
869		if(c==0)
870			break;
871		if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize))
872		{
873			c = cp-first-2;
874			if(c)
875				mac_copy(mp,first,c);
876			first=cp;
877			if(n=='\\' || n==RBRACE)
878			{
879				first--;
880				continue;
881			}
882			if((c=subexp[2*n])>=0)
883			{
884				if((n=subexp[2*n+1]-c)>0)
885					mac_copy(mp,str+c,n);
886			}
887		}
888		else if(n==0)
889			break;
890	}
891	if(n=cp-first-1)
892		mac_copy(mp,first,n);
893}
894
895#if  SHOPT_FILESCAN
896#define	MAX_OFFSETS	 (sizeof(shp->offsets)/sizeof(shp->offsets[0]))
897#define MAX_ARGN	(32*1024)
898
899/*
900 * compute the arguments $1 ... $n and $# from the current line as needed
901 * save line offsets in the offsets array.
902 */
903static char *getdolarg(Shell_t *shp, int n, int *size)
904{
905	register int c=S_DELIM, d=shp->ifstable['\\'];
906	register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line;
907	register int m=shp->offsets[0],delim=0;
908	if(m==0)
909		return(0);
910	if(m<0)
911		m = 0;
912	else if(n<=m)
913		m = n-1;
914	else
915		m--;
916	if(m >= MAX_OFFSETS-1)
917		m =  MAX_OFFSETS-2;
918	cp += shp->offsets[m+1];
919	n -= m;
920	shp->ifstable['\\'] = 0;
921	shp->ifstable[0] = S_EOF;
922	while(1)
923	{
924		if(c==S_DELIM)
925			while(shp->ifstable[*cp++]==S_SPACE);
926		first = --cp;
927		if(++m < MAX_OFFSETS)
928			shp->offsets[m] = (first-(unsigned char*)shp->cur_line);
929		while((c=shp->ifstable[*cp++])==0);
930		last = cp-1;
931		if(c==S_SPACE)
932			while((c=shp->ifstable[*cp++])==S_SPACE);
933		if(--n==0 || c==S_EOF)
934		{
935			if(last==first && c==S_EOF && (!delim || (m>1)))
936			{
937				n++;
938				m--;
939			}
940			break;
941		}
942		delim = (c==S_DELIM);
943	}
944	shp->ifstable['\\'] = d;
945	if(m > shp->offsets[0])
946		shp->offsets[0] = m;
947	if(n)
948		first = last = 0;
949	if(size)
950		*size = last-first;
951	return((char*)first);
952}
953#endif /* SHOPT_FILESCAN */
954
955/*
956 * get the prefix after name reference resolution
957 */
958static char *prefix(Shell_t *shp, char *id)
959{
960	Namval_t *np;
961	register char *sub=0, *cp = strchr(id,'.');
962	if(cp)
963	{
964		*cp = 0;
965		np = nv_search(id, shp->var_tree,0);
966		*cp = '.';
967		if(isastchar(cp[1]))
968			cp[1] = 0;
969		if(np && nv_isref(np))
970		{
971			int n;
972			char *sp;
973			shp->argaddr = 0;
974			while(nv_isref(np) && np->nvalue.cp)
975			{
976				sub = nv_refsub(np);
977				np = nv_refnode(np);
978				if(sub)
979					nv_putsub(np,sub,0L);
980			}
981			id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1));
982			memcpy(id,sp,n);
983			if(sub)
984			{
985				id[n++] = '[';
986				strcpy(&id[n],sub);
987				n+= strlen(sub)+1;
988				id[n-1] = ']';
989			}
990			strcpy(&id[n],cp);
991			return(id);
992		}
993	}
994	return(strdup(id));
995}
996
997/*
998 * copy to ']' onto the stack and return offset to it
999 */
1000static int subcopy(Mac_t *mp, int flag)
1001{
1002	int split = mp->split;
1003	int xpattern = mp->pattern;
1004	int loc = stktell(mp->shp->stk);
1005	int xarith = mp->arith;
1006	int arrayok = mp->arrayok;
1007	mp->split = 0;
1008	mp->arith = 0;
1009	mp->pattern = flag?4:0;
1010	mp->arrayok=1;
1011	mp->subcopy++;
1012	mp->dotdot = 0;
1013	copyto(mp,RBRACT,0);
1014	mp->subcopy = 0;
1015	mp->pattern = xpattern;
1016	mp->split = split;
1017	mp->arith = xarith;
1018	mp->arrayok = arrayok;
1019	return(loc);
1020}
1021
1022/*
1023 * if name is a discipline function, run the function and put the results
1024 * on the stack so that ${x.foo} behaves like ${ x.foo;}
1025 */
1026int sh_macfun(Shell_t *shp, const char *name, int offset)
1027{
1028	Namval_t	*np, *nq;
1029	np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0);
1030	if(np)
1031	{
1032		/* treat ${x.foo} as ${x.foo;} */
1033		union
1034		{
1035			struct comnod	com;
1036			Shnode_t	node;
1037		} t;
1038		union
1039		{
1040			struct argnod	arg;
1041			struct dolnod	dol;
1042			char buff[sizeof(struct dolnod)+sizeof(char*)];
1043		} d;
1044		memset(&t,0,sizeof(t));
1045		memset(&d,0,sizeof(d));
1046		t.node.com.comarg = &d.arg;
1047		t.node.com.comline = shp->inlineno;
1048		d.dol.dolnum = 1;
1049		d.dol.dolval[0] = strdup(name);
1050		stkseek(shp->stk,offset);
1051		comsubst((Mac_t*)shp->mac_context,&t.node,2);
1052		free(d.dol.dolval[0]);
1053		return(1);
1054	}
1055	return(0);
1056}
1057
1058static int namecount(Mac_t *mp,const char *prefix)
1059{
1060	int count = 0;
1061	mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1062	while(nv_dirnext(mp->nvwalk))
1063		count++;
1064	nv_dirclose(mp->nvwalk);
1065	return(count);
1066}
1067
1068static char *nextname(Mac_t *mp,const char *prefix, int len)
1069{
1070	char *cp;
1071	if(len==0)
1072	{
1073		mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1074		return((char*)mp->nvwalk);
1075	}
1076	if(!(cp=nv_dirnext(mp->nvwalk)))
1077		nv_dirclose(mp->nvwalk);
1078	return(cp);
1079}
1080
1081/*
1082 * This routine handles $param,  ${parm}, and ${param op word}
1083 * The input stream is assumed to be a string
1084 */
1085static int varsub(Mac_t *mp)
1086{
1087	register int	c;
1088	register int	type=0; /* M_xxx */
1089	register char	*v,*argp=0;
1090	register Namval_t	*np = NIL(Namval_t*);
1091	register int 	dolg=0, mode=0;
1092	Lex_t		*lp = (Lex_t*)mp->shp->lex_context;
1093	Namarr_t	*ap=0;
1094	int		dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0;
1095	char		idbuff[3], *id = idbuff, *pattern=0, *repstr=0, *arrmax=0;
1096	char		*idx = 0;
1097	int		var=1,addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d;
1098	Stk_t		*stkp = mp->shp->stk;
1099retry1:
1100	mp->zeros = 0;
1101	idbuff[0] = 0;
1102	idbuff[1] = 0;
1103	c = fcmbget(&LEN);
1104	switch(isascii(c)?sh_lexstates[ST_DOL][c]:S_ALP)
1105	{
1106	    case S_RBRA:
1107		if(type<M_SIZE)
1108			goto nosub;
1109		/* This code handles ${#} */
1110		c = mode;
1111		mode = type = 0;
1112		/* FALL THRU */
1113	    case S_SPC1:
1114		if(type==M_BRACE)
1115		{
1116			if(isaletter(mode=fcpeek(0)) || mode=='.')
1117			{
1118				if(c=='#')
1119					type = M_SIZE;
1120#ifdef SHOPT_TYPEDEF
1121				else if(c=='@')
1122				{
1123					type = M_TYPE;
1124					goto retry1;
1125				}
1126#endif /* SHOPT_TYPEDEF */
1127				else
1128					type = M_VNAME;
1129				mode = c;
1130				goto retry1;
1131			}
1132			else if(c=='#' && (isadigit(mode)||fcpeek(1)==RBRACE))
1133			{
1134				type = M_SIZE;
1135				mode = c;
1136				goto retry1;
1137			}
1138		}
1139		/* FALL THRU */
1140	    case S_SPC2:
1141		var = 0;
1142		*id = c;
1143		v = special(mp->shp,c);
1144		if(isastchar(c))
1145		{
1146			mode = c;
1147#if  SHOPT_FILESCAN
1148			if(mp->shp->cur_line)
1149			{
1150				v = getdolarg(mp->shp,1,(int*)0);
1151				dolmax = MAX_ARGN;
1152			}
1153			else
1154#endif  /* SHOPT_FILESCAN */
1155			dolmax = mp->shp->st.dolc+1;
1156			mp->atmode = (v && mp->quoted && c=='@');
1157			dolg = (v!=0);
1158		}
1159		break;
1160	    case S_LBRA:
1161		if(type)
1162			goto nosub;
1163		type = M_BRACE;
1164		goto retry1;
1165	    case S_PAR:
1166		if(type)
1167			goto nosub;
1168		comsubst(mp,(Shnode_t*)0,1);
1169		return(1);
1170	    case S_DIG:
1171		var = 0;
1172		c -= '0';
1173		mp->shp->argaddr = 0;
1174		if(type)
1175		{
1176			register int d;
1177			while((d=fcget()),isadigit(d))
1178				c = 10*c + (d-'0');
1179			fcseek(-1);
1180		}
1181		idnum = c;
1182		if(c==0)
1183			v = special(mp->shp,c);
1184#if  SHOPT_FILESCAN
1185		else if(mp->shp->cur_line)
1186		{
1187			mp->shp->used_pos = 1;
1188			v = getdolarg(mp->shp,c,&vsize);
1189		}
1190#endif  /* SHOPT_FILESCAN */
1191		else if(c <= mp->shp->st.dolc)
1192		{
1193			mp->shp->used_pos = 1;
1194			v = mp->shp->st.dolv[c];
1195		}
1196		else
1197			v = 0;
1198		break;
1199	    case S_ALP:
1200		if(c=='.' && type==0)
1201			goto nosub;
1202		offset = stktell(stkp);
1203		do
1204		{
1205			register int d;
1206			np = 0;
1207			do
1208			{
1209				if(LEN==1)
1210					sfputc(stkp,c);
1211				else
1212					sfwrite(stkp,fcseek(0)-LEN,LEN);
1213			}
1214			while((d=c,(c=fcmbget(&LEN)),isaname(c))||type && c=='.');
1215			while(c==LBRACT && (type||mp->arrayok))
1216			{
1217				mp->shp->argaddr=0;
1218				if((c=fcmbget(&LEN),isastchar(c)) && fcpeek(0)==RBRACT && d!='.')
1219				{
1220					if(type==M_VNAME)
1221						type = M_SUBNAME;
1222					idbuff[0] = mode = c;
1223					fcget();
1224					c = fcmbget(&LEN);
1225					if(c=='.' || c==LBRACT)
1226					{
1227						sfputc(stkp,LBRACT);
1228						sfputc(stkp,mode);
1229						sfputc(stkp,RBRACT);
1230					}
1231					else
1232						flag = NV_ARRAY;
1233					break;
1234				}
1235				else
1236				{
1237					fcseek(-LEN);
1238					c = stktell(stkp);
1239					if(d!='.')
1240						sfputc(stkp,LBRACT);
1241					v = stkptr(stkp,subcopy(mp,1));
1242					if(type && mp->dotdot)
1243					{
1244						mode = '@';
1245						v[-1] = 0;
1246						if(type==M_VNAME)
1247							type = M_SUBNAME;
1248						else if(type==M_SIZE)
1249							goto nosub;
1250					}
1251					else if(d!='.')
1252						sfputc(stkp,RBRACT);
1253					c = fcmbget(&LEN);
1254					if(c==0 && type==M_VNAME)
1255						type = M_SUBNAME;
1256				}
1257			}
1258		}
1259		while(type && c=='.');
1260		if(type!=M_VNAME && c==RBRACE && type &&  fcpeek(-2)=='.')
1261		{
1262			/* ${x.} or ${x..} */
1263			if(fcpeek(-3) == '.')
1264			{
1265				stkseek(stkp,stktell(stkp)-2);
1266				nv_local = 1;
1267			}
1268			else
1269			{
1270				stkseek(stkp,stktell(stkp)-1);
1271				type = M_TREE;
1272			}
1273		}
1274		sfputc(stkp,0);
1275		id=stkptr(stkp,offset);
1276		if(isastchar(c) && type)
1277		{
1278			if(type==M_VNAME || type==M_SIZE)
1279			{
1280				idbuff[0] = mode = c;
1281				if((d=fcpeek(0))==c)
1282					idbuff[1] = fcget();
1283				if(type==M_VNAME)
1284					type = M_NAMESCAN;
1285				else
1286					type = M_NAMECOUNT;
1287				break;
1288			}
1289			goto nosub;
1290		}
1291		flag |= NV_NOASSIGN|NV_VARNAME|NV_NOADD;
1292		if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?')))
1293		{
1294			if(c=='=' || (c==':' && d=='='))
1295				flag |= NV_ASSIGN;
1296			flag &= ~NV_NOADD;
1297		}
1298#if  SHOPT_FILESCAN
1299		if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0)
1300		{
1301			mp->shp->argaddr=0;
1302			np = REPLYNOD;
1303		}
1304		else
1305#endif  /* SHOPT_FILESCAN */
1306		{
1307			if(mp->shp->argaddr)
1308				flag &= ~NV_NOADD;
1309			np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL);
1310			if(!np)
1311			{
1312				sfprintf(mp->shp->strbuf,"%s%c",id,0);
1313				id = sfstruse(mp->shp->strbuf);
1314			}
1315		}
1316		if(isastchar(mode))
1317			var = 0;
1318		if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY) && strchr(id,'.'))
1319		{
1320			if(sh_macfun(mp->shp,id,offset))
1321			{
1322				fcmbget(&LEN);
1323				return(1);
1324			}
1325		}
1326		if(np && (flag&NV_NOADD) && nv_isnull(np))
1327		{
1328			if(nv_isattr(np,NV_NOFREE))
1329				nv_offattr(np,NV_NOFREE);
1330#if  SHOPT_FILESCAN
1331			else if(np!=REPLYNOD  || !mp->shp->cur_line)
1332#else
1333			else
1334#endif  /* SHOPT_FILESCAN */
1335				np = 0;
1336		}
1337		ap = np?nv_arrayptr(np):0;
1338		if(type)
1339		{
1340			if(mp->dotdot)
1341			{
1342				Namval_t *nq;
1343#if SHOPT_FIXEDARRAY
1344				if(ap && !ap->fixed && (nq=nv_opensub(np)))
1345#else
1346				if(ap && (nq=nv_opensub(np)))
1347#endif /* SHOPT_FIXEDARRAY */
1348					ap = nv_arrayptr(np=nq);
1349				if(ap)
1350				{
1351					nv_putsub(np,v,ARRAY_SCAN);
1352					v = stkptr(stkp,mp->dotdot);
1353					dolmax =1;
1354					if(array_assoc(ap))
1355						arrmax = strdup(v);
1356					else if((dolmax = (int)sh_arith(mp->shp,v))<0)
1357						dolmax += array_maxindex(np);
1358					if(type==M_SUBNAME)
1359						bysub = 1;
1360				}
1361				else
1362				{
1363					if((int)sh_arith(mp->shp,v))
1364						np = 0;
1365				}
1366			}
1367			else if(ap && (isastchar(mode)||type==M_TREE)  && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE)
1368				nv_putsub(np,NIL(char*),ARRAY_SCAN);
1369			if(!isbracechar(c))
1370				goto nosub;
1371			else
1372				fcseek(-LEN);
1373		}
1374		else
1375			fcseek(-1);
1376		if(type<=1 && np && nv_isvtree(np) && mp->pattern==1 && !mp->split)
1377		{
1378			int cc=fcmbget(&LEN),peek=LEN;
1379			if(type && cc=='}')
1380			{
1381				cc = fcmbget(&LEN);
1382				peek++;
1383			}
1384			if(mp->quote && cc=='"')
1385			{
1386				cc = fcmbget(&LEN);
1387				peek++;
1388			}
1389			fcseek(-peek);
1390			if(cc==0)
1391				mp->assign = 1;
1392		}
1393		if((type==M_VNAME||type==M_SUBNAME)  && mp->shp->argaddr && strcmp(nv_name(np),id))
1394			mp->shp->argaddr = 0;
1395		c = (type>M_BRACE && isastchar(mode));
1396		if(np && (type==M_TREE || !c || !ap))
1397		{
1398			char *savptr;
1399			c = *((unsigned char*)stkptr(stkp,offset-1));
1400			savptr = stkfreeze(stkp,0);
1401			if(type==M_VNAME || (type==M_SUBNAME && ap))
1402			{
1403				type = M_BRACE;
1404				v = nv_name(np);
1405				if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF))
1406					addsub = 1;
1407			}
1408#ifdef SHOPT_TYPEDEF
1409			else if(type==M_TYPE)
1410			{
1411				Namval_t *nq = nv_type(np);
1412				type = M_BRACE;
1413				if(nq)
1414					nv_typename(nq,mp->shp->strbuf);
1415				else
1416					nv_attribute(np,mp->shp->strbuf,"typeset",1);
1417				v = sfstruse(mp->shp->strbuf);
1418			}
1419#endif /* SHOPT_TYPEDEF */
1420#if  SHOPT_FILESCAN
1421			else if(mp->shp->cur_line && np==REPLYNOD)
1422				v = mp->shp->cur_line;
1423#endif  /* SHOPT_FILESCAN */
1424			else if(type==M_TREE)
1425				v = nv_getvtree(np,(Namfun_t*)0);
1426			else
1427			{
1428				if(type && fcpeek(0)=='+')
1429				{
1430					if(ap)
1431						v = nv_arrayisset(np,ap)?(char*)"x":0;
1432					else
1433						v = nv_isnull(np)?0:(char*)"x";
1434				}
1435				else
1436					v = nv_getval(np);
1437				mp->atmode = (v && mp->quoted && mode=='@');
1438				/* special case --- ignore leading zeros */
1439				if((mp->let || (mp->arith&&nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL)))) && !nv_isattr(np,NV_INTEGER) && (offset==0 || isspace(c) || strchr(",.+-*/=%&|^?!<>",c)))
1440					mp->zeros = 1;
1441			}
1442			if(savptr==stakptr(0))
1443				stkseek(stkp,offset);
1444			else
1445				stkset(stkp,savptr,offset);
1446		}
1447		else
1448		{
1449			if(sh_isoption(SH_NOUNSET) && !isastchar(mode) && (type==M_VNAME || type==M_SIZE))
1450				errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1451			v = 0;
1452			if(type==M_VNAME)
1453			{
1454				v = id;
1455				type = M_BRACE;
1456			}
1457			else if(type==M_TYPE)
1458				type = M_BRACE;
1459		}
1460		stkseek(stkp,offset);
1461		if(ap)
1462		{
1463#if SHOPT_OPTIMIZE
1464			if(mp->shp->argaddr)
1465				nv_optimize(np);
1466#endif
1467			if(isastchar(mode) && array_elem(ap)> !c)
1468				dolg = -1;
1469			else
1470			{
1471				ap->nelem &= ~ARRAY_SCAN;
1472				dolg = 0;
1473
1474			}
1475		}
1476		break;
1477	    case S_EOF:
1478		fcseek(-1);
1479	    default:
1480		goto nosub;
1481	}
1482	c = fcmbget(&LEN);
1483	if(type>M_TREE)
1484	{
1485		if(c!=RBRACE)
1486			mac_error(np);
1487		if(type==M_NAMESCAN || type==M_NAMECOUNT)
1488		{
1489			mp->shp->last_root = mp->shp->var_tree;
1490			id = idx = prefix(mp->shp,id);
1491			stkseek(stkp,offset);
1492			if(type==M_NAMECOUNT)
1493			{
1494				c = namecount(mp,id);
1495				v = ltos(c);
1496			}
1497			else
1498			{
1499				dolmax = strlen(id);
1500				dolg = -1;
1501				nextname(mp,id,0);
1502				v = nextname(mp,id,dolmax);
1503			}
1504		}
1505		else if(type==M_SUBNAME)
1506		{
1507			if(dolg<0)
1508			{
1509				v = nv_getsub(np);
1510				bysub=1;
1511			}
1512			else if(v)
1513			{
1514				if(!ap || isastchar(mode))
1515					v = "0";
1516				else
1517					v = nv_getsub(np);
1518			}
1519		}
1520		else
1521		{
1522			if(!isastchar(mode))
1523				c = charlen(v,vsize);
1524			else if(dolg>0)
1525			{
1526#if  SHOPT_FILESCAN
1527				if(mp->shp->cur_line)
1528				{
1529					getdolarg(mp->shp,MAX_ARGN,(int*)0);
1530					c = mp->shp->offsets[0];
1531				}
1532				else
1533#endif  /* SHOPT_FILESCAN */
1534				c = mp->shp->st.dolc;
1535			}
1536			else if(dolg<0)
1537				c = array_elem(ap);
1538			else
1539				c = (v!=0);
1540			dolg = dolmax = 0;
1541			v = ltos(c);
1542		}
1543		c = RBRACE;
1544	}
1545	nulflg = 0;
1546	if(type && c==':')
1547	{
1548		c = fcmbget(&LEN);
1549		if(isascii(c) &&sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':')
1550			nulflg=1;
1551		else if(c!='%' && c!='#')
1552		{
1553			fcseek(-LEN);
1554			c = ':';
1555		}
1556	}
1557	if(type)
1558	{
1559		if(!isbracechar(c))
1560		{
1561			if(!nulflg)
1562				mac_error(np);
1563			fcseek(-LEN);
1564			c = ':';
1565		}
1566		if(c!=RBRACE)
1567		{
1568			int newops = (c=='#' || c == '%' || c=='/');
1569			offset = stktell(stkp);
1570			if(newops && sh_isoption(SH_NOUNSET) && *id && id!=idbuff  && (!np || nv_isnull(np)))
1571				errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1572			if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%')))
1573			{
1574				int newquote = mp->quote;
1575				int split = mp->split;
1576				int quoted = mp->quoted;
1577				int arith = mp->arith;
1578				int zeros = mp->zeros;
1579				int assign = mp->assign;
1580				if(newops)
1581				{
1582					type = fcget();
1583					if(type=='%' || type=='#')
1584					{
1585						int d = fcmbget(&LEN);
1586						fcseek(-LEN);
1587						if(d=='(')
1588							type = 0;
1589					}
1590					fcseek(-1);
1591					mp->pattern = 1+(c=='/');
1592					mp->split = 0;
1593					mp->quoted = 0;
1594					mp->assign &= ~1;
1595					mp->arith = mp->zeros = 0;
1596					newquote = 0;
1597				}
1598				else if(c=='?' || c=='=')
1599					mp->split = mp->pattern = 0;
1600				copyto(mp,RBRACE,newquote);
1601				if(!oldpat)
1602					mp->patfound = 0;
1603				mp->pattern = oldpat;
1604				mp->split = split;
1605				mp->quoted = quoted;
1606				mp->arith = arith;
1607				mp->zeros = zeros;
1608				mp->assign = assign;
1609				/* add null byte */
1610				sfputc(stkp,0);
1611				if(c!='=')
1612					stkseek(stkp,stktell(stkp)-1);
1613			}
1614			else
1615			{
1616				sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED);
1617				stkseek(stkp,offset);
1618			}
1619			argp=stkptr(stkp,offset);
1620		}
1621	}
1622	else
1623	{
1624		fcseek(-1);
1625		c=0;
1626	}
1627	if(c==':')  /* ${name:expr1[:expr2]} */
1628	{
1629		char *ptr;
1630		type = (int)sh_strnum(argp,&ptr,1);
1631		if(isastchar(mode))
1632		{
1633			if(id==idbuff)  /* ${@} or ${*} */
1634			{
1635				if(type<0 && (type+= dolmax)<0)
1636					type = 0;
1637				if(type==0)
1638					v = special(mp->shp,dolg=0);
1639#if  SHOPT_FILESCAN
1640				else if(mp->shp->cur_line)
1641				{
1642					v = getdolarg(mp->shp,dolg=type,&vsize);
1643					if(!v)
1644						dolmax = type;
1645				}
1646#endif  /* SHOPT_FILESCAN */
1647				else if(type < dolmax)
1648					v = mp->shp->st.dolv[dolg=type];
1649				else
1650					v =  0;
1651			}
1652			else if(ap)
1653			{
1654				if(type<0)
1655				{
1656					if(array_assoc(ap))
1657						type = -type;
1658					else
1659						type += array_maxindex(np);
1660				}
1661				if(array_assoc(ap))
1662				{
1663					while(type-- >0 && (v=0,nv_nextsub(np)))
1664						v = nv_getval(np);
1665				}
1666				else if(type > 0)
1667				{
1668					if(nv_putsub(np,NIL(char*),type|ARRAY_SCAN))
1669						v = nv_getval(np);
1670					else
1671						v = 0;
1672				}
1673			}
1674			else if(type>0)
1675				v = 0;
1676			if(!v)
1677				mp->atmode = 0;
1678		}
1679		else if(v)
1680		{
1681			vsize = charlen(v,vsize);
1682			if(type<0 && (type += vsize)<0)
1683				type = 0;
1684			if(vsize < type)
1685				v = 0;
1686#if SHOPT_MULTIBYTE
1687			else if(mbwide())
1688			{
1689				mbinit();
1690				for(c=type;c;c--)
1691					mbchar(v);
1692				c = ':';
1693			}
1694#endif /* SHOPT_MULTIBYTE */
1695			else
1696				v += type;
1697			vsize = v?strlen(v):0;
1698		}
1699		if(*ptr==':')
1700		{
1701			if((type = (int)sh_strnum(ptr+1,&ptr,1)) <=0)
1702			{
1703				v = 0;
1704				mp->atmode = 0;
1705			}
1706			else if(isastchar(mode))
1707			{
1708				if(dolg>=0)
1709				{
1710					if(dolg+type < dolmax)
1711						dolmax = dolg+type;
1712				}
1713				else
1714					dolmax = type;
1715			}
1716			else if(type < vsize)
1717			{
1718#if SHOPT_MULTIBYTE
1719				if(mbwide())
1720				{
1721					char *vp = v;
1722					mbinit();
1723					while(type-->0)
1724					{
1725						if((c=mbsize(vp))<1)
1726							c = 1;
1727						vp += c;
1728					}
1729					type = vp-v;
1730					c = ':';
1731				}
1732#endif /* SHOPT_MULTIBYTE */
1733				vsize = type;
1734			}
1735			else
1736				vsize = v?strlen(v):0;
1737		}
1738		if(*ptr)
1739			mac_error(np);
1740		stkseek(stkp,offset);
1741		argp = 0;
1742	}
1743	/* check for substring operations */
1744	else if(c == '#' || c == '%' || c=='/')
1745	{
1746		if(c=='/')
1747		{
1748			if(type=='/' || type=='#' || type=='%')
1749			{
1750				c = type;
1751				type = '/';
1752				argp++;
1753			}
1754			else
1755				type = 0;
1756		}
1757		else
1758		{
1759			if(type==c) /* ## or %% */
1760				argp++;
1761			else
1762				type = 0;
1763		}
1764		pattern = strdup(argp);
1765		if((type=='/' || c=='/') && (repstr = mac_getstring(pattern)))
1766		{
1767			Mac_t	savemac;
1768			char	*first = fcseek(0);
1769			int	n = stktell(stkp);
1770			savemac = *mp;
1771			fcsopen(repstr);
1772			mp->pattern = 3;
1773			mp->split = 0;
1774			copyto(mp,0,0);
1775			sfputc(stkp,0);
1776			repstr = strdup(stkptr(stkp,n));
1777			replen = strlen(repstr);
1778			stkseek(stkp,n);
1779			*mp = savemac;
1780			fcsopen(first);
1781		}
1782		if(v || c=='/' && offset>=0)
1783			stkseek(stkp,offset);
1784	}
1785	/* check for quoted @ */
1786	if(mode=='@' && mp->quote && !v && c!='-')
1787		mp->quoted-=2;
1788retry2:
1789	if(v && (!nulflg || *v ) && c!='+')
1790	{
1791		register int d = (mode=='@'?' ':mp->ifs);
1792		regoff_t match[2*(MATCH_MAX+1)];
1793		int nmatch, nmatch_prev, vsize_last;
1794		char *vlast;
1795		while(1)
1796		{
1797			if(!v)
1798				v= "";
1799			if(c=='/' || c=='#' || c== '%')
1800			{
1801				int index = 0;
1802				flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP;
1803				if(c!='/')
1804					flag |= STR_LEFT;
1805				nmatch = 0;
1806				while(1)
1807				{
1808					vsize = strlen(v);
1809					nmatch_prev = nmatch;
1810					if(c=='%')
1811						nmatch=substring(v,pattern,match,flag&STR_MAXIMAL);
1812					else
1813						nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag);
1814					if(nmatch && replen>0)
1815						sh_setmatch(mp->shp,v,vsize,nmatch,match,index++);
1816					if(nmatch)
1817					{
1818						vlast = v;
1819						vsize_last = vsize;
1820						vsize = match[0];
1821					}
1822					else if(c=='#')
1823						vsize = 0;
1824					if(vsize)
1825						mac_copy(mp,v,vsize);
1826					if(nmatch && replen>0 && (match[1] || !nmatch_prev))
1827						mac_substitute(mp,repstr,v,match,nmatch);
1828					if(nmatch==0)
1829						v += vsize;
1830					else
1831						v += match[1];
1832					if(*v &&  c=='/' && type)
1833					{
1834						/* avoid infinite loop */
1835						if(nmatch && match[1]==0)
1836						{
1837							nmatch = 0;
1838							mac_copy(mp,v,1);
1839							v++;
1840						}
1841						continue;
1842					}
1843					vsize = -1;
1844					break;
1845				}
1846				if(replen==0)
1847					sh_setmatch(mp->shp,vlast,vsize_last,nmatch,match,index++);
1848			}
1849			if(vsize)
1850				mac_copy(mp,v,vsize>0?vsize:strlen(v));
1851			if(addsub)
1852			{
1853				mp->shp->instance++;
1854				sfprintf(mp->shp->strbuf,"[%s]",nv_getsub(np));
1855				mp->shp->instance--;
1856				v = sfstruse(mp->shp->strbuf);
1857				mac_copy(mp, v, strlen(v));
1858			}
1859			if(dolg==0 && dolmax==0)
1860				 break;
1861			if(mp->dotdot)
1862			{
1863				if(nv_nextsub(np) == 0)
1864					break;
1865				if(bysub)
1866					v = nv_getsub(np);
1867				else
1868					v = nv_getval(np);
1869				if(array_assoc(ap))
1870				{
1871					if(strcmp(bysub?v:nv_getsub(np),arrmax)>0)
1872						break;
1873				}
1874				else
1875				{
1876					if(nv_aindex(np) > dolmax)
1877						break;
1878				}
1879			}
1880			else if(dolg>=0)
1881			{
1882				if(++dolg >= dolmax)
1883					break;
1884#if  SHOPT_FILESCAN
1885				if(mp->shp->cur_line)
1886				{
1887					if(dolmax==MAX_ARGN && isastchar(mode))
1888						break;
1889					if(!(v=getdolarg(mp->shp,dolg,&vsize)))
1890					{
1891						dolmax = dolg;
1892						break;
1893					}
1894				}
1895				else
1896#endif  /* SHOPT_FILESCAN */
1897				v = mp->shp->st.dolv[dolg];
1898			}
1899			else if(!np)
1900			{
1901				if(!(v = nextname(mp,id,dolmax)))
1902					break;
1903			}
1904			else
1905			{
1906				if(dolmax &&  --dolmax <=0)
1907				{
1908					nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1909					break;
1910				}
1911				if(ap)
1912					ap->nelem |= ARRAY_SCAN;
1913				if(nv_nextsub(np) == 0)
1914					break;
1915				if(bysub)
1916					v = nv_getsub(np);
1917				else
1918					v = nv_getval(np);
1919			}
1920			if(mp->split && (!mp->quote || mode=='@'))
1921			{
1922				if(!np)
1923					mp->pattern = 0;
1924				endfield(mp,mp->quoted);
1925				mp->atmode = mode=='@';
1926				mp->pattern = oldpat;
1927			}
1928			else if(d)
1929			{
1930				if(mp->sp)
1931					sfputc(mp->sp,d);
1932				else
1933					sfputc(stkp,d);
1934			}
1935		}
1936		if(arrmax)
1937			free((void*)arrmax);
1938	}
1939	else if(argp)
1940	{
1941		if(c=='/' && replen>0 && pattern && strmatch("",pattern))
1942			mac_substitute(mp,repstr,v,0,0);
1943		if(c=='?')
1944		{
1945			if(np)
1946				id = nv_name(np);
1947			else if(idnum)
1948				id = ltos(idnum);
1949			if(*argp)
1950			{
1951				sfputc(stkp,0);
1952				errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp);
1953			}
1954			else if(v)
1955				errormsg(SH_DICT,ERROR_exit(1),e_nullset,id);
1956			else
1957				errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1958		}
1959		else if(c=='=')
1960		{
1961			if(np)
1962			{
1963				if(mp->shp->subshell)
1964					np = sh_assignok(np,1);
1965				nv_putval(np,argp,0);
1966				v = nv_getval(np);
1967				nulflg = 0;
1968				stkseek(stkp,offset);
1969				goto retry2;
1970			}
1971		else
1972			mac_error(np);
1973		}
1974	}
1975	else if(var && sh_isoption(SH_NOUNSET) && type<=M_TREE && (!np  || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp)))
1976	{
1977		if(np)
1978		{
1979			if(nv_isarray(np))
1980			{
1981				sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np));
1982				id = sfstruse(mp->shp->strbuf);
1983			}
1984			else
1985				id = nv_name(np);
1986			nv_close(np);
1987		}
1988		errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1989	}
1990	if(np)
1991		nv_close(np);
1992	if(pattern)
1993		free(pattern);
1994	if(repstr)
1995		free(repstr);
1996	if(idx)
1997		free(idx);
1998	return(1);
1999nosub:
2000	if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK)
2001	{
2002		fcseek(-1);
2003		comsubst(mp,(Shnode_t*)0,2);
2004		return(1);
2005	}
2006	if(type)
2007		mac_error(np);
2008	fcseek(-1);
2009	nv_close(np);
2010	return(0);
2011}
2012
2013/*
2014 * This routine handles command substitution
2015 * <type> is 0 for older `...` version
2016 */
2017static void comsubst(Mac_t *mp,register Shnode_t* t, int type)
2018{
2019	Sfdouble_t		num;
2020	register int		c;
2021	register char		*str;
2022	Sfio_t			*sp;
2023	Stk_t			*stkp = mp->shp->stk;
2024	Fcin_t			save;
2025	struct slnod            *saveslp = mp->shp->st.staklist;
2026	struct _mac_		savemac;
2027	int			savtop = stktell(stkp);
2028	char			lastc=0, *savptr = stkfreeze(stkp,0);
2029	int			was_history = sh_isstate(SH_HISTORY);
2030	int			was_verbose = sh_isstate(SH_VERBOSE);
2031	int			was_interactive = sh_isstate(SH_INTERACTIVE);
2032	int			newlines,bufsize,nextnewlines;
2033	Sfoff_t			foff;
2034	Namval_t		*np;
2035	mp->shp->argaddr = 0;
2036	savemac = *mp;
2037	mp->shp->st.staklist=0;
2038#ifdef SHOPT_COSHELL
2039	if(mp->shp->inpool)
2040		return;
2041#endif /*SHOPT_COSHELL */
2042	if(type)
2043	{
2044		sp = 0;
2045		fcseek(-1);
2046		if(!t)
2047			t = sh_dolparen((Lex_t*)mp->shp->lex_context);
2048		if(t && t->tre.tretyp==TARITH)
2049		{
2050			mp->shp->inarith = 1;
2051			fcsave(&save);
2052			if(t->ar.arcomp)
2053				num = arith_exec(t->ar.arcomp);
2054			else if((t->ar.arexpr->argflag&ARG_RAW))
2055				num = sh_arith(mp->shp,t->ar.arexpr->argval);
2056			else
2057				num = sh_arith(mp->shp,sh_mactrim(mp->shp,t->ar.arexpr->argval,3));
2058			mp->shp->inarith = 0;
2059		out_offset:
2060			stkset(stkp,savptr,savtop);
2061			*mp = savemac;
2062			if((Sflong_t)num!=num)
2063				sfprintf(mp->shp->strbuf,"%.*Lg",LDBL_DIG,num);
2064			else if(num)
2065				sfprintf(mp->shp->strbuf,"%lld",(Sflong_t)num);
2066			else
2067				sfprintf(mp->shp->strbuf,"%Lg",num);
2068			str = sfstruse(mp->shp->strbuf);
2069			mac_copy(mp,str,strlen(str));
2070			mp->shp->st.staklist = saveslp;
2071			fcrestore(&save);
2072			return;
2073		}
2074	}
2075	else
2076	{
2077		while(fcgetc(c)!='`' && c)
2078		{
2079			if(c==ESCAPE)
2080			{
2081				fcgetc(c);
2082				if(!(isescchar(sh_lexstates[ST_QUOTE][c]) ||
2083				  (c=='"' && mp->quote)))
2084					sfputc(stkp,ESCAPE);
2085			}
2086			sfputc(stkp,c);
2087		}
2088		c = stktell(stkp);
2089		str=stkfreeze(stkp,1);
2090		/* disable verbose and don't save in history file */
2091		sh_offstate(SH_HISTORY);
2092		sh_offstate(SH_VERBOSE);
2093		if(mp->sp)
2094			sfsync(mp->sp);	/* flush before executing command */
2095		sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ);
2096		c = mp->shp->inlineno;
2097		mp->shp->inlineno = error_info.line+mp->shp->st.firstline;
2098		t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL);
2099		mp->shp->inlineno = c;
2100		type = 1;
2101	}
2102#if KSHELL
2103	if(t)
2104	{
2105		fcsave(&save);
2106		sfclose(sp);
2107		if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset)
2108		{
2109			/* special case $(<file) and $(<#file) */
2110			register int fd;
2111			int r;
2112			struct checkpt buff;
2113			struct ionod *ip=0;
2114			sh_pushcontext(mp->shp,&buff,SH_JMPIO);
2115			if((ip=t->tre.treio) &&
2116				((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) &&
2117				(r=sigsetjmp(buff.buff,0))==0)
2118				fd = sh_redirect(mp->shp,ip,3);
2119			else
2120				fd = sh_chkopen(e_devnull);
2121			sh_popcontext(mp->shp,&buff);
2122			if(r==0 && ip && (ip->iofile&IOLSEEK))
2123			{
2124				if(sp=mp->shp->sftable[fd])
2125					num = sftell(sp);
2126				else
2127					num = lseek(fd, (off_t)0, SEEK_CUR);
2128				goto out_offset;
2129			}
2130			if(!(sp=mp->shp->sftable[fd]))
2131				sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC);
2132			type = 3;
2133		}
2134		else
2135			sp = sh_subshell(mp->shp,t,sh_isstate(SH_ERREXIT),type);
2136		fcrestore(&save);
2137	}
2138	else
2139		sp = sfopen(NIL(Sfio_t*),"","sr");
2140	sh_freeup(mp->shp);
2141	mp->shp->st.staklist = saveslp;
2142	if(was_history)
2143		sh_onstate(SH_HISTORY);
2144	if(was_verbose)
2145		sh_onstate(SH_VERBOSE);
2146#else
2147	sp = sfpopen(NIL(Sfio_t*),str,"r");
2148#endif
2149	*mp = savemac;
2150	np = sh_scoped(mp->shp,IFSNOD);
2151	nv_putval(np,mp->ifsp,NV_RDONLY);
2152	mp->ifsp = nv_getval(np);
2153	stkset(stkp,savptr,savtop);
2154	newlines = 0;
2155	sfsetbuf(sp,(void*)sp,0);
2156	bufsize = sfvalue(sp);
2157	/* read command substitution output and put on stack or here-doc */
2158	sfpool(sp, NIL(Sfio_t*), SF_WRITE);
2159	sh_offstate(SH_INTERACTIVE);
2160	if((foff = sfseek(sp,(Sfoff_t)0,SEEK_END)) > 0)
2161	{
2162		size_t soff = stktell(stkp);
2163		sfseek(sp,(Sfoff_t)0,SEEK_SET);
2164		stkseek(stkp,soff+foff+64);
2165		stkseek(stkp,soff);
2166	}
2167	while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c=bufsize=sfvalue(sp))>0)
2168	{
2169#if SHOPT_CRNL
2170		/* eliminate <cr> */
2171		register char *dp;
2172		char *buff = str;
2173		while(c>1 && (*str !='\r'|| str[1]!='\n'))
2174		{
2175			c--;
2176			str++;
2177		}
2178		dp = str;
2179		while(c>1)
2180		{
2181			str++;
2182			c--;
2183			while(c>1 && (*str!='\r' || str[1]!='\n'))
2184			{
2185				c--;
2186				*dp++ = *str++;
2187			}
2188		}
2189		if(c)
2190			*dp++ = *str++;
2191		str = buff;
2192		c = dp-str;
2193#endif /* SHOPT_CRNL */
2194		/* delay appending trailing new-lines */
2195		for(nextnewlines=0; c-->0 && str[c]=='\n'; nextnewlines++);
2196		if(c < 0)
2197		{
2198			newlines += nextnewlines;
2199			continue;
2200		}
2201		if(newlines >0)
2202		{
2203			if(mp->sp)
2204				sfnputc(mp->sp,'\n',newlines);
2205			else if(!mp->quote && mp->split && mp->shp->ifstable['\n'])
2206				endfield(mp,0);
2207			else
2208				sfnputc(stkp,'\n',newlines);
2209		}
2210		else if(lastc)
2211		{
2212			mac_copy(mp,&lastc,1);
2213			lastc = 0;
2214		}
2215		newlines = nextnewlines;
2216		if(++c < bufsize)
2217			str[c] = 0;
2218		else
2219		{
2220			ssize_t len = 1;
2221
2222			/* can't write past buffer so save last character */
2223			c -= len;
2224			lastc = str[c];
2225			str[c] = 0;
2226		}
2227		mac_copy(mp,str,c);
2228	}
2229	if(was_interactive)
2230		sh_onstate(SH_INTERACTIVE);
2231	if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM)
2232	{
2233		if(mp->sp)
2234			sfnputc(mp->sp,'\n',newlines);
2235		else if(!mp->quote && mp->split)
2236			while(newlines--)
2237				endfield(mp,1);
2238		else
2239			sfnputc(stkp,'\n',newlines);
2240	}
2241	if(lastc)
2242	{
2243		mac_copy(mp,&lastc,1);
2244		lastc = 0;
2245	}
2246	sfclose(sp);
2247	return;
2248}
2249
2250/*
2251 * copy <str> onto the stack
2252 */
2253static void mac_copy(register Mac_t *mp,register const char *str, register int size)
2254{
2255	register char		*state;
2256	register const char	*cp=str;
2257	register int		c,n,nopat,len;
2258	Stk_t			*stkp=mp->shp->stk;
2259	int			oldpat = mp->pattern;
2260	nopat = (mp->quote||(mp->assign==1)||mp->arith);
2261	if(mp->zeros)
2262	{
2263		/* prevent leading 0's from becomming octal constants */
2264		while(size>1 && *str=='0')
2265		{
2266			if(str[1]=='x' || str[1]=='X')
2267				break;
2268			str++,size--;
2269		}
2270		mp->zeros = 0;
2271		cp = str;
2272	}
2273	if(mp->sp)
2274		sfwrite(mp->sp,str,size);
2275	else if(mp->pattern>=2 || (mp->pattern && nopat) || mp->assign==3)
2276	{
2277		state = sh_lexstates[ST_MACRO];
2278		/* insert \ before file expansion characters */
2279		while(size-->0)
2280		{
2281#if SHOPT_MULTIBYTE
2282			if(mbwide() && (len=mbsize(cp))>1)
2283			{
2284				cp += len;
2285				size -= (len-1);
2286				continue;
2287			}
2288#endif
2289			c = state[n= *(unsigned char*)cp++];
2290			if(mp->assign==3 && mp->pattern!=4)
2291			{
2292				if(c==S_BRACT)
2293				{
2294					nopat = 0;
2295					mp->pattern = 4;
2296				}
2297				continue;
2298			}
2299			if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3)
2300				c=1;
2301			else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n)))
2302			{
2303				if(c==S_ENDCH && oldpat!=4)
2304				{
2305					if(*cp==0 || *cp=='.' || *cp=='[')
2306					{
2307						mp->pattern = oldpat;
2308						c=0;
2309					}
2310					else
2311						c=1;
2312				}
2313				else
2314					c=1;
2315			}
2316			else if(mp->pattern==2 && c==S_SLASH)
2317				c=1;
2318			else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE)))
2319			{
2320				if(!(c=mp->quote))
2321					cp++;
2322			}
2323			else
2324				c=0;
2325			if(c)
2326			{
2327				if(c = (cp-1) - str)
2328					sfwrite(stkp,str,c);
2329				sfputc(stkp,ESCAPE);
2330				str = cp-1;
2331			}
2332		}
2333		if(c = cp-str)
2334			sfwrite(stkp,str,c);
2335	}
2336	else if(!mp->quote && mp->split && (mp->ifs||mp->pattern))
2337	{
2338		/* split words at ifs characters */
2339		state = mp->shp->ifstable;
2340		if(mp->pattern)
2341		{
2342			char *sp = "&|()";
2343			while(c = *sp++)
2344			{
2345				if(state[c]==0)
2346					state[c] = S_EPAT;
2347			}
2348			sp = "*?[{";
2349			while(c = *sp++)
2350			{
2351				if(state[c]==0)
2352					state[c] = S_PAT;
2353			}
2354			if(state[ESCAPE]==0)
2355				state[ESCAPE] = S_ESC;
2356		}
2357		while(size-->0)
2358		{
2359			n=state[c= *(unsigned char*)cp++];
2360#if SHOPT_MULTIBYTE
2361			if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1)
2362			{
2363				sfwrite(stkp,cp-1, len);
2364				cp += --len;
2365				size -= len;
2366				continue;
2367			}
2368#endif
2369			if(n==S_ESC || n==S_EPAT)
2370			{
2371				/* don't allow extended patterns in this case */
2372				mp->patfound = mp->pattern;
2373				sfputc(stkp,ESCAPE);
2374			}
2375			else if(n==S_PAT)
2376				mp->patfound = mp->pattern;
2377			else if(n && mp->ifs)
2378			{
2379#if SHOPT_MULTIBYTE
2380				if(n==S_MBYTE)
2381				{
2382					if(sh_strchr(mp->ifsp,cp-1)<0)
2383						continue;
2384					n = mbsize(cp-1) - 1;
2385					if(n==-2)
2386						n = 0;
2387					cp += n;
2388					size -= n;
2389					n= S_DELIM;
2390				}
2391#endif /* SHOPT_MULTIBYTE */
2392				if(n==S_SPACE || n==S_NL)
2393				{
2394					while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2395						size--;
2396#if SHOPT_MULTIBYTE
2397					if(n==S_MBYTE && sh_strchr(mp->ifsp,cp-1)>=0)
2398					{
2399						n = mbsize(cp-1) - 1;
2400						if(n==-2)
2401							n = 0;
2402						cp += n;
2403						size -= n;
2404						n=S_DELIM;
2405					}
2406					else
2407#endif /* SHOPT_MULTIBYTE */
2408					if(n==S_DELIM)
2409						size--;
2410				}
2411				endfield(mp,n==S_DELIM||mp->quoted);
2412				mp->patfound = 0;
2413				if(n==S_DELIM)
2414					while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2415						size--;
2416				if(size<=0)
2417					break;
2418				cp--;
2419				continue;
2420
2421			}
2422			sfputc(stkp,c);
2423		}
2424		if(mp->pattern)
2425		{
2426			cp = "&|()";
2427			while(c = *cp++)
2428			{
2429				if(state[c]==S_EPAT)
2430					state[c] = 0;
2431			}
2432			cp = "*?[{";
2433			while(c = *cp++)
2434			{
2435				if(state[c]==S_PAT)
2436					state[c] = 0;
2437			}
2438			if(mp->shp->ifstable[ESCAPE]==S_ESC)
2439				mp->shp->ifstable[ESCAPE] = 0;
2440		}
2441	}
2442	else
2443		sfwrite(stkp,str,size);
2444}
2445
2446/*
2447 * Terminate field.
2448 * If field is null count field if <split> is non-zero
2449 * Do filename expansion of required
2450 */
2451static void endfield(register Mac_t *mp,int split)
2452{
2453	register struct argnod	*argp;
2454	register int		count=0;
2455	Stk_t			*stkp = mp->shp->stk;
2456	if(stktell(stkp) > ARGVAL || split)
2457	{
2458		argp = (struct argnod*)stkfreeze(stkp,1);
2459		argp->argnxt.cp = 0;
2460		argp->argflag = 0;
2461		mp->atmode = 0;
2462		if(mp->patfound)
2463		{
2464			mp->shp->argaddr = 0;
2465#if SHOPT_BRACEPAT
2466			count = path_generate(mp->shp,argp,mp->arghead);
2467#else
2468			count = path_expand(mp->shp,argp->argval,mp->arghead);
2469#endif /* SHOPT_BRACEPAT */
2470			if(count)
2471				mp->fields += count;
2472			else if(split)	/* pattern is null string */
2473				*argp->argval = 0;
2474			else	/* pattern expands to nothing */
2475				count = -1;
2476		}
2477		if(count==0)
2478		{
2479			argp->argchn.ap = *mp->arghead;
2480			*mp->arghead = argp;
2481			mp->fields++;
2482		}
2483		if(count>=0)
2484		{
2485			(*mp->arghead)->argflag |= ARG_MAKE;
2486			if(mp->assign || sh_isoption(SH_NOGLOB))
2487				argp->argflag |= ARG_RAW|ARG_EXP;
2488		}
2489		stkseek(stkp,ARGVAL);
2490	}
2491	mp->quoted = mp->quote;
2492}
2493
2494/*
2495 * Finds the right substring of STRING using the expression PAT
2496 * the longest substring is found when FLAG is set.
2497 */
2498static int substring(register const char *string,const char *pat,int match[], int flag)
2499{
2500	register const char *sp=string;
2501	register int size,len,nmatch,n;
2502	int smatch[2*(MATCH_MAX+1)];
2503	if(flag)
2504	{
2505		if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL))
2506		{
2507			memcpy(match,smatch,n*2*sizeof(smatch[0]));
2508			return(n);
2509		}
2510		return(0);
2511	}
2512	size = len = strlen(sp);
2513	sp += size;
2514	while(sp>=string)
2515	{
2516#if SHOPT_MULTIBYTE
2517		if(mbwide())
2518			sp = lastchar(string,sp);
2519#endif /* SHOPT_MULTIBYTE */
2520		if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL))
2521		{
2522			nmatch = n;
2523			memcpy(match,smatch,n*2*sizeof(smatch[0]));
2524			size = sp-string;
2525			break;
2526		}
2527		sp--;
2528	}
2529	if(size==len)
2530		return(0);
2531	if(nmatch)
2532	{
2533		nmatch *=2;
2534		while(--nmatch>=0)
2535			match[nmatch] += size;
2536	}
2537	return(n);
2538}
2539
2540#if SHOPT_MULTIBYTE
2541	static char	*lastchar(const char *string, const char *endstring)
2542	{
2543		register char *str = (char*)string;
2544		register int c;
2545		mbinit();
2546		while(*str)
2547		{
2548			if((c=mbsize(str))<0)
2549				c = 1;
2550			if(str+c > endstring)
2551				break;
2552			str += c;
2553		}
2554		return(str);
2555	}
2556#endif /* SHOPT_MULTIBYTE */
2557static int	charlen(const char *string,int len)
2558{
2559	if(!string)
2560		return(0);
2561#if SHOPT_MULTIBYTE
2562	if(mbwide())
2563	{
2564		register const char *str = string, *strmax=string+len;
2565		register int n=0;
2566		mbinit();
2567		if(len>0)
2568		{
2569			while(str<strmax && mbchar(str))
2570				n++;
2571		}
2572		else while(mbchar(str))
2573			n++;
2574		return(n);
2575	}
2576	else
2577#endif /* SHOPT_MULTIBYTE */
2578	{
2579		if(len<0)
2580			return(strlen(string));
2581		return(len);
2582	}
2583}
2584
2585/*
2586 * This is the default tilde discipline function
2587 */
2588static int sh_btilde(int argc, char *argv[], Shbltin_t *context)
2589{
2590	Shell_t *shp = context->shp;
2591	char *cp = sh_tilde(shp,argv[1]);
2592	NOT_USED(argc);
2593	if(!cp)
2594		cp = argv[1];
2595	sfputr(sfstdout, cp, '\n');
2596	return(0);
2597}
2598
2599/*
2600 * <offset> is byte offset for beginning of tilde string
2601 */
2602static void tilde_expand2(Shell_t *shp, register int offset)
2603{
2604	char		shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1);
2605	Sfio_t		*iop, *save=sfstdout;
2606	Namval_t	*np;
2607	static int	beenhere=0;
2608	strcpy(shtilde,".sh.tilde");
2609	np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL);
2610	if(np && !beenhere)
2611	{
2612		beenhere = 1;
2613		sh_addbuiltin(shtilde,sh_btilde,0);
2614		nv_onattr(np,NV_EXPORT);
2615	}
2616	av[0] = ".sh.tilde";
2617	av[1] = &ptr[offset];
2618	av[2] = 0;
2619	iop = sftmp((IOBSIZE>PATH_MAX?IOBSIZE:PATH_MAX)+1);
2620	sfset(iop,SF_READ,0);
2621	sfstdout = iop;
2622	if(np)
2623		sh_fun(np, (Namval_t*)0, av);
2624	else
2625		sh_btilde(2, av, &shp->bltindata);
2626	sfstdout = save;
2627	stkset(shp->stk,ptr, offset);
2628	sfseek(iop,(Sfoff_t)0,SEEK_SET);
2629	sfset(iop,SF_READ,1);
2630	if(ptr = sfreserve(iop, SF_UNBOUND, -1))
2631	{
2632		Sfoff_t n = sfvalue(iop);
2633		while(ptr[n-1]=='\n')
2634			n--;
2635		if(n==1 && fcpeek(0)=='/' && ptr[n-1])
2636			n--;
2637		if(n)
2638			sfwrite(shp->stk,ptr,n);
2639	}
2640	else
2641		sfputr(shp->stk,av[1],0);
2642	sfclose(iop);
2643}
2644
2645/*
2646 * This routine is used to resolve ~ expansion.
2647 * A ~ by itself is replaced with the users login directory.
2648 * A ~- is replaced by the previous working directory in shell.
2649 * A ~+ is replaced by the present working directory in shell.
2650 * If ~name  is replaced with login directory of name.
2651 * If string doesn't start with ~ or ~... not found then 0 returned.
2652 */
2653
2654static char *sh_tilde(Shell_t *shp,register const char *string)
2655{
2656	register char		*cp;
2657	register int		c;
2658	register struct passwd	*pw;
2659	register Namval_t *np=0;
2660	static Dt_t *logins_tree;
2661	if(*string++!='~')
2662		return(NIL(char*));
2663	if((c = *string)==0)
2664	{
2665		if(!(cp=nv_getval(sh_scoped(shp,HOME))))
2666			cp = getlogin();
2667		return(cp);
2668	}
2669	if((c=='-' || c=='+') && string[1]==0)
2670	{
2671		if(c=='+')
2672			cp = nv_getval(sh_scoped(shp,PWDNOD));
2673		else
2674			cp = nv_getval(sh_scoped(shp,OLDPWDNOD));
2675		return(cp);
2676	}
2677#if _WINIX
2678	if(fcgetc(c)=='/')
2679	{
2680		char	*str;
2681		int	n=0,offset=staktell();
2682		stakputs(string);
2683		do
2684		{
2685			stakputc(c);
2686			n++;
2687		}
2688		while (fcgetc(c) && c!='/');
2689		stakputc(0);
2690		if(c)
2691			fcseek(-1);
2692		str = stakseek(offset);
2693		Skip = n;
2694		if(logins_tree && (np=nv_search(str,logins_tree,0)))
2695			return(nv_getval(np));
2696		if(pw = getpwnam(str))
2697		{
2698			string = str;
2699			goto skip;
2700		}
2701		Skip = 0;
2702	}
2703#endif /* _WINIX */
2704	if(logins_tree && (np=nv_search(string,logins_tree,0)))
2705		return(nv_getval(np));
2706	if(!(pw = getpwnam(string)))
2707		return(NIL(char*));
2708#if _WINIX
2709skip:
2710#endif /* _WINIX */
2711	if(!logins_tree)
2712		logins_tree = dtopen(&_Nvdisc,Dtbag);
2713	if(np=nv_search(string,logins_tree,NV_ADD))
2714	{
2715		c = shp->subshell;
2716		shp->subshell = 0;
2717		nv_putval(np, pw->pw_dir,0);
2718		shp->subshell = c;
2719	}
2720	return(pw->pw_dir);
2721}
2722
2723/*
2724 * return values for special macros
2725 */
2726static char *special(Shell_t *shp,register int c)
2727{
2728	if(c!='$')
2729		shp->argaddr = 0;
2730	switch(c)
2731	{
2732	    case '@':
2733	    case '*':
2734		return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*));
2735	    case '#':
2736#if  SHOPT_FILESCAN
2737		if(shp->cur_line)
2738		{
2739			getdolarg(shp,MAX_ARGN,(int*)0);
2740			return(ltos(shp->offsets[0]));
2741		}
2742#endif  /* SHOPT_FILESCAN */
2743		return(ltos(shp->st.dolc));
2744	    case '!':
2745		if(shp->bckpid)
2746#if SHOPT_COSHELL
2747			return(sh_pid2str(shp,shp->bckpid));
2748#else
2749			return(ltos(shp->bckpid));
2750#endif /* SHOPT_COSHELL */
2751		break;
2752	    case '$':
2753		if(nv_isnull(SH_DOLLARNOD))
2754			return(ltos(shp->gd->pid));
2755		return(nv_getval(SH_DOLLARNOD));
2756	    case '-':
2757		return(sh_argdolminus(shp->arg_context));
2758	    case '?':
2759		return(ltos(shp->savexit));
2760	    case 0:
2761		if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname)
2762			return(shp->shname);
2763		else
2764			return(shp->st.cmdname);
2765	}
2766	return(NIL(char*));
2767}
2768
2769/*
2770 * Handle macro expansion errors
2771 */
2772static void mac_error(Namval_t *np)
2773{
2774	if(np)
2775		nv_close(np);
2776	errormsg(SH_DICT,ERROR_exit(1),e_subst,fcfirst());
2777}
2778
2779/*
2780 * Given pattern/string, replace / with 0 and return pointer to string
2781 * \ characters are stripped from string.  The \ are stripped in the
2782 * replacement string unless followed by a digit or \.
2783 */
2784static char *mac_getstring(char *pattern)
2785{
2786	register char	*cp=pattern, *rep=0, *dp;
2787	register int	c;
2788	while(c = *cp++)
2789	{
2790		if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp))))
2791		{
2792			c = *cp++;
2793		}
2794		else if(!rep && c=='/')
2795		{
2796			cp[-1] = 0;
2797			rep = dp = cp;
2798			continue;
2799		}
2800		if(rep)
2801			*dp++ = c;
2802	}
2803	if(rep)
2804		*dp = 0;
2805	return(rep);
2806}
2807