1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)glob.c 5.2 (Berkeley) 3/7/86"; 9: #endif not lint 10: 11: /* 12: * C-shell glob for random programs. 13: */ 14: 15: #include <sys/param.h> 16: #include <sys/stat.h> 17: #include <sys/dir.h> 18: 19: #include <stdio.h> 20: #include <errno.h> 21: #include <pwd.h> 22: 23: #define QUOTE 0200 24: #define TRIM 0177 25: #define eq(a,b) (strcmp(a, b)==0) 26: #define GAVSIZ (NCARGS/6) 27: #define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR) 28: 29: static char **gargv; /* Pointer to the (stack) arglist */ 30: static short gargc; /* Number args in gargv */ 31: static short gnleft; 32: static short gflag; 33: static int tglob(); 34: char **glob(); 35: char *globerr; 36: char *home; 37: struct passwd *getpwnam(); 38: extern int errno; 39: static char *strspl(), *strend(); 40: char *malloc(), *strcpy(), *strcat(); 41: char **copyblk(); 42: 43: static int globcnt; 44: 45: char *globchars = "`{[*?"; 46: 47: static char *gpath, *gpathp, *lastgpathp; 48: static int globbed; 49: static char *entp; 50: static char **sortbas; 51: 52: char ** 53: glob(v) 54: register char *v; 55: { 56: char agpath[BUFSIZ]; 57: char *agargv[GAVSIZ]; 58: char *vv[2]; 59: vv[0] = v; 60: vv[1] = 0; 61: gflag = 0; 62: rscan(vv, tglob); 63: if (gflag == 0) 64: return (copyblk(vv)); 65: 66: globerr = 0; 67: gpath = agpath; gpathp = gpath; *gpathp = 0; 68: lastgpathp = &gpath[sizeof agpath - 2]; 69: ginit(agargv); globcnt = 0; 70: collect(v); 71: if (globcnt == 0 && (gflag&1)) { 72: blkfree(gargv), gargv = 0; 73: return (0); 74: } else 75: return (gargv = copyblk(gargv)); 76: } 77: 78: static 79: ginit(agargv) 80: char **agargv; 81: { 82: 83: agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; 84: gnleft = NCARGS - 4; 85: } 86: 87: static 88: collect(as) 89: register char *as; 90: { 91: if (eq(as, "{") || eq(as, "{}")) { 92: Gcat(as, ""); 93: sort(); 94: } else 95: acollect(as); 96: } 97: 98: static 99: acollect(as) 100: register char *as; 101: { 102: register int ogargc = gargc; 103: 104: gpathp = gpath; *gpathp = 0; globbed = 0; 105: expand(as); 106: if (gargc != ogargc) 107: sort(); 108: } 109: 110: static 111: sort() 112: { 113: register char **p1, **p2, *c; 114: char **Gvp = &gargv[gargc]; 115: 116: p1 = sortbas; 117: while (p1 < Gvp-1) { 118: p2 = p1; 119: while (++p2 < Gvp) 120: if (strcmp(*p1, *p2) > 0) 121: c = *p1, *p1 = *p2, *p2 = c; 122: p1++; 123: } 124: sortbas = Gvp; 125: } 126: 127: static 128: expand(as) 129: char *as; 130: { 131: register char *cs; 132: register char *sgpathp, *oldcs; 133: struct stat stb; 134: 135: sgpathp = gpathp; 136: cs = as; 137: if (*cs == '~' && gpathp == gpath) { 138: addpath('~'); 139: for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) 140: addpath(*cs++); 141: if (!*cs || *cs == '/') { 142: if (gpathp != gpath + 1) { 143: *gpathp = 0; 144: if (gethdir(gpath + 1)) 145: globerr = "Unknown user name after ~"; 146: (void) strcpy(gpath, gpath + 1); 147: } else 148: (void) strcpy(gpath, home); 149: gpathp = strend(gpath); 150: } 151: } 152: while (!any(*cs, globchars)) { 153: if (*cs == 0) { 154: if (!globbed) 155: Gcat(gpath, ""); 156: else if (stat(gpath, &stb) >= 0) { 157: Gcat(gpath, ""); 158: globcnt++; 159: } 160: goto endit; 161: } 162: addpath(*cs++); 163: } 164: oldcs = cs; 165: while (cs > as && *cs != '/') 166: cs--, gpathp--; 167: if (*cs == '/') 168: cs++, gpathp++; 169: *gpathp = 0; 170: if (*oldcs == '{') { 171: (void) execbrc(cs, ((char *)0)); 172: return; 173: } 174: matchdir(cs); 175: endit: 176: gpathp = sgpathp; 177: *gpathp = 0; 178: } 179: 180: static 181: matchdir(pattern) 182: char *pattern; 183: { 184: struct stat stb; 185: register struct direct *dp; 186: DIR *dirp; 187: 188: dirp = opendir(gpath); 189: if (dirp == NULL) { 190: if (globbed) 191: return; 192: goto patherr2; 193: } 194: if (fstat(dirp->dd_fd, &stb) < 0) 195: goto patherr1; 196: if (!isdir(stb)) { 197: errno = ENOTDIR; 198: goto patherr1; 199: } 200: while ((dp = readdir(dirp)) != NULL) { 201: if (dp->d_ino == 0) 202: continue; 203: if (match(dp->d_name, pattern)) { 204: Gcat(gpath, dp->d_name); 205: globcnt++; 206: } 207: } 208: closedir(dirp); 209: return; 210: 211: patherr1: 212: closedir(dirp); 213: patherr2: 214: globerr = "Bad directory components"; 215: } 216: 217: static 218: execbrc(p, s) 219: char *p, *s; 220: { 221: char restbuf[BUFSIZ + 2]; 222: register char *pe, *pm, *pl; 223: int brclev = 0; 224: char *lm, savec, *sgpathp; 225: 226: for (lm = restbuf; *p != '{'; *lm++ = *p++) 227: continue; 228: for (pe = ++p; *pe; pe++) 229: switch (*pe) { 230: 231: case '{': 232: brclev++; 233: continue; 234: 235: case '}': 236: if (brclev == 0) 237: goto pend; 238: brclev--; 239: continue; 240: 241: case '[': 242: for (pe++; *pe && *pe != ']'; pe++) 243: continue; 244: continue; 245: } 246: pend: 247: brclev = 0; 248: for (pl = pm = p; pm <= pe; pm++) 249: switch (*pm & (QUOTE|TRIM)) { 250: 251: case '{': 252: brclev++; 253: continue; 254: 255: case '}': 256: if (brclev) { 257: brclev--; 258: continue; 259: } 260: goto doit; 261: 262: case ','|QUOTE: 263: case ',': 264: if (brclev) 265: continue; 266: doit: 267: savec = *pm; 268: *pm = 0; 269: (void) strcpy(lm, pl); 270: (void) strcat(restbuf, pe + 1); 271: *pm = savec; 272: if (s == 0) { 273: sgpathp = gpathp; 274: expand(restbuf); 275: gpathp = sgpathp; 276: *gpathp = 0; 277: } else if (amatch(s, restbuf)) 278: return (1); 279: sort(); 280: pl = pm + 1; 281: if (brclev) 282: return (0); 283: continue; 284: 285: case '[': 286: for (pm++; *pm && *pm != ']'; pm++) 287: continue; 288: if (!*pm) 289: pm--; 290: continue; 291: } 292: if (brclev) 293: goto doit; 294: return (0); 295: } 296: 297: static 298: match(s, p) 299: char *s, *p; 300: { 301: register int c; 302: register char *sentp; 303: char sglobbed = globbed; 304: 305: if (*s == '.' && *p != '.') 306: return (0); 307: sentp = entp; 308: entp = s; 309: c = amatch(s, p); 310: entp = sentp; 311: globbed = sglobbed; 312: return (c); 313: } 314: 315: static 316: amatch(s, p) 317: register char *s, *p; 318: { 319: register int scc; 320: int ok, lc; 321: char *sgpathp; 322: struct stat stb; 323: int c, cc; 324: 325: globbed = 1; 326: for (;;) { 327: scc = *s++ & TRIM; 328: switch (c = *p++) { 329: 330: case '{': 331: return (execbrc(p - 1, s - 1)); 332: 333: case '[': 334: ok = 0; 335: lc = 077777; 336: while (cc = *p++) { 337: if (cc == ']') { 338: if (ok) 339: break; 340: return (0); 341: } 342: if (cc == '-') { 343: if (lc <= scc && scc <= *p++) 344: ok++; 345: } else 346: if (scc == (lc = cc)) 347: ok++; 348: } 349: if (cc == 0) 350: if (ok) 351: p--; 352: else 353: return 0; 354: continue; 355: 356: case '*': 357: if (!*p) 358: return (1); 359: if (*p == '/') { 360: p++; 361: goto slash; 362: } 363: s--; 364: do { 365: if (amatch(s, p)) 366: return (1); 367: } while (*s++); 368: return (0); 369: 370: case 0: 371: return (scc == 0); 372: 373: default: 374: if (c != scc) 375: return (0); 376: continue; 377: 378: case '?': 379: if (scc == 0) 380: return (0); 381: continue; 382: 383: case '/': 384: if (scc) 385: return (0); 386: slash: 387: s = entp; 388: sgpathp = gpathp; 389: while (*s) 390: addpath(*s++); 391: addpath('/'); 392: if (stat(gpath, &stb) == 0 && isdir(stb)) 393: if (*p == 0) { 394: Gcat(gpath, ""); 395: globcnt++; 396: } else 397: expand(p); 398: gpathp = sgpathp; 399: *gpathp = 0; 400: return (0); 401: } 402: } 403: } 404: 405: static 406: Gmatch(s, p) 407: register char *s, *p; 408: { 409: register int scc; 410: int ok, lc; 411: int c, cc; 412: 413: for (;;) { 414: scc = *s++ & TRIM; 415: switch (c = *p++) { 416: 417: case '[': 418: ok = 0; 419: lc = 077777; 420: while (cc = *p++) { 421: if (cc == ']') { 422: if (ok) 423: break; 424: return (0); 425: } 426: if (cc == '-') { 427: if (lc <= scc && scc <= *p++) 428: ok++; 429: } else 430: if (scc == (lc = cc)) 431: ok++; 432: } 433: if (cc == 0) 434: if (ok) 435: p--; 436: else 437: return 0; 438: continue; 439: 440: case '*': 441: if (!*p) 442: return (1); 443: for (s--; *s; s++) 444: if (Gmatch(s, p)) 445: return (1); 446: return (0); 447: 448: case 0: 449: return (scc == 0); 450: 451: default: 452: if ((c & TRIM) != scc) 453: return (0); 454: continue; 455: 456: case '?': 457: if (scc == 0) 458: return (0); 459: continue; 460: 461: } 462: } 463: } 464: 465: static 466: Gcat(s1, s2) 467: register char *s1, *s2; 468: { 469: register int len = strlen(s1) + strlen(s2) + 1; 470: 471: if (len >= gnleft || gargc >= GAVSIZ - 1) 472: globerr = "Arguments too long"; 473: else { 474: gargc++; 475: gnleft -= len; 476: gargv[gargc] = 0; 477: gargv[gargc - 1] = strspl(s1, s2); 478: } 479: } 480: 481: static 482: addpath(c) 483: char c; 484: { 485: 486: if (gpathp >= lastgpathp) 487: globerr = "Pathname too long"; 488: else { 489: *gpathp++ = c; 490: *gpathp = 0; 491: } 492: } 493: 494: static 495: rscan(t, f) 496: register char **t; 497: int (*f)(); 498: { 499: register char *p, c; 500: 501: while (p = *t++) { 502: if (f == tglob) 503: if (*p == '~') 504: gflag |= 2; 505: else if (eq(p, "{") || eq(p, "{}")) 506: continue; 507: while (c = *p++) 508: (*f)(c); 509: } 510: } 511: /* 512: static 513: scan(t, f) 514: register char **t; 515: int (*f)(); 516: { 517: register char *p, c; 518: 519: while (p = *t++) 520: while (c = *p) 521: *p++ = (*f)(c); 522: } */ 523: 524: static 525: tglob(c) 526: register char c; 527: { 528: 529: if (any(c, globchars)) 530: gflag |= c == '{' ? 2 : 1; 531: return (c); 532: } 533: /* 534: static 535: trim(c) 536: char c; 537: { 538: 539: return (c & TRIM); 540: } */ 541: 542: 543: letter(c) 544: register char c; 545: { 546: 547: return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); 548: } 549: 550: digit(c) 551: register char c; 552: { 553: 554: return (c >= '0' && c <= '9'); 555: } 556: 557: any(c, s) 558: register int c; 559: register char *s; 560: { 561: 562: while (*s) 563: if (*s++ == c) 564: return(1); 565: return(0); 566: } 567: blklen(av) 568: register char **av; 569: { 570: register int i = 0; 571: 572: while (*av++) 573: i++; 574: return (i); 575: } 576: 577: char ** 578: blkcpy(oav, bv) 579: char **oav; 580: register char **bv; 581: { 582: register char **av = oav; 583: 584: while (*av++ = *bv++) 585: continue; 586: return (oav); 587: } 588: 589: blkfree(av0) 590: char **av0; 591: { 592: register char **av = av0; 593: 594: while (*av) 595: free(*av++); 596: free((char *)av0); 597: } 598: 599: static 600: char * 601: strspl(cp, dp) 602: register char *cp, *dp; 603: { 604: register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1)); 605: 606: if (ep == (char *)0) 607: fatal("Out of memory"); 608: (void) strcpy(ep, cp); 609: (void) strcat(ep, dp); 610: return (ep); 611: } 612: 613: char ** 614: copyblk(v) 615: register char **v; 616: { 617: register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) * 618: sizeof(char **))); 619: if (nv == (char **)0) 620: fatal("Out of memory"); 621: 622: return (blkcpy(nv, v)); 623: } 624: 625: static 626: char * 627: strend(cp) 628: register char *cp; 629: { 630: 631: while (*cp) 632: cp++; 633: return (cp); 634: } 635: /* 636: * Extract a home directory from the password file 637: * The argument points to a buffer where the name of the 638: * user whose home directory is sought is currently. 639: * We write the home directory of the user back there. 640: */ 641: gethdir(home) 642: char *home; 643: { 644: register struct passwd *pp = getpwnam(home); 645: 646: if (pp == 0) 647: return (1); 648: (void) strcpy(home, pp->pw_dir); 649: return (0); 650: }