STATIC int subevalvar __P((char *, char *, int, int, int));
STATIC int subevalvar __P((char *, char *, int, int, int, int));
STATIC char *exptilde __P((char *, int));STATIC void expbackq __P((union node *, int, int));STATIC int subevalvar __P((char *, char *, int, int, int));STATIC char *evalvar __P((char *, int));STATIC int varisset __P((int));STATIC void varvalue __P((int, int, int));STATIC void recordregion __P((int, int, int));STATIC void ifsbreakup __P((char *, struct arglist *));STATIC void expandmeta __P((struct strlist *, int));STATIC void expmeta __P((char *, char *));STATIC void addfname __P((char *));STATIC struct strlist *expsort __P((struct strlist *));STATIC struct strlist *msort __P((struct strlist *, int));STATIC int pmatch __P((char *, char *));STATIC char *cvtnum __P((int, char *));/* * Expand shell variables and backquotes inside a here document. */voidexpandhere(arg, fd)	union node *arg;	/* the document */	int fd;			/* where to write the expanded version */	{	herefd = fd;	expandarg(arg, (struct arglist *)NULL, 0);	xwrite(fd, stackblock(), expdest - stackblock());}/* * Perform variable substitution and command substitution on an argument, * placing the resulting list of arguments in arglist.  If EXP_FULL is true, * perform splitting and file name expansion.  When arglist is NULL, perform * here document expansion. */voidexpandarg(arg, arglist, flag)	union node *arg;	struct arglist *arglist;	int flag;{	struct strlist *sp;	char *p;	argbackq = arg->narg.backquote;	STARTSTACKSTR(expdest);	ifsfirst.next = NULL;	ifslastp = NULL;	argstr(arg->narg.text, flag);	if (arglist == NULL) {		return;			/* here document expanded */	}	STPUTC('\0', expdest);	p = grabstackstr(expdest);	exparg.lastp = &exparg.list;	/*	 * TODO - EXP_REDIR	 */	if (flag & EXP_FULL) {		ifsbreakup(p, &exparg);		*exparg.lastp = NULL;		exparg.lastp = &exparg.list;		expandmeta(exparg.list, flag);	} else {		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */			rmescapes(p);		sp = (struct strlist *)stalloc(sizeof (struct strlist));		sp->text = p;		*exparg.lastp = sp;		exparg.lastp = &sp->next;	}	while (ifsfirst.next != NULL) {		struct ifsregion *ifsp;		INTOFF;		ifsp = ifsfirst.next->next;		ckfree(ifsfirst.next);		ifsfirst.next = ifsp;		INTON;	}	*exparg.lastp = NULL;	if (exparg.list) {		*arglist->lastp = exparg.list;		arglist->lastp = exparg.lastp;	}}/* * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC * characters to allow for further processing.  Otherwise treat * $@ like $* since no splitting will be performed. */STATIC voidargstr(p, flag)	register char *p;	int flag;{	register char c;	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */	int firsteq = 1;	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))		p = exptilde(p, flag);	for (;;) {		switch (c = *p++) {		case '\0':		case CTLENDVAR: /* ??? */			goto breakloop;		case CTLESC:			if (quotes)				STPUTC(c, expdest);			c = *p++;			STPUTC(c, expdest);			break;		case CTLVAR:			p = evalvar(p, flag);			break;		case CTLBACKQ:		case CTLBACKQ|CTLQUOTE:			expbackq(argbackq->n, c & CTLQUOTE, flag);			argbackq = argbackq->next;			break;		case CTLENDARI:			expari(flag);			break;		case ':':		case '=':			/*			 * sort of a hack - expand tildes in variable			 * assignments (after the first '=' and after ':'s).			 */			STPUTC(c, expdest);			if (flag & EXP_VARTILDE && *p == '~') {				if (c == '=') {					if (firsteq)						firsteq = 0;					else						break;				}				p = exptilde(p, flag);			}			break;		default:			STPUTC(c, expdest);		}	}breakloop:;}STATIC char *exptilde(p, flag)	char *p;	int flag;{	char c, *startp = p;	struct passwd *pw;	char *home;	int quotes = flag & (EXP_FULL | EXP_CASE);	while ((c = *p) != '\0') {		switch(c) {		case CTLESC:			return (startp);		case ':':			if (flag & EXP_VARTILDE)				goto done;			break;		case '/':			goto done;		}		p++;	}done:	*p = '\0';	if (*(startp+1) == '\0') {		if ((home = lookupvar("HOME")) == NULL)			goto lose;	} else {		if ((pw = getpwnam(startp+1)) == NULL)			goto lose;		home = pw->pw_dir;	}	if (*home == '\0')		goto lose;	*p = c;	while ((c = *home++) != '\0') {		if (quotes && SQSYNTAX[c] == CCTL)			STPUTC(CTLESC, expdest);		STPUTC(c, expdest);	}	return (p);lose:	*p = c;	return (startp);}