|
|
1.1 ! root 1: /* ! 2: * egrep -- pattern matcher ! 3: * ! 4: * Lines of input are searched for the user-supplied extended ! 5: * regular expression. Command line options determine what "egrep" ! 6: * does on a match: usually the line is printed. Lines over BUFSIZ ! 7: * chars in length may be fatal when read from pipes or raw devices. ! 8: * The implementation goal is speed and, to this end, a DFA is ! 9: * employed. Two key strategies reduce the time spent constructing ! 10: * the DFA by a factor of 100, in typical cases: (1) the use of ! 11: * equivalence classes, (2) construction of the DFA dynamically. ! 12: * These strategies win because of the way "egrep" tends to be used. ! 13: * Most patterns use only 10-20 characters in the ASCII set of 128. ! 14: * Most input exercises only 10% of the total possible transitions ! 15: * (so why compute the remaining 90%?). As a side benefit, these ! 16: * strategies reduce "egrep"'s gigantic appetite for memory to merely ! 17: * huge. Strategy (2) has the important psychological effect of making ! 18: * "egrep" appear to start running instantly; the inevitable time spent ! 19: * constructing the DFA is amortized over the running time of the ! 20: * program. ! 21: */ ! 22: #include <stdio.h> ! 23: #include <ctype.h> ! 24: #ifdef COHERENT ! 25: #include <access.h> ! 26: #else ! 27: #define DOS 1 ! 28: #endif ! 29: ! 30: /* ! 31: ** rico.h ! 32: */ ! 33: #define bool char ! 34: #define TRUE 1 ! 35: #define FALSE 0 ! 36: ! 37: /* ! 38: ** egrep.h ! 39: */ ! 40: /* ! 41: * bit diddling ! 42: */ ! 43: #define NCHARS 128 /* chars in ASCII set */ ! 44: #define NBCHAR 8 /* bits per char */ ! 45: ! 46: #define bitset(c, p) ((p)[(c)>>3] |= bitmask[(c)&7]) ! 47: #define bitclr(c, p) ((p)[(c)>>3] &= ~bitmask[(c)&7]) ! 48: #define bitcom(c, p) ((p)[(c)>>3] ^= bitmask[(c)&7]) ! 49: #define bittst(c, p) ((p)[(c)>>3] & bitmask[(c)&7]) ! 50: ! 51: /* ! 52: * support for bitmaps ! 53: */ ! 54: readonly char bitmask[] = { ! 55: 0001, 0002, 0004, 0010, 0020, 0040, 0100, 0200 ! 56: }; ! 57: ! 58: ! 59: extern char *newbits(); ! 60: ! 61: /* ! 62: ** dragon.h ! 63: */ ! 64: /* ! 65: * DFA state ! 66: * The egrep DFA is composed of these structs. Operation of the DFA ! 67: * requires the use of d_success and d_p, only. ! 68: */ ! 69: struct dragon { ! 70: bool d_success; /* this is an accepting state */ ! 71: struct newt **d_s; /* set of NFA states (newts) */ ! 72: char *d_b; /* bitmap of d_s */ ! 73: int d_hash; /* hash of d_s */ ! 74: struct dragon *d_next; /* next dragon (or 0) */ ! 75: struct dragon *d_last; /* previous dragon (or 0) */ ! 76: struct dragon **d_p; /* transition vector */ ! 77: }; ! 78: ! 79: /* ! 80: ** newt.h ! 81: */ ! 82: /* ! 83: * NFA state ! 84: * The rex is converted into an NFA composed of these structs. ! 85: */ ! 86: struct newt { ! 87: char n_c; /* label for transition n_cp */ ! 88: char n_flags; /* [see below] */ ! 89: int n_uniq; /* unique # */ ! 90: int n_id; /* ID # of this newt */ ! 91: char *n_b; /* alternative label (char class) */ ! 92: struct newt *n_cp; /* transition labeled n_c */ ! 93: struct newt *n_ep; /* transition labeled EPSILON */ ! 94: struct newt *n_fp; /* final newt in this sub-goal */ ! 95: }; ! 96: ! 97: /* n_c ! 98: */ ! 99: #define EPSILON (-1) /* n_cp is an epsilon transition */ ! 100: ! 101: /* n_flags ! 102: */ ! 103: #define N_BOL 01 /* beginning-of-line */ ! 104: #define N_EOL 02 /* end-of-line */ ! 105: ! 106: /* ! 107: ** equiv.c ! 108: */ ! 109: /* ! 110: * equivalence class ! 111: * The set of ASCII chars is refined by the sets of chars used by ! 112: * the regular expression. The result is a set of equivalence classes: ! 113: * disjoint sets of chars, whose union is the ASCII set. ! 114: * An eclass struct describes one equivalence class. The structs ! 115: * are linked, and headed by `eclasses'. ! 116: */ ! 117: struct eclass { ! 118: char e_c; /* used if only one char in set */ ! 119: char e_class; /* ID # of this eclass */ ! 120: char *e_b; /* used if many chars in set */ ! 121: struct eclass *e_next; /* next eclass (or 0) */ ! 122: }; ! 123: ! 124: bool aflag; /* use emacs after file with hit */ ! 125: bool eflag; /* next arg is regular expression */ ! 126: bool fflag; /* next arg is file containing rex */ ! 127: bool vflag; /* line matches if rex NOT found */ ! 128: bool cflag; /* only print # matches */ ! 129: bool lflag; /* only print name of files that match */ ! 130: bool nflag; /* also print line # */ ! 131: bool bflag; /* also print block # */ ! 132: bool sflag; /* only provide exit status */ ! 133: bool hflag; /* do not print file names */ ! 134: bool yflag; /* lower case also matches upper case input */ ! 135: ! 136: int uniq, n_id, n_ec; ! 137: ! 138: FILE *ifp; /* input */ ! 139: FILE *tmpFile; /* tmp file for use with emacs */ ! 140: char *tmpFn = NULL; /* tmp file name */ ! 141: /* ! 142: * egrep ! 143: * Return 0 if any matches found in the input files, else 1. ! 144: */ ! 145: main(argc, argv) ! 146: char **argv; ! 147: { ! 148: register struct newt *np; ! 149: register struct dragon *dp; ! 150: struct newt *makenfa(); ! 151: struct newt *npolish(); ! 152: struct dragon *initdfa(); ! 153: int status; ! 154: char **init(); ! 155: bool search(); ! 156: ! 157: #ifdef MSDOS ! 158: msdoscvt("egrep", &argc, &argv); ! 159: #endif ! 160: argv = init(argc, argv ); ! 161: #ifdef MSDOS ! 162: /* ! 163: * On systems which distinguish between ASCII and binary streams, ! 164: * egrep reads its input as a binary stream, so it can be used to ! 165: * look for a string in an object file (for example). It also ! 166: * writes its output as a binary stream in most cases, so for ASCII ! 167: * input files newline mapping happens neither on input nor on output. ! 168: * However, "-c" and "-l" require ASCII output for newline mapping. ! 169: * Kludgy; one alternative is to have it read and write ASCII streams, ! 170: * forget about egrep'ing object files, and futz the seek count when ! 171: * it sees a newline in the input. ! 172: */ ! 173: if (!cflag && !lflag) ! 174: _setbinary(stdout); ! 175: #endif ! 176: ! 177: np = makenfa(); ! 178: ncheck(initdfa(np)->d_s); ! 179: np = npolish(np); ! 180: dp = initdfa(np); ! 181: ! 182: status = 1; ! 183: ! 184: if (*argv) ! 185: do { ! 186: if ((ifp = fopen(*argv, "rb")) == NULL) { ! 187: fprintf(stderr, ! 188: "egrep: can't open %s\n", *argv); ! 189: continue; ! 190: } ! 191: if (search(*argv, dp, np)) ! 192: status = 0; ! 193: fclose(ifp); ! 194: if (aflag && (NULL != tmpFn)) ! 195: emacs(*argv); ! 196: } while (*++argv); ! 197: else { ! 198: ifp = stdin; ! 199: #ifdef MSDOS ! 200: _setbinary(ifp); ! 201: #endif ! 202: if (search("(stdin)", dp, np)) ! 203: status = 0; ! 204: } ! 205: ! 206: return (status); ! 207: } ! 208: ! 209: /* ! 210: * initialization ! 211: * Process command line. Return `argv' pointing to first file arg. ! 212: */ ! 213: static char ** ! 214: init(argc, argv) ! 215: char **argv; ! 216: { ! 217: register char **av; ! 218: register char *a; ! 219: register bool gotrex; ! 220: extern char *regexp; ! 221: extern FILE *rexf; ! 222: ! 223: gotrex = FALSE; ! 224: av = &argv[1]; ! 225: ! 226: while (a = *av++) { ! 227: if (*a != '-') { ! 228: if (! gotrex) { ! 229: gotrex = TRUE; ! 230: regexp = a; ! 231: a = *av++; ! 232: } ! 233: break; ! 234: } ! 235: while (*++a) ! 236: switch (*a) { ! 237: case 'A': ! 238: aflag = TRUE; ! 239: break; ! 240: case 'e': ! 241: if (gotrex) ! 242: onlyone(); ! 243: if (*av == NULL) ! 244: fatal("missing arg to -e"); ! 245: regexp = *av++; ! 246: gotrex = TRUE; ! 247: break; ! 248: case 'f': ! 249: if (gotrex) ! 250: onlyone(); ! 251: if (*av == NULL) ! 252: fatal("missing arg to -f"); ! 253: rexf = fopen(*av, "r"); ! 254: if (rexf == NULL) ! 255: fatal("can't open %s", *av); ! 256: ++av; ! 257: gotrex = TRUE; ! 258: break; ! 259: case 'v': ! 260: vflag = TRUE; ! 261: break; ! 262: case 'c': ! 263: cflag = TRUE; ! 264: break; ! 265: case 'l': ! 266: lflag = TRUE; ! 267: break; ! 268: case 'n': ! 269: nflag = TRUE; ! 270: break; ! 271: case 'b': ! 272: bflag = TRUE; ! 273: break; ! 274: case 's': ! 275: sflag = TRUE; ! 276: break; ! 277: case 'h': ! 278: hflag = TRUE; ! 279: break; ! 280: case 'y': ! 281: case 'i': ! 282: yflag = TRUE; ! 283: break; ! 284: default: ! 285: fatal("no such flag -%c", *a); ! 286: } ! 287: } ! 288: ! 289: if (! gotrex) { ! 290: fprintf(stderr, ! 291: "Usage: egrep [ -bcefhlnsvy ] pattern [ file ...]\n"); ! 292: exit(2); ! 293: } ! 294: ! 295: --av; ! 296: if (argc-(av-argv) <= 1) ! 297: hflag = TRUE; ! 298: return (av); ! 299: } ! 300: ! 301: /* ! 302: * call emacs with tmpfile. ! 303: */ ! 304: emacs(arg) ! 305: char *arg; ! 306: { ! 307: #ifdef GEMDOS ! 308: #include <path.h> ! 309: extern char *path(), *getenv(); ! 310: extern char **environ; ! 311: static char* cmda[5] = { NULL, "-e", NULL, NULL, NULL }; ! 312: #endif ! 313: #ifdef MSDOS ! 314: char line[BUFSIZ]; ! 315: #endif ! 316: #ifdef COHERENT ! 317: char line[BUFSIZ]; ! 318: #endif ! 319: int quit; ! 320: ! 321: fclose(tmpFile); ! 322: #ifdef MSDOS ! 323: sprintf(line, "-e %s %s", tmpFn, arg); ! 324: if (0x7f == (quit = execall("me", line))) ! 325: #endif ! 326: #ifdef COHERENT ! 327: sprintf(line, "me -e %s %s ", tmpFn, arg); ! 328: if (0x7f == (quit = system(line))) ! 329: #endif ! 330: #ifdef GEMDOS ! 331: cmda[2] = tmpFn; ! 332: cmda[3] = arg; ! 333: if ((NULL == cmda[0]) && ! 334: (NULL == (cmda[0] = path(getenv("PATH"), "me.tos", 1)))) { ! 335: fprintf(stderr, "egrep: Cannot locate me.tos\n"); ! 336: quit = 1; ! 337: } ! 338: else if ((quit = execve(cmda[0], cmda, environ)) < 0) ! 339: #endif ! 340: fprintf(stderr, "egrep: cannot execute 'me'"); ! 341: unlink(tmpFn); ! 342: free(tmpFn); ! 343: tmpFn = NULL; ! 344: if (quit) ! 345: exit(0); ! 346: } ! 347: ! 348: static ! 349: onlyone() ! 350: { ! 351: fatal("exactly one pattern required"); ! 352: } ! 353: ! 354: ! 355: nomem() ! 356: { ! 357: ! 358: fatal("out of mem"); ! 359: } ! 360: ! 361: ! 362: /* ! 363: * fatal error ! 364: */ ! 365: fatal(arg0) ! 366: char *arg0; ! 367: { ! 368: fflush(stdout); ! 369: fprintf(stderr, "egrep: %r\n", &arg0); ! 370: exit(2); ! 371: } ! 372: ! 373: /* ! 374: ** nfa.c ! 375: */ ! 376: ! 377: ! 378: /* ! 379: * creation of the NFA ! 380: */ ! 381: ! 382: ! 383: /* only one is set by init() ! 384: */ ! 385: char *regexp; /* user's regular expression */ ! 386: FILE *rexf; /* file containing user's rex */ ! 387: ! 388: ! 389: static curc; /* current char from rex */ ! 390: ! 391: struct newt *getrex(); ! 392: struct newt *getterm(); ! 393: struct newt *getfac(); ! 394: struct newt *getatom(); ! 395: struct newt *newnewt(); ! 396: ! 397: ! 398: /* ! 399: * create NFA from rex ! 400: * A pointer to the NFA is returned. ! 401: */ ! 402: struct newt *makenfa() ! 403: { ! 404: register struct newt *p; ! 405: ! 406: advance(); ! 407: p = getrex(); ! 408: if (curc) ! 409: misplaced(curc); ! 410: if (p == NULL) ! 411: fatal("empty pattern"); ! 412: return (p); ! 413: } ! 414: ! 415: ! 416: /* ! 417: * check NFA semantics ! 418: * Ensure correct usage of '^' and '$'. ! 419: */ ! 420: ncheck(npp) ! 421: register struct newt **npp; ! 422: { ! 423: register struct newt *np; ! 424: ! 425: ++uniq; ! 426: ! 427: while (np = *npp++) ! 428: if (np->n_cp && np->n_c!=EPSILON) { ! 429: if (np->n_flags & N_EOL) ! 430: nbeeline(np); ! 431: nwalk(np->n_cp); ! 432: } ! 433: } ! 434: ! 435: ! 436: /* ! 437: * add finishing touch to NFA ! 438: * Prepend a sort of ".*" to the front of the NFA. ! 439: */ ! 440: struct newt *npolish(np) ! 441: register struct newt *np; ! 442: { ! 443: register struct newt *p; ! 444: ! 445: p = newnewt(); ! 446: p->n_b = newbits(TRUE); ! 447: p->n_cp = newnewt(); ! 448: p->n_cp->n_c = EPSILON; ! 449: p->n_cp->n_cp = p; ! 450: p->n_ep = np; ! 451: p->n_fp = np->n_fp; ! 452: return (p); ! 453: } ! 454: ! 455: ! 456: /* ! 457: * get regular expression ! 458: * A trailing '\n' is tolerated, to accommodate the "-f" option. ! 459: */ ! 460: static struct newt *getrex() ! 461: { ! 462: register struct newt *p; ! 463: register struct newt *q; ! 464: register struct newt *start; ! 465: struct newt *final; ! 466: ! 467: start = getterm(); ! 468: if (start == NULL) ! 469: return (start); ! 470: final = newnewt(); ! 471: start->n_fp->n_c = EPSILON; ! 472: start->n_fp->n_cp = final; ! 473: start->n_fp = final; ! 474: ! 475: for (; ; ) { ! 476: switch (curc) { ! 477: case '|': ! 478: advance(); ! 479: if (p = getterm()) ! 480: break; ! 481: misplaced('|'); ! 482: case '\n': ! 483: advance(); ! 484: if (p = getterm()) ! 485: break; ! 486: if (curc != '\0') ! 487: misplaced('\n'); ! 488: default: ! 489: return (start); ! 490: } ! 491: p->n_fp->n_c = EPSILON; ! 492: p->n_fp->n_cp = final; ! 493: q = newnewt(); ! 494: q->n_c = EPSILON; ! 495: q->n_cp = p; ! 496: q->n_ep = start; ! 497: q->n_fp = final; ! 498: start = q; ! 499: } ! 500: } ! 501: ! 502: ! 503: /* ! 504: * get term ! 505: */ ! 506: static struct newt * ! 507: getterm() ! 508: { ! 509: register struct newt *start; ! 510: register struct newt *p; ! 511: ! 512: start = getfac(); ! 513: if (start == NULL) ! 514: return (start); ! 515: ! 516: while (p = getfac()) { ! 517: start->n_fp->n_c = EPSILON; ! 518: start->n_fp->n_cp = p; ! 519: start->n_fp = p->n_fp; ! 520: } ! 521: ! 522: return (start); ! 523: } ! 524: ! 525: ! 526: /* ! 527: * get factor ! 528: */ ! 529: static struct newt *getfac() ! 530: { ! 531: register struct newt *p; ! 532: register struct newt *q; ! 533: register struct newt *start; ! 534: ! 535: start = getatom(); ! 536: if (start == NULL) ! 537: return (start); ! 538: p = start; ! 539: ! 540: if (curc == '*') { ! 541: advance(); ! 542: start = newnewt(); ! 543: q = newnewt(); ! 544: start->n_c = EPSILON; ! 545: start->n_cp = p; ! 546: start->n_ep = q; ! 547: p->n_fp->n_c = EPSILON; ! 548: p->n_fp->n_cp = q; ! 549: p->n_fp->n_ep = p; ! 550: start->n_fp = q; ! 551: } ! 552: else if (curc == '+') { ! 553: advance(); ! 554: q = newnewt(); ! 555: p->n_fp->n_c = EPSILON; ! 556: p->n_fp->n_cp = q; ! 557: p->n_fp->n_ep = p; ! 558: start->n_fp = q; ! 559: } ! 560: else if (curc == '?') { ! 561: advance(); ! 562: start = newnewt(); ! 563: start->n_c = EPSILON; ! 564: start->n_cp = p; ! 565: start->n_ep = p->n_fp; ! 566: start->n_fp = p->n_fp; ! 567: } ! 568: return (start); ! 569: } ! 570: ! 571: ! 572: /* ! 573: * get atom ! 574: * The interpretation of the "-y" option is given by this example: ! 575: * egrep -y 'R\i\c\o H[a-z]* Tudor' ! 576: * means ! 577: * egrep 'Rico H[A-Za-z]* T[Uu][Dd][Oo][Rr]' ! 578: */ ! 579: static struct newt *getatom() ! 580: { ! 581: register struct newt *start; ! 582: char *charclass(); ! 583: ! 584: start = newnewt(); ! 585: start->n_cp = newnewt(); ! 586: start->n_fp = start->n_cp; ! 587: ! 588: switch (curc) { ! 589: case '\0': ! 590: case '\n': ! 591: case '|': ! 592: case '*': ! 593: case ')': ! 594: case ']': ! 595: case '+': ! 596: case '?': ! 597: nonewts(start); ! 598: return (0); ! 599: case '.': ! 600: start->n_b = newbits(TRUE); ! 601: bitclr('\n', start->n_b); ! 602: equiv(start); ! 603: break; ! 604: case '^': ! 605: start->n_flags |= N_BOL; ! 606: start->n_c = '\n'; ! 607: equiv(start); ! 608: break; ! 609: case '$': ! 610: start->n_flags |= N_EOL; ! 611: #if DOS ! 612: start->n_c = '\r'; ! 613: #else ! 614: start->n_c = '\n'; ! 615: #endif ! 616: equiv(start); ! 617: break; ! 618: case '[': ! 619: advance(); ! 620: start->n_b = charclass(); ! 621: equiv(start); ! 622: break; ! 623: case '(': ! 624: advance(); ! 625: nonewts(start); ! 626: start = getrex(); ! 627: if (curc == '\0') ! 628: fatal("missing ')'"); ! 629: if ((start == NULL) || curc!=')') ! 630: misplaced(curc); ! 631: break; ! 632: case '\\': ! 633: advance(); ! 634: if (curc=='\0' || curc=='\n') ! 635: misplaced('\\'); ! 636: start->n_c = curc; ! 637: equiv(start); ! 638: break; ! 639: default: ! 640: if (yflag && islower(curc)) { ! 641: start->n_b = newbits(FALSE); ! 642: bitset(curc, start->n_b); ! 643: bitset(toupper(curc), start->n_b); ! 644: } ! 645: else ! 646: start->n_c = curc; ! 647: equiv(start); ! 648: } ! 649: advance(); ! 650: ! 651: return (start); ! 652: } ! 653: ! 654: ! 655: static char *charclass() ! 656: { ! 657: register char *p; ! 658: register c; ! 659: register bool compl; ! 660: ! 661: compl = FALSE; ! 662: p = newbits(FALSE); ! 663: if (curc == '^') { ! 664: compl = TRUE; ! 665: advance(); ! 666: } ! 667: if (curc == '\0') ! 668: badclass(); ! 669: ! 670: do { ! 671: c = curc; ! 672: advance(); ! 673: if (c == '\0') ! 674: badclass(); ! 675: if (curc == '-') { ! 676: advance(); ! 677: if (curc == '\0') ! 678: badclass(); ! 679: if (curc == ']') { ! 680: bitset('-', p); ! 681: bitset(c, p); ! 682: } ! 683: else if (c > curc) ! 684: fatal("bad char class range %c-%c", c, curc); ! 685: else { ! 686: do { ! 687: bitset(c, p); ! 688: } while (++c <= curc); ! 689: advance(); ! 690: } ! 691: } ! 692: else ! 693: bitset(c, p); ! 694: } while (curc != ']'); ! 695: ! 696: if (bittst('\n', p)) ! 697: misplaced('\n'); ! 698: if (yflag) ! 699: for (c='a'; c<='z'; ++c) ! 700: if (bittst(c, p)) ! 701: bitset(toupper(c), p); ! 702: if (compl) { ! 703: for (c=0; c<NCHARS; ++c) ! 704: bitcom(c, p); ! 705: bitclr('\n', p); ! 706: } ! 707: return (p); ! 708: } ! 709: ! 710: ! 711: /* ! 712: * allocate new newt struct ! 713: */ ! 714: static struct newt *newnewt() ! 715: { ! 716: register struct newt *p; ! 717: ! 718: p = malloc(sizeof *p); ! 719: if (p == NULL) ! 720: nomem(); ! 721: p->n_c = 0; ! 722: p->n_flags = 0; ! 723: p->n_b = NULL; ! 724: p->n_cp = NULL; ! 725: p->n_ep = NULL; ! 726: p->n_fp = NULL; ! 727: p->n_uniq = 0; ! 728: p->n_id = n_id++; ! 729: ! 730: return (p); ! 731: } ! 732: ! 733: ! 734: /* ! 735: * free newt structs ! 736: * Used to free unused atoms. ! 737: */ ! 738: static nonewts(np) ! 739: struct newt *np; ! 740: { ! 741: ! 742: free((char *)np->n_cp); ! 743: free((char *)np); ! 744: n_id -= 2; ! 745: } ! 746: ! 747: ! 748: /* ! 749: * get next char from rex ! 750: * The next char from the file or the string is placed in `curc'. ! 751: */ ! 752: static advance() ! 753: { ! 754: register c; ! 755: ! 756: if (regexp) ! 757: c = *regexp++; ! 758: else { ! 759: c = getc(rexf); ! 760: if (c == EOF) ! 761: c = '\0'; ! 762: } ! 763: curc = c & 0177; ! 764: } ! 765: ! 766: ! 767: /* ! 768: * report misplaced '^' ! 769: */ ! 770: static nwalk(np) ! 771: register struct newt *np; ! 772: { ! 773: ! 774: while (np->n_cp) { ! 775: if (np->n_uniq == uniq) ! 776: return; ! 777: np->n_uniq = uniq; ! 778: if (np->n_flags & N_EOL) ! 779: nbeeline(np); ! 780: if (np->n_flags & N_BOL) ! 781: misplaced('^'); ! 782: if (np->n_ep) ! 783: nwalk(np->n_ep); ! 784: np = np->n_cp; ! 785: } ! 786: } ! 787: ! 788: ! 789: /* ! 790: * report misplaced '$' ! 791: */ ! 792: static nbeeline(np) ! 793: register struct newt *np; ! 794: { ! 795: ! 796: while (np = np->n_cp) { ! 797: if ((np->n_cp && np->n_c!=EPSILON) ! 798: || (np->n_ep)) ! 799: misplaced('$'); ! 800: } ! 801: } ! 802: ! 803: ! 804: static misplaced(c) ! 805: { ! 806: static char s[] = "`c'"; ! 807: ! 808: s[1] = c; ! 809: fatal("misplaced %s in pattern", c=='\n'? "newline": s); ! 810: } ! 811: ! 812: ! 813: static badclass() ! 814: { ! 815: ! 816: fatal("non-terminated char class"); ! 817: } ! 818: /* ! 819: ** equiv.c ! 820: */ ! 821: ! 822: ! 823: /* ! 824: * equivalence classes ! 825: */ ! 826: ! 827: ! 828: char etab[NCHARS]; /* map ASCII to eclass # */ ! 829: struct eclass *eclasses; /* head of eclass list */ ! 830: ! 831: bool intersect(); ! 832: struct eclass *neweclass(); ! 833: ! 834: ! 835: /* ! 836: * check equivalence ! 837: * A set of eclasses must exist such that their union equals the ! 838: * chars in `np'. If not, the equivalence relation must be "refined". ! 839: */ ! 840: equiv(np) ! 841: register struct newt *np; ! 842: { ! 843: register struct eclass *ep; ! 844: register struct eclass *p; ! 845: struct eclass e; ! 846: ! 847: if (eclasses == NULL) { ! 848: eclasses = neweclass(); ! 849: eclasses->e_c = 0; ! 850: eclasses->e_b = newbits(TRUE); ! 851: eclasses->e_next = NULL; ! 852: eclasses->e_class = n_ec++; ! 853: } ! 854: ! 855: for (ep=eclasses; ep; ep=ep->e_next) { ! 856: if (! intersect(np, ep, &e)) ! 857: continue; ! 858: p = neweclass(); ! 859: *p = e; ! 860: p->e_class = n_ec++; ! 861: p->e_next = eclasses; ! 862: eclasses = p; ! 863: } ! 864: } ! 865: ! 866: ! 867: /* ! 868: * is there a transition? ! 869: * Return TRUE if there is a transition from `np' on the chars given ! 870: * by `ep'. ! 871: */ ! 872: bool eqtrans(ep, np) ! 873: register struct eclass *ep; ! 874: register struct newt *np; ! 875: { ! 876: register i; ! 877: ! 878: if (ep->e_b) { ! 879: if (np->n_b) { ! 880: for (i=0; i<NCHARS/NBCHAR; ++i) ! 881: if (ep->e_b[i] & np->n_b[i]) ! 882: return (TRUE); ! 883: } ! 884: else ! 885: return (bittst(np->n_c, ep->e_b)); ! 886: } ! 887: else { ! 888: if (np->n_b) ! 889: return (bittst(ep->e_c, np->n_b)); ! 890: else ! 891: return (ep->e_c == np->n_c); ! 892: } ! 893: return (FALSE); ! 894: } ! 895: ! 896: ! 897: /* ! 898: * intersect char sets ! 899: * If the intersection of `np' and `ep0' is a proper subset of `ep0', ! 900: * then store the intersection in `ep1', store the difference of ! 901: * `ep0' - `ep1' in `ep0' and return TRUE. ! 902: */ ! 903: static bool intersect(np, ep0, ep1) ! 904: register struct newt *np; ! 905: register struct eclass *ep0; ! 906: struct eclass *ep1; ! 907: { ! 908: register i; ! 909: bool classcheck(); ! 910: ! 911: if (ep0->e_b == NULL) ! 912: return (FALSE); ! 913: ! 914: if (np->n_b == NULL) { ! 915: i = np->n_c; ! 916: if (! bittst(i, ep0->e_b)) ! 917: return (FALSE); ! 918: bitclr(i, ep0->e_b); ! 919: ep1->e_c = i; ! 920: etab[i] = n_ec; ! 921: ep1->e_b = NULL; ! 922: } ! 923: else { ! 924: if (! classcheck(np->n_b, ep0->e_b)) ! 925: return (FALSE); ! 926: ep1->e_b = newbits(FALSE); ! 927: for (i=0; i<NCHARS/NBCHAR; ++i) { ! 928: ep1->e_b[i] = ep0->e_b[i] & np->n_b[i]; ! 929: ep0->e_b[i] &= ~np->n_b[i]; ! 930: } ! 931: for (i=0; i<NCHARS; ++i) ! 932: if (bittst(i, ep1->e_b)) ! 933: etab[i] = n_ec; ! 934: ep1->e_c = 0; ! 935: } ! 936: ! 937: return (TRUE); ! 938: } ! 939: ! 940: ! 941: /* ! 942: * check intersection ! 943: * Specific check for char sets represented as bitmaps. If the ! 944: * intersection of `p' and `q' is a proper subset of `q' return TRUE. ! 945: * Non-modifying nature of this routine is optimized for the "-y" option, ! 946: * where intersections of [Aa] and [Bb] are commonplace. ! 947: */ ! 948: static bool classcheck(p, q) ! 949: register char *p; ! 950: register char *q; ! 951: { ! 952: register i; ! 953: bool k1; ! 954: bool k2; ! 955: ! 956: k1 = FALSE; ! 957: k2 = FALSE; ! 958: ! 959: i = NCHARS / NBCHAR; ! 960: do { ! 961: if (*q & *p) ! 962: k1 = TRUE; ! 963: if (*q++ & ~*p++) ! 964: k2 = TRUE; ! 965: } while (--i); ! 966: ! 967: return (k1 && k2); ! 968: } ! 969: ! 970: ! 971: /* ! 972: * allocate new eclass ! 973: */ ! 974: static struct eclass *neweclass() ! 975: { ! 976: register struct eclass *ep; ! 977: ! 978: ep = malloc(sizeof *ep); ! 979: if (ep == NULL) ! 980: nomem(); ! 981: return (ep); ! 982: } ! 983: ! 984: /* ! 985: ** dfa.c ! 986: */ ! 987: ! 988: ! 989: /* ! 990: * creation of the DFA ! 991: */ ! 992: ! 993: static bmsize; /* size of bitmap `d_b' */ ! 994: static struct dragon d; /* prototype dragon */ ! 995: ! 996: static struct dragon *dragons; /* head of the dragon list */ ! 997: ! 998: struct dragon *member(); ! 999: struct dragon *enter(); ! 1000: ! 1001: ! 1002: /* ! 1003: * create the DFA start state ! 1004: */ ! 1005: struct dragon * ! 1006: initdfa(np) ! 1007: struct newt *np; ! 1008: { ! 1009: ! 1010: if (d.d_s) ! 1011: free((char *)d.d_s); ! 1012: d.d_s = malloc((n_id+1)*sizeof(*d.d_s)); ! 1013: if (d.d_s == NULL) ! 1014: nomem(); ! 1015: d.d_s[0] = np; ! 1016: d.d_s[1] = NULL; ! 1017: bmsize = (n_id+NBCHAR-1) / NBCHAR; ! 1018: if (d.d_b) ! 1019: free((char *)d.d_b); ! 1020: d.d_b = malloc(bmsize); ! 1021: if (d.d_b == NULL) ! 1022: nomem(); ! 1023: dragons = NULL; ! 1024: ++uniq; ! 1025: e_closure(); ! 1026: return (enter(np->n_fp)); ! 1027: } ! 1028: ! 1029: ! 1030: /* ! 1031: * construct the DFA ! 1032: * This task is done incrementally, after searching has started. ! 1033: * The current dragon `dp' needs a transition on the input `ec' given ! 1034: * the NFA `np'. The new dragon is determined, entered into `dp->d_p', ! 1035: * and returned. If the new dragon has never been encountered, it is ! 1036: * remembered. A special case arises if the current dragon is an accept ! 1037: * state: all transitions loop to itself. ! 1038: * Note that `ec' is an equivalence class, not a char. ! 1039: */ ! 1040: struct dragon * ! 1041: makedfa(dp, ec, np) ! 1042: struct dragon *dp; ! 1043: struct newt *np; ! 1044: { ! 1045: register struct eclass *ep; ! 1046: register struct dragon *p; ! 1047: extern struct eclass *eclasses; ! 1048: ! 1049: if (dp->d_success) { ! 1050: dp->d_p[ec] = dp; ! 1051: return (dp); ! 1052: } ! 1053: for (ep=eclasses; ep->e_class!=ec; ep=ep->e_next) ! 1054: ; ! 1055: ++uniq; ! 1056: gettrans(dp, ep); ! 1057: e_closure(); ! 1058: p = member(); ! 1059: if (p == NULL) ! 1060: p = enter(np->n_fp); ! 1061: dp->d_p[ec] = p; ! 1062: return (p); ! 1063: } ! 1064: ! 1065: ! 1066: /* ! 1067: * get transitions ! 1068: * Construct in `d.d_s' the set of newts to which there is a ! 1069: * transition on `ep' from some newt in `dp->d_s'. ! 1070: */ ! 1071: static gettrans(dp, ep) ! 1072: struct dragon *dp; ! 1073: struct eclass *ep; ! 1074: { ! 1075: register struct newt **pp; ! 1076: register struct newt *np; ! 1077: register struct newt *p; ! 1078: struct newt **npp; ! 1079: bool eqtrans(); ! 1080: ! 1081: npp = d.d_s; ! 1082: ! 1083: pp = dp->d_s; ! 1084: while (np = *pp++) ! 1085: if ((p = np->n_cp) ! 1086: && (np->n_c != EPSILON) ! 1087: && (eqtrans(ep, np))) { ! 1088: *npp++ = p; ! 1089: p->n_uniq = uniq; ! 1090: } ! 1091: *npp = NULL; ! 1092: } ! 1093: ! 1094: ! 1095: /* ! 1096: * locate a dragon ! 1097: * The set of newts given by `d.d_s' are sought in the DFA. The ! 1098: * appropriate dragon is returned, else 0. The use of bitmap `d_b' allows ! 1099: * comparing (unsorted) `d_s' sets in time O(N). Hashing of `d_s' and ! 1100: * "self-organizing" the DFA also help to keep things fast. ! 1101: */ ! 1102: static struct dragon *member() ! 1103: { ! 1104: register struct dragon *dp; ! 1105: register char *p; ! 1106: register char *q; ! 1107: int i; ! 1108: ! 1109: dp = dragons; ! 1110: ! 1111: do { ! 1112: if (dp->d_hash == d.d_hash) { ! 1113: p = dp->d_b; ! 1114: q = d.d_b; ! 1115: i = bmsize; do { ! 1116: if (*p++ != *q++) ! 1117: break; ! 1118: } while (--i); ! 1119: if (i == 0) { ! 1120: if (dp == dragons) ! 1121: break; ! 1122: if (dp->d_next) ! 1123: dp->d_next->d_last = dp->d_last; ! 1124: dp->d_last->d_next = dp->d_next; ! 1125: dragons->d_last = dp; ! 1126: dp->d_next = dragons; ! 1127: dp->d_last = NULL; ! 1128: dragons = dp; ! 1129: break; ! 1130: } ! 1131: } ! 1132: } while (dp = dp->d_next); ! 1133: ! 1134: return (dp); ! 1135: } ! 1136: ! 1137: ! 1138: /* ! 1139: * enter the dragon ! 1140: * The prototype dragon `d' is used to create a dragon, which is ! 1141: * entered in the DFA. ! 1142: */ ! 1143: static struct dragon * ! 1144: enter(finalnp) ! 1145: struct newt *finalnp; ! 1146: { ! 1147: register struct dragon *p; ! 1148: register i; ! 1149: ! 1150: p = malloc(sizeof *p); ! 1151: if (p == NULL) ! 1152: nomem(); ! 1153: p->d_success = FALSE; ! 1154: p->d_hash = d.d_hash; ! 1155: for (i=0; d.d_s[i]; ++i) ! 1156: if (d.d_s[i] == finalnp) ! 1157: p->d_success = TRUE; ! 1158: p->d_s = malloc((i+1)*sizeof(*p->d_s)); ! 1159: if (p->d_s == NULL) ! 1160: nomem(); ! 1161: for (i=0; p->d_s[i]=d.d_s[i]; ++i) ! 1162: ; ! 1163: p->d_b = malloc(bmsize); ! 1164: if (p->d_b == NULL) ! 1165: nomem(); ! 1166: for (i=0; i<bmsize; ++i) ! 1167: p->d_b[i] = d.d_b[i]; ! 1168: p->d_p = malloc(n_ec*sizeof(*p->d_p)); ! 1169: if (p->d_p == NULL) ! 1170: nomem(); ! 1171: for (i=0; i<n_ec; ++i) ! 1172: p->d_p[i] = NULL; ! 1173: if (dragons) ! 1174: dragons->d_last = p; ! 1175: p->d_next = dragons; ! 1176: dragons = p; ! 1177: p->d_last = NULL; ! 1178: return (p); ! 1179: } ! 1180: ! 1181: ! 1182: /* ! 1183: * perform epsilon-closure ! 1184: * Epsilon-transition `d.d_s' is computed and the result placed ! 1185: * in `d.d_s'. Ensuring a newt is not already on the list requires ! 1186: * time O(N), thanks to `uniq'. ! 1187: */ ! 1188: static ! 1189: e_closure() ! 1190: { ! 1191: register struct newt **nqq; ! 1192: register struct newt *np; ! 1193: register struct newt *p; ! 1194: struct newt **npp; ! 1195: ! 1196: d.d_hash = 0; ! 1197: for (nqq=d.d_s; *nqq++; ) ! 1198: ; ! 1199: --nqq; ! 1200: ! 1201: for (npp=d.d_s; npp<nqq; ) { ! 1202: np = *npp++; ! 1203: d.d_hash += (int)np; ! 1204: if ((p = np->n_cp) ! 1205: && (np->n_c == EPSILON) ! 1206: && (p->n_uniq != uniq)) { ! 1207: *nqq++ = p; ! 1208: p->n_uniq = uniq; ! 1209: } ! 1210: if ((p = np->n_ep) ! 1211: && (p->n_uniq != uniq)) { ! 1212: *nqq++ = p; ! 1213: p->n_uniq = uniq; ! 1214: } ! 1215: } ! 1216: *nqq = NULL; ! 1217: ! 1218: bmbuild(); ! 1219: } ! 1220: ! 1221: ! 1222: /* ! 1223: * build bitmap ! 1224: * A bitmap of `d.d_s' is built in `d.d_b'. ! 1225: */ ! 1226: static ! 1227: bmbuild() ! 1228: { ! 1229: register struct newt *np; ! 1230: register char *p; ! 1231: register i; ! 1232: ! 1233: p = d.d_b; ! 1234: i = bmsize; do { ! 1235: *p++ = 0; ! 1236: } while (--i); ! 1237: i = 0; ! 1238: while (np = d.d_s[i++]) ! 1239: bitset(np->n_id, d.d_b); ! 1240: } ! 1241: /* ! 1242: ** search.c ! 1243: */ ! 1244: /* ! 1245: * execution of the DFA ! 1246: */ ! 1247: ! 1248: ! 1249: static bool status; /* set TRUE if any matches */ ! 1250: static char cbuf[BUFSIZ]; /* first BUFSIZ chars of input line */ ! 1251: static char *file; /* input file name */ ! 1252: static long nlines; /* input line count */ ! 1253: static long seekpos; /* start of current line in file */ ! 1254: static long matches; /* # matches */ ! 1255: static struct dragon *dfa; /* DFA start state */ ! 1256: static struct newt *nfa; /* NFA */ ! 1257: ! 1258: ! 1259: /* ! 1260: * search a file ! 1261: * Return TRUE if any matches. ! 1262: */ ! 1263: bool ! 1264: search(fn, dp, np) ! 1265: char *fn; ! 1266: struct dragon *dp; ! 1267: struct newt *np; ! 1268: { ! 1269: bool match(); ! 1270: ! 1271: file = fn; ! 1272: dfa = dp; ! 1273: nfa = np; ! 1274: nlines = 0; ! 1275: seekpos = 0; ! 1276: matches = 0; ! 1277: status = FALSE; ! 1278: ! 1279: while (match()) ! 1280: ; ! 1281: ! 1282: if (! sflag && ! lflag && cflag) { ! 1283: printfile(); ! 1284: printf("%ld\n", matches); ! 1285: } ! 1286: return (status); ! 1287: } ! 1288: ! 1289: ! 1290: /* ! 1291: * look for a match ! 1292: */ ! 1293: bool ! 1294: match() ! 1295: { ! 1296: register struct dragon *dp; ! 1297: register c; ! 1298: register char *p; ! 1299: long nchars; ! 1300: struct dragon *dp2; ! 1301: extern char etab[]; ! 1302: bool success(); ! 1303: ! 1304: if ((dp=dfa->d_p[etab['\n']]) == NULL) ! 1305: dp = makedfa(dfa, etab['\n'], nfa); ! 1306: nchars = 0; ! 1307: p = cbuf; ! 1308: ! 1309: while ((c=getc(ifp)) != EOF) { ! 1310: ++nchars; ! 1311: c &= 0177; ! 1312: if (p < &cbuf[BUFSIZ]) ! 1313: *p++ = c; ! 1314: dp2 = dp; ! 1315: if ((dp=dp->d_p[etab[c]]) == NULL) ! 1316: dp = makedfa(dp2, etab[c], nfa); ! 1317: if (c == '\n') { ! 1318: ++nlines; ! 1319: if (vflag!=dp->d_success && ! success(file, p)) ! 1320: break; ! 1321: seekpos += nchars; ! 1322: if (dp->d_success) ! 1323: return (TRUE); ! 1324: nchars = 0; ! 1325: p = cbuf; ! 1326: } ! 1327: } ! 1328: ! 1329: return (FALSE); ! 1330: } ! 1331: ! 1332: ! 1333: /* ! 1334: * report a match ! 1335: * If the line is to be printed, and it is over BUFSIZ chars, the ! 1336: * input file better be seekable. ! 1337: */ ! 1338: bool ! 1339: success(file, p) ! 1340: char *file; ! 1341: char *p; ! 1342: { ! 1343: extern char *tempnam(); ! 1344: register char *q; ! 1345: register c; ! 1346: register n; ! 1347: ! 1348: ++matches; ! 1349: status = TRUE; ! 1350: if (sflag) ! 1351: return (FALSE); ! 1352: if (lflag) { ! 1353: printf("%s\n", file); ! 1354: return (FALSE); ! 1355: } ! 1356: if (aflag) { ! 1357: if ((NULL == tmpFn) && ! 1358: ((NULL == (tmpFn = tempnam(NULL, "egr"))) || ! 1359: (NULL == (tmpFile = fopen(tmpFn, "w"))))) { ! 1360: fprintf(stderr, "egrep: cant open tmp file"); ! 1361: exit(1); ! 1362: } ! 1363: fprintf(tmpFile, "%ld:%s: egrep\n", nlines, file); ! 1364: return (TRUE); ! 1365: } ! 1366: if (cflag) ! 1367: return (TRUE); ! 1368: printfile(); ! 1369: if (nflag) ! 1370: printf("%ld:", nlines); ! 1371: if (bflag) ! 1372: printf("%ld:", seekpos/BUFSIZ); ! 1373: q = cbuf; ! 1374: n = p - q; ! 1375: while (q < p) ! 1376: putchar(*q++); ! 1377: if (*--q != '\n') { ! 1378: if (fseek(ifp, seekpos+n, 0) == EOF) { ! 1379: putchar('\n'); ! 1380: fatal("line too long"); ! 1381: } ! 1382: do { ! 1383: c = getc(ifp); ! 1384: if (c == EOF) ! 1385: return (FALSE); ! 1386: putchar(c); ! 1387: } while (c != '\n'); ! 1388: } ! 1389: return (TRUE); ! 1390: } ! 1391: ! 1392: ! 1393: static ! 1394: printfile() ! 1395: { ! 1396: ! 1397: if (! hflag) ! 1398: printf("%s:", file); ! 1399: } ! 1400: ! 1401: /* ! 1402: ** bits.c ! 1403: */ ! 1404: ! 1405: ! 1406: /* ! 1407: * allocate bitmap for character class ! 1408: * If `setbits'==TRUE then the map is initialized to ones, else zeros. ! 1409: */ ! 1410: char * ! 1411: newbits(setbits) ! 1412: bool setbits; ! 1413: { ! 1414: register i; ! 1415: register c; ! 1416: register char *p; ! 1417: register char *q; ! 1418: ! 1419: p = malloc(NCHARS/NBCHAR); ! 1420: if (p == NULL) ! 1421: nomem(); ! 1422: c = 0; ! 1423: if (setbits) ! 1424: c = ~0; ! 1425: q = p; ! 1426: i = NCHARS / NBCHAR; ! 1427: do { ! 1428: *p++ = c; ! 1429: } while (--i); ! 1430: return (q); ! 1431: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.