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