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