Annotation of 43BSDTahoe/ucb/grep/egrep.c, revision 1.1

1.1     ! root        1: #ifndef lint
        !             2: static char sccsid[] = "@(#)egrep.c    5.10 (Berkeley) 6/30/88";
        !             3: #endif not lint
        !             4: 
        !             5: /*
        !             6:      Hybrid Boyer/Moore/Gosper-assisted 'grep/egrep/fgrep' search, with delta0
        !             7:      table as in original paper (CACM, October, 1977).  No delta1 or delta2.
        !             8:      According to experiment (Horspool, Soft. Prac. Exp., 1982), delta2 is of
        !             9:      minimal practical value.  However, to improve for worst case input,
        !            10:      integrating the improved Galil strategies (Apostolico/Giancarlo, SIAM. J.
        !            11:      Comput., Feb. 1986) deserves consideration.
        !            12: 
        !            13:      Method:   extract longest metacharacter-free string from expression.
        !            14:                this is done using a side-effect from henry spencer's regcomp().
        !            15:                use boyer-moore to match such, then pass submatching lines
        !            16:                to either regexp() or standard 'egrep', depending on certain
        !            17:                criteria within execstrategy() below.  [this tradeoff is due
        !            18:                to the general slowness of the regexp() nondeterministic
        !            19:                machine on complex expressions, as well as the startup time
        !            20:                of standard 'egrep' on short files.]  alternatively, one may
        !            21:                change the vendor-supplied 'egrep' automaton to include
        !            22:                boyer-moore directly.  see accompanying writeup for discussion
        !            23:                of kanji expression treatment.
        !            24: 
        !            25:                late addition:  apply trickbag for fast match of simple
        !            26:                alternations (sublinear, in common low-cardinality cases).
        !            27:                trap fgrep into this lair.
        !            28: 
        !            29:                gnu additions:  -f, newline as |, \< and \> [in regexec()], more
        !            30:                                comments.  inspire better dfa exec() strategy.
        !            31:                                serious testing and help with special cases.
        !            32: 
        !            33:      Algorithm amalgam summary:
        !            34: 
        !            35:                dfa e?grep              (aho/thompson)
        !            36:                ndfa regexp()           (spencer/aho)
        !            37:                bmg                     (boyer/moore/gosper)
        !            38:                "superimposed" bmg      (jaw)
        !            39:                fgrep                   (aho/corrasick)
        !            40: 
        !            41:                sorry, but the knuth/morris/pratt machine, horspool's
        !            42:                "frequentist" code, and the rabin/karp matcher, however cute,
        !            43:                just don't cut it for this production.
        !            44: 
        !            45:      James A. Woods                            Copyright (c) 1986
        !            46:      NASA Ames Research Center
        !            47: */
        !            48: #include <stdio.h>
        !            49: #include <ctype.h>
        !            50: #include <sys/types.h>
        !            51: #include <sys/stat.h>
        !            52: #include <sys/file.h>
        !            53: #include <regexp.h>            /* must be henry spencer's version */
        !            54: 
        !            55: #define        MIN(A, B)       ((A) > (B) ? (B) : (A))
        !            56: 
        !            57: #ifdef SLOWSYS
        !            58: #define read   xread
        !            59: #endif
        !            60: /*
        !            61:  * define existing [ef]?grep program locations below for use by execvp().
        !            62:  * [execlp() would be used were it not for the possibility of
        !            63:  * installation-dependent recursion.] 
        !            64:  */
        !            65: #ifndef EGREPSTD
        !            66: #define        EGREPSTD        "/usr/bin/egrep"
        !            67: #endif
        !            68: #ifndef GREPSTD
        !            69: #define        GREPSTD         "/bin/grep"
        !            70: #endif
        !            71: #ifndef FGREPSTD
        !            72: #define        FGREPSTD        "/usr/bin/fgrep"
        !            73: #endif
        !            74: 
        !            75: #define BUFSIZE        8192            /* make higher for cray */
        !            76: #define PATSIZE 6000
        !            77: #define LARGE  BUFSIZE + PATSIZE
        !            78: 
        !            79: #define NALT   7               /* tied to scanf() size in alternate() */
        !            80: #define NMUSH  6               /* loosely relates to expected alt length */
        !            81: 
        !            82: #define        FIRSTFEW        33      /* Always do FIRSTFEW matches with regexec() */
        !            83: #define        PUNTPERCENT     10      /* After FIRSTFEW, if PUNTPERCENT of the input
        !            84:                                 * was processed by regexp(), exec std egrep. */
        !            85: #define NL     '\n'
        !            86: #define        EOS     '\0'
        !            87: #define        NONASCII        0200    /* Bit mask for Kanji non-ascii chars */
        !            88: #define META   "\n^$.[]()?+*|\\"       /* egrep meta-characters */
        !            89: #define SS2    '\216'          /* EUC Katakana (or Chinese2) prefix */
        !            90: #define SS3    '\217'          /* EUC Kanji2 (or Chinese3) prefix */
        !            91: 
        !            92: extern char *optarg;
        !            93: extern int optind;
        !            94: char *progname;
        !            95: 
        !            96: int cflag, iflag, eflag, fflag, lflag, nflag;  /* SVID flags */
        !            97: int sflag, hflag;              /* v7, v8, bsd */
        !            98: 
        !            99: int firstflag;                 /* Stop at first match */
        !           100: int grepflag;                  /* Called as "grep" */
        !           101: int fgrepflag;                 /* Called as "fgrep" */
        !           102: int altflag;                   /* Simple alternation in pattern */
        !           103: int boyonly;                   /* No regexp needed -- all simple */
        !           104: int flushflag;
        !           105: int grepold, egrepold, fgrepold;
        !           106: 
        !           107: int nalt;                      /* Number of alternatives */
        !           108: int nsuccess;                  /* 1 for match, 2 for error */
        !           109: int altmin;                    /* Minimum length of all the alternate
        !           110:                                 * strings */
        !           111: int firstfile;                 /* argv index of first file argument */
        !           112: int patind;                    /* argv index of pattern */
        !           113: long nmatch;                   /* Number of matches in this file */
        !           114: long incount, counted;         /* Amount of input consumed */
        !           115: long rxcount;                  /* Bytes of input processed by regexec() */
        !           116: int boyfound;                  /* accumulated partial matches (tripped by
        !           117:                                 * FIRSTFEW) */
        !           118: int prevmatch;                 /* next three lines aid fast -n */
        !           119: long nline, prevnline;
        !           120: char *prevloc;
        !           121: 
        !           122: regexp *rspencer;
        !           123: char *pattern;
        !           124: char *patboy;                  /* Pattern for simple Boyer-Moore */
        !           125: char *patfile;                 /* Filename containing pattern(s) */
        !           126: 
        !           127: int delta0[256];               /* Boyer-Moore algorithm core */
        !           128: char cmap[256];                        /* Usually 0-255, but if -i, maps upper to
        !           129:                                 * lower case */
        !           130: char str[BUFSIZE + 2];
        !           131: int nleftover;
        !           132: char linetemp[BUFSIZE];
        !           133: char *altpat[NALT];            /* alternation component storage */
        !           134: int altlen[NALT];
        !           135: short altset[NMUSH + 1][256];
        !           136: char preamble[200];            /* match prefix (filename, line no.) */
        !           137: 
        !           138: int fd;
        !           139: char *
        !           140: strchr(), *strrchr(), *strcpy(), *strncpy(), *strpbrk(), *malloc();
        !           141: char *
        !           142: grepxlat(), *fold(), *pfile(), *alternate(), *isolate();
        !           143: char **args;
        !           144: 
        !           145: main(argc, argv)
        !           146:        int argc;
        !           147:        char *argv[];
        !           148: {
        !           149:        int c, oflag;
        !           150:        int errflag = 0;
        !           151: 
        !           152:        args = argv;
        !           153: 
        !           154:        if ((progname = strrchr(argv[0], '/')) != 0)
        !           155:                progname++;
        !           156:        else
        !           157:                progname = argv[0];
        !           158:        if (strcmp(progname, "grep") == 0)
        !           159:                grepflag++;
        !           160:        else if (strcmp(progname, "fgrep") == 0)
        !           161:                fgrepflag++;
        !           162: 
        !           163:        oflag = 0;
        !           164:        while ((c = getopt(argc, argv, "bchie:f:lnosvwxy1")) != EOF) {
        !           165:                switch (c) {
        !           166: 
        !           167:                case 'f':
        !           168:                        fflag++;
        !           169:                        patfile = optarg;
        !           170:                        continue;
        !           171:                case 'b':
        !           172:                case 'v':
        !           173:                        egrepold++;     /* boyer-moore of little help here */
        !           174:                        continue;
        !           175:                case 'c':
        !           176:                        cflag++;
        !           177:                        continue;
        !           178:                case 'e':
        !           179:                        eflag++;
        !           180:                        pattern = optarg;
        !           181:                        continue;
        !           182:                case 'h':
        !           183:                        hflag++;
        !           184:                        continue;
        !           185:                case 'o':
        !           186:                        oflag++;
        !           187:                        continue;
        !           188:                case '1':       /* Stop at very first match */
        !           189:                        firstflag++;    /* spead freaks only */
        !           190:                        continue;
        !           191:                case 'i':
        !           192:                        iflag++;
        !           193:                        continue;
        !           194:                case 'l':
        !           195:                        lflag++;
        !           196:                        continue;
        !           197:                case 'n':
        !           198:                        nflag++;
        !           199:                        continue;
        !           200:                case 's':
        !           201:                        sflag++;
        !           202:                        continue;
        !           203:                case 'w':
        !           204:                case 'y':
        !           205:                        if (!grepflag)
        !           206:                                errflag++;
        !           207:                        grepold++;
        !           208:                        continue;
        !           209:                case 'x':       /* needs more work, like -b above */
        !           210:                        if (!fgrepflag)
        !           211:                                errflag++;
        !           212:                        fgrepold++;
        !           213:                        continue;
        !           214:                case '?':
        !           215:                        errflag++;
        !           216:                }
        !           217:        }
        !           218:        if (errflag || ((argc <= optind) && !fflag && !eflag)) {
        !           219:                if (grepflag)
        !           220: oops("usage: grep [-bchilnosvwy] [-e] pattern [file ...]");
        !           221:                else if (fgrepflag)
        !           222: oops("usage: fgrep [-bchilnosvx] {-f patfile | [-e] strings} [file ...]");
        !           223:                else            /* encourage SVID options, though we provide
        !           224:                                 * others */
        !           225: oops("usage: egrep [-bchilnosv] {-f patfile | [-e] pattern} [file ...]");
        !           226:        }
        !           227:        if (fflag)
        !           228:                pattern = pfile(patfile);
        !           229:        else if (!eflag) {
        !           230:                patind = optind;
        !           231:                pattern = argv[optind++];
        !           232:        }
        !           233: 
        !           234:        if (!oflag && (argc - optind) <= 1)     /* Filename invisible given < 2 files */
        !           235:                hflag++;
        !           236:        if (pattern[0] == EOS)
        !           237:                kernighan(argv);        /* same as it ever was */
        !           238:        /*
        !           239:         * 'grep/egrep' merger -- "old" grep is called to handle: tagged
        !           240:         * exprs \( \), word matches \< and \>, -w and -y options, char
        !           241:         * classes with '-' at end (egrep bug?), and patterns beginning with
        !           242:         * an asterisk (don't ask why). otherwise, characters meaningful to
        !           243:         * 'egrep' but not to 'grep' are escaped; the entire expr is then
        !           244:         * passed to 'egrep'. 
        !           245:         */
        !           246:        if (grepflag && !grepold) {
        !           247:                if (strindex(pattern, "\\(") >= 0 ||
        !           248:                    strindex(pattern, "\\<") >= 0 ||
        !           249:                    strindex(pattern, "\\>") >= 0 ||
        !           250:                    strindex(pattern, "-]") >= 0 ||
        !           251:                    pattern[0] == '*')  /* grep bug */
        !           252:                        grepold++;
        !           253:                else
        !           254:                        pattern = grepxlat(pattern);
        !           255:        }
        !           256:        if (grepold || egrepold || fgrepold)
        !           257:                kernighan(argv);
        !           258: 
        !           259:        if (iflag)
        !           260:                strcpy(pattern, fold(pattern));
        !           261:        /*
        !           262:         * If the pattern is a plain string, just run boyer-moore. If it
        !           263:         * consists of meta-free alternatives, run "superimposed" bmg.
        !           264:         * Otherwise, find best string, and compile pattern for regexec(). 
        !           265:         */
        !           266:        if (strpbrk(pattern, META) == NULL) {   /* do boyer-moore only */
        !           267:                boyonly++;
        !           268:                patboy = pattern;
        !           269:        } else {
        !           270:                if ((patboy = alternate(pattern)) != NULL)
        !           271:                        boyonly++;
        !           272:                else {
        !           273:                        if ((patboy = isolate(pattern)) == NULL)
        !           274:                                kernighan(argv);        /* expr too involved */
        !           275: #ifndef NOKANJI
        !           276:                        for (c = 0; pattern[c] != EOS; c++)
        !           277:                                if (pattern[c] & NONASCII)      /* kanji + meta */
        !           278:                                        kernighan(argv);
        !           279: #endif
        !           280:                        if ((rspencer = regcomp(pattern)) == NULL)
        !           281:                                oops("regcomp failure");
        !           282:                }
        !           283:        }
        !           284:        gosper(patboy);         /* "pre-conditioning is wonderful"
        !           285:                                 * -- v. strassen */
        !           286: 
        !           287:        if ((firstfile = optind) >= argc) {
        !           288:                /* Grep standard input */
        !           289:                if (lflag)      /* We don't know its name! */
        !           290:                        exit(1);
        !           291:                egsecute((char *) NULL);
        !           292:        } else {
        !           293:                while (optind < argc) {
        !           294:                        egsecute(argv[optind]);
        !           295:                        optind++;
        !           296:                        if (firstflag && (nsuccess == 1))
        !           297:                                break;
        !           298:                }
        !           299:        }
        !           300:        exit((nsuccess == 2) ? 2 : (nsuccess == 0));
        !           301: }
        !           302: 
        !           303: char *
        !           304: pfile(pfname)                  /* absorb expression from file */
        !           305:        char *pfname;
        !           306: {
        !           307:        int fd;
        !           308:        struct stat patstat;
        !           309:        static char *pat;
        !           310: 
        !           311:        if ((fd = open(pfname, O_RDONLY, 0)) < 0)
        !           312:                oops("can't read pattern file");
        !           313:        if (fstat(fd, &patstat) != 0)
        !           314:                oops("can't stat pattern file");
        !           315:        if (patstat.st_size > PATSIZE) {
        !           316:                if (fgrepflag) {        /* defer to unix version */
        !           317:                        fgrepold++;
        !           318:                        return "dummy";
        !           319:                } else
        !           320:                        oops("pattern file too big");
        !           321:        }
        !           322:        if ((pat = malloc((unsigned) patstat.st_size + 1)) == NULL)
        !           323:                oops("out of memory to read pattern file");
        !           324:        if (patstat.st_size != read(fd, pat, (int)patstat.st_size))
        !           325:                oops("error reading pattern file");
        !           326:        (void) close(fd);
        !           327: 
        !           328:        pat[patstat.st_size] = EOS;
        !           329:        if (pat[patstat.st_size - 1] == NL)     /* NOP for egrep; helps grep */
        !           330:                pat[patstat.st_size - 1] = EOS;
        !           331: 
        !           332:        if (nlcount(pat, &pat[patstat.st_size]) > NALT) {
        !           333:                if (fgrepflag)
        !           334:                        fgrepold++;     /* "what's it all about, alfie?" */
        !           335:                else
        !           336:                        egrepold++;
        !           337:        }
        !           338:        return (pat);
        !           339: }
        !           340: 
        !           341: egsecute(file)
        !           342:        char *file;
        !           343: {
        !           344:        if (file == NULL)
        !           345:                fd = 0;
        !           346:        else if ((fd = open(file, O_RDONLY, 0)) <= 0) {
        !           347:                fprintf(stderr, "%s: can't open %s\n", progname, file);
        !           348:                nsuccess = 2;
        !           349:                return;
        !           350:        }
        !           351:        chimaera(file, patboy);
        !           352: 
        !           353:        if (!boyonly && !flushflag && file != NULL)
        !           354:                flushmatches();
        !           355:        if (file != NULL)
        !           356:                close(fd);
        !           357: }
        !           358: 
        !           359: chimaera(file, pat)            /* "reach out and boyer-moore search someone" */
        !           360:        char *file, *pat;       /* -- soon-to-be-popular bumper sticker */
        !           361: {
        !           362:        register char *k, *strend, *s;
        !           363:        register int j, count;
        !           364:        register int *deltazero = delta0;
        !           365:        int patlen = altmin;
        !           366:        char *t;
        !           367:        char *gotamatch(), *kanji(), *linesave(), *submatch();
        !           368: 
        !           369:        nleftover = boyfound = flushflag = 0;
        !           370:        nline = 1L;
        !           371:        prevmatch = 0;
        !           372:        nmatch = counted = rxcount = 0L;
        !           373: 
        !           374:        while ((count = read(fd, str + nleftover, BUFSIZE - nleftover)) > 0) {
        !           375: 
        !           376:                counted += count;
        !           377:                strend = linesave(str, count);
        !           378: 
        !           379:                for (k = str + patlen - 1; k < strend;) {
        !           380:                        /*
        !           381:                         * for a large class of patterns, upwards of 80% of
        !           382:                         * match time is spent on the next line.  we beat
        !           383:                         * existing microcode (vax 'matchc') this way. 
        !           384:                         */
        !           385:                        while ((k += deltazero[*(unsigned char *) k]) < strend);
        !           386:                        if (k < (str + LARGE))
        !           387:                                break;
        !           388:                        k -= LARGE;
        !           389: 
        !           390:                        if (altflag) {
        !           391:                                /*
        !           392:                                 * Parallel Boyer-Moore.  Check whether each
        !           393:                                 * of the previous <altmin> chars COULD be
        !           394:                                 * from one of the alternative strings. 
        !           395:                                 */
        !           396:                                s = k - 1;
        !           397:                                j = altmin;
        !           398:                                while (altset[--j][(unsigned char)
        !           399:                                             cmap[*(unsigned char *) s--]]);
        !           400:                                /*
        !           401:                                 * quick test fails. in this life, compare
        !           402:                                 * 'em all.  but, a "reverse trie" would
        !           403:                                 * attenuate worst case (linear w/delta2?). 
        !           404:                                 */
        !           405:                                if (--j < 0) {
        !           406:                                        count = nalt - 1;
        !           407:                                        do {
        !           408:                                                s = k;
        !           409:                                                j = altlen[count];
        !           410:                                                t = altpat[count];
        !           411: 
        !           412:                                                while
        !           413:                                                        (cmap[*(unsigned char *) s--]
        !           414:                                                         == t[--j]);
        !           415:                                                if (j < 0)
        !           416:                                                        break;
        !           417:                                        }
        !           418:                                        while (count--);
        !           419:                                }
        !           420:                        } else {
        !           421:                                /* One string -- check it */
        !           422:                                j = patlen - 1;
        !           423:                                s = k - 1;
        !           424:                                while (cmap[*(unsigned char *) s--] == pat[--j]);
        !           425:                        }
        !           426:                        /*
        !           427:                         * delta-less shortcut for literati. short shrift for
        !           428:                         * genetic engineers? 
        !           429:                         */
        !           430:                        if (j >= 0) {
        !           431:                                k++;    /* no match; restart next char */
        !           432:                                continue;
        !           433:                        }
        !           434:                        k = submatch(file, pat, str, strend, k, count);
        !           435:                        if (k == NULL)
        !           436:                                return;
        !           437:                }
        !           438:                if (nflag) {
        !           439:                        if (prevmatch)
        !           440:                                nline = prevnline + nlcount(prevloc, k);
        !           441:                        else
        !           442:                                nline = nline + nlcount(str, k);
        !           443:                        prevmatch = 0;
        !           444:                }
        !           445:                strncpy(str, linetemp, nleftover);
        !           446:        }
        !           447:        if (cflag) {
        !           448:                /* Bug from old grep: -c overrides -h.  We fix the bug. */
        !           449:                if (!hflag)
        !           450:                        printf("%s:", file);
        !           451:                printf("%ld\n", nmatch);
        !           452:        }
        !           453: }
        !           454: 
        !           455: char *
        !           456: linesave(str, count)           /* accumulate partial line at end of buffer */
        !           457:        char str[];
        !           458:        register int count;
        !           459: {
        !           460:        register int j;
        !           461: 
        !           462:        count += nleftover;
        !           463:        if (count != BUFSIZE && fd != 0)
        !           464:                str[count++] = NL;      /* insurance for broken last line */
        !           465:        str[count] = EOS;
        !           466:        for (j = count - 1; str[j] != NL && j >= 0;)
        !           467:                j--;
        !           468:        /*
        !           469:         * break up these lines: long line (> BUFSIZE), last line of file, or
        !           470:         * short return from read(), as from tee(1) input 
        !           471:         */
        !           472:        if (j < 0 && (count == (BUFSIZE - nleftover))) {
        !           473:                str[count++] = NL;
        !           474:                str[count] = EOS;
        !           475:                linetemp[0] = EOS;
        !           476:                nleftover = 0;
        !           477:                return (str + count);
        !           478:        } else {
        !           479:                nleftover = count - j - 1;
        !           480:                strncpy(linetemp, str + j + 1, nleftover);
        !           481:                return (str + j);
        !           482:        }
        !           483: }
        !           484: 
        !           485: /*
        !           486:  * Process partial match. First check for mis-aligned Kanji, then match line
        !           487:  * against full compiled r.e. if statistics do not warrant handing off to
        !           488:  * standard egrep. 
        !           489:  */
        !           490: char *
        !           491: submatch(file, pat, str, strend, k, altindex)
        !           492:        char file[], pat[], str[];
        !           493:        register char *strend, *k;
        !           494:        int altindex;
        !           495: {
        !           496:        register char *s;
        !           497:        char *t, c;
        !           498: 
        !           499:        t = k;
        !           500:        s = ((altflag) ? k - altlen[altindex] + 1 : k - altmin + 1);
        !           501: #ifndef NOKANJI
        !           502:        c = ((altflag) ? altpat[altindex][0] : pat[0]);
        !           503:        if (c & NONASCII)
        !           504:                if ((s = kanji(str, s, k)) == NULL)
        !           505:                        return (++k);   /* reject false kanji */
        !           506: #endif
        !           507:        do;
        !           508:        while (*s != NL && --s >= str);
        !           509:        k = s + 1;              /* now at line start */
        !           510: 
        !           511:        if (boyonly)
        !           512:                return (gotamatch(file, k));
        !           513: 
        !           514:        incount = counted - (strend - k);
        !           515:        if (boyfound++ == FIRSTFEW)
        !           516:                execstrategy(file);
        !           517: 
        !           518:        s = t;
        !           519:        do
        !           520:                rxcount++;
        !           521:        while (*s++ != NL);
        !           522:        *--s = EOS;
        !           523:        /*
        !           524:         * "quick henry -- the flit" (after theodor geisel) 
        !           525:         */
        !           526:        if (regexec(rspencer, ((iflag) ? fold(k) : k)) == 1) {
        !           527:                *s = NL;
        !           528:                if (gotamatch(file, k) == NULL)
        !           529:                        return (NULL);
        !           530:        }
        !           531:        *s = NL;
        !           532:        return (s + 1);
        !           533: }
        !           534: 
        !           535: #ifndef NOKANJI
        !           536: /*
        !           537:  * EUC code disambiguation -- scan backwards to first 7-bit code, while
        !           538:  * counting intervening 8-bit codes.  If odd, reject unaligned Kanji pattern. 
        !           539:  * SS2/3 checks are for intermixed Japanase Katakana or Kanji2. 
        !           540:  */
        !           541: char *
        !           542: kanji(str, s, k)
        !           543:        register char *str, *s, *k;
        !           544: {
        !           545:        register int j = 0;
        !           546: 
        !           547:        for (s--; s >= str; s--) {
        !           548:                if (*s == SS2 || *s == SS3 || (*s & NONASCII) == 0)
        !           549:                        break;
        !           550:                j++;
        !           551:        }
        !           552: #ifndef CHINESE
        !           553:        if (*s == SS2)
        !           554:                j -= 1;
        !           555: #endif  CHINESE
        !           556:        return ((j & 01) ? NULL : k);
        !           557: }
        !           558: #endif
        !           559: 
        !           560: /*
        !           561:  * Compute "Boyer-Moore" delta table -- put skip distance in delta0[c] 
        !           562:  */
        !           563: gosper(pattern)
        !           564:        char *pattern;          /* ... HAKMEM lives ... */
        !           565: {
        !           566:        register int i, j;
        !           567:        unsigned char c;
        !           568: 
        !           569:        /* Make one-string case look like simple alternatives case */
        !           570:        if (!altflag) {
        !           571:                nalt = 1;
        !           572:                altmin = altlen[0] = strlen(pattern);
        !           573:                altpat[0] = pattern;
        !           574:        }
        !           575:        /* For chars that aren't in any string, skip by string length. */
        !           576:        for (j = 0; j < 256; j++) {
        !           577:                delta0[j] = altmin;
        !           578:                cmap[j] = j;    /* Sneak in initialization of cmap */
        !           579:        }
        !           580: 
        !           581:        /* For chars in a string, skip distance from char to end of string. */
        !           582:        /* (If char appears more than once, skip minimum distance.) */
        !           583:        for (i = 0; i < nalt; i++)
        !           584:                for (j = 0; j < altlen[i] - 1; j++) {
        !           585:                        c = altpat[i][j];
        !           586:                        delta0[c] = MIN(delta0[c], altlen[i] - j - 1);
        !           587:                        if (iflag && islower((int) c))
        !           588:                                delta0[toupper((int) c)] = delta0[c];
        !           589:                }
        !           590: 
        !           591:        /* For last char of each string, fall out of search loop. */
        !           592:        for (i = 0; i < nalt; i++) {
        !           593:                c = altpat[i][altlen[i] - 1];
        !           594:                delta0[c] = LARGE;
        !           595:                if (iflag && islower((int) c))
        !           596:                        delta0[toupper((int) c)] = LARGE;
        !           597:        }
        !           598:        if (iflag)
        !           599:                for (j = 'A'; j <= 'Z'; j++)
        !           600:                        cmap[j] = tolower((int) j);
        !           601: }
        !           602: 
        !           603: /*
        !           604:  * Print, count, or stop on full match. Result is either the location for
        !           605:  * continued search, or NULL to stop. 
        !           606:  */
        !           607: char *
        !           608: gotamatch(file, s)
        !           609:        register char *file, *s;
        !           610: {
        !           611:        char *savematch();
        !           612:        int squirrel = 0;       /* nonzero to squirrel away FIRSTFEW matches */
        !           613: 
        !           614:        nmatch++;
        !           615:        nsuccess = 1;
        !           616:        if (!boyonly && boyfound <= FIRSTFEW && file != NULL)
        !           617:                squirrel = 1;
        !           618: 
        !           619:        if (sflag)
        !           620:                return (NULL);  /* -s usurps all flags (unlike some versions) */
        !           621:        if (cflag) {            /* -c overrides -l, we guess */
        !           622:                do;
        !           623:                while (*s++ != NL);
        !           624:        } else if (lflag) {
        !           625:                puts(file);
        !           626:                return (NULL);
        !           627:        } else {
        !           628:                if (!hflag)
        !           629:                        if (!squirrel)
        !           630:                                printf("%s:", file);
        !           631:                        else
        !           632:                                (void)sprintf(preamble, "%s:", file);
        !           633:                if (nflag) {
        !           634:                        if (prevmatch)
        !           635:                                prevnline = prevnline + nlcount(prevloc, s);
        !           636:                        else
        !           637:                                prevnline = nline + nlcount(str, s);
        !           638:                        prevmatch = 1;
        !           639: 
        !           640:                        if (!squirrel)
        !           641:                                printf("%ld:", prevnline);
        !           642:                        else
        !           643:                                (void)sprintf(preamble + strlen(preamble),
        !           644:                                        "%ld:", prevnline);
        !           645:                }
        !           646:                if (!squirrel) {
        !           647:                        do
        !           648:                                putchar(*s);
        !           649:                        while (*s++ != NL);
        !           650:                } else
        !           651:                        s = savematch(s);
        !           652: 
        !           653:                if (nflag)
        !           654:                        prevloc = s - 1;
        !           655:        }
        !           656:        return ((firstflag && !cflag) ? NULL : s);
        !           657: }
        !           658: 
        !           659: char *
        !           660: fold(line)
        !           661:        char *line;
        !           662: {
        !           663:        static char fline[BUFSIZE];
        !           664:        register char *s, *t = fline;
        !           665: 
        !           666:        for (s = line; *s != EOS; s++)
        !           667:                *t++ = (isupper((int) *s) ? (char) tolower((int) *s) : *s);
        !           668:        *t = EOS;
        !           669:        return (fline);
        !           670: }
        !           671: 
        !           672: strindex(s, t)                 /* the easy way, as in K&P, p. 192 */
        !           673:        char *s, *t;
        !           674: {
        !           675:        int i, n;
        !           676: 
        !           677:        n = strlen(t);
        !           678:        for (i = 0; s[i] != '\0'; i++)
        !           679:                if (strncmp(s + i, t, n) == 0)
        !           680:                        return (i);
        !           681:        return (-1);
        !           682: }
        !           683: 
        !           684: char *
        !           685: grepxlat(pattern)              /* grep pattern meta conversion */
        !           686:        char *pattern;
        !           687: {
        !           688:        register char *p, *s;
        !           689:        static char newpat[BUFSIZE];
        !           690: 
        !           691:        for (s = newpat, p = pattern; *p != EOS;) {
        !           692:                if (*p == '\\') {       /* skip escapes ... */
        !           693:                        *s++ = *p++;
        !           694:                        if (*p)
        !           695:                                *s++ = *p++;
        !           696:                } else if (*p == '[') { /* ... and char classes */
        !           697:                        while (*p != EOS && *p != ']')
        !           698:                                *s++ = *p++;
        !           699:                } else if (strchr("+?|()", *p) != NULL) {
        !           700:                        *s++ = '\\';    /* insert protection */
        !           701:                        *s++ = *p++;
        !           702:                } else
        !           703:                        *s++ = *p++;
        !           704:        }
        !           705:        *s = EOS;
        !           706:        grepflag = ((patind) ? 0 : 1);
        !           707:        return (newpat);
        !           708: }
        !           709: 
        !           710: /*
        !           711:  * Test for simple alternation.  Result is NULL if it's not so simple, or is
        !           712:  * a pointer to the first string if it is. Warning:  sscanf size is a
        !           713:  * fixpoint, beyond which the speedup linearity starts to break down.  In the
        !           714:  * wake of the elegant aho/corrasick "trie"-based fgrep, generalizing
        !           715:  * altpat[] to arbitrary size is not useful. 
        !           716:  */
        !           717: char *
        !           718: alternate(regexpr)
        !           719:        char *regexpr;
        !           720: {
        !           721:        register int i, j;
        !           722:        register char *start, *stop;
        !           723:        unsigned char c;
        !           724: 
        !           725:        if (fgrepflag && strchr(regexpr, '|'))
        !           726:                        return (NULL);
        !           727: 
        !           728:        /*
        !           729:         * break pattern up into altpat array; delimit on newline, bar,
        !           730:         * or EOS.  We know we won't overflow, we've already checked the
        !           731:         * number of patterns we're going to find against NALT.
        !           732:         * Also, set length of pattern and find minimum pattern length.
        !           733:         */
        !           734:        nalt = 0;
        !           735:        altmin = NMUSH;
        !           736:        for (start = stop = regexpr;; ++stop)
        !           737:                if (!*stop || *stop == '|' || *stop == NL) {
        !           738:                        altlen[nalt] = j = stop - start;
        !           739:                        if (j < altmin)
        !           740:                                altmin = j;
        !           741:                        if (!(altpat[nalt] = malloc((u_int)(j + 1))))
        !           742:                                oops("out of memory");
        !           743:                        bcopy(start, altpat[nalt], j);
        !           744:                        altpat[nalt][j] = EOS;
        !           745:                        ++nalt;
        !           746:                        if (!*stop)
        !           747:                                break;
        !           748:                        if (nalt == NALT)
        !           749:                                return(NULL);
        !           750:                        if (*stop == NL)
        !           751:                                *stop = '|';
        !           752:                        start = stop + 1;
        !           753:                }
        !           754:        if (!fgrepflag) {
        !           755:                if (strchr(regexpr, '|') == NULL || regexpr[0] == '|')
        !           756:                        return (NULL);
        !           757:                if (strpbrk(regexpr, "^$.[]()?+*\\") != NULL
        !           758:                    || strindex(regexpr, "||") >= 0)
        !           759:                        return (NULL);
        !           760:        }
        !           761: 
        !           762:        if (nalt > 1) {         /* build superimposed "pre-match" sets per
        !           763:                                 * char */
        !           764:                altflag++;
        !           765:                for (j = 0; j < nalt; j++)
        !           766:                        for (i = 0; i < altmin; i++) {
        !           767:                                c = altpat[j][altlen[j] - altmin + i];
        !           768:                                altset[i + 1][c] = 1;   /* offset for sentinel */
        !           769:                        }
        !           770:        }
        !           771:        return (altpat[0]);
        !           772: }
        !           773: 
        !           774: /*
        !           775:  * Grapple with the dfa (std egrep) vs. ndfa (regexp) tradeoff. Criteria to
        !           776:  * determine whether to use dfa-based egrep:  We do FIRSTFEW matches with
        !           777:  * regexec().  If Boyer-Moore up to now matched more than PUNTPERCENT
        !           778:  * of the input, the r.e. is likely to be underspecified, so do old *grep,
        !           779:  * which is faster on complex patterns than regexp().  At FIRSTFEW,
        !           780:  * dump the saved matches collected by savematch(). They are saved
        !           781:  * so that a "PUNT" can "rewind" to ignore them.  Stdin is problematic,
        !           782:  * since it's hard to rewind. 
        !           783:  */
        !           784: 
        !           785: execstrategy(file)
        !           786:        char *file;
        !           787: {
        !           788:        int pctmatch;
        !           789: 
        !           790:        pctmatch = (100 * rxcount) / incount;
        !           791:        if (pctmatch > PUNTPERCENT && file != NULL)
        !           792:                kernighan(args);
        !           793:        if (file != NULL)
        !           794:                flushmatches();
        !           795: }
        !           796: 
        !           797: nlcount(bstart, bstop)         /* flail interval to totalize newlines. */
        !           798:        char *bstart, *bstop;
        !           799: {
        !           800:        register char *s = bstart;
        !           801:        register char *t = bstop;
        !           802:        register int count = 0;
        !           803: 
        !           804:        do {                    /* loop unroll for older architectures */
        !           805:                if (*t == NL)   /* ... ask ames!jaw for sample code */
        !           806:                        count++;
        !           807:        } while (t-- > s);
        !           808: 
        !           809:        return (count);
        !           810: }
        !           811: 
        !           812: char *
        !           813: isolate(regexpr)               /* isolate longest metacharacter-free string */
        !           814:        char *regexpr;
        !           815: {
        !           816:        char *dummyexpr;
        !           817: 
        !           818:        /*
        !           819:         * We add (.)* because Henry's regcomp only figures regmust if it
        !           820:         * sees a leading * pattern.  Foo! 
        !           821:         */
        !           822:        dummyexpr = malloc((unsigned) strlen(regexpr) + 5);
        !           823:        (void)sprintf(dummyexpr, "(.)*%s", regexpr);
        !           824:        if ((rspencer = regcomp(dummyexpr)) == NULL)
        !           825:                kernighan(args);
        !           826:        return (rspencer->regmust);
        !           827: }
        !           828: 
        !           829: char *matches[FIRSTFEW];
        !           830: static int mcount = 0;
        !           831: 
        !           832: char *
        !           833: savematch(s)                   /* horde matches during statistics gathering */
        !           834:        register char *s;
        !           835: {
        !           836:        char *p;
        !           837:        char *start = s;
        !           838:        int msize = 0;
        !           839:        int psize = strlen(preamble);
        !           840: 
        !           841:        while (*s++ != NL)
        !           842:                msize++;
        !           843:        *--s = EOS;
        !           844: 
        !           845:        p = malloc((unsigned) msize + 1 + psize);
        !           846:        strcpy(p, preamble);
        !           847:        strcpy(p + psize, start);
        !           848:        matches[mcount++] = p;
        !           849: 
        !           850:        preamble[0] = 0;
        !           851:        *s = NL;
        !           852:        return (s);
        !           853: }
        !           854: 
        !           855: flushmatches()
        !           856: {
        !           857:        int n;
        !           858: 
        !           859:        flushflag = 1;
        !           860:        for (n = 0; n < mcount; n++)
        !           861:                printf("%s\n", matches[n]);
        !           862:        mcount = 0;
        !           863: }
        !           864: 
        !           865: oops(message)
        !           866:        char *message;
        !           867: {
        !           868:        fprintf(stderr, "%s: %s\n", progname, message);
        !           869:        exit(2);
        !           870: }
        !           871: 
        !           872: kernighan(args)                        /* "let others do the hard part ..." */
        !           873:        char *args[];
        !           874: {
        !           875:        /*
        !           876:         * We may have already run grep on some of the files; remove them
        !           877:         * from the arg list we pass on.  Note that we can't delete them
        !           878:         * totally because the number of file names affects the output
        !           879:         * (automatic -h). 
        !           880:         */
        !           881:        /* better would be fork/exec per punted file -- jaw */
        !           882: 
        !           883:        while (firstfile && optind > firstfile)
        !           884:                args[firstfile++] = "/dev/null";
        !           885:        if (patind)
        !           886:                args[patind] = pattern;
        !           887:        (void) fflush(stdout);
        !           888: 
        !           889:        if (grepflag)
        !           890:                execvp(GREPSTD, args), oops("can't exec old 'grep'");
        !           891:        else if (fgrepflag)
        !           892:                execvp(FGREPSTD, args), oops("can't exec old 'fgrep'");
        !           893:        else
        !           894:                execvp(EGREPSTD, args), oops("can't exec old 'egrep'");
        !           895: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.