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