Annotation of 43BSDReno/contrib/jove/re1.c, revision 1.1

1.1     ! root        1: /***************************************************************************
        !             2:  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
        !             3:  * is provided to you without charge, and with no warranty.  You may give  *
        !             4:  * away copies of JOVE, including sources, provided that this notice is    *
        !             5:  * included in all the files.                                              *
        !             6:  ***************************************************************************/
        !             7: 
        !             8: #include "jove.h"
        !             9: #include "fp.h"
        !            10: #include "re.h"
        !            11: #include "ctype.h"
        !            12: #include "chars.h"
        !            13: #include "disp.h"
        !            14: 
        !            15: #ifdef MAC
        !            16: # include "mac.h"
        !            17: #else
        !            18: # include <sys/stat.h>
        !            19: #endif
        !            20: 
        !            21: private Bufpos *doisearch proto((int, int, int));
        !            22: 
        !            23: private void
        !            24:        IncSearch proto((int)),
        !            25:        replace proto((int, int));
        !            26: private int
        !            27:        isearch proto((int, Bufpos *)),
        !            28:        lookup proto((char *, char *, char *, char *)),
        !            29:        substitute proto((struct RE_block *, int, Line *, int, Line *, int));
        !            30: 
        !            31: private int
        !            32: substitute(re_blk, query, l1, char1, l2, char2)
        !            33: struct RE_block        *re_blk;
        !            34: Line   *l1,
        !            35:        *l2;
        !            36: int    query,
        !            37:        char1,
        !            38:        char2;
        !            39: {
        !            40:        Line    *lp;
        !            41:        int     numdone = 0,
        !            42:                UNDO_nd = 0,
        !            43:                offset = char1,
        !            44:                stop = NO;
        !            45:        daddr   UNDO_da = 0;
        !            46:        Line    *UNDO_lp = NULL;
        !            47: 
        !            48:        lsave();
        !            49:        REdirection = FORWARD;
        !            50: 
        !            51:        for (lp = l1; lp != l2->l_next; lp = lp->l_next) {
        !            52:                int     crater = -1;    /* end of last substitution on this line */
        !            53:                int     LineDone = NO;  /* already replaced last empty string on line? */
        !            54: 
        !            55:                while (!LineDone
        !            56:                && re_lindex(lp, offset, re_blk, NO, crater)
        !            57:                && (lp != l2 || REeom <= char2))
        !            58:                {
        !            59:                        DotTo(lp, REeom);
        !            60:                        offset = curchar;
        !            61:                        if (query) {
        !            62:                                int     c;
        !            63: 
        !            64:                                message("Replace (Type '?' for help)? ");
        !            65: reswitch:
        !            66:                                redisplay();
        !            67:                                c = jgetchar();
        !            68:                                if (c == AbortChar)
        !            69:                                        return numdone;
        !            70: 
        !            71:                                switch (CharUpcase(c)) {
        !            72:                                case '.':
        !            73:                                        stop = YES;
        !            74:                                        /*FALLTHROUGH*/
        !            75:                                case ' ':
        !            76:                                case 'Y':
        !            77:                                        break;
        !            78: 
        !            79:                                case BS:
        !            80:                                case RUBOUT:
        !            81:                                case 'N':
        !            82:                                        if (REbom == REeom) {
        !            83:                                                offset += 1;
        !            84:                                                if (linebuf[REeom] == '\0')
        !            85:                                                        LineDone = YES;
        !            86:                                        }
        !            87:                                        continue;
        !            88: 
        !            89:                                case CTL('W'):
        !            90:                                        re_dosub(re_blk, linebuf, YES);
        !            91:                                        if (lp == l2)
        !            92:                                                char2 += REdelta;
        !            93:                                        modify();
        !            94:                                        numdone += 1;
        !            95:                                        curchar = REbom;
        !            96:                                        makedirty(curline);
        !            97:                                        UNDO_da = curline->l_dline;
        !            98:                                        UNDO_lp = curline;
        !            99:                                        /*FALLTHROUGH*/
        !           100:                                case CTL('R'):
        !           101:                                case 'R':
        !           102:                                        RErecur();
        !           103:                                        UNDO_lp = NULL; /* can't reliably undo this */
        !           104:                                        offset = curchar;
        !           105:                                        lp = curline;
        !           106:                                        continue;
        !           107: 
        !           108:                                case CTL('U'):
        !           109:                                case 'U':
        !           110:                                        if (UNDO_lp == NULL) {
        !           111:                                                rbell();
        !           112:                                                goto reswitch;
        !           113:                                        }
        !           114:                                        if (UNDO_lp == NULL)
        !           115:                                                getline(UNDO_da, linebuf);      /* someone ought to */
        !           116:                                        lp = UNDO_lp;
        !           117:                                        lp->l_dline = UNDO_da;
        !           118:                                        makedirty(lp);
        !           119:                                        offset = 0;
        !           120:                                        numdone = UNDO_nd;
        !           121:                                        UNDO_lp = NULL;
        !           122:                                        continue;
        !           123: 
        !           124:                                case 'P':
        !           125:                                case '!':
        !           126:                                        query = 0;
        !           127:                                        break;
        !           128: 
        !           129:                                case CR:
        !           130:                                case LF:
        !           131:                                case 'Q':
        !           132:                                        return numdone;
        !           133: 
        !           134:                                case CTL('L'):
        !           135:                                        RedrawDisplay();
        !           136:                                        goto reswitch;
        !           137: 
        !           138:                                default:
        !           139:                                        rbell();
        !           140: message("Space or Y, Period, Rubout or N, C-R or R, C-W, C-U or U, P or !, Return.");
        !           141:                                        goto reswitch;
        !           142:                                }
        !           143:                        }
        !           144:                        if (UNDO_lp != curline) {
        !           145:                                UNDO_da = curline->l_dline;
        !           146:                                UNDO_lp = curline;
        !           147:                                UNDO_nd = numdone;
        !           148:                        }
        !           149:                        if (REbom == REeom && linebuf[REeom] == '\0')
        !           150:                                LineDone = YES;
        !           151:                        re_dosub(re_blk, linebuf, NO);
        !           152:                        if (lp == l2)
        !           153:                                char2 += REdelta;
        !           154:                        numdone += 1;
        !           155:                        modify();
        !           156:                        crater = offset = curchar = REeom;
        !           157:                        makedirty(curline);
        !           158:                        if (query) {
        !           159:                                message(mesgbuf);       /* no blinking */
        !           160:                                redisplay();            /* show the change */
        !           161:                        }
        !           162:                        if (stop)
        !           163:                                return numdone;
        !           164:                }
        !           165:                offset = 0;
        !           166:        }
        !           167:        return numdone;
        !           168: }
        !           169: 
        !           170: /* prompt for search and replacement strings and do the substitution */
        !           171: private void
        !           172: replace(query, inreg)
        !           173: int    query,
        !           174:        inreg;
        !           175: {
        !           176:        Mark    *m;
        !           177:        char    *rep_ptr;
        !           178:        Line    *l1 = curline,
        !           179:                *l2 = curbuf->b_last;
        !           180:        int     char1 = curchar,
        !           181:                char2 = length(curbuf->b_last),
        !           182:                numdone;
        !           183:        struct RE_block re_blk;
        !           184: 
        !           185:        if (inreg) {
        !           186:                m = CurMark();
        !           187:                l2 = m->m_line;
        !           188:                char2 = m->m_char;
        !           189:                (void) fixorder(&l1, &char1, &l2, &char2);
        !           190:        }
        !           191: 
        !           192:        /* get search string */
        !           193:        strcpy(rep_search, ask(rep_search[0] ? rep_search : (char *) 0, ProcFmt));
        !           194:        REcompile(rep_search, UseRE, &re_blk);
        !           195:        /* Now the replacement string.  Do_ask() so the user can play with
        !           196:           the default (previous) replacement string by typing C-R in ask(),
        !           197:           OR, he can just hit Return to replace with nothing. */
        !           198:        rep_ptr = do_ask("\r\n", (int (*) proto((int))) 0, rep_str,
        !           199:                ": %f %s with ", rep_search);
        !           200:        if (rep_ptr == 0)
        !           201:                rep_ptr = NullStr;
        !           202:        strcpy(rep_str, rep_ptr);
        !           203: 
        !           204:        if (((numdone = substitute(&re_blk, query, l1, char1, l2, char2)) != 0) &&
        !           205:            (inreg == NO)) {
        !           206:                do_set_mark(l1, char1);
        !           207:                add_mess(" ");          /* just making things pretty */
        !           208:        } else
        !           209:                message("");
        !           210:        add_mess("(%d substitution%n)", numdone, numdone);
        !           211: }
        !           212: 
        !           213: void
        !           214: RegReplace()
        !           215: {
        !           216:        replace(0, YES);
        !           217: }
        !           218: 
        !           219: void
        !           220: QRepSearch()
        !           221: {
        !           222:        replace(1, NO);
        !           223: }
        !           224: 
        !           225: void
        !           226: RepSearch()
        !           227: {
        !           228:        replace(0, NO);
        !           229: }
        !           230: 
        !           231: /* Lookup a tag in tag file FILE.  FILE is assumed to be sorted
        !           232:    alphabetically.  The FASTTAGS code, which is implemented with
        !           233:    a binary search, depends on this assumption.  If it's not true
        !           234:    it is possible to comment out the fast tag code (which is clearly
        !           235:    labeled), delete the marked test in the sequential loop, and
        !           236:    everything else will just work. */
        !           237: 
        !           238: private int
        !           239: lookup(searchbuf, filebuf, tag, file)
        !           240: char   *searchbuf,
        !           241:        *filebuf,
        !           242:        *tag,
        !           243:        *file;
        !           244: {
        !           245:        register size_t taglen = strlen(tag);
        !           246:        char    line[JBUFSIZ],
        !           247:                pattern[128];
        !           248:        register File   *fp;
        !           249:        struct stat     stbuf;
        !           250:        int     success = NO;
        !           251: 
        !           252:        fp = open_file(file, iobuff, F_READ, NO, YES);
        !           253:        if (fp == NIL)
        !           254:                return NO;
        !           255:        swritef(pattern, "^%s[^\t]*\t*\\([^\t]*\\)\t*\\([?/]\\)\\(.*\\)\\2$", tag);
        !           256: 
        !           257:        /* ********BEGIN FAST TAG CODE******** */
        !           258: 
        !           259:        if (stat(file, &stbuf) >= 0) {
        !           260:                /* Invariant: if there is a line matching the tag, it
        !           261:                 * begins somewhere after position lower, and begins
        !           262:                 * at or before upper.  There is one possible
        !           263:                 * exception: if lower is 0, the line with the tag
        !           264:                 * might be the very first line.
        !           265:                 *
        !           266:                 * When this loop is done, we seek to lower, advance
        !           267:                 * past the next newline (unless lower is 0), and fall
        !           268:                 * into the sequential search.
        !           269:                 */
        !           270:                register off_t  lower = 0;
        !           271:                register off_t  upper = stbuf.st_size;
        !           272: 
        !           273:                for (;;) {
        !           274:                        off_t   mid;
        !           275:                        int     chars_eq;
        !           276: 
        !           277:                        if (upper - lower < JBUFSIZ)
        !           278:                                break;  /* small range: search sequentially */
        !           279:                        mid = (lower + upper) / 2;
        !           280:                        f_seek(fp, mid);        /* mid will not be 0 */
        !           281:                        f_toNL(fp);
        !           282:                        if (f_gets(fp, line, sizeof line) == EOF)
        !           283:                                break;          /* unexpected: bail out */
        !           284:                        chars_eq = numcomp(line, tag);
        !           285:                        if (chars_eq == taglen && iswhite(line[chars_eq])) {
        !           286:                                /* we hit the exact line: get out */
        !           287:                                lower = mid;
        !           288:                                break;
        !           289:                        }
        !           290:                        if (line[chars_eq] < tag[chars_eq])
        !           291:                                lower = mid;    /* line is BEFORE tag */
        !           292:                        else
        !           293:                                upper = mid;    /* line is AFTER tag */
        !           294:                }
        !           295:                /* sequentially search from lower */
        !           296:                f_seek(fp, lower);
        !           297:                if (lower > 0)
        !           298:                        f_toNL(fp);
        !           299:        }
        !           300: 
        !           301:        /* END FAST TAG CODE */
        !           302: 
        !           303:        while (f_gets(fp, line, sizeof line) != EOF) {
        !           304:                int     cmp = line[0] - *tag;
        !           305: 
        !           306:                if (cmp == 0) {
        !           307:                        cmp = strncmp(line, tag, taglen);
        !           308:                        if (cmp == 0) {
        !           309:                                /* we've found the match */
        !           310:                                if (!LookingAt(pattern, line, 0)) {
        !           311:                                        complain("I thought I saw it!");
        !           312:                                } else {
        !           313:                                        putmatch(1, filebuf, (size_t)FILESIZE);
        !           314:                                        putmatch(3, searchbuf, (size_t)100);
        !           315:                                        success = YES;
        !           316:                                }
        !           317:                                break;
        !           318:                        }
        !           319:                }
        !           320:                if (cmp > 0)
        !           321:                        break;  /* failure: gone too far.  PRESUMES ALPHABETIC ORDER */
        !           322:        }
        !           323:        close_file(fp);
        !           324: 
        !           325:        if (success == NO)
        !           326:                s_mess("Can't find tag \"%s\".", tag);
        !           327:        return success;
        !           328: }
        !           329: 
        !           330: #if !(defined(MSDOS) || defined(MAC))
        !           331: char   TagFile[FILESIZE] = "./tags";
        !           332: #else /* MSDOS */
        !           333: char   TagFile[FILESIZE] = "tags";
        !           334: #endif /* MSDOS */
        !           335: 
        !           336: void
        !           337: find_tag(tag, localp)
        !           338: char   *tag;
        !           339: int    localp;
        !           340: {
        !           341:        char    filebuf[FILESIZE],
        !           342:                sstr[100],
        !           343:                tfbuf[FILESIZE];
        !           344:        register Bufpos *bp;
        !           345:        register Buffer *b;
        !           346:        char    *tagfname;
        !           347: 
        !           348:        if (!localp) 
        !           349:                tagfname = ask_file("With tag file: ", TagFile, tfbuf);
        !           350:        else
        !           351:                tagfname = TagFile;
        !           352:        if (lookup(sstr, filebuf, tag, tagfname) == 0)
        !           353:                return;
        !           354:        set_mark();
        !           355:        b = do_find(curwind, filebuf, 0);
        !           356:        if (curbuf != b)
        !           357:                SetABuf(curbuf);
        !           358:        SetBuf(b);
        !           359:        if ((bp = dosearch(sstr, BACKWARD, 0)) == 0 &&
        !           360:            ((bp = dosearch(sstr, FORWARD, 0)) == 0))
        !           361:                message("Well, I found the file, but the tag is missing.");
        !           362:        else
        !           363:                SetDot(bp);
        !           364: }
        !           365: 
        !           366: void
        !           367: FindTag()
        !           368: {
        !           369:        int     localp = !is_an_arg();
        !           370:        char    tag[128];
        !           371: 
        !           372:        strcpy(tag, ask((char *) 0, ProcFmt));
        !           373:        find_tag(tag, localp);
        !           374: }
        !           375: 
        !           376: /* Find Tag at Dot. */
        !           377: 
        !           378: void
        !           379: FDotTag()
        !           380: {
        !           381:        int     c1 = curchar,
        !           382:                c2 = c1;
        !           383:        char    tagname[50];
        !           384: 
        !           385:        if (!ismword(linebuf[curchar]))
        !           386:                complain("Not a tag!");
        !           387:        while (c1 > 0 && ismword(linebuf[c1 - 1]))
        !           388:                c1 -= 1;
        !           389:        while (ismword(linebuf[c2]))
        !           390:                c2 += 1;
        !           391: 
        !           392:        null_ncpy(tagname, linebuf + c1, (size_t) (c2 - c1));
        !           393:        find_tag(tagname, !is_an_arg());
        !           394: }
        !           395: 
        !           396: /* I-search returns a code saying what to do:
        !           397:    STOP:       We found the match, so unwind the stack and leave
        !           398:                where it is.
        !           399:    DELETE:     Rubout the last command.
        !           400:    BACKUP:     Back up to where the isearch was last NOT failing.
        !           401: 
        !           402:    When a character is typed it is appended to the search string, and
        !           403:    then, isearch is called recursively.  When C-S or C-R is typed, isearch
        !           404:    is again called recursively. */
        !           405: 
        !           406: #define STOP   1
        !           407: #define DELETE 2
        !           408: #define BACKUP 3
        !           409: #define TOSTART        4
        !           410: 
        !           411: static char    ISbuf[128],
        !           412:                *incp = 0;
        !           413: int    SExitChar = CR;
        !           414: 
        !           415: #define cmp_char(a, b) ((a) == (b) || (CaseIgnore && (CharUpcase(a) == CharUpcase(b))))
        !           416: 
        !           417: static Bufpos *
        !           418: doisearch(dir, c, failing)
        !           419: register int   c,
        !           420:                dir,
        !           421:                failing;
        !           422: {
        !           423:        static Bufpos   buf;
        !           424:        Bufpos  *bp;
        !           425: 
        !           426:        if (c == CTL('S') || c == CTL('R'))
        !           427:                goto dosrch;
        !           428: 
        !           429:        if (failing)
        !           430:                return 0;
        !           431:        DOTsave(&buf);
        !           432:        if (dir == FORWARD) {
        !           433:                if (cmp_char(linebuf[curchar], c)) {
        !           434:                        buf.p_char = curchar + 1;
        !           435:                        return &buf;
        !           436:                }
        !           437:        } else {
        !           438:                if (look_at(ISbuf))
        !           439:                        return &buf;
        !           440:        }
        !           441: dosrch:        okay_wrap = YES;
        !           442:        if ((bp = dosearch(ISbuf, dir, 0)) == 0)
        !           443:                rbell();        /* ring the first time there's no match */
        !           444:        okay_wrap = NO;
        !           445:        return bp;
        !           446: }
        !           447: 
        !           448: void
        !           449: IncFSearch()
        !           450: {
        !           451:        IncSearch(FORWARD);
        !           452: }
        !           453: 
        !           454: void
        !           455: IncRSearch()
        !           456: {
        !           457:        IncSearch(BACKWARD);
        !           458: }
        !           459: 
        !           460: private void
        !           461: IncSearch(dir)
        !           462: int    dir;
        !           463: {
        !           464:        Bufpos  save_env;
        !           465: 
        !           466:        DOTsave(&save_env);
        !           467:        ISbuf[0] = 0;
        !           468:        incp = ISbuf;
        !           469:        if (isearch(dir, &save_env) == TOSTART)
        !           470:                SetDot(&save_env);
        !           471:        else {
        !           472:                if (LineDist(curline, save_env.p_line) >= MarkThresh)
        !           473:                        do_set_mark(save_env.p_line, save_env.p_char);
        !           474:        }
        !           475:        setsearch(ISbuf);
        !           476: }
        !           477: 
        !           478: /* Nicely recursive. */
        !           479: 
        !           480: private int
        !           481: isearch(dir, bp)
        !           482: int    dir;
        !           483: Bufpos *bp;
        !           484: {
        !           485:        Bufpos  pushbp;
        !           486:        int     c,
        !           487:                ndir,
        !           488:                failing;
        !           489:        char    *orig_incp;
        !           490: 
        !           491:        if (bp != 0) {          /* Move to the new position. */
        !           492:                pushbp.p_line = bp->p_line;
        !           493:                pushbp.p_char = bp->p_char;
        !           494:                SetDot(bp);
        !           495:                failing = 0;
        !           496:        } else {
        !           497:                DOTsave(&pushbp);
        !           498:                failing = 1;
        !           499:        }
        !           500:        orig_incp = incp;
        !           501:        ndir = dir;             /* Same direction as when we got here, unless
        !           502:                                   we change it with C-S or C-R. */
        !           503:        for (;;) {
        !           504:                SetDot(&pushbp);
        !           505:                message(NullStr);
        !           506:                if (failing)
        !           507:                        add_mess("Failing ");
        !           508:                if (dir == BACKWARD)
        !           509:                        add_mess("reverse-");
        !           510:                add_mess("I-search: %s", ISbuf);
        !           511:                DrawMesg(NO);
        !           512:                add_mess(NullStr);      /* tell me this is disgusting ... */
        !           513:                c = getch();
        !           514:                if (c == SExitChar)
        !           515:                        return STOP;
        !           516:                if (c == AbortChar) {
        !           517:                        /* If we're failing, we backup until we're no longer
        !           518:                           failing or we've reached the beginning; else, we
        !           519:                           just about the search and go back to the start. */
        !           520:                        if (failing)
        !           521:                                return BACKUP;
        !           522:                        return TOSTART;
        !           523:                }
        !           524:                switch (c) {
        !           525:                case RUBOUT:
        !           526:                case BS:
        !           527:                        return DELETE;
        !           528: 
        !           529:                case CTL('\\'):
        !           530:                        c = CTL('S');
        !           531:                        /*FALLTHROUGH*/
        !           532:                case CTL('S'):
        !           533:                case CTL('R'):
        !           534:                        /* If this is the first time through and we have a
        !           535:                           search string left over from last time, use that
        !           536:                           one now. */
        !           537:                        if (incp == ISbuf) {
        !           538:                                strcpy(ISbuf, getsearch());
        !           539:                                incp = &ISbuf[strlen(ISbuf)];
        !           540:                        }
        !           541:                        ndir = (c == CTL('S')) ? FORWARD : BACKWARD;
        !           542:                        /* If we're failing and we're not changing our
        !           543:                           direction, don't recur since there's no way
        !           544:                           the search can work. */
        !           545:                        if (failing && ndir == dir) {
        !           546:                                rbell();
        !           547:                                continue;
        !           548:                        }
        !           549:                        break;
        !           550: 
        !           551:                case '\\':
        !           552:                        if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
        !           553:                                rbell();
        !           554:                                continue;
        !           555:                        }
        !           556:                        *incp++ = '\\';
        !           557:                        add_mess("\\");
        !           558:                        /*FALLTHROUGH*/
        !           559:                case CTL('Q'):
        !           560:                case CTL('^'):
        !           561:                        add_mess("");
        !           562:                        c = getch() | 0400;
        !           563:                        /*FALLTHROUGH*/
        !           564:                default:
        !           565:                        if (c & 0400)
        !           566:                                c &= CHARMASK;
        !           567:                        else {
        !           568: #ifdef IBMPC
        !           569:                                if (c == RUBOUT || c == 0xff ||
        !           570:                                    (c < ' ' && c != '\t')
        !           571: #else
        !           572:                                if (c > RUBOUT || (c < ' ' && c != '\t')
        !           573: #endif
        !           574:                                    || PrefChar(c)) {
        !           575:                                        Ungetc(c);
        !           576:                                        return STOP;
        !           577:                                }
        !           578:                        }
        !           579:                        if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
        !           580:                                rbell();
        !           581:                                continue;
        !           582:                        }
        !           583:                        *incp++ = c;
        !           584:                        *incp = 0;
        !           585:                        break;
        !           586:                }
        !           587:                add_mess("%s", orig_incp);
        !           588:                add_mess(" ...");       /* so we know what's going on */
        !           589:                DrawMesg(NO);           /* do it now */
        !           590:                switch (isearch(ndir, doisearch(ndir, c, failing))) {
        !           591:                case TOSTART:
        !           592:                        return TOSTART;
        !           593: 
        !           594:                case STOP:
        !           595:                        return STOP;
        !           596: 
        !           597:                case BACKUP:
        !           598:                        /* If we're not failing, we just continue to to the
        !           599:                           for loop; otherwise we keep returning to the
        !           600:                           previous levels until we find one that isn't
        !           601:                           failing OR we reach the beginning. */
        !           602:                        if (failing)
        !           603:                                return BACKUP;
        !           604:                        /*FALLTHROUGH*/
        !           605:                case DELETE:
        !           606:                        incp = orig_incp;
        !           607:                        *incp = 0;
        !           608:                        continue;
        !           609:                }
        !           610:        }
        !           611: }

unix.superglobalmegacorp.com

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