xref: /netbsd-src/bin/sh/expand.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: expand.c,v 1.29 1997/03/18 18:54:40 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.5 (Berkeley) 5/15/95";
42 #else
43 static char rcsid[] = "$NetBSD: expand.c,v 1.29 1997/03/18 18:54:40 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, int));
102 STATIC char *evalvar __P((char *, int));
103 STATIC int varisset __P((char *, int));
104 STATIC void varvalue __P((char *, 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 	char *p;
199 	int flag;
200 {
201 	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 	while (ifsfirst.next != NULL) {
314 		struct ifsregion *ifsp;
315 		INTOFF;
316 		ifsp = ifsfirst.next->next;
317 		ckfree(ifsfirst.next);
318 		ifsfirst.next = ifsp;
319 		INTON;
320 	}
321 	ifslastp = NULL;
322 
323 	/*
324 	 * This routine is slightly over-compilcated for
325 	 * efficiency.  First we make sure there is
326 	 * enough space for the result, which may be bigger
327 	 * than the expression if we add exponentation.  Next we
328 	 * scan backwards looking for the start of arithmetic.  If the
329 	 * next previous character is a CTLESC character, then we
330 	 * have to rescan starting from the beginning since CTLESC
331 	 * characters have to be processed left to right.
332 	 */
333 	CHECKSTRSPACE(8, expdest);
334 	USTPUTC('\0', expdest);
335 	start = stackblock();
336 	p = expdest;
337 	while (*p != CTLARI && p >= start)
338 		--p;
339 	if (*p != CTLARI)
340 		error("missing CTLARI (shouldn't happen)");
341 	if (p > start && *(p-1) == CTLESC)
342 		for (p = start; *p != CTLARI; p++)
343 			if (*p == CTLESC)
344 				p++;
345 	if (quotes)
346 		rmescapes(p+1);
347 	result = arith(p+1);
348 	fmtstr(p, 10, "%d", result);
349 
350 	while (*p++)
351 		;
352 
353 	result = expdest - p + 1;
354 	STADJUST(-result, expdest);
355 }
356 
357 
358 /*
359  * Expand stuff in backwards quotes.
360  */
361 
362 STATIC void
363 expbackq(cmd, quoted, flag)
364 	union node *cmd;
365 	int quoted;
366 	int flag;
367 {
368 	struct backcmd in;
369 	int i;
370 	char buf[128];
371 	char *p;
372 	char *dest = expdest;
373 	struct ifsregion saveifs, *savelastp;
374 	struct nodelist *saveargbackq;
375 	char lastc;
376 	int startloc = dest - stackblock();
377 	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
378 	int saveherefd;
379 	int quotes = flag & (EXP_FULL | EXP_CASE);
380 
381 	INTOFF;
382 	saveifs = ifsfirst;
383 	savelastp = ifslastp;
384 	saveargbackq = argbackq;
385 	saveherefd = herefd;
386 	herefd = -1;
387 	p = grabstackstr(dest);
388 	evalbackcmd(cmd, &in);
389 	ungrabstackstr(p, dest);
390 	ifsfirst = saveifs;
391 	ifslastp = savelastp;
392 	argbackq = saveargbackq;
393 	herefd = saveherefd;
394 
395 	p = in.buf;
396 	lastc = '\0';
397 	for (;;) {
398 		if (--in.nleft < 0) {
399 			if (in.fd < 0)
400 				break;
401 			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
402 			TRACE(("expbackq: read returns %d\n", i));
403 			if (i <= 0)
404 				break;
405 			p = buf;
406 			in.nleft = i - 1;
407 		}
408 		lastc = *p++;
409 		if (lastc != '\0') {
410 			if (quotes && syntax[lastc] == CCTL)
411 				STPUTC(CTLESC, dest);
412 			STPUTC(lastc, dest);
413 		}
414 	}
415 
416 	/* Eat all trailing newlines */
417 	for (p--; lastc == '\n'; lastc = *--p)
418 		STUNPUTC(dest);
419 
420 	if (in.fd >= 0)
421 		close(in.fd);
422 	if (in.buf)
423 		ckfree(in.buf);
424 	if (in.jp)
425 		exitstatus = waitforjob(in.jp);
426 	if (quoted == 0)
427 		recordregion(startloc, dest - stackblock(), 0);
428 	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
429 		(dest - stackblock()) - startloc,
430 		(dest - stackblock()) - startloc,
431 		stackblock() + startloc));
432 	expdest = dest;
433 	INTON;
434 }
435 
436 
437 
438 STATIC int
439 subevalvar(p, str, strloc, subtype, startloc, varflags)
440 	char *p;
441 	char *str;
442 	int strloc;
443 	int subtype;
444 	int startloc;
445 	int varflags;
446 {
447 	char *startp;
448 	char *loc = NULL;
449 	int c = 0;
450 	int saveherefd = herefd;
451 	struct nodelist *saveargbackq = argbackq;
452 	int amount;
453 
454 	herefd = -1;
455 	argstr(p, 0);
456 	STACKSTRNUL(expdest);
457 	herefd = saveherefd;
458 	argbackq = saveargbackq;
459 	startp = stackblock() + startloc;
460 	if (str == NULL)
461 	    str = stackblock() + strloc;
462 
463 	switch (subtype) {
464 	case VSASSIGN:
465 		setvar(str, startp, 0);
466 		amount = startp - expdest;
467 		STADJUST(amount, expdest);
468 		varflags &= ~VSNUL;
469 		if (c != 0)
470 			*loc = c;
471 		return 1;
472 
473 	case VSQUESTION:
474 		if (*p != CTLENDVAR) {
475 			outfmt(&errout, "%s\n", startp);
476 			error((char *)NULL);
477 		}
478 		error("%.*s: parameter %snot set", p - str - 1,
479 		      str, (varflags & VSNUL) ? "null or "
480 					      : nullstr);
481 		return 0;
482 
483 	case VSTRIMLEFT:
484 		for (loc = startp; loc < str; loc++) {
485 			c = *loc;
486 			*loc = '\0';
487 			if (patmatch(str, startp)) {
488 				*loc = c;
489 				goto recordleft;
490 			}
491 			*loc = c;
492 		}
493 		return 0;
494 
495 	case VSTRIMLEFTMAX:
496 		for (loc = str - 1; loc >= startp; loc--) {
497 			c = *loc;
498 			*loc = '\0';
499 			if (patmatch(str, startp)) {
500 				*loc = c;
501 				goto recordleft;
502 			}
503 			*loc = c;
504 		}
505 		return 0;
506 
507 	case VSTRIMRIGHT:
508 		for (loc = str - 1; loc >= startp; loc--) {
509 			if (patmatch(str, loc)) {
510 				amount = loc - expdest;
511 				STADJUST(amount, expdest);
512 				return 1;
513 			}
514 		}
515 		return 0;
516 
517 	case VSTRIMRIGHTMAX:
518 		for (loc = startp; loc < str - 1; loc++) {
519 			if (patmatch(str, loc)) {
520 				amount = loc - expdest;
521 				STADJUST(amount, expdest);
522 				return 1;
523 			}
524 		}
525 		return 0;
526 
527 
528 	default:
529 		abort();
530 	}
531 
532 recordleft:
533 	amount = ((str - 1) - (loc - startp)) - expdest;
534 	STADJUST(amount, expdest);
535 	while (loc != str - 1)
536 		*startp++ = *loc++;
537 	return 1;
538 }
539 
540 
541 /*
542  * Expand a variable, and return a pointer to the next character in the
543  * input string.
544  */
545 
546 STATIC char *
547 evalvar(p, flag)
548 	char *p;
549 	int flag;
550 {
551 	int subtype;
552 	int varflags;
553 	char *var;
554 	char *val;
555 	char *pat;
556 	int c;
557 	int set;
558 	int special;
559 	int startloc;
560 	int varlen;
561 	int easy;
562 	int quotes = flag & (EXP_FULL | EXP_CASE);
563 
564 	varflags = *p++;
565 	subtype = varflags & VSTYPE;
566 	var = p;
567 	special = 0;
568 	if (! is_name(*p))
569 		special = 1;
570 	p = strchr(p, '=') + 1;
571 again: /* jump here after setting a variable with ${var=text} */
572 	if (special) {
573 		set = varisset(var, varflags & VSNUL);
574 		val = NULL;
575 	} else {
576 		val = lookupvar(var);
577 		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
578 			val = NULL;
579 			set = 0;
580 		} else
581 			set = 1;
582 	}
583 	varlen = 0;
584 	startloc = expdest - stackblock();
585 	if (set && subtype != VSPLUS) {
586 		/* insert the value of the variable */
587 		if (special) {
588 			varvalue(var, varflags & VSQUOTE, flag & EXP_FULL);
589 			if (subtype == VSLENGTH) {
590 				varlen = expdest - stackblock() - startloc;
591 				STADJUST(-varlen, expdest);
592 			}
593 		} else {
594 			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
595 								  : BASESYNTAX;
596 
597 			if (subtype == VSLENGTH) {
598 				for (;*val; val++)
599 					varlen++;
600 			}
601 			else {
602 				while (*val) {
603 					if (quotes && syntax[*val] == CCTL)
604 						STPUTC(CTLESC, expdest);
605 					STPUTC(*val++, expdest);
606 				}
607 
608 			}
609 		}
610 	}
611 
612 	if (subtype == VSPLUS)
613 		set = ! set;
614 
615 	easy = ((varflags & VSQUOTE) == 0 ||
616 		(*var == '@' && shellparam.nparam != 1));
617 
618 
619 	switch (subtype) {
620 	case VSLENGTH:
621 		expdest = cvtnum(varlen, expdest);
622 		goto record;
623 
624 	case VSNORMAL:
625 		if (!easy)
626 			break;
627 record:
628 		recordregion(startloc, expdest - stackblock(),
629 			     varflags & VSQUOTE);
630 		break;
631 
632 	case VSPLUS:
633 	case VSMINUS:
634 		if (!set) {
635 			argstr(p, flag);
636 			break;
637 		}
638 		if (easy)
639 			goto record;
640 		break;
641 
642 	case VSTRIMLEFT:
643 	case VSTRIMLEFTMAX:
644 	case VSTRIMRIGHT:
645 	case VSTRIMRIGHTMAX:
646 		if (!set)
647 			break;
648 		/*
649 		 * Terminate the string and start recording the pattern
650 		 * right after it
651 		 */
652 		STPUTC('\0', expdest);
653 		pat = expdest;
654 		if (subevalvar(p, NULL, expdest - stackblock(), subtype,
655 			       startloc, varflags))
656 			goto record;
657 		else {
658 			int amount = (expdest - pat) + 1;
659 			STADJUST(-amount, expdest);
660 		}
661 		break;
662 
663 	case VSASSIGN:
664 	case VSQUESTION:
665 		if (!set) {
666 			if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
667 				varflags &= ~VSNUL;
668 				goto again;
669 			}
670 			break;
671 		}
672 		if (easy)
673 			goto record;
674 		break;
675 
676 	default:
677 		abort();
678 	}
679 
680 	if (subtype != VSNORMAL) {	/* skip to end of alternative */
681 		int nesting = 1;
682 		for (;;) {
683 			if ((c = *p++) == CTLESC)
684 				p++;
685 			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
686 				if (set)
687 					argbackq = argbackq->next;
688 			} else if (c == CTLVAR) {
689 				if ((*p++ & VSTYPE) != VSNORMAL)
690 					nesting++;
691 			} else if (c == CTLENDVAR) {
692 				if (--nesting == 0)
693 					break;
694 			}
695 		}
696 	}
697 	return p;
698 }
699 
700 
701 
702 /*
703  * Test whether a specialized variable is set.
704  */
705 
706 STATIC int
707 varisset(name, nulok)
708 	char *name;
709 	int nulok;
710 {
711 	if (*name == '!')
712 		return backgndpid != -1;
713 	else if (*name == '@' || *name == '*') {
714 		if (*shellparam.p == NULL)
715 			return 0;
716 
717 		if (nulok) {
718 			char **av;
719 
720 			for (av = shellparam.p; *av; av++)
721 				if (**av != '\0')
722 					return 1;
723 			return 0;
724 		}
725 	} else if (is_digit(*name)) {
726 		char *ap;
727 		int num = atoi(name);
728 
729 		if (num > shellparam.nparam)
730 			return 0;
731 
732 		if (num == 0)
733 			ap = arg0;
734 		else
735 			ap = shellparam.p[num - 1];
736 
737 		if (nulok && (ap == NULL || *ap == '\0'))
738 			return 0;
739 	}
740 	return 1;
741 }
742 
743 
744 
745 /*
746  * Add the value of a specialized variable to the stack string.
747  */
748 
749 STATIC void
750 varvalue(name, quoted, allow_split)
751 	char *name;
752 	int quoted;
753 	int allow_split;
754 {
755 	int num;
756 	char *p;
757 	int i;
758 	extern int oexitstatus;
759 	char sep;
760 	char **ap;
761 	char const *syntax;
762 
763 #define STRTODEST(p) \
764 	do {\
765 	if (allow_split) { \
766 		syntax = quoted? DQSYNTAX : BASESYNTAX; \
767 		while (*p) { \
768 			if (syntax[*p] == CCTL) \
769 				STPUTC(CTLESC, expdest); \
770 			STPUTC(*p++, expdest); \
771 		} \
772 	} else \
773 		while (*p) \
774 			STPUTC(*p++, expdest); \
775 	} while (0)
776 
777 
778 	switch (*name) {
779 	case '$':
780 		num = rootpid;
781 		goto numvar;
782 	case '?':
783 		num = oexitstatus;
784 		goto numvar;
785 	case '#':
786 		num = shellparam.nparam;
787 		goto numvar;
788 	case '!':
789 		num = backgndpid;
790 numvar:
791 		expdest = cvtnum(num, expdest);
792 		break;
793 	case '-':
794 		for (i = 0 ; i < NOPTS ; i++) {
795 			if (optlist[i].val)
796 				STPUTC(optlist[i].letter, expdest);
797 		}
798 		break;
799 	case '@':
800 		if (allow_split) {
801 			sep = '\0';
802 			goto allargs;
803 		}
804 		/* fall through */
805 	case '*':
806 		sep = ' ';
807 allargs:
808 		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
809 			STRTODEST(p);
810 			if (*ap)
811 				STPUTC(sep, expdest);
812 		}
813 		break;
814 	case '0':
815 		p = arg0;
816 		STRTODEST(p);
817 		break;
818 	default:
819 		if (is_digit(*name)) {
820 			num = atoi(name);
821 			if (num > 0 && num <= shellparam.nparam) {
822 				p = shellparam.p[num - 1];
823 				STRTODEST(p);
824 			}
825 		}
826 		break;
827 	}
828 }
829 
830 
831 
832 /*
833  * Record the the fact that we have to scan this region of the
834  * string for IFS characters.
835  */
836 
837 STATIC void
838 recordregion(start, end, nulonly)
839 	int start;
840 	int end;
841 	int nulonly;
842 {
843 	struct ifsregion *ifsp;
844 
845 	if (ifslastp == NULL) {
846 		ifsp = &ifsfirst;
847 	} else {
848 		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
849 		ifslastp->next = ifsp;
850 	}
851 	ifslastp = ifsp;
852 	ifslastp->next = NULL;
853 	ifslastp->begoff = start;
854 	ifslastp->endoff = end;
855 	ifslastp->nulonly = nulonly;
856 }
857 
858 
859 
860 /*
861  * Break the argument string into pieces based upon IFS and add the
862  * strings to the argument list.  The regions of the string to be
863  * searched for IFS characters have been stored by recordregion.
864  */
865 STATIC void
866 ifsbreakup(string, arglist)
867 	char *string;
868 	struct arglist *arglist;
869 	{
870 	struct ifsregion *ifsp;
871 	struct strlist *sp;
872 	char *start;
873 	char *p;
874 	char *q;
875 	char *ifs;
876 	int ifsspc;
877 
878 
879 	start = string;
880 	if (ifslastp != NULL) {
881 		ifsp = &ifsfirst;
882 		do {
883 			p = string + ifsp->begoff;
884 			ifs = ifsp->nulonly? nullstr : ifsval();
885 			ifsspc = strchr(ifs, ' ') != NULL;
886 			while (p < string + ifsp->endoff) {
887 				q = p;
888 				if (*p == CTLESC)
889 					p++;
890 				if (strchr(ifs, *p++)) {
891 					if (q > start || !ifsspc) {
892 						*q = '\0';
893 						sp = (struct strlist *)stalloc(sizeof *sp);
894 						sp->text = start;
895 						*arglist->lastp = sp;
896 						arglist->lastp = &sp->next;
897 					}
898 					if (ifsspc) {
899 						for (;;) {
900 							if (p >= string + ifsp->endoff)
901 								break;
902 							q = p;
903 							if (*p == CTLESC)
904 								p++;
905 							if (strchr(ifs, *p++) == NULL) {
906 								p = q;
907 								break;
908 							}
909 						}
910 					}
911 					start = p;
912 				}
913 			}
914 		} while ((ifsp = ifsp->next) != NULL);
915 		if (*start || (!ifsspc && start > string)) {
916 			sp = (struct strlist *)stalloc(sizeof *sp);
917 			sp->text = start;
918 			*arglist->lastp = sp;
919 			arglist->lastp = &sp->next;
920 		}
921 	} else {
922 		sp = (struct strlist *)stalloc(sizeof *sp);
923 		sp->text = start;
924 		*arglist->lastp = sp;
925 		arglist->lastp = &sp->next;
926 	}
927 }
928 
929 
930 
931 /*
932  * Expand shell metacharacters.  At this point, the only control characters
933  * should be escapes.  The results are stored in the list exparg.
934  */
935 
936 char *expdir;
937 
938 
939 STATIC void
940 expandmeta(str, flag)
941 	struct strlist *str;
942 	int flag;
943 {
944 	char *p;
945 	struct strlist **savelastp;
946 	struct strlist *sp;
947 	char c;
948 	/* TODO - EXP_REDIR */
949 
950 	while (str) {
951 		if (fflag)
952 			goto nometa;
953 		p = str->text;
954 		for (;;) {			/* fast check for meta chars */
955 			if ((c = *p++) == '\0')
956 				goto nometa;
957 			if (c == '*' || c == '?' || c == '[' || c == '!')
958 				break;
959 		}
960 		savelastp = exparg.lastp;
961 		INTOFF;
962 		if (expdir == NULL) {
963 			int i = strlen(str->text);
964 			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
965 		}
966 
967 		expmeta(expdir, str->text);
968 		ckfree(expdir);
969 		expdir = NULL;
970 		INTON;
971 		if (exparg.lastp == savelastp) {
972 			/*
973 			 * no matches
974 			 */
975 nometa:
976 			*exparg.lastp = str;
977 			rmescapes(str->text);
978 			exparg.lastp = &str->next;
979 		} else {
980 			*exparg.lastp = NULL;
981 			*savelastp = sp = expsort(*savelastp);
982 			while (sp->next != NULL)
983 				sp = sp->next;
984 			exparg.lastp = &sp->next;
985 		}
986 		str = str->next;
987 	}
988 }
989 
990 
991 /*
992  * Do metacharacter (i.e. *, ?, [...]) expansion.
993  */
994 
995 STATIC void
996 expmeta(enddir, name)
997 	char *enddir;
998 	char *name;
999 	{
1000 	char *p;
1001 	char *q;
1002 	char *start;
1003 	char *endname;
1004 	int metaflag;
1005 	struct stat statb;
1006 	DIR *dirp;
1007 	struct dirent *dp;
1008 	int atend;
1009 	int matchdot;
1010 
1011 	metaflag = 0;
1012 	start = name;
1013 	for (p = name ; ; p++) {
1014 		if (*p == '*' || *p == '?')
1015 			metaflag = 1;
1016 		else if (*p == '[') {
1017 			q = p + 1;
1018 			if (*q == '!')
1019 				q++;
1020 			for (;;) {
1021 				if (*q == CTLESC)
1022 					q++;
1023 				if (*q == '/' || *q == '\0')
1024 					break;
1025 				if (*++q == ']') {
1026 					metaflag = 1;
1027 					break;
1028 				}
1029 			}
1030 		} else if (*p == '!' && p[1] == '!'	&& (p == name || p[-1] == '/')) {
1031 			metaflag = 1;
1032 		} else if (*p == '\0')
1033 			break;
1034 		else if (*p == CTLESC)
1035 			p++;
1036 		if (*p == '/') {
1037 			if (metaflag)
1038 				break;
1039 			start = p + 1;
1040 		}
1041 	}
1042 	if (metaflag == 0) {	/* we've reached the end of the file name */
1043 		if (enddir != expdir)
1044 			metaflag++;
1045 		for (p = name ; ; p++) {
1046 			if (*p == CTLESC)
1047 				p++;
1048 			*enddir++ = *p;
1049 			if (*p == '\0')
1050 				break;
1051 		}
1052 		if (metaflag == 0 || stat(expdir, &statb) >= 0)
1053 			addfname(expdir);
1054 		return;
1055 	}
1056 	endname = p;
1057 	if (start != name) {
1058 		p = name;
1059 		while (p < start) {
1060 			if (*p == CTLESC)
1061 				p++;
1062 			*enddir++ = *p++;
1063 		}
1064 	}
1065 	if (enddir == expdir) {
1066 		p = ".";
1067 	} else if (enddir == expdir + 1 && *expdir == '/') {
1068 		p = "/";
1069 	} else {
1070 		p = expdir;
1071 		enddir[-1] = '\0';
1072 	}
1073 	if ((dirp = opendir(p)) == NULL)
1074 		return;
1075 	if (enddir != expdir)
1076 		enddir[-1] = '/';
1077 	if (*endname == 0) {
1078 		atend = 1;
1079 	} else {
1080 		atend = 0;
1081 		*endname++ = '\0';
1082 	}
1083 	matchdot = 0;
1084 	if (start[0] == '.' || (start[0] == CTLESC && start[1] == '.'))
1085 		matchdot++;
1086 	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1087 		if (dp->d_name[0] == '.' && ! matchdot)
1088 			continue;
1089 		if (patmatch(start, dp->d_name)) {
1090 			if (atend) {
1091 				scopy(dp->d_name, enddir);
1092 				addfname(expdir);
1093 			} else {
1094 				char *q;
1095 				for (p = enddir, q = dp->d_name;
1096 				     (*p++ = *q++) != '\0';)
1097 					continue;
1098 				p[-1] = '/';
1099 				expmeta(p, endname);
1100 			}
1101 		}
1102 	}
1103 	closedir(dirp);
1104 	if (! atend)
1105 		endname[-1] = '/';
1106 }
1107 
1108 
1109 /*
1110  * Add a file name to the list.
1111  */
1112 
1113 STATIC void
1114 addfname(name)
1115 	char *name;
1116 	{
1117 	char *p;
1118 	struct strlist *sp;
1119 
1120 	p = stalloc(strlen(name) + 1);
1121 	scopy(name, p);
1122 	sp = (struct strlist *)stalloc(sizeof *sp);
1123 	sp->text = p;
1124 	*exparg.lastp = sp;
1125 	exparg.lastp = &sp->next;
1126 }
1127 
1128 
1129 /*
1130  * Sort the results of file name expansion.  It calculates the number of
1131  * strings to sort and then calls msort (short for merge sort) to do the
1132  * work.
1133  */
1134 
1135 STATIC struct strlist *
1136 expsort(str)
1137 	struct strlist *str;
1138 	{
1139 	int len;
1140 	struct strlist *sp;
1141 
1142 	len = 0;
1143 	for (sp = str ; sp ; sp = sp->next)
1144 		len++;
1145 	return msort(str, len);
1146 }
1147 
1148 
1149 STATIC struct strlist *
1150 msort(list, len)
1151 	struct strlist *list;
1152 	int len;
1153 {
1154 	struct strlist *p, *q = NULL;
1155 	struct strlist **lpp;
1156 	int half;
1157 	int n;
1158 
1159 	if (len <= 1)
1160 		return list;
1161 	half = len >> 1;
1162 	p = list;
1163 	for (n = half ; --n >= 0 ; ) {
1164 		q = p;
1165 		p = p->next;
1166 	}
1167 	q->next = NULL;			/* terminate first half of list */
1168 	q = msort(list, half);		/* sort first half of list */
1169 	p = msort(p, len - half);		/* sort second half */
1170 	lpp = &list;
1171 	for (;;) {
1172 		if (strcmp(p->text, q->text) < 0) {
1173 			*lpp = p;
1174 			lpp = &p->next;
1175 			if ((p = *lpp) == NULL) {
1176 				*lpp = q;
1177 				break;
1178 			}
1179 		} else {
1180 			*lpp = q;
1181 			lpp = &q->next;
1182 			if ((q = *lpp) == NULL) {
1183 				*lpp = p;
1184 				break;
1185 			}
1186 		}
1187 	}
1188 	return list;
1189 }
1190 
1191 
1192 
1193 /*
1194  * Returns true if the pattern matches the string.
1195  */
1196 
1197 int
1198 patmatch(pattern, string)
1199 	char *pattern;
1200 	char *string;
1201 	{
1202 #ifdef notdef
1203 	if (pattern[0] == '!' && pattern[1] == '!')
1204 		return 1 - pmatch(pattern + 2, string);
1205 	else
1206 #endif
1207 		return pmatch(pattern, string);
1208 }
1209 
1210 
1211 STATIC int
1212 pmatch(pattern, string)
1213 	char *pattern;
1214 	char *string;
1215 	{
1216 	char *p, *q;
1217 	char c;
1218 
1219 	p = pattern;
1220 	q = string;
1221 	for (;;) {
1222 		switch (c = *p++) {
1223 		case '\0':
1224 			goto breakloop;
1225 		case CTLESC:
1226 			if (*q++ != *p++)
1227 				return 0;
1228 			break;
1229 		case '?':
1230 			if (*q++ == '\0')
1231 				return 0;
1232 			break;
1233 		case '*':
1234 			c = *p;
1235 			if (c != CTLESC && c != '?' && c != '*' && c != '[') {
1236 				while (*q != c) {
1237 					if (*q == '\0')
1238 						return 0;
1239 					q++;
1240 				}
1241 			}
1242 			do {
1243 				if (pmatch(p, q))
1244 					return 1;
1245 			} while (*q++ != '\0');
1246 			return 0;
1247 		case '[': {
1248 			char *endp;
1249 			int invert, found;
1250 			char chr;
1251 
1252 			endp = p;
1253 			if (*endp == '!')
1254 				endp++;
1255 			for (;;) {
1256 				if (*endp == '\0')
1257 					goto dft;		/* no matching ] */
1258 				if (*endp == CTLESC)
1259 					endp++;
1260 				if (*++endp == ']')
1261 					break;
1262 			}
1263 			invert = 0;
1264 			if (*p == '!') {
1265 				invert++;
1266 				p++;
1267 			}
1268 			found = 0;
1269 			chr = *q++;
1270 			if (chr == '\0')
1271 				return 0;
1272 			c = *p++;
1273 			do {
1274 				if (c == CTLESC)
1275 					c = *p++;
1276 				if (*p == '-' && p[1] != ']') {
1277 					p++;
1278 					if (*p == CTLESC)
1279 						p++;
1280 					if (chr >= c && chr <= *p)
1281 						found = 1;
1282 					p++;
1283 				} else {
1284 					if (chr == c)
1285 						found = 1;
1286 				}
1287 			} while ((c = *p++) != ']');
1288 			if (found == invert)
1289 				return 0;
1290 			break;
1291 		}
1292 dft:	        default:
1293 			if (*q++ != c)
1294 				return 0;
1295 			break;
1296 		}
1297 	}
1298 breakloop:
1299 	if (*q != '\0')
1300 		return 0;
1301 	return 1;
1302 }
1303 
1304 
1305 
1306 /*
1307  * Remove any CTLESC characters from a string.
1308  */
1309 
1310 void
1311 rmescapes(str)
1312 	char *str;
1313 	{
1314 	char *p, *q;
1315 
1316 	p = str;
1317 	while (*p != CTLESC) {
1318 		if (*p++ == '\0')
1319 			return;
1320 	}
1321 	q = p;
1322 	while (*p) {
1323 		if (*p == CTLESC)
1324 			p++;
1325 		*q++ = *p++;
1326 	}
1327 	*q = '\0';
1328 }
1329 
1330 
1331 
1332 /*
1333  * See if a pattern matches in a case statement.
1334  */
1335 
1336 int
1337 casematch(pattern, val)
1338 	union node *pattern;
1339 	char *val;
1340 	{
1341 	struct stackmark smark;
1342 	int result;
1343 	char *p;
1344 
1345 	setstackmark(&smark);
1346 	argbackq = pattern->narg.backquote;
1347 	STARTSTACKSTR(expdest);
1348 	ifslastp = NULL;
1349 	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1350 	STPUTC('\0', expdest);
1351 	p = grabstackstr(expdest);
1352 	result = patmatch(p, val);
1353 	popstackmark(&smark);
1354 	return result;
1355 }
1356 
1357 /*
1358  * Our own itoa().
1359  */
1360 
1361 STATIC char *
1362 cvtnum(num, buf)
1363 	int num;
1364 	char *buf;
1365 	{
1366 	char temp[32];
1367 	int neg = num < 0;
1368 	char *p = temp + 31;
1369 
1370 	temp[31] = '\0';
1371 
1372 	do {
1373 		*--p = num % 10 + '0';
1374 	} while ((num /= 10) != 0);
1375 
1376 	if (neg)
1377 		*--p = '-';
1378 
1379 	while (*p)
1380 		STPUTC(*p++, buf);
1381 	return buf;
1382 }
1383