|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.