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