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

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