xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/rdist/expand.c (revision 473:9c6ea6da29de)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
30Sstevel@tonic-gate  * All rights reserved.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
60Sstevel@tonic-gate  * provided that the above copyright notice and this paragraph are
70Sstevel@tonic-gate  * duplicated in all such forms and that any documentation,
80Sstevel@tonic-gate  * advertising materials, and other materials related to such
90Sstevel@tonic-gate  * distribution and use acknowledge that the software was developed
100Sstevel@tonic-gate  * by the University of California, Berkeley.  The name of the
110Sstevel@tonic-gate  * University may not be used to endorse or promote products derived
120Sstevel@tonic-gate  * from this software without specific prior written permission.
130Sstevel@tonic-gate  *
14*473Sbw  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
15*473Sbw  * Use is subject to license terms.
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
180Sstevel@tonic-gate 
190Sstevel@tonic-gate #include "defs.h"
200Sstevel@tonic-gate #include <string.h>
210Sstevel@tonic-gate 
220Sstevel@tonic-gate #define	GAVSIZ	NCARGS / 6
230Sstevel@tonic-gate #define	LC '{'
240Sstevel@tonic-gate #define	RC '}'
250Sstevel@tonic-gate 
260Sstevel@tonic-gate static char	shchars[] = "${[*?";
270Sstevel@tonic-gate 
280Sstevel@tonic-gate int	which;		/* bit mask of types to expand */
290Sstevel@tonic-gate int	eargc;		/* expanded arg count */
300Sstevel@tonic-gate char	**eargv;	/* expanded arg vectors */
310Sstevel@tonic-gate char	*path;
320Sstevel@tonic-gate char	*pathp;
330Sstevel@tonic-gate char	*lastpathp;
340Sstevel@tonic-gate char	*tilde;		/* "~user" if not expanding tilde, else "" */
350Sstevel@tonic-gate char	*tpathp;
360Sstevel@tonic-gate int	nleft;
370Sstevel@tonic-gate 
380Sstevel@tonic-gate int	expany;		/* any expansions done? */
390Sstevel@tonic-gate char	*entp;
400Sstevel@tonic-gate char	**sortbase;
410Sstevel@tonic-gate 
420Sstevel@tonic-gate char	*index();
43*473Sbw 
44*473Sbw static int argcmp(const void *arg1, const void *arg2);
45*473Sbw static void addpath(char c);
46*473Sbw static void Cat(char *s1, char *s2);
47*473Sbw static void matchdir(char *pattern);
48*473Sbw static void expsh(char *s);
49*473Sbw static void expstr(char *s);
50*473Sbw static int execbrc(char *p, char *s);
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	sort()	qsort((char *)sortbase, &eargv[eargc] - sortbase, \
530Sstevel@tonic-gate 		sizeof (*sortbase), argcmp), sortbase = &eargv[eargc]
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	MIN(a, b)	((a) < (b) ? (a) : (b))
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Take a list of names and expand any macros, etc.
590Sstevel@tonic-gate  * wh = E_VARS if expanding variables.
600Sstevel@tonic-gate  * wh = E_SHELL if expanding shell characters.
610Sstevel@tonic-gate  * wh = E_TILDE if expanding `~'.
620Sstevel@tonic-gate  * or any of these or'ed together.
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * Major portions of this were snarfed from csh/sh.glob.c.
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate struct namelist *
expand(list,wh)670Sstevel@tonic-gate expand(list, wh)
680Sstevel@tonic-gate 	struct namelist *list;
690Sstevel@tonic-gate 	int wh;
700Sstevel@tonic-gate {
710Sstevel@tonic-gate 	register struct namelist *nl, *prev;
720Sstevel@tonic-gate 	register int n;
730Sstevel@tonic-gate 	char pathbuf[LINESIZE];
740Sstevel@tonic-gate 	char *argvbuf[GAVSIZ];
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	if (debug) {
770Sstevel@tonic-gate 		printf("expand(%x, %d)\nlist = ", list, wh);
780Sstevel@tonic-gate 		prnames(list);
790Sstevel@tonic-gate 	}
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	if (wh == 0) {
820Sstevel@tonic-gate 		register char *cp;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 		for (nl = list; nl != NULL; nl = nl->n_next)
850Sstevel@tonic-gate 			for (cp = nl->n_name; *cp; cp++)
860Sstevel@tonic-gate 				*cp = *cp & TRIM;
870Sstevel@tonic-gate 		return (list);
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	which = wh;
910Sstevel@tonic-gate 	path = tpathp = pathp = pathbuf;
920Sstevel@tonic-gate 	*pathp = '\0';
930Sstevel@tonic-gate 	lastpathp = &path[sizeof pathbuf - 2];
940Sstevel@tonic-gate 	tilde = "";
950Sstevel@tonic-gate 	eargc = 0;
960Sstevel@tonic-gate 	eargv = sortbase = argvbuf;
970Sstevel@tonic-gate 	*eargv = 0;
980Sstevel@tonic-gate 	nleft = NCARGS - 4;
990Sstevel@tonic-gate 	/*
1000Sstevel@tonic-gate 	 * Walk the name list and expand names into eargv[];
1010Sstevel@tonic-gate 	 */
1020Sstevel@tonic-gate 	for (nl = list; nl != NULL; nl = nl->n_next)
1030Sstevel@tonic-gate 		expstr(nl->n_name);
1040Sstevel@tonic-gate 	/*
1050Sstevel@tonic-gate 	 * Take expanded list of names from eargv[] and build a new list.
1060Sstevel@tonic-gate 	 */
1070Sstevel@tonic-gate 	list = prev = NULL;
1080Sstevel@tonic-gate 	for (n = 0; n < eargc; n++) {
1090Sstevel@tonic-gate 		nl = makenl(NULL);
1100Sstevel@tonic-gate 		nl->n_name = eargv[n];
1110Sstevel@tonic-gate 		if (prev == NULL)
1120Sstevel@tonic-gate 			list = prev = nl;
1130Sstevel@tonic-gate 		else {
1140Sstevel@tonic-gate 			prev->n_next = nl;
1150Sstevel@tonic-gate 			prev = nl;
1160Sstevel@tonic-gate 		}
1170Sstevel@tonic-gate 	}
1180Sstevel@tonic-gate 	if (debug) {
1190Sstevel@tonic-gate 		printf("expanded list = ");
1200Sstevel@tonic-gate 		prnames(list);
1210Sstevel@tonic-gate 	}
1220Sstevel@tonic-gate 	return (list);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate 
125*473Sbw static void
expstr(s)1260Sstevel@tonic-gate expstr(s)
1270Sstevel@tonic-gate 	char *s;
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate 	register char *cp, *cp1;
1300Sstevel@tonic-gate 	register struct namelist *tp;
1310Sstevel@tonic-gate 	char *tail;
1320Sstevel@tonic-gate 	char buf[LINESIZE];
1330Sstevel@tonic-gate 	int savec, oeargc;
1340Sstevel@tonic-gate 	extern char homedir[];
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	if (s == NULL || *s == '\0')
1370Sstevel@tonic-gate 		return;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if ((which & E_VARS) && (cp = index(s, '$')) != NULL) {
1400Sstevel@tonic-gate 		*cp++ = '\0';
1410Sstevel@tonic-gate 		if (*cp == '\0') {
1420Sstevel@tonic-gate 			yyerror("no variable name after '$'");
1430Sstevel@tonic-gate 			return;
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 		if (*cp == LC) {
1460Sstevel@tonic-gate 			cp++;
1470Sstevel@tonic-gate 			if ((tail = index(cp, RC)) == NULL) {
1480Sstevel@tonic-gate 				yyerror("unmatched '{'");
1490Sstevel@tonic-gate 				return;
1500Sstevel@tonic-gate 			}
1510Sstevel@tonic-gate 			*tail++ = savec = '\0';
1520Sstevel@tonic-gate 			if (*cp == '\0') {
1530Sstevel@tonic-gate 				yyerror("no variable name after '$'");
1540Sstevel@tonic-gate 				return;
1550Sstevel@tonic-gate 			}
1560Sstevel@tonic-gate 		} else {
1570Sstevel@tonic-gate 			tail = cp + 1;
1580Sstevel@tonic-gate 			savec = *tail;
1590Sstevel@tonic-gate 			*tail = '\0';
1600Sstevel@tonic-gate 		}
1610Sstevel@tonic-gate 		tp = lookup(cp, NULL, 0);
1620Sstevel@tonic-gate 		if (savec != '\0')
1630Sstevel@tonic-gate 			*tail = savec;
1640Sstevel@tonic-gate 		if (tp != NULL) {
1650Sstevel@tonic-gate 			for (; tp != NULL; tp = tp->n_next) {
1660Sstevel@tonic-gate 				(void) snprintf(buf, sizeof (buf), "%s%s%s", s,
1670Sstevel@tonic-gate 				    tp->n_name, tail);
1680Sstevel@tonic-gate 				expstr(buf);
1690Sstevel@tonic-gate 			}
1700Sstevel@tonic-gate 			return;
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%s%s", s, tail);
1730Sstevel@tonic-gate 		expstr(buf);
1740Sstevel@tonic-gate 		return;
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 	if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {
1770Sstevel@tonic-gate 		Cat(s, "");
1780Sstevel@tonic-gate 		sort();
1790Sstevel@tonic-gate 		return;
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 	if (*s == '~') {
1820Sstevel@tonic-gate 		cp = ++s;
1830Sstevel@tonic-gate 		if (*cp == '\0' || *cp == '/') {
1840Sstevel@tonic-gate 			tilde = "~";
1850Sstevel@tonic-gate 			cp1 = homedir;
1860Sstevel@tonic-gate 		} else {
1870Sstevel@tonic-gate 			tilde = cp1 = buf;
1880Sstevel@tonic-gate 			*cp1++ = '~';
1890Sstevel@tonic-gate 			do {
1900Sstevel@tonic-gate 				if (cp1 >= &buf[sizeof (buf)]) {
1910Sstevel@tonic-gate 					yyerror("User name too long");
1920Sstevel@tonic-gate 					return;
1930Sstevel@tonic-gate 				}
1940Sstevel@tonic-gate 				*cp1++ = *cp++;
1950Sstevel@tonic-gate 			} while (*cp && *cp != '/');
1960Sstevel@tonic-gate 			*cp1 = '\0';
1970Sstevel@tonic-gate 			if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) {
1980Sstevel@tonic-gate 				if ((pw = getpwnam(buf+1)) == NULL) {
1990Sstevel@tonic-gate 					static char unknown_user[] =
2000Sstevel@tonic-gate 					    ": unknown user name";
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 					cp1 = MIN(cp1,
2030Sstevel@tonic-gate 					    &buf[sizeof (buf)] -
2040Sstevel@tonic-gate 					    sizeof (unknown_user));
2050Sstevel@tonic-gate 					strcpy(cp1, unknown_user);
2060Sstevel@tonic-gate 					yyerror(buf+1);
2070Sstevel@tonic-gate 					return;
2080Sstevel@tonic-gate 				}
2090Sstevel@tonic-gate 			}
2100Sstevel@tonic-gate 			cp1 = pw->pw_dir;
2110Sstevel@tonic-gate 			s = cp;
2120Sstevel@tonic-gate 		}
2130Sstevel@tonic-gate 		for (cp = path; cp <= lastpathp + 1 && (*cp++ = *cp1++); )
2140Sstevel@tonic-gate 			;
2150Sstevel@tonic-gate 		tpathp = pathp = cp - 1;
2160Sstevel@tonic-gate 	} else {
2170Sstevel@tonic-gate 		tpathp = pathp = path;
2180Sstevel@tonic-gate 		tilde = "";
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 	*pathp = '\0';
2210Sstevel@tonic-gate 	if (!(which & E_SHELL)) {
2220Sstevel@tonic-gate 		if (which & E_TILDE)
2230Sstevel@tonic-gate 			Cat(path, s);
2240Sstevel@tonic-gate 		else
2250Sstevel@tonic-gate 			Cat(tilde, s);
2260Sstevel@tonic-gate 		sort();
2270Sstevel@tonic-gate 		return;
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 	oeargc = eargc;
2300Sstevel@tonic-gate 	expany = 0;
2310Sstevel@tonic-gate 	expsh(s);
2320Sstevel@tonic-gate 	if (eargc == oeargc)
2330Sstevel@tonic-gate 		Cat(s, "");		/* "nonomatch" is set */
2340Sstevel@tonic-gate 	sort();
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
237*473Sbw static int
argcmp(const void * arg1,const void * arg2)238*473Sbw argcmp(const void *arg1, const void *arg2)
2390Sstevel@tonic-gate {
240*473Sbw 	char *a1 = *(char **)arg1;
241*473Sbw 	char *a2 = *(char **)arg2;
2420Sstevel@tonic-gate 
243*473Sbw 	return (strcmp(a1, a2));
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate  * If there are any Shell meta characters in the name,
2480Sstevel@tonic-gate  * expand into a list, after searching directory
2490Sstevel@tonic-gate  */
250*473Sbw static void
expsh(s)2510Sstevel@tonic-gate expsh(s)
2520Sstevel@tonic-gate 	char *s;
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate 	register char *cp;
2550Sstevel@tonic-gate 	register char *spathp, *oldcp;
2560Sstevel@tonic-gate 	struct stat stb;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	spathp = pathp;
2590Sstevel@tonic-gate 	cp = s;
2600Sstevel@tonic-gate 	while (!any(*cp, shchars)) {
2610Sstevel@tonic-gate 		if (*cp == '\0') {
2620Sstevel@tonic-gate 			if (!expany || stat(path, &stb) >= 0) {
2630Sstevel@tonic-gate 				if (which & E_TILDE)
2640Sstevel@tonic-gate 					Cat(path, "");
2650Sstevel@tonic-gate 				else
2660Sstevel@tonic-gate 					Cat(tilde, tpathp);
2670Sstevel@tonic-gate 			}
2680Sstevel@tonic-gate 			goto endit;
2690Sstevel@tonic-gate 		}
2700Sstevel@tonic-gate 		addpath(*cp++);
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 	oldcp = cp;
2730Sstevel@tonic-gate 	while (cp > s && *cp != '/')
2740Sstevel@tonic-gate 		cp--, pathp--;
2750Sstevel@tonic-gate 	if (*cp == '/')
2760Sstevel@tonic-gate 		cp++, pathp++;
2770Sstevel@tonic-gate 	*pathp = '\0';
2780Sstevel@tonic-gate 	if (*oldcp == '{') {
2790Sstevel@tonic-gate 		execbrc(cp, NULL);
2800Sstevel@tonic-gate 		return;
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 	matchdir(cp);
2830Sstevel@tonic-gate endit:
2840Sstevel@tonic-gate 	pathp = spathp;
2850Sstevel@tonic-gate 	*pathp = '\0';
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
288*473Sbw static void
matchdir(pattern)2890Sstevel@tonic-gate matchdir(pattern)
2900Sstevel@tonic-gate 	char *pattern;
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	struct stat stb;
2930Sstevel@tonic-gate 	register struct dirent *dp;
2940Sstevel@tonic-gate 	DIR *dirp;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	dirp = opendir(path);
2970Sstevel@tonic-gate 	if (dirp == NULL) {
2980Sstevel@tonic-gate 		if (expany)
2990Sstevel@tonic-gate 			return;
3000Sstevel@tonic-gate 		goto patherr2;
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 	if (fstat(dirp->dd_fd, &stb) < 0)
3030Sstevel@tonic-gate 		goto patherr1;
3040Sstevel@tonic-gate 	if (!ISDIR(stb.st_mode)) {
3050Sstevel@tonic-gate 		errno = ENOTDIR;
3060Sstevel@tonic-gate 		goto patherr1;
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL)
3090Sstevel@tonic-gate 		if (match(dp->d_name, pattern)) {
3100Sstevel@tonic-gate 			if (which & E_TILDE)
3110Sstevel@tonic-gate 				Cat(path, dp->d_name);
3120Sstevel@tonic-gate 			else {
3130Sstevel@tonic-gate 				if (pathp + strlen(dp->d_name) - 1 >
3140Sstevel@tonic-gate 				    lastpathp) {
3150Sstevel@tonic-gate 					errno = ENAMETOOLONG;
3160Sstevel@tonic-gate 					goto patherr1;
3170Sstevel@tonic-gate 				}
3180Sstevel@tonic-gate 				strcpy(pathp, dp->d_name);
3190Sstevel@tonic-gate 				Cat(tilde, tpathp);
3200Sstevel@tonic-gate 				*pathp = '\0';
3210Sstevel@tonic-gate 			}
3220Sstevel@tonic-gate 		}
3230Sstevel@tonic-gate 	closedir(dirp);
3240Sstevel@tonic-gate 	return;
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate patherr1:
3270Sstevel@tonic-gate 	closedir(dirp);
3280Sstevel@tonic-gate patherr2:
3290Sstevel@tonic-gate 	{
3300Sstevel@tonic-gate 		char *strerr = strerror(errno);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		if (path + strlen(path) + strlen(strerr) + 1 > lastpathp)
3330Sstevel@tonic-gate 			strcpy(lastpathp - strlen(strerr) - 1, ": ");
3340Sstevel@tonic-gate 		else
3350Sstevel@tonic-gate 			strcat(path, ": ");
3360Sstevel@tonic-gate 		strcat(path, strerr);
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 	yyerror(path);
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate 
341*473Sbw static int
execbrc(p,s)3420Sstevel@tonic-gate execbrc(p, s)
3430Sstevel@tonic-gate 	char *p, *s;
3440Sstevel@tonic-gate {
3450Sstevel@tonic-gate 	char restbuf[LINESIZE + 2];
3460Sstevel@tonic-gate 	register char *pe, *pm, *pl;
3470Sstevel@tonic-gate 	int brclev = 0;
3480Sstevel@tonic-gate 	char *lm, savec, *spathp;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	for (lm = restbuf; *p != '{'; *lm++ = *p++) {
3510Sstevel@tonic-gate 		if (lm >= &restbuf[sizeof (restbuf)]) {
3520Sstevel@tonic-gate 			yyerror("Pathname too long");
3530Sstevel@tonic-gate 			return (0);
3540Sstevel@tonic-gate 		}
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 	for (pe = ++p; *pe; pe++)
3570Sstevel@tonic-gate 		switch (*pe) {
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		case '{':
3600Sstevel@tonic-gate 			brclev++;
3610Sstevel@tonic-gate 			continue;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 		case '}':
3640Sstevel@tonic-gate 			if (brclev == 0)
3650Sstevel@tonic-gate 				goto pend;
3660Sstevel@tonic-gate 			brclev--;
3670Sstevel@tonic-gate 			continue;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		case '[':
3700Sstevel@tonic-gate 			for (pe++; *pe && *pe != ']'; pe++)
3710Sstevel@tonic-gate 				continue;
3720Sstevel@tonic-gate 			if (!*pe)
3730Sstevel@tonic-gate 				yyerror("Missing ']'");
3740Sstevel@tonic-gate 			continue;
3750Sstevel@tonic-gate 		}
3760Sstevel@tonic-gate pend:
3770Sstevel@tonic-gate 	if (brclev || !*pe) {
3780Sstevel@tonic-gate 		yyerror("Missing '}'");
3790Sstevel@tonic-gate 		return (0);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 	for (pl = pm = p; pm <= pe; pm++)
3820Sstevel@tonic-gate 		switch (*pm & (QUOTE|TRIM)) {
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 		case '{':
3850Sstevel@tonic-gate 			brclev++;
3860Sstevel@tonic-gate 			continue;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		case '}':
3890Sstevel@tonic-gate 			if (brclev) {
3900Sstevel@tonic-gate 				brclev--;
3910Sstevel@tonic-gate 				continue;
3920Sstevel@tonic-gate 			}
3930Sstevel@tonic-gate 			goto doit;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 		case ',':
3960Sstevel@tonic-gate 			if (brclev)
3970Sstevel@tonic-gate 				continue;
3980Sstevel@tonic-gate doit:
3990Sstevel@tonic-gate 			savec = *pm;
4000Sstevel@tonic-gate 			*pm = 0;
4010Sstevel@tonic-gate 			if (lm + strlen(pl) + strlen(pe + 1) >=
4020Sstevel@tonic-gate 			    &restbuf[sizeof (restbuf)]) {
4030Sstevel@tonic-gate 				yyerror("Pathname too long");
4040Sstevel@tonic-gate 				return (0);
4050Sstevel@tonic-gate 			}
4060Sstevel@tonic-gate 			strcpy(lm, pl);
4070Sstevel@tonic-gate 			strcat(restbuf, pe + 1);
4080Sstevel@tonic-gate 			*pm = savec;
4090Sstevel@tonic-gate 			if (s == 0) {
4100Sstevel@tonic-gate 				spathp = pathp;
4110Sstevel@tonic-gate 				expsh(restbuf);
4120Sstevel@tonic-gate 				pathp = spathp;
4130Sstevel@tonic-gate 				*pathp = 0;
4140Sstevel@tonic-gate 			} else if (amatch(s, restbuf))
4150Sstevel@tonic-gate 				return (1);
4160Sstevel@tonic-gate 			sort();
4170Sstevel@tonic-gate 			pl = pm + 1;
4180Sstevel@tonic-gate 			continue;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 		case '[':
4210Sstevel@tonic-gate 			for (pm++; *pm && *pm != ']'; pm++)
4220Sstevel@tonic-gate 				continue;
4230Sstevel@tonic-gate 			if (!*pm)
4240Sstevel@tonic-gate 				yyerror("Missing ']'");
4250Sstevel@tonic-gate 			continue;
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 	return (0);
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
430*473Sbw int
match(s,p)4310Sstevel@tonic-gate match(s, p)
4320Sstevel@tonic-gate 	char *s, *p;
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate 	register int c;
4350Sstevel@tonic-gate 	register char *sentp;
4360Sstevel@tonic-gate 	char sexpany = expany;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	if (*s == '.' && *p != '.')
4390Sstevel@tonic-gate 		return (0);
4400Sstevel@tonic-gate 	sentp = entp;
4410Sstevel@tonic-gate 	entp = s;
4420Sstevel@tonic-gate 	c = amatch(s, p);
4430Sstevel@tonic-gate 	entp = sentp;
4440Sstevel@tonic-gate 	expany = sexpany;
4450Sstevel@tonic-gate 	return (c);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
448*473Sbw int
amatch(s,p)4490Sstevel@tonic-gate amatch(s, p)
4500Sstevel@tonic-gate 	register char *s, *p;
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	register int scc;
4530Sstevel@tonic-gate 	int ok, lc;
4540Sstevel@tonic-gate 	char *spathp;
4550Sstevel@tonic-gate 	struct stat stb;
4560Sstevel@tonic-gate 	int c, cc;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	expany = 1;
4590Sstevel@tonic-gate 	for (;;) {
4600Sstevel@tonic-gate 		scc = *s++ & TRIM;
4610Sstevel@tonic-gate 		switch (c = *p++) {
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		case '{':
4640Sstevel@tonic-gate 			return (execbrc(p - 1, s - 1));
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		case '[':
4670Sstevel@tonic-gate 			ok = 0;
4680Sstevel@tonic-gate 			lc = 077777;
4690Sstevel@tonic-gate 			while (cc = *p++) {
4700Sstevel@tonic-gate 				if (cc == ']') {
4710Sstevel@tonic-gate 					if (ok)
4720Sstevel@tonic-gate 						break;
4730Sstevel@tonic-gate 					return (0);
4740Sstevel@tonic-gate 				}
4750Sstevel@tonic-gate 				if (cc == '-') {
4760Sstevel@tonic-gate 					if (lc <= scc && scc <= *p++)
4770Sstevel@tonic-gate 						ok++;
4780Sstevel@tonic-gate 				} else
4790Sstevel@tonic-gate 					if (scc == (lc = cc))
4800Sstevel@tonic-gate 						ok++;
4810Sstevel@tonic-gate 			}
4820Sstevel@tonic-gate 			if (cc == 0) {
4830Sstevel@tonic-gate 				yyerror("Missing ']'");
4840Sstevel@tonic-gate 				return (0);
4850Sstevel@tonic-gate 			}
4860Sstevel@tonic-gate 			continue;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 		case '*':
4890Sstevel@tonic-gate 			if (!*p)
4900Sstevel@tonic-gate 				return (1);
4910Sstevel@tonic-gate 			if (*p == '/') {
4920Sstevel@tonic-gate 				p++;
4930Sstevel@tonic-gate 				goto slash;
4940Sstevel@tonic-gate 			}
4950Sstevel@tonic-gate 			for (s--; *s; s++)
4960Sstevel@tonic-gate 				if (amatch(s, p))
4970Sstevel@tonic-gate 					return (1);
4980Sstevel@tonic-gate 			return (0);
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 		case '\0':
5010Sstevel@tonic-gate 			return (scc == '\0');
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 		default:
5040Sstevel@tonic-gate 			if ((c & TRIM) != scc)
5050Sstevel@tonic-gate 				return (0);
5060Sstevel@tonic-gate 			continue;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 		case '?':
5090Sstevel@tonic-gate 			if (scc == '\0')
5100Sstevel@tonic-gate 				return (0);
5110Sstevel@tonic-gate 			continue;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		case '/':
5140Sstevel@tonic-gate 			if (scc)
5150Sstevel@tonic-gate 				return (0);
5160Sstevel@tonic-gate slash:
5170Sstevel@tonic-gate 			s = entp;
5180Sstevel@tonic-gate 			spathp = pathp;
5190Sstevel@tonic-gate 			while (*s)
5200Sstevel@tonic-gate 				addpath(*s++);
5210Sstevel@tonic-gate 			addpath('/');
5220Sstevel@tonic-gate 			if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))
5230Sstevel@tonic-gate 				if (*p == '\0') {
5240Sstevel@tonic-gate 					if (which & E_TILDE)
5250Sstevel@tonic-gate 						Cat(path, "");
5260Sstevel@tonic-gate 					else
5270Sstevel@tonic-gate 						Cat(tilde, tpathp);
5280Sstevel@tonic-gate 				} else
5290Sstevel@tonic-gate 					expsh(p);
5300Sstevel@tonic-gate 			pathp = spathp;
5310Sstevel@tonic-gate 			*pathp = '\0';
5320Sstevel@tonic-gate 			return (0);
5330Sstevel@tonic-gate 		}
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate 
537*473Sbw int
smatch(s,p)5380Sstevel@tonic-gate smatch(s, p)
5390Sstevel@tonic-gate 	register char *s, *p;
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	register int scc;
5420Sstevel@tonic-gate 	int ok, lc;
5430Sstevel@tonic-gate 	int c, cc;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	for (;;) {
5460Sstevel@tonic-gate 		scc = *s++ & TRIM;
5470Sstevel@tonic-gate 		switch (c = *p++) {
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 		case '[':
5500Sstevel@tonic-gate 			ok = 0;
5510Sstevel@tonic-gate 			lc = 077777;
5520Sstevel@tonic-gate 			while (cc = *p++) {
5530Sstevel@tonic-gate 				if (cc == ']') {
5540Sstevel@tonic-gate 					if (ok)
5550Sstevel@tonic-gate 						break;
5560Sstevel@tonic-gate 					return (0);
5570Sstevel@tonic-gate 				}
5580Sstevel@tonic-gate 				if (cc == '-') {
5590Sstevel@tonic-gate 					if (lc <= scc && scc <= *p++)
5600Sstevel@tonic-gate 						ok++;
5610Sstevel@tonic-gate 				} else
5620Sstevel@tonic-gate 					if (scc == (lc = cc))
5630Sstevel@tonic-gate 						ok++;
5640Sstevel@tonic-gate 			}
5650Sstevel@tonic-gate 			if (cc == 0) {
5660Sstevel@tonic-gate 				yyerror("Missing ']'");
5670Sstevel@tonic-gate 				return (0);
5680Sstevel@tonic-gate 			}
5690Sstevel@tonic-gate 			continue;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 		case '*':
5720Sstevel@tonic-gate 			if (!*p)
5730Sstevel@tonic-gate 				return (1);
5740Sstevel@tonic-gate 			for (s--; *s; s++)
5750Sstevel@tonic-gate 				if (smatch(s, p))
5760Sstevel@tonic-gate 					return (1);
5770Sstevel@tonic-gate 			return (0);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 		case '\0':
5800Sstevel@tonic-gate 			return (scc == '\0');
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 		default:
5830Sstevel@tonic-gate 			if ((c & TRIM) != scc)
5840Sstevel@tonic-gate 				return (0);
5850Sstevel@tonic-gate 			continue;
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 		case '?':
5880Sstevel@tonic-gate 			if (scc == 0)
5890Sstevel@tonic-gate 				return (0);
5900Sstevel@tonic-gate 			continue;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 		}
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate 
596*473Sbw static void
Cat(s1,s2)5970Sstevel@tonic-gate Cat(s1, s2)
5980Sstevel@tonic-gate 	register char *s1, *s2;
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	int len = strlen(s1) + strlen(s2) + 1;
6010Sstevel@tonic-gate 	register char *s;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	nleft -= len;
6040Sstevel@tonic-gate 	if (nleft <= 0 || ++eargc >= GAVSIZ)
6050Sstevel@tonic-gate 		fatal("Arguments too long\n");
6060Sstevel@tonic-gate 	eargv[eargc] = 0;
6070Sstevel@tonic-gate 	eargv[eargc - 1] = s = (char *)malloc(len);
6080Sstevel@tonic-gate 	if (s == NULL)
6090Sstevel@tonic-gate 		fatal("ran out of memory\n");
6100Sstevel@tonic-gate 	while (*s++ = *s1++ & TRIM)
6110Sstevel@tonic-gate 		;
6120Sstevel@tonic-gate 	s--;
6130Sstevel@tonic-gate 	while (*s++ = *s2++ & TRIM)
6140Sstevel@tonic-gate 		;
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
617*473Sbw static void
addpath(char c)618*473Sbw addpath(char c)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	if (pathp > lastpathp)
6220Sstevel@tonic-gate 		yyerror("Pathname too long");
6230Sstevel@tonic-gate 	else {
6240Sstevel@tonic-gate 		*pathp++ = c & TRIM;
6250Sstevel@tonic-gate 		*pathp = '\0';
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate /*
6300Sstevel@tonic-gate  * Expand file names beginning with `~' into the
6310Sstevel@tonic-gate  * user's home directory path name. Return a pointer in buf to the
6320Sstevel@tonic-gate  * part corresponding to `file'.
6330Sstevel@tonic-gate  */
6340Sstevel@tonic-gate char *
exptilde(buf,len,file)6350Sstevel@tonic-gate exptilde(buf, len, file)
6360Sstevel@tonic-gate 	char buf[];
6370Sstevel@tonic-gate 	unsigned int len;
6380Sstevel@tonic-gate 	register char *file;
6390Sstevel@tonic-gate {
6400Sstevel@tonic-gate 	register char *s1, *s2, *s3;
6410Sstevel@tonic-gate 	extern char homedir[];
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	if (*file != '~') {
6440Sstevel@tonic-gate 		if (strlen(file) + 1 > len) {
6450Sstevel@tonic-gate 			error("pathname too long: %s\n", file);
6460Sstevel@tonic-gate 			return (NULL);
6470Sstevel@tonic-gate 		}
6480Sstevel@tonic-gate 		strcpy(buf, file);
6490Sstevel@tonic-gate 		return (buf);
6500Sstevel@tonic-gate 	}
6510Sstevel@tonic-gate 	if (*++file == '\0') {
6520Sstevel@tonic-gate 		s2 = homedir;
6530Sstevel@tonic-gate 		s3 = NULL;
6540Sstevel@tonic-gate 	} else if (*file == '/') {
6550Sstevel@tonic-gate 		s2 = homedir;
6560Sstevel@tonic-gate 		s3 = file;
6570Sstevel@tonic-gate 	} else {
6580Sstevel@tonic-gate 		s3 = file;
6590Sstevel@tonic-gate 		while (*s3 && *s3 != '/')
6600Sstevel@tonic-gate 			s3++;
6610Sstevel@tonic-gate 		if (*s3 == '/')
6620Sstevel@tonic-gate 			*s3 = '\0';
6630Sstevel@tonic-gate 		else
6640Sstevel@tonic-gate 			s3 = NULL;
6650Sstevel@tonic-gate 		if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
6660Sstevel@tonic-gate 			if ((pw = getpwnam(file)) == NULL) {
6670Sstevel@tonic-gate 				error("%s: unknown user name\n", file);
6680Sstevel@tonic-gate 				if (s3 != NULL)
6690Sstevel@tonic-gate 					*s3 = '/';
6700Sstevel@tonic-gate 				return (NULL);
6710Sstevel@tonic-gate 			}
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 		if (s3 != NULL)
6740Sstevel@tonic-gate 			*s3 = '/';
6750Sstevel@tonic-gate 		s2 = pw->pw_dir;
6760Sstevel@tonic-gate 	}
6770Sstevel@tonic-gate 	for (s1 = buf; s1 < &buf[len] && (*s1++ = *s2++); )
6780Sstevel@tonic-gate 		;
6790Sstevel@tonic-gate 	s2 = --s1;
6800Sstevel@tonic-gate 	if (s3 != NULL) {
6810Sstevel@tonic-gate 		s2++;
6820Sstevel@tonic-gate 		while (s1 < &buf[len] && (*s1++ = *s3++))
6830Sstevel@tonic-gate 			;
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 	if (s1 == &buf[len]) {
6860Sstevel@tonic-gate 		error("pathname too long: %s\n", file - 1);
6870Sstevel@tonic-gate 		return (NULL);
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 	return (s2);
6900Sstevel@tonic-gate }
691