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