expand.c revision 17987
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: expand.c,v 1.6 1996/08/12 19:31:11 ache Exp $
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((int));
101STATIC void varvalue __P((int, 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
684	if (name == '!') {
685		if (backgndpid == -1)
686			return 0;
687	} else if (name == '@' || name == '*') {
688		if (*shellparam.p == NULL)
689			return 0;
690	} else if ((unsigned)(name -= '1') <= '9' - '1') {
691		ap = shellparam.p;
692		do {
693			if (*ap++ == NULL)
694				return 0;
695		} while (--name >= 0);
696	}
697	return 1;
698}
699
700
701
702/*
703 * Add the value of a specialized variable to the stack string.
704 */
705
706STATIC void
707varvalue(name, quoted, allow_split)
708	char name;
709	int quoted;
710	int allow_split;
711{
712	int num;
713	char *p;
714	int i;
715	extern int oexitstatus;
716	char sep;
717	char **ap;
718	char const *syntax;
719
720#define STRTODEST(p) \
721	do {\
722	if (allow_split) { \
723		syntax = quoted? DQSYNTAX : BASESYNTAX; \
724		while (*p) { \
725			if (syntax[*p] == CCTL) \
726				STPUTC(CTLESC, expdest); \
727			STPUTC(*p++, expdest); \
728		} \
729	} else \
730		while (*p) \
731			STPUTC(*p++, expdest); \
732	} while (0)
733
734
735	switch (name) {
736	case '$':
737		num = rootpid;
738		goto numvar;
739	case '?':
740		num = oexitstatus;
741		goto numvar;
742	case '#':
743		num = shellparam.nparam;
744		goto numvar;
745	case '!':
746		num = backgndpid;
747numvar:
748		expdest = cvtnum(num, expdest);
749		break;
750	case '-':
751		for (i = 0 ; i < NOPTS ; i++) {
752			if (optlist[i].val)
753				STPUTC(optlist[i].letter, expdest);
754		}
755		break;
756	case '@':
757		if (allow_split) {
758			sep = '\0';
759			goto allargs;
760		}
761		/* fall through */
762	case '*':
763		sep = ' ';
764allargs:
765		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
766			STRTODEST(p);
767			if (*ap)
768				STPUTC(sep, expdest);
769		}
770		break;
771	case '0':
772		p = arg0;
773		STRTODEST(p);
774		break;
775	default:
776		if ((unsigned)(name -= '1') <= '9' - '1') {
777			p = shellparam.p[name];
778			STRTODEST(p);
779		}
780		break;
781	}
782}
783
784
785
786/*
787 * Record the the fact that we have to scan this region of the
788 * string for IFS characters.
789 */
790
791STATIC void
792recordregion(start, end, nulonly)
793	int start;
794	int end;
795	int nulonly;
796{
797	register struct ifsregion *ifsp;
798
799	if (ifslastp == NULL) {
800		ifsp = &ifsfirst;
801	} else {
802		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
803		ifslastp->next = ifsp;
804	}
805	ifslastp = ifsp;
806	ifslastp->next = NULL;
807	ifslastp->begoff = start;
808	ifslastp->endoff = end;
809	ifslastp->nulonly = nulonly;
810}
811
812
813
814/*
815 * Break the argument string into pieces based upon IFS and add the
816 * strings to the argument list.  The regions of the string to be
817 * searched for IFS characters have been stored by recordregion.
818 */
819STATIC void
820ifsbreakup(string, arglist)
821	char *string;
822	struct arglist *arglist;
823	{
824	struct ifsregion *ifsp;
825	struct strlist *sp;
826	char *start;
827	register char *p;
828	char *q;
829	char *ifs;
830	int ifsspc;
831
832
833	start = string;
834	if (ifslastp != NULL) {
835		ifsp = &ifsfirst;
836		do {
837			p = string + ifsp->begoff;
838			ifs = ifsp->nulonly? nullstr : ifsval();
839			ifsspc = strchr(ifs, ' ') != NULL;
840			while (p < string + ifsp->endoff) {
841				q = p;
842				if (*p == CTLESC)
843					p++;
844				if (strchr(ifs, *p++)) {
845					if (q > start || !ifsspc) {
846						*q = '\0';
847						sp = (struct strlist *)stalloc(sizeof *sp);
848						sp->text = start;
849						*arglist->lastp = sp;
850						arglist->lastp = &sp->next;
851					}
852					if (ifsspc) {
853						for (;;) {
854							if (p >= string + ifsp->endoff)
855								break;
856							q = p;
857							if (*p == CTLESC)
858								p++;
859							if (strchr(ifs, *p++) == NULL) {
860								p = q;
861								break;
862							}
863						}
864					}
865					start = p;
866				}
867			}
868		} while ((ifsp = ifsp->next) != NULL);
869		if (*start || (!ifsspc && start > string)) {
870			sp = (struct strlist *)stalloc(sizeof *sp);
871			sp->text = start;
872			*arglist->lastp = sp;
873			arglist->lastp = &sp->next;
874		}
875	} else {
876		sp = (struct strlist *)stalloc(sizeof *sp);
877		sp->text = start;
878		*arglist->lastp = sp;
879		arglist->lastp = &sp->next;
880	}
881}
882
883
884
885/*
886 * Expand shell metacharacters.  At this point, the only control characters
887 * should be escapes.  The results are stored in the list exparg.
888 */
889
890char *expdir;
891
892
893STATIC void
894expandmeta(str, flag)
895	struct strlist *str;
896	int flag;
897{
898	char *p;
899	struct strlist **savelastp;
900	struct strlist *sp;
901	char c;
902	/* TODO - EXP_REDIR */
903
904	while (str) {
905		if (fflag)
906			goto nometa;
907		p = str->text;
908		for (;;) {			/* fast check for meta chars */
909			if ((c = *p++) == '\0')
910				goto nometa;
911			if (c == '*' || c == '?' || c == '[' || c == '!')
912				break;
913		}
914		savelastp = exparg.lastp;
915		INTOFF;
916		if (expdir == NULL) {
917			int i = strlen(str->text);
918			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
919		}
920
921		expmeta(expdir, str->text);
922		ckfree(expdir);
923		expdir = NULL;
924		INTON;
925		if (exparg.lastp == savelastp) {
926			/*
927			 * no matches
928			 */
929nometa:
930			*exparg.lastp = str;
931			rmescapes(str->text);
932			exparg.lastp = &str->next;
933		} else {
934			*exparg.lastp = NULL;
935			*savelastp = sp = expsort(*savelastp);
936			while (sp->next != NULL)
937				sp = sp->next;
938			exparg.lastp = &sp->next;
939		}
940		str = str->next;
941	}
942}
943
944
945/*
946 * Do metacharacter (i.e. *, ?, [...]) expansion.
947 */
948
949STATIC void
950expmeta(enddir, name)
951	char *enddir;
952	char *name;
953	{
954	register char *p;
955	char *q;
956	char *start;
957	char *endname;
958	int metaflag;
959	struct stat statb;
960	DIR *dirp;
961	struct dirent *dp;
962	int atend;
963	int matchdot;
964
965	metaflag = 0;
966	start = name;
967	for (p = name ; ; p++) {
968		if (*p == '*' || *p == '?')
969			metaflag = 1;
970		else if (*p == '[') {
971			q = p + 1;
972			if (*q == '!')
973				q++;
974			for (;;) {
975				if (*q == CTLESC)
976					q++;
977				if (*q == '/' || *q == '\0')
978					break;
979				if (*++q == ']') {
980					metaflag = 1;
981					break;
982				}
983			}
984		} else if (*p == '!' && p[1] == '!'	&& (p == name || p[-1] == '/')) {
985			metaflag = 1;
986		} else if (*p == '\0')
987			break;
988		else if (*p == CTLESC)
989			p++;
990		if (*p == '/') {
991			if (metaflag)
992				break;
993			start = p + 1;
994		}
995	}
996	if (metaflag == 0) {	/* we've reached the end of the file name */
997		if (enddir != expdir)
998			metaflag++;
999		for (p = name ; ; p++) {
1000			if (*p == CTLESC)
1001				p++;
1002			*enddir++ = *p;
1003			if (*p == '\0')
1004				break;
1005		}
1006		if (metaflag == 0 || stat(expdir, &statb) >= 0)
1007			addfname(expdir);
1008		return;
1009	}
1010	endname = p;
1011	if (start != name) {
1012		p = name;
1013		while (p < start) {
1014			if (*p == CTLESC)
1015				p++;
1016			*enddir++ = *p++;
1017		}
1018	}
1019	if (enddir == expdir) {
1020		p = ".";
1021	} else if (enddir == expdir + 1 && *expdir == '/') {
1022		p = "/";
1023	} else {
1024		p = expdir;
1025		enddir[-1] = '\0';
1026	}
1027	if ((dirp = opendir(p)) == NULL)
1028		return;
1029	if (enddir != expdir)
1030		enddir[-1] = '/';
1031	if (*endname == 0) {
1032		atend = 1;
1033	} else {
1034		atend = 0;
1035		*endname++ = '\0';
1036	}
1037	matchdot = 0;
1038	if (start[0] == '.' || (start[0] == CTLESC && start[1] == '.'))
1039		matchdot++;
1040	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1041		if (dp->d_name[0] == '.' && ! matchdot)
1042			continue;
1043		if (patmatch(start, dp->d_name)) {
1044			if (atend) {
1045				scopy(dp->d_name, enddir);
1046				addfname(expdir);
1047			} else {
1048				char *q;
1049				for (p = enddir, q = dp->d_name;
1050				     (*p++ = *q++) != '\0';)
1051					continue;
1052				p[-1] = '/';
1053				expmeta(p, endname);
1054			}
1055		}
1056	}
1057	closedir(dirp);
1058	if (! atend)
1059		endname[-1] = '/';
1060}
1061
1062
1063/*
1064 * Add a file name to the list.
1065 */
1066
1067STATIC void
1068addfname(name)
1069	char *name;
1070	{
1071	char *p;
1072	struct strlist *sp;
1073
1074	p = stalloc(strlen(name) + 1);
1075	scopy(name, p);
1076	sp = (struct strlist *)stalloc(sizeof *sp);
1077	sp->text = p;
1078	*exparg.lastp = sp;
1079	exparg.lastp = &sp->next;
1080}
1081
1082
1083/*
1084 * Sort the results of file name expansion.  It calculates the number of
1085 * strings to sort and then calls msort (short for merge sort) to do the
1086 * work.
1087 */
1088
1089STATIC struct strlist *
1090expsort(str)
1091	struct strlist *str;
1092	{
1093	int len;
1094	struct strlist *sp;
1095
1096	len = 0;
1097	for (sp = str ; sp ; sp = sp->next)
1098		len++;
1099	return msort(str, len);
1100}
1101
1102
1103STATIC struct strlist *
1104msort(list, len)
1105	struct strlist *list;
1106	int len;
1107{
1108	struct strlist *p, *q = NULL;
1109	struct strlist **lpp;
1110	int half;
1111	int n;
1112
1113	if (len <= 1)
1114		return list;
1115	half = len >> 1;
1116	p = list;
1117	for (n = half ; --n >= 0 ; ) {
1118		q = p;
1119		p = p->next;
1120	}
1121	q->next = NULL;			/* terminate first half of list */
1122	q = msort(list, half);		/* sort first half of list */
1123	p = msort(p, len - half);		/* sort second half */
1124	lpp = &list;
1125	for (;;) {
1126		if (strcmp(p->text, q->text) < 0) {
1127			*lpp = p;
1128			lpp = &p->next;
1129			if ((p = *lpp) == NULL) {
1130				*lpp = q;
1131				break;
1132			}
1133		} else {
1134			*lpp = q;
1135			lpp = &q->next;
1136			if ((q = *lpp) == NULL) {
1137				*lpp = p;
1138				break;
1139			}
1140		}
1141	}
1142	return list;
1143}
1144
1145
1146
1147/*
1148 * Returns true if the pattern matches the string.
1149 */
1150
1151int
1152patmatch(pattern, string)
1153	char *pattern;
1154	char *string;
1155	{
1156#ifdef notdef
1157	if (pattern[0] == '!' && pattern[1] == '!')
1158		return 1 - pmatch(pattern + 2, string);
1159	else
1160#endif
1161		return pmatch(pattern, string);
1162}
1163
1164
1165STATIC int
1166pmatch(pattern, string)
1167	char *pattern;
1168	char *string;
1169	{
1170	register char *p, *q;
1171	register char c;
1172
1173	p = pattern;
1174	q = string;
1175	for (;;) {
1176		switch (c = *p++) {
1177		case '\0':
1178			goto breakloop;
1179		case CTLESC:
1180			if (*q++ != *p++)
1181				return 0;
1182			break;
1183		case '?':
1184			if (*q++ == '\0')
1185				return 0;
1186			break;
1187		case '*':
1188			c = *p;
1189			if (c != CTLESC && c != '?' && c != '*' && c != '[') {
1190				while (*q != c) {
1191					if (*q == '\0')
1192						return 0;
1193					q++;
1194				}
1195			}
1196			do {
1197				if (pmatch(p, q))
1198					return 1;
1199			} while (*q++ != '\0');
1200			return 0;
1201		case '[': {
1202			char *endp;
1203			int invert, found;
1204			char chr;
1205
1206			endp = p;
1207			if (*endp == '!')
1208				endp++;
1209			for (;;) {
1210				if (*endp == '\0')
1211					goto dft;		/* no matching ] */
1212				if (*endp == CTLESC)
1213					endp++;
1214				if (*++endp == ']')
1215					break;
1216			}
1217			invert = 0;
1218			if (*p == '!') {
1219				invert++;
1220				p++;
1221			}
1222			found = 0;
1223			chr = *q++;
1224			if (chr == '\0')
1225				return 0;
1226			c = *p++;
1227			do {
1228				if (c == CTLESC)
1229					c = *p++;
1230				if (*p == '-' && p[1] != ']') {
1231					p++;
1232					if (*p == CTLESC)
1233						p++;
1234					if (   collate_range_cmp(chr, c) >= 0
1235					    && collate_range_cmp(chr, *p) <= 0
1236					   )
1237						found = 1;
1238					p++;
1239				} else {
1240					if (chr == c)
1241						found = 1;
1242				}
1243			} while ((c = *p++) != ']');
1244			if (found == invert)
1245				return 0;
1246			break;
1247		}
1248dft:	        default:
1249			if (*q++ != c)
1250				return 0;
1251			break;
1252		}
1253	}
1254breakloop:
1255	if (*q != '\0')
1256		return 0;
1257	return 1;
1258}
1259
1260
1261
1262/*
1263 * Remove any CTLESC characters from a string.
1264 */
1265
1266void
1267rmescapes(str)
1268	char *str;
1269	{
1270	register char *p, *q;
1271
1272	p = str;
1273	while (*p != CTLESC) {
1274		if (*p++ == '\0')
1275			return;
1276	}
1277	q = p;
1278	while (*p) {
1279		if (*p == CTLESC)
1280			p++;
1281		*q++ = *p++;
1282	}
1283	*q = '\0';
1284}
1285
1286
1287
1288/*
1289 * See if a pattern matches in a case statement.
1290 */
1291
1292int
1293casematch(pattern, val)
1294	union node *pattern;
1295	char *val;
1296	{
1297	struct stackmark smark;
1298	int result;
1299	char *p;
1300
1301	setstackmark(&smark);
1302	argbackq = pattern->narg.backquote;
1303	STARTSTACKSTR(expdest);
1304	ifslastp = NULL;
1305	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1306	STPUTC('\0', expdest);
1307	p = grabstackstr(expdest);
1308	result = patmatch(p, val);
1309	popstackmark(&smark);
1310	return result;
1311}
1312
1313/*
1314 * Our own itoa().
1315 */
1316
1317STATIC char *
1318cvtnum(num, buf)
1319	int num;
1320	char *buf;
1321	{
1322	char temp[32];
1323	int neg = num < 0;
1324	char *p = temp + 31;
1325
1326	temp[31] = '\0';
1327
1328	do {
1329		*--p = num % 10 + '0';
1330	} while ((num /= 10) != 0);
1331
1332	if (neg)
1333		*--p = '-';
1334
1335	while (*p)
1336		STPUTC(*p++, buf);
1337	return buf;
1338}
1339