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