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