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