[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.1

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:
        !            16: #define SRCH_BEGIN     (0)                     /* Search sub-codes.    */
        !            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:
        !            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();
        !            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:  */
        !            51: /*ARGSUSED*/
        !            52: forwsearch(f, n)
        !            53: {
        !            54:        register int    s;
        !            55:
        !            56:        if ((s=readpattern("Search")) != TRUE)
        !            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:  */
        !            73: /*ARGSUSED*/
        !            74: backsearch(f, n)
        !            75: {
        !            76:        register int    s;
        !            77:
        !            78:        if ((s=readpattern("Search backward")) != TRUE)
        !            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:  */
        !            94: /*ARGSUSED*/
        !            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:  */
        !           119: /*ARGSUSED*/
        !           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:  */
        !           129: /*ARGSUSED*/
        !           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:  */
        !           146: isearch(dir) {
        !           147:        register int    c;
        !           148:        register LINE   *clp;
        !           149:        register int    cbo;
        !           150:        register int    success;
        !           151:        int             pptr;
        !           152:        char            opat[NPAT];
        !           153:        VOID            ungetkey();
        !           154:
        !           155: #ifndef NO_MACRO
        !           156:        if(macrodef) {
        !           157:            ewprintf("Can't isearch in macro");
        !           158:            return FALSE;
        !           159:        }
        !           160: #endif
        !           161:        for (cip=0; cip<NSRCH; cip++)
        !           162:                cmds[cip].s_code = SRCH_NOPR;
        !           163:        (VOID) strcpy(opat, pat);
        !           164:        cip = 0;
        !           165:        pptr = -1;
        !           166:        clp = curwp->w_dotp;
        !           167:        cbo = curwp->w_doto;
        !           168:        is_lpush();
        !           169:        is_cpush(SRCH_BEGIN);
        !           170:        success = TRUE;
        !           171:        is_prompt(dir, TRUE, success);
        !           172:        for (;;) {
        !           173:                update();
        !           174:                switch (c = getkey(FALSE)) {
        !           175:                case CCHR('['):
        !           176:                        srch_lastdir = dir;
        !           177:                        curwp->w_markp = clp;
        !           178:                        curwp->w_marko = cbo;
        !           179:                        ewprintf("Mark set");
        !           180:                        return (TRUE);
        !           181:
        !           182:                case CCHR('G'):
        !           183:                        if (success != TRUE) {
        !           184:                                while (is_peek() == SRCH_ACCM)
        !           185:                                        is_undo(&pptr, &dir);
        !           186:                                success = TRUE;
        !           187:                                is_prompt(dir, pptr < 0, success);
        !           188:                                break;
        !           189:                        }
        !           190:                        curwp->w_dotp = clp;
        !           191:                        curwp->w_doto = cbo;
        !           192:                        curwp->w_flag |= WFMOVE;
        !           193:                        srch_lastdir = dir;
        !           194:                        (VOID) ctrlg(FFRAND, 0);
        !           195:                        (VOID) strcpy(pat, opat);
        !           196:                        return ABORT;
        !           197:
        !           198:                case CCHR(']'):
        !           199:                case CCHR('S'):
        !           200:                        if (dir == SRCH_BACK) {
        !           201:                                dir = SRCH_FORW;
        !           202:                                is_lpush();
        !           203:                                is_cpush(SRCH_FORW);
        !           204:                                success = TRUE;
        !           205:                        }
        !           206:                        if (success==FALSE && dir==SRCH_FORW)
        !           207:                                break;
        !           208:                        is_lpush();
        !           209:                        pptr = strlen(pat);
        !           210:                        (VOID) forwchar(FFRAND, 1);
        !           211:                        if (is_find(SRCH_FORW) != FALSE) is_cpush(SRCH_MARK);
        !           212:                        else {
        !           213:                                (VOID) backchar(FFRAND, 1);
        !           214:                                ttbeep();
        !           215:                                success = FALSE;
        !           216:                        }
        !           217:                        is_prompt(dir, pptr < 0, success);
        !           218:                        break;
        !           219:
        !           220:                case CCHR('R'):
        !           221:                        if (dir == SRCH_FORW) {
        !           222:                                dir = SRCH_BACK;
        !           223:                                is_lpush();
        !           224:                                is_cpush(SRCH_BACK);
        !           225:                                success = TRUE;
        !           226:                        }
        !           227:                        if (success==FALSE && dir==SRCH_BACK)
        !           228:                                break;
        !           229:                        is_lpush();
        !           230:                        pptr = strlen(pat);
        !           231:                        (VOID) backchar(FFRAND, 1);
        !           232:                        if (is_find(SRCH_BACK) != FALSE) is_cpush(SRCH_MARK);
        !           233:                        else {
        !           234:                                (VOID) forwchar(FFRAND, 1);
        !           235:                                ttbeep();
        !           236:                                success = FALSE;
        !           237:                        }
        !           238:                        is_prompt(dir, pptr < 0, success);
        !           239:                        break;
        !           240:
        !           241:                case CCHR('H'):
        !           242:                case CCHR('?'):
        !           243:                        is_undo(&pptr, &dir);
        !           244:                        if (is_peek() != SRCH_ACCM) success = TRUE;
        !           245:                        is_prompt(dir, pptr < 0, success);
        !           246:                        break;
        !           247:
        !           248:                case CCHR('\\'):
        !           249:                case CCHR('Q'):
        !           250:                        c = (char) getkey(FALSE);
        !           251:                        goto  addchar;
        !           252:                case CCHR('M'):
        !           253:                        c = CCHR('J');
        !           254:                        goto  addchar;
        !           255:
        !           256:                default:
        !           257:                        if (ISCTRL(c)) {
        !           258:                                ungetkey(c);
        !           259:                                curwp->w_markp = clp;
        !           260:                                curwp->w_marko = cbo;
        !           261:                                ewprintf("Mark set");
        !           262:                                curwp->w_flag |= WFMOVE;
        !           263:                                return  TRUE;
        !           264:                        }       /* and continue */
        !           265:                case CCHR('I'):
        !           266:                case CCHR('J'):
        !           267:                addchar:
        !           268:                        if (pptr == -1)
        !           269:                                pptr = 0;
        !           270:                        if (pptr == 0)
        !           271:                                success = TRUE;
        !           272:                        pat[pptr++] = c;
        !           273:                        if (pptr == NPAT) {
        !           274:                                ewprintf("Pattern too long");
        !           275:                                return FALSE;
        !           276:                        }
        !           277:                        pat[pptr] = '\0';
        !           278:                        is_lpush();
        !           279:                        if (success != FALSE) {
        !           280:                                if (is_find(dir) != FALSE)
        !           281:                                        is_cpush(c);
        !           282:                                else {
        !           283:                                        success = FALSE;
        !           284:                                        ttbeep();
        !           285:                                        is_cpush(SRCH_ACCM);
        !           286:                                }
        !           287:                        } else
        !           288:                                is_cpush(SRCH_ACCM);
        !           289:                        is_prompt(dir, FALSE, success);
        !           290:                }
        !           291:        }
        !           292:        /*NOTREACHED*/
        !           293: }
        !           294:
        !           295: static VOID
        !           296: is_cpush(cmd) register int cmd; {
        !           297:        if (++cip >= NSRCH)
        !           298:                cip = 0;
        !           299:        cmds[cip].s_code = cmd;
        !           300: }
        !           301:
        !           302: static VOID
        !           303: is_lpush() {
        !           304:        register int    ctp;
        !           305:
        !           306:        ctp = cip+1;
        !           307:        if (ctp >= NSRCH)
        !           308:                ctp = 0;
        !           309:        cmds[ctp].s_code = SRCH_NOPR;
        !           310:        cmds[ctp].s_doto = curwp->w_doto;
        !           311:        cmds[ctp].s_dotp = curwp->w_dotp;
        !           312: }
        !           313:
        !           314: static VOID
        !           315: is_pop() {
        !           316:        if (cmds[cip].s_code != SRCH_NOPR) {
        !           317:                curwp->w_doto  = cmds[cip].s_doto;
        !           318:                curwp->w_dotp  = cmds[cip].s_dotp;
        !           319:                curwp->w_flag |= WFMOVE;
        !           320:                cmds[cip].s_code = SRCH_NOPR;
        !           321:        }
        !           322:        if (--cip <= 0)
        !           323:                cip = NSRCH-1;
        !           324: }
        !           325:
        !           326: static int
        !           327: is_peek() {
        !           328:        return cmds[cip].s_code;
        !           329: }
        !           330:
        !           331: /* this used to always return TRUE (the return value was checked) */
        !           332: static VOID
        !           333: is_undo(pptr, dir) register int *pptr; register int *dir; {
        !           334:        register int    redo = FALSE ;
        !           335:        switch (cmds[cip].s_code) {
        !           336:        case SRCH_BEGIN:
        !           337:        case SRCH_NOPR:
        !           338:                *pptr = -1;
        !           339:        case SRCH_MARK:
        !           340:                break;
        !           341:
        !           342:        case SRCH_FORW:
        !           343:                *dir = SRCH_BACK;
        !           344:                redo = TRUE;
        !           345:                break;
        !           346:
        !           347:        case SRCH_BACK:
        !           348:                *dir = SRCH_FORW;
        !           349:                redo = TRUE;
        !           350:                break;
        !           351:
        !           352:        case SRCH_ACCM:
        !           353:        default:
        !           354:                *pptr -= 1;
        !           355:                if (*pptr < 0)
        !           356:                        *pptr = 0;
        !           357:                pat[*pptr] = '\0';
        !           358:                break;
        !           359:        }
        !           360:        is_pop();
        !           361:        if (redo) is_undo(pptr, dir);
        !           362: }
        !           363:
        !           364: static int
        !           365: is_find(dir) register int dir; {
        !           366:        register int    plen, odoto;
        !           367:        register LINE   *odotp ;
        !           368:
        !           369:        odoto = curwp->w_doto;
        !           370:        odotp = curwp->w_dotp;
        !           371:        plen = strlen(pat);
        !           372:        if (plen != 0) {
        !           373:                if (dir==SRCH_FORW) {
        !           374:                        (VOID) backchar(FFARG | FFRAND, plen);
        !           375:                        if (forwsrch() == FALSE) {
        !           376:                                curwp->w_doto = odoto;
        !           377:                                curwp->w_dotp = odotp;
        !           378:                                return FALSE;
        !           379:                        }
        !           380:                        return TRUE;
        !           381:                }
        !           382:                if (dir==SRCH_BACK) {
        !           383:                        (VOID) forwchar(FFARG | FFRAND, plen);
        !           384:                        if (backsrch() == FALSE) {
        !           385:                                curwp->w_doto = odoto;
        !           386:                                curwp->w_dotp = odotp;
        !           387:                                return FALSE;
        !           388:                        }
        !           389:                        return TRUE;
        !           390:                }
        !           391:                ewprintf("bad call to is_find");
        !           392:                return FALSE;
        !           393:        }
        !           394:        return FALSE;
        !           395: }
        !           396:
        !           397: /*
        !           398:  * If called with "dir" not one of SRCH_FORW
        !           399:  * or SRCH_BACK, this routine used to print an error
        !           400:  * message. It also used to return TRUE or FALSE,
        !           401:  * depending on if it liked the "dir". However, none
        !           402:  * of the callers looked at the status, so I just
        !           403:  * made the checking vanish.
        !           404:  */
        !           405: static VOID
        !           406: is_prompt(dir, flag, success) {
        !           407:        if (dir == SRCH_FORW) {
        !           408:                if (success != FALSE)
        !           409:                        is_dspl("I-search", flag);
        !           410:                else
        !           411:                        is_dspl("Failing I-search", flag);
        !           412:        } else if (dir == SRCH_BACK) {
        !           413:                if (success != FALSE)
        !           414:                        is_dspl("I-search backward", flag);
        !           415:                else
        !           416:                        is_dspl("Failing I-search backward", flag);
        !           417:        } else ewprintf("Broken call to is_prompt");
        !           418: }
        !           419:
        !           420: /*
        !           421:  * Prompt writing routine for the incremental search.
        !           422:  * The "prompt" is just a string. The "flag" determines
        !           423:  * whether pat should be printed.
        !           424:  */
        !           425: static VOID
        !           426: is_dspl(prompt, flag) char *prompt; {
        !           427:
        !           428:        if (flag != FALSE)
        !           429:                ewprintf("%s: ", prompt);
        !           430:        else
        !           431:                ewprintf("%s: %s", prompt, pat);
        !           432: }
        !           433:
        !           434: /*
        !           435:  * Query Replace.
        !           436:  *     Replace strings selectively.  Does a search and replace operation.
        !           437:  */
        !           438: /*ARGSUSED*/
        !           439: queryrepl(f, n)
        !           440: {
        !           441:        register int    s;
        !           442:        register int    rcnt = 0;       /* Replacements made so far     */
        !           443:        register int    plen;           /* length of found string       */
        !           444:        char            news[NPAT];     /* replacement string           */
        !           445:
        !           446: #ifndef NO_MACRO
        !           447:        if(macrodef) {
        !           448:            ewprintf("Can't query replace in macro");
        !           449:            return FALSE;
        !           450:        }
        !           451: #endif
        !           452:        if ((s=readpattern("Query replace")) != TRUE)
        !           453:                return (s);
        !           454:        if ((s=ereply("Query replace %s with: ",news, NPAT, pat)) == ABORT)
        !           455:                return (s);
        !           456:        if (s == FALSE)
        !           457:                news[0] = '\0';
        !           458:        ewprintf("Query replacing %s with %s:", pat, news);
        !           459:        plen = strlen(pat);
        !           460:
        !           461:        /*
        !           462:         * Search forward repeatedly, checking each time whether to insert
        !           463:         * or not.  The "!" case makes the check always true, so it gets put
        !           464:         * into a tighter loop for efficiency.
        !           465:         */
        !           466:
        !           467:        while (forwsrch() == TRUE) {
        !           468:        retry:
        !           469:                update();
        !           470:                switch (getkey(FALSE)) {
        !           471:                case ' ':
        !           472:                        if (lreplace((RSIZE) plen, news, f) == FALSE)
        !           473:                                return (FALSE);
        !           474:                        rcnt++;
        !           475:                        break;
        !           476:
        !           477:                case '.':
        !           478:                        if (lreplace((RSIZE) plen, news, f) == FALSE)
        !           479:                                return (FALSE);
        !           480:                        rcnt++;
        !           481:                        goto stopsearch;
        !           482:
        !           483:                case CCHR('G'): /* ^G or ESC */
        !           484:                        (VOID) ctrlg(FFRAND, 0);
        !           485:                case CCHR('['):
        !           486:                        goto stopsearch;
        !           487:
        !           488:                case '!':
        !           489:                        do {
        !           490:                                if (lreplace((RSIZE) plen, news, f) == FALSE)
        !           491:                                        return (FALSE);
        !           492:                                rcnt++;
        !           493:                        } while (forwsrch() == TRUE);
        !           494:                        goto stopsearch;
        !           495:
        !           496:                case CCHR('H'):
        !           497:                case CCHR('?'):         /* To not replace */
        !           498:                        break;
        !           499:
        !           500:                default:
        !           501: ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
        !           502:                        goto retry;
        !           503:                }
        !           504:        }
        !           505: stopsearch:
        !           506:        curwp->w_flag |= WFHARD;
        !           507:        update();
        !           508:        if (rcnt == 0)
        !           509:                ewprintf("(No replacements done)");
        !           510:        else if (rcnt == 1)
        !           511:                ewprintf("(1 replacement done)");
        !           512:        else
        !           513:                ewprintf("(%d replacements done)", rcnt);
        !           514:        return TRUE;
        !           515: }
        !           516:
        !           517: /*
        !           518:  * This routine does the real work of a
        !           519:  * forward search. The pattern is sitting in the external
        !           520:  * variable "pat". If found, dot is updated, the window system
        !           521:  * is notified of the change, and TRUE is returned. If the
        !           522:  * string isn't found, FALSE is returned.
        !           523:  */
        !           524: forwsrch() {
        !           525:        register LINE   *clp;
        !           526:        register int    cbo;
        !           527:        register LINE   *tlp;
        !           528:        register int    tbo;
        !           529:        char            *pp;
        !           530:        register int    c;
        !           531:
        !           532:        clp = curwp->w_dotp;
        !           533:        cbo = curwp->w_doto;
        !           534:        for(;;) {
        !           535:                if (cbo == llength(clp)) {
        !           536:                        if((clp = lforw(clp)) == curbp->b_linep) break;
        !           537:                        cbo = 0;
        !           538:                        c = CCHR('J');
        !           539:                } else
        !           540:                        c = lgetc(clp, cbo++);
        !           541:                if (eq(c, pat[0]) != FALSE) {
        !           542:                        tlp = clp;
        !           543:                        tbo = cbo;
        !           544:                        pp  = &pat[1];
        !           545:                        while (*pp != 0) {
        !           546:                                if (tbo == llength(tlp)) {
        !           547:                                        tlp = lforw(tlp);
        !           548:                                        if (tlp == curbp->b_linep)
        !           549:                                                goto fail;
        !           550:                                        tbo = 0;
        !           551:                                        c = CCHR('J');
        !           552:                                } else
        !           553:                                        c = lgetc(tlp, tbo++);
        !           554:                                if (eq(c, *pp++) == FALSE)
        !           555:                                        goto fail;
        !           556:                        }
        !           557:                        curwp->w_dotp  = tlp;
        !           558:                        curwp->w_doto  = tbo;
        !           559:                        curwp->w_flag |= WFMOVE;
        !           560:                        return TRUE;
        !           561:                }
        !           562:        fail:   ;
        !           563:        }
        !           564:        return FALSE;
        !           565: }
        !           566:
        !           567: /*
        !           568:  * This routine does the real work of a
        !           569:  * backward search. The pattern is sitting in the external
        !           570:  * variable "pat". If found, dot is updated, the window system
        !           571:  * is notified of the change, and TRUE is returned. If the
        !           572:  * string isn't found, FALSE is returned.
        !           573:  */
        !           574: backsrch() {
        !           575:        register LINE   *clp;
        !           576:        register int    cbo;
        !           577:        register LINE   *tlp;
        !           578:        register int    tbo;
        !           579:        register int    c;
        !           580:        register char   *epp;
        !           581:        register char   *pp;
        !           582:
        !           583:        for (epp = &pat[0]; epp[1] != 0; ++epp)
        !           584:                ;
        !           585:        clp = curwp->w_dotp;
        !           586:        cbo = curwp->w_doto;
        !           587:        for (;;) {
        !           588:                if (cbo == 0) {
        !           589:                        clp = lback(clp);
        !           590:                        if (clp == curbp->b_linep)
        !           591:                                return FALSE;
        !           592:                        cbo = llength(clp)+1;
        !           593:                }
        !           594:                if (--cbo == llength(clp))
        !           595:                        c = CCHR('J');
        !           596:                else
        !           597:                        c = lgetc(clp,cbo);
        !           598:                if (eq(c, *epp) != FALSE) {
        !           599:                        tlp = clp;
        !           600:                        tbo = cbo;
        !           601:                        pp  = epp;
        !           602:                        while (pp != &pat[0]) {
        !           603:                                if (tbo == 0) {
        !           604:                                        tlp = lback(tlp);
        !           605:                                        if (tlp == curbp->b_linep)
        !           606:                                                goto fail;
        !           607:                                        tbo = llength(tlp)+1;
        !           608:                                }
        !           609:                                if (--tbo == llength(tlp))
        !           610:                                        c = CCHR('J');
        !           611:                                else
        !           612:                                        c = lgetc(tlp,tbo);
        !           613:                                if (eq(c, *--pp) == FALSE)
        !           614:                                        goto fail;
        !           615:                        }
        !           616:                        curwp->w_dotp  = tlp;
        !           617:                        curwp->w_doto  = tbo;
        !           618:                        curwp->w_flag |= WFMOVE;
        !           619:                        return TRUE;
        !           620:                }
        !           621:        fail:   ;
        !           622:        }
        !           623:        /*NOTREACHED*/
        !           624: }
        !           625:
        !           626: /*
        !           627:  * Compare two characters.
        !           628:  * The "bc" comes from the buffer.
        !           629:  * It has its case folded out. The
        !           630:  * "pc" is from the pattern.
        !           631:  */
        !           632: static int
        !           633: eq(bc, pc)
        !           634: register int bc, pc;
        !           635: {
        !           636:        bc = CHARMASK(bc);
        !           637:        pc = CHARMASK(pc);
        !           638:        if (bc == pc) return TRUE;
        !           639:        if (ISUPPER(bc)) return TOLOWER(bc) == pc;
        !           640:        if (ISUPPER(pc)) return bc == TOLOWER(pc);
        !           641:        return FALSE;
        !           642: }
        !           643:
        !           644: /*
        !           645:  * Read a pattern.
        !           646:  * Stash it in the external variable "pat". The "pat" is
        !           647:  * not updated if the user types in an empty line. If the user typed
        !           648:  * an empty line, and there is no old pattern, it is an error.
        !           649:  * Display the old pattern, in the style of Jeff Lomicka. There is
        !           650:  * some do-it-yourself control expansion.
        !           651:  */
        !           652: readpattern(prompt) char *prompt; {
        !           653:        register int    s;
        !           654:        char            tpat[NPAT];
        !           655:
        !           656:        if (tpat[0] == '\0') s = ereply("%s: ", tpat, NPAT, prompt);
        !           657:        else s = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
        !           658:
        !           659:        if (s == TRUE)                          /* Specified            */
        !           660:                (VOID) strcpy(pat, tpat);
        !           661:        else if (s==FALSE && pat[0]!=0)         /* CR, but old one      */
        !           662:                s = TRUE;
        !           663:        return s;
        !           664: }