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

unix.superglobalmegacorp.com

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