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 = "@(#)sh.glob.c	5.4 (Berkeley) 5/13/86";
   9: #endif
  10: 
  11: #include "sh.h"
  12: #include <sys/dir.h>
  13: 
  14: /*
  15:  * C Shell
  16:  */
  17: 
  18: int globcnt;
  19: 
  20: char    *gpath, *gpathp, *lastgpathp;
  21: int globbed;
  22: bool    noglob;
  23: bool    nonomatch;
  24: char    *entp;
  25: char    **sortbas;
  26: int sortscmp();
  27: 
  28: #define sort()  qsort((char *)sortbas, &gargv[gargc] - sortbas, \
  29:               sizeof(*sortbas), sortscmp), sortbas = &gargv[gargc]
  30: 
  31: 
  32: char **
  33: glob(v)
  34:     register char **v;
  35: {
  36:     char agpath[BUFSIZ];
  37:     char *agargv[GAVSIZ];
  38: 
  39:     gpath = agpath; gpathp = gpath; *gpathp = 0;
  40:     lastgpathp = &gpath[sizeof agpath - 2];
  41:     ginit(agargv); globcnt = 0;
  42: #ifdef GDEBUG
  43:     printf("glob entered: "); blkpr(v); printf("\n");
  44: #endif
  45:     noglob = adrof("noglob") != 0;
  46:     nonomatch = adrof("nonomatch") != 0;
  47:     globcnt = noglob | nonomatch;
  48:     while (*v)
  49:         collect(*v++);
  50: #ifdef GDEBUG
  51:     printf("glob done, globcnt=%d, gflag=%d: ", globcnt, gflag); blkpr(gargv); printf("\n");
  52: #endif
  53:     if (globcnt == 0 && (gflag&1)) {
  54:         blkfree(gargv), gargv = 0;
  55:         return (0);
  56:     } else
  57:         return (gargv = copyblk(gargv));
  58: }
  59: 
  60: ginit(agargv)
  61:     char **agargv;
  62: {
  63: 
  64:     agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
  65:     gnleft = NCARGS - 4;
  66: }
  67: 
  68: collect(as)
  69:     register char *as;
  70: {
  71:     register int i;
  72: 
  73:     if (any('`', as)) {
  74: #ifdef GDEBUG
  75:         printf("doing backp of %s\n", as);
  76: #endif
  77:         (void) dobackp(as, 0);
  78: #ifdef GDEBUG
  79:         printf("backp done, acollect'ing\n");
  80: #endif
  81:         for (i = 0; i < pargc; i++)
  82:             if (noglob) {
  83:                 Gcat(pargv[i], "");
  84:                 sortbas = &gargv[gargc];
  85:             } else
  86:                 acollect(pargv[i]);
  87:         if (pargv)
  88:             blkfree(pargv), pargv = 0;
  89: #ifdef GDEBUG
  90:         printf("acollect done\n");
  91: #endif
  92:     } else if (noglob || eq(as, "{") || eq(as, "{}")) {
  93:         Gcat(as, "");
  94:         sort();
  95:     } else
  96:         acollect(as);
  97: }
  98: 
  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:         if (nonomatch) {
 108:             Gcat(as, "");
 109:             sort();
 110:         }
 111:     } else
 112:         sort();
 113: }
 114: 
 115: /*
 116:  * String compare for qsort.  Also used by filec code in sh.file.c.
 117:  */
 118: sortscmp(a1, a2)
 119:     char **a1, **a2;
 120: {
 121: 
 122:      return (strcmp(*a1, *a2));
 123: }
 124: 
 125: expand(as)
 126:     char *as;
 127: {
 128:     register char *cs;
 129:     register char *sgpathp, *oldcs;
 130:     struct stat stb;
 131: 
 132:     sgpathp = gpathp;
 133:     cs = as;
 134:     if (*cs == '~' && gpathp == gpath) {
 135:         addpath('~');
 136:         for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
 137:             addpath(*cs++);
 138:         if (!*cs || *cs == '/') {
 139:             if (gpathp != gpath + 1) {
 140:                 *gpathp = 0;
 141:                 if (gethdir(gpath + 1))
 142:                     error("Unknown user: %s", gpath + 1);
 143:                 (void) strcpy(gpath, gpath + 1);
 144:             } else
 145:                 (void) strcpy(gpath, value("home"));
 146:             gpathp = strend(gpath);
 147:         }
 148:     }
 149:     while (!isglob(*cs)) {
 150:         if (*cs == 0) {
 151:             if (!globbed)
 152:                 Gcat(gpath, "");
 153:             else if (stat(gpath, &stb) >= 0) {
 154:                 Gcat(gpath, "");
 155:                 globcnt++;
 156:             }
 157:             goto endit;
 158:         }
 159:         addpath(*cs++);
 160:     }
 161:     oldcs = cs;
 162:     while (cs > as && *cs != '/')
 163:         cs--, gpathp--;
 164:     if (*cs == '/')
 165:         cs++, gpathp++;
 166:     *gpathp = 0;
 167:     if (*oldcs == '{') {
 168:         (void) execbrc(cs, NOSTR);
 169:         return;
 170:     }
 171:     matchdir(cs);
 172: endit:
 173:     gpathp = sgpathp;
 174:     *gpathp = 0;
 175: }
 176: 
 177: matchdir(pattern)
 178:     char *pattern;
 179: {
 180:     struct stat stb;
 181:     register struct direct *dp;
 182:     register DIR *dirp;
 183: 
 184:     dirp = opendir(gpath);
 185:     if (dirp == NULL) {
 186:         if (globbed)
 187:             return;
 188:         goto patherr2;
 189:     }
 190:     if (fstat(dirp->dd_fd, &stb) < 0)
 191:         goto patherr1;
 192:     if (!isdir(stb)) {
 193:         errno = ENOTDIR;
 194:         goto patherr1;
 195:     }
 196:     while ((dp = readdir(dirp)) != NULL) {
 197:         if (dp->d_ino == 0)
 198:             continue;
 199:         if (match(dp->d_name, pattern)) {
 200:             Gcat(gpath, dp->d_name);
 201:             globcnt++;
 202:         }
 203:     }
 204:     closedir(dirp);
 205:     return;
 206: 
 207: patherr1:
 208:     closedir(dirp);
 209: patherr2:
 210:     Perror(gpath);
 211: }
 212: 
 213: execbrc(p, s)
 214:     char *p, *s;
 215: {
 216:     char restbuf[BUFSIZ + 2];
 217:     register char *pe, *pm, *pl;
 218:     int brclev = 0;
 219:     char *lm, savec, *sgpathp;
 220: 
 221:     for (lm = restbuf; *p != '{'; *lm++ = *p++)
 222:         continue;
 223:     for (pe = ++p; *pe; pe++)
 224:     switch (*pe) {
 225: 
 226:     case '{':
 227:         brclev++;
 228:         continue;
 229: 
 230:     case '}':
 231:         if (brclev == 0)
 232:             goto pend;
 233:         brclev--;
 234:         continue;
 235: 
 236:     case '[':
 237:         for (pe++; *pe && *pe != ']'; pe++)
 238:             continue;
 239:         if (!*pe)
 240:             error("Missing ]");
 241:         continue;
 242:     }
 243: pend:
 244:     if (brclev || !*pe)
 245:         error("Missing }");
 246:     for (pl = pm = p; pm <= pe; pm++)
 247:     switch (*pm & (QUOTE|TRIM)) {
 248: 
 249:     case '{':
 250:         brclev++;
 251:         continue;
 252: 
 253:     case '}':
 254:         if (brclev) {
 255:             brclev--;
 256:             continue;
 257:         }
 258:         goto doit;
 259: 
 260:     case ','|QUOTE:
 261:     case ',':
 262:         if (brclev)
 263:             continue;
 264: doit:
 265:         savec = *pm;
 266:         *pm = 0;
 267:         (void) strcpy(lm, pl);
 268:         (void) strcat(restbuf, pe + 1);
 269:         *pm = savec;
 270:         if (s == 0) {
 271:             sgpathp = gpathp;
 272:             expand(restbuf);
 273:             gpathp = sgpathp;
 274:             *gpathp = 0;
 275:         } else if (amatch(s, restbuf))
 276:             return (1);
 277:         sort();
 278:         pl = pm + 1;
 279:         continue;
 280: 
 281:     case '[':
 282:         for (pm++; *pm && *pm != ']'; pm++)
 283:             continue;
 284:         if (!*pm)
 285:             error("Missing ]");
 286:         continue;
 287:     }
 288:     return (0);
 289: }
 290: 
 291: match(s, p)
 292:     char *s, *p;
 293: {
 294:     register int c;
 295:     register char *sentp;
 296:     char sglobbed = globbed;
 297: 
 298:     if (*s == '.' && *p != '.')
 299:         return (0);
 300:     sentp = entp;
 301:     entp = s;
 302:     c = amatch(s, p);
 303:     entp = sentp;
 304:     globbed = sglobbed;
 305:     return (c);
 306: }
 307: 
 308: amatch(s, p)
 309:     register char *s, *p;
 310: {
 311:     register int scc;
 312:     int ok, lc;
 313:     char *sgpathp;
 314:     struct stat stb;
 315:     int c, cc;
 316: 
 317:     globbed = 1;
 318:     for (;;) {
 319:         scc = *s++ & TRIM;
 320:         switch (c = *p++) {
 321: 
 322:         case '{':
 323:             return (execbrc(p - 1, s - 1));
 324: 
 325:         case '[':
 326:             ok = 0;
 327:             lc = 077777;
 328:             while (cc = *p++) {
 329:                 if (cc == ']') {
 330:                     if (ok)
 331:                         break;
 332:                     return (0);
 333:                 }
 334:                 if (cc == '-') {
 335:                     if (lc <= scc && scc <= *p++)
 336:                         ok++;
 337:                 } else
 338:                     if (scc == (lc = cc))
 339:                         ok++;
 340:             }
 341:             if (cc == 0)
 342:                 error("Missing ]");
 343:             continue;
 344: 
 345:         case '*':
 346:             if (!*p)
 347:                 return (1);
 348:             if (*p == '/') {
 349:                 p++;
 350:                 goto slash;
 351:             }
 352:             for (s--; *s; s++)
 353:                 if (amatch(s, p))
 354:                     return (1);
 355:             return (0);
 356: 
 357:         case 0:
 358:             return (scc == 0);
 359: 
 360:         default:
 361:             if ((c & TRIM) != scc)
 362:                 return (0);
 363:             continue;
 364: 
 365:         case '?':
 366:             if (scc == 0)
 367:                 return (0);
 368:             continue;
 369: 
 370:         case '/':
 371:             if (scc)
 372:                 return (0);
 373: slash:
 374:             s = entp;
 375:             sgpathp = gpathp;
 376:             while (*s)
 377:                 addpath(*s++);
 378:             addpath('/');
 379:             if (stat(gpath, &stb) == 0 && isdir(stb))
 380:                 if (*p == 0) {
 381:                     Gcat(gpath, "");
 382:                     globcnt++;
 383:                 } else
 384:                     expand(p);
 385:             gpathp = sgpathp;
 386:             *gpathp = 0;
 387:             return (0);
 388:         }
 389:     }
 390: }
 391: 
 392: Gmatch(s, p)
 393:     register char *s, *p;
 394: {
 395:     register int scc;
 396:     int ok, lc;
 397:     int c, cc;
 398: 
 399:     for (;;) {
 400:         scc = *s++ & TRIM;
 401:         switch (c = *p++) {
 402: 
 403:         case '[':
 404:             ok = 0;
 405:             lc = 077777;
 406:             while (cc = *p++) {
 407:                 if (cc == ']') {
 408:                     if (ok)
 409:                         break;
 410:                     return (0);
 411:                 }
 412:                 if (cc == '-') {
 413:                     if (lc <= scc && scc <= *p++)
 414:                         ok++;
 415:                 } else
 416:                     if (scc == (lc = cc))
 417:                         ok++;
 418:             }
 419:             if (cc == 0)
 420:                 bferr("Missing ]");
 421:             continue;
 422: 
 423:         case '*':
 424:             if (!*p)
 425:                 return (1);
 426:             for (s--; *s; s++)
 427:                 if (Gmatch(s, p))
 428:                     return (1);
 429:             return (0);
 430: 
 431:         case 0:
 432:             return (scc == 0);
 433: 
 434:         default:
 435:             if ((c & TRIM) != scc)
 436:                 return (0);
 437:             continue;
 438: 
 439:         case '?':
 440:             if (scc == 0)
 441:                 return (0);
 442:             continue;
 443: 
 444:         }
 445:     }
 446: }
 447: 
 448: Gcat(s1, s2)
 449:     char *s1, *s2;
 450: {
 451:     register char *p, *q;
 452:     int n;
 453: 
 454:     for (p = s1; *p++;)
 455:         ;
 456:     for (q = s2; *q++;)
 457:         ;
 458:     gnleft -= (n = (p - s1) + (q - s2) - 1);
 459:     if (gnleft <= 0 || ++gargc >= GAVSIZ)
 460:         error("Arguments too long");
 461:     gargv[gargc] = 0;
 462:     p = gargv[gargc - 1] = xalloc((unsigned)n);
 463:     for (q = s1; *p++ = *q++;)
 464:         ;
 465:     for (p--, q = s2; *p++ = *q++;)
 466:         ;
 467: }
 468: 
 469: addpath(c)
 470:     char c;
 471: {
 472: 
 473:     if (gpathp >= lastgpathp)
 474:         error("Pathname too long");
 475:     *gpathp++ = c & TRIM;
 476:     *gpathp = 0;
 477: }
 478: 
 479: rscan(t, f)
 480:     register char **t;
 481:     int (*f)();
 482: {
 483:     register char *p;
 484: 
 485:     while (p = *t++)
 486:         while (*p)
 487:             (*f)(*p++);
 488: }
 489: 
 490: trim(t)
 491:     register char **t;
 492: {
 493:     register char *p;
 494: 
 495:     while (p = *t++)
 496:         while (*p)
 497:             *p++ &= TRIM;
 498: }
 499: 
 500: tglob(t)
 501:     register char **t;
 502: {
 503:     register char *p, c;
 504: 
 505:     while (p = *t++) {
 506:         if (*p == '~')
 507:             gflag |= 2;
 508:         else if (*p == '{' && (p[1] == '\0' || p[1] == '}' && p[2] == '\0'))
 509:             continue;
 510:         while (c = *p++)
 511:             if (isglob(c))
 512:                 gflag |= c == '{' ? 2 : 1;
 513:     }
 514: }
 515: 
 516: char *
 517: globone(str)
 518:     register char *str;
 519: {
 520:     char *gv[2];
 521:     register char **gvp;
 522:     register char *cp;
 523: 
 524:     gv[0] = str;
 525:     gv[1] = 0;
 526:     gflag = 0;
 527:     tglob(gv);
 528:     if (gflag) {
 529:         gvp = glob(gv);
 530:         if (gvp == 0) {
 531:             setname(str);
 532:             bferr("No match");
 533:         }
 534:         cp = *gvp++;
 535:         if (cp == 0)
 536:             cp = "";
 537:         else if (*gvp) {
 538:             setname(str);
 539:             bferr("Ambiguous");
 540:         } else
 541:             cp = strip(cp);
 542: /*
 543: 		if (cp == 0 || *gvp) {
 544: 			setname(str);
 545: 			bferr(cp ? "Ambiguous" : "No output");
 546: 		}
 547: */
 548:         xfree((char *)gargv); gargv = 0;
 549:     } else {
 550:         trim(gv);
 551:         cp = savestr(gv[0]);
 552:     }
 553:     return (cp);
 554: }
 555: 
 556: /*
 557:  * Command substitute cp.  If literal, then this is
 558:  * a substitution from a << redirection, and so we should
 559:  * not crunch blanks and tabs, separating words only at newlines.
 560:  */
 561: char **
 562: dobackp(cp, literal)
 563:     char *cp;
 564:     bool literal;
 565: {
 566:     register char *lp, *rp;
 567:     char *ep;
 568:     char word[BUFSIZ];
 569:     char *apargv[GAVSIZ + 2];
 570: 
 571:     if (pargv) {
 572:         abort();
 573:         blkfree(pargv);
 574:     }
 575:     pargv = apargv;
 576:     pargv[0] = NOSTR;
 577:     pargcp = pargs = word;
 578:     pargc = 0;
 579:     pnleft = BUFSIZ - 4;
 580:     for (;;) {
 581:         for (lp = cp; *lp != '`'; lp++) {
 582:             if (*lp == 0) {
 583:                 if (pargcp != pargs)
 584:                     pword();
 585: #ifdef GDEBUG
 586:                 printf("leaving dobackp\n");
 587: #endif
 588:                 return (pargv = copyblk(pargv));
 589:             }
 590:             psave(*lp);
 591:         }
 592:         lp++;
 593:         for (rp = lp; *rp && *rp != '`'; rp++)
 594:             if (*rp == '\\') {
 595:                 rp++;
 596:                 if (!*rp)
 597:                     goto oops;
 598:             }
 599:         if (!*rp)
 600: oops:
 601:             error("Unmatched `");
 602:         ep = savestr(lp);
 603:         ep[rp - lp] = 0;
 604:         backeval(ep, literal);
 605: #ifdef GDEBUG
 606:         printf("back from backeval\n");
 607: #endif
 608:         cp = rp + 1;
 609:     }
 610: }
 611: 
 612: backeval(cp, literal)
 613:     char *cp;
 614:     bool literal;
 615: {
 616:     int pvec[2];
 617:     int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
 618:     char ibuf[BUFSIZ];
 619:     register int icnt = 0, c;
 620:     register char *ip;
 621:     bool hadnl = 0;
 622:     char *fakecom[2];
 623:     struct command faket;
 624: 
 625:     faket.t_dtyp = TCOM;
 626:     faket.t_dflg = 0;
 627:     faket.t_dlef = 0;
 628:     faket.t_drit = 0;
 629:     faket.t_dspr = 0;
 630:     faket.t_dcom = fakecom;
 631:     fakecom[0] = "` ... `";
 632:     fakecom[1] = 0;
 633:     /*
 634: 	 * We do the psave job to temporarily change the current job
 635: 	 * so that the following fork is considered a separate job.
 636: 	 * This is so that when backquotes are used in a
 637: 	 * builtin function that calls glob the "current job" is not corrupted.
 638: 	 * We only need one level of pushed jobs as long as we are sure to
 639: 	 * fork here.
 640: 	 */
 641:     psavejob();
 642:     /*
 643: 	 * It would be nicer if we could integrate this redirection more
 644: 	 * with the routines in sh.sem.c by doing a fake execute on a builtin
 645: 	 * function that was piped out.
 646: 	 */
 647:     mypipe(pvec);
 648:     if (pfork(&faket, -1) == 0) {
 649:         struct wordent paraml;
 650:         struct command *t;
 651: 
 652:         (void) close(pvec[0]);
 653:         (void) dmove(pvec[1], 1);
 654:         (void) dmove(SHDIAG, 2);
 655:         initdesc();
 656:         arginp = cp;
 657:         while (*cp)
 658:             *cp++ &= TRIM;
 659:         (void) lex(&paraml);
 660:         if (err)
 661:             error(err);
 662:         alias(&paraml);
 663:         t = syntax(paraml.next, &paraml, 0);
 664:         if (err)
 665:             error(err);
 666:         if (t)
 667:             t->t_dflg |= FPAR;
 668:         (void) signal(SIGTSTP, SIG_IGN);
 669:         (void) signal(SIGTTIN, SIG_IGN);
 670:         (void) signal(SIGTTOU, SIG_IGN);
 671:         execute(t, -1);
 672:         exitstat();
 673:     }
 674:     xfree(cp);
 675:     (void) close(pvec[1]);
 676:     do {
 677:         int cnt = 0;
 678:         for (;;) {
 679:             if (icnt == 0) {
 680:                 ip = ibuf;
 681:                 icnt = read(pvec[0], ip, BUFSIZ);
 682:                 if (icnt <= 0) {
 683:                     c = -1;
 684:                     break;
 685:                 }
 686:             }
 687:             if (hadnl)
 688:                 break;
 689:             --icnt;
 690:             c = (*ip++ & TRIM);
 691:             if (c == 0)
 692:                 break;
 693:             if (c == '\n') {
 694:                 /*
 695: 				 * Continue around the loop one
 696: 				 * more time, so that we can eat
 697: 				 * the last newline without terminating
 698: 				 * this word.
 699: 				 */
 700:                 hadnl = 1;
 701:                 continue;
 702:             }
 703:             if (!quoted && (c == ' ' || c == '\t'))
 704:                 break;
 705:             cnt++;
 706:             psave(c | quoted);
 707:         }
 708:         /*
 709: 		 * Unless at end-of-file, we will form a new word
 710: 		 * here if there were characters in the word, or in
 711: 		 * any case when we take text literally.  If
 712: 		 * we didn't make empty words here when literal was
 713: 		 * set then we would lose blank lines.
 714: 		 */
 715:         if (c != -1 && (cnt || literal))
 716:             pword();
 717:         hadnl = 0;
 718:     } while (c >= 0);
 719: #ifdef GDEBUG
 720:     printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]);
 721:     printf("also c = %c <%o>\n", c, c);
 722: #endif
 723:     (void) close(pvec[0]);
 724:     pwait();
 725:     prestjob();
 726: }
 727: 
 728: psave(c)
 729:     char c;
 730: {
 731: 
 732:     if (--pnleft <= 0)
 733:         error("Word too long");
 734:     *pargcp++ = c;
 735: }
 736: 
 737: pword()
 738: {
 739: 
 740:     psave(0);
 741:     if (pargc == GAVSIZ)
 742:         error("Too many words from ``");
 743:     pargv[pargc++] = savestr(pargs);
 744:     pargv[pargc] = NOSTR;
 745: #ifdef GDEBUG
 746:     printf("got word %s\n", pargv[pargc-1]);
 747: #endif
 748:     pargcp = pargs;
 749:     pnleft = BUFSIZ - 4;
 750: }

