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