expand.c revision 45644
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.25 1999/04/09 15:23:48 tegge 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 *, int));
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(), expdest - stackblock());
146}
147
148
149/*
150 * Perform variable substitution and command substitution on an argument,
151 * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
152 * perform splitting and file name expansion.  When arglist is NULL, perform
153 * here document expansion.
154 */
155
156void
157expandarg(arg, arglist, flag)
158	union node *arg;
159	struct arglist *arglist;
160	int flag;
161{
162	struct strlist *sp;
163	char *p;
164
165	argbackq = arg->narg.backquote;
166	STARTSTACKSTR(expdest);
167	ifsfirst.next = NULL;
168	ifslastp = NULL;
169	argstr(arg->narg.text, flag);
170	if (arglist == NULL) {
171		return;			/* here document expanded */
172	}
173	STPUTC('\0', expdest);
174	p = grabstackstr(expdest);
175	exparg.lastp = &exparg.list;
176	/*
177	 * TODO - EXP_REDIR
178	 */
179	if (flag & EXP_FULL) {
180		ifsbreakup(p, &exparg);
181		*exparg.lastp = NULL;
182		exparg.lastp = &exparg.list;
183		expandmeta(exparg.list, flag);
184	} else {
185		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
186			rmescapes(p);
187		sp = (struct strlist *)stalloc(sizeof (struct strlist));
188		sp->text = p;
189		*exparg.lastp = sp;
190		exparg.lastp = &sp->next;
191	}
192	while (ifsfirst.next != NULL) {
193		struct ifsregion *ifsp;
194		INTOFF;
195		ifsp = ifsfirst.next->next;
196		ckfree(ifsfirst.next);
197		ifsfirst.next = ifsp;
198		INTON;
199	}
200	*exparg.lastp = NULL;
201	if (exparg.list) {
202		*arglist->lastp = exparg.list;
203		arglist->lastp = exparg.lastp;
204	}
205}
206
207
208
209/*
210 * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
211 * characters to allow for further processing.  Otherwise treat
212 * $@ like $* since no splitting will be performed.
213 */
214
215STATIC void
216argstr(p, flag)
217	char *p;
218	int flag;
219{
220	char c;
221	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */
222	int firsteq = 1;
223
224	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
225		p = exptilde(p, flag);
226	for (;;) {
227		switch (c = *p++) {
228		case '\0':
229		case CTLENDVAR: /* ??? */
230			goto breakloop;
231		case CTLQUOTEMARK:
232			/* "$@" syntax adherence hack */
233			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
234				break;
235			if ((flag & EXP_FULL) != 0)
236				STPUTC(c, expdest);
237			break;
238		case CTLESC:
239			if (quotes)
240				STPUTC(c, expdest);
241			c = *p++;
242			STPUTC(c, expdest);
243			break;
244		case CTLVAR:
245			p = evalvar(p, flag);
246			break;
247		case CTLBACKQ:
248		case CTLBACKQ|CTLQUOTE:
249			expbackq(argbackq->n, c & CTLQUOTE, flag);
250			argbackq = argbackq->next;
251			break;
252		case CTLENDARI:
253			expari(flag);
254			break;
255		case ':':
256		case '=':
257			/*
258			 * sort of a hack - expand tildes in variable
259			 * assignments (after the first '=' and after ':'s).
260			 */
261			STPUTC(c, expdest);
262			if (flag & EXP_VARTILDE && *p == '~') {
263				if (c == '=') {
264					if (firsteq)
265						firsteq = 0;
266					else
267						break;
268				}
269				p = exptilde(p, flag);
270			}
271			break;
272		default:
273			STPUTC(c, expdest);
274		}
275	}
276breakloop:;
277}
278
279STATIC char *
280exptilde(p, flag)
281	char *p;
282	int flag;
283{
284	char c, *startp = p;
285	struct passwd *pw;
286	char *home;
287	int quotes = flag & (EXP_FULL | EXP_CASE);
288
289	while ((c = *p) != '\0') {
290		switch(c) {
291		case CTLESC:
292			return (startp);
293		case CTLQUOTEMARK:
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	char *q;
521	int c = 0;
522	int saveherefd = herefd;
523	struct nodelist *saveargbackq = argbackq;
524	int amount;
525
526	herefd = -1;
527	argstr(p, 0);
528	STACKSTRNUL(expdest);
529	herefd = saveherefd;
530	argbackq = saveargbackq;
531	startp = stackblock() + startloc;
532	if (str == NULL)
533	    str = stackblock() + strloc;
534
535	switch (subtype) {
536	case VSASSIGN:
537		setvar(str, startp, 0);
538		amount = startp - expdest;
539		STADJUST(amount, expdest);
540		varflags &= ~VSNUL;
541		if (c != 0)
542			*loc = c;
543		return 1;
544
545	case VSQUESTION:
546		if (*p != CTLENDVAR) {
547			outfmt(&errout, "%s\n", startp);
548			error((char *)NULL);
549		}
550		error("%.*s: parameter %snot set", p - str - 1,
551		      str, (varflags & VSNUL) ? "null or "
552					      : nullstr);
553		return 0;
554
555	case VSTRIMLEFT:
556		for (loc = startp; loc < str; loc++) {
557			c = *loc;
558			*loc = '\0';
559			if (patmatch(str, startp, varflags & VSQUOTE)) {
560				*loc = c;
561				goto recordleft;
562			}
563			*loc = c;
564			if ((varflags & VSQUOTE) && *loc == CTLESC)
565				loc++;
566		}
567		return 0;
568
569	case VSTRIMLEFTMAX:
570		for (loc = str - 1; loc >= startp;) {
571			c = *loc;
572			*loc = '\0';
573			if (patmatch(str, startp, varflags & VSQUOTE)) {
574				*loc = c;
575				goto recordleft;
576			}
577			*loc = c;
578			loc--;
579			if ((varflags & VSQUOTE) && loc > startp &&
580			    *(loc - 1) == CTLESC) {
581				for (q = startp; q < loc; q++)
582					if (*q == CTLESC)
583						q++;
584				if (q > loc)
585					loc--;
586			}
587		}
588		return 0;
589
590	case VSTRIMRIGHT:
591		for (loc = str - 1; loc >= startp;) {
592			if (patmatch(str, loc, varflags & VSQUOTE)) {
593				amount = loc - expdest;
594				STADJUST(amount, expdest);
595				return 1;
596			}
597			loc--;
598			if ((varflags & VSQUOTE) && loc > startp &&
599			    *(loc - 1) == CTLESC) {
600				for (q = startp; q < loc; q++)
601					if (*q == CTLESC)
602						q++;
603				if (q > loc)
604					loc--;
605			}
606		}
607		return 0;
608
609	case VSTRIMRIGHTMAX:
610		for (loc = startp; loc < str - 1; loc++) {
611			if (patmatch(str, loc, varflags & VSQUOTE)) {
612				amount = loc - expdest;
613				STADJUST(amount, expdest);
614				return 1;
615			}
616			if ((varflags & VSQUOTE) && *loc == CTLESC)
617				loc++;
618		}
619		return 0;
620
621
622	default:
623		abort();
624	}
625
626recordleft:
627	amount = ((str - 1) - (loc - startp)) - expdest;
628	STADJUST(amount, expdest);
629	while (loc != str - 1)
630		*startp++ = *loc++;
631	return 1;
632}
633
634
635/*
636 * Expand a variable, and return a pointer to the next character in the
637 * input string.
638 */
639
640STATIC char *
641evalvar(p, flag)
642	char *p;
643	int flag;
644{
645	int subtype;
646	int varflags;
647	char *var;
648	char *val;
649	int patloc;
650	int c;
651	int set;
652	int special;
653	int startloc;
654	int varlen;
655	int easy;
656	int quotes = flag & (EXP_FULL | EXP_CASE);
657
658	varflags = *p++;
659	subtype = varflags & VSTYPE;
660	var = p;
661	special = 0;
662	if (! is_name(*p))
663		special = 1;
664	p = strchr(p, '=') + 1;
665again: /* jump here after setting a variable with ${var=text} */
666	if (special) {
667		set = varisset(var, varflags & VSNUL);
668		val = NULL;
669	} else {
670		val = lookupvar(var);
671		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
672			val = NULL;
673			set = 0;
674		} else
675			set = 1;
676	}
677	varlen = 0;
678	startloc = expdest - stackblock();
679	if (set && subtype != VSPLUS) {
680		/* insert the value of the variable */
681		if (special) {
682			varvalue(var, varflags & VSQUOTE, flag & EXP_FULL);
683			if (subtype == VSLENGTH) {
684				varlen = expdest - stackblock() - startloc;
685				STADJUST(-varlen, expdest);
686			}
687		} else {
688			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
689								  : BASESYNTAX;
690
691			if (subtype == VSLENGTH) {
692				for (;*val; val++)
693					varlen++;
694			}
695			else {
696				while (*val) {
697					if (quotes && syntax[*val] == CCTL)
698						STPUTC(CTLESC, expdest);
699					STPUTC(*val++, expdest);
700				}
701
702			}
703		}
704	}
705
706	if (subtype == VSPLUS)
707		set = ! set;
708
709	easy = ((varflags & VSQUOTE) == 0 ||
710		(*var == '@' && shellparam.nparam != 1));
711
712
713	switch (subtype) {
714	case VSLENGTH:
715		expdest = cvtnum(varlen, expdest);
716		goto record;
717
718	case VSNORMAL:
719		if (!easy)
720			break;
721record:
722		recordregion(startloc, expdest - stackblock(),
723			     varflags & VSQUOTE);
724		break;
725
726	case VSPLUS:
727	case VSMINUS:
728		if (!set) {
729			argstr(p, flag);
730			break;
731		}
732		if (easy)
733			goto record;
734		break;
735
736	case VSTRIMLEFT:
737	case VSTRIMLEFTMAX:
738	case VSTRIMRIGHT:
739	case VSTRIMRIGHTMAX:
740		if (!set)
741			break;
742		/*
743		 * Terminate the string and start recording the pattern
744		 * right after it
745		 */
746		STPUTC('\0', expdest);
747		patloc = expdest - stackblock();
748		if (subevalvar(p, NULL, patloc, subtype,
749			       startloc, varflags) == 0) {
750			int amount = (expdest - stackblock() - patloc) + 1;
751			STADJUST(-amount, expdest);
752		}
753		/* Remove any recorded regions beyond start of variable */
754		removerecordregions(startloc);
755		goto record;
756
757	case VSASSIGN:
758	case VSQUESTION:
759		if (!set) {
760			if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
761				varflags &= ~VSNUL;
762				/*
763				 * Remove any recorded regions beyond
764				 * start of variable
765				 */
766				removerecordregions(startloc);
767				goto again;
768			}
769			break;
770		}
771		if (easy)
772			goto record;
773		break;
774
775	default:
776		abort();
777	}
778
779	if (subtype != VSNORMAL) {	/* skip to end of alternative */
780		int nesting = 1;
781		for (;;) {
782			if ((c = *p++) == CTLESC)
783				p++;
784			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
785				if (set)
786					argbackq = argbackq->next;
787			} else if (c == CTLVAR) {
788				if ((*p++ & VSTYPE) != VSNORMAL)
789					nesting++;
790			} else if (c == CTLENDVAR) {
791				if (--nesting == 0)
792					break;
793			}
794		}
795	}
796	return p;
797}
798
799
800
801/*
802 * Test whether a specialized variable is set.
803 */
804
805STATIC int
806varisset(name, nulok)
807	char *name;
808	int nulok;
809{
810
811	if (*name == '!')
812		return backgndpid != -1;
813	else if (*name == '@' || *name == '*') {
814		if (*shellparam.p == NULL)
815			return 0;
816
817		if (nulok) {
818			char **av;
819
820			for (av = shellparam.p; *av; av++)
821				if (**av != '\0')
822					return 1;
823			return 0;
824		}
825	} else if (is_digit(*name)) {
826		char *ap;
827		int num = atoi(name);
828
829		if (num > shellparam.nparam)
830			return 0;
831
832		if (num == 0)
833			ap = arg0;
834		else
835			ap = shellparam.p[num - 1];
836
837		if (nulok && (ap == NULL || *ap == '\0'))
838			return 0;
839	}
840	return 1;
841}
842
843
844
845/*
846 * Add the value of a specialized variable to the stack string.
847 */
848
849STATIC void
850varvalue(name, quoted, allow_split)
851	char *name;
852	int quoted;
853	int allow_split;
854{
855	int num;
856	char *p;
857	int i;
858	extern int oexitstatus;
859	char sep;
860	char **ap;
861	char const *syntax;
862
863#define STRTODEST(p) \
864	do {\
865	if (allow_split) { \
866		syntax = quoted? DQSYNTAX : BASESYNTAX; \
867		while (*p) { \
868			if (syntax[*p] == CCTL) \
869				STPUTC(CTLESC, expdest); \
870			STPUTC(*p++, expdest); \
871		} \
872	} else \
873		while (*p) \
874			STPUTC(*p++, expdest); \
875	} while (0)
876
877
878	switch (*name) {
879	case '$':
880		num = rootpid;
881		goto numvar;
882	case '?':
883		num = oexitstatus;
884		goto numvar;
885	case '#':
886		num = shellparam.nparam;
887		goto numvar;
888	case '!':
889		num = backgndpid;
890numvar:
891		expdest = cvtnum(num, expdest);
892		break;
893	case '-':
894		for (i = 0 ; i < NOPTS ; i++) {
895			if (optlist[i].val)
896				STPUTC(optlist[i].letter, expdest);
897		}
898		break;
899	case '@':
900		if (allow_split && quoted) {
901			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
902				STRTODEST(p);
903				if (*ap)
904					STPUTC('\0', expdest);
905			}
906			break;
907		}
908		/* fall through */
909	case '*':
910		if (ifsset() != 0)
911			sep = ifsval()[0];
912		else
913			sep = ' ';
914		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
915			STRTODEST(p);
916			if (*ap && sep)
917				STPUTC(sep, expdest);
918		}
919		break;
920	case '0':
921		p = arg0;
922		STRTODEST(p);
923		break;
924	default:
925		if (is_digit(*name)) {
926			num = atoi(name);
927			if (num > 0 && num <= shellparam.nparam) {
928				p = shellparam.p[num - 1];
929				STRTODEST(p);
930			}
931		}
932		break;
933	}
934}
935
936
937
938/*
939 * Record the the fact that we have to scan this region of the
940 * string for IFS characters.
941 */
942
943STATIC void
944recordregion(start, end, nulonly)
945	int start;
946	int end;
947	int nulonly;
948{
949	struct ifsregion *ifsp;
950
951	if (ifslastp == NULL) {
952		ifsp = &ifsfirst;
953	} else {
954		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
955		ifslastp->next = ifsp;
956	}
957	ifslastp = ifsp;
958	ifslastp->next = NULL;
959	ifslastp->begoff = start;
960	ifslastp->endoff = end;
961	ifslastp->nulonly = nulonly;
962}
963
964
965
966/*
967 * Break the argument string into pieces based upon IFS and add the
968 * strings to the argument list.  The regions of the string to be
969 * searched for IFS characters have been stored by recordregion.
970 */
971STATIC void
972ifsbreakup(string, arglist)
973	char *string;
974	struct arglist *arglist;
975	{
976	struct ifsregion *ifsp;
977	struct strlist *sp;
978	char *start;
979	char *p;
980	char *q;
981	char *ifs;
982	int ifsspc;
983	int nulonly;
984
985
986	start = string;
987	ifsspc = 0;
988	nulonly = 0;
989	if (ifslastp != NULL) {
990		ifsp = &ifsfirst;
991		do {
992			p = string + ifsp->begoff;
993			nulonly = ifsp->nulonly;
994			ifs = nulonly ? nullstr :
995				( ifsset() ? ifsval() : " \t\n" );
996			ifsspc = 0;
997			while (p < string + ifsp->endoff) {
998				q = p;
999				if (*p == CTLESC)
1000					p++;
1001				if (strchr(ifs, *p)) {
1002					if (!nulonly)
1003						ifsspc = (strchr(" \t\n", *p) != NULL);
1004					/* Ignore IFS whitespace at start */
1005					if (q == start && ifsspc) {
1006						p++;
1007						start = p;
1008						continue;
1009					}
1010					*q = '\0';
1011					sp = (struct strlist *)stalloc(sizeof *sp);
1012					sp->text = start;
1013					*arglist->lastp = sp;
1014					arglist->lastp = &sp->next;
1015					p++;
1016					if (!nulonly) {
1017						for (;;) {
1018							if (p >= string + ifsp->endoff) {
1019								break;
1020							}
1021							q = p;
1022							if (*p == CTLESC)
1023								p++;
1024							if (strchr(ifs, *p) == NULL ) {
1025								p = q;
1026								break;
1027							} else if (strchr(" \t\n",*p) == NULL) {
1028								if (ifsspc) {
1029									p++;
1030									ifsspc = 0;
1031								} else {
1032									p = q;
1033									break;
1034								}
1035							} else
1036								p++;
1037						}
1038					}
1039					start = p;
1040				} else
1041					p++;
1042			}
1043		} while ((ifsp = ifsp->next) != NULL);
1044		if (*start || (!ifsspc && start > string &&
1045			(nulonly || 1))) {
1046			sp = (struct strlist *)stalloc(sizeof *sp);
1047			sp->text = start;
1048			*arglist->lastp = sp;
1049			arglist->lastp = &sp->next;
1050		}
1051	} else {
1052		sp = (struct strlist *)stalloc(sizeof *sp);
1053		sp->text = start;
1054		*arglist->lastp = sp;
1055		arglist->lastp = &sp->next;
1056	}
1057}
1058
1059
1060
1061/*
1062 * Expand shell metacharacters.  At this point, the only control characters
1063 * should be escapes.  The results are stored in the list exparg.
1064 */
1065
1066char *expdir;
1067
1068
1069STATIC void
1070expandmeta(str, flag)
1071	struct strlist *str;
1072	int flag __unused;
1073{
1074	char *p;
1075	struct strlist **savelastp;
1076	struct strlist *sp;
1077	char c;
1078	/* TODO - EXP_REDIR */
1079
1080	while (str) {
1081		if (fflag)
1082			goto nometa;
1083		p = str->text;
1084		for (;;) {			/* fast check for meta chars */
1085			if ((c = *p++) == '\0')
1086				goto nometa;
1087			if (c == '*' || c == '?' || c == '[' || c == '!')
1088				break;
1089		}
1090		savelastp = exparg.lastp;
1091		INTOFF;
1092		if (expdir == NULL) {
1093			int i = strlen(str->text);
1094			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
1095		}
1096
1097		expmeta(expdir, str->text);
1098		ckfree(expdir);
1099		expdir = NULL;
1100		INTON;
1101		if (exparg.lastp == savelastp) {
1102			/*
1103			 * no matches
1104			 */
1105nometa:
1106			*exparg.lastp = str;
1107			rmescapes(str->text);
1108			exparg.lastp = &str->next;
1109		} else {
1110			*exparg.lastp = NULL;
1111			*savelastp = sp = expsort(*savelastp);
1112			while (sp->next != NULL)
1113				sp = sp->next;
1114			exparg.lastp = &sp->next;
1115		}
1116		str = str->next;
1117	}
1118}
1119
1120
1121/*
1122 * Do metacharacter (i.e. *, ?, [...]) expansion.
1123 */
1124
1125STATIC void
1126expmeta(enddir, name)
1127	char *enddir;
1128	char *name;
1129	{
1130	char *p;
1131	char *q;
1132	char *start;
1133	char *endname;
1134	int metaflag;
1135	struct stat statb;
1136	DIR *dirp;
1137	struct dirent *dp;
1138	int atend;
1139	int matchdot;
1140
1141	metaflag = 0;
1142	start = name;
1143	for (p = name ; ; p++) {
1144		if (*p == '*' || *p == '?')
1145			metaflag = 1;
1146		else if (*p == '[') {
1147			q = p + 1;
1148			if (*q == '!' || *q == '^')
1149				q++;
1150			for (;;) {
1151				while (*q == CTLQUOTEMARK)
1152					q++;
1153				if (*q == CTLESC)
1154					q++;
1155				if (*q == '/' || *q == '\0')
1156					break;
1157				if (*++q == ']') {
1158					metaflag = 1;
1159					break;
1160				}
1161			}
1162		} else if (*p == '!' && p[1] == '!'	&& (p == name || p[-1] == '/')) {
1163			metaflag = 1;
1164		} else if (*p == '\0')
1165			break;
1166		else if (*p == CTLQUOTEMARK)
1167			continue;
1168		else if (*p == CTLESC)
1169			p++;
1170		if (*p == '/') {
1171			if (metaflag)
1172				break;
1173			start = p + 1;
1174		}
1175	}
1176	if (metaflag == 0) {	/* we've reached the end of the file name */
1177		if (enddir != expdir)
1178			metaflag++;
1179		for (p = name ; ; p++) {
1180			if (*p == CTLQUOTEMARK)
1181				continue;
1182			if (*p == CTLESC)
1183				p++;
1184			*enddir++ = *p;
1185			if (*p == '\0')
1186				break;
1187		}
1188		if (metaflag == 0 || stat(expdir, &statb) >= 0)
1189			addfname(expdir);
1190		return;
1191	}
1192	endname = p;
1193	if (start != name) {
1194		p = name;
1195		while (p < start) {
1196			while (*p == CTLQUOTEMARK)
1197				p++;
1198			if (*p == CTLESC)
1199				p++;
1200			*enddir++ = *p++;
1201		}
1202	}
1203	if (enddir == expdir) {
1204		p = ".";
1205	} else if (enddir == expdir + 1 && *expdir == '/') {
1206		p = "/";
1207	} else {
1208		p = expdir;
1209		enddir[-1] = '\0';
1210	}
1211	if ((dirp = opendir(p)) == NULL)
1212		return;
1213	if (enddir != expdir)
1214		enddir[-1] = '/';
1215	if (*endname == 0) {
1216		atend = 1;
1217	} else {
1218		atend = 0;
1219		*endname++ = '\0';
1220	}
1221	matchdot = 0;
1222	p = start;
1223	while (*p == CTLQUOTEMARK)
1224		p++;
1225	if (*p == CTLESC)
1226		p++;
1227	if (*p == '.')
1228		matchdot++;
1229	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1230		if (dp->d_name[0] == '.' && ! matchdot)
1231			continue;
1232		if (patmatch(start, dp->d_name, 0)) {
1233			if (atend) {
1234				scopy(dp->d_name, enddir);
1235				addfname(expdir);
1236			} else {
1237				char *q;
1238				for (p = enddir, q = dp->d_name;
1239				     (*p++ = *q++) != '\0';)
1240					continue;
1241				p[-1] = '/';
1242				expmeta(p, endname);
1243			}
1244		}
1245	}
1246	closedir(dirp);
1247	if (! atend)
1248		endname[-1] = '/';
1249}
1250
1251
1252/*
1253 * Add a file name to the list.
1254 */
1255
1256STATIC void
1257addfname(name)
1258	char *name;
1259	{
1260	char *p;
1261	struct strlist *sp;
1262
1263	p = stalloc(strlen(name) + 1);
1264	scopy(name, p);
1265	sp = (struct strlist *)stalloc(sizeof *sp);
1266	sp->text = p;
1267	*exparg.lastp = sp;
1268	exparg.lastp = &sp->next;
1269}
1270
1271
1272/*
1273 * Sort the results of file name expansion.  It calculates the number of
1274 * strings to sort and then calls msort (short for merge sort) to do the
1275 * work.
1276 */
1277
1278STATIC struct strlist *
1279expsort(str)
1280	struct strlist *str;
1281	{
1282	int len;
1283	struct strlist *sp;
1284
1285	len = 0;
1286	for (sp = str ; sp ; sp = sp->next)
1287		len++;
1288	return msort(str, len);
1289}
1290
1291
1292STATIC struct strlist *
1293msort(list, len)
1294	struct strlist *list;
1295	int len;
1296{
1297	struct strlist *p, *q = NULL;
1298	struct strlist **lpp;
1299	int half;
1300	int n;
1301
1302	if (len <= 1)
1303		return list;
1304	half = len >> 1;
1305	p = list;
1306	for (n = half ; --n >= 0 ; ) {
1307		q = p;
1308		p = p->next;
1309	}
1310	q->next = NULL;			/* terminate first half of list */
1311	q = msort(list, half);		/* sort first half of list */
1312	p = msort(p, len - half);		/* sort second half */
1313	lpp = &list;
1314	for (;;) {
1315		if (strcmp(p->text, q->text) < 0) {
1316			*lpp = p;
1317			lpp = &p->next;
1318			if ((p = *lpp) == NULL) {
1319				*lpp = q;
1320				break;
1321			}
1322		} else {
1323			*lpp = q;
1324			lpp = &q->next;
1325			if ((q = *lpp) == NULL) {
1326				*lpp = p;
1327				break;
1328			}
1329		}
1330	}
1331	return list;
1332}
1333
1334
1335
1336/*
1337 * Returns true if the pattern matches the string.
1338 */
1339
1340int
1341patmatch(pattern, string, squoted)
1342	char *pattern;
1343	char *string;
1344	int squoted;	/* string might have quote chars */
1345	{
1346#ifdef notdef
1347	if (pattern[0] == '!' && pattern[1] == '!')
1348		return 1 - pmatch(pattern + 2, string);
1349	else
1350#endif
1351		return pmatch(pattern, string, squoted);
1352}
1353
1354
1355STATIC int
1356pmatch(pattern, string, squoted)
1357	char *pattern;
1358	char *string;
1359	int squoted;
1360	{
1361	char *p, *q;
1362	char c;
1363
1364	p = pattern;
1365	q = string;
1366	for (;;) {
1367		switch (c = *p++) {
1368		case '\0':
1369			goto breakloop;
1370		case CTLESC:
1371			if (squoted && *q == CTLESC)
1372				q++;
1373			if (*q++ != *p++)
1374				return 0;
1375			break;
1376		case CTLQUOTEMARK:
1377			continue;
1378		case '?':
1379			if (squoted && *q == CTLESC)
1380				q++;
1381			if (*q++ == '\0')
1382				return 0;
1383			break;
1384		case '*':
1385			c = *p;
1386			while (c == CTLQUOTEMARK || c == '*')
1387				c = *++p;
1388			if (c != CTLESC &&  c != CTLQUOTEMARK &&
1389			    c != '?' && c != '*' && c != '[') {
1390				while (*q != c) {
1391					if (squoted && *q == CTLESC &&
1392					    q[1] == c)
1393						break;
1394					if (*q == '\0')
1395						return 0;
1396					if (squoted && *q == CTLESC)
1397						q++;
1398					q++;
1399				}
1400			}
1401			do {
1402				if (pmatch(p, q, squoted))
1403					return 1;
1404				if (squoted && *q == CTLESC)
1405					q++;
1406			} while (*q++ != '\0');
1407			return 0;
1408		case '[': {
1409			char *endp;
1410			int invert, found;
1411			char chr;
1412
1413			endp = p;
1414			if (*endp == '!' || *endp == '^')
1415				endp++;
1416			for (;;) {
1417				while (*endp == CTLQUOTEMARK)
1418					endp++;
1419				if (*endp == '\0')
1420					goto dft;		/* no matching ] */
1421				if (*endp == CTLESC)
1422					endp++;
1423				if (*++endp == ']')
1424					break;
1425			}
1426			invert = 0;
1427			if (*p == '!' || *p == '^') {
1428				invert++;
1429				p++;
1430			}
1431			found = 0;
1432			chr = *q++;
1433			if (squoted && chr == CTLESC)
1434				chr = *q++;
1435			if (chr == '\0')
1436				return 0;
1437			c = *p++;
1438			do {
1439				if (c == CTLQUOTEMARK)
1440					continue;
1441				if (c == CTLESC)
1442					c = *p++;
1443				if (*p == '-' && p[1] != ']') {
1444					p++;
1445					while (*p == CTLQUOTEMARK)
1446						p++;
1447					if (*p == CTLESC)
1448						p++;
1449					if (   collate_range_cmp(chr, c) >= 0
1450					    && collate_range_cmp(chr, *p) <= 0
1451					   )
1452						found = 1;
1453					p++;
1454				} else {
1455					if (chr == c)
1456						found = 1;
1457				}
1458			} while ((c = *p++) != ']');
1459			if (found == invert)
1460				return 0;
1461			break;
1462		}
1463dft:	        default:
1464			if (squoted && *q == CTLESC)
1465				q++;
1466			if (*q++ != c)
1467				return 0;
1468			break;
1469		}
1470	}
1471breakloop:
1472	if (*q != '\0')
1473		return 0;
1474	return 1;
1475}
1476
1477
1478
1479/*
1480 * Remove any CTLESC characters from a string.
1481 */
1482
1483void
1484rmescapes(str)
1485	char *str;
1486{
1487	char *p, *q;
1488
1489	p = str;
1490	while (*p != CTLESC && *p != CTLQUOTEMARK) {
1491		if (*p++ == '\0')
1492			return;
1493	}
1494	q = p;
1495	while (*p) {
1496		if (*p == CTLQUOTEMARK) {
1497			p++;
1498			continue;
1499		}
1500		if (*p == CTLESC)
1501			p++;
1502		*q++ = *p++;
1503	}
1504	*q = '\0';
1505}
1506
1507
1508
1509/*
1510 * See if a pattern matches in a case statement.
1511 */
1512
1513int
1514casematch(pattern, val)
1515	union node *pattern;
1516	char *val;
1517	{
1518	struct stackmark smark;
1519	int result;
1520	char *p;
1521
1522	setstackmark(&smark);
1523	argbackq = pattern->narg.backquote;
1524	STARTSTACKSTR(expdest);
1525	ifslastp = NULL;
1526	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1527	STPUTC('\0', expdest);
1528	p = grabstackstr(expdest);
1529	result = patmatch(p, val, 0);
1530	popstackmark(&smark);
1531	return result;
1532}
1533
1534/*
1535 * Our own itoa().
1536 */
1537
1538STATIC char *
1539cvtnum(num, buf)
1540	int num;
1541	char *buf;
1542	{
1543	char temp[32];
1544	int neg = num < 0;
1545	char *p = temp + 31;
1546
1547	temp[31] = '\0';
1548
1549	do {
1550		*--p = num % 10 + '0';
1551	} while ((num /= 10) != 0);
1552
1553	if (neg)
1554		*--p = '-';
1555
1556	while (*p)
1557		STPUTC(*p++, buf);
1558	return buf;
1559}
1560