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

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