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