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