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