Home | History | Annotate | Line # | Download | only in rdist
expand.c revision 1.1.1.2
      1      1.1  cgd /*
      2  1.1.1.2  mrg  * Copyright (c) 1983, 1993
      3  1.1.1.2  mrg  *	The Regents of the University of California.  All rights reserved.
      4      1.1  cgd  *
      5      1.1  cgd  * Redistribution and use in source and binary forms, with or without
      6      1.1  cgd  * modification, are permitted provided that the following conditions
      7      1.1  cgd  * are met:
      8      1.1  cgd  * 1. Redistributions of source code must retain the above copyright
      9      1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     10      1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11      1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     12      1.1  cgd  *    documentation and/or other materials provided with the distribution.
     13      1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     14      1.1  cgd  *    must display the following acknowledgement:
     15      1.1  cgd  *	This product includes software developed by the University of
     16      1.1  cgd  *	California, Berkeley and its contributors.
     17      1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     18      1.1  cgd  *    may be used to endorse or promote products derived from this software
     19      1.1  cgd  *    without specific prior written permission.
     20      1.1  cgd  *
     21      1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1  cgd  * SUCH DAMAGE.
     32      1.1  cgd  */
     33      1.1  cgd 
     34      1.1  cgd #ifndef lint
     35  1.1.1.2  mrg static char sccsid[] = "@(#)expand.c	8.1 (Berkeley) 6/9/93";
     36      1.1  cgd #endif /* not lint */
     37      1.1  cgd 
     38      1.1  cgd #include "defs.h"
     39      1.1  cgd 
     40      1.1  cgd #define	GAVSIZ	NCARGS / 6
     41      1.1  cgd #define LC '{'
     42      1.1  cgd #define RC '}'
     43      1.1  cgd 
     44      1.1  cgd static char	shchars[] = "${[*?";
     45      1.1  cgd 
     46      1.1  cgd int	which;		/* bit mask of types to expand */
     47      1.1  cgd int	eargc;		/* expanded arg count */
     48      1.1  cgd char	**eargv;	/* expanded arg vectors */
     49      1.1  cgd char	*path;
     50      1.1  cgd char	*pathp;
     51      1.1  cgd char	*lastpathp;
     52      1.1  cgd char	*tilde;		/* "~user" if not expanding tilde, else "" */
     53      1.1  cgd char	*tpathp;
     54      1.1  cgd int	nleft;
     55      1.1  cgd 
     56      1.1  cgd int	expany;		/* any expansions done? */
     57      1.1  cgd char	*entp;
     58      1.1  cgd char	**sortbase;
     59      1.1  cgd 
     60      1.1  cgd #define sort()	qsort((char *)sortbase, &eargv[eargc] - sortbase, \
     61      1.1  cgd 		      sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]
     62      1.1  cgd 
     63  1.1.1.2  mrg static void	Cat __P((char *, char *));
     64  1.1.1.2  mrg static void	addpath __P((int));
     65  1.1.1.2  mrg static int	amatch __P((char *, char *));
     66  1.1.1.2  mrg static int	argcmp __P((const void *, const void *));
     67  1.1.1.2  mrg static int	execbrc __P((char *, char *));
     68  1.1.1.2  mrg static void	expsh __P((char *));
     69  1.1.1.2  mrg static void	expstr __P((char *));
     70  1.1.1.2  mrg static int	match __P((char *, char *));
     71  1.1.1.2  mrg static void	matchdir __P((char *));
     72  1.1.1.2  mrg static int	smatch __P((char *, char *));
     73  1.1.1.2  mrg 
     74      1.1  cgd /*
     75      1.1  cgd  * Take a list of names and expand any macros, etc.
     76      1.1  cgd  * wh = E_VARS if expanding variables.
     77      1.1  cgd  * wh = E_SHELL if expanding shell characters.
     78      1.1  cgd  * wh = E_TILDE if expanding `~'.
     79      1.1  cgd  * or any of these or'ed together.
     80      1.1  cgd  *
     81      1.1  cgd  * Major portions of this were snarfed from csh/sh.glob.c.
     82      1.1  cgd  */
     83      1.1  cgd struct namelist *
     84      1.1  cgd expand(list, wh)
     85      1.1  cgd 	struct namelist *list;
     86      1.1  cgd 	int wh;
     87      1.1  cgd {
     88      1.1  cgd 	register struct namelist *nl, *prev;
     89      1.1  cgd 	register int n;
     90      1.1  cgd 	char pathbuf[BUFSIZ];
     91      1.1  cgd 	char *argvbuf[GAVSIZ];
     92      1.1  cgd 
     93      1.1  cgd 	if (debug) {
     94      1.1  cgd 		printf("expand(%x, %d)\nlist = ", list, wh);
     95      1.1  cgd 		prnames(list);
     96      1.1  cgd 	}
     97      1.1  cgd 
     98      1.1  cgd 	if (wh == 0) {
     99      1.1  cgd 		register char *cp;
    100      1.1  cgd 
    101      1.1  cgd 		for (nl = list; nl != NULL; nl = nl->n_next)
    102      1.1  cgd 			for (cp = nl->n_name; *cp; cp++)
    103      1.1  cgd 				*cp = *cp & TRIM;
    104      1.1  cgd 		return(list);
    105      1.1  cgd 	}
    106      1.1  cgd 
    107      1.1  cgd 	which = wh;
    108      1.1  cgd 	path = tpathp = pathp = pathbuf;
    109      1.1  cgd 	*pathp = '\0';
    110      1.1  cgd 	lastpathp = &path[sizeof pathbuf - 2];
    111      1.1  cgd 	tilde = "";
    112      1.1  cgd 	eargc = 0;
    113      1.1  cgd 	eargv = sortbase = argvbuf;
    114      1.1  cgd 	*eargv = 0;
    115      1.1  cgd 	nleft = NCARGS - 4;
    116      1.1  cgd 	/*
    117      1.1  cgd 	 * Walk the name list and expand names into eargv[];
    118      1.1  cgd 	 */
    119      1.1  cgd 	for (nl = list; nl != NULL; nl = nl->n_next)
    120      1.1  cgd 		expstr(nl->n_name);
    121      1.1  cgd 	/*
    122      1.1  cgd 	 * Take expanded list of names from eargv[] and build a new list.
    123      1.1  cgd 	 */
    124      1.1  cgd 	list = prev = NULL;
    125      1.1  cgd 	for (n = 0; n < eargc; n++) {
    126      1.1  cgd 		nl = makenl(NULL);
    127      1.1  cgd 		nl->n_name = eargv[n];
    128      1.1  cgd 		if (prev == NULL)
    129      1.1  cgd 			list = prev = nl;
    130      1.1  cgd 		else {
    131      1.1  cgd 			prev->n_next = nl;
    132      1.1  cgd 			prev = nl;
    133      1.1  cgd 		}
    134      1.1  cgd 	}
    135      1.1  cgd 	if (debug) {
    136      1.1  cgd 		printf("expanded list = ");
    137      1.1  cgd 		prnames(list);
    138      1.1  cgd 	}
    139      1.1  cgd 	return(list);
    140      1.1  cgd }
    141      1.1  cgd 
    142  1.1.1.2  mrg static void
    143      1.1  cgd expstr(s)
    144      1.1  cgd 	char *s;
    145      1.1  cgd {
    146      1.1  cgd 	register char *cp, *cp1;
    147      1.1  cgd 	register struct namelist *tp;
    148      1.1  cgd 	char *tail;
    149      1.1  cgd 	char buf[BUFSIZ];
    150      1.1  cgd 	int savec, oeargc;
    151      1.1  cgd 	extern char homedir[];
    152      1.1  cgd 
    153      1.1  cgd 	if (s == NULL || *s == '\0')
    154      1.1  cgd 		return;
    155      1.1  cgd 
    156      1.1  cgd 	if ((which & E_VARS) && (cp = index(s, '$')) != NULL) {
    157      1.1  cgd 		*cp++ = '\0';
    158      1.1  cgd 		if (*cp == '\0') {
    159      1.1  cgd 			yyerror("no variable name after '$'");
    160      1.1  cgd 			return;
    161      1.1  cgd 		}
    162      1.1  cgd 		if (*cp == LC) {
    163      1.1  cgd 			cp++;
    164      1.1  cgd 			if ((tail = index(cp, RC)) == NULL) {
    165      1.1  cgd 				yyerror("unmatched '{'");
    166      1.1  cgd 				return;
    167      1.1  cgd 			}
    168      1.1  cgd 			*tail++ = savec = '\0';
    169      1.1  cgd 			if (*cp == '\0') {
    170      1.1  cgd 				yyerror("no variable name after '$'");
    171      1.1  cgd 				return;
    172      1.1  cgd 			}
    173      1.1  cgd 		} else {
    174      1.1  cgd 			tail = cp + 1;
    175      1.1  cgd 			savec = *tail;
    176      1.1  cgd 			*tail = '\0';
    177      1.1  cgd 		}
    178      1.1  cgd 		tp = lookup(cp, NULL, 0);
    179      1.1  cgd 		if (savec != '\0')
    180      1.1  cgd 			*tail = savec;
    181      1.1  cgd 		if (tp != NULL) {
    182      1.1  cgd 			for (; tp != NULL; tp = tp->n_next) {
    183      1.1  cgd 				sprintf(buf, "%s%s%s", s, tp->n_name, tail);
    184      1.1  cgd 				expstr(buf);
    185      1.1  cgd 			}
    186      1.1  cgd 			return;
    187      1.1  cgd 		}
    188      1.1  cgd 		sprintf(buf, "%s%s", s, tail);
    189      1.1  cgd 		expstr(buf);
    190      1.1  cgd 		return;
    191      1.1  cgd 	}
    192      1.1  cgd 	if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {
    193      1.1  cgd 		Cat(s, "");
    194      1.1  cgd 		sort();
    195      1.1  cgd 		return;
    196      1.1  cgd 	}
    197      1.1  cgd 	if (*s == '~') {
    198      1.1  cgd 		cp = ++s;
    199      1.1  cgd 		if (*cp == '\0' || *cp == '/') {
    200      1.1  cgd 			tilde = "~";
    201      1.1  cgd 			cp1 = homedir;
    202      1.1  cgd 		} else {
    203      1.1  cgd 			tilde = cp1 = buf;
    204      1.1  cgd 			*cp1++ = '~';
    205      1.1  cgd 			do
    206      1.1  cgd 				*cp1++ = *cp++;
    207      1.1  cgd 			while (*cp && *cp != '/');
    208      1.1  cgd 			*cp1 = '\0';
    209      1.1  cgd 			if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) {
    210      1.1  cgd 				if ((pw = getpwnam(buf+1)) == NULL) {
    211      1.1  cgd 					strcat(buf, ": unknown user name");
    212      1.1  cgd 					yyerror(buf+1);
    213      1.1  cgd 					return;
    214      1.1  cgd 				}
    215      1.1  cgd 			}
    216      1.1  cgd 			cp1 = pw->pw_dir;
    217      1.1  cgd 			s = cp;
    218      1.1  cgd 		}
    219      1.1  cgd 		for (cp = path; *cp++ = *cp1++; )
    220      1.1  cgd 			;
    221      1.1  cgd 		tpathp = pathp = cp - 1;
    222      1.1  cgd 	} else {
    223      1.1  cgd 		tpathp = pathp = path;
    224      1.1  cgd 		tilde = "";
    225      1.1  cgd 	}
    226      1.1  cgd 	*pathp = '\0';
    227      1.1  cgd 	if (!(which & E_SHELL)) {
    228      1.1  cgd 		if (which & E_TILDE)
    229      1.1  cgd 			Cat(path, s);
    230      1.1  cgd 		else
    231      1.1  cgd 			Cat(tilde, s);
    232      1.1  cgd 		sort();
    233      1.1  cgd 		return;
    234      1.1  cgd 	}
    235      1.1  cgd 	oeargc = eargc;
    236      1.1  cgd 	expany = 0;
    237      1.1  cgd 	expsh(s);
    238      1.1  cgd 	if (eargc == oeargc)
    239      1.1  cgd 		Cat(s, "");		/* "nonomatch" is set */
    240      1.1  cgd 	sort();
    241      1.1  cgd }
    242      1.1  cgd 
    243  1.1.1.2  mrg static int
    244      1.1  cgd argcmp(a1, a2)
    245  1.1.1.2  mrg 	const void *a1, *a2;
    246      1.1  cgd {
    247      1.1  cgd 
    248  1.1.1.2  mrg 	return (strcmp(*(char **)a1, *(char **)a2));
    249      1.1  cgd }
    250      1.1  cgd 
    251      1.1  cgd /*
    252      1.1  cgd  * If there are any Shell meta characters in the name,
    253      1.1  cgd  * expand into a list, after searching directory
    254      1.1  cgd  */
    255  1.1.1.2  mrg static void
    256      1.1  cgd expsh(s)
    257      1.1  cgd 	char *s;
    258      1.1  cgd {
    259      1.1  cgd 	register char *cp;
    260      1.1  cgd 	register char *spathp, *oldcp;
    261      1.1  cgd 	struct stat stb;
    262      1.1  cgd 
    263      1.1  cgd 	spathp = pathp;
    264      1.1  cgd 	cp = s;
    265      1.1  cgd 	while (!any(*cp, shchars)) {
    266      1.1  cgd 		if (*cp == '\0') {
    267      1.1  cgd 			if (!expany || stat(path, &stb) >= 0) {
    268      1.1  cgd 				if (which & E_TILDE)
    269      1.1  cgd 					Cat(path, "");
    270      1.1  cgd 				else
    271      1.1  cgd 					Cat(tilde, tpathp);
    272      1.1  cgd 			}
    273      1.1  cgd 			goto endit;
    274      1.1  cgd 		}
    275      1.1  cgd 		addpath(*cp++);
    276      1.1  cgd 	}
    277      1.1  cgd 	oldcp = cp;
    278      1.1  cgd 	while (cp > s && *cp != '/')
    279      1.1  cgd 		cp--, pathp--;
    280      1.1  cgd 	if (*cp == '/')
    281      1.1  cgd 		cp++, pathp++;
    282      1.1  cgd 	*pathp = '\0';
    283      1.1  cgd 	if (*oldcp == '{') {
    284      1.1  cgd 		execbrc(cp, NULL);
    285      1.1  cgd 		return;
    286      1.1  cgd 	}
    287      1.1  cgd 	matchdir(cp);
    288      1.1  cgd endit:
    289      1.1  cgd 	pathp = spathp;
    290      1.1  cgd 	*pathp = '\0';
    291      1.1  cgd }
    292      1.1  cgd 
    293  1.1.1.2  mrg static void
    294      1.1  cgd matchdir(pattern)
    295      1.1  cgd 	char *pattern;
    296      1.1  cgd {
    297      1.1  cgd 	struct stat stb;
    298      1.1  cgd 	register struct direct *dp;
    299      1.1  cgd 	DIR *dirp;
    300      1.1  cgd 
    301      1.1  cgd 	dirp = opendir(path);
    302      1.1  cgd 	if (dirp == NULL) {
    303      1.1  cgd 		if (expany)
    304      1.1  cgd 			return;
    305      1.1  cgd 		goto patherr2;
    306      1.1  cgd 	}
    307      1.1  cgd 	if (fstat(dirp->dd_fd, &stb) < 0)
    308      1.1  cgd 		goto patherr1;
    309      1.1  cgd 	if (!ISDIR(stb.st_mode)) {
    310      1.1  cgd 		errno = ENOTDIR;
    311      1.1  cgd 		goto patherr1;
    312      1.1  cgd 	}
    313      1.1  cgd 	while ((dp = readdir(dirp)) != NULL)
    314      1.1  cgd 		if (match(dp->d_name, pattern)) {
    315      1.1  cgd 			if (which & E_TILDE)
    316      1.1  cgd 				Cat(path, dp->d_name);
    317      1.1  cgd 			else {
    318      1.1  cgd 				strcpy(pathp, dp->d_name);
    319      1.1  cgd 				Cat(tilde, tpathp);
    320      1.1  cgd 				*pathp = '\0';
    321      1.1  cgd 			}
    322      1.1  cgd 		}
    323      1.1  cgd 	closedir(dirp);
    324      1.1  cgd 	return;
    325      1.1  cgd 
    326      1.1  cgd patherr1:
    327      1.1  cgd 	closedir(dirp);
    328      1.1  cgd patherr2:
    329      1.1  cgd 	strcat(path, ": ");
    330      1.1  cgd 	strcat(path, strerror(errno));
    331      1.1  cgd 	yyerror(path);
    332      1.1  cgd }
    333      1.1  cgd 
    334  1.1.1.2  mrg static int
    335      1.1  cgd execbrc(p, s)
    336      1.1  cgd 	char *p, *s;
    337      1.1  cgd {
    338      1.1  cgd 	char restbuf[BUFSIZ + 2];
    339      1.1  cgd 	register char *pe, *pm, *pl;
    340      1.1  cgd 	int brclev = 0;
    341      1.1  cgd 	char *lm, savec, *spathp;
    342      1.1  cgd 
    343      1.1  cgd 	for (lm = restbuf; *p != '{'; *lm++ = *p++)
    344      1.1  cgd 		continue;
    345      1.1  cgd 	for (pe = ++p; *pe; pe++)
    346      1.1  cgd 		switch (*pe) {
    347      1.1  cgd 
    348      1.1  cgd 		case '{':
    349      1.1  cgd 			brclev++;
    350      1.1  cgd 			continue;
    351      1.1  cgd 
    352      1.1  cgd 		case '}':
    353      1.1  cgd 			if (brclev == 0)
    354      1.1  cgd 				goto pend;
    355      1.1  cgd 			brclev--;
    356      1.1  cgd 			continue;
    357      1.1  cgd 
    358      1.1  cgd 		case '[':
    359      1.1  cgd 			for (pe++; *pe && *pe != ']'; pe++)
    360      1.1  cgd 				continue;
    361      1.1  cgd 			if (!*pe)
    362      1.1  cgd 				yyerror("Missing ']'");
    363      1.1  cgd 			continue;
    364      1.1  cgd 		}
    365      1.1  cgd pend:
    366      1.1  cgd 	if (brclev || !*pe) {
    367      1.1  cgd 		yyerror("Missing '}'");
    368      1.1  cgd 		return (0);
    369      1.1  cgd 	}
    370      1.1  cgd 	for (pl = pm = p; pm <= pe; pm++)
    371      1.1  cgd 		switch (*pm & (QUOTE|TRIM)) {
    372      1.1  cgd 
    373      1.1  cgd 		case '{':
    374      1.1  cgd 			brclev++;
    375      1.1  cgd 			continue;
    376      1.1  cgd 
    377      1.1  cgd 		case '}':
    378      1.1  cgd 			if (brclev) {
    379      1.1  cgd 				brclev--;
    380      1.1  cgd 				continue;
    381      1.1  cgd 			}
    382      1.1  cgd 			goto doit;
    383      1.1  cgd 
    384      1.1  cgd 		case ',':
    385      1.1  cgd 			if (brclev)
    386      1.1  cgd 				continue;
    387      1.1  cgd doit:
    388      1.1  cgd 			savec = *pm;
    389      1.1  cgd 			*pm = 0;
    390      1.1  cgd 			strcpy(lm, pl);
    391      1.1  cgd 			strcat(restbuf, pe + 1);
    392      1.1  cgd 			*pm = savec;
    393      1.1  cgd 			if (s == 0) {
    394      1.1  cgd 				spathp = pathp;
    395      1.1  cgd 				expsh(restbuf);
    396      1.1  cgd 				pathp = spathp;
    397      1.1  cgd 				*pathp = 0;
    398      1.1  cgd 			} else if (amatch(s, restbuf))
    399      1.1  cgd 				return (1);
    400      1.1  cgd 			sort();
    401      1.1  cgd 			pl = pm + 1;
    402      1.1  cgd 			continue;
    403      1.1  cgd 
    404      1.1  cgd 		case '[':
    405      1.1  cgd 			for (pm++; *pm && *pm != ']'; pm++)
    406      1.1  cgd 				continue;
    407      1.1  cgd 			if (!*pm)
    408      1.1  cgd 				yyerror("Missing ']'");
    409      1.1  cgd 			continue;
    410      1.1  cgd 		}
    411      1.1  cgd 	return (0);
    412      1.1  cgd }
    413      1.1  cgd 
    414  1.1.1.2  mrg static int
    415      1.1  cgd match(s, p)
    416      1.1  cgd 	char *s, *p;
    417      1.1  cgd {
    418      1.1  cgd 	register int c;
    419      1.1  cgd 	register char *sentp;
    420      1.1  cgd 	char sexpany = expany;
    421      1.1  cgd 
    422      1.1  cgd 	if (*s == '.' && *p != '.')
    423      1.1  cgd 		return (0);
    424      1.1  cgd 	sentp = entp;
    425      1.1  cgd 	entp = s;
    426      1.1  cgd 	c = amatch(s, p);
    427      1.1  cgd 	entp = sentp;
    428      1.1  cgd 	expany = sexpany;
    429      1.1  cgd 	return (c);
    430      1.1  cgd }
    431      1.1  cgd 
    432  1.1.1.2  mrg static int
    433      1.1  cgd amatch(s, p)
    434      1.1  cgd 	register char *s, *p;
    435      1.1  cgd {
    436      1.1  cgd 	register int scc;
    437      1.1  cgd 	int ok, lc;
    438      1.1  cgd 	char *spathp;
    439      1.1  cgd 	struct stat stb;
    440      1.1  cgd 	int c, cc;
    441      1.1  cgd 
    442      1.1  cgd 	expany = 1;
    443      1.1  cgd 	for (;;) {
    444      1.1  cgd 		scc = *s++ & TRIM;
    445      1.1  cgd 		switch (c = *p++) {
    446      1.1  cgd 
    447      1.1  cgd 		case '{':
    448      1.1  cgd 			return (execbrc(p - 1, s - 1));
    449      1.1  cgd 
    450      1.1  cgd 		case '[':
    451      1.1  cgd 			ok = 0;
    452      1.1  cgd 			lc = 077777;
    453      1.1  cgd 			while (cc = *p++) {
    454      1.1  cgd 				if (cc == ']') {
    455      1.1  cgd 					if (ok)
    456      1.1  cgd 						break;
    457      1.1  cgd 					return (0);
    458      1.1  cgd 				}
    459      1.1  cgd 				if (cc == '-') {
    460      1.1  cgd 					if (lc <= scc && scc <= *p++)
    461      1.1  cgd 						ok++;
    462      1.1  cgd 				} else
    463      1.1  cgd 					if (scc == (lc = cc))
    464      1.1  cgd 						ok++;
    465      1.1  cgd 			}
    466      1.1  cgd 			if (cc == 0) {
    467      1.1  cgd 				yyerror("Missing ']'");
    468      1.1  cgd 				return (0);
    469      1.1  cgd 			}
    470      1.1  cgd 			continue;
    471      1.1  cgd 
    472      1.1  cgd 		case '*':
    473      1.1  cgd 			if (!*p)
    474      1.1  cgd 				return (1);
    475      1.1  cgd 			if (*p == '/') {
    476      1.1  cgd 				p++;
    477      1.1  cgd 				goto slash;
    478      1.1  cgd 			}
    479      1.1  cgd 			for (s--; *s; s++)
    480      1.1  cgd 				if (amatch(s, p))
    481      1.1  cgd 					return (1);
    482      1.1  cgd 			return (0);
    483      1.1  cgd 
    484      1.1  cgd 		case '\0':
    485      1.1  cgd 			return (scc == '\0');
    486      1.1  cgd 
    487      1.1  cgd 		default:
    488      1.1  cgd 			if ((c & TRIM) != scc)
    489      1.1  cgd 				return (0);
    490      1.1  cgd 			continue;
    491      1.1  cgd 
    492      1.1  cgd 		case '?':
    493      1.1  cgd 			if (scc == '\0')
    494      1.1  cgd 				return (0);
    495      1.1  cgd 			continue;
    496      1.1  cgd 
    497      1.1  cgd 		case '/':
    498      1.1  cgd 			if (scc)
    499      1.1  cgd 				return (0);
    500      1.1  cgd slash:
    501      1.1  cgd 			s = entp;
    502      1.1  cgd 			spathp = pathp;
    503      1.1  cgd 			while (*s)
    504      1.1  cgd 				addpath(*s++);
    505      1.1  cgd 			addpath('/');
    506      1.1  cgd 			if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))
    507      1.1  cgd 				if (*p == '\0') {
    508      1.1  cgd 					if (which & E_TILDE)
    509      1.1  cgd 						Cat(path, "");
    510      1.1  cgd 					else
    511      1.1  cgd 						Cat(tilde, tpathp);
    512      1.1  cgd 				} else
    513      1.1  cgd 					expsh(p);
    514      1.1  cgd 			pathp = spathp;
    515      1.1  cgd 			*pathp = '\0';
    516      1.1  cgd 			return (0);
    517      1.1  cgd 		}
    518      1.1  cgd 	}
    519      1.1  cgd }
    520      1.1  cgd 
    521  1.1.1.2  mrg static int
    522      1.1  cgd smatch(s, p)
    523      1.1  cgd 	register char *s, *p;
    524      1.1  cgd {
    525      1.1  cgd 	register int scc;
    526      1.1  cgd 	int ok, lc;
    527      1.1  cgd 	int c, cc;
    528      1.1  cgd 
    529      1.1  cgd 	for (;;) {
    530      1.1  cgd 		scc = *s++ & TRIM;
    531      1.1  cgd 		switch (c = *p++) {
    532      1.1  cgd 
    533      1.1  cgd 		case '[':
    534      1.1  cgd 			ok = 0;
    535      1.1  cgd 			lc = 077777;
    536      1.1  cgd 			while (cc = *p++) {
    537      1.1  cgd 				if (cc == ']') {
    538      1.1  cgd 					if (ok)
    539      1.1  cgd 						break;
    540      1.1  cgd 					return (0);
    541      1.1  cgd 				}
    542      1.1  cgd 				if (cc == '-') {
    543      1.1  cgd 					if (lc <= scc && scc <= *p++)
    544      1.1  cgd 						ok++;
    545      1.1  cgd 				} else
    546      1.1  cgd 					if (scc == (lc = cc))
    547      1.1  cgd 						ok++;
    548      1.1  cgd 			}
    549      1.1  cgd 			if (cc == 0) {
    550      1.1  cgd 				yyerror("Missing ']'");
    551      1.1  cgd 				return (0);
    552      1.1  cgd 			}
    553      1.1  cgd 			continue;
    554      1.1  cgd 
    555      1.1  cgd 		case '*':
    556      1.1  cgd 			if (!*p)
    557      1.1  cgd 				return (1);
    558      1.1  cgd 			for (s--; *s; s++)
    559      1.1  cgd 				if (smatch(s, p))
    560      1.1  cgd 					return (1);
    561      1.1  cgd 			return (0);
    562      1.1  cgd 
    563      1.1  cgd 		case '\0':
    564      1.1  cgd 			return (scc == '\0');
    565      1.1  cgd 
    566      1.1  cgd 		default:
    567      1.1  cgd 			if ((c & TRIM) != scc)
    568      1.1  cgd 				return (0);
    569      1.1  cgd 			continue;
    570      1.1  cgd 
    571      1.1  cgd 		case '?':
    572      1.1  cgd 			if (scc == 0)
    573      1.1  cgd 				return (0);
    574      1.1  cgd 			continue;
    575      1.1  cgd 
    576      1.1  cgd 		}
    577      1.1  cgd 	}
    578      1.1  cgd }
    579      1.1  cgd 
    580  1.1.1.2  mrg static void
    581      1.1  cgd Cat(s1, s2)
    582      1.1  cgd 	register char *s1, *s2;
    583      1.1  cgd {
    584      1.1  cgd 	int len = strlen(s1) + strlen(s2) + 1;
    585      1.1  cgd 	register char *s;
    586      1.1  cgd 
    587      1.1  cgd 	nleft -= len;
    588      1.1  cgd 	if (nleft <= 0 || ++eargc >= GAVSIZ)
    589      1.1  cgd 		yyerror("Arguments too long");
    590      1.1  cgd 	eargv[eargc] = 0;
    591      1.1  cgd 	eargv[eargc - 1] = s = malloc(len);
    592      1.1  cgd 	if (s == NULL)
    593      1.1  cgd 		fatal("ran out of memory\n");
    594      1.1  cgd 	while (*s++ = *s1++ & TRIM)
    595      1.1  cgd 		;
    596      1.1  cgd 	s--;
    597      1.1  cgd 	while (*s++ = *s2++ & TRIM)
    598      1.1  cgd 		;
    599      1.1  cgd }
    600      1.1  cgd 
    601  1.1.1.2  mrg static void
    602      1.1  cgd addpath(c)
    603  1.1.1.2  mrg 	int c;
    604      1.1  cgd {
    605      1.1  cgd 
    606      1.1  cgd 	if (pathp >= lastpathp)
    607      1.1  cgd 		yyerror("Pathname too long");
    608      1.1  cgd 	else {
    609      1.1  cgd 		*pathp++ = c & TRIM;
    610      1.1  cgd 		*pathp = '\0';
    611      1.1  cgd 	}
    612      1.1  cgd }
    613      1.1  cgd 
    614      1.1  cgd /*
    615      1.1  cgd  * Expand file names beginning with `~' into the
    616      1.1  cgd  * user's home directory path name. Return a pointer in buf to the
    617      1.1  cgd  * part corresponding to `file'.
    618      1.1  cgd  */
    619      1.1  cgd char *
    620      1.1  cgd exptilde(buf, file)
    621      1.1  cgd 	char buf[];
    622      1.1  cgd 	register char *file;
    623      1.1  cgd {
    624      1.1  cgd 	register char *s1, *s2, *s3;
    625      1.1  cgd 	extern char homedir[];
    626      1.1  cgd 
    627      1.1  cgd 	if (*file != '~') {
    628      1.1  cgd 		strcpy(buf, file);
    629      1.1  cgd 		return(buf);
    630      1.1  cgd 	}
    631      1.1  cgd 	if (*++file == '\0') {
    632      1.1  cgd 		s2 = homedir;
    633      1.1  cgd 		s3 = NULL;
    634      1.1  cgd 	} else if (*file == '/') {
    635      1.1  cgd 		s2 = homedir;
    636      1.1  cgd 		s3 = file;
    637      1.1  cgd 	} else {
    638      1.1  cgd 		s3 = file;
    639      1.1  cgd 		while (*s3 && *s3 != '/')
    640      1.1  cgd 			s3++;
    641      1.1  cgd 		if (*s3 == '/')
    642      1.1  cgd 			*s3 = '\0';
    643      1.1  cgd 		else
    644      1.1  cgd 			s3 = NULL;
    645      1.1  cgd 		if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
    646      1.1  cgd 			if ((pw = getpwnam(file)) == NULL) {
    647      1.1  cgd 				error("%s: unknown user name\n", file);
    648      1.1  cgd 				if (s3 != NULL)
    649      1.1  cgd 					*s3 = '/';
    650      1.1  cgd 				return(NULL);
    651      1.1  cgd 			}
    652      1.1  cgd 		}
    653      1.1  cgd 		if (s3 != NULL)
    654      1.1  cgd 			*s3 = '/';
    655      1.1  cgd 		s2 = pw->pw_dir;
    656      1.1  cgd 	}
    657      1.1  cgd 	for (s1 = buf; *s1++ = *s2++; )
    658      1.1  cgd 		;
    659      1.1  cgd 	s2 = --s1;
    660      1.1  cgd 	if (s3 != NULL) {
    661      1.1  cgd 		s2++;
    662      1.1  cgd 		while (*s1++ = *s3++)
    663      1.1  cgd 			;
    664      1.1  cgd 	}
    665      1.1  cgd 	return(s2);
    666      1.1  cgd }
    667