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