17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 1983 Regents of the University of California.
37c478bd9Sstevel@tonic-gate  * All rights reserved.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
67c478bd9Sstevel@tonic-gate  * provided that the above copyright notice and this paragraph are
77c478bd9Sstevel@tonic-gate  * duplicated in all such forms and that any documentation,
87c478bd9Sstevel@tonic-gate  * advertising materials, and other materials related to such
97c478bd9Sstevel@tonic-gate  * distribution and use acknowledge that the software was developed
107c478bd9Sstevel@tonic-gate  * by the University of California, Berkeley.  The name of the
117c478bd9Sstevel@tonic-gate  * University may not be used to endorse or promote products derived
127c478bd9Sstevel@tonic-gate  * from this software without specific prior written permission.
137c478bd9Sstevel@tonic-gate  *
14*740638c8Sbw  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
15*740638c8Sbw  * Use is subject to license terms.
167c478bd9Sstevel@tonic-gate  */
177c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
187c478bd9Sstevel@tonic-gate 
197c478bd9Sstevel@tonic-gate #include "defs.h"
207c478bd9Sstevel@tonic-gate #include <string.h>
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate #define	GAVSIZ	NCARGS / 6
237c478bd9Sstevel@tonic-gate #define	LC '{'
247c478bd9Sstevel@tonic-gate #define	RC '}'
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate static char	shchars[] = "${[*?";
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate int	which;		/* bit mask of types to expand */
297c478bd9Sstevel@tonic-gate int	eargc;		/* expanded arg count */
307c478bd9Sstevel@tonic-gate char	**eargv;	/* expanded arg vectors */
317c478bd9Sstevel@tonic-gate char	*path;
327c478bd9Sstevel@tonic-gate char	*pathp;
337c478bd9Sstevel@tonic-gate char	*lastpathp;
347c478bd9Sstevel@tonic-gate char	*tilde;		/* "~user" if not expanding tilde, else "" */
357c478bd9Sstevel@tonic-gate char	*tpathp;
367c478bd9Sstevel@tonic-gate int	nleft;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate int	expany;		/* any expansions done? */
397c478bd9Sstevel@tonic-gate char	*entp;
407c478bd9Sstevel@tonic-gate char	**sortbase;
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate char	*index();
43*740638c8Sbw 
44*740638c8Sbw static int argcmp(const void *arg1, const void *arg2);
45*740638c8Sbw static void addpath(char c);
46*740638c8Sbw static void Cat(char *s1, char *s2);
47*740638c8Sbw static void matchdir(char *pattern);
48*740638c8Sbw static void expsh(char *s);
49*740638c8Sbw static void expstr(char *s);
50*740638c8Sbw static int execbrc(char *p, char *s);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define	sort()	qsort((char *)sortbase, &eargv[eargc] - sortbase, \
537c478bd9Sstevel@tonic-gate 		sizeof (*sortbase), argcmp), sortbase = &eargv[eargc]
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #define	MIN(a, b)	((a) < (b) ? (a) : (b))
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Take a list of names and expand any macros, etc.
597c478bd9Sstevel@tonic-gate  * wh = E_VARS if expanding variables.
607c478bd9Sstevel@tonic-gate  * wh = E_SHELL if expanding shell characters.
617c478bd9Sstevel@tonic-gate  * wh = E_TILDE if expanding `~'.
627c478bd9Sstevel@tonic-gate  * or any of these or'ed together.
637c478bd9Sstevel@tonic-gate  *
647c478bd9Sstevel@tonic-gate  * Major portions of this were snarfed from csh/sh.glob.c.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate struct namelist *
677c478bd9Sstevel@tonic-gate expand(list, wh)
687c478bd9Sstevel@tonic-gate 	struct namelist *list;
697c478bd9Sstevel@tonic-gate 	int wh;
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	register struct namelist *nl, *prev;
727c478bd9Sstevel@tonic-gate 	register int n;
737c478bd9Sstevel@tonic-gate 	char pathbuf[LINESIZE];
747c478bd9Sstevel@tonic-gate 	char *argvbuf[GAVSIZ];
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	if (debug) {
777c478bd9Sstevel@tonic-gate 		printf("expand(%x, %d)\nlist = ", list, wh);
787c478bd9Sstevel@tonic-gate 		prnames(list);
797c478bd9Sstevel@tonic-gate 	}
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	if (wh == 0) {
827c478bd9Sstevel@tonic-gate 		register char *cp;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 		for (nl = list; nl != NULL; nl = nl->n_next)
857c478bd9Sstevel@tonic-gate 			for (cp = nl->n_name; *cp; cp++)
867c478bd9Sstevel@tonic-gate 				*cp = *cp & TRIM;
877c478bd9Sstevel@tonic-gate 		return (list);
887c478bd9Sstevel@tonic-gate 	}
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	which = wh;
917c478bd9Sstevel@tonic-gate 	path = tpathp = pathp = pathbuf;
927c478bd9Sstevel@tonic-gate 	*pathp = '\0';
937c478bd9Sstevel@tonic-gate 	lastpathp = &path[sizeof pathbuf - 2];
947c478bd9Sstevel@tonic-gate 	tilde = "";
957c478bd9Sstevel@tonic-gate 	eargc = 0;
967c478bd9Sstevel@tonic-gate 	eargv = sortbase = argvbuf;
977c478bd9Sstevel@tonic-gate 	*eargv = 0;
987c478bd9Sstevel@tonic-gate 	nleft = NCARGS - 4;
997c478bd9Sstevel@tonic-gate 	/*
1007c478bd9Sstevel@tonic-gate 	 * Walk the name list and expand names into eargv[];
1017c478bd9Sstevel@tonic-gate 	 */
1027c478bd9Sstevel@tonic-gate 	for (nl = list; nl != NULL; nl = nl->n_next)
1037c478bd9Sstevel@tonic-gate 		expstr(nl->n_name);
1047c478bd9Sstevel@tonic-gate 	/*
1057c478bd9Sstevel@tonic-gate 	 * Take expanded list of names from eargv[] and build a new list.
1067c478bd9Sstevel@tonic-gate 	 */
1077c478bd9Sstevel@tonic-gate 	list = prev = NULL;
1087c478bd9Sstevel@tonic-gate 	for (n = 0; n < eargc; n++) {
1097c478bd9Sstevel@tonic-gate 		nl = makenl(NULL);
1107c478bd9Sstevel@tonic-gate 		nl->n_name = eargv[n];
1117c478bd9Sstevel@tonic-gate 		if (prev == NULL)
1127c478bd9Sstevel@tonic-gate 			list = prev = nl;
1137c478bd9Sstevel@tonic-gate 		else {
1147c478bd9Sstevel@tonic-gate 			prev->n_next = nl;
1157c478bd9Sstevel@tonic-gate 			prev = nl;
1167c478bd9Sstevel@tonic-gate 		}
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate 	if (debug) {
1197c478bd9Sstevel@tonic-gate 		printf("expanded list = ");
1207c478bd9Sstevel@tonic-gate 		prnames(list);
1217c478bd9Sstevel@tonic-gate 	}
1227c478bd9Sstevel@tonic-gate 	return (list);
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate 
125*740638c8Sbw static void
1267c478bd9Sstevel@tonic-gate expstr(s)
1277c478bd9Sstevel@tonic-gate 	char *s;
1287c478bd9Sstevel@tonic-gate {
1297c478bd9Sstevel@tonic-gate 	register char *cp, *cp1;
1307c478bd9Sstevel@tonic-gate 	register struct namelist *tp;
1317c478bd9Sstevel@tonic-gate 	char *tail;
1327c478bd9Sstevel@tonic-gate 	char buf[LINESIZE];
1337c478bd9Sstevel@tonic-gate 	int savec, oeargc;
1347c478bd9Sstevel@tonic-gate 	extern char homedir[];
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (s == NULL || *s == '\0')
1377c478bd9Sstevel@tonic-gate 		return;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	if ((which & E_VARS) && (cp = index(s, '$')) != NULL) {
1407c478bd9Sstevel@tonic-gate 		*cp++ = '\0';
1417c478bd9Sstevel@tonic-gate 		if (*cp == '\0') {
1427c478bd9Sstevel@tonic-gate 			yyerror("no variable name after '$'");
1437c478bd9Sstevel@tonic-gate 			return;
1447c478bd9Sstevel@tonic-gate 		}
1457c478bd9Sstevel@tonic-gate 		if (*cp == LC) {
1467c478bd9Sstevel@tonic-gate 			cp++;
1477c478bd9Sstevel@tonic-gate 			if ((tail = index(cp, RC)) == NULL) {
1487c478bd9Sstevel@tonic-gate 				yyerror("unmatched '{'");
1497c478bd9Sstevel@tonic-gate 				return;
1507c478bd9Sstevel@tonic-gate 			}
1517c478bd9Sstevel@tonic-gate 			*tail++ = savec = '\0';
1527c478bd9Sstevel@tonic-gate 			if (*cp == '\0') {
1537c478bd9Sstevel@tonic-gate 				yyerror("no variable name after '$'");
1547c478bd9Sstevel@tonic-gate 				return;
1557c478bd9Sstevel@tonic-gate 			}
1567c478bd9Sstevel@tonic-gate 		} else {
1577c478bd9Sstevel@tonic-gate 			tail = cp + 1;
1587c478bd9Sstevel@tonic-gate 			savec = *tail;
1597c478bd9Sstevel@tonic-gate 			*tail = '\0';
1607c478bd9Sstevel@tonic-gate 		}
1617c478bd9Sstevel@tonic-gate 		tp = lookup(cp, NULL, 0);
1627c478bd9Sstevel@tonic-gate 		if (savec != '\0')
1637c478bd9Sstevel@tonic-gate 			*tail = savec;
1647c478bd9Sstevel@tonic-gate 		if (tp != NULL) {
1657c478bd9Sstevel@tonic-gate 			for (; tp != NULL; tp = tp->n_next) {
1667c478bd9Sstevel@tonic-gate 				(void) snprintf(buf, sizeof (buf), "%s%s%s", s,
1677c478bd9Sstevel@tonic-gate 				    tp->n_name, tail);
1687c478bd9Sstevel@tonic-gate 				expstr(buf);
1697c478bd9Sstevel@tonic-gate 			}
1707c478bd9Sstevel@tonic-gate 			return;
1717c478bd9Sstevel@tonic-gate 		}
1727c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%s%s", s, tail);
1737c478bd9Sstevel@tonic-gate 		expstr(buf);
1747c478bd9Sstevel@tonic-gate 		return;
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 	if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {
1777c478bd9Sstevel@tonic-gate 		Cat(s, "");
1787c478bd9Sstevel@tonic-gate 		sort();
1797c478bd9Sstevel@tonic-gate 		return;
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 	if (*s == '~') {
1827c478bd9Sstevel@tonic-gate 		cp = ++s;
1837c478bd9Sstevel@tonic-gate 		if (*cp == '\0' || *cp == '/') {
1847c478bd9Sstevel@tonic-gate 			tilde = "~";
1857c478bd9Sstevel@tonic-gate 			cp1 = homedir;
1867c478bd9Sstevel@tonic-gate 		} else {
1877c478bd9Sstevel@tonic-gate 			tilde = cp1 = buf;
1887c478bd9Sstevel@tonic-gate 			*cp1++ = '~';
1897c478bd9Sstevel@tonic-gate 			do {
1907c478bd9Sstevel@tonic-gate 				if (cp1 >= &buf[sizeof (buf)]) {
1917c478bd9Sstevel@tonic-gate 					yyerror("User name too long");
1927c478bd9Sstevel@tonic-gate 					return;
1937c478bd9Sstevel@tonic-gate 				}
1947c478bd9Sstevel@tonic-gate 				*cp1++ = *cp++;
1957c478bd9Sstevel@tonic-gate 			} while (*cp && *cp != '/');
1967c478bd9Sstevel@tonic-gate 			*cp1 = '\0';
1977c478bd9Sstevel@tonic-gate 			if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) {
1987c478bd9Sstevel@tonic-gate 				if ((pw = getpwnam(buf+1)) == NULL) {
1997c478bd9Sstevel@tonic-gate 					static char unknown_user[] =
2007c478bd9Sstevel@tonic-gate 					    ": unknown user name";
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 					cp1 = MIN(cp1,
2037c478bd9Sstevel@tonic-gate 					    &buf[sizeof (buf)] -
2047c478bd9Sstevel@tonic-gate 					    sizeof (unknown_user));
2057c478bd9Sstevel@tonic-gate 					strcpy(cp1, unknown_user);
2067c478bd9Sstevel@tonic-gate 					yyerror(buf+1);
2077c478bd9Sstevel@tonic-gate 					return;
2087c478bd9Sstevel@tonic-gate 				}
2097c478bd9Sstevel@tonic-gate 			}
2107c478bd9Sstevel@tonic-gate 			cp1 = pw->pw_dir;
2117c478bd9Sstevel@tonic-gate 			s = cp;
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 		for (cp = path; cp <= lastpathp + 1 && (*cp++ = *cp1++); )
2147c478bd9Sstevel@tonic-gate 			;
2157c478bd9Sstevel@tonic-gate 		tpathp = pathp = cp - 1;
2167c478bd9Sstevel@tonic-gate 	} else {
2177c478bd9Sstevel@tonic-gate 		tpathp = pathp = path;
2187c478bd9Sstevel@tonic-gate 		tilde = "";
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 	*pathp = '\0';
2217c478bd9Sstevel@tonic-gate 	if (!(which & E_SHELL)) {
2227c478bd9Sstevel@tonic-gate 		if (which & E_TILDE)
2237c478bd9Sstevel@tonic-gate 			Cat(path, s);
2247c478bd9Sstevel@tonic-gate 		else
2257c478bd9Sstevel@tonic-gate 			Cat(tilde, s);
2267c478bd9Sstevel@tonic-gate 		sort();
2277c478bd9Sstevel@tonic-gate 		return;
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 	oeargc = eargc;
2307c478bd9Sstevel@tonic-gate 	expany = 0;
2317c478bd9Sstevel@tonic-gate 	expsh(s);
2327c478bd9Sstevel@tonic-gate 	if (eargc == oeargc)
2337c478bd9Sstevel@tonic-gate 		Cat(s, "");		/* "nonomatch" is set */
2347c478bd9Sstevel@tonic-gate 	sort();
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
237*740638c8Sbw static int
238*740638c8Sbw argcmp(const void *arg1, const void *arg2)
2397c478bd9Sstevel@tonic-gate {
240*740638c8Sbw 	char *a1 = *(char **)arg1;
241*740638c8Sbw 	char *a2 = *(char **)arg2;
2427c478bd9Sstevel@tonic-gate 
243*740638c8Sbw 	return (strcmp(a1, a2));
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * If there are any Shell meta characters in the name,
2487c478bd9Sstevel@tonic-gate  * expand into a list, after searching directory
2497c478bd9Sstevel@tonic-gate  */
250*740638c8Sbw static void
2517c478bd9Sstevel@tonic-gate expsh(s)
2527c478bd9Sstevel@tonic-gate 	char *s;
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate 	register char *cp;
2557c478bd9Sstevel@tonic-gate 	register char *spathp, *oldcp;
2567c478bd9Sstevel@tonic-gate 	struct stat stb;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	spathp = pathp;
2597c478bd9Sstevel@tonic-gate 	cp = s;
2607c478bd9Sstevel@tonic-gate 	while (!any(*cp, shchars)) {
2617c478bd9Sstevel@tonic-gate 		if (*cp == '\0') {
2627c478bd9Sstevel@tonic-gate 			if (!expany || stat(path, &stb) >= 0) {
2637c478bd9Sstevel@tonic-gate 				if (which & E_TILDE)
2647c478bd9Sstevel@tonic-gate 					Cat(path, "");
2657c478bd9Sstevel@tonic-gate 				else
2667c478bd9Sstevel@tonic-gate 					Cat(tilde, tpathp);
2677c478bd9Sstevel@tonic-gate 			}
2687c478bd9Sstevel@tonic-gate 			goto endit;
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 		addpath(*cp++);
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 	oldcp = cp;
2737c478bd9Sstevel@tonic-gate 	while (cp > s && *cp != '/')
2747c478bd9Sstevel@tonic-gate 		cp--, pathp--;
2757c478bd9Sstevel@tonic-gate 	if (*cp == '/')
2767c478bd9Sstevel@tonic-gate 		cp++, pathp++;
2777c478bd9Sstevel@tonic-gate 	*pathp = '\0';
2787c478bd9Sstevel@tonic-gate 	if (*oldcp == '{') {
2797c478bd9Sstevel@tonic-gate 		execbrc(cp, NULL);
2807c478bd9Sstevel@tonic-gate 		return;
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	matchdir(cp);
2837c478bd9Sstevel@tonic-gate endit:
2847c478bd9Sstevel@tonic-gate 	pathp = spathp;
2857c478bd9Sstevel@tonic-gate 	*pathp = '\0';
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
288*740638c8Sbw static void
2897c478bd9Sstevel@tonic-gate matchdir(pattern)
2907c478bd9Sstevel@tonic-gate 	char *pattern;
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	struct stat stb;
2937c478bd9Sstevel@tonic-gate 	register struct dirent *dp;
2947c478bd9Sstevel@tonic-gate 	DIR *dirp;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	dirp = opendir(path);
2977c478bd9Sstevel@tonic-gate 	if (dirp == NULL) {
2987c478bd9Sstevel@tonic-gate 		if (expany)
2997c478bd9Sstevel@tonic-gate 			return;
3007c478bd9Sstevel@tonic-gate 		goto patherr2;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 	if (fstat(dirp->dd_fd, &stb) < 0)
3037c478bd9Sstevel@tonic-gate 		goto patherr1;
3047c478bd9Sstevel@tonic-gate 	if (!ISDIR(stb.st_mode)) {
3057c478bd9Sstevel@tonic-gate 		errno = ENOTDIR;
3067c478bd9Sstevel@tonic-gate 		goto patherr1;
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL)
3097c478bd9Sstevel@tonic-gate 		if (match(dp->d_name, pattern)) {
3107c478bd9Sstevel@tonic-gate 			if (which & E_TILDE)
3117c478bd9Sstevel@tonic-gate 				Cat(path, dp->d_name);
3127c478bd9Sstevel@tonic-gate 			else {
3137c478bd9Sstevel@tonic-gate 				if (pathp + strlen(dp->d_name) - 1 >
3147c478bd9Sstevel@tonic-gate 				    lastpathp) {
3157c478bd9Sstevel@tonic-gate 					errno = ENAMETOOLONG;
3167c478bd9Sstevel@tonic-gate 					goto patherr1;
3177c478bd9Sstevel@tonic-gate 				}
3187c478bd9Sstevel@tonic-gate 				strcpy(pathp, dp->d_name);
3197c478bd9Sstevel@tonic-gate 				Cat(tilde, tpathp);
3207c478bd9Sstevel@tonic-gate 				*pathp = '\0';
3217c478bd9Sstevel@tonic-gate 			}
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 	closedir(dirp);
3247c478bd9Sstevel@tonic-gate 	return;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate patherr1:
3277c478bd9Sstevel@tonic-gate 	closedir(dirp);
3287c478bd9Sstevel@tonic-gate patherr2:
3297c478bd9Sstevel@tonic-gate 	{
3307c478bd9Sstevel@tonic-gate 		char *strerr = strerror(errno);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		if (path + strlen(path) + strlen(strerr) + 1 > lastpathp)
3337c478bd9Sstevel@tonic-gate 			strcpy(lastpathp - strlen(strerr) - 1, ": ");
3347c478bd9Sstevel@tonic-gate 		else
3357c478bd9Sstevel@tonic-gate 			strcat(path, ": ");
3367c478bd9Sstevel@tonic-gate 		strcat(path, strerr);
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 	yyerror(path);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
341*740638c8Sbw static int
3427c478bd9Sstevel@tonic-gate execbrc(p, s)
3437c478bd9Sstevel@tonic-gate 	char *p, *s;
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	char restbuf[LINESIZE + 2];
3467c478bd9Sstevel@tonic-gate 	register char *pe, *pm, *pl;
3477c478bd9Sstevel@tonic-gate 	int brclev = 0;
3487c478bd9Sstevel@tonic-gate 	char *lm, savec, *spathp;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	for (lm = restbuf; *p != '{'; *lm++ = *p++) {
3517c478bd9Sstevel@tonic-gate 		if (lm >= &restbuf[sizeof (restbuf)]) {
3527c478bd9Sstevel@tonic-gate 			yyerror("Pathname too long");
3537c478bd9Sstevel@tonic-gate 			return (0);
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 	for (pe = ++p; *pe; pe++)
3577c478bd9Sstevel@tonic-gate 		switch (*pe) {
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		case '{':
3607c478bd9Sstevel@tonic-gate 			brclev++;
3617c478bd9Sstevel@tonic-gate 			continue;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		case '}':
3647c478bd9Sstevel@tonic-gate 			if (brclev == 0)
3657c478bd9Sstevel@tonic-gate 				goto pend;
3667c478bd9Sstevel@tonic-gate 			brclev--;
3677c478bd9Sstevel@tonic-gate 			continue;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		case '[':
3707c478bd9Sstevel@tonic-gate 			for (pe++; *pe && *pe != ']'; pe++)
3717c478bd9Sstevel@tonic-gate 				continue;
3727c478bd9Sstevel@tonic-gate 			if (!*pe)
3737c478bd9Sstevel@tonic-gate 				yyerror("Missing ']'");
3747c478bd9Sstevel@tonic-gate 			continue;
3757c478bd9Sstevel@tonic-gate 		}
3767c478bd9Sstevel@tonic-gate pend:
3777c478bd9Sstevel@tonic-gate 	if (brclev || !*pe) {
3787c478bd9Sstevel@tonic-gate 		yyerror("Missing '}'");
3797c478bd9Sstevel@tonic-gate 		return (0);
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 	for (pl = pm = p; pm <= pe; pm++)
3827c478bd9Sstevel@tonic-gate 		switch (*pm & (QUOTE|TRIM)) {
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 		case '{':
3857c478bd9Sstevel@tonic-gate 			brclev++;
3867c478bd9Sstevel@tonic-gate 			continue;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 		case '}':
3897c478bd9Sstevel@tonic-gate 			if (brclev) {
3907c478bd9Sstevel@tonic-gate 				brclev--;
3917c478bd9Sstevel@tonic-gate 				continue;
3927c478bd9Sstevel@tonic-gate 			}
3937c478bd9Sstevel@tonic-gate 			goto doit;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		case ',':
3967c478bd9Sstevel@tonic-gate 			if (brclev)
3977c478bd9Sstevel@tonic-gate 				continue;
3987c478bd9Sstevel@tonic-gate doit:
3997c478bd9Sstevel@tonic-gate 			savec = *pm;
4007c478bd9Sstevel@tonic-gate 			*pm = 0;
4017c478bd9Sstevel@tonic-gate 			if (lm + strlen(pl) + strlen(pe + 1) >=
4027c478bd9Sstevel@tonic-gate 			    &restbuf[sizeof (restbuf)]) {
4037c478bd9Sstevel@tonic-gate 				yyerror("Pathname too long");
4047c478bd9Sstevel@tonic-gate 				return (0);
4057c478bd9Sstevel@tonic-gate 			}
4067c478bd9Sstevel@tonic-gate 			strcpy(lm, pl);
4077c478bd9Sstevel@tonic-gate 			strcat(restbuf, pe + 1);
4087c478bd9Sstevel@tonic-gate 			*pm = savec;
4097c478bd9Sstevel@tonic-gate 			if (s == 0) {
4107c478bd9Sstevel@tonic-gate 				spathp = pathp;
4117c478bd9Sstevel@tonic-gate 				expsh(restbuf);
4127c478bd9Sstevel@tonic-gate 				pathp = spathp;
4137c478bd9Sstevel@tonic-gate 				*pathp = 0;
4147c478bd9Sstevel@tonic-gate 			} else if (amatch(s, restbuf))
4157c478bd9Sstevel@tonic-gate 				return (1);
4167c478bd9Sstevel@tonic-gate 			sort();
4177c478bd9Sstevel@tonic-gate 			pl = pm + 1;
4187c478bd9Sstevel@tonic-gate 			continue;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 		case '[':
4217c478bd9Sstevel@tonic-gate 			for (pm++; *pm && *pm != ']'; pm++)
4227c478bd9Sstevel@tonic-gate 				continue;
4237c478bd9Sstevel@tonic-gate 			if (!*pm)
4247c478bd9Sstevel@tonic-gate 				yyerror("Missing ']'");
4257c478bd9Sstevel@tonic-gate 			continue;
4267c478bd9Sstevel@tonic-gate 		}
4277c478bd9Sstevel@tonic-gate 	return (0);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
430*740638c8Sbw int
4317c478bd9Sstevel@tonic-gate match(s, p)
4327c478bd9Sstevel@tonic-gate 	char *s, *p;
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 	register int c;
4357c478bd9Sstevel@tonic-gate 	register char *sentp;
4367c478bd9Sstevel@tonic-gate 	char sexpany = expany;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	if (*s == '.' && *p != '.')
4397c478bd9Sstevel@tonic-gate 		return (0);
4407c478bd9Sstevel@tonic-gate 	sentp = entp;
4417c478bd9Sstevel@tonic-gate 	entp = s;
4427c478bd9Sstevel@tonic-gate 	c = amatch(s, p);
4437c478bd9Sstevel@tonic-gate 	entp = sentp;
4447c478bd9Sstevel@tonic-gate 	expany = sexpany;
4457c478bd9Sstevel@tonic-gate 	return (c);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
448*740638c8Sbw int
4497c478bd9Sstevel@tonic-gate amatch(s, p)
4507c478bd9Sstevel@tonic-gate 	register char *s, *p;
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	register int scc;
4537c478bd9Sstevel@tonic-gate 	int ok, lc;
4547c478bd9Sstevel@tonic-gate 	char *spathp;
4557c478bd9Sstevel@tonic-gate 	struct stat stb;
4567c478bd9Sstevel@tonic-gate 	int c, cc;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	expany = 1;
4597c478bd9Sstevel@tonic-gate 	for (;;) {
4607c478bd9Sstevel@tonic-gate 		scc = *s++ & TRIM;
4617c478bd9Sstevel@tonic-gate 		switch (c = *p++) {
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 		case '{':
4647c478bd9Sstevel@tonic-gate 			return (execbrc(p - 1, s - 1));
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		case '[':
4677c478bd9Sstevel@tonic-gate 			ok = 0;
4687c478bd9Sstevel@tonic-gate 			lc = 077777;
4697c478bd9Sstevel@tonic-gate 			while (cc = *p++) {
4707c478bd9Sstevel@tonic-gate 				if (cc == ']') {
4717c478bd9Sstevel@tonic-gate 					if (ok)
4727c478bd9Sstevel@tonic-gate 						break;
4737c478bd9Sstevel@tonic-gate 					return (0);
4747c478bd9Sstevel@tonic-gate 				}
4757c478bd9Sstevel@tonic-gate 				if (cc == '-') {
4767c478bd9Sstevel@tonic-gate 					if (lc <= scc && scc <= *p++)
4777c478bd9Sstevel@tonic-gate 						ok++;
4787c478bd9Sstevel@tonic-gate 				} else
4797c478bd9Sstevel@tonic-gate 					if (scc == (lc = cc))
4807c478bd9Sstevel@tonic-gate 						ok++;
4817c478bd9Sstevel@tonic-gate 			}
4827c478bd9Sstevel@tonic-gate 			if (cc == 0) {
4837c478bd9Sstevel@tonic-gate 				yyerror("Missing ']'");
4847c478bd9Sstevel@tonic-gate 				return (0);
4857c478bd9Sstevel@tonic-gate 			}
4867c478bd9Sstevel@tonic-gate 			continue;
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 		case '*':
4897c478bd9Sstevel@tonic-gate 			if (!*p)
4907c478bd9Sstevel@tonic-gate 				return (1);
4917c478bd9Sstevel@tonic-gate 			if (*p == '/') {
4927c478bd9Sstevel@tonic-gate 				p++;
4937c478bd9Sstevel@tonic-gate 				goto slash;
4947c478bd9Sstevel@tonic-gate 			}
4957c478bd9Sstevel@tonic-gate 			for (s--; *s; s++)
4967c478bd9Sstevel@tonic-gate 				if (amatch(s, p))
4977c478bd9Sstevel@tonic-gate 					return (1);
4987c478bd9Sstevel@tonic-gate 			return (0);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		case '\0':
5017c478bd9Sstevel@tonic-gate 			return (scc == '\0');
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		default:
5047c478bd9Sstevel@tonic-gate 			if ((c & TRIM) != scc)
5057c478bd9Sstevel@tonic-gate 				return (0);
5067c478bd9Sstevel@tonic-gate 			continue;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 		case '?':
5097c478bd9Sstevel@tonic-gate 			if (scc == '\0')
5107c478bd9Sstevel@tonic-gate 				return (0);
5117c478bd9Sstevel@tonic-gate 			continue;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 		case '/':
5147c478bd9Sstevel@tonic-gate 			if (scc)
5157c478bd9Sstevel@tonic-gate 				return (0);
5167c478bd9Sstevel@tonic-gate slash:
5177c478bd9Sstevel@tonic-gate 			s = entp;
5187c478bd9Sstevel@tonic-gate 			spathp = pathp;
5197c478bd9Sstevel@tonic-gate 			while (*s)
5207c478bd9Sstevel@tonic-gate 				addpath(*s++);
5217c478bd9Sstevel@tonic-gate 			addpath('/');
5227c478bd9Sstevel@tonic-gate 			if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))
5237c478bd9Sstevel@tonic-gate 				if (*p == '\0') {
5247c478bd9Sstevel@tonic-gate 					if (which & E_TILDE)
5257c478bd9Sstevel@tonic-gate 						Cat(path, "");
5267c478bd9Sstevel@tonic-gate 					else
5277c478bd9Sstevel@tonic-gate 						Cat(tilde, tpathp);
5287c478bd9Sstevel@tonic-gate 				} else
5297c478bd9Sstevel@tonic-gate 					expsh(p);
5307c478bd9Sstevel@tonic-gate 			pathp = spathp;
5317c478bd9Sstevel@tonic-gate 			*pathp = '\0';
5327c478bd9Sstevel@tonic-gate 			return (0);
5337c478bd9Sstevel@tonic-gate 		}
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate 
537*740638c8Sbw int
5387c478bd9Sstevel@tonic-gate smatch(s, p)
5397c478bd9Sstevel@tonic-gate 	register char *s, *p;
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	register int scc;
5427c478bd9Sstevel@tonic-gate 	int ok, lc;
5437c478bd9Sstevel@tonic-gate 	int c, cc;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	for (;;) {
5467c478bd9Sstevel@tonic-gate 		scc = *s++ & TRIM;
5477c478bd9Sstevel@tonic-gate 		switch (c = *p++) {
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 		case '[':
5507c478bd9Sstevel@tonic-gate 			ok = 0;
5517c478bd9Sstevel@tonic-gate 			lc = 077777;
5527c478bd9Sstevel@tonic-gate 			while (cc = *p++) {
5537c478bd9Sstevel@tonic-gate 				if (cc == ']') {
5547c478bd9Sstevel@tonic-gate 					if (ok)
5557c478bd9Sstevel@tonic-gate 						break;
5567c478bd9Sstevel@tonic-gate 					return (0);
5577c478bd9Sstevel@tonic-gate 				}
5587c478bd9Sstevel@tonic-gate 				if (cc == '-') {
5597c478bd9Sstevel@tonic-gate 					if (lc <= scc && scc <= *p++)
5607c478bd9Sstevel@tonic-gate 						ok++;
5617c478bd9Sstevel@tonic-gate 				} else
5627c478bd9Sstevel@tonic-gate 					if (scc == (lc = cc))
5637c478bd9Sstevel@tonic-gate 						ok++;
5647c478bd9Sstevel@tonic-gate 			}
5657c478bd9Sstevel@tonic-gate 			if (cc == 0) {
5667c478bd9Sstevel@tonic-gate 				yyerror("Missing ']'");
5677c478bd9Sstevel@tonic-gate 				return (0);
5687c478bd9Sstevel@tonic-gate 			}
5697c478bd9Sstevel@tonic-gate 			continue;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 		case '*':
5727c478bd9Sstevel@tonic-gate 			if (!*p)
5737c478bd9Sstevel@tonic-gate 				return (1);
5747c478bd9Sstevel@tonic-gate 			for (s--; *s; s++)
5757c478bd9Sstevel@tonic-gate 				if (smatch(s, p))
5767c478bd9Sstevel@tonic-gate 					return (1);
5777c478bd9Sstevel@tonic-gate 			return (0);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 		case '\0':
5807c478bd9Sstevel@tonic-gate 			return (scc == '\0');
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		default:
5837c478bd9Sstevel@tonic-gate 			if ((c & TRIM) != scc)
5847c478bd9Sstevel@tonic-gate 				return (0);
5857c478bd9Sstevel@tonic-gate 			continue;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 		case '?':
5887c478bd9Sstevel@tonic-gate 			if (scc == 0)
5897c478bd9Sstevel@tonic-gate 				return (0);
5907c478bd9Sstevel@tonic-gate 			continue;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 		}
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
596*740638c8Sbw static void
5977c478bd9Sstevel@tonic-gate Cat(s1, s2)
5987c478bd9Sstevel@tonic-gate 	register char *s1, *s2;
5997c478bd9Sstevel@tonic-gate {
6007c478bd9Sstevel@tonic-gate 	int len = strlen(s1) + strlen(s2) + 1;
6017c478bd9Sstevel@tonic-gate 	register char *s;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	nleft -= len;
6047c478bd9Sstevel@tonic-gate 	if (nleft <= 0 || ++eargc >= GAVSIZ)
6057c478bd9Sstevel@tonic-gate 		fatal("Arguments too long\n");
6067c478bd9Sstevel@tonic-gate 	eargv[eargc] = 0;
6077c478bd9Sstevel@tonic-gate 	eargv[eargc - 1] = s = (char *)malloc(len);
6087c478bd9Sstevel@tonic-gate 	if (s == NULL)
6097c478bd9Sstevel@tonic-gate 		fatal("ran out of memory\n");
6107c478bd9Sstevel@tonic-gate 	while (*s++ = *s1++ & TRIM)
6117c478bd9Sstevel@tonic-gate 		;
6127c478bd9Sstevel@tonic-gate 	s--;
6137c478bd9Sstevel@tonic-gate 	while (*s++ = *s2++ & TRIM)
6147c478bd9Sstevel@tonic-gate 		;
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate 
617*740638c8Sbw static void
618*740638c8Sbw addpath(char c)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	if (pathp > lastpathp)
6227c478bd9Sstevel@tonic-gate 		yyerror("Pathname too long");
6237c478bd9Sstevel@tonic-gate 	else {
6247c478bd9Sstevel@tonic-gate 		*pathp++ = c & TRIM;
6257c478bd9Sstevel@tonic-gate 		*pathp = '\0';
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate /*
6307c478bd9Sstevel@tonic-gate  * Expand file names beginning with `~' into the
6317c478bd9Sstevel@tonic-gate  * user's home directory path name. Return a pointer in buf to the
6327c478bd9Sstevel@tonic-gate  * part corresponding to `file'.
6337c478bd9Sstevel@tonic-gate  */
6347c478bd9Sstevel@tonic-gate char *
6357c478bd9Sstevel@tonic-gate exptilde(buf, len, file)
6367c478bd9Sstevel@tonic-gate 	char buf[];
6377c478bd9Sstevel@tonic-gate 	unsigned int len;
6387c478bd9Sstevel@tonic-gate 	register char *file;
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate 	register char *s1, *s2, *s3;
6417c478bd9Sstevel@tonic-gate 	extern char homedir[];
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	if (*file != '~') {
6447c478bd9Sstevel@tonic-gate 		if (strlen(file) + 1 > len) {
6457c478bd9Sstevel@tonic-gate 			error("pathname too long: %s\n", file);
6467c478bd9Sstevel@tonic-gate 			return (NULL);
6477c478bd9Sstevel@tonic-gate 		}
6487c478bd9Sstevel@tonic-gate 		strcpy(buf, file);
6497c478bd9Sstevel@tonic-gate 		return (buf);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	if (*++file == '\0') {
6527c478bd9Sstevel@tonic-gate 		s2 = homedir;
6537c478bd9Sstevel@tonic-gate 		s3 = NULL;
6547c478bd9Sstevel@tonic-gate 	} else if (*file == '/') {
6557c478bd9Sstevel@tonic-gate 		s2 = homedir;
6567c478bd9Sstevel@tonic-gate 		s3 = file;
6577c478bd9Sstevel@tonic-gate 	} else {
6587c478bd9Sstevel@tonic-gate 		s3 = file;
6597c478bd9Sstevel@tonic-gate 		while (*s3 && *s3 != '/')
6607c478bd9Sstevel@tonic-gate 			s3++;
6617c478bd9Sstevel@tonic-gate 		if (*s3 == '/')
6627c478bd9Sstevel@tonic-gate 			*s3 = '\0';
6637c478bd9Sstevel@tonic-gate 		else
6647c478bd9Sstevel@tonic-gate 			s3 = NULL;
6657c478bd9Sstevel@tonic-gate 		if (pw == NULL || strcmp(pw->pw_name, file) != 0) {
6667c478bd9Sstevel@tonic-gate 			if ((pw = getpwnam(file)) == NULL) {
6677c478bd9Sstevel@tonic-gate 				error("%s: unknown user name\n", file);
6687c478bd9Sstevel@tonic-gate 				if (s3 != NULL)
6697c478bd9Sstevel@tonic-gate 					*s3 = '/';
6707c478bd9Sstevel@tonic-gate 				return (NULL);
6717c478bd9Sstevel@tonic-gate 			}
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 		if (s3 != NULL)
6747c478bd9Sstevel@tonic-gate 			*s3 = '/';
6757c478bd9Sstevel@tonic-gate 		s2 = pw->pw_dir;
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 	for (s1 = buf; s1 < &buf[len] && (*s1++ = *s2++); )
6787c478bd9Sstevel@tonic-gate 		;
6797c478bd9Sstevel@tonic-gate 	s2 = --s1;
6807c478bd9Sstevel@tonic-gate 	if (s3 != NULL) {
6817c478bd9Sstevel@tonic-gate 		s2++;
6827c478bd9Sstevel@tonic-gate 		while (s1 < &buf[len] && (*s1++ = *s3++))
6837c478bd9Sstevel@tonic-gate 			;
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 	if (s1 == &buf[len]) {
6867c478bd9Sstevel@tonic-gate 		error("pathname too long: %s\n", file - 1);
6877c478bd9Sstevel@tonic-gate 		return (NULL);
6887c478bd9Sstevel@tonic-gate 	}
6897c478bd9Sstevel@tonic-gate 	return (s2);
6907c478bd9Sstevel@tonic-gate }
691