[BACK]Return to search.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/search.c, Revision 1.2

1.1       deraadt     1: /*
                      2:  *             Search commands.
                      3:  * The functions in this file implement the
                      4:  * search commands (both plain and incremental searches
                      5:  * are supported) and the query-replace command.
                      6:  *
                      7:  * The plain old search code is part of the original
                      8:  * MicroEMACS "distribution". The incremental search code,
                      9:  * and the query-replace code, is by Rich Ellison.
                     10:  */
                     11: #include       "def.h"
                     12: #ifndef NO_MACRO
                     13: #include       "macro.h"
                     14: #endif
                     15:
1.2     ! millert    16: #define SRCH_BEGIN     (0)     /* Search sub-codes.     */
1.1       deraadt    17: #define SRCH_FORW      (-1)
                     18: #define SRCH_BACK      (-2)
                     19: #define SRCH_NOPR      (-3)
                     20: #define SRCH_ACCM      (-4)
                     21: #define SRCH_MARK      (-5)
                     22:
1.2     ! millert    23: typedef struct {
        !            24:        int             s_code;
        !            25:        LINE           *s_dotp;
        !            26:        int             s_doto;
        !            27: }               SRCHCOM;
        !            28:
        !            29: static SRCHCOM  cmds[NSRCH];
        !            30: static int      cip;
        !            31:
        !            32: int             srch_lastdir = SRCH_NOPR;      /* Last search flags.    */
        !            33:
        !            34: static VOID     is_cpush();
        !            35: static VOID     is_lpush();
        !            36: static VOID     is_pop();
        !            37: static int      is_peek();
        !            38: static VOID     is_undo();
        !            39: static int      is_find();
        !            40: static VOID     is_prompt();
        !            41: static VOID     is_dspl();
        !            42: static int      eq();
1.1       deraadt    43:
                     44: /*
                     45:  * Search forward.
                     46:  * Get a search string from the user, and search for it,
                     47:  * starting at ".". If found, "." gets moved to just after the
                     48:  * matched characters, and display does all the hard stuff.
                     49:  * If not found, it just prints a message.
                     50:  */
1.2     ! millert    51: /* ARGSUSED */
1.1       deraadt    52: forwsearch(f, n)
                     53: {
1.2     ! millert    54:        register int    s;
1.1       deraadt    55:
1.2     ! millert    56:        if ((s = readpattern("Search")) != TRUE)
1.1       deraadt    57:                return s;
                     58:        if (forwsrch() == FALSE) {
                     59:                ewprintf("Search failed: \"%s\"", pat);
                     60:                return FALSE;
                     61:        }
                     62:        srch_lastdir = SRCH_FORW;
                     63:        return TRUE;
                     64: }
                     65:
                     66: /*
                     67:  * Reverse search.
                     68:  * Get a search string from the         user, and search, starting at "."
                     69:  * and proceeding toward the front of the buffer. If found "." is left
                     70:  * pointing at the first character of the pattern [the last character that
                     71:  * was matched].
                     72:  */
1.2     ! millert    73: /* ARGSUSED */
1.1       deraadt    74: backsearch(f, n)
                     75: {
1.2     ! millert    76:        register int    s;
1.1       deraadt    77:
1.2     ! millert    78:        if ((s = readpattern("Search backward")) != TRUE)
1.1       deraadt    79:                return (s);
                     80:        if (backsrch() == FALSE) {
                     81:                ewprintf("Search failed: \"%s\"", pat);
                     82:                return FALSE;
                     83:        }
                     84:        srch_lastdir = SRCH_BACK;
                     85:        return TRUE;
                     86: }
                     87:
                     88: /*
                     89:  * Search again, using the same search string
                     90:  * and direction as the last search command. The direction
                     91:  * has been saved in "srch_lastdir", so you know which way
                     92:  * to go.
                     93:  */
