Annotation of 43BSDReno/contrib/jove/re1.c, revision 1.1.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.