|
|
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.5 (Berkeley) 12/22/87"; ! 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 ',': ! 261: if (brclev) ! 262: continue; ! 263: doit: ! 264: savec = *pm; ! 265: *pm = 0; ! 266: (void) strcpy(lm, pl); ! 267: (void) strcat(restbuf, pe + 1); ! 268: *pm = savec; ! 269: if (s == 0) { ! 270: sgpathp = gpathp; ! 271: expand(restbuf); ! 272: gpathp = sgpathp; ! 273: *gpathp = 0; ! 274: } else if (amatch(s, restbuf)) ! 275: return (1); ! 276: sort(); ! 277: pl = pm + 1; ! 278: continue; ! 279: ! 280: case '[': ! 281: for (pm++; *pm && *pm != ']'; pm++) ! 282: continue; ! 283: if (!*pm) ! 284: error("Missing ]"); ! 285: continue; ! 286: } ! 287: return (0); ! 288: } ! 289: ! 290: match(s, p) ! 291: char *s, *p; ! 292: { ! 293: register int c; ! 294: register char *sentp; ! 295: char sglobbed = globbed; ! 296: ! 297: if (*s == '.' && *p != '.') ! 298: return (0); ! 299: sentp = entp; ! 300: entp = s; ! 301: c = amatch(s, p); ! 302: entp = sentp; ! 303: globbed = sglobbed; ! 304: return (c); ! 305: } ! 306: ! 307: amatch(s, p) ! 308: register char *s, *p; ! 309: { ! 310: register int scc; ! 311: int ok, lc; ! 312: char *sgpathp; ! 313: struct stat stb; ! 314: int c, cc; ! 315: ! 316: globbed = 1; ! 317: for (;;) { ! 318: scc = *s++ & TRIM; ! 319: switch (c = *p++) { ! 320: ! 321: case '{': ! 322: return (execbrc(p - 1, s - 1)); ! 323: ! 324: case '[': ! 325: ok = 0; ! 326: lc = 077777; ! 327: while (cc = *p++) { ! 328: if (cc == ']') { ! 329: if (ok) ! 330: break; ! 331: return (0); ! 332: } ! 333: if (cc == '-') { ! 334: if (lc <= scc && scc <= *p++) ! 335: ok++; ! 336: } else ! 337: if (scc == (lc = cc)) ! 338: ok++; ! 339: } ! 340: if (cc == 0) ! 341: error("Missing ]"); ! 342: continue; ! 343: ! 344: case '*': ! 345: if (!*p) ! 346: return (1); ! 347: if (*p == '/') { ! 348: p++; ! 349: goto slash; ! 350: } ! 351: for (s--; *s; s++) ! 352: if (amatch(s, p)) ! 353: return (1); ! 354: return (0); ! 355: ! 356: case 0: ! 357: return (scc == 0); ! 358: ! 359: default: ! 360: if ((c & TRIM) != scc) ! 361: return (0); ! 362: continue; ! 363: ! 364: case '?': ! 365: if (scc == 0) ! 366: return (0); ! 367: continue; ! 368: ! 369: case '/': ! 370: if (scc) ! 371: return (0); ! 372: slash: ! 373: s = entp; ! 374: sgpathp = gpathp; ! 375: while (*s) ! 376: addpath(*s++); ! 377: addpath('/'); ! 378: if (stat(gpath, &stb) == 0 && isdir(stb)) ! 379: if (*p == 0) { ! 380: Gcat(gpath, ""); ! 381: globcnt++; ! 382: } else ! 383: expand(p); ! 384: gpathp = sgpathp; ! 385: *gpathp = 0; ! 386: return (0); ! 387: } ! 388: } ! 389: } ! 390: ! 391: Gmatch(s, p) ! 392: register char *s, *p; ! 393: { ! 394: register int scc; ! 395: int ok, lc; ! 396: int c, cc; ! 397: ! 398: for (;;) { ! 399: scc = *s++ & TRIM; ! 400: switch (c = *p++) { ! 401: ! 402: case '[': ! 403: ok = 0; ! 404: lc = 077777; ! 405: while (cc = *p++) { ! 406: if (cc == ']') { ! 407: if (ok) ! 408: break; ! 409: return (0); ! 410: } ! 411: if (cc == '-') { ! 412: if (lc <= scc && scc <= *p++) ! 413: ok++; ! 414: } else ! 415: if (scc == (lc = cc)) ! 416: ok++; ! 417: } ! 418: if (cc == 0) ! 419: bferr("Missing ]"); ! 420: continue; ! 421: ! 422: case '*': ! 423: if (!*p) ! 424: return (1); ! 425: for (s--; *s; s++) ! 426: if (Gmatch(s, p)) ! 427: return (1); ! 428: return (0); ! 429: ! 430: case 0: ! 431: return (scc == 0); ! 432: ! 433: default: ! 434: if ((c & TRIM) != scc) ! 435: return (0); ! 436: continue; ! 437: ! 438: case '?': ! 439: if (scc == 0) ! 440: return (0); ! 441: continue; ! 442: ! 443: } ! 444: } ! 445: } ! 446: ! 447: Gcat(s1, s2) ! 448: char *s1, *s2; ! 449: { ! 450: register char *p, *q; ! 451: int n; ! 452: ! 453: for (p = s1; *p++;) ! 454: ; ! 455: for (q = s2; *q++;) ! 456: ; ! 457: gnleft -= (n = (p - s1) + (q - s2) - 1); ! 458: if (gnleft <= 0 || ++gargc >= GAVSIZ) ! 459: error("Arguments too long"); ! 460: gargv[gargc] = 0; ! 461: p = gargv[gargc - 1] = xalloc((unsigned)n); ! 462: for (q = s1; *p++ = *q++;) ! 463: ; ! 464: for (p--, q = s2; *p++ = *q++;) ! 465: ; ! 466: } ! 467: ! 468: addpath(c) ! 469: char c; ! 470: { ! 471: ! 472: if (gpathp >= lastgpathp) ! 473: error("Pathname too long"); ! 474: *gpathp++ = c & TRIM; ! 475: *gpathp = 0; ! 476: } ! 477: ! 478: rscan(t, f) ! 479: register char **t; ! 480: int (*f)(); ! 481: { ! 482: register char *p; ! 483: ! 484: while (p = *t++) ! 485: while (*p) ! 486: (*f)(*p++); ! 487: } ! 488: ! 489: trim(t) ! 490: register char **t; ! 491: { ! 492: register char *p; ! 493: ! 494: while (p = *t++) ! 495: while (*p) ! 496: *p++ &= TRIM; ! 497: } ! 498: ! 499: tglob(t) ! 500: register char **t; ! 501: { ! 502: register char *p, c; ! 503: ! 504: while (p = *t++) { ! 505: if (*p == '~') ! 506: gflag |= 2; ! 507: else if (*p == '{' && (p[1] == '\0' || p[1] == '}' && p[2] == '\0')) ! 508: continue; ! 509: while (c = *p++) ! 510: if (isglob(c)) ! 511: gflag |= c == '{' ? 2 : 1; ! 512: } ! 513: } ! 514: ! 515: char * ! 516: globone(str) ! 517: register char *str; ! 518: { ! 519: char *gv[2]; ! 520: register char **gvp; ! 521: register char *cp; ! 522: ! 523: gv[0] = str; ! 524: gv[1] = 0; ! 525: gflag = 0; ! 526: tglob(gv); ! 527: if (gflag) { ! 528: gvp = glob(gv); ! 529: if (gvp == 0) { ! 530: setname(str); ! 531: bferr("No match"); ! 532: } ! 533: cp = *gvp++; ! 534: if (cp == 0) ! 535: cp = ""; ! 536: else if (*gvp) { ! 537: setname(str); ! 538: bferr("Ambiguous"); ! 539: } else ! 540: cp = strip(cp); ! 541: /* ! 542: if (cp == 0 || *gvp) { ! 543: setname(str); ! 544: bferr(cp ? "Ambiguous" : "No output"); ! 545: } ! 546: */ ! 547: xfree((char *)gargv); gargv = 0; ! 548: } else { ! 549: trim(gv); ! 550: cp = savestr(gv[0]); ! 551: } ! 552: return (cp); ! 553: } ! 554: ! 555: /* ! 556: * Command substitute cp. If literal, then this is ! 557: * a substitution from a << redirection, and so we should ! 558: * not crunch blanks and tabs, separating words only at newlines. ! 559: */ ! 560: char ** ! 561: dobackp(cp, literal) ! 562: char *cp; ! 563: bool literal; ! 564: { ! 565: register char *lp, *rp; ! 566: char *ep; ! 567: char word[BUFSIZ]; ! 568: char *apargv[GAVSIZ + 2]; ! 569: ! 570: if (pargv) { ! 571: abort(); ! 572: blkfree(pargv); ! 573: } ! 574: pargv = apargv; ! 575: pargv[0] = NOSTR; ! 576: pargcp = pargs = word; ! 577: pargc = 0; ! 578: pnleft = BUFSIZ - 4; ! 579: for (;;) { ! 580: for (lp = cp; *lp != '`'; lp++) { ! 581: if (*lp == 0) { ! 582: if (pargcp != pargs) ! 583: pword(); ! 584: #ifdef GDEBUG ! 585: printf("leaving dobackp\n"); ! 586: #endif ! 587: return (pargv = copyblk(pargv)); ! 588: } ! 589: psave(*lp); ! 590: } ! 591: lp++; ! 592: for (rp = lp; *rp && *rp != '`'; rp++) ! 593: if (*rp == '\\') { ! 594: rp++; ! 595: if (!*rp) ! 596: goto oops; ! 597: } ! 598: if (!*rp) ! 599: oops: ! 600: error("Unmatched `"); ! 601: ep = savestr(lp); ! 602: ep[rp - lp] = 0; ! 603: backeval(ep, literal); ! 604: #ifdef GDEBUG ! 605: printf("back from backeval\n"); ! 606: #endif ! 607: cp = rp + 1; ! 608: } ! 609: } ! 610: ! 611: backeval(cp, literal) ! 612: char *cp; ! 613: bool literal; ! 614: { ! 615: int pvec[2]; ! 616: int quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0; ! 617: char ibuf[BUFSIZ]; ! 618: register int icnt = 0, c; ! 619: register char *ip; ! 620: bool hadnl = 0; ! 621: char *fakecom[2]; ! 622: struct command faket; ! 623: ! 624: faket.t_dtyp = TCOM; ! 625: faket.t_dflg = 0; ! 626: faket.t_dlef = 0; ! 627: faket.t_drit = 0; ! 628: faket.t_dspr = 0; ! 629: faket.t_dcom = fakecom; ! 630: fakecom[0] = "` ... `"; ! 631: fakecom[1] = 0; ! 632: /* ! 633: * We do the psave job to temporarily change the current job ! 634: * so that the following fork is considered a separate job. ! 635: * This is so that when backquotes are used in a ! 636: * builtin function that calls glob the "current job" is not corrupted. ! 637: * We only need one level of pushed jobs as long as we are sure to ! 638: * fork here. ! 639: */ ! 640: psavejob(); ! 641: /* ! 642: * It would be nicer if we could integrate this redirection more ! 643: * with the routines in sh.sem.c by doing a fake execute on a builtin ! 644: * function that was piped out. ! 645: */ ! 646: mypipe(pvec); ! 647: if (pfork(&faket, -1) == 0) { ! 648: struct wordent paraml; ! 649: struct command *t; ! 650: ! 651: (void) close(pvec[0]); ! 652: (void) dmove(pvec[1], 1); ! 653: (void) dmove(SHDIAG, 2); ! 654: initdesc(); ! 655: arginp = cp; ! 656: while (*cp) ! 657: *cp++ &= TRIM; ! 658: (void) lex(¶ml); ! 659: if (err) ! 660: error(err); ! 661: alias(¶ml); ! 662: t = syntax(paraml.next, ¶ml, 0); ! 663: if (err) ! 664: error(err); ! 665: if (t) ! 666: t->t_dflg |= FPAR; ! 667: (void) signal(SIGTSTP, SIG_IGN); ! 668: (void) signal(SIGTTIN, SIG_IGN); ! 669: (void) signal(SIGTTOU, SIG_IGN); ! 670: execute(t, -1); ! 671: exitstat(); ! 672: } ! 673: xfree(cp); ! 674: (void) close(pvec[1]); ! 675: do { ! 676: int cnt = 0; ! 677: for (;;) { ! 678: if (icnt == 0) { ! 679: ip = ibuf; ! 680: icnt = read(pvec[0], ip, BUFSIZ); ! 681: if (icnt <= 0) { ! 682: c = -1; ! 683: break; ! 684: } ! 685: } ! 686: if (hadnl) ! 687: break; ! 688: --icnt; ! 689: c = (*ip++ & TRIM); ! 690: if (c == 0) ! 691: break; ! 692: if (c == '\n') { ! 693: /* ! 694: * Continue around the loop one ! 695: * more time, so that we can eat ! 696: * the last newline without terminating ! 697: * this word. ! 698: */ ! 699: hadnl = 1; ! 700: continue; ! 701: } ! 702: if (!quoted && (c == ' ' || c == '\t')) ! 703: break; ! 704: cnt++; ! 705: psave(c | quoted); ! 706: } ! 707: /* ! 708: * Unless at end-of-file, we will form a new word ! 709: * here if there were characters in the word, or in ! 710: * any case when we take text literally. If ! 711: * we didn't make empty words here when literal was ! 712: * set then we would lose blank lines. ! 713: */ ! 714: if (c != -1 && (cnt || literal)) ! 715: pword(); ! 716: hadnl = 0; ! 717: } while (c >= 0); ! 718: #ifdef GDEBUG ! 719: printf("done in backeval, pvec: %d %d\n", pvec[0], pvec[1]); ! 720: printf("also c = %c <%o>\n", c, c); ! 721: #endif ! 722: (void) close(pvec[0]); ! 723: pwait(); ! 724: prestjob(); ! 725: } ! 726: ! 727: psave(c) ! 728: char c; ! 729: { ! 730: ! 731: if (--pnleft <= 0) ! 732: error("Word too long"); ! 733: *pargcp++ = c; ! 734: } ! 735: ! 736: pword() ! 737: { ! 738: ! 739: psave(0); ! 740: if (pargc == GAVSIZ) ! 741: error("Too many words from ``"); ! 742: pargv[pargc++] = savestr(pargs); ! 743: pargv[pargc] = NOSTR; ! 744: #ifdef GDEBUG ! 745: printf("got word %s\n", pargv[pargc-1]); ! 746: #endif ! 747: pargcp = pargs; ! 748: pnleft = BUFSIZ - 4; ! 749: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.