xref: /netbsd-src/bin/sh/expand.c (revision 4b896b232495b7a9b8b94a1cf1e21873296d53b8)
1 /*	$NetBSD: expand.c,v 1.60 2003/12/21 08:32:39 jdolecek Exp $	*/
2 
3 /*-
4  * Copyright (c) 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)expand.c	8.5 (Berkeley) 5/15/95";
39 #else
40 __RCSID("$NetBSD: expand.c,v 1.60 2003/12/21 08:32:39 jdolecek Exp $");
41 #endif
42 #endif /* not lint */
43 
44 #include <sys/types.h>
45 #include <sys/time.h>
46 #include <sys/stat.h>
47 #include <errno.h>
48 #include <dirent.h>
49 #include <unistd.h>
50 #include <pwd.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 
54 /*
55  * Routines to expand arguments to commands.  We have to deal with
56  * backquotes, shell variables, and file metacharacters.
57  */
58 
59 #include "shell.h"
60 #include "main.h"
61 #include "nodes.h"
62 #include "eval.h"
63 #include "expand.h"
64 #include "syntax.h"
65 #include "parser.h"
66 #include "jobs.h"
67 #include "options.h"
68 #include "var.h"
69 #include "input.h"
70 #include "output.h"
71 #include "memalloc.h"
72 #include "error.h"
73 #include "mystring.h"
74 #include "show.h"
75 
76 /*
77  * Structure specifying which parts of the string should be searched
78  * for IFS characters.
79  */
80 
81 struct ifsregion {
82 	struct ifsregion *next;	/* next region in list */
83 	int begoff;		/* offset of start of region */
84 	int endoff;		/* offset of end of region */
85 	int nulonly;		/* search for nul bytes only */
86 };
87 
88 
89 char *expdest;			/* output of current string */
90 struct nodelist *argbackq;	/* list of back quote expressions */
91 struct ifsregion ifsfirst;	/* first struct in list of ifs regions */
92 struct ifsregion *ifslastp;	/* last struct in list */
93 struct arglist exparg;		/* holds expanded arg list */
94 
95 STATIC void argstr(char *, int);
96 STATIC char *exptilde(char *, int);
97 STATIC void expbackq(union node *, int, int);
98 STATIC int subevalvar(char *, char *, int, int, int, int);
99 STATIC char *evalvar(char *, int);
100 STATIC int varisset(char *, int);
101 STATIC void varvalue(char *, int, int, int);
102 STATIC void recordregion(int, int, int);
103 STATIC void removerecordregions(int);
104 STATIC void ifsbreakup(char *, struct arglist *);
105 STATIC void ifsfree(void);
106 STATIC void expandmeta(struct strlist *, int);
107 STATIC void expmeta(char *, char *);
108 STATIC void addfname(char *);
109 STATIC struct strlist *expsort(struct strlist *);
110 STATIC struct strlist *msort(struct strlist *, int);
111 STATIC int pmatch(char *, char *, int);
112 STATIC char *cvtnum(int, char *);
113 
114 /*
115  * Expand shell variables and backquotes inside a here document.
116  */
117 
118 void
119 expandhere(union node *arg, int fd)
120 {
121 	herefd = fd;
122 	expandarg(arg, (struct arglist *)NULL, 0);
123 	xwrite(fd, stackblock(), expdest - stackblock());
124 }
125 
126 
127 /*
128  * Perform variable substitution and command substitution on an argument,
129  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
130  * perform splitting and file name expansion.  When arglist is NULL, perform
131  * here document expansion.
132  */
133 
134 void
135 expandarg(union node *arg, struct arglist *arglist, int flag)
136 {
137 	struct strlist *sp;
138 	char *p;
139 
140 	argbackq = arg->narg.backquote;
141 	STARTSTACKSTR(expdest);
142 	ifsfirst.next = NULL;
143 	ifslastp = NULL;
144 	argstr(arg->narg.text, flag);
145 	if (arglist == NULL) {
146 		return;			/* here document expanded */
147 	}
148 	STPUTC('\0', expdest);
149 	p = grabstackstr(expdest);
150 	exparg.lastp = &exparg.list;
151 	/*
152 	 * TODO - EXP_REDIR
153 	 */
154 	if (flag & EXP_FULL) {
155 		ifsbreakup(p, &exparg);
156 		*exparg.lastp = NULL;
157 		exparg.lastp = &exparg.list;
158 		expandmeta(exparg.list, flag);
159 	} else {
160 		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
161 			rmescapes(p);
162 		sp = (struct strlist *)stalloc(sizeof (struct strlist));
163 		sp->text = p;
164 		*exparg.lastp = sp;
165 		exparg.lastp = &sp->next;
166 	}
167 	ifsfree();
168 	*exparg.lastp = NULL;
169 	if (exparg.list) {
170 		*arglist->lastp = exparg.list;
171 		arglist->lastp = exparg.lastp;
172 	}
173 }
174 
175 
176 
177 /*
178  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
179  * characters to allow for further processing.  Otherwise treat
180  * $@ like $* since no splitting will be performed.
181  */
182 
183 STATIC void
184 argstr(char *p, int flag)
185 {
186 	char c;
187 	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */
188 	int firsteq = 1;
189 
190 	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
191 		p = exptilde(p, flag);
192 	for (;;) {
193 		switch (c = *p++) {
194 		case '\0':
195 		case CTLENDVAR: /* ??? */
196 			goto breakloop;
197 		case CTLQUOTEMARK:
198 			/* "$@" syntax adherence hack */
199 			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
200 				break;
201 			if ((flag & EXP_FULL) != 0)
202 				STPUTC(c, expdest);
203 			break;
204 		case CTLESC:
205 			if (quotes)
206 				STPUTC(c, expdest);
207 			c = *p++;
208 			STPUTC(c, expdest);
209 			break;
210 		case CTLVAR:
211 			p = evalvar(p, flag);
212 			break;
213 		case CTLBACKQ:
214 		case CTLBACKQ|CTLQUOTE:
215 			expbackq(argbackq->n, c & CTLQUOTE, flag);
216 			argbackq = argbackq->next;
217 			break;
218 		case CTLENDARI:
219 			expari(flag);
220 			break;
221 		case ':':
222 		case '=':
223 			/*
224 			 * sort of a hack - expand tildes in variable
225 			 * assignments (after the first '=' and after ':'s).
226 			 */
227 			STPUTC(c, expdest);
228 			if (flag & EXP_VARTILDE && *p == '~') {
229 				if (c == '=') {
230 					if (firsteq)
231 						firsteq = 0;
232 					else
233 						break;
234 				}
235 				p = exptilde(p, flag);
236 			}
237 			break;
238 		default:
239 			STPUTC(c, expdest);
240 		}
241 	}
242 breakloop:;
243 	return;
244 }
245 
246 STATIC char *
247 exptilde(char *p, int flag)
248 {
249 	char c, *startp = p;
250 	struct passwd *pw;
251 	const char *home;
252 	int quotes = flag & (EXP_FULL | EXP_CASE);
253 
254 	while ((c = *p) != '\0') {
255 		switch(c) {
256 		case CTLESC:
257 			return (startp);
258 		case CTLQUOTEMARK:
259 			return (startp);
260 		case ':':
261 			if (flag & EXP_VARTILDE)
262 				goto done;
263 			break;
264 		case '/':
265 			goto done;
266 		}
267 		p++;
268 	}
269 done:
270 	*p = '\0';
271 	if (*(startp+1) == '\0') {
272 		if ((home = lookupvar("HOME")) == NULL)
273 			goto lose;
274 	} else {
275 		if ((pw = getpwnam(startp+1)) == NULL)
276 			goto lose;
277 		home = pw->pw_dir;
278 	}
279 	if (*home == '\0')
280 		goto lose;
281 	*p = c;
282 	while ((c = *home++) != '\0') {
283 		if (quotes && SQSYNTAX[(int)c] == CCTL)
284 			STPUTC(CTLESC, expdest);
285 		STPUTC(c, expdest);
286 	}
287 	return (p);
288 lose:
289 	*p = c;
290 	return (startp);
291 }
292 
293 
294 STATIC void
295 removerecordregions(int endoff)
296 {
297 	if (ifslastp == NULL)
298 		return;
299 
300 	if (ifsfirst.endoff > endoff) {
301 		while (ifsfirst.next != NULL) {
302 			struct ifsregion *ifsp;
303 			INTOFF;
304 			ifsp = ifsfirst.next->next;
305 			ckfree(ifsfirst.next);
306 			ifsfirst.next = ifsp;
307 			INTON;
308 		}
309 		if (ifsfirst.begoff > endoff)
310 			ifslastp = NULL;
311 		else {
312 			ifslastp = &ifsfirst;
313 			ifsfirst.endoff = endoff;
314 		}
315 		return;
316 	}
317 
318 	ifslastp = &ifsfirst;
319 	while (ifslastp->next && ifslastp->next->begoff < endoff)
320 		ifslastp=ifslastp->next;
321 	while (ifslastp->next != NULL) {
322 		struct ifsregion *ifsp;
323 		INTOFF;
324 		ifsp = ifslastp->next->next;
325 		ckfree(ifslastp->next);
326 		ifslastp->next = ifsp;
327 		INTON;
328 	}
329 	if (ifslastp->endoff > endoff)
330 		ifslastp->endoff = endoff;
331 }
332 
333 
334 /*
335  * Expand arithmetic expression.  Backup to start of expression,
336  * evaluate, place result in (backed up) result, adjust string position.
337  */
338 void
339 expari(int flag)
340 {
341 	char *p, *start;
342 	int result;
343 	int begoff;
344 	int quotes = flag & (EXP_FULL | EXP_CASE);
345 	int quoted;
346 
347 	/*	ifsfree(); */
348 
349 	/*
350 	 * This routine is slightly over-complicated for
351 	 * efficiency.  First we make sure there is
352 	 * enough space for the result, which may be bigger
353 	 * than the expression if we add exponentation.  Next we
354 	 * scan backwards looking for the start of arithmetic.  If the
355 	 * next previous character is a CTLESC character, then we
356 	 * have to rescan starting from the beginning since CTLESC
357 	 * characters have to be processed left to right.
358 	 */
359 #if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
360 #error "integers with more than 10 digits are not supported"
361 #endif
362 	CHECKSTRSPACE(12 - 2, expdest);
363 	USTPUTC('\0', expdest);
364 	start = stackblock();
365 	p = expdest - 1;
366 	while (*p != CTLARI && p >= start)
367 		--p;
368 	if (*p != CTLARI)
369 		error("missing CTLARI (shouldn't happen)");
370 	if (p > start && *(p-1) == CTLESC)
371 		for (p = start; *p != CTLARI; p++)
372 			if (*p == CTLESC)
373 				p++;
374 
375 	if (p[1] == '"')
376 		quoted=1;
377 	else
378 		quoted=0;
379 	begoff = p - start;
380 	removerecordregions(begoff);
381 	if (quotes)
382 		rmescapes(p+2);
383 	result = arith(p+2);
384 	fmtstr(p, 12, "%d", result);
385 
386 	while (*p++)
387 		;
388 
389 	if (quoted == 0)
390 		recordregion(begoff, p - 1 - start, 0);
391 	result = expdest - p + 1;
392 	STADJUST(-result, expdest);
393 }
394 
395 
396 /*
397  * Expand stuff in backwards quotes.
398  */
399 
400 STATIC void
401 expbackq(union node *cmd, int quoted, int flag)
402 {
403 	struct backcmd in;
404 	int i;
405 	char buf[128];
406 	char *p;
407 	char *dest = expdest;
408 	struct ifsregion saveifs, *savelastp;
409 	struct nodelist *saveargbackq;
410 	char lastc;
411 	int startloc = dest - stackblock();
412 	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
413 	int saveherefd;
414 	int quotes = flag & (EXP_FULL | EXP_CASE);
415 
416 	INTOFF;
417 	saveifs = ifsfirst;
418 	savelastp = ifslastp;
419 	saveargbackq = argbackq;
420 	saveherefd = herefd;
421 	herefd = -1;
422 	p = grabstackstr(dest);
423 	evalbackcmd(cmd, &in);
424 	ungrabstackstr(p, dest);
425 	ifsfirst = saveifs;
426 	ifslastp = savelastp;
427 	argbackq = saveargbackq;
428 	herefd = saveherefd;
429 
430 	p = in.buf;
431 	lastc = '\0';
432 	for (;;) {
433 		if (--in.nleft < 0) {
434 			if (in.fd < 0)
435 				break;
436 			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
437 			TRACE(("expbackq: read returns %d\n", i));
438 			if (i <= 0)
439 				break;
440 			p = buf;
441 			in.nleft = i - 1;
442 		}
443 		lastc = *p++;
444 		if (lastc != '\0') {
445 			if (quotes && syntax[(int)lastc] == CCTL)
446 				STPUTC(CTLESC, dest);
447 			STPUTC(lastc, dest);
448 		}
449 	}
450 
451 	/* Eat all trailing newlines */
452 	for (p--; lastc == '\n'; lastc = *--p)
453 		STUNPUTC(dest);
454 
455 	if (in.fd >= 0)
456 		close(in.fd);
457 	if (in.buf)
458 		ckfree(in.buf);
459 	if (in.jp)
460 		back_exitstatus = waitforjob(in.jp);
461 	if (quoted == 0)
462 		recordregion(startloc, dest - stackblock(), 0);
463 	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
464 		(dest - stackblock()) - startloc,
465 		(dest - stackblock()) - startloc,
466 		stackblock() + startloc));
467 	expdest = dest;
468 	INTON;
469 }
470 
471 
472 
473 STATIC int
474 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags)
475 {
476 	char *startp;
477 	char *loc = NULL;
478 	char *q;
479 	int c = 0;
480 	int saveherefd = herefd;
481 	struct nodelist *saveargbackq = argbackq;
482 	int amount;
483 
484 	herefd = -1;
485 	argstr(p, 0);
486 	STACKSTRNUL(expdest);
487 	herefd = saveherefd;
488 	argbackq = saveargbackq;
489 	startp = stackblock() + startloc;
490 	if (str == NULL)
491 	    str = stackblock() + strloc;
492 
493 	switch (subtype) {
494 	case VSASSIGN:
495 		setvar(str, startp, 0);
496 		amount = startp - expdest;
497 		STADJUST(amount, expdest);
498 		varflags &= ~VSNUL;
499 		if (c != 0)
500 			*loc = c;
501 		return 1;
502 
503 	case VSQUESTION:
504 		if (*p != CTLENDVAR) {
505 			outfmt(&errout, "%s\n", startp);
506 			error((char *)NULL);
507 		}
508 		error("%.*s: parameter %snot set", p - str - 1,
509 		      str, (varflags & VSNUL) ? "null or "
510 					      : nullstr);
511 		/* NOTREACHED */
512 
513 	case VSTRIMLEFT:
514 		for (loc = startp; loc < str; loc++) {
515 			c = *loc;
516 			*loc = '\0';
517 			if (patmatch(str, startp, varflags & VSQUOTE))
518 				goto recordleft;
519 			*loc = c;
520 			if ((varflags & VSQUOTE) && *loc == CTLESC)
521 			        loc++;
522 		}
523 		return 0;
524 
525 	case VSTRIMLEFTMAX:
526 		for (loc = str - 1; loc >= startp;) {
527 			c = *loc;
528 			*loc = '\0';
529 			if (patmatch(str, startp, varflags & VSQUOTE))
530 				goto recordleft;
531 			*loc = c;
532 			loc--;
533 			if ((varflags & VSQUOTE) && loc > startp &&
534 			    *(loc - 1) == CTLESC) {
535 				for (q = startp; q < loc; q++)
536 					if (*q == CTLESC)
537 						q++;
538 				if (q > loc)
539 					loc--;
540 			}
541 		}
542 		return 0;
543 
544 	case VSTRIMRIGHT:
545 	        for (loc = str - 1; loc >= startp;) {
546 			if (patmatch(str, loc, varflags & VSQUOTE))
547 				goto recordright;
548 			loc--;
549 			if ((varflags & VSQUOTE) && loc > startp &&
550 			    *(loc - 1) == CTLESC) {
551 				for (q = startp; q < loc; q++)
552 					if (*q == CTLESC)
553 						q++;
554 				if (q > loc)
555 					loc--;
556 			}
557 		}
558 		return 0;
559 
560 	case VSTRIMRIGHTMAX:
561 		for (loc = startp; loc < str - 1; loc++) {
562 			if (patmatch(str, loc, varflags & VSQUOTE))
563 				goto recordright;
564 			if ((varflags & VSQUOTE) && *loc == CTLESC)
565 			        loc++;
566 		}
567 		return 0;
568 
569 	default:
570 		abort();
571 	}
572 
573 recordleft:
574 	*loc = c;
575 	amount = ((str - 1) - (loc - startp)) - expdest;
576 	STADJUST(amount, expdest);
577 	while (loc != str - 1)
578 		*startp++ = *loc++;
579 	return 1;
580 
581 recordright:
582 	amount = loc - expdest;
583 	STADJUST(amount, expdest);
584 	STPUTC('\0', expdest);
585 	STADJUST(-1, expdest);
586 	return 1;
587 }
588 
589 
590 /*
591  * Expand a variable, and return a pointer to the next character in the
592  * input string.
593  */
594 
595 STATIC char *
596 evalvar(char *p, int flag)
597 {
598 	int subtype;
599 	int varflags;
600 	char *var;
601 	char *val;
602 	int patloc;
603 	int c;
604 	int set;
605 	int special;
606 	int startloc;
607 	int varlen;
608 	int easy;
609 	int quotes = flag & (EXP_FULL | EXP_CASE);
610 
611 	varflags = (unsigned char)*p++;
612 	subtype = varflags & VSTYPE;
613 	var = p;
614 	special = !is_name(*p);
615 	p = strchr(p, '=') + 1;
616 again: /* jump here after setting a variable with ${var=text} */
617 	if (special) {
618 		set = varisset(var, varflags & VSNUL);
619 		val = NULL;
620 	} else {
621 		val = lookupvar(var);
622 		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
623 			val = NULL;
624 			set = 0;
625 		} else
626 			set = 1;
627 	}
628 	varlen = 0;
629 	startloc = expdest - stackblock();
630 	if (!set && uflag)
631 		switch (subtype) {
632 		case VSNORMAL:
633 		case VSTRIMLEFT:
634 		case VSTRIMLEFTMAX:
635 		case VSTRIMRIGHT:
636 		case VSTRIMRIGHTMAX:
637 		case VSLENGTH:
638 			error("%.*s: parameter not set", p - var - 1, var);
639 			/* NOTREACHED */
640 		}
641 	if (set && subtype != VSPLUS) {
642 		/* insert the value of the variable */
643 		if (special) {
644 			varvalue(var, varflags & VSQUOTE, subtype, flag);
645 			if (subtype == VSLENGTH) {
646 				varlen = expdest - stackblock() - startloc;
647 				STADJUST(-varlen, expdest);
648 			}
649 		} else {
650 			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
651 								  : BASESYNTAX;
652 
653 			if (subtype == VSLENGTH) {
654 				for (;*val; val++)
655 					varlen++;
656 			}
657 			else {
658 				while (*val) {
659 					if (quotes && syntax[(int)*val] == CCTL)
660 						STPUTC(CTLESC, expdest);
661 					STPUTC(*val++, expdest);
662 				}
663 
664 			}
665 		}
666 	}
667 
668 	if (subtype == VSPLUS)
669 		set = ! set;
670 
671 	easy = ((varflags & VSQUOTE) == 0 ||
672 		(*var == '@' && shellparam.nparam != 1));
673 
674 
675 	switch (subtype) {
676 	case VSLENGTH:
677 		expdest = cvtnum(varlen, expdest);
678 		goto record;
679 
680 	case VSNORMAL:
681 		if (!easy)
682 			break;
683 record:
684 		recordregion(startloc, expdest - stackblock(),
685 			     varflags & VSQUOTE);
686 		break;
687 
688 	case VSPLUS:
689 	case VSMINUS:
690 		if (!set) {
691 		        argstr(p, flag);
692 			break;
693 		}
694 		if (easy)
695 			goto record;
696 		break;
697 
698 	case VSTRIMLEFT:
699 	case VSTRIMLEFTMAX:
700 	case VSTRIMRIGHT:
701 	case VSTRIMRIGHTMAX:
702 		if (!set)
703 			break;
704 		/*
705 		 * Terminate the string and start recording the pattern
706 		 * right after it
707 		 */
708 		STPUTC('\0', expdest);
709 		patloc = expdest - stackblock();
710 		if (subevalvar(p, NULL, patloc, subtype,
711 			       startloc, varflags) == 0) {
712 			int amount = (expdest - stackblock() - patloc) + 1;
713 			STADJUST(-amount, expdest);
714 		}
715 		/* Remove any recorded regions beyond start of variable */
716 		removerecordregions(startloc);
717 		goto record;
718 
719 	case VSASSIGN:
720 	case VSQUESTION:
721 		if (!set) {
722 			if (subevalvar(p, var, 0, subtype, startloc,
723 				       varflags)) {
724 				varflags &= ~VSNUL;
725 				/*
726 				 * Remove any recorded regions beyond
727 				 * start of variable
728 				 */
729 				removerecordregions(startloc);
730 				goto again;
731 			}
732 			break;
733 		}
734 		if (easy)
735 			goto record;
736 		break;
737 
738 	default:
739 		abort();
740 	}
741 
742 	if (subtype != VSNORMAL) {	/* skip to end of alternative */
743 		int nesting = 1;
744 		for (;;) {
745 			if ((c = *p++) == CTLESC)
746 				p++;
747 			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
748 				if (set)
749 					argbackq = argbackq->next;
750 			} else if (c == CTLVAR) {
751 				if ((*p++ & VSTYPE) != VSNORMAL)
752 					nesting++;
753 			} else if (c == CTLENDVAR) {
754 				if (--nesting == 0)
755 					break;
756 			}
757 		}
758 	}
759 	return p;
760 }
761 
762 
763 
764 /*
765  * Test whether a specialized variable is set.
766  */
767 
768 STATIC int
769 varisset(char *name, int nulok)
770 {
771 	if (*name == '!')
772 		return backgndpid != -1;
773 	else if (*name == '@' || *name == '*') {
774 		if (*shellparam.p == NULL)
775 			return 0;
776 
777 		if (nulok) {
778 			char **av;
779 
780 			for (av = shellparam.p; *av; av++)
781 				if (**av != '\0')
782 					return 1;
783 			return 0;
784 		}
785 	} else if (is_digit(*name)) {
786 		char *ap;
787 		int num = atoi(name);
788 
789 		if (num > shellparam.nparam)
790 			return 0;
791 
792 		if (num == 0)
793 			ap = arg0;
794 		else
795 			ap = shellparam.p[num - 1];
796 
797 		if (nulok && (ap == NULL || *ap == '\0'))
798 			return 0;
799 	}
800 	return 1;
801 }
802 
803 
804 
805 /*
806  * Add the value of a specialized variable to the stack string.
807  */
808 
809 STATIC void
810 varvalue(char *name, int quoted, int subtype, int flag)
811 {
812 	int num;
813 	char *p;
814 	int i;
815 	char sep;
816 	char **ap;
817 	char const *syntax;
818 
819 #define STRTODEST(p) \
820 	do {\
821 	if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
822 		syntax = quoted? DQSYNTAX : BASESYNTAX; \
823 		while (*p) { \
824 			if (syntax[(int)*p] == CCTL) \
825 				STPUTC(CTLESC, expdest); \
826 			STPUTC(*p++, expdest); \
827 		} \
828 	} else \
829 		while (*p) \
830 			STPUTC(*p++, expdest); \
831 	} while (0)
832 
833 
834 	switch (*name) {
835 	case '$':
836 		num = rootpid;
837 		goto numvar;
838 	case '?':
839 		num = exitstatus;
840 		goto numvar;
841 	case '#':
842 		num = shellparam.nparam;
843 		goto numvar;
844 	case '!':
845 		num = backgndpid;
846 numvar:
847 		expdest = cvtnum(num, expdest);
848 		break;
849 	case '-':
850 		for (i = 0; optlist[i].name; i++) {
851 			if (optlist[i].val)
852 				STPUTC(optlist[i].letter, expdest);
853 		}
854 		break;
855 	case '@':
856 		if (flag & EXP_FULL && quoted) {
857 			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
858 				STRTODEST(p);
859 				if (*ap)
860 					STPUTC('\0', expdest);
861 			}
862 			break;
863 		}
864 		/* fall through */
865 	case '*':
866 		if (ifsset() != 0)
867 			sep = ifsval()[0];
868 		else
869 			sep = ' ';
870 		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
871 			STRTODEST(p);
872 			if (*ap && sep)
873 				STPUTC(sep, expdest);
874 		}
875 		break;
876 	case '0':
877 		p = arg0;
878 		STRTODEST(p);
879 		break;
880 	default:
881 		if (is_digit(*name)) {
882 			num = atoi(name);
883 			if (num > 0 && num <= shellparam.nparam) {
884 				p = shellparam.p[num - 1];
885 				STRTODEST(p);
886 			}
887 		}
888 		break;
889 	}
890 }
891 
892 
893 
894 /*
895  * Record the fact that we have to scan this region of the
896  * string for IFS characters.
897  */
898 
899 STATIC void
900 recordregion(int start, int end, int nulonly)
901 {
902 	struct ifsregion *ifsp;
903 
904 	if (ifslastp == NULL) {
905 		ifsp = &ifsfirst;
906 	} else {
907 		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
908 		ifslastp->next = ifsp;
909 	}
910 	ifslastp = ifsp;
911 	ifslastp->next = NULL;
912 	ifslastp->begoff = start;
913 	ifslastp->endoff = end;
914 	ifslastp->nulonly = nulonly;
915 }
916 
917 
918 
919 /*
920  * Break the argument string into pieces based upon IFS and add the
921  * strings to the argument list.  The regions of the string to be
922  * searched for IFS characters have been stored by recordregion.
923  */
924 STATIC void
925 ifsbreakup(char *string, struct arglist *arglist)
926 {
927 	struct ifsregion *ifsp;
928 	struct strlist *sp;
929 	char *start;
930 	char *p;
931 	char *q;
932 	const char *ifs;
933 	int ifsspc;
934 	int nulonly;
935 
936 
937 	start = string;
938 	ifsspc = 0;
939 	nulonly = 0;
940 	if (ifslastp != NULL) {
941 		ifsp = &ifsfirst;
942 		do {
943 			p = string + ifsp->begoff;
944 			nulonly = ifsp->nulonly;
945 			ifs = nulonly ? nullstr :
946 				( ifsset() ? ifsval() : " \t\n" );
947 			ifsspc = 0;
948 			while (p < string + ifsp->endoff) {
949 				q = p;
950 				if (*p == CTLESC)
951 					p++;
952 				if (strchr(ifs, *p)) {
953 					if (!nulonly)
954 						ifsspc = (strchr(" \t\n", *p) != NULL);
955 					/* Ignore IFS whitespace at start */
956 					if (q == start && ifsspc) {
957 						p++;
958 						start = p;
959 						continue;
960 					}
961 					*q = '\0';
962 					sp = (struct strlist *)stalloc(sizeof *sp);
963 					sp->text = start;
964 					*arglist->lastp = sp;
965 					arglist->lastp = &sp->next;
966 					p++;
967 					if (!nulonly) {
968 						for (;;) {
969 							if (p >= string + ifsp->endoff) {
970 								break;
971 							}
972 							q = p;
973 							if (*p == CTLESC)
974 								p++;
975 							if (strchr(ifs, *p) == NULL ) {
976 								p = q;
977 								break;
978 							} else if (strchr(" \t\n",*p) == NULL) {
979 								if (ifsspc) {
980 									p++;
981 									ifsspc = 0;
982 								} else {
983 									p = q;
984 									break;
985 								}
986 							} else
987 								p++;
988 						}
989 					}
990 					start = p;
991 				} else
992 					p++;
993 			}
994 		} while ((ifsp = ifsp->next) != NULL);
995 		if (*start || (!ifsspc && start > string &&
996 			(nulonly || 1))) {
997 			sp = (struct strlist *)stalloc(sizeof *sp);
998 			sp->text = start;
999 			*arglist->lastp = sp;
1000 			arglist->lastp = &sp->next;
1001 		}
1002 	} else {
1003 		sp = (struct strlist *)stalloc(sizeof *sp);
1004 		sp->text = start;
1005 		*arglist->lastp = sp;
1006 		arglist->lastp = &sp->next;
1007 	}
1008 }
1009 
1010 STATIC void
1011 ifsfree(void)
1012 {
1013 	while (ifsfirst.next != NULL) {
1014 		struct ifsregion *ifsp;
1015 		INTOFF;
1016 		ifsp = ifsfirst.next->next;
1017 		ckfree(ifsfirst.next);
1018 		ifsfirst.next = ifsp;
1019 		INTON;
1020 	}
1021 	ifslastp = NULL;
1022 	ifsfirst.next = NULL;
1023 }
1024 
1025 
1026 
1027 /*
1028  * Expand shell metacharacters.  At this point, the only control characters
1029  * should be escapes.  The results are stored in the list exparg.
1030  */
1031 
1032 char *expdir;
1033 
1034 
1035 STATIC void
1036 expandmeta(struct strlist *str, int flag)
1037 {
1038 	char *p;
1039 	struct strlist **savelastp;
1040 	struct strlist *sp;
1041 	char c;
1042 	/* TODO - EXP_REDIR */
1043 
1044 	while (str) {
1045 		if (fflag)
1046 			goto nometa;
1047 		p = str->text;
1048 		for (;;) {			/* fast check for meta chars */
1049 			if ((c = *p++) == '\0')
1050 				goto nometa;
1051 			if (c == '*' || c == '?' || c == '[' || c == '!')
1052 				break;
1053 		}
1054 		savelastp = exparg.lastp;
1055 		INTOFF;
1056 		if (expdir == NULL) {
1057 			int i = strlen(str->text);
1058 			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
1059 		}
1060 
1061 		expmeta(expdir, str->text);
1062 		ckfree(expdir);
1063 		expdir = NULL;
1064 		INTON;
1065 		if (exparg.lastp == savelastp) {
1066 			/*
1067 			 * no matches
1068 			 */
1069 nometa:
1070 			*exparg.lastp = str;
1071 			rmescapes(str->text);
1072 			exparg.lastp = &str->next;
1073 		} else {
1074 			*exparg.lastp = NULL;
1075 			*savelastp = sp = expsort(*savelastp);
1076 			while (sp->next != NULL)
1077 				sp = sp->next;
1078 			exparg.lastp = &sp->next;
1079 		}
1080 		str = str->next;
1081 	}
1082 }
1083 
1084 
1085 /*
1086  * Do metacharacter (i.e. *, ?, [...]) expansion.
1087  */
1088 
1089 STATIC void
1090 expmeta(char *enddir, char *name)
1091 {
1092 	char *p;
1093 	const char *cp;
1094 	char *q;
1095 	char *start;
1096 	char *endname;
1097 	int metaflag;
1098 	struct stat statb;
1099 	DIR *dirp;
1100 	struct dirent *dp;
1101 	int atend;
1102 	int matchdot;
1103 
1104 	metaflag = 0;
1105 	start = name;
1106 	for (p = name ; ; p++) {
1107 		if (*p == '*' || *p == '?')
1108 			metaflag = 1;
1109 		else if (*p == '[') {
1110 			q = p + 1;
1111 			if (*q == '!')
1112 				q++;
1113 			for (;;) {
1114 				while (*q == CTLQUOTEMARK)
1115 					q++;
1116 				if (*q == CTLESC)
1117 					q++;
1118 				if (*q == '/' || *q == '\0')
1119 					break;
1120 				if (*++q == ']') {
1121 					metaflag = 1;
1122 					break;
1123 				}
1124 			}
1125 		} else if (*p == '!' && p[1] == '!'	&& (p == name || p[-1] == '/')) {
1126 			metaflag = 1;
1127 		} else if (*p == '\0')
1128 			break;
1129 		else if (*p == CTLQUOTEMARK)
1130 			continue;
1131 		else if (*p == CTLESC)
1132 			p++;
1133 		if (*p == '/') {
1134 			if (metaflag)
1135 				break;
1136 			start = p + 1;
1137 		}
1138 	}
1139 	if (metaflag == 0) {	/* we've reached the end of the file name */
1140 		if (enddir != expdir)
1141 			metaflag++;
1142 		for (p = name ; ; p++) {
1143 			if (*p == CTLQUOTEMARK)
1144 				continue;
1145 			if (*p == CTLESC)
1146 				p++;
1147 			*enddir++ = *p;
1148 			if (*p == '\0')
1149 				break;
1150 		}
1151 		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
1152 			addfname(expdir);
1153 		return;
1154 	}
1155 	endname = p;
1156 	if (start != name) {
1157 		p = name;
1158 		while (p < start) {
1159 			while (*p == CTLQUOTEMARK)
1160 				p++;
1161 			if (*p == CTLESC)
1162 				p++;
1163 			*enddir++ = *p++;
1164 		}
1165 	}
1166 	if (enddir == expdir) {
1167 		cp = ".";
1168 	} else if (enddir == expdir + 1 && *expdir == '/') {
1169 		cp = "/";
1170 	} else {
1171 		cp = expdir;
1172 		enddir[-1] = '\0';
1173 	}
1174 	if ((dirp = opendir(cp)) == NULL)
1175 		return;
1176 	if (enddir != expdir)
1177 		enddir[-1] = '/';
1178 	if (*endname == 0) {
1179 		atend = 1;
1180 	} else {
1181 		atend = 0;
1182 		*endname++ = '\0';
1183 	}
1184 	matchdot = 0;
1185 	p = start;
1186 	while (*p == CTLQUOTEMARK)
1187 		p++;
1188 	if (*p == CTLESC)
1189 		p++;
1190 	if (*p == '.')
1191 		matchdot++;
1192 	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1193 		if (dp->d_name[0] == '.' && ! matchdot)
1194 			continue;
1195 		if (patmatch(start, dp->d_name, 0)) {
1196 			if (atend) {
1197 				scopy(dp->d_name, enddir);
1198 				addfname(expdir);
1199 			} else {
1200 				for (p = enddir, cp = dp->d_name;
1201 				     (*p++ = *cp++) != '\0';)
1202 					continue;
1203 				p[-1] = '/';
1204 				expmeta(p, endname);
1205 			}
1206 		}
1207 	}
1208 	closedir(dirp);
1209 	if (! atend)
1210 		endname[-1] = '/';
1211 }
1212 
1213 
1214 /*
1215  * Add a file name to the list.
1216  */
1217 
1218 STATIC void
1219 addfname(char *name)
1220 {
1221 	char *p;
1222 	struct strlist *sp;
1223 
1224 	p = stalloc(strlen(name) + 1);
1225 	scopy(name, p);
1226 	sp = (struct strlist *)stalloc(sizeof *sp);
1227 	sp->text = p;
1228 	*exparg.lastp = sp;
1229 	exparg.lastp = &sp->next;
1230 }
1231 
1232 
1233 /*
1234  * Sort the results of file name expansion.  It calculates the number of
1235  * strings to sort and then calls msort (short for merge sort) to do the
1236  * work.
1237  */
1238 
1239 STATIC struct strlist *
1240 expsort(struct strlist *str)
1241 {
1242 	int len;
1243 	struct strlist *sp;
1244 
1245 	len = 0;
1246 	for (sp = str ; sp ; sp = sp->next)
1247 		len++;
1248 	return msort(str, len);
1249 }
1250 
1251 
1252 STATIC struct strlist *
1253 msort(struct strlist *list, int len)
1254 {
1255 	struct strlist *p, *q = NULL;
1256 	struct strlist **lpp;
1257 	int half;
1258 	int n;
1259 
1260 	if (len <= 1)
1261 		return list;
1262 	half = len >> 1;
1263 	p = list;
1264 	for (n = half ; --n >= 0 ; ) {
1265 		q = p;
1266 		p = p->next;
1267 	}
1268 	q->next = NULL;			/* terminate first half of list */
1269 	q = msort(list, half);		/* sort first half of list */
1270 	p = msort(p, len - half);		/* sort second half */
1271 	lpp = &list;
1272 	for (;;) {
1273 		if (strcmp(p->text, q->text) < 0) {
1274 			*lpp = p;
1275 			lpp = &p->next;
1276 			if ((p = *lpp) == NULL) {
1277 				*lpp = q;
1278 				break;
1279 			}
1280 		} else {
1281 			*lpp = q;
1282 			lpp = &q->next;
1283 			if ((q = *lpp) == NULL) {
1284 				*lpp = p;
1285 				break;
1286 			}
1287 		}
1288 	}
1289 	return list;
1290 }
1291 
1292 
1293 
1294 /*
1295  * Returns true if the pattern matches the string.
1296  */
1297 
1298 int
1299 patmatch(char *pattern, char *string, int squoted)
1300 {
1301 #ifdef notdef
1302 	if (pattern[0] == '!' && pattern[1] == '!')
1303 		return 1 - pmatch(pattern + 2, string);
1304 	else
1305 #endif
1306 		return pmatch(pattern, string, squoted);
1307 }
1308 
1309 
1310 STATIC int
1311 pmatch(char *pattern, char *string, int squoted)
1312 {
1313 	char *p, *q;
1314 	char c;
1315 
1316 	p = pattern;
1317 	q = string;
1318 	for (;;) {
1319 		switch (c = *p++) {
1320 		case '\0':
1321 			goto breakloop;
1322 		case CTLESC:
1323 			if (squoted && *q == CTLESC)
1324 				q++;
1325 			if (*q++ != *p++)
1326 				return 0;
1327 			break;
1328 		case CTLQUOTEMARK:
1329 			continue;
1330 		case '?':
1331 			if (squoted && *q == CTLESC)
1332 				q++;
1333 			if (*q++ == '\0')
1334 				return 0;
1335 			break;
1336 		case '*':
1337 			c = *p;
1338 			while (c == CTLQUOTEMARK || c == '*')
1339 				c = *++p;
1340 			if (c != CTLESC &&  c != CTLQUOTEMARK &&
1341 			    c != '?' && c != '*' && c != '[') {
1342 				while (*q != c) {
1343 					if (squoted && *q == CTLESC &&
1344 					    q[1] == c)
1345 						break;
1346 					if (*q == '\0')
1347 						return 0;
1348 					if (squoted && *q == CTLESC)
1349 						q++;
1350 					q++;
1351 				}
1352 			}
1353 			do {
1354 				if (pmatch(p, q, squoted))
1355 					return 1;
1356 				if (squoted && *q == CTLESC)
1357 					q++;
1358 			} while (*q++ != '\0');
1359 			return 0;
1360 		case '[': {
1361 			char *endp;
1362 			int invert, found;
1363 			char chr;
1364 
1365 			endp = p;
1366 			if (*endp == '!')
1367 				endp++;
1368 			for (;;) {
1369 				while (*endp == CTLQUOTEMARK)
1370 					endp++;
1371 				if (*endp == '\0')
1372 					goto dft;		/* no matching ] */
1373 				if (*endp == CTLESC)
1374 					endp++;
1375 				if (*++endp == ']')
1376 					break;
1377 			}
1378 			invert = 0;
1379 			if (*p == '!') {
1380 				invert++;
1381 				p++;
1382 			}
1383 			found = 0;
1384 			chr = *q++;
1385 			if (squoted && chr == CTLESC)
1386 				chr = *q++;
1387 			if (chr == '\0')
1388 				return 0;
1389 			c = *p++;
1390 			do {
1391 				if (c == CTLQUOTEMARK)
1392 					continue;
1393 				if (c == CTLESC)
1394 					c = *p++;
1395 				if (*p == '-' && p[1] != ']') {
1396 					p++;
1397 					while (*p == CTLQUOTEMARK)
1398 						p++;
1399 					if (*p == CTLESC)
1400 						p++;
1401 					if (chr >= c && chr <= *p)
1402 						found = 1;
1403 					p++;
1404 				} else {
1405 					if (chr == c)
1406 						found = 1;
1407 				}
1408 			} while ((c = *p++) != ']');
1409 			if (found == invert)
1410 				return 0;
1411 			break;
1412 		}
1413 dft:	        default:
1414 			if (squoted && *q == CTLESC)
1415 				q++;
1416 			if (*q++ != c)
1417 				return 0;
1418 			break;
1419 		}
1420 	}
1421 breakloop:
1422 	if (*q != '\0')
1423 		return 0;
1424 	return 1;
1425 }
1426 
1427 
1428 
1429 /*
1430  * Remove any CTLESC characters from a string.
1431  */
1432 
1433 void
1434 rmescapes(char *str)
1435 {
1436 	char *p, *q;
1437 
1438 	p = str;
1439 	while (*p != CTLESC && *p != CTLQUOTEMARK) {
1440 		if (*p++ == '\0')
1441 			return;
1442 	}
1443 	q = p;
1444 	while (*p) {
1445 		if (*p == CTLQUOTEMARK) {
1446 			p++;
1447 			continue;
1448 		}
1449 		if (*p == CTLESC)
1450 			p++;
1451 		*q++ = *p++;
1452 	}
1453 	*q = '\0';
1454 }
1455 
1456 
1457 
1458 /*
1459  * See if a pattern matches in a case statement.
1460  */
1461 
1462 int
1463 casematch(union node *pattern, char *val)
1464 {
1465 	struct stackmark smark;
1466 	int result;
1467 	char *p;
1468 
1469 	setstackmark(&smark);
1470 	argbackq = pattern->narg.backquote;
1471 	STARTSTACKSTR(expdest);
1472 	ifslastp = NULL;
1473 	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1474 	STPUTC('\0', expdest);
1475 	p = grabstackstr(expdest);
1476 	result = patmatch(p, val, 0);
1477 	popstackmark(&smark);
1478 	return result;
1479 }
1480 
1481 /*
1482  * Our own itoa().
1483  */
1484 
1485 STATIC char *
1486 cvtnum(int num, char *buf)
1487 {
1488 	char temp[32];
1489 	int neg = num < 0;
1490 	char *p = temp + 31;
1491 
1492 	temp[31] = '\0';
1493 
1494 	do {
1495 		*--p = num % 10 + '0';
1496 	} while ((num /= 10) != 0);
1497 
1498 	if (neg)
1499 		*--p = '-';
1500 
1501 	while (*p)
1502 		STPUTC(*p++, buf);
1503 	return buf;
1504 }
1505