1.2     ! millert    94: /* ARGSUSED */
1.1       deraadt    95: searchagain(f, n)
                     96: {
                     97:        if (srch_lastdir == SRCH_FORW) {
                     98:                if (forwsrch() == FALSE) {
                     99:                        ewprintf("Search failed: \"%s\"", pat);
                    100:                        return FALSE;
                    101:                }
                    102:                return TRUE;
                    103:        }
                    104:        if (srch_lastdir == SRCH_BACK) {
                    105:                if (backsrch() == FALSE) {
                    106:                        ewprintf("Search failed: \"%s\"", pat);
                    107:                        return FALSE;
                    108:                }
                    109:                return TRUE;
                    110:        }
                    111:        ewprintf("No last search");
                    112:        return FALSE;
                    113: }
                    114:
                    115: /*
                    116:  * Use incremental searching, initially in the forward direction.
                    117:  * isearch ignores any explicit arguments.
                    118:  */
1.2     ! millert   119: /* ARGSUSED */
1.1       deraadt   120: forwisearch(f, n)
                    121: {
                    122:        return isearch(SRCH_FORW);
                    123: }
                    124:
                    125: /*
                    126:  * Use incremental searching, initially in the reverse direction.
                    127:  * isearch ignores any explicit arguments.
                    128:  */
1.2     ! millert   129: /* ARGSUSED */
1.1       deraadt   130: backisearch(f, n)
                    131: {
                    132:        return isearch(SRCH_BACK);
                    133: }
                    134:
                    135: /*
                    136:  * Incremental Search.
                    137:  *     dir is used as the initial direction to search.
                    138:  *     ^S      switch direction to forward
                    139:  *     ^R      switch direction to reverse
                    140:  *     ^Q      quote next character (allows searching for ^N etc.)
                    141:  *     <ESC>   exit from Isearch
                    142:  *     <DEL>   undoes last character typed. (tricky job to do this correctly).
                    143:  *     other ^ exit search, don't set mark
                    144:  *     else    accumulate into search string
                    145:  */
