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: }

Defined functions

Gcat defined in line 479; used 5 times
Gmatch defined in line 419; used 1 times
acollect defined in line 112; used 1 times
addpath defined in line 495; used 5 times
amatch defined in line 329; used 3 times
any defined in line 571; used 2 times
blkcpy defined in line 591; used 1 times
blkfree defined in line 603; used 5 times
blklen defined in line 581; used 1 times
collect defined in line 101; used 1 times
  • in line 84
copyblk defined in line 626; used 3 times
digit defined in line 564; used 1 times
execbrc defined in line 231; used 2 times
expand defined in line 141; used 3 times
gethdir defined in line 654; used 1 times
ginit defined in line 92; used 1 times
  • in line 83
glob defined in line 63; used 5 times
letter defined in line 557; used 1 times
match defined in line 311; used 1 times
matchdir defined in line 194; used 1 times
rscan defined in line 508; used 1 times
  • in line 73
sort defined in line 124; used 3 times
strend defined in line 638; used 2 times
strspl defined in line 612; used 2 times
tglob defined in line 538; used 3 times

Defined variables

entp defined in line 60; used 4 times
gargc defined in line 41; used 8 times
gargv defined in line 40; used 8 times
gflag defined in line 43; used 5 times
globbed defined in line 59; used 6 times
globchars defined in line 56; used 2 times
globcnt defined in line 54; used 5 times
globerr defined in line 46; used 9 times
gnleft defined in line 42; used 3 times
gpath defined in line 58; used 18 times
gpathp defined in line 58; used 23 times
home defined in line 47; used 9 times
lastgpathp defined in line 58; used 3 times
sccsid defined in line 19; never used
sortbas defined in line 61; used 3 times

Defined macros

GAVSIZ defined in line 37; used 2 times
QUOTE defined in line 34; used 1 times
TRIM defined in line 35; used 4 times
eq defined in line 36; used 4 times
isdir defined in line 38; used 2 times
Last modified: 1990-05-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4676
Valid CSS Valid XHTML 1.0 Strict