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