expand.c revision 222907
11541Srgrimes/*-
21541Srgrimes * Copyright (c) 1991, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * Copyright (c) 1997-2005
51541Srgrimes *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
61541Srgrimes *
71541Srgrimes * This code is derived from software contributed to Berkeley by
81541Srgrimes * Kenneth Almquist.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 4. Neither the name of the University nor the names of its contributors
191541Srgrimes *    may be used to endorse or promote products derived from this software
201541Srgrimes *    without specific prior written permission.
211541Srgrimes *
221541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321541Srgrimes * SUCH DAMAGE.
331541Srgrimes */
341541Srgrimes
351541Srgrimes#ifndef lint
361541Srgrimes#if 0
371541Srgrimesstatic char sccsid[] = "@(#)expand.c	8.5 (Berkeley) 5/15/95";
3844510Swollman#endif
3950477Speter#endif /* not lint */
401541Srgrimes#include <sys/cdefs.h>
411541Srgrimes__FBSDID("$FreeBSD: head/bin/sh/expand.c 222907 2011-06-09 23:12:23Z jilles $");
421541Srgrimes
431541Srgrimes#include <sys/types.h>
4433392Sphk#include <sys/time.h>
451541Srgrimes#include <sys/stat.h>
4674914Sjhb#include <dirent.h>
4768840Sjhb#include <errno.h>
481541Srgrimes#include <inttypes.h>
4933392Sphk#include <limits.h>
5033392Sphk#include <pwd.h>
5133392Sphk#include <stdio.h>
5233392Sphk#include <stdlib.h>
5333392Sphk#include <string.h>
5433392Sphk#include <unistd.h>
5529680Sgibbs#include <wchar.h>
5629680Sgibbs
5729680Sgibbs/*
5829680Sgibbs * Routines to expand arguments to commands.  We have to deal with
5933392Sphk * backquotes, shell variables, and file metacharacters.
6068889Sjake */
612112Swollman
6229680Sgibbs#include "shell.h"
631541Srgrimes#include "main.h"
641541Srgrimes#include "nodes.h"
6582127Sdillon#include "eval.h"
6682127Sdillon#include "expand.h"
6782127Sdillon#include "syntax.h"
6882127Sdillon#include "parser.h"
6982127Sdillon#include "jobs.h"
7082127Sdillon#include "options.h"
7182127Sdillon#include "var.h"
7282127Sdillon#include "input.h"
7382127Sdillon#include "output.h"
7482127Sdillon#include "memalloc.h"
7582127Sdillon#include "error.h"
7682127Sdillon#include "mystring.h"
7782127Sdillon#include "arith.h"
7882127Sdillon#include "show.h"
7982127Sdillon
8082127Sdillon/*
8182127Sdillon * Structure specifying which parts of the string should be searched
8282127Sdillon * for IFS characters.
8382127Sdillon */
8482127Sdillon
8582127Sdillonstruct ifsregion {
8682127Sdillon	struct ifsregion *next;	/* next region in list */
8782127Sdillon	int begoff;		/* offset of start of region */
8882127Sdillon	int endoff;		/* offset of end of region */
8982127Sdillon	int inquotes;		/* search for nul bytes only */
9082127Sdillon};
9182127Sdillon
9282127Sdillon
9382127Sdillonstatic char *expdest;			/* output of current string */
9482127Sdillonstatic struct nodelist *argbackq;	/* list of back quote expressions */
9582127Sdillonstatic struct ifsregion ifsfirst;	/* first struct in list of ifs regions */
9682127Sdillonstatic struct ifsregion *ifslastp;	/* last struct in list */
9782127Sdillonstatic struct arglist exparg;		/* holds expanded arg list */
9882127Sdillon
9982127Sdillonstatic void argstr(char *, int);
10082127Sdillonstatic char *exptilde(char *, int);
10182127Sdillonstatic void expbackq(union node *, int, int);
10282127Sdillonstatic int subevalvar(char *, char *, int, int, int, int, int);
10382127Sdillonstatic char *evalvar(char *, int);
10482127Sdillonstatic int varisset(char *, int);
10582127Sdillonstatic void varvalue(char *, int, int, int);
10682127Sdillonstatic void recordregion(int, int, int);
10782127Sdillonstatic void removerecordregions(int);
10882127Sdillonstatic void ifsbreakup(char *, struct arglist *);
10982127Sdillonstatic void expandmeta(struct strlist *, int);
11093818Sjhbstatic void expmeta(char *, char *);
11182127Sdillonstatic void addfname(char *);
11282127Sdillonstatic struct strlist *expsort(struct strlist *);
11382127Sdillonstatic struct strlist *msort(struct strlist *, int);
11429680Sgibbsstatic char *cvtnum(int, char *);
11529680Sgibbsstatic int collate_range_cmp(wchar_t, wchar_t);
11629680Sgibbs
11729680Sgibbsstatic int
11829680Sgibbscollate_range_cmp(wchar_t c1, wchar_t c2)
11929680Sgibbs{
12029680Sgibbs	static wchar_t s1[2], s2[2];
12129680Sgibbs
12229680Sgibbs	s1[0] = c1;
12329680Sgibbs	s2[0] = c2;
12432388Sphk	return (wcscoll(s1, s2));
12529680Sgibbs}
1261541Srgrimes
1271541Srgrimes/*
1281541Srgrimes * Expand shell variables and backquotes inside a here document.
1291541Srgrimes *	union node *arg		the document
13067551Sjhb *	int fd;			where to write the expanded version
1311541Srgrimes */
132102936Sphk
133102936Sphkvoid
134102936Sphkexpandhere(union node *arg, int fd)
135102936Sphk{
136102936Sphk	expandarg(arg, (struct arglist *)NULL, 0);
137102936Sphk	xwrite(fd, stackblock(), expdest - stackblock());
138102936Sphk}
139102936Sphk
140102936Sphkstatic char *
1411541Srgrimesstputs_quotes(const char *data, const char *syntax, char *p)
14233392Sphk{
14333392Sphk	while (*data) {
14433392Sphk		CHECKSTRSPACE(2, p);
14529680Sgibbs		if (syntax[(int)*data] == CCTL)
14629680Sgibbs			USTPUTC(CTLESC, p);
14772200Sbmilekic		USTPUTC(*data++, p);
14829680Sgibbs	}
14929805Sgibbs	return (p);
15029805Sgibbs}
15129805Sgibbs#define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p)
15229805Sgibbs
15329805Sgibbs/*
15429805Sgibbs * Perform expansions on an argument, placing the resulting list of arguments
15529805Sgibbs * in arglist.  Parameter expansion, command substitution and arithmetic
15629805Sgibbs * expansion are always performed; additional expansions can be requested
15729680Sgibbs * via flag (EXP_*).
15829805Sgibbs * The result is left in the stack string.
15929680Sgibbs * When arglist is NULL, perform here document expansion.
16029680Sgibbs *
16129680Sgibbs * Caution: this function uses global state and is not reentrant.
16229680Sgibbs * However, a new invocation after an interrupted invocation is safe
16329805Sgibbs * and will reset the global state for the new call.
16472200Sbmilekic */
16581370Sjhbvoid
16672200Sbmilekicexpandarg(union node *arg, struct arglist *arglist, int flag)
16729680Sgibbs{
16829680Sgibbs	struct strlist *sp;
16929680Sgibbs	char *p;
17029680Sgibbs
17129680Sgibbs	argbackq = arg->narg.backquote;
17229680Sgibbs	STARTSTACKSTR(expdest);
17368889Sjake	ifsfirst.next = NULL;
17429680Sgibbs	ifslastp = NULL;
17529680Sgibbs	argstr(arg->narg.text, flag);
17629805Sgibbs	if (arglist == NULL) {
17729680Sgibbs		STACKSTRNUL(expdest);
17829680Sgibbs		return;			/* here document expanded */
17968889Sjake	}
18029680Sgibbs	STPUTC('\0', expdest);
18144510Swollman	p = grabstackstr(expdest);
18244510Swollman	exparg.lastp = &exparg.list;
18344510Swollman	/*
18444510Swollman	 * TODO - EXP_REDIR
18544510Swollman	 */
18644510Swollman	if (flag & EXP_FULL) {
18750673Sjlemon		ifsbreakup(p, &exparg);
18844510Swollman		*exparg.lastp = NULL;
18972200Sbmilekic		exparg.lastp = &exparg.list;
19068889Sjake		expandmeta(exparg.list, flag);
19172200Sbmilekic	} else {
192102936Sphk		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
193102936Sphk			rmescapes(p);
194102936Sphk		sp = (struct strlist *)stalloc(sizeof (struct strlist));
19529680Sgibbs		sp->text = p;
196102936Sphk		*exparg.lastp = sp;
197102936Sphk		exparg.lastp = &sp->next;
198102936Sphk	}
199102936Sphk	while (ifsfirst.next != NULL) {
200102936Sphk		struct ifsregion *ifsp;
201102936Sphk		INTOFF;
202102936Sphk		ifsp = ifsfirst.next->next;
203102936Sphk		ckfree(ifsfirst.next);
204102936Sphk		ifsfirst.next = ifsp;
205102936Sphk		INTON;
206102936Sphk	}
20768889Sjake	*exparg.lastp = NULL;
20872200Sbmilekic	if (exparg.list) {
20972200Sbmilekic		*arglist->lastp = exparg.list;
21029680Sgibbs		arglist->lastp = exparg.lastp;
21129680Sgibbs	}
21229680Sgibbs}
21329680Sgibbs
2141541Srgrimes
21529680Sgibbs
21672200Sbmilekic/*
2171541Srgrimes * Perform parameter expansion, command substitution and arithmetic
2181541Srgrimes * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
2191541Srgrimes * Processing ends at a CTLENDVAR character as well as '\0'.
2201541Srgrimes * This is used to expand word in ${var+word} etc.
2211541Srgrimes * If EXP_FULL, EXP_CASE or EXP_REDIR are set, keep and/or generate CTLESC
2221541Srgrimes * characters to allow for further processing.
2231541Srgrimes * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
2241541Srgrimes */
2251541Srgrimesstatic void
22629680Sgibbsargstr(char *p, int flag)
22729680Sgibbs{
22829680Sgibbs	char c;
2291541Srgrimes	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);	/* do CTLESC */
23029680Sgibbs	int firsteq = 1;
23129680Sgibbs	int split_lit;
23229680Sgibbs	int lit_quoted;
23329680Sgibbs
2341541Srgrimes	split_lit = flag & EXP_SPLIT_LIT;
23529680Sgibbs	lit_quoted = flag & EXP_LIT_QUOTED;
23629680Sgibbs	flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED);
23733824Sbde	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
2381541Srgrimes		p = exptilde(p, flag);
23969147Sjlemon	for (;;) {
2401541Srgrimes		CHECKSTRSPACE(2, expdest);
24129680Sgibbs		switch (c = *p++) {
24229680Sgibbs		case '\0':
2431541Srgrimes		case CTLENDVAR:
24472200Sbmilekic			goto breakloop;
2451541Srgrimes		case CTLQUOTEMARK:
2461541Srgrimes			lit_quoted = 1;
24729680Sgibbs			/* "$@" syntax adherence hack */
24829680Sgibbs			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
24929680Sgibbs				break;
2501541Srgrimes			if ((flag & EXP_FULL) != 0)
25129680Sgibbs				USTPUTC(c, expdest);
25244510Swollman			break;
25344510Swollman		case CTLQUOTEEND:
2541541Srgrimes			lit_quoted = 0;
25544510Swollman			break;
25672200Sbmilekic		case CTLESC:
25729680Sgibbs			if (quotes)
2581541Srgrimes				USTPUTC(c, expdest);
2591541Srgrimes			c = *p++;
2601541Srgrimes			USTPUTC(c, expdest);
26129680Sgibbs			if (split_lit && !lit_quoted)
26233824Sbde				recordregion(expdest - stackblock() -
2631541Srgrimes				    (quotes ? 2 : 1),
26429680Sgibbs				    expdest - stackblock(), 0);
2651541Srgrimes			break;
2661541Srgrimes		case CTLVAR:
26729680Sgibbs			p = evalvar(p, flag);
26829680Sgibbs			break;
26929680Sgibbs		case CTLBACKQ:
27029680Sgibbs		case CTLBACKQ|CTLQUOTE:
27129680Sgibbs			expbackq(argbackq->n, c & CTLQUOTE, flag);
27229680Sgibbs			argbackq = argbackq->next;
27329680Sgibbs			break;
27429680Sgibbs		case CTLENDARI:
27572200Sbmilekic			expari(flag);
27644510Swollman			break;
27744510Swollman		case ':':
27872200Sbmilekic		case '=':
2791541Srgrimes			/*
2801541Srgrimes			 * sort of a hack - expand tildes in variable
28124101Sbde			 * assignments (after the first '=' and after ':'s).
28229680Sgibbs			 */
28329680Sgibbs			USTPUTC(c, expdest);
28429680Sgibbs			if (split_lit && !lit_quoted)
28529680Sgibbs				recordregion(expdest - stackblock() - 1,
28629680Sgibbs				    expdest - stackblock(), 0);
28744510Swollman			if (flag & EXP_VARTILDE && *p == '~' &&
28844510Swollman			    (c != '=' || firsteq)) {
28944510Swollman				if (c == '=')
29044510Swollman					firsteq = 0;
29144510Swollman				p = exptilde(p, flag);
29244510Swollman			}
29344510Swollman			break;
29444510Swollman		default:
29550673Sjlemon			USTPUTC(c, expdest);
29644510Swollman			if (split_lit && !lit_quoted)
29750673Sjlemon				recordregion(expdest - stackblock() - 1,
29850673Sjlemon				    expdest - stackblock(), 0);
29950673Sjlemon		}
30044510Swollman	}
30144510Swollmanbreakloop:;
30269147Sjlemon}
30344510Swollman
30444510Swollman/*
30592723Salfred * Perform tilde expansion, placing the result in the stack string and
30644510Swollman * returning the next position in the input string to process.
30744510Swollman */
30844510Swollmanstatic char *
30972200Sbmilekicexptilde(char *p, int flag)
31044510Swollman{
31144510Swollman	char c, *startp = p;
31244510Swollman	struct passwd *pw;
31344510Swollman	char *home;
31481370Sjhb	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
31581370Sjhb
31681370Sjhb	while ((c = *p) != '\0') {
31744510Swollman		switch(c) {
31844510Swollman		case CTLESC: /* This means CTL* are always considered quoted. */
31944510Swollman		case CTLVAR:
32044510Swollman		case CTLBACKQ:
32144510Swollman		case CTLBACKQ | CTLQUOTE:
32269147Sjlemon		case CTLARI:
32344510Swollman		case CTLENDARI:
32444510Swollman		case CTLQUOTEMARK:
32544510Swollman			return (startp);
32644510Swollman		case ':':
32772200Sbmilekic			if (flag & EXP_VARTILDE)
32844510Swollman				goto done;
32944510Swollman			break;
33081481Sjhb		case '/':
33144510Swollman		case CTLENDVAR:
33244510Swollman			goto done;
33344510Swollman		}
33444510Swollman		p++;
33572200Sbmilekic	}
33644510Swollmandone:
33744510Swollman	*p = '\0';
33844510Swollman	if (*(startp+1) == '\0') {
33944510Swollman		if ((home = lookupvar("HOME")) == NULL)
34050673Sjlemon			goto lose;
34172200Sbmilekic	} else {
34281481Sjhb		if ((pw = getpwnam(startp+1)) == NULL)
34344510Swollman			goto lose;
34450673Sjlemon		home = pw->pw_dir;
34544510Swollman	}
34644510Swollman	if (*home == '\0')
34744510Swollman		goto lose;
34844510Swollman	*p = c;
34944510Swollman	if (quotes)
35044510Swollman		STPUTS_QUOTES(home, SQSYNTAX, expdest);
35144510Swollman	else
35244510Swollman		STPUTS(home, expdest);
35344510Swollman	return (p);
35444510Swollmanlose:
35572200Sbmilekic	*p = c;
35681481Sjhb	return (startp);
35744510Swollman}
35844510Swollman
35944510Swollman
36069147Sjlemonstatic void
36144510Swollmanremoverecordregions(int endoff)
36269147Sjlemon{
36344510Swollman	if (ifslastp == NULL)
36444527Swollman		return;
36569147Sjlemon
36669147Sjlemon	if (ifsfirst.endoff > endoff) {
36744510Swollman		while (ifsfirst.next != NULL) {
36844510Swollman			struct ifsregion *ifsp;
36931950Snate			INTOFF;
37031950Snate			ifsp = ifsfirst.next->next;
37131950Snate			ckfree(ifsfirst.next);
37231950Snate			ifsfirst.next = ifsp;
37331950Snate			INTON;
37431950Snate		}
37531950Snate		if (ifsfirst.begoff > endoff)
37631950Snate			ifslastp = NULL;
37731950Snate		else {
37831950Snate			ifslastp = &ifsfirst;
37931950Snate			ifsfirst.endoff = endoff;
38031950Snate		}
38131950Snate		return;
38231950Snate	}
38331950Snate
38431950Snate	ifslastp = &ifsfirst;
38531950Snate	while (ifslastp->next && ifslastp->next->begoff < endoff)
38631950Snate		ifslastp=ifslastp->next;
38731950Snate	while (ifslastp->next != NULL) {
38831950Snate		struct ifsregion *ifsp;
38931950Snate		INTOFF;
39031950Snate		ifsp = ifslastp->next->next;
39131950Snate		ckfree(ifslastp->next);
39231950Snate		ifslastp->next = ifsp;
39331950Snate		INTON;
39436127Sbde	}
39531950Snate	if (ifslastp->endoff > endoff)
39631950Snate		ifslastp->endoff = endoff;
39731950Snate}
39831950Snate
39931950Snate/*
40031950Snate * Expand arithmetic expression.  Backup to start of expression,
40131950Snate * evaluate, place result in (backed up) result, adjust string position.
40231950Snate */
40331950Snatevoid
40431950Snateexpari(int flag)
40531950Snate{
40631950Snate	char *p, *q, *start;
40731950Snate	arith_t result;
40831950Snate	int begoff;
40931950Snate	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
41031950Snate	int quoted;
41131950Snate
41231950Snate	/*
41331950Snate	 * This routine is slightly over-complicated for
41431950Snate	 * efficiency.  First we make sure there is
41531950Snate	 * enough space for the result, which may be bigger
41631950Snate	 * than the expression.  Next we
41731950Snate	 * scan backwards looking for the start of arithmetic.  If the
41872200Sbmilekic	 * next previous character is a CTLESC character, then we
41931950Snate	 * have to rescan starting from the beginning since CTLESC
42031950Snate	 * characters have to be processed left to right.
42131950Snate	 */
42231950Snate	CHECKSTRSPACE(DIGITS(result) - 2, expdest);
42331950Snate	USTPUTC('\0', expdest);
42431950Snate	start = stackblock();
42531950Snate	p = expdest - 2;
42631950Snate	while (p >= start && *p != CTLARI)
42731950Snate		--p;
42831950Snate	if (p < start || *p != CTLARI)
42972200Sbmilekic		error("missing CTLARI (shouldn't happen)");
43031950Snate	if (p > start && *(p - 1) == CTLESC)
43131950Snate		for (p = start; *p != CTLARI; p++)
43231950Snate			if (*p == CTLESC)
43331950Snate				p++;
434
435	if (p[1] == '"')
436		quoted=1;
437	else
438		quoted=0;
439	begoff = p - start;
440	removerecordregions(begoff);
441	if (quotes)
442		rmescapes(p+2);
443	q = grabstackstr(expdest);
444	result = arith(p+2);
445	ungrabstackstr(q, expdest);
446	fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
447	while (*p++)
448		;
449	if (quoted == 0)
450		recordregion(begoff, p - 1 - start, 0);
451	result = expdest - p + 1;
452	STADJUST(-result, expdest);
453}
454
455
456/*
457 * Perform command substitution.
458 */
459static void
460expbackq(union node *cmd, int quoted, int flag)
461{
462	struct backcmd in;
463	int i;
464	char buf[128];
465	char *p;
466	char *dest = expdest;
467	struct ifsregion saveifs, *savelastp;
468	struct nodelist *saveargbackq;
469	char lastc;
470	int startloc = dest - stackblock();
471	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
472	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
473	int nnl;
474
475	INTOFF;
476	saveifs = ifsfirst;
477	savelastp = ifslastp;
478	saveargbackq = argbackq;
479	p = grabstackstr(dest);
480	evalbackcmd(cmd, &in);
481	ungrabstackstr(p, dest);
482	ifsfirst = saveifs;
483	ifslastp = savelastp;
484	argbackq = saveargbackq;
485
486	p = in.buf;
487	lastc = '\0';
488	nnl = 0;
489	/* Don't copy trailing newlines */
490	for (;;) {
491		if (--in.nleft < 0) {
492			if (in.fd < 0)
493				break;
494			while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
495			TRACE(("expbackq: read returns %d\n", i));
496			if (i <= 0)
497				break;
498			p = buf;
499			in.nleft = i - 1;
500		}
501		lastc = *p++;
502		if (lastc != '\0') {
503			if (lastc == '\n') {
504				nnl++;
505			} else {
506				CHECKSTRSPACE(nnl + 2, dest);
507				while (nnl > 0) {
508					nnl--;
509					USTPUTC('\n', dest);
510				}
511				if (quotes && syntax[(int)lastc] == CCTL)
512					USTPUTC(CTLESC, dest);
513				USTPUTC(lastc, dest);
514			}
515		}
516	}
517
518	if (in.fd >= 0)
519		close(in.fd);
520	if (in.buf)
521		ckfree(in.buf);
522	if (in.jp)
523		exitstatus = waitforjob(in.jp, (int *)NULL);
524	if (quoted == 0)
525		recordregion(startloc, dest - stackblock(), 0);
526	TRACE(("expbackq: size=%td: \"%.*s\"\n",
527		((dest - stackblock()) - startloc),
528		(int)((dest - stackblock()) - startloc),
529		stackblock() + startloc));
530	expdest = dest;
531	INTON;
532}
533
534
535
536static int
537subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
538  int varflags, int quotes)
539{
540	char *startp;
541	char *loc = NULL;
542	char *q;
543	int c = 0;
544	struct nodelist *saveargbackq = argbackq;
545	int amount;
546
547	argstr(p, (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
548	    subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX ?
549	    EXP_CASE : 0) | EXP_TILDE);
550	STACKSTRNUL(expdest);
551	argbackq = saveargbackq;
552	startp = stackblock() + startloc;
553	if (str == NULL)
554	    str = stackblock() + strloc;
555
556	switch (subtype) {
557	case VSASSIGN:
558		setvar(str, startp, 0);
559		amount = startp - expdest;
560		STADJUST(amount, expdest);
561		varflags &= ~VSNUL;
562		return 1;
563
564	case VSQUESTION:
565		if (*p != CTLENDVAR) {
566			outfmt(out2, "%s\n", startp);
567			error((char *)NULL);
568		}
569		error("%.*s: parameter %snot set", (int)(p - str - 1),
570		      str, (varflags & VSNUL) ? "null or "
571					      : nullstr);
572		return 0;
573
574	case VSTRIMLEFT:
575		for (loc = startp; loc < str; loc++) {
576			c = *loc;
577			*loc = '\0';
578			if (patmatch(str, startp, quotes)) {
579				*loc = c;
580				goto recordleft;
581			}
582			*loc = c;
583			if (quotes && *loc == CTLESC)
584				loc++;
585		}
586		return 0;
587
588	case VSTRIMLEFTMAX:
589		for (loc = str - 1; loc >= startp;) {
590			c = *loc;
591			*loc = '\0';
592			if (patmatch(str, startp, quotes)) {
593				*loc = c;
594				goto recordleft;
595			}
596			*loc = c;
597			loc--;
598			if (quotes && loc > startp && *(loc - 1) == CTLESC) {
599				for (q = startp; q < loc; q++)
600					if (*q == CTLESC)
601						q++;
602				if (q > loc)
603					loc--;
604			}
605		}
606		return 0;
607
608	case VSTRIMRIGHT:
609		for (loc = str - 1; loc >= startp;) {
610			if (patmatch(str, loc, quotes)) {
611				amount = loc - expdest;
612				STADJUST(amount, expdest);
613				return 1;
614			}
615			loc--;
616			if (quotes && loc > startp && *(loc - 1) == CTLESC) {
617				for (q = startp; q < loc; q++)
618					if (*q == CTLESC)
619						q++;
620				if (q > loc)
621					loc--;
622			}
623		}
624		return 0;
625
626	case VSTRIMRIGHTMAX:
627		for (loc = startp; loc < str - 1; loc++) {
628			if (patmatch(str, loc, quotes)) {
629				amount = loc - expdest;
630				STADJUST(amount, expdest);
631				return 1;
632			}
633			if (quotes && *loc == CTLESC)
634				loc++;
635		}
636		return 0;
637
638
639	default:
640		abort();
641	}
642
643recordleft:
644	amount = ((str - 1) - (loc - startp)) - expdest;
645	STADJUST(amount, expdest);
646	while (loc != str - 1)
647		*startp++ = *loc++;
648	return 1;
649}
650
651
652/*
653 * Expand a variable, and return a pointer to the next character in the
654 * input string.
655 */
656
657static char *
658evalvar(char *p, int flag)
659{
660	int subtype;
661	int varflags;
662	char *var;
663	char *val;
664	int patloc;
665	int c;
666	int set;
667	int special;
668	int startloc;
669	int varlen;
670	int varlenb;
671	int easy;
672	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
673
674	varflags = (unsigned char)*p++;
675	subtype = varflags & VSTYPE;
676	var = p;
677	special = 0;
678	if (! is_name(*p))
679		special = 1;
680	p = strchr(p, '=') + 1;
681again: /* jump here after setting a variable with ${var=text} */
682	if (varflags & VSLINENO) {
683		set = 1;
684		special = 0;
685		val = var;
686		p[-1] = '\0';	/* temporarily overwrite '=' to have \0
687				   terminated string */
688	} else if (special) {
689		set = varisset(var, varflags & VSNUL);
690		val = NULL;
691	} else {
692		val = bltinlookup(var, 1);
693		if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
694			val = NULL;
695			set = 0;
696		} else
697			set = 1;
698	}
699	varlen = 0;
700	startloc = expdest - stackblock();
701	if (!set && uflag && *var != '@' && *var != '*') {
702		switch (subtype) {
703		case VSNORMAL:
704		case VSTRIMLEFT:
705		case VSTRIMLEFTMAX:
706		case VSTRIMRIGHT:
707		case VSTRIMRIGHTMAX:
708		case VSLENGTH:
709			error("%.*s: parameter not set", (int)(p - var - 1),
710			    var);
711		}
712	}
713	if (set && subtype != VSPLUS) {
714		/* insert the value of the variable */
715		if (special) {
716			varvalue(var, varflags & VSQUOTE, subtype, flag);
717			if (subtype == VSLENGTH) {
718				varlenb = expdest - stackblock() - startloc;
719				varlen = varlenb;
720				if (localeisutf8) {
721					val = stackblock() + startloc;
722					for (;val != expdest; val++)
723						if ((*val & 0xC0) == 0x80)
724							varlen--;
725				}
726				STADJUST(-varlenb, expdest);
727			}
728		} else {
729			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
730								  : BASESYNTAX;
731
732			if (subtype == VSLENGTH) {
733				for (;*val; val++)
734					if (!localeisutf8 ||
735					    (*val & 0xC0) != 0x80)
736						varlen++;
737			}
738			else {
739				if (quotes)
740					STPUTS_QUOTES(val, syntax, expdest);
741				else
742					STPUTS(val, expdest);
743
744			}
745		}
746	}
747
748	if (subtype == VSPLUS)
749		set = ! set;
750
751	easy = ((varflags & VSQUOTE) == 0 ||
752		(*var == '@' && shellparam.nparam != 1));
753
754
755	switch (subtype) {
756	case VSLENGTH:
757		expdest = cvtnum(varlen, expdest);
758		goto record;
759
760	case VSNORMAL:
761		if (!easy)
762			break;
763record:
764		recordregion(startloc, expdest - stackblock(),
765		    varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' &&
766		    (*var == '@' || *var == '*')));
767		break;
768
769	case VSPLUS:
770	case VSMINUS:
771		if (!set) {
772			argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) |
773			    (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0));
774			break;
775		}
776		if (easy)
777			goto record;
778		break;
779
780	case VSTRIMLEFT:
781	case VSTRIMLEFTMAX:
782	case VSTRIMRIGHT:
783	case VSTRIMRIGHTMAX:
784		if (!set)
785			break;
786		/*
787		 * Terminate the string and start recording the pattern
788		 * right after it
789		 */
790		STPUTC('\0', expdest);
791		patloc = expdest - stackblock();
792		if (subevalvar(p, NULL, patloc, subtype,
793		    startloc, varflags, quotes) == 0) {
794			int amount = (expdest - stackblock() - patloc) + 1;
795			STADJUST(-amount, expdest);
796		}
797		/* Remove any recorded regions beyond start of variable */
798		removerecordregions(startloc);
799		goto record;
800
801	case VSASSIGN:
802	case VSQUESTION:
803		if (!set) {
804			if (subevalvar(p, var, 0, subtype, startloc, varflags,
805			    quotes)) {
806				varflags &= ~VSNUL;
807				/*
808				 * Remove any recorded regions beyond
809				 * start of variable
810				 */
811				removerecordregions(startloc);
812				goto again;
813			}
814			break;
815		}
816		if (easy)
817			goto record;
818		break;
819
820	case VSERROR:
821		c = p - var - 1;
822		error("${%.*s%s}: Bad substitution", c, var,
823		    (c > 0 && *p != CTLENDVAR) ? "..." : "");
824
825	default:
826		abort();
827	}
828	p[-1] = '=';	/* recover overwritten '=' */
829
830	if (subtype != VSNORMAL) {	/* skip to end of alternative */
831		int nesting = 1;
832		for (;;) {
833			if ((c = *p++) == CTLESC)
834				p++;
835			else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
836				if (set)
837					argbackq = argbackq->next;
838			} else if (c == CTLVAR) {
839				if ((*p++ & VSTYPE) != VSNORMAL)
840					nesting++;
841			} else if (c == CTLENDVAR) {
842				if (--nesting == 0)
843					break;
844			}
845		}
846	}
847	return p;
848}
849
850
851
852/*
853 * Test whether a specialized variable is set.
854 */
855
856static int
857varisset(char *name, int nulok)
858{
859
860	if (*name == '!')
861		return backgndpidset();
862	else if (*name == '@' || *name == '*') {
863		if (*shellparam.p == NULL)
864			return 0;
865
866		if (nulok) {
867			char **av;
868
869			for (av = shellparam.p; *av; av++)
870				if (**av != '\0')
871					return 1;
872			return 0;
873		}
874	} else if (is_digit(*name)) {
875		char *ap;
876		int num = atoi(name);
877
878		if (num > shellparam.nparam)
879			return 0;
880
881		if (num == 0)
882			ap = arg0;
883		else
884			ap = shellparam.p[num - 1];
885
886		if (nulok && (ap == NULL || *ap == '\0'))
887			return 0;
888	}
889	return 1;
890}
891
892static void
893strtodest(const char *p, int flag, int subtype, int quoted)
894{
895	if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH)
896		STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest);
897	else
898		STPUTS(p, expdest);
899}
900
901/*
902 * Add the value of a specialized variable to the stack string.
903 */
904
905static void
906varvalue(char *name, int quoted, int subtype, int flag)
907{
908	int num;
909	char *p;
910	int i;
911	char sep;
912	char **ap;
913
914	switch (*name) {
915	case '$':
916		num = rootpid;
917		goto numvar;
918	case '?':
919		num = oexitstatus;
920		goto numvar;
921	case '#':
922		num = shellparam.nparam;
923		goto numvar;
924	case '!':
925		num = backgndpidval();
926numvar:
927		expdest = cvtnum(num, expdest);
928		break;
929	case '-':
930		for (i = 0 ; i < NOPTS ; i++) {
931			if (optlist[i].val)
932				STPUTC(optlist[i].letter, expdest);
933		}
934		break;
935	case '@':
936		if (flag & EXP_FULL && quoted) {
937			for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
938				strtodest(p, flag, subtype, quoted);
939				if (*ap)
940					STPUTC('\0', expdest);
941			}
942			break;
943		}
944		/* FALLTHROUGH */
945	case '*':
946		if (ifsset())
947			sep = ifsval()[0];
948		else
949			sep = ' ';
950		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
951			strtodest(p, flag, subtype, quoted);
952			if (!*ap)
953				break;
954			if (sep || (flag & EXP_FULL && !quoted && **ap != '\0'))
955				STPUTC(sep, expdest);
956		}
957		break;
958	case '0':
959		p = arg0;
960		strtodest(p, flag, subtype, quoted);
961		break;
962	default:
963		if (is_digit(*name)) {
964			num = atoi(name);
965			if (num > 0 && num <= shellparam.nparam) {
966				p = shellparam.p[num - 1];
967				strtodest(p, flag, subtype, quoted);
968			}
969		}
970		break;
971	}
972}
973
974
975
976/*
977 * Record the fact that we have to scan this region of the
978 * string for IFS characters.
979 */
980
981static void
982recordregion(int start, int end, int inquotes)
983{
984	struct ifsregion *ifsp;
985
986	if (ifslastp == NULL) {
987		ifsp = &ifsfirst;
988	} else {
989		if (ifslastp->endoff == start
990		    && ifslastp->inquotes == inquotes) {
991			/* extend previous area */
992			ifslastp->endoff = end;
993			return;
994		}
995		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
996		ifslastp->next = ifsp;
997	}
998	ifslastp = ifsp;
999	ifslastp->next = NULL;
1000	ifslastp->begoff = start;
1001	ifslastp->endoff = end;
1002	ifslastp->inquotes = inquotes;
1003}
1004
1005
1006
1007/*
1008 * Break the argument string into pieces based upon IFS and add the
1009 * strings to the argument list.  The regions of the string to be
1010 * searched for IFS characters have been stored by recordregion.
1011 * CTLESC characters are preserved but have little effect in this pass
1012 * other than escaping CTL* characters.  In particular, they do not escape
1013 * IFS characters: that should be done with the ifsregion mechanism.
1014 * CTLQUOTEMARK characters are used to preserve empty quoted strings.
1015 * This pass treats them as a regular character, making the string non-empty.
1016 * Later, they are removed along with the other CTL* characters.
1017 */
1018static void
1019ifsbreakup(char *string, struct arglist *arglist)
1020{
1021	struct ifsregion *ifsp;
1022	struct strlist *sp;
1023	char *start;
1024	char *p;
1025	char *q;
1026	const char *ifs;
1027	const char *ifsspc;
1028	int had_param_ch = 0;
1029
1030	start = string;
1031
1032	if (ifslastp == NULL) {
1033		/* Return entire argument, IFS doesn't apply to any of it */
1034		sp = (struct strlist *)stalloc(sizeof *sp);
1035		sp->text = start;
1036		*arglist->lastp = sp;
1037		arglist->lastp = &sp->next;
1038		return;
1039	}
1040
1041	ifs = ifsset() ? ifsval() : " \t\n";
1042
1043	for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
1044		p = string + ifsp->begoff;
1045		while (p < string + ifsp->endoff) {
1046			q = p;
1047			if (*p == CTLESC)
1048				p++;
1049			if (ifsp->inquotes) {
1050				/* Only NULs (should be from "$@") end args */
1051				had_param_ch = 1;
1052				if (*p != 0) {
1053					p++;
1054					continue;
1055				}
1056				ifsspc = NULL;
1057			} else {
1058				if (!strchr(ifs, *p)) {
1059					had_param_ch = 1;
1060					p++;
1061					continue;
1062				}
1063				ifsspc = strchr(" \t\n", *p);
1064
1065				/* Ignore IFS whitespace at start */
1066				if (q == start && ifsspc != NULL) {
1067					p++;
1068					start = p;
1069					continue;
1070				}
1071				had_param_ch = 0;
1072			}
1073
1074			/* Save this argument... */
1075			*q = '\0';
1076			sp = (struct strlist *)stalloc(sizeof *sp);
1077			sp->text = start;
1078			*arglist->lastp = sp;
1079			arglist->lastp = &sp->next;
1080			p++;
1081
1082			if (ifsspc != NULL) {
1083				/* Ignore further trailing IFS whitespace */
1084				for (; p < string + ifsp->endoff; p++) {
1085					q = p;
1086					if (*p == CTLESC)
1087						p++;
1088					if (strchr(ifs, *p) == NULL) {
1089						p = q;
1090						break;
1091					}
1092					if (strchr(" \t\n", *p) == NULL) {
1093						p++;
1094						break;
1095					}
1096				}
1097			}
1098			start = p;
1099		}
1100	}
1101
1102	/*
1103	 * Save anything left as an argument.
1104	 * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
1105	 * generating 2 arguments, the second of which is empty.
1106	 * Some recent clarification of the Posix spec say that it
1107	 * should only generate one....
1108	 */
1109	if (had_param_ch || *start != 0) {
1110		sp = (struct strlist *)stalloc(sizeof *sp);
1111		sp->text = start;
1112		*arglist->lastp = sp;
1113		arglist->lastp = &sp->next;
1114	}
1115}
1116
1117
1118static char expdir[PATH_MAX];
1119#define expdir_end (expdir + sizeof(expdir))
1120
1121/*
1122 * Perform pathname generation and remove control characters.
1123 * At this point, the only control characters should be CTLESC and CTLQUOTEMARK.
1124 * The results are stored in the list exparg.
1125 */
1126static void
1127expandmeta(struct strlist *str, int flag __unused)
1128{
1129	char *p;
1130	struct strlist **savelastp;
1131	struct strlist *sp;
1132	char c;
1133	/* TODO - EXP_REDIR */
1134
1135	while (str) {
1136		if (fflag)
1137			goto nometa;
1138		p = str->text;
1139		for (;;) {			/* fast check for meta chars */
1140			if ((c = *p++) == '\0')
1141				goto nometa;
1142			if (c == '*' || c == '?' || c == '[')
1143				break;
1144		}
1145		savelastp = exparg.lastp;
1146		INTOFF;
1147		expmeta(expdir, str->text);
1148		INTON;
1149		if (exparg.lastp == savelastp) {
1150			/*
1151			 * no matches
1152			 */
1153nometa:
1154			*exparg.lastp = str;
1155			rmescapes(str->text);
1156			exparg.lastp = &str->next;
1157		} else {
1158			*exparg.lastp = NULL;
1159			*savelastp = sp = expsort(*savelastp);
1160			while (sp->next != NULL)
1161				sp = sp->next;
1162			exparg.lastp = &sp->next;
1163		}
1164		str = str->next;
1165	}
1166}
1167
1168
1169/*
1170 * Do metacharacter (i.e. *, ?, [...]) expansion.
1171 */
1172
1173static void
1174expmeta(char *enddir, char *name)
1175{
1176	char *p;
1177	char *q;
1178	char *start;
1179	char *endname;
1180	int metaflag;
1181	struct stat statb;
1182	DIR *dirp;
1183	struct dirent *dp;
1184	int atend;
1185	int matchdot;
1186	int esc;
1187
1188	metaflag = 0;
1189	start = name;
1190	for (p = name; esc = 0, *p; p += esc + 1) {
1191		if (*p == '*' || *p == '?')
1192			metaflag = 1;
1193		else if (*p == '[') {
1194			q = p + 1;
1195			if (*q == '!' || *q == '^')
1196				q++;
1197			for (;;) {
1198				while (*q == CTLQUOTEMARK)
1199					q++;
1200				if (*q == CTLESC)
1201					q++;
1202				if (*q == '/' || *q == '\0')
1203					break;
1204				if (*++q == ']') {
1205					metaflag = 1;
1206					break;
1207				}
1208			}
1209		} else if (*p == '\0')
1210			break;
1211		else if (*p == CTLQUOTEMARK)
1212			continue;
1213		else {
1214			if (*p == CTLESC)
1215				esc++;
1216			if (p[esc] == '/') {
1217				if (metaflag)
1218					break;
1219				start = p + esc + 1;
1220			}
1221		}
1222	}
1223	if (metaflag == 0) {	/* we've reached the end of the file name */
1224		if (enddir != expdir)
1225			metaflag++;
1226		for (p = name ; ; p++) {
1227			if (*p == CTLQUOTEMARK)
1228				continue;
1229			if (*p == CTLESC)
1230				p++;
1231			*enddir++ = *p;
1232			if (*p == '\0')
1233				break;
1234			if (enddir == expdir_end)
1235				return;
1236		}
1237		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
1238			addfname(expdir);
1239		return;
1240	}
1241	endname = p;
1242	if (start != name) {
1243		p = name;
1244		while (p < start) {
1245			while (*p == CTLQUOTEMARK)
1246				p++;
1247			if (*p == CTLESC)
1248				p++;
1249			*enddir++ = *p++;
1250			if (enddir == expdir_end)
1251				return;
1252		}
1253	}
1254	if (enddir == expdir) {
1255		p = ".";
1256	} else if (enddir == expdir + 1 && *expdir == '/') {
1257		p = "/";
1258	} else {
1259		p = expdir;
1260		enddir[-1] = '\0';
1261	}
1262	if ((dirp = opendir(p)) == NULL)
1263		return;
1264	if (enddir != expdir)
1265		enddir[-1] = '/';
1266	if (*endname == 0) {
1267		atend = 1;
1268	} else {
1269		atend = 0;
1270		*endname = '\0';
1271		endname += esc + 1;
1272	}
1273	matchdot = 0;
1274	p = start;
1275	while (*p == CTLQUOTEMARK)
1276		p++;
1277	if (*p == CTLESC)
1278		p++;
1279	if (*p == '.')
1280		matchdot++;
1281	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
1282		if (dp->d_name[0] == '.' && ! matchdot)
1283			continue;
1284		if (patmatch(start, dp->d_name, 0)) {
1285			if (enddir + dp->d_namlen + 1 > expdir_end)
1286				continue;
1287			memcpy(enddir, dp->d_name, dp->d_namlen + 1);
1288			if (atend)
1289				addfname(expdir);
1290			else {
1291				if (enddir + dp->d_namlen + 2 > expdir_end)
1292					continue;
1293				enddir[dp->d_namlen] = '/';
1294				enddir[dp->d_namlen + 1] = '\0';
1295				expmeta(enddir + dp->d_namlen + 1, endname);
1296			}
1297		}
1298	}
1299	closedir(dirp);
1300	if (! atend)
1301		endname[-esc - 1] = esc ? CTLESC : '/';
1302}
1303
1304
1305/*
1306 * Add a file name to the list.
1307 */
1308
1309static void
1310addfname(char *name)
1311{
1312	char *p;
1313	struct strlist *sp;
1314
1315	p = stalloc(strlen(name) + 1);
1316	scopy(name, p);
1317	sp = (struct strlist *)stalloc(sizeof *sp);
1318	sp->text = p;
1319	*exparg.lastp = sp;
1320	exparg.lastp = &sp->next;
1321}
1322
1323
1324/*
1325 * Sort the results of file name expansion.  It calculates the number of
1326 * strings to sort and then calls msort (short for merge sort) to do the
1327 * work.
1328 */
1329
1330static struct strlist *
1331expsort(struct strlist *str)
1332{
1333	int len;
1334	struct strlist *sp;
1335
1336	len = 0;
1337	for (sp = str ; sp ; sp = sp->next)
1338		len++;
1339	return msort(str, len);
1340}
1341
1342
1343static struct strlist *
1344msort(struct strlist *list, int len)
1345{
1346	struct strlist *p, *q = NULL;
1347	struct strlist **lpp;
1348	int half;
1349	int n;
1350
1351	if (len <= 1)
1352		return list;
1353	half = len >> 1;
1354	p = list;
1355	for (n = half ; --n >= 0 ; ) {
1356		q = p;
1357		p = p->next;
1358	}
1359	q->next = NULL;			/* terminate first half of list */
1360	q = msort(list, half);		/* sort first half of list */
1361	p = msort(p, len - half);		/* sort second half */
1362	lpp = &list;
1363	for (;;) {
1364		if (strcmp(p->text, q->text) < 0) {
1365			*lpp = p;
1366			lpp = &p->next;
1367			if ((p = *lpp) == NULL) {
1368				*lpp = q;
1369				break;
1370			}
1371		} else {
1372			*lpp = q;
1373			lpp = &q->next;
1374			if ((q = *lpp) == NULL) {
1375				*lpp = p;
1376				break;
1377			}
1378		}
1379	}
1380	return list;
1381}
1382
1383
1384
1385static wchar_t
1386get_wc(const char **p)
1387{
1388	wchar_t c;
1389	int chrlen;
1390
1391	chrlen = mbtowc(&c, *p, 4);
1392	if (chrlen == 0)
1393		return 0;
1394	else if (chrlen == -1)
1395		c = 0;
1396	else
1397		*p += chrlen;
1398	return c;
1399}
1400
1401
1402/*
1403 * Returns true if the pattern matches the string.
1404 */
1405
1406int
1407patmatch(const char *pattern, const char *string, int squoted)
1408{
1409	const char *p, *q;
1410	char c;
1411	wchar_t wc, wc2;
1412
1413	p = pattern;
1414	q = string;
1415	for (;;) {
1416		switch (c = *p++) {
1417		case '\0':
1418			goto breakloop;
1419		case CTLESC:
1420			if (squoted && *q == CTLESC)
1421				q++;
1422			if (*q++ != *p++)
1423				return 0;
1424			break;
1425		case CTLQUOTEMARK:
1426			continue;
1427		case '?':
1428			if (squoted && *q == CTLESC)
1429				q++;
1430			if (localeisutf8)
1431				wc = get_wc(&q);
1432			else
1433				wc = *q++;
1434			if (wc == '\0')
1435				return 0;
1436			break;
1437		case '*':
1438			c = *p;
1439			while (c == CTLQUOTEMARK || c == '*')
1440				c = *++p;
1441			if (c != CTLESC &&  c != CTLQUOTEMARK &&
1442			    c != '?' && c != '*' && c != '[') {
1443				while (*q != c) {
1444					if (squoted && *q == CTLESC &&
1445					    q[1] == c)
1446						break;
1447					if (*q == '\0')
1448						return 0;
1449					if (squoted && *q == CTLESC)
1450						q++;
1451					q++;
1452				}
1453			}
1454			do {
1455				if (patmatch(p, q, squoted))
1456					return 1;
1457				if (squoted && *q == CTLESC)
1458					q++;
1459			} while (*q++ != '\0');
1460			return 0;
1461		case '[': {
1462			const char *endp;
1463			int invert, found;
1464			wchar_t chr;
1465
1466			endp = p;
1467			if (*endp == '!' || *endp == '^')
1468				endp++;
1469			for (;;) {
1470				while (*endp == CTLQUOTEMARK)
1471					endp++;
1472				if (*endp == '\0')
1473					goto dft;		/* no matching ] */
1474				if (*endp == CTLESC)
1475					endp++;
1476				if (*++endp == ']')
1477					break;
1478			}
1479			invert = 0;
1480			if (*p == '!' || *p == '^') {
1481				invert++;
1482				p++;
1483			}
1484			found = 0;
1485			if (squoted && *q == CTLESC)
1486				q++;
1487			if (localeisutf8)
1488				chr = get_wc(&q);
1489			else
1490				chr = *q++;
1491			if (chr == '\0')
1492				return 0;
1493			c = *p++;
1494			do {
1495				if (c == CTLQUOTEMARK)
1496					continue;
1497				if (c == CTLESC)
1498					c = *p++;
1499				if (localeisutf8 && c & 0x80) {
1500					p--;
1501					wc = get_wc(&p);
1502					if (wc == 0) /* bad utf-8 */
1503						return 0;
1504				} else
1505					wc = c;
1506				if (*p == '-' && p[1] != ']') {
1507					p++;
1508					while (*p == CTLQUOTEMARK)
1509						p++;
1510					if (*p == CTLESC)
1511						p++;
1512					if (localeisutf8) {
1513						wc2 = get_wc(&p);
1514						if (wc2 == 0) /* bad utf-8 */
1515							return 0;
1516					} else
1517						wc2 = *p++;
1518					if (   collate_range_cmp(chr, wc) >= 0
1519					    && collate_range_cmp(chr, wc2) <= 0
1520					   )
1521						found = 1;
1522				} else {
1523					if (chr == wc)
1524						found = 1;
1525				}
1526			} while ((c = *p++) != ']');
1527			if (found == invert)
1528				return 0;
1529			break;
1530		}
1531dft:	        default:
1532			if (squoted && *q == CTLESC)
1533				q++;
1534			if (*q++ != c)
1535				return 0;
1536			break;
1537		}
1538	}
1539breakloop:
1540	if (*q != '\0')
1541		return 0;
1542	return 1;
1543}
1544
1545
1546
1547/*
1548 * Remove any CTLESC and CTLQUOTEMARK characters from a string.
1549 */
1550
1551void
1552rmescapes(char *str)
1553{
1554	char *p, *q;
1555
1556	p = str;
1557	while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) {
1558		if (*p++ == '\0')
1559			return;
1560	}
1561	q = p;
1562	while (*p) {
1563		if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
1564			p++;
1565			continue;
1566		}
1567		if (*p == CTLESC)
1568			p++;
1569		*q++ = *p++;
1570	}
1571	*q = '\0';
1572}
1573
1574
1575
1576/*
1577 * See if a pattern matches in a case statement.
1578 */
1579
1580int
1581casematch(union node *pattern, const char *val)
1582{
1583	struct stackmark smark;
1584	int result;
1585	char *p;
1586
1587	setstackmark(&smark);
1588	argbackq = pattern->narg.backquote;
1589	STARTSTACKSTR(expdest);
1590	ifslastp = NULL;
1591	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
1592	STPUTC('\0', expdest);
1593	p = grabstackstr(expdest);
1594	result = patmatch(p, val, 0);
1595	popstackmark(&smark);
1596	return result;
1597}
1598
1599/*
1600 * Our own itoa().
1601 */
1602
1603static char *
1604cvtnum(int num, char *buf)
1605{
1606	char temp[32];
1607	int neg = num < 0;
1608	char *p = temp + 31;
1609
1610	temp[31] = '\0';
1611
1612	do {
1613		*--p = num % 10 + '0';
1614	} while ((num /= 10) != 0);
1615
1616	if (neg)
1617		*--p = '-';
1618
1619	STPUTS(p, buf);
1620	return buf;
1621}
1622
1623/*
1624 * Check statically if expanding a string may have side effects.
1625 */
1626int
1627expandhassideeffects(const char *p)
1628{
1629	int c;
1630	int arinest;
1631
1632	arinest = 0;
1633	while ((c = *p++) != '\0') {
1634		switch (c) {
1635		case CTLESC:
1636			p++;
1637			break;
1638		case CTLVAR:
1639			c = *p++;
1640			/* Expanding $! sets the job to remembered. */
1641			if (*p == '!')
1642				return 1;
1643			if ((c & VSTYPE) == VSASSIGN)
1644				return 1;
1645			/*
1646			 * If we are in arithmetic, the parameter may contain
1647			 * '=' which may cause side effects. Exceptions are
1648			 * the length of a parameter and $$, $# and $? which
1649			 * are always numeric.
1650			 */
1651			if ((c & VSTYPE) == VSLENGTH) {
1652				while (*p != '=')
1653					p++;
1654				p++;
1655				break;
1656			}
1657			if ((*p == '$' || *p == '#' || *p == '?') &&
1658			    p[1] == '=') {
1659				p += 2;
1660				break;
1661			}
1662			if (arinest > 0)
1663				return 1;
1664			break;
1665		case CTLBACKQ:
1666		case CTLBACKQ | CTLQUOTE:
1667			if (arinest > 0)
1668				return 1;
1669			break;
1670		case CTLARI:
1671			arinest++;
1672			break;
1673		case CTLENDARI:
1674			arinest--;
1675			break;
1676		case '=':
1677			if (*p == '=') {
1678				/* Allow '==' operator. */
1679				p++;
1680				continue;
1681			}
1682			if (arinest > 0)
1683				return 1;
1684			break;
1685		case '!': case '<': case '>':
1686			/* Allow '!=', '<=', '>=' operators. */
1687			if (*p == '=')
1688				p++;
1689			break;
1690		}
1691	}
1692	return 0;
1693}
1694
1695/*
1696 * Do most of the work for wordexp(3).
1697 */
1698
1699int
1700wordexpcmd(int argc, char **argv)
1701{
1702	size_t len;
1703	int i;
1704
1705	out1fmt("%08x", argc - 1);
1706	for (i = 1, len = 0; i < argc; i++)
1707		len += strlen(argv[i]);
1708	out1fmt("%08x", (int)len);
1709	for (i = 1; i < argc; i++)
1710		outbin(argv[i], strlen(argv[i]) + 1, out1);
1711        return (0);
1712}
1713