1.2     ! millert   146: isearch(dir)
        !           147: {
        !           148:        register int    c;
        !           149:        register LINE  *clp;
        !           150:        register int    cbo;
        !           151:        register int    success;
        !           152:        int             pptr;
        !           153:        char            opat[NPAT];
        !           154:        VOID            ungetkey();
1.1       deraadt   155:
                    156: #ifndef NO_MACRO
1.2     ! millert   157:        if (macrodef) {
        !           158:                ewprintf("Can't isearch in macro");
        !           159:                return FALSE;
1.1       deraadt   160:        }
                    161: #endif
1.2     ! millert   162:        for (cip = 0; cip < NSRCH; cip++)
1.1       deraadt   163:                cmds[cip].s_code = SRCH_NOPR;
                    164:        (VOID) strcpy(opat, pat);
                    165:        cip = 0;
                    166:        pptr = -1;
                    167:        clp = curwp->w_dotp;
                    168:        cbo = curwp->w_doto;
                    169:        is_lpush();
                    170:        is_cpush(SRCH_BEGIN);
                    171:        success = TRUE;
                    172:        is_prompt(dir, TRUE, success);
                    173:        for (;;) {
                    174:                update();
                    175:                switch (c = getkey(FALSE)) {
                    176:                case CCHR('['):
                    177:                        srch_lastdir = dir;
                    178:                        curwp->w_markp = clp;
                    179:                        curwp->w_marko = cbo;
                    180:                        ewprintf("Mark set");
                    181:                        return (TRUE);
                    182:
                    183:                case CCHR('G'):
                    184:                        if (success != TRUE) {
                    185:                                while (is_peek() == SRCH_ACCM)
                    186:                                        is_undo(&pptr, &dir);
                    187:                                success = TRUE;
                    188:                                is_prompt(dir, pptr < 0, success);
                    189:                                break;
                    190:                        }
                    191:                        curwp->w_dotp = clp;
                    192:                        curwp->w_doto = cbo;
                    193:                        curwp->w_flag |= WFMOVE;
                    194:                        srch_lastdir = dir;
                    195:                        (VOID) ctrlg(FFRAND, 0);
                    196:                        (VOID) strcpy(pat, opat);
                    197:                        return ABORT;
                    198:
                    199:                case CCHR(']'):
                    200:                case CCHR('S'):
                    201:                        if (dir == SRCH_BACK) {
                    202:                                dir = SRCH_FORW;
                    203:                                is_lpush();
                    204:                                is_cpush(SRCH_FORW);
                    205:                                success = TRUE;
                    206:                        }
1.2     ! millert   207:                        if (success == FALSE && dir == SRCH_FORW)
1.1       deraadt   208:                                break;
                    209:                        is_lpush();
                    210:                        pptr = strlen(pat);
                    211:                        (VOID) forwchar(FFRAND, 1);
1.2     ! millert   212:                        if (is_find(SRCH_FORW) != FALSE)
        !           213:                                is_cpush(SRCH_MARK);
1.1       deraadt   214:                        else {
                    215:                                (VOID) backchar(FFRAND, 1);
                    216:                                ttbeep();
                    217:                                success = FALSE;
                    218:                        }
                    219:                        is_prompt(dir, pptr < 0, success);
                    220:                        break;
                    221:
                    222:                case CCHR('R'):
                    223:                        if (dir == SRCH_FORW) {
                    224:                                dir = SRCH_BACK;
                    225:                                is_lpush();
                    226:                                is_cpush(SRCH_BACK);
                    227:                                success = TRUE;
                    228:                        }
1.2     ! millert   229:                        if (success == FALSE && dir == SRCH_BACK)
1.1       deraadt   230:                                break;
                    231:                        is_lpush();
                    232:                        pptr = strlen(pat);
                    233:                        (VOID) backchar(FFRAND, 1);
1.2     ! millert   234:                        if (is_find(SRCH_BACK) != FALSE)
        !           235:                                is_cpush(SRCH_MARK);
1.1       deraadt   236:                        else {
                    237:                                (VOID) forwchar(FFRAND, 1);
                    238:                                ttbeep();
                    239:                                success = FALSE;
                    240:                        }
                    241:                        is_prompt(dir, pptr < 0, success);
                    242:                        break;
                    243:
                    244:                case CCHR('H'):
                    245:                case CCHR('?'):
                    246:                        is_undo(&pptr, &dir);
1.2     ! millert   247:                        if (is_peek() != SRCH_ACCM)
        !           248:                                success = TRUE;
1.1       deraadt   249:                        is_prompt(dir, pptr < 0, success);
                    250:                        break;
                    251:
                    252:                case CCHR('\\'):
                    253:                case CCHR('Q'):
                    254:                        c = (char) getkey(FALSE);
1.2     ! millert   255:                        goto addchar;
1.1       deraadt   256:                case CCHR('M'):
                    257:                        c = CCHR('J');
1.2     ! millert   258:                        goto addchar;
1.1       deraadt   259:
                    260:                default:
                    261:                        if (ISCTRL(c)) {
                    262:                                ungetkey(c);
                    263:                                curwp->w_markp = clp;
                    264:                                curwp->w_marko = cbo;
                    265:                                ewprintf("Mark set");
                    266:                                curwp->w_flag |= WFMOVE;
1.2     ! millert   267:                                return TRUE;
1.1       deraadt   268:                        }       /* and continue */
                    269:                case CCHR('I'):
                    270:                case CCHR('J'):
1.2     ! millert   271:        addchar:
1.1       deraadt   272:                        if (pptr == -1)
                    273:                                pptr = 0;
                    274:                        if (pptr == 0)
                    275:                                success = TRUE;
                    276:                        pat[pptr++] = c;
                    277:                        if (pptr == NPAT) {
                    278:                                ewprintf("Pattern too long");
                    279:                                return FALSE;
                    280:                        }
                    281:                        pat[pptr] = '\0';
                    282:                        is_lpush();
                    283:                        if (success != FALSE) {
                    284:                                if (is_find(dir) != FALSE)
                    285:                                        is_cpush(c);
                    286:                                else {
                    287:                                        success = FALSE;
                    288:                                        ttbeep();
                    289:                                        is_cpush(SRCH_ACCM);
                    290:                                }
                    291:                        } else
                    292:                                is_cpush(SRCH_ACCM);
                    293:                        is_prompt(dir, FALSE, success);
                    294:                }
                    295:        }
1.2     ! millert   296:        /* NOTREACHED */
1.1       deraadt   297: }
                    298:
