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