Defined functions

Gcat defined in line 448; used 8 times
Gmatch defined in line 392; used 5 times
acollect defined in line 99; used 2 times
addpath defined in line 469; used 5 times
amatch defined in line 308; used 3 times
backeval defined in line 612; used 1 times
collect defined in line 68; used 1 times
  • in line 49
dobackp defined in line 561; used 3 times
execbrc defined in line 213; used 2 times
expand defined in line 125; used 3 times
ginit defined in line 60; used 2 times
glob defined in line 32; used 7 times
match defined in line 291; used 1 times
matchdir defined in line 177; used 1 times
psave defined in line 728; used 3 times
pword defined in line 737; used 2 times
rscan defined in line 479; used 1 times
sortscmp defined in line 118; used 4 times
tglob defined in line 500; used 6 times

Defined variables

entp defined in line 24; used 4 times
globbed defined in line 21; used 6 times
globcnt defined in line 18; used 7 times
gpath defined in line 20; used 20 times
gpathp defined in line 20; used 23 times
lastgpathp defined in line 20; used 2 times
noglob defined in line 22; used 4 times
nonomatch defined in line 23; used 3 times
sccsid defined in line 8; never used
sortbas defined in line 25; used 6 times

Defined macros

sort defined in line 28; used 4 times
Last modified: 1986-05-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2349
Valid CSS Valid XHTML 1.0 Strict