1.2     ! millert   299: static          VOID
        !           300: is_cpush(cmd)
        !           301:        register int    cmd;
        !           302: {
1.1       deraadt   303:        if (++cip >= NSRCH)
                    304:                cip = 0;
                    305:        cmds[cip].s_code = cmd;
                    306: }
                    307:
1.2     ! millert   308: static          VOID
        !           309: is_lpush()
        !           310: {
        !           311:        register int    ctp;
1.1       deraadt   312:
1.2     ! millert   313:        ctp = cip + 1;
1.1       deraadt   314:        if (ctp >= NSRCH)
                    315:                ctp = 0;
                    316:        cmds[ctp].s_code = SRCH_NOPR;
                    317:        cmds[ctp].s_doto = curwp->w_doto;
                    318:        cmds[ctp].s_dotp = curwp->w_dotp;
                    319: }
                    320:
1.2     ! millert   321: static          VOID
        !           322: is_pop()
        !           323: {
1.1       deraadt   324:        if (cmds[cip].s_code != SRCH_NOPR) {
1.2     ! millert   325:                curwp->w_doto = cmds[cip].s_doto;
        !           326:                curwp->w_dotp = cmds[cip].s_dotp;
1.1       deraadt   327:                curwp->w_flag |= WFMOVE;
                    328:                cmds[cip].s_code = SRCH_NOPR;
                    329:        }
                    330:        if (--cip <= 0)
1.2     ! millert   331:                cip = NSRCH - 1;
1.1       deraadt   332: }
                    333:
                    334: static int
1.2     ! millert   335: is_peek()
        !           336: {
1.1       deraadt   337:        return cmds[cip].s_code;
                    338: }
                    339:
                    340: /* this used to always return TRUE (the return value was checked) */
1.2     ! millert   341: static          VOID
        !           342: is_undo(pptr, dir)
        !           343:        register int   *pptr;
        !           344:        register int   *dir;
        !           345: {
        !           346:        register int    redo = FALSE;
1.1       deraadt   347:        switch (cmds[cip].s_code) {
                    348:        case SRCH_BEGIN:
                    349:        case SRCH_NOPR:
                    350:                *pptr = -1;
                    351:        case SRCH_MARK:
                    352:                break;
                    353:
                    354:        case SRCH_FORW:
                    355:                *dir = SRCH_BACK;
                    356:                redo = TRUE;
                    357:                break;
                    358:
                    359:        case SRCH_BACK:
                    360:                *dir = SRCH_FORW;
                    361:                redo = TRUE;
                    362:                break;
                    363:
                    364:        case SRCH_ACCM:
                    365:        default:
                    366:                *pptr -= 1;
                    367:                if (*pptr < 0)
                    368:                        *pptr = 0;
                    369:                pat[*pptr] = '\0';
                    370:                break;
                    371:        }
                    372:        is_pop();
1.2     ! millert   373:        if (redo)
        !           374:                is_undo(pptr, dir);
1.1       deraadt   375: }
                    376:
                    377: static int
1.2     ! millert   378: is_find(dir)
        !           379:        register int    dir;
        !           380: {
        !           381:        register int    plen, odoto;
        !           382:        register LINE  *odotp;
1.1       deraadt   383:
                    384:        odoto = curwp->w_doto;
                    385:        odotp = curwp->w_dotp;
                    386:        plen = strlen(pat);
                    387:        if (plen != 0) {
1.2     ! millert   388:                if (dir == SRCH_FORW) {
1.1       deraadt   389:                        (VOID) backchar(FFARG | FFRAND, plen);
                    390:                        if (forwsrch() == FALSE) {
                    391:                                curwp->w_doto = odoto;
                    392:                                curwp->w_dotp = odotp;
                    393:                                return FALSE;
                    394:                        }
                    395:                        return TRUE;
                    396:                }
1.2     ! millert   397:                if (dir == SRCH_BACK) {
1.1       deraadt   398:                        (VOID) forwchar(FFARG | FFRAND, plen);
                    399:                        if (backsrch() == FALSE) {
                    400:                                curwp->w_doto = odoto;
                    401:                                curwp->w_dotp = odotp;
                    402:                                return FALSE;
                    403:                        }
                    404:                        return TRUE;
                    405:                }
                    406:                ewprintf("bad call to is_find");
                    407:                return FALSE;
                    408:        }
                    409:        return FALSE;
                    410: }
                    411:
                    412: /*
                    413:  * If called with "dir" not one of SRCH_FORW
                    414:  * or SRCH_BACK, this routine used to print an error
                    415:  * message. It also used to return TRUE or FALSE,
                    416:  * depending on if it liked the "dir". However, none
                    417:  * of the callers looked at the status, so I just
                    418:  * made the checking vanish.
                    419:  */
