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