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

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