1.2     ! millert   420: static          VOID
        !           421: is_prompt(dir, flag, success)
        !           422: {
1.1       deraadt   423:        if (dir == SRCH_FORW) {
                    424:                if (success != FALSE)
                    425:                        is_dspl("I-search", flag);
                    426:                else
                    427:                        is_dspl("Failing I-search", flag);
                    428:        } else if (dir == SRCH_BACK) {
                    429:                if (success != FALSE)
                    430:                        is_dspl("I-search backward", flag);
                    431:                else
                    432:                        is_dspl("Failing I-search backward", flag);
1.2     ! millert   433:        } else
        !           434:                ewprintf("Broken call to is_prompt");
1.1       deraadt   435: }
                    436:
                    437: /*
                    438:  * Prompt writing routine for the incremental search.
                    439:  * The "prompt" is just a string. The "flag" determines
                    440:  * whether pat should be printed.
                    441:  */
1.2     ! millert   442: static          VOID
        !           443: is_dspl(prompt, flag)
        !           444:        char           *prompt;
        !           445: {
1.1       deraadt   446:
                    447:        if (flag != FALSE)
                    448:                ewprintf("%s: ", prompt);
                    449:        else
                    450:                ewprintf("%s: %s", prompt, pat);
                    451: }
                    452:
                    453: /*
                    454:  * Query Replace.
                    455:  *     Replace strings selectively.  Does a search and replace operation.
                    456:  */
1.2     ! millert   457: /* ARGSUSED */
1.1       deraadt   458: queryrepl(f, n)
                    459: {
1.2     ! millert   460:        register int    s;
        !           461:        register int    rcnt = 0;       /* Replacements made so far      */
        !           462:        register int    plen;   /* length of found string        */
        !           463:        char            news[NPAT];     /* replacement string            */
1.1       deraadt   464:
                    465: #ifndef NO_MACRO
1.2     ! millert   466:        if (macrodef) {
        !           467:                ewprintf("Can't query replace in macro");
        !           468:                return FALSE;
1.1       deraadt   469:        }
                    470: #endif
1.2     ! millert   471:        if ((s = readpattern("Query replace")) != TRUE)
1.1       deraadt   472:                return (s);
1.2     ! millert   473:        if ((s = ereply("Query replace %s with: ", news, NPAT, pat)) == ABORT)
1.1       deraadt   474:                return (s);
                    475:        if (s == FALSE)
                    476:                news[0] = '\0';
                    477:        ewprintf("Query replacing %s with %s:", pat, news);
                    478:        plen = strlen(pat);
                    479:
                    480:        /*
                    481:         * Search forward repeatedly, checking each time whether to insert
                    482:         * or not.  The "!" case makes the check always true, so it gets put
                    483:         * into a tighter loop for efficiency.
                    484:         */
                    485:
                    486:        while (forwsrch() == TRUE) {
1.2     ! millert   487: retry:
1.1       deraadt   488:                update();
                    489:                switch (getkey(FALSE)) {
                    490:                case ' ':
                    491:                        if (lreplace((RSIZE) plen, news, f) == FALSE)
                    492:                                return (FALSE);
                    493:                        rcnt++;
                    494:                        break;
                    495:
                    496:                case '.':
                    497:                        if (lreplace((RSIZE) plen, news, f) == FALSE)
                    498:                                return (FALSE);
                    499:                        rcnt++;
                    500:                        goto stopsearch;
                    501:
1.2     ! millert   502:                case CCHR('G'):/* ^G or ESC */
1.1       deraadt   503:                        (VOID) ctrlg(FFRAND, 0);
                    504:                case CCHR('['):
                    505:                        goto stopsearch;
                    506:
                    507:                case '!':
                    508:                        do {
                    509:                                if (lreplace((RSIZE) plen, news, f) == FALSE)
                    510:                                        return (FALSE);
                    511:                                rcnt++;
                    512:                        } while (forwsrch() == TRUE);
                    513:                        goto stopsearch;
                    514:
                    515:                case CCHR('H'):
1.2     ! millert   516:                case CCHR('?'):/* To not replace */
1.1       deraadt   517:                        break;
                    518:
                    519:                default:
1.2     ! millert   520:                        ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
1.1       deraadt   521:                        goto retry;
                    522:                }
                    523:        }
                    524: stopsearch:
                    525:        curwp->w_flag |= WFHARD;
                    526:        update();
                    527:        if (rcnt == 0)
                    528:                ewprintf("(No replacements done)");
                    529:        else if (rcnt == 1)
                    530:                ewprintf("(1 replacement done)");
                    531:        else
                    532:                ewprintf("(%d replacements done)", rcnt);
                    533:        return TRUE;
                    534: }
                    535:
                    536: /*
                    537:  * This routine does the real work of a
                    538:  * forward search. The pattern is sitting in the external
                    539:  * variable "pat". If found, dot is updated, the window system
                    540:  * is notified of the change, and TRUE is returned. If the
                    541:  * string isn't found, FALSE is returned.
                    542:  */
