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