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