1.2     ! millert   543: forwsrch()
        !           544: {
        !           545:        register LINE  *clp;
        !           546:        register int    cbo;
        !           547:        register LINE  *tlp;
        !           548:        register int    tbo;
        !           549:        char           *pp;
        !           550:        register int    c;
1.1       deraadt   551:
                    552:        clp = curwp->w_dotp;
                    553:        cbo = curwp->w_doto;
1.2     ! millert   554:        for (;;) {
1.1       deraadt   555:                if (cbo == llength(clp)) {
1.2     ! millert   556:                        if ((clp = lforw(clp)) == curbp->b_linep)
        !           557:                                break;
1.1       deraadt   558:                        cbo = 0;
                    559:                        c = CCHR('J');
                    560:                } else
                    561:                        c = lgetc(clp, cbo++);
                    562:                if (eq(c, pat[0]) != FALSE) {
                    563:                        tlp = clp;
                    564:                        tbo = cbo;
1.2     ! millert   565:                        pp = &pat[1];
1.1       deraadt   566:                        while (*pp != 0) {
                    567:                                if (tbo == llength(tlp)) {
                    568:                                        tlp = lforw(tlp);
                    569:                                        if (tlp == curbp->b_linep)
                    570:                                                goto fail;
                    571:                                        tbo = 0;
                    572:                                        c = CCHR('J');
                    573:                                } else
                    574:                                        c = lgetc(tlp, tbo++);
                    575:                                if (eq(c, *pp++) == FALSE)
                    576:                                        goto fail;
                    577:                        }
1.2     ! millert   578:                        curwp->w_dotp = tlp;
        !           579:                        curwp->w_doto = tbo;
1.1       deraadt   580:                        curwp->w_flag |= WFMOVE;
                    581:                        return TRUE;
                    582:                }
1.2     ! millert   583: fail:          ;
1.1       deraadt   584:        }
                    585:        return FALSE;
                    586: }
                    587:
                    588: /*
                    589:  * This routine does the real work of a
                    590:  * backward search. The pattern is sitting in the external
                    591:  * variable "pat". If found, dot is updated, the window system
                    592:  * is notified of the change, and TRUE is returned. If the
                    593:  * string isn't found, FALSE is returned.
                    594:  */
