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