expand.c revision 212243
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
4207944Sjilles * Copyright (c) 1997-2005
5207944Sjilles *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
61556Srgrimes *
71556Srgrimes * This code is derived from software contributed to Berkeley by
81556Srgrimes * Kenneth Almquist.
91556Srgrimes *
101556Srgrimes * Redistribution and use in source and binary forms, with or without
111556Srgrimes * modification, are permitted provided that the following conditions
121556Srgrimes * are met:
131556Srgrimes * 1. Redistributions of source code must retain the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer.
151556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161556Srgrimes *    notice, this list of conditions and the following disclaimer in the
171556Srgrimes *    documentation and/or other materials provided with the distribution.
181556Srgrimes * 4. Neither the name of the University nor the names of its contributors
191556Srgrimes *    may be used to endorse or promote products derived from this software
201556Srgrimes *    without specific prior written permission.
211556Srgrimes *
221556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321556Srgrimes * SUCH DAMAGE.
331556Srgrimes */
341556Srgrimes
351556Srgrimes#ifndef lint
3636150Scharnier#if 0
3736150Scharnierstatic char sccsid[] = "@(#)expand.c	8.5 (Berkeley) 5/15/95";
3836150Scharnier#endif
391556Srgrimes#endif /* not lint */
4099110Sobrien#include <sys/cdefs.h>
4199110Sobrien__FBSDID("$FreeBSD: head/bin/sh/expand.c 212243 2010-09-05 21:12:48Z jilles $");
421556Srgrimes
4317987Speter#include <sys/types.h>
4417987Speter#include <sys/time.h>
4517987Speter#include <sys/stat.h>
4617987Speter#include <errno.h>
4717987Speter#include <dirent.h>
4817987Speter#include <unistd.h>
4917987Speter#include <pwd.h>
5017987Speter#include <stdlib.h>
5119281Sache#include <limits.h>
5238887Stegge#include <stdio.h>
53108286Stjr#include <string.h>
5417987Speter
551556Srgrimes/*
561556Srgrimes * Routines to expand arguments to commands.  We have to deal with
571556Srgrimes * backquotes, shell variables, and file metacharacters.
581556Srgrimes */
591556Srgrimes
601556Srgrimes#include "shell.h"
611556Srgrimes#include "main.h"
621556Srgrimes#include "nodes.h"
631556Srgrimes#include "eval.h"
641556Srgrimes#include "expand.h"
651556Srgrimes#include "syntax.h"
661556Srgrimes#include "parser.h"
671556Srgrimes#include "jobs.h"
681556Srgrimes#include "options.h"
691556Srgrimes#include "var.h"
701556Srgrimes#include "input.h"
711556Srgrimes#include "output.h"
721556Srgrimes#include "memalloc.h"
731556Srgrimes#include "error.h"
741556Srgrimes#include "mystring.h"
7517987Speter#include "arith.h"
7617987Speter#include "show.h"
771556Srgrimes
781556Srgrimes/*
791556Srgrimes * Structure specifying which parts of the string should be searched
801556Srgrimes * for IFS characters.
811556Srgrimes */
821556Srgrimes
831556Srgrimesstruct ifsregion {
841556Srgrimes	struct ifsregion *next;	/* next region in list */
851556Srgrimes	int begoff;		/* offset of start of region */
861556Srgrimes	int endoff;		/* offset of end of region */
87194975Sjilles	int inquotes;		/* search for nul bytes only */
881556Srgrimes};
891556Srgrimes
901556Srgrimes
91117261SddsSTATIC char *expdest;			/* output of current string */
92117261SddsSTATIC struct nodelist *argbackq;	/* list of back quote expressions */
93117261SddsSTATIC struct ifsregion ifsfirst;	/* first struct in list of ifs regions */
94117261SddsSTATIC struct ifsregion *ifslastp;	/* last struct in list */
95117261SddsSTATIC struct arglist exparg;		/* holds expanded arg list */
961556Srgrimes
9790111SimpSTATIC void argstr(char *, int);
9890111SimpSTATIC char *exptilde(char *, int);
9990111SimpSTATIC void expbackq(union node *, int, int);
10090111SimpSTATIC int subevalvar(char *, char *, int, int, int, int);
10190111SimpSTATIC char *evalvar(char *, int);
10290111SimpSTATIC int varisset(char *, int);
103164081SstefanfSTATIC void varvalue(char *, int, int, int);
10490111SimpSTATIC void recordregion(int, int, int);
105155301SschweikhSTATIC void removerecordregions(int);
10690111SimpSTATIC void ifsbreakup(char *, struct arglist *);
10790111SimpSTATIC void expandmeta(struct strlist *, int);
10890111SimpSTATIC void expmeta(char *, char *);
10990111SimpSTATIC void addfname(char *);
11090111SimpSTATIC struct strlist *expsort(struct strlist *);
11190111SimpSTATIC struct strlist *msort(struct strlist *, int);
11290111SimpSTATIC char *cvtnum(int, char *);
11390111SimpSTATIC int collate_range_cmp(int, int);
1141556Srgrimes
11590111SimpSTATIC int
116118374Sachecollate_range_cmp(int c1, int c2)
11719281Sache{
11819281Sache	static char s1[2], s2[2];
11919281Sache
12019281Sache	s1[0] = c1;
12119281Sache	s2[0] = c2;
122118374Sache	return (strcoll(s1, s2));
12319281Sache}
12419281Sache
1251556Srgrimes/*
1261556Srgrimes * Expand shell variables and backquotes inside a here document.
12790111Simp *	union node *arg		the document
12890111Simp *	int fd;			where to write the expanded version
1291556Srgrimes */
1301556Srgrimes
1311556Srgrimesvoid
13290111Simpexpandhere(union node *arg, int fd)
13390111Simp{
1341556Srgrimes	herefd = fd;
1351556Srgrimes	expandarg(arg, (struct arglist *)NULL, 0);
13639137Stegge	xwrite(fd, stackblock(), expdest - stackblock());
1371556Srgrimes}
1381556Srgrimes
1391556Srgrimes
1401556Srgrimes/*
141212243Sjilles * Perform expansions on an argument, placing the resulting list of arguments
142212243Sjilles * in arglist.  Parameter expansion, command substitution and arithmetic
143212243Sjilles * expansion are always performed; additional expansions can be requested
144212243Sjilles * via flag (EXP_*).
145212243Sjilles * The result is left in the stack string.
146212243Sjilles * When arglist is NULL, perform here document expansion.  A partial result
147212243Sjilles * may be written to herefd, which is then not included in the stack string.
148212243Sjilles *
149212243Sjilles * Caution: this function uses global state and is not reentrant.
150212243Sjilles * However, a new invocation after an interrupted invocation is safe
151212243Sjilles * and will reset the global state for the new call.
1521556Srgrimes */
1531556Srgrimesvoid
15490111Simpexpandarg(union node *arg, struct arglist *arglist, int flag)
15517987Speter{
1561556Srgrimes	struct strlist *sp;
1571556Srgrimes	char *p;
1581556Srgrimes
1591556Srgrimes	argbackq = arg->narg.backquote;
1601556Srgrimes	STARTSTACKSTR(expdest);
1611556Srgrimes	ifsfirst.next = NULL;
1621556Srgrimes	ifslastp = NULL;
1631556Srgrimes	argstr(arg->narg.text, flag);
1641556Srgrimes	if (arglist == NULL) {
1651556Srgrimes		return;			/* here document expanded */
1661556Srgrimes	}
1671556Srgrimes	STPUTC('\0', expdest);
1681556Srgrimes	p = grabstackstr(expdest);
1691556Srgrimes	exparg.lastp = &exparg.list;
1701556Srgrimes	/*
1711556Srgrimes	 * TODO - EXP_REDIR
1721556Srgrimes	 */
1731556Srgrimes	if (flag & EXP_FULL) {
1741556Srgrimes		ifsbreakup(p, &exparg);
1751556Srgrimes		*exparg.lastp = NULL;
1761556Srgrimes		exparg.lastp = &exparg.list;
1771556Srgrimes		expandmeta(exparg.list, flag);
1781556Srgrimes	} else {
1791556Srgrimes		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
1801556Srgrimes			rmescapes(p);
1811556Srgrimes		sp = (struct strlist *)stalloc(sizeof (struct strlist));
1821556Srgrimes		sp->text = p;
1831556Srgrimes		*exparg.lastp = sp;
1841556Srgrimes		exparg.lastp = &sp->next;
1851556Srgrimes	}
1861556Srgrimes	while (ifsfirst.next != NULL) {
1871556Srgrimes		struct ifsregion *ifsp;
1881556Srgrimes		INTOFF;
1891556Srgrimes		ifsp = ifsfirst.next->next;
1901556Srgrimes		ckfree(ifsfirst.next);
1911556Srgrimes		ifsfirst.next = ifsp;
1921556Srgrimes		INTON;
1931556Srgrimes	}
1941556Srgrimes	*exparg.lastp = NULL;
1951556Srgrimes	if (exparg.list) {
1961556Srgrimes		*arglist->lastp = exparg.list;
1971556Srgrimes		arglist->lastp = exparg.lastp;
1981556Srgrimes	}
1991556Srgrimes}
2001556Srgrimes
2011556Srgrimes
2021556Srgrimes
2031556Srgrimes/*
204212243Sjilles * Perform parameter expansion, command substitution and arithmetic
205212243Sjilles * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
206212243Sjilles * Processing ends at a CTLENDVAR character as well as '\0'.
207212243Sjilles * This is used to expand word in ${var+word} etc.
208212243Sjilles * If EXP_FULL, EXP_CASE or EXP_REDIR are set, keep and/or generate CTLESC
209212243Sjilles * characters to allow for further processing.
210212243Sjilles * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
2111556Srgrimes */
2121556SrgrimesSTATIC void
21390111Simpargstr(char *p, int flag)
21417987Speter{
21525233Ssteve	char c;
216104672Stjr	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);	/* do CTLESC */
2171556Srgrimes	int firsteq = 1;
2181556Srgrimes
2191556Srgrimes	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
2201556Srgrimes		p = exptilde(p, flag);
2211556Srgrimes	for (;;) {
2221556Srgrimes		switch (c = *p++) {
2231556Srgrimes		case '\0':
224212243Sjilles		case CTLENDVAR:
2251556Srgrimes			goto breakloop;
22638887Stegge		case CTLQUOTEMARK:
22738887Stegge			/* "$@" syntax adherence hack */
22838887Stegge			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
22938887Stegge				break;
23039137Stegge			if ((flag & EXP_FULL) != 0)
23139137Stegge				STPUTC(c, expdest);
23238887Stegge			break;
2331556Srgrimes		case CTLESC:
2341556Srgrimes			if (quotes)
2351556Srgrimes				STPUTC(c, expdest);
2361556Srgrimes			c = *p++;
2371556Srgrimes			STPUTC(c, expdest);
2381556Srgrimes			break;
2391556Srgrimes		case CTLVAR:
2401556Srgrimes			p = evalvar(p, flag);
2411556Srgrimes			break;
2421556Srgrimes		case CTLBACKQ:
2431556Srgrimes		case CTLBACKQ|CTLQUOTE:
2441556Srgrimes			expbackq(argbackq->n, c & CTLQUOTE, flag);
2451556Srgrimes			argbackq = argbackq->next;
2461556Srgrimes			break;
2471556Srgrimes		case CTLENDARI:
2481556Srgrimes			expari(flag);
2491556Srgrimes			break;
2501556Srgrimes		case ':':
2511556Srgrimes		case '=':
2521556Srgrimes			/*
2531556Srgrimes			 * sort of a hack - expand tildes in variable
2541556Srgrimes			 * assignments (after the first '=' and after ':'s).
2551556Srgrimes			 */
2561556Srgrimes			STPUTC(c, expdest);
2571556Srgrimes			if (flag & EXP_VARTILDE && *p == '~') {
2581556Srgrimes				if (c == '=') {
2591556Srgrimes					if (firsteq)
2601556Srgrimes						firsteq = 0;
2611556Srgrimes					else
2621556Srgrimes						break;
2631556Srgrimes				}
2641556Srgrimes				p = exptilde(p, flag);
2651556Srgrimes			}
2661556Srgrimes			break;
2671556Srgrimes		default:
2681556Srgrimes			STPUTC(c, expdest);
2691556Srgrimes		}
2701556Srgrimes	}
2711556Srgrimesbreakloop:;
2721556Srgrimes}
2731556Srgrimes
274212243Sjilles/*
275212243Sjilles * Perform tilde expansion, placing the result in the stack string and
276212243Sjilles * returning the next position in the input string to process.
277212243Sjilles */
2781556SrgrimesSTATIC char *
27990111Simpexptilde(char *p, int flag)
28017987Speter{
2811556Srgrimes	char c, *startp = p;
2821556Srgrimes	struct passwd *pw;
2831556Srgrimes	char *home;
284108935Stjr	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
2851556Srgrimes
28617987Speter	while ((c = *p) != '\0') {
2871556Srgrimes		switch(c) {
288200988Sjilles		case CTLESC: /* This means CTL* are always considered quoted. */
289200988Sjilles		case CTLVAR:
290200988Sjilles		case CTLBACKQ:
291200988Sjilles		case CTLBACKQ | CTLQUOTE:
292200988Sjilles		case CTLARI:
293200988Sjilles		case CTLENDARI:
29439137Stegge		case CTLQUOTEMARK:
29539137Stegge			return (startp);
2961556Srgrimes		case ':':
2971556Srgrimes			if (flag & EXP_VARTILDE)
2981556Srgrimes				goto done;
2991556Srgrimes			break;
3001556Srgrimes		case '/':
301206150Sjilles		case CTLENDVAR:
3021556Srgrimes			goto done;
3031556Srgrimes		}
3041556Srgrimes		p++;
3051556Srgrimes	}
3061556Srgrimesdone:
3071556Srgrimes	*p = '\0';
3081556Srgrimes	if (*(startp+1) == '\0') {
3091556Srgrimes		if ((home = lookupvar("HOME")) == NULL)
3101556Srgrimes			goto lose;
3111556Srgrimes	} else {
3121556Srgrimes		if ((pw = getpwnam(startp+1)) == NULL)
3131556Srgrimes			goto lose;
3141556Srgrimes		home = pw->pw_dir;
3151556Srgrimes	}
3161556Srgrimes	if (*home == '\0')
3171556Srgrimes		goto lose;
3181556Srgrimes	*p = c;
31917987Speter	while ((c = *home++) != '\0') {
32083675Stegge		if (quotes && SQSYNTAX[(int)c] == CCTL)
3211556Srgrimes			STPUTC(CTLESC, expdest);
3221556Srgrimes		STPUTC(c, expdest);
3231556Srgrimes	}
3241556Srgrimes	return (p);
3251556Srgrimeslose:
3261556Srgrimes	*p = c;
3271556Srgrimes	return (startp);
3281556Srgrimes}
3291556Srgrimes
3301556Srgrimes
331155301SschweikhSTATIC void
33290111Simpremoverecordregions(int endoff)
33338887Stegge{
33438887Stegge	if (ifslastp == NULL)
33538887Stegge		return;
33638887Stegge
33738887Stegge	if (ifsfirst.endoff > endoff) {
33838887Stegge		while (ifsfirst.next != NULL) {
33938887Stegge			struct ifsregion *ifsp;
34038887Stegge			INTOFF;
34138887Stegge			ifsp = ifsfirst.next->next;
34238887Stegge			ckfree(ifsfirst.next);
34338887Stegge			ifsfirst.next = ifsp;
34438887Stegge			INTON;
34538887Stegge		}
34638887Stegge		if (ifsfirst.begoff > endoff)
34738887Stegge			ifslastp = NULL;
34838887Stegge		else {
34938887Stegge			ifslastp = &ifsfirst;
35038887Stegge			ifsfirst.endoff = endoff;
35138887Stegge		}
35238887Stegge		return;
35338887Stegge	}
354155301Sschweikh
35538887Stegge	ifslastp = &ifsfirst;
35638887Stegge	while (ifslastp->next && ifslastp->next->begoff < endoff)
35738887Stegge		ifslastp=ifslastp->next;
35838887Stegge	while (ifslastp->next != NULL) {
35938887Stegge		struct ifsregion *ifsp;
36038887Stegge		INTOFF;
36138887Stegge		ifsp = ifslastp->next->next;
36238887Stegge		ckfree(ifslastp->next);
36338887Stegge		ifslastp->next = ifsp;
36438887Stegge		INTON;
36538887Stegge	}
36638887Stegge	if (ifslastp->endoff > endoff)
36738887Stegge		ifslastp->endoff = endoff;
36838887Stegge}
36938887Stegge
3701556Srgrimes/*
3711556Srgrimes * Expand arithmetic expression.  Backup to start of expression,
3721556Srgrimes * evaluate, place result in (backed up) result, adjust string position.
3731556Srgrimes */
3741556Srgrimesvoid
37590111Simpexpari(int flag)
37617987Speter{
377207206Sjilles	char *p, *q, *start;
378178631Sstefanf	arith_t result;
37938887Stegge	int begoff;
380108935Stjr	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
38138887Stegge	int quoted;
3821556Srgrimes
3831556Srgrimes	/*
38446684Skris	 * This routine is slightly over-complicated for
3851556Srgrimes	 * efficiency.  First we make sure there is
3861556Srgrimes	 * enough space for the result, which may be bigger
387212243Sjilles	 * than the expression.  Next we
3881556Srgrimes	 * scan backwards looking for the start of arithmetic.  If the
3891556Srgrimes	 * next previous character is a CTLESC character, then we
3901556Srgrimes	 * have to rescan starting from the beginning since CTLESC
3918855Srgrimes	 * characters have to be processed left to right.
3921556Srgrimes	 */
393178631Sstefanf	CHECKSTRSPACE(DIGITS(result) - 2, expdest);
3948855Srgrimes	USTPUTC('\0', expdest);
3951556Srgrimes	start = stackblock();
39683676Stegge	p = expdest - 2;
39783676Stegge	while (p >= start && *p != CTLARI)
3981556Srgrimes		--p;
39983676Stegge	if (p < start || *p != CTLARI)
4001556Srgrimes		error("missing CTLARI (shouldn't happen)");
40183676Stegge	if (p > start && *(p - 1) == CTLESC)
4021556Srgrimes		for (p = start; *p != CTLARI; p++)
4031556Srgrimes			if (*p == CTLESC)
4041556Srgrimes				p++;
40538887Stegge
40638887Stegge	if (p[1] == '"')
40738887Stegge		quoted=1;
40838887Stegge	else
40938887Stegge		quoted=0;
41038887Stegge	begoff = p - start;
41138887Stegge	removerecordregions(begoff);
4121556Srgrimes	if (quotes)
41338887Stegge		rmescapes(p+2);
414207206Sjilles	q = grabstackstr(expdest);
41538887Stegge	result = arith(p+2);
416207206Sjilles	ungrabstackstr(q, expdest);
417178631Sstefanf	fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
4181556Srgrimes	while (*p++)
4191556Srgrimes		;
42038887Stegge	if (quoted == 0)
42138887Stegge		recordregion(begoff, p - 1 - start, 0);
4221556Srgrimes	result = expdest - p + 1;
4231556Srgrimes	STADJUST(-result, expdest);
4241556Srgrimes}
4251556Srgrimes
4261556Srgrimes
4271556Srgrimes/*
428212243Sjilles * Perform command substitution.
4291556Srgrimes */
4301556SrgrimesSTATIC void
43190111Simpexpbackq(union node *cmd, int quoted, int flag)
43217987Speter{
4331556Srgrimes	struct backcmd in;
4341556Srgrimes	int i;
4351556Srgrimes	char buf[128];
4361556Srgrimes	char *p;
4371556Srgrimes	char *dest = expdest;
4381556Srgrimes	struct ifsregion saveifs, *savelastp;
4391556Srgrimes	struct nodelist *saveargbackq;
4401556Srgrimes	char lastc;
4411556Srgrimes	int startloc = dest - stackblock();
4421556Srgrimes	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4431556Srgrimes	int saveherefd;
444108935Stjr	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
445115424Sfenner	int nnl;
4461556Srgrimes
4471556Srgrimes	INTOFF;
4481556Srgrimes	saveifs = ifsfirst;
4491556Srgrimes	savelastp = ifslastp;
4501556Srgrimes	saveargbackq = argbackq;
4518855Srgrimes	saveherefd = herefd;
4521556Srgrimes	herefd = -1;
4531556Srgrimes	p = grabstackstr(dest);
4541556Srgrimes	evalbackcmd(cmd, &in);
4551556Srgrimes	ungrabstackstr(p, dest);
4561556Srgrimes	ifsfirst = saveifs;
4571556Srgrimes	ifslastp = savelastp;
4581556Srgrimes	argbackq = saveargbackq;
4591556Srgrimes	herefd = saveherefd;
4601556Srgrimes
4611556Srgrimes	p = in.buf;
4621556Srgrimes	lastc = '\0';
463115424Sfenner	nnl = 0;
464115424Sfenner	/* Don't copy trailing newlines */
4651556Srgrimes	for (;;) {
4661556Srgrimes		if (--in.nleft < 0) {
4671556Srgrimes			if (in.fd < 0)
4681556Srgrimes				break;
4691556Srgrimes			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
4701556Srgrimes			TRACE(("expbackq: read returns %d\n", i));
4711556Srgrimes			if (i <= 0)
4721556Srgrimes				break;
4731556Srgrimes			p = buf;
4741556Srgrimes			in.nleft = i - 1;
4751556Srgrimes		}
4761556Srgrimes		lastc = *p++;
4771556Srgrimes		if (lastc != '\0') {
47883675Stegge			if (quotes && syntax[(int)lastc] == CCTL)
4791556Srgrimes				STPUTC(CTLESC, dest);
480115424Sfenner			if (lastc == '\n') {
481115424Sfenner				nnl++;
482115424Sfenner			} else {
483115424Sfenner				while (nnl > 0) {
484115424Sfenner					nnl--;
485115424Sfenner					STPUTC('\n', dest);
486115424Sfenner				}
487115424Sfenner				STPUTC(lastc, dest);
488115424Sfenner			}
4891556Srgrimes		}
4901556Srgrimes	}
49117987Speter
4921556Srgrimes	if (in.fd >= 0)
4931556Srgrimes		close(in.fd);
4941556Srgrimes	if (in.buf)
4951556Srgrimes		ckfree(in.buf);
4961556Srgrimes	if (in.jp)
49745916Scracauer		exitstatus = waitforjob(in.jp, (int *)NULL);
4981556Srgrimes	if (quoted == 0)
4991556Srgrimes		recordregion(startloc, dest - stackblock(), 0);
5001556Srgrimes	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5011556Srgrimes		(dest - stackblock()) - startloc,
5021556Srgrimes		(dest - stackblock()) - startloc,
5031556Srgrimes		stackblock() + startloc));
5041556Srgrimes	expdest = dest;
5051556Srgrimes	INTON;
5061556Srgrimes}
5071556Srgrimes
5081556Srgrimes
5091556Srgrimes
51017987SpeterSTATIC int
51190111Simpsubevalvar(char *p, char *str, int strloc, int subtype, int startloc,
51290111Simp  int varflags)
51317987Speter{
51417987Speter	char *startp;
51517987Speter	char *loc = NULL;
51645514Stegge	char *q;
51717987Speter	int c = 0;
51817987Speter	int saveherefd = herefd;
51917987Speter	struct nodelist *saveargbackq = argbackq;
52020425Ssteve	int amount;
52120425Ssteve
52217987Speter	herefd = -1;
523206150Sjilles	argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
524206147Sjilles	    subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ?
525206150Sjilles	    EXP_CASE : 0) | EXP_TILDE);
52617987Speter	STACKSTRNUL(expdest);
52717987Speter	herefd = saveherefd;
52817987Speter	argbackq = saveargbackq;
52917987Speter	startp = stackblock() + startloc;
53020425Ssteve	if (str == NULL)
53120425Ssteve	    str = stackblock() + strloc;
53217987Speter
53317987Speter	switch (subtype) {
53417987Speter	case VSASSIGN:
53517987Speter		setvar(str, startp, 0);
53620425Ssteve		amount = startp - expdest;
53720425Ssteve		STADJUST(amount, expdest);
53817987Speter		varflags &= ~VSNUL;
53917987Speter		if (c != 0)
54017987Speter			*loc = c;
54117987Speter		return 1;
54217987Speter
54317987Speter	case VSQUESTION:
54417987Speter		if (*p != CTLENDVAR) {
545201366Sjilles			outfmt(out2, "%s\n", startp);
54617987Speter			error((char *)NULL);
54717987Speter		}
548112254Sru		error("%.*s: parameter %snot set", (int)(p - str - 1),
54917987Speter		      str, (varflags & VSNUL) ? "null or "
55017987Speter					      : nullstr);
55117987Speter		return 0;
55217987Speter
55317987Speter	case VSTRIMLEFT:
55425233Ssteve		for (loc = startp; loc < str; loc++) {
55517987Speter			c = *loc;
55617987Speter			*loc = '\0';
55745514Stegge			if (patmatch(str, startp, varflags & VSQUOTE)) {
55817987Speter				*loc = c;
55917987Speter				goto recordleft;
56017987Speter			}
56117987Speter			*loc = c;
56245514Stegge			if ((varflags & VSQUOTE) && *loc == CTLESC)
56345514Stegge				loc++;
56417987Speter		}
56517987Speter		return 0;
56617987Speter
56717987Speter	case VSTRIMLEFTMAX:
56845514Stegge		for (loc = str - 1; loc >= startp;) {
56917987Speter			c = *loc;
57017987Speter			*loc = '\0';
57145514Stegge			if (patmatch(str, startp, varflags & VSQUOTE)) {
57217987Speter				*loc = c;
57317987Speter				goto recordleft;
57417987Speter			}
57517987Speter			*loc = c;
57645514Stegge			loc--;
57745514Stegge			if ((varflags & VSQUOTE) && loc > startp &&
57845514Stegge			    *(loc - 1) == CTLESC) {
57945514Stegge				for (q = startp; q < loc; q++)
58045514Stegge					if (*q == CTLESC)
58145514Stegge						q++;
58245514Stegge				if (q > loc)
58345514Stegge					loc--;
58445514Stegge			}
58517987Speter		}
58617987Speter		return 0;
58717987Speter
58817987Speter	case VSTRIMRIGHT:
58945514Stegge		for (loc = str - 1; loc >= startp;) {
59045514Stegge			if (patmatch(str, loc, varflags & VSQUOTE)) {
59120425Ssteve				amount = loc - expdest;
59220425Ssteve				STADJUST(amount, expdest);
59317987Speter				return 1;
59417987Speter			}
59545514Stegge			loc--;
59645514Stegge			if ((varflags & VSQUOTE) && loc > startp &&
597155301Sschweikh			    *(loc - 1) == CTLESC) {
59845514Stegge				for (q = startp; q < loc; q++)
59945514Stegge					if (*q == CTLESC)
60045514Stegge						q++;
60145514Stegge				if (q > loc)
60245514Stegge					loc--;
60345514Stegge			}
60417987Speter		}
60517987Speter		return 0;
60617987Speter
60717987Speter	case VSTRIMRIGHTMAX:
60817987Speter		for (loc = startp; loc < str - 1; loc++) {
60945514Stegge			if (patmatch(str, loc, varflags & VSQUOTE)) {
61020425Ssteve				amount = loc - expdest;
61120425Ssteve				STADJUST(amount, expdest);
61217987Speter				return 1;
61317987Speter			}
61445514Stegge			if ((varflags & VSQUOTE) && *loc == CTLESC)
61545514Stegge				loc++;
61617987Speter		}
61717987Speter		return 0;
61817987Speter
61917987Speter
62017987Speter	default:
62117987Speter		abort();
62217987Speter	}
62317987Speter
62417987Speterrecordleft:
62520425Ssteve	amount = ((str - 1) - (loc - startp)) - expdest;
62620425Ssteve	STADJUST(amount, expdest);
62717987Speter	while (loc != str - 1)
62817987Speter		*startp++ = *loc++;
62917987Speter	return 1;
63017987Speter}
63117987Speter
63217987Speter
6331556Srgrimes/*
6341556Srgrimes * Expand a variable, and return a pointer to the next character in the
6351556Srgrimes * input string.
6361556Srgrimes */
6371556Srgrimes
6381556SrgrimesSTATIC char *
63990111Simpevalvar(char *p, int flag)
64017987Speter{
6411556Srgrimes	int subtype;
6421556Srgrimes	int varflags;
6431556Srgrimes	char *var;
6441556Srgrimes	char *val;
64545644Stegge	int patloc;
6461556Srgrimes	int c;
6471556Srgrimes	int set;
6481556Srgrimes	int special;
6491556Srgrimes	int startloc;
65017987Speter	int varlen;
65117987Speter	int easy;
652108935Stjr	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
6531556Srgrimes
654164081Sstefanf	varflags = (unsigned char)*p++;
6551556Srgrimes	subtype = varflags & VSTYPE;
6561556Srgrimes	var = p;
6571556Srgrimes	special = 0;
6581556Srgrimes	if (! is_name(*p))
6591556Srgrimes		special = 1;
6601556Srgrimes	p = strchr(p, '=') + 1;
6611556Srgrimesagain: /* jump here after setting a variable with ${var=text} */
662179022Sstefanf	if (varflags & VSLINENO) {
663179022Sstefanf		set = 1;
664179022Sstefanf		special = 0;
665179022Sstefanf		val = var;
666179022Sstefanf		p[-1] = '\0';	/* temporarily overwrite '=' to have \0
667179022Sstefanf				   terminated string */
668179022Sstefanf	} else if (special) {
66925233Ssteve		set = varisset(var, varflags & VSNUL);
6701556Srgrimes		val = NULL;
6711556Srgrimes	} else {
67260592Scracauer		val = bltinlookup(var, 1);
67317987Speter		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
6741556Srgrimes			val = NULL;
6751556Srgrimes			set = 0;
6761556Srgrimes		} else
6771556Srgrimes			set = 1;
6781556Srgrimes	}
67917987Speter	varlen = 0;
6801556Srgrimes	startloc = expdest - stackblock();
681198454Sjilles	if (!set && uflag && *var != '@' && *var != '*') {
68296939Stjr		switch (subtype) {
68396939Stjr		case VSNORMAL:
68496939Stjr		case VSTRIMLEFT:
68596939Stjr		case VSTRIMLEFTMAX:
68696939Stjr		case VSTRIMRIGHT:
68796939Stjr		case VSTRIMRIGHTMAX:
68896939Stjr		case VSLENGTH:
689112254Sru			error("%.*s: parameter not set", (int)(p - var - 1),
690112254Sru			    var);
69196939Stjr		}
69296939Stjr	}
6931556Srgrimes	if (set && subtype != VSPLUS) {
6941556Srgrimes		/* insert the value of the variable */
6951556Srgrimes		if (special) {
696164081Sstefanf			varvalue(var, varflags & VSQUOTE, subtype, flag);
69717987Speter			if (subtype == VSLENGTH) {
69825233Ssteve				varlen = expdest - stackblock() - startloc;
69925233Ssteve				STADJUST(-varlen, expdest);
70017987Speter			}
7011556Srgrimes		} else {
70220425Ssteve			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
70317987Speter								  : BASESYNTAX;
7041556Srgrimes
70517987Speter			if (subtype == VSLENGTH) {
70617987Speter				for (;*val; val++)
70717987Speter					varlen++;
7081556Srgrimes			}
70917987Speter			else {
71017987Speter				while (*val) {
71183675Stegge					if (quotes &&
71254132Scracauer					    syntax[(int)*val] == CCTL)
71317987Speter						STPUTC(CTLESC, expdest);
71417987Speter					STPUTC(*val++, expdest);
71517987Speter				}
71617987Speter
71717987Speter			}
7181556Srgrimes		}
7191556Srgrimes	}
72020425Ssteve
7211556Srgrimes	if (subtype == VSPLUS)
7221556Srgrimes		set = ! set;
72317987Speter
72420425Ssteve	easy = ((varflags & VSQUOTE) == 0 ||
72517987Speter		(*var == '@' && shellparam.nparam != 1));
72617987Speter
72717987Speter
72817987Speter	switch (subtype) {
72917987Speter	case VSLENGTH:
73017987Speter		expdest = cvtnum(varlen, expdest);
73117987Speter		goto record;
73217987Speter
73317987Speter	case VSNORMAL:
73417987Speter		if (!easy)
73517987Speter			break;
73617987Speterrecord:
73720425Ssteve		recordregion(startloc, expdest - stackblock(),
73817987Speter			     varflags & VSQUOTE);
73917987Speter		break;
74017987Speter
74117987Speter	case VSPLUS:
74217987Speter	case VSMINUS:
74317987Speter		if (!set) {
7441556Srgrimes			argstr(p, flag);
74517987Speter			break;
74617987Speter		}
74717987Speter		if (easy)
74817987Speter			goto record;
74917987Speter		break;
75017987Speter
75117987Speter	case VSTRIMLEFT:
75217987Speter	case VSTRIMLEFTMAX:
75317987Speter	case VSTRIMRIGHT:
75417987Speter	case VSTRIMRIGHTMAX:
75517987Speter		if (!set)
75617987Speter			break;
75717987Speter		/*
75817987Speter		 * Terminate the string and start recording the pattern
75917987Speter		 * right after it
76017987Speter		 */
76117987Speter		STPUTC('\0', expdest);
76245644Stegge		patloc = expdest - stackblock();
76345644Stegge		if (subevalvar(p, NULL, patloc, subtype,
76438887Stegge			       startloc, varflags) == 0) {
76545644Stegge			int amount = (expdest - stackblock() - patloc) + 1;
76625233Ssteve			STADJUST(-amount, expdest);
76725233Ssteve		}
76838887Stegge		/* Remove any recorded regions beyond start of variable */
76938887Stegge		removerecordregions(startloc);
77038887Stegge		goto record;
77117987Speter
77217987Speter	case VSASSIGN:
77317987Speter	case VSQUESTION:
77417987Speter		if (!set) {
77520425Ssteve			if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
77620425Ssteve				varflags &= ~VSNUL;
777155301Sschweikh				/*
778155301Sschweikh				 * Remove any recorded regions beyond
779155301Sschweikh				 * start of variable
78038887Stegge				 */
78138887Stegge				removerecordregions(startloc);
7821556Srgrimes				goto again;
78320425Ssteve			}
78417987Speter			break;
7851556Srgrimes		}
78617987Speter		if (easy)
78717987Speter			goto record;
78817987Speter		break;
78917987Speter
790164003Sstefanf	case VSERROR:
791164003Sstefanf		c = p - var - 1;
792164003Sstefanf		error("${%.*s%s}: Bad substitution", c, var,
793164003Sstefanf		    (c > 0 && *p != CTLENDVAR) ? "..." : "");
794164003Sstefanf
79517987Speter	default:
79617987Speter		abort();
7971556Srgrimes	}
798179022Sstefanf	p[-1] = '=';	/* recover overwritten '=' */
79917987Speter
8001556Srgrimes	if (subtype != VSNORMAL) {	/* skip to end of alternative */
8011556Srgrimes		int nesting = 1;
8021556Srgrimes		for (;;) {
8031556Srgrimes			if ((c = *p++) == CTLESC)
8041556Srgrimes				p++;
8051556Srgrimes			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
8061556Srgrimes				if (set)
8071556Srgrimes					argbackq = argbackq->next;
8081556Srgrimes			} else if (c == CTLVAR) {
8091556Srgrimes				if ((*p++ & VSTYPE) != VSNORMAL)
8101556Srgrimes					nesting++;
8111556Srgrimes			} else if (c == CTLENDVAR) {
8121556Srgrimes				if (--nesting == 0)
8131556Srgrimes					break;
8141556Srgrimes			}
8151556Srgrimes		}
8161556Srgrimes	}
8171556Srgrimes	return p;
8181556Srgrimes}
8191556Srgrimes
8201556Srgrimes
8211556Srgrimes
8221556Srgrimes/*
8231556Srgrimes * Test whether a specialized variable is set.
8241556Srgrimes */
8251556Srgrimes
8261556SrgrimesSTATIC int
82790111Simpvarisset(char *name, int nulok)
82825233Ssteve{
8291556Srgrimes
83025233Ssteve	if (*name == '!')
831209600Sjilles		return backgndpidset();
83225233Ssteve	else if (*name == '@' || *name == '*') {
8331556Srgrimes		if (*shellparam.p == NULL)
8341556Srgrimes			return 0;
83525233Ssteve
83625233Ssteve		if (nulok) {
83725233Ssteve			char **av;
83825233Ssteve
83925233Ssteve			for (av = shellparam.p; *av; av++)
84025233Ssteve				if (**av != '\0')
84125233Ssteve					return 1;
84225233Ssteve			return 0;
84325233Ssteve		}
84418202Speter	} else if (is_digit(*name)) {
84525233Ssteve		char *ap;
84620425Ssteve		int num = atoi(name);
84725233Ssteve
84825233Ssteve		if (num > shellparam.nparam)
84925233Ssteve			return 0;
85025233Ssteve
85125233Ssteve		if (num == 0)
85225233Ssteve			ap = arg0;
85325233Ssteve		else
85425233Ssteve			ap = shellparam.p[num - 1];
85525233Ssteve
85625233Ssteve		if (nulok && (ap == NULL || *ap == '\0'))
85725233Ssteve			return 0;
8581556Srgrimes	}
8591556Srgrimes	return 1;
8601556Srgrimes}
8611556Srgrimes
8621556Srgrimes
8631556Srgrimes
8641556Srgrimes/*
8651556Srgrimes * Add the value of a specialized variable to the stack string.
8661556Srgrimes */
8671556Srgrimes
8681556SrgrimesSTATIC void
869164081Sstefanfvarvalue(char *name, int quoted, int subtype, int flag)
87017987Speter{
8711556Srgrimes	int num;
8721556Srgrimes	char *p;
8731556Srgrimes	int i;
8741556Srgrimes	char sep;
8751556Srgrimes	char **ap;
8761556Srgrimes	char const *syntax;
8771556Srgrimes
8781556Srgrimes#define STRTODEST(p) \
8791556Srgrimes	do {\
880164081Sstefanf	if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
8811556Srgrimes		syntax = quoted? DQSYNTAX : BASESYNTAX; \
8821556Srgrimes		while (*p) { \
88383675Stegge			if (syntax[(int)*p] == CCTL) \
8841556Srgrimes				STPUTC(CTLESC, expdest); \
8851556Srgrimes			STPUTC(*p++, expdest); \
8861556Srgrimes		} \
8871556Srgrimes	} else \
8881556Srgrimes		while (*p) \
8891556Srgrimes			STPUTC(*p++, expdest); \
8901556Srgrimes	} while (0)
8911556Srgrimes
8921556Srgrimes
89318202Speter	switch (*name) {
8941556Srgrimes	case '$':
8951556Srgrimes		num = rootpid;
8961556Srgrimes		goto numvar;
8971556Srgrimes	case '?':
89817987Speter		num = oexitstatus;
8991556Srgrimes		goto numvar;
9001556Srgrimes	case '#':
9011556Srgrimes		num = shellparam.nparam;
9021556Srgrimes		goto numvar;
9031556Srgrimes	case '!':
904209600Sjilles		num = backgndpidval();
9051556Srgrimesnumvar:
90617987Speter		expdest = cvtnum(num, expdest);
9071556Srgrimes		break;
9081556Srgrimes	case '-':
9091556Srgrimes		for (i = 0 ; i < NOPTS ; i++) {
9101556Srgrimes			if (optlist[i].val)
9111556Srgrimes				STPUTC(optlist[i].letter, expdest);
9121556Srgrimes		}
9131556Srgrimes		break;
9141556Srgrimes	case '@':
915164081Sstefanf		if (flag & EXP_FULL && quoted) {
91638887Stegge			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
91738887Stegge				STRTODEST(p);
91838887Stegge				if (*ap)
91938887Stegge					STPUTC('\0', expdest);
92038887Stegge			}
92138887Stegge			break;
9221556Srgrimes		}
923102410Scharnier		/* FALLTHROUGH */
9241556Srgrimes	case '*':
925149825Srse		if (ifsset())
92638887Stegge			sep = ifsval()[0];
92738887Stegge		else
92838887Stegge			sep = ' ';
9291556Srgrimes		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
9301556Srgrimes			STRTODEST(p);
93138887Stegge			if (*ap && sep)
9321556Srgrimes				STPUTC(sep, expdest);
9331556Srgrimes		}
9341556Srgrimes		break;
9351556Srgrimes	case '0':
9361556Srgrimes		p = arg0;
9371556Srgrimes		STRTODEST(p);
9381556Srgrimes		break;
9391556Srgrimes	default:
94018202Speter		if (is_digit(*name)) {
94118202Speter			num = atoi(name);
94218202Speter			if (num > 0 && num <= shellparam.nparam) {
94318202Speter				p = shellparam.p[num - 1];
94418202Speter				STRTODEST(p);
94518202Speter			}
9461556Srgrimes		}
9471556Srgrimes		break;
9481556Srgrimes	}
9491556Srgrimes}
9501556Srgrimes
9511556Srgrimes
9521556Srgrimes
9531556Srgrimes/*
9541556Srgrimes * Record the the fact that we have to scan this region of the
9551556Srgrimes * string for IFS characters.
9561556Srgrimes */
9571556Srgrimes
9581556SrgrimesSTATIC void
959194975Sjillesrecordregion(int start, int end, int inquotes)
96017987Speter{
96125233Ssteve	struct ifsregion *ifsp;
9621556Srgrimes
9631556Srgrimes	if (ifslastp == NULL) {
9641556Srgrimes		ifsp = &ifsfirst;
9651556Srgrimes	} else {
966194975Sjilles		if (ifslastp->endoff == start
967194975Sjilles		    && ifslastp->inquotes == inquotes) {
968194975Sjilles			/* extend previous area */
969194975Sjilles			ifslastp->endoff = end;
970194975Sjilles			return;
971194975Sjilles		}
9721556Srgrimes		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
9731556Srgrimes		ifslastp->next = ifsp;
9741556Srgrimes	}
9751556Srgrimes	ifslastp = ifsp;
9761556Srgrimes	ifslastp->next = NULL;
9771556Srgrimes	ifslastp->begoff = start;
9781556Srgrimes	ifslastp->endoff = end;
979194975Sjilles	ifslastp->inquotes = inquotes;
9801556Srgrimes}
9811556Srgrimes
9821556Srgrimes
9831556Srgrimes
9841556Srgrimes/*
9851556Srgrimes * Break the argument string into pieces based upon IFS and add the
9861556Srgrimes * strings to the argument list.  The regions of the string to be
9871556Srgrimes * searched for IFS characters have been stored by recordregion.
988212243Sjilles * CTLESC characters are preserved but have little effect in this pass
989212243Sjilles * other than escaping CTL* characters.  In particular, they do not escape
990212243Sjilles * IFS characters: that should be done with the ifsregion mechanism.
991212243Sjilles * CTLQUOTEMARK characters are used to preserve empty quoted strings.
992212243Sjilles * This pass treats them as a regular character, making the string non-empty.
993212243Sjilles * Later, they are removed along with the other CTL* characters.
9941556Srgrimes */
9951556SrgrimesSTATIC void
99690111Simpifsbreakup(char *string, struct arglist *arglist)
99790111Simp{
9981556Srgrimes	struct ifsregion *ifsp;
9991556Srgrimes	struct strlist *sp;
10001556Srgrimes	char *start;
100125233Ssteve	char *p;
10021556Srgrimes	char *q;
1003201053Sjilles	const char *ifs;
1004194975Sjilles	const char *ifsspc;
1005194975Sjilles	int had_param_ch = 0;
10061556Srgrimes
1007194975Sjilles	start = string;
100817987Speter
1009194975Sjilles	if (ifslastp == NULL) {
1010194975Sjilles		/* Return entire argument, IFS doesn't apply to any of it */
1011194975Sjilles		sp = (struct strlist *)stalloc(sizeof *sp);
1012194975Sjilles		sp->text = start;
1013194975Sjilles		*arglist->lastp = sp;
1014194975Sjilles		arglist->lastp = &sp->next;
1015194975Sjilles		return;
1016194975Sjilles	}
1017194975Sjilles
1018194975Sjilles	ifs = ifsset() ? ifsval() : " \t\n";
1019194975Sjilles
1020194975Sjilles	for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
1021194975Sjilles		p = string + ifsp->begoff;
1022194975Sjilles		while (p < string + ifsp->endoff) {
1023194975Sjilles			q = p;
1024194975Sjilles			if (*p == CTLESC)
1025194975Sjilles				p++;
1026194975Sjilles			if (ifsp->inquotes) {
1027194975Sjilles				/* Only NULs (should be from "$@") end args */
1028194977Sjilles				had_param_ch = 1;
1029194975Sjilles				if (*p != 0) {
10301556Srgrimes					p++;
1031194975Sjilles					continue;
1032194975Sjilles				}
1033194975Sjilles				ifsspc = NULL;
1034194975Sjilles			} else {
1035194975Sjilles				if (!strchr(ifs, *p)) {
1036194977Sjilles					had_param_ch = 1;
103738887Stegge					p++;
1038194975Sjilles					continue;
1039194975Sjilles				}
1040194975Sjilles				ifsspc = strchr(" \t\n", *p);
1041194975Sjilles
1042194975Sjilles				/* Ignore IFS whitespace at start */
1043194975Sjilles				if (q == start && ifsspc != NULL) {
1044194975Sjilles					p++;
10451556Srgrimes					start = p;
1046194975Sjilles					continue;
1047194975Sjilles				}
1048194977Sjilles				had_param_ch = 0;
10491556Srgrimes			}
1050194975Sjilles
1051194975Sjilles			/* Save this argument... */
1052194975Sjilles			*q = '\0';
10531556Srgrimes			sp = (struct strlist *)stalloc(sizeof *sp);
10541556Srgrimes			sp->text = start;
10551556Srgrimes			*arglist->lastp = sp;
10561556Srgrimes			arglist->lastp = &sp->next;
1057194975Sjilles			p++;
1058194975Sjilles
1059194975Sjilles			if (ifsspc != NULL) {
1060194975Sjilles				/* Ignore further trailing IFS whitespace */
1061194975Sjilles				for (; p < string + ifsp->endoff; p++) {
1062194975Sjilles					q = p;
1063194975Sjilles					if (*p == CTLESC)
1064194975Sjilles						p++;
1065194975Sjilles					if (strchr(ifs, *p) == NULL) {
1066194975Sjilles						p = q;
1067194975Sjilles						break;
1068194975Sjilles					}
1069194975Sjilles					if (strchr(" \t\n", *p) == NULL) {
1070194975Sjilles						p++;
1071194975Sjilles						break;
1072194975Sjilles					}
1073194975Sjilles				}
1074194975Sjilles			}
1075194975Sjilles			start = p;
10761556Srgrimes		}
1077194975Sjilles	}
1078194975Sjilles
1079194975Sjilles	/*
1080194975Sjilles	 * Save anything left as an argument.
1081194975Sjilles	 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1082194975Sjilles	 * generating 2 arguments, the second of which is empty.
1083194975Sjilles	 * Some recent clarification of the Posix spec say that it
1084194975Sjilles	 * should only generate one....
1085194975Sjilles	 */
1086194975Sjilles	if (had_param_ch || *start != 0) {
10871556Srgrimes		sp = (struct strlist *)stalloc(sizeof *sp);
10881556Srgrimes		sp->text = start;
10891556Srgrimes		*arglist->lastp = sp;
10901556Srgrimes		arglist->lastp = &sp->next;
10911556Srgrimes	}
10921556Srgrimes}
10931556Srgrimes
10941556Srgrimes
1095212243SjillesSTATIC char expdir[PATH_MAX];
1096212243Sjilles#define expdir_end (expdir + sizeof(expdir))
10971556Srgrimes
10981556Srgrimes/*
1099212243Sjilles * Perform pathname generation and remove control characters.
1100212243Sjilles * At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
1101212243Sjilles * The results are stored in the list exparg.
11021556Srgrimes */
11031556SrgrimesSTATIC void
110490111Simpexpandmeta(struct strlist *str, int flag __unused)
110517987Speter{
11061556Srgrimes	char *p;
11071556Srgrimes	struct strlist **savelastp;
11081556Srgrimes	struct strlist *sp;
11091556Srgrimes	char c;
11101556Srgrimes	/* TODO - EXP_REDIR */
11111556Srgrimes
11121556Srgrimes	while (str) {
11131556Srgrimes		if (fflag)
11141556Srgrimes			goto nometa;
11151556Srgrimes		p = str->text;
11161556Srgrimes		for (;;) {			/* fast check for meta chars */
11171556Srgrimes			if ((c = *p++) == '\0')
11181556Srgrimes				goto nometa;
1119211646Sjilles			if (c == '*' || c == '?' || c == '[')
11201556Srgrimes				break;
11211556Srgrimes		}
11221556Srgrimes		savelastp = exparg.lastp;
11231556Srgrimes		INTOFF;
11241556Srgrimes		expmeta(expdir, str->text);
11251556Srgrimes		INTON;
11261556Srgrimes		if (exparg.lastp == savelastp) {
11278855Srgrimes			/*
11288855Srgrimes			 * no matches
11291556Srgrimes			 */
11301556Srgrimesnometa:
11311556Srgrimes			*exparg.lastp = str;
11321556Srgrimes			rmescapes(str->text);
11331556Srgrimes			exparg.lastp = &str->next;
11341556Srgrimes		} else {
11351556Srgrimes			*exparg.lastp = NULL;
11361556Srgrimes			*savelastp = sp = expsort(*savelastp);
11371556Srgrimes			while (sp->next != NULL)
11381556Srgrimes				sp = sp->next;
11391556Srgrimes			exparg.lastp = &sp->next;
11401556Srgrimes		}
11411556Srgrimes		str = str->next;
11421556Srgrimes	}
11431556Srgrimes}
11441556Srgrimes
11451556Srgrimes
11461556Srgrimes/*
11471556Srgrimes * Do metacharacter (i.e. *, ?, [...]) expansion.
11481556Srgrimes */
11491556Srgrimes
11501556SrgrimesSTATIC void
115190111Simpexpmeta(char *enddir, char *name)
115290111Simp{
115325233Ssteve	char *p;
11541556Srgrimes	char *q;
11551556Srgrimes	char *start;
11561556Srgrimes	char *endname;
11571556Srgrimes	int metaflag;
11581556Srgrimes	struct stat statb;
11591556Srgrimes	DIR *dirp;
11601556Srgrimes	struct dirent *dp;
11611556Srgrimes	int atend;
11621556Srgrimes	int matchdot;
1163207944Sjilles	int esc;
11641556Srgrimes
11651556Srgrimes	metaflag = 0;
11661556Srgrimes	start = name;
1167207944Sjilles	for (p = name; esc = 0, *p; p += esc + 1) {
11681556Srgrimes		if (*p == '*' || *p == '?')
11691556Srgrimes			metaflag = 1;
11701556Srgrimes		else if (*p == '[') {
11711556Srgrimes			q = p + 1;
117226488Sache			if (*q == '!' || *q == '^')
11731556Srgrimes				q++;
11741556Srgrimes			for (;;) {
117538887Stegge				while (*q == CTLQUOTEMARK)
117638887Stegge					q++;
11771556Srgrimes				if (*q == CTLESC)
11781556Srgrimes					q++;
11791556Srgrimes				if (*q == '/' || *q == '\0')
11801556Srgrimes					break;
11811556Srgrimes				if (*++q == ']') {
11821556Srgrimes					metaflag = 1;
11831556Srgrimes					break;
11841556Srgrimes				}
11851556Srgrimes			}
11861556Srgrimes		} else if (*p == '\0')
11871556Srgrimes			break;
118838887Stegge		else if (*p == CTLQUOTEMARK)
118938887Stegge			continue;
1190207944Sjilles		else {
1191207944Sjilles			if (*p == CTLESC)
1192207944Sjilles				esc++;
1193207944Sjilles			if (p[esc] == '/') {
1194207944Sjilles				if (metaflag)
1195207944Sjilles					break;
1196207944Sjilles				start = p + esc + 1;
1197207944Sjilles			}
11981556Srgrimes		}
11991556Srgrimes	}
12001556Srgrimes	if (metaflag == 0) {	/* we've reached the end of the file name */
12011556Srgrimes		if (enddir != expdir)
12021556Srgrimes			metaflag++;
12031556Srgrimes		for (p = name ; ; p++) {
120438887Stegge			if (*p == CTLQUOTEMARK)
120538887Stegge				continue;
12061556Srgrimes			if (*p == CTLESC)
12071556Srgrimes				p++;
12081556Srgrimes			*enddir++ = *p;
12091556Srgrimes			if (*p == '\0')
12101556Srgrimes				break;
1211211155Sjilles			if (enddir == expdir_end)
1212211155Sjilles				return;
12131556Srgrimes		}
1214147812Sdelphij		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
12151556Srgrimes			addfname(expdir);
12161556Srgrimes		return;
12171556Srgrimes	}
12181556Srgrimes	endname = p;
12191556Srgrimes	if (start != name) {
12201556Srgrimes		p = name;
12211556Srgrimes		while (p < start) {
122238887Stegge			while (*p == CTLQUOTEMARK)
122338887Stegge				p++;
12241556Srgrimes			if (*p == CTLESC)
12251556Srgrimes				p++;
12261556Srgrimes			*enddir++ = *p++;
1227211155Sjilles			if (enddir == expdir_end)
1228211155Sjilles				return;
12291556Srgrimes		}
12301556Srgrimes	}
12311556Srgrimes	if (enddir == expdir) {
12321556Srgrimes		p = ".";
12331556Srgrimes	} else if (enddir == expdir + 1 && *expdir == '/') {
12341556Srgrimes		p = "/";
12351556Srgrimes	} else {
12361556Srgrimes		p = expdir;
12371556Srgrimes		enddir[-1] = '\0';
12381556Srgrimes	}
12391556Srgrimes	if ((dirp = opendir(p)) == NULL)
12401556Srgrimes		return;
12411556Srgrimes	if (enddir != expdir)
12421556Srgrimes		enddir[-1] = '/';
12431556Srgrimes	if (*endname == 0) {
12441556Srgrimes		atend = 1;
12451556Srgrimes	} else {
12461556Srgrimes		atend = 0;
1247207944Sjilles		*endname = '\0';
1248207944Sjilles		endname += esc + 1;
12491556Srgrimes	}
12501556Srgrimes	matchdot = 0;
125138887Stegge	p = start;
125238887Stegge	while (*p == CTLQUOTEMARK)
125338887Stegge		p++;
125438887Stegge	if (*p == CTLESC)
125538887Stegge		p++;
125638887Stegge	if (*p == '.')
12571556Srgrimes		matchdot++;
12581556Srgrimes	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
12591556Srgrimes		if (dp->d_name[0] == '.' && ! matchdot)
12601556Srgrimes			continue;
126145514Stegge		if (patmatch(start, dp->d_name, 0)) {
1262211155Sjilles			if (enddir + dp->d_namlen + 1 > expdir_end)
1263211155Sjilles				continue;
1264211155Sjilles			memcpy(enddir, dp->d_name, dp->d_namlen + 1);
1265211155Sjilles			if (atend)
12661556Srgrimes				addfname(expdir);
1267211155Sjilles			else {
1268211155Sjilles				if (enddir + dp->d_namlen + 2 > expdir_end)
126917987Speter					continue;
1270211155Sjilles				enddir[dp->d_namlen] = '/';
1271211155Sjilles				enddir[dp->d_namlen + 1] = '\0';
1272211155Sjilles				expmeta(enddir + dp->d_namlen + 1, endname);
12731556Srgrimes			}
12741556Srgrimes		}
12751556Srgrimes	}
12761556Srgrimes	closedir(dirp);
12771556Srgrimes	if (! atend)
1278207944Sjilles		endname[-esc - 1] = esc ? CTLESC : '/';
12791556Srgrimes}
12801556Srgrimes
12811556Srgrimes
12821556Srgrimes/*
12831556Srgrimes * Add a file name to the list.
12841556Srgrimes */
12851556Srgrimes
12861556SrgrimesSTATIC void
128790111Simpaddfname(char *name)
128890111Simp{
12891556Srgrimes	char *p;
12901556Srgrimes	struct strlist *sp;
12911556Srgrimes
12921556Srgrimes	p = stalloc(strlen(name) + 1);
12931556Srgrimes	scopy(name, p);
12941556Srgrimes	sp = (struct strlist *)stalloc(sizeof *sp);
12951556Srgrimes	sp->text = p;
12961556Srgrimes	*exparg.lastp = sp;
12971556Srgrimes	exparg.lastp = &sp->next;
12981556Srgrimes}
12991556Srgrimes
13001556Srgrimes
13011556Srgrimes/*
13021556Srgrimes * Sort the results of file name expansion.  It calculates the number of
13031556Srgrimes * strings to sort and then calls msort (short for merge sort) to do the
13041556Srgrimes * work.
13051556Srgrimes */
13061556Srgrimes
13071556SrgrimesSTATIC struct strlist *
130890111Simpexpsort(struct strlist *str)
130990111Simp{
13101556Srgrimes	int len;
13111556Srgrimes	struct strlist *sp;
13121556Srgrimes
13131556Srgrimes	len = 0;
13141556Srgrimes	for (sp = str ; sp ; sp = sp->next)
13151556Srgrimes		len++;
13161556Srgrimes	return msort(str, len);
13171556Srgrimes}
13181556Srgrimes
13191556Srgrimes
13201556SrgrimesSTATIC struct strlist *
132190111Simpmsort(struct strlist *list, int len)
132217987Speter{
132317987Speter	struct strlist *p, *q = NULL;
13241556Srgrimes	struct strlist **lpp;
13251556Srgrimes	int half;
13261556Srgrimes	int n;
13271556Srgrimes
13281556Srgrimes	if (len <= 1)
13291556Srgrimes		return list;
13308855Srgrimes	half = len >> 1;
13311556Srgrimes	p = list;
13321556Srgrimes	for (n = half ; --n >= 0 ; ) {
13331556Srgrimes		q = p;
13341556Srgrimes		p = p->next;
13351556Srgrimes	}
13361556Srgrimes	q->next = NULL;			/* terminate first half of list */
13371556Srgrimes	q = msort(list, half);		/* sort first half of list */
13381556Srgrimes	p = msort(p, len - half);		/* sort second half */
13391556Srgrimes	lpp = &list;
13401556Srgrimes	for (;;) {
13411556Srgrimes		if (strcmp(p->text, q->text) < 0) {
13421556Srgrimes			*lpp = p;
13431556Srgrimes			lpp = &p->next;
13441556Srgrimes			if ((p = *lpp) == NULL) {
13451556Srgrimes				*lpp = q;
13461556Srgrimes				break;
13471556Srgrimes			}
13481556Srgrimes		} else {
13491556Srgrimes			*lpp = q;
13501556Srgrimes			lpp = &q->next;
13511556Srgrimes			if ((q = *lpp) == NULL) {
13521556Srgrimes				*lpp = p;
13531556Srgrimes				break;
13541556Srgrimes			}
13551556Srgrimes		}
13561556Srgrimes	}
13571556Srgrimes	return list;
13581556Srgrimes}
13591556Srgrimes
13601556Srgrimes
13611556Srgrimes
13621556Srgrimes/*
13631556Srgrimes * Returns true if the pattern matches the string.
13641556Srgrimes */
13651556Srgrimes
13661556Srgrimesint
1367200956Sjillespatmatch(const char *pattern, const char *string, int squoted)
136890111Simp{
1369200956Sjilles	const char *p, *q;
137025233Ssteve	char c;
13711556Srgrimes
13721556Srgrimes	p = pattern;
13731556Srgrimes	q = string;
13741556Srgrimes	for (;;) {
13751556Srgrimes		switch (c = *p++) {
13761556Srgrimes		case '\0':
13771556Srgrimes			goto breakloop;
13781556Srgrimes		case CTLESC:
137945514Stegge			if (squoted && *q == CTLESC)
138045514Stegge				q++;
13811556Srgrimes			if (*q++ != *p++)
13821556Srgrimes				return 0;
13831556Srgrimes			break;
138438887Stegge		case CTLQUOTEMARK:
138538887Stegge			continue;
13861556Srgrimes		case '?':
138745514Stegge			if (squoted && *q == CTLESC)
138845514Stegge				q++;
13891556Srgrimes			if (*q++ == '\0')
13901556Srgrimes				return 0;
13911556Srgrimes			break;
13921556Srgrimes		case '*':
13931556Srgrimes			c = *p;
139438887Stegge			while (c == CTLQUOTEMARK || c == '*')
139538887Stegge				c = *++p;
139638887Stegge			if (c != CTLESC &&  c != CTLQUOTEMARK &&
139738887Stegge			    c != '?' && c != '*' && c != '[') {
13981556Srgrimes				while (*q != c) {
139945514Stegge					if (squoted && *q == CTLESC &&
140045514Stegge					    q[1] == c)
140145514Stegge						break;
14021556Srgrimes					if (*q == '\0')
14031556Srgrimes						return 0;
140445514Stegge					if (squoted && *q == CTLESC)
140545514Stegge						q++;
14061556Srgrimes					q++;
14071556Srgrimes				}
14081556Srgrimes			}
14091556Srgrimes			do {
1410211646Sjilles				if (patmatch(p, q, squoted))
14111556Srgrimes					return 1;
141245514Stegge				if (squoted && *q == CTLESC)
141345514Stegge					q++;
14141556Srgrimes			} while (*q++ != '\0');
14151556Srgrimes			return 0;
14161556Srgrimes		case '[': {
1417200956Sjilles			const char *endp;
14181556Srgrimes			int invert, found;
14191556Srgrimes			char chr;
14201556Srgrimes
14211556Srgrimes			endp = p;
142226488Sache			if (*endp == '!' || *endp == '^')
14231556Srgrimes				endp++;
14241556Srgrimes			for (;;) {
142538887Stegge				while (*endp == CTLQUOTEMARK)
142638887Stegge					endp++;
14271556Srgrimes				if (*endp == '\0')
14281556Srgrimes					goto dft;		/* no matching ] */
14291556Srgrimes				if (*endp == CTLESC)
14301556Srgrimes					endp++;
14311556Srgrimes				if (*++endp == ']')
14321556Srgrimes					break;
14331556Srgrimes			}
14341556Srgrimes			invert = 0;
143526488Sache			if (*p == '!' || *p == '^') {
14361556Srgrimes				invert++;
14371556Srgrimes				p++;
14381556Srgrimes			}
14391556Srgrimes			found = 0;
14401556Srgrimes			chr = *q++;
144145514Stegge			if (squoted && chr == CTLESC)
144245514Stegge				chr = *q++;
144317987Speter			if (chr == '\0')
144417987Speter				return 0;
14451556Srgrimes			c = *p++;
14461556Srgrimes			do {
144738887Stegge				if (c == CTLQUOTEMARK)
144838887Stegge					continue;
14491556Srgrimes				if (c == CTLESC)
14501556Srgrimes					c = *p++;
14511556Srgrimes				if (*p == '-' && p[1] != ']') {
14521556Srgrimes					p++;
145338887Stegge					while (*p == CTLQUOTEMARK)
145438887Stegge						p++;
14551556Srgrimes					if (*p == CTLESC)
14561556Srgrimes						p++;
145717557Sache					if (   collate_range_cmp(chr, c) >= 0
145817557Sache					    && collate_range_cmp(chr, *p) <= 0
145917525Sache					   )
14601556Srgrimes						found = 1;
14611556Srgrimes					p++;
14621556Srgrimes				} else {
14631556Srgrimes					if (chr == c)
14641556Srgrimes						found = 1;
14651556Srgrimes				}
14661556Srgrimes			} while ((c = *p++) != ']');
14671556Srgrimes			if (found == invert)
14681556Srgrimes				return 0;
14691556Srgrimes			break;
14701556Srgrimes		}
14711556Srgrimesdft:	        default:
147245514Stegge			if (squoted && *q == CTLESC)
147345514Stegge				q++;
14741556Srgrimes			if (*q++ != c)
14751556Srgrimes				return 0;
14761556Srgrimes			break;
14771556Srgrimes		}
14781556Srgrimes	}
14791556Srgrimesbreakloop:
14801556Srgrimes	if (*q != '\0')
14811556Srgrimes		return 0;
14821556Srgrimes	return 1;
14831556Srgrimes}
14841556Srgrimes
14851556Srgrimes
14861556Srgrimes
14871556Srgrimes/*
1488212243Sjilles * Remove any CTLESC and CTLQUOTEMARK characters from a string.
14891556Srgrimes */
14901556Srgrimes
14911556Srgrimesvoid
149290111Simprmescapes(char *str)
149338887Stegge{
149425233Ssteve	char *p, *q;
14951556Srgrimes
14961556Srgrimes	p = str;
149738887Stegge	while (*p != CTLESC && *p != CTLQUOTEMARK) {
14981556Srgrimes		if (*p++ == '\0')
14991556Srgrimes			return;
15001556Srgrimes	}
15011556Srgrimes	q = p;
15021556Srgrimes	while (*p) {
150338887Stegge		if (*p == CTLQUOTEMARK) {
150438887Stegge			p++;
150538887Stegge			continue;
150638887Stegge		}
15071556Srgrimes		if (*p == CTLESC)
15081556Srgrimes			p++;
15091556Srgrimes		*q++ = *p++;
15101556Srgrimes	}
15111556Srgrimes	*q = '\0';
15121556Srgrimes}
15131556Srgrimes
15141556Srgrimes
15151556Srgrimes
15161556Srgrimes/*
15171556Srgrimes * See if a pattern matches in a case statement.
15181556Srgrimes */
15191556Srgrimes
15201556Srgrimesint
1521200956Sjillescasematch(union node *pattern, const char *val)
152290111Simp{
15231556Srgrimes	struct stackmark smark;
15241556Srgrimes	int result;
15251556Srgrimes	char *p;
15261556Srgrimes
15271556Srgrimes	setstackmark(&smark);
15281556Srgrimes	argbackq = pattern->narg.backquote;
15291556Srgrimes	STARTSTACKSTR(expdest);
15301556Srgrimes	ifslastp = NULL;
15311556Srgrimes	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
15321556Srgrimes	STPUTC('\0', expdest);
15331556Srgrimes	p = grabstackstr(expdest);
153445514Stegge	result = patmatch(p, val, 0);
15351556Srgrimes	popstackmark(&smark);
15361556Srgrimes	return result;
15371556Srgrimes}
153817987Speter
153917987Speter/*
154017987Speter * Our own itoa().
154117987Speter */
154217987Speter
154317987SpeterSTATIC char *
154490111Simpcvtnum(int num, char *buf)
154590111Simp{
154617987Speter	char temp[32];
154717987Speter	int neg = num < 0;
154817987Speter	char *p = temp + 31;
154917987Speter
155017987Speter	temp[31] = '\0';
155117987Speter
155217987Speter	do {
155317987Speter		*--p = num % 10 + '0';
155417987Speter	} while ((num /= 10) != 0);
155517987Speter
155617987Speter	if (neg)
155717987Speter		*--p = '-';
155817987Speter
155917987Speter	while (*p)
156017987Speter		STPUTC(*p++, buf);
156117987Speter	return buf;
156217987Speter}
1563108286Stjr
1564108286Stjr/*
1565108286Stjr * Do most of the work for wordexp(3).
1566108286Stjr */
1567108286Stjr
1568108286Stjrint
1569108286Stjrwordexpcmd(int argc, char **argv)
1570108286Stjr{
1571108286Stjr	size_t len;
1572108286Stjr	int i;
1573108286Stjr
1574108286Stjr	out1fmt("%08x", argc - 1);
1575108286Stjr	for (i = 1, len = 0; i < argc; i++)
1576108286Stjr		len += strlen(argv[i]);
1577108286Stjr	out1fmt("%08x", (int)len);
1578108286Stjr	for (i = 1; i < argc; i++) {
1579108286Stjr		out1str(argv[i]);
1580108286Stjr		out1c('\0');
1581108286Stjr	}
1582108286Stjr        return (0);
1583108286Stjr}
1584