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