1.2     ! millert   595: backsrch()
        !           596: {
        !           597:        register LINE  *clp;
        !           598:        register int    cbo;
        !           599:        register LINE  *tlp;
        !           600:        register int    tbo;
        !           601:        register int    c;
        !           602:        register char  *epp;
        !           603:        register char  *pp;
1.1       deraadt   604:
1.2     ! millert   605:        for (epp = &pat[0]; epp[1] != 0; ++epp);
1.1       deraadt   606:        clp = curwp->w_dotp;
                    607:        cbo = curwp->w_doto;
                    608:        for (;;) {
                    609:                if (cbo == 0) {
                    610:                        clp = lback(clp);
                    611:                        if (clp == curbp->b_linep)
                    612:                                return FALSE;
1.2     ! millert   613:                        cbo = llength(clp) + 1;
1.1       deraadt   614:                }
                    615:                if (--cbo == llength(clp))
                    616:                        c = CCHR('J');
                    617:                else
1.2     ! millert   618:                        c = lgetc(clp, cbo);
1.1       deraadt   619:                if (eq(c, *epp) != FALSE) {
                    620:                        tlp = clp;
                    621:                        tbo = cbo;
1.2     ! millert   622:                        pp = epp;
1.1       deraadt   623:                        while (pp != &pat[0]) {
                    624:                                if (tbo == 0) {
                    625:                                        tlp = lback(tlp);
                    626:                                        if (tlp == curbp->b_linep)
                    627:                                                goto fail;
1.2     ! millert   628:                                        tbo = llength(tlp) + 1;
1.1       deraadt   629:                                }
                    630:                                if (--tbo == llength(tlp))
                    631:                                        c = CCHR('J');
                    632:                                else
1.2     ! millert   633:                                        c = lgetc(tlp, tbo);
1.1       deraadt   634:                                if (eq(c, *--pp) == FALSE)
                    635:                                        goto fail;
                    636:                        }
1.2     ! millert   637:                        curwp->w_dotp = tlp;
        !           638:                        curwp->w_doto = tbo;
1.1       deraadt   639:                        curwp->w_flag |= WFMOVE;
                    640:                        return TRUE;
                    641:                }
1.2     ! millert   642: fail:          ;
1.1       deraadt   643:        }
1.2     ! millert   644:        /* NOTREACHED */
1.1       deraadt   645: }
                    646:
                    647: /*
                    648:  * Compare two characters.
                    649:  * The "bc" comes from the buffer.
                    650:  * It has its case folded out. The
                    651:  * "pc" is from the pattern.
                    652:  */
                    653: static int
                    654: eq(bc, pc)
1.2     ! millert   655:        register int    bc, pc;
1.1       deraadt   656: {
                    657:        bc = CHARMASK(bc);
                    658:        pc = CHARMASK(pc);
1.2     ! millert   659:        if (bc == pc)
        !           660:                return TRUE;
        !           661:        if (ISUPPER(bc))
        !           662:                return TOLOWER(bc) == pc;
        !           663:        if (ISUPPER(pc))
        !           664:                return bc == TOLOWER(pc);
1.1       deraadt   665:        return FALSE;
                    666: }
                    667:
                    668: /*
                    669:  * Read a pattern.
                    670:  * Stash it in the external variable "pat". The "pat" is
                    671:  * not updated if the user types in an empty line. If the user typed
                    672:  * an empty line, and there is no old pattern, it is an error.
                    673:  * Display the old pattern, in the style of Jeff Lomicka. There is
                    674:  * some do-it-yourself control expansion.
                    675:  */
1.2     ! millert   676: readpattern(prompt)
        !           677:        char           *prompt;
        !           678: {
        !           679:        register int    s;
        !           680:        char            tpat[NPAT];
1.1       deraadt   681:
1.2     ! millert   682:        if (tpat[0] == '\0')
        !           683:                s = ereply("%s: ", tpat, NPAT, prompt);
        !           684:        else
        !           685:                s = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
1.1       deraadt   686:
1.2     ! millert   687:        if (s == TRUE)          /* Specified             */
1.1       deraadt   688:                (VOID) strcpy(pat, tpat);
1.2     ! millert   689:        else if (s == FALSE && pat[0] != 0)     /* CR, but old one       */
1.1       deraadt   690:                s = TRUE;
                    691:        return s;
                    692: }