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

Annotation of src/usr.bin/mg/re_search.c, Revision 1.13

1.13    ! vincent     1: /*     $OpenBSD: re_search.c,v 1.12 2003/05/20 03:08:55 cloder Exp $   */
1.7       niklas      2:
1.1       deraadt     3: /*
1.6       millert     4:  *     regular expression search commands for Mg
1.1       deraadt     5:  *
1.6       millert     6:  * This file contains functions to implement several of gnuemacs's regular
                      7:  * expression functions for Mg.  Several of the routines below are just minor
                      8:  * re-arrangements of Mg's non-regular expression search functions.  Some of
1.9       mickey      9:  * them are similar in structure to the original MicroEMACS, others are
1.6       millert    10:  * modifications of Rich Ellison's code.  Peter Newton re-wrote about half of
                     11:  * them from scratch.
1.1       deraadt    12:  */
                     13:
1.6       millert    14: #ifdef REGEX
1.2       millert    15: #include <sys/types.h>
                     16: #include <regex.h>
                     17:
1.6       millert    18: #include "def.h"
                     19: #include "macro.h"
1.1       deraadt    20:
1.6       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.6       millert    28: #define RE_NMATCH      10              /* max number of matches            */
                     29: #define REPLEN         256             /* max length of replacement string */
1.2       millert    30:
1.6       millert    31: char   re_pat[NPAT];                   /* regex pattern                    */
                     32: int    re_srch_lastdir = SRCH_NOPR;    /* last search flags                */
                     33: int    casefoldsearch = TRUE;          /* does search ignore case?         */
                     34:
1.11      millert    35: static int      re_doreplace(RSIZE, char *, int);
                     36: static int      re_forwsrch(void);
                     37: static int      re_backsrch(void);
                     38: static int      re_readpattern(char *);
                     39: static int      killmatches(int);
                     40: static int      countmatches(int);
1.1       deraadt    41:
                     42: /*
                     43:  * Search forward.
1.9       mickey     44:  * Get a search string from the user and search for it starting at ".".  If
                     45:  * found, move "." to just after the matched characters.  display does all
1.6       millert    46:  * the hard stuff.  If not found, it just prints a message.
1.1       deraadt    47:  */
1.5       millert    48: /* ARGSUSED */
1.6       millert    49: int
1.12      cloder     50: re_forwsearch(int f, int n)
1.5       millert    51: {
1.6       millert    52:        int     s;
1.1       deraadt    53:
1.5       millert    54:        if ((s = re_readpattern("RE Search")) != TRUE)
1.1       deraadt    55:                return (s);
                     56:        if (re_forwsrch() == FALSE) {
                     57:                ewprintf("Search failed: \"%s\"", re_pat);
                     58:                return (FALSE);
                     59:        }
                     60:        re_srch_lastdir = SRCH_FORW;
                     61:        return (TRUE);
                     62: }
                     63:
                     64: /*
                     65:  * Reverse search.
                     66:  * Get a search string from the         user, and search, starting at "."
                     67:  * and proceeding toward the front of the buffer. If found "." is left
                     68:  * pointing at the first character of the pattern [the last character that
                     69:  * was matched].
                     70:  */
1.5       millert    71: /* ARGSUSED */
1.6       millert    72: int
1.12      cloder     73: re_backsearch(int f, int n)
1.5       millert    74: {
1.6       millert    75:        int     s;
1.1       deraadt    76:
1.5       millert    77:        if ((s = re_readpattern("RE Search backward")) != TRUE)
1.1       deraadt    78:                return (s);
                     79:        if (re_backsrch() == FALSE) {
                     80:                ewprintf("Search failed: \"%s\"", re_pat);
                     81:                return (FALSE);
                     82:        }
                     83:        re_srch_lastdir = SRCH_BACK;
                     84:        return (TRUE);
                     85: }
                     86:
                     87: /*
1.9       mickey     88:  * Search again, using the same search string and direction as the last search
                     89:  * command.  The direction has been saved in "srch_lastdir", so you know which
1.6       millert    90:  * way to go.
                     91:  *
                     92:  * XXX: This code has problems -- some incompatibility(?) with extend.c causes
                     93:  * match to fail when it should not.
1.1       deraadt    94:  */
1.5       millert    95: /* ARGSUSED */
1.6       millert    96: int
1.12      cloder     97: re_searchagain(int f, int n)
1.5       millert    98: {
                     99:        if (re_srch_lastdir == SRCH_NOPR) {
                    100:                ewprintf("No last search");
                    101:                return (FALSE);
                    102:        }
                    103:        if (re_srch_lastdir == SRCH_FORW) {
                    104:                if (re_forwsrch() == FALSE) {
                    105:                        ewprintf("Search failed: \"%s\"", re_pat);
                    106:                        return (FALSE);
                    107:                }
                    108:                return (TRUE);
                    109:        }
1.9       mickey    110:        if (re_srch_lastdir == SRCH_BACK)
1.5       millert   111:                if (re_backsrch() == FALSE) {
                    112:                        ewprintf("Search failed: \"%s\"", re_pat);
                    113:                        return (FALSE);
                    114:                }
1.6       millert   115:
                    116:        return (TRUE);
1.1       deraadt   117: }
                    118:
                    119: /* Compiled regex goes here-- changed only when new pattern read */
1.6       millert   120: static regex_t         re_buff;
                    121: static regmatch_t      re_match[RE_NMATCH];
1.1       deraadt   122:
                    123: /*
                    124:  * Re-Query Replace.
                    125:  *     Replace strings selectively.  Does a search and replace operation.
                    126:  */
1.5       millert   127: /* ARGSUSED */
1.6       millert   128: int
1.12      cloder    129: re_queryrepl(int f, int n)
1.5       millert   130: {
1.6       millert   131:        int     rcnt = 0;       /* replacements made so far     */
1.13    ! vincent   132:        int     plen, s;                /* length of found string       */
        !           133:        char    news[NPAT], *rep;       /* replacement string           */
1.1       deraadt   134:
                    135:        /* Casefold check */
1.5       millert   136:        if (!casefoldsearch)
                    137:                f = TRUE;
1.1       deraadt   138:
1.5       millert   139:        if ((s = re_readpattern("RE Query replace")) != TRUE)
1.1       deraadt   140:                return (s);
1.13    ! vincent   141:        if ((rep =
        !           142:            ereply("Query replace %s with: ", news, NPAT, re_pat)) == NULL)
        !           143:                return (ABORT);
1.1       deraadt   144:        ewprintf("Query replacing %s with %s:", re_pat, news);
                    145:
                    146:        /*
                    147:         * Search forward repeatedly, checking each time whether to insert
                    148:         * or not.  The "!" case makes the check always true, so it gets put
                    149:         * into a tighter loop for efficiency.
                    150:         */
                    151:        while (re_forwsrch() == TRUE) {
1.5       millert   152: retry:
1.1       deraadt   153:                update();
                    154:                switch (getkey(FALSE)) {
                    155:                case ' ':
1.2       millert   156:                        plen = re_match[0].rm_eo - re_match[0].rm_so;
1.6       millert   157:                        if (re_doreplace((RSIZE)plen, news, f) == FALSE)
1.1       deraadt   158:                                return (FALSE);
                    159:                        rcnt++;
                    160:                        break;
                    161:
                    162:                case '.':
1.2       millert   163:                        plen = re_match[0].rm_eo - re_match[0].rm_so;
1.6       millert   164:                        if (re_doreplace((RSIZE)plen, news, f) == FALSE)
1.1       deraadt   165:                                return (FALSE);
                    166:                        rcnt++;
                    167:                        goto stopsearch;
                    168:
1.6       millert   169:                case CCHR('G'):                         /* ^G */
1.8       art       170:                        (void)ctrlg(FFRAND, 0);
1.6       millert   171:                case CCHR('['):                         /* ESC */
1.1       deraadt   172:                case '`':
                    173:                        goto stopsearch;
                    174:                case '!':
                    175:                        do {
1.2       millert   176:                                plen = re_match[0].rm_eo - re_match[0].rm_so;
1.6       millert   177:                                if (re_doreplace((RSIZE)plen, news, f) == FALSE)
1.1       deraadt   178:                                        return (FALSE);
                    179:                                rcnt++;
                    180:                        } while (re_forwsrch() == TRUE);
                    181:                        goto stopsearch;
                    182:
1.6       millert   183:                case CCHR('?'):                         /* To not replace */
1.1       deraadt   184:                        break;
                    185:
                    186:                default:
1.5       millert   187:                        ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
1.1       deraadt   188:                        goto retry;
                    189:                }
                    190:        }
1.6       millert   191:
1.1       deraadt   192: stopsearch:
                    193:        curwp->w_flag |= WFHARD;
                    194:        update();
                    195:        if (!inmacro) {
                    196:                if (rcnt == 0)
                    197:                        ewprintf("(No replacements done)");
                    198:                else if (rcnt == 1)
                    199:                        ewprintf("(1 replacement done)");
                    200:                else
                    201:                        ewprintf("(%d replacements done)", rcnt);
                    202:        }
                    203:        return TRUE;
                    204: }
                    205:
1.5       millert   206: /*
                    207:  * Routine re_doreplace calls lreplace to make replacements needed by
                    208:  * re_query replace.  Its reason for existence is to deal with \1, \2. etc.
1.12      cloder    209:  *  plen: length to remove
                    210:  *  st:   replacement string
                    211:  *  f:    case hack disable
1.1       deraadt   212:  */
1.6       millert   213: static int
1.12      cloder    214: re_doreplace(RSIZE plen, char *st, int f)
1.6       millert   215: {
                    216:        int      j, k, s, more, num, state;
                    217:        LINE    *clp;
                    218:        char     repstr[REPLEN];
1.5       millert   219:
                    220:        clp = curwp->w_dotp;
                    221:        more = TRUE;
                    222:        j = 0;
                    223:        state = 0;
1.6       millert   224:        num = 0;
1.5       millert   225:
                    226:        /* The following FSA parses the replacement string */
                    227:        while (more) {
                    228:                switch (state) {
                    229:                case 0:
                    230:                        if (*st == '\\') {
                    231:                                st++;
                    232:                                state = 1;
                    233:                        } else if (*st == '\0')
                    234:                                more = FALSE;
                    235:                        else {
                    236:                                repstr[j] = *st;
                    237:                                j++;
                    238:                                if (j >= REPLEN)
                    239:                                        return (FALSE);
                    240:                                st++;
                    241:                        }
                    242:                        break;
                    243:                case 1:
                    244:                        if (*st >= '0' && *st <= '9') {
                    245:                                num = *st - '0';
                    246:                                st++;
                    247:                                state = 2;
                    248:                        } else if (*st == '\0')
                    249:                                more = FALSE;
                    250:                        else {
                    251:                                repstr[j] = *st;
                    252:                                j++;
                    253:                                if (j >= REPLEN)
                    254:                                        return (FALSE);
                    255:                                st++;
                    256:                                state = 0;
                    257:                        }
                    258:                        break;
                    259:                case 2:
                    260:                        if (*st >= '0' && *st <= '9') {
                    261:                                num = 10 * num + *st - '0';
                    262:                                st++;
                    263:                        } else {
                    264:                                if (num >= RE_NMATCH)
                    265:                                        return (FALSE);
                    266:                                k = re_match[num].rm_eo - re_match[num].rm_so;
                    267:                                if (j + k >= REPLEN)
                    268:                                        return (FALSE);
1.9       mickey    269:                                bcopy(&(clp->l_text[re_match[num].rm_so]),
1.6       millert   270:                                    &repstr[j], k);
1.5       millert   271:                                j += k;
                    272:                                if (*st == '\0')
                    273:                                        more = FALSE;
                    274:                                if (*st == '\\') {
                    275:                                        st++;
                    276:                                        state = 1;
                    277:                                } else {
                    278:                                        repstr[j] = *st;
                    279:                                        j++;
                    280:                                        if (j >= REPLEN)
                    281:                                                return (FALSE);
                    282:                                        st++;
                    283:                                        state = 0;
                    284:                                }
                    285:                        }
                    286:                        break;
1.6       millert   287:                }               /* switch (state) */
                    288:        }                       /* while (more)   */
1.1       deraadt   289:
1.5       millert   290:        repstr[j] = '\0';
                    291:        s = lreplace(plen, repstr, f);
                    292:        return (s);
1.1       deraadt   293: }
                    294:
                    295:
                    296:
                    297: /*
1.9       mickey    298:  * This routine does the real work of a forward search.  The pattern is
                    299:  * sitting in the external variable "pat".  If found, dot is updated, the
1.6       millert   300:  * window system is notified of the change, and TRUE is returned.  If the
1.1       deraadt   301:  * string isn't found, FALSE is returned.
                    302:  */
1.6       millert   303: static int
1.12      cloder    304: re_forwsrch(void)
1.5       millert   305: {
1.6       millert   306:        int      tbo, error;
                    307:        LINE    *clp;
1.5       millert   308:
                    309:        clp = curwp->w_dotp;
                    310:        tbo = curwp->w_doto;
                    311:
                    312:        if (tbo == clp->l_used)
                    313:                /*
1.6       millert   314:                 * Don't start matching past end of line -- must move to
                    315:                 * beginning of next line, unless at end of file.
1.5       millert   316:                 */
                    317:                if (clp != curbp->b_linep) {
                    318:                        clp = lforw(clp);
                    319:                        tbo = 0;
                    320:                }
                    321:        /*
                    322:         * Note this loop does not process the last line, but this editor
                    323:         * always makes the last line empty so this is good.
                    324:         */
                    325:        while (clp != (curbp->b_linep)) {
                    326:                re_match[0].rm_so = tbo;
                    327:                re_match[0].rm_eo = llength(clp);
1.9       mickey    328:                error = regexec(&re_buff, ltext(clp), RE_NMATCH, re_match,
1.6       millert   329:                    REG_STARTEND);
                    330:                if (error != 0) {
1.5       millert   331:                        clp = lforw(clp);
                    332:                        tbo = 0;
                    333:                } else {
                    334:                        curwp->w_doto = re_match[0].rm_eo;
                    335:                        curwp->w_dotp = clp;
                    336:                        curwp->w_flag |= WFMOVE;
                    337:                        return (TRUE);
                    338:                }
                    339:        }
                    340:        return (FALSE);
1.1       deraadt   341: }
                    342:
                    343:
                    344: /*
1.6       millert   345:  * This routine does the real work of a backward search.  The pattern is sitting
1.9       mickey    346:  * in the external variable "re_pat".  If found, dot is updated, the window
                    347:  * system is notified of the change, and TRUE is returned.  If the string isn't
1.6       millert   348:  * found, FALSE is returned.
1.1       deraadt   349:  */
1.6       millert   350: static int
1.12      cloder    351: re_backsrch(void)
1.5       millert   352: {
1.6       millert   353:        LINE            *clp;
                    354:        int              tbo;
                    355:        regmatch_t       lastmatch;
1.5       millert   356:
                    357:        clp = curwp->w_dotp;
                    358:        tbo = curwp->w_doto;
                    359:
                    360:        /* Start search one position to the left of dot */
                    361:        tbo = tbo - 1;
                    362:        if (tbo < 0) {
                    363:                /* must move up one line */
                    364:                clp = lback(clp);
                    365:                tbo = llength(clp);
                    366:        }
1.6       millert   367:
1.5       millert   368:        /*
                    369:         * Note this loop does not process the last line, but this editor
                    370:         * always makes the last line empty so this is good.
                    371:         */
                    372:        while (clp != (curbp->b_linep)) {
                    373:                re_match[0].rm_so = 0;
                    374:                re_match[0].rm_eo = llength(clp);
                    375:                lastmatch.rm_so = -1;
                    376:                /*
                    377:                 * Keep searching until we don't match any longer.  Assumes a
                    378:                 * non-match does not modify the re_match array.  We have to
                    379:                 * do this character-by-character after the first match since
                    380:                 * POSIX regexps don't give you a way to do reverse matches.
                    381:                 */
                    382:                while (!regexec(&re_buff, ltext(clp), RE_NMATCH, re_match,
                    383:                    REG_STARTEND) && re_match[0].rm_so < tbo) {
                    384:                        memcpy(&lastmatch, &re_match[0], sizeof(regmatch_t));
                    385:                        re_match[0].rm_so++;
                    386:                        re_match[0].rm_eo = llength(clp);
                    387:                }
                    388:                if (lastmatch.rm_so == -1) {
                    389:                        clp = lback(clp);
                    390:                        tbo = llength(clp);
                    391:                } else {
                    392:                        memcpy(&re_match[0], &lastmatch, sizeof(regmatch_t));
                    393:                        curwp->w_doto = re_match[0].rm_so;
                    394:                        curwp->w_dotp = clp;
                    395:                        curwp->w_flag |= WFMOVE;
                    396:                        return (TRUE);
                    397:                }
                    398:        }
                    399:        return (FALSE);
1.1       deraadt   400: }
                    401:
                    402:
                    403: /*
                    404:  * Read a pattern.
                    405:  * Stash it in the external variable "re_pat". The "pat" is
                    406:  * not updated if the user types in an empty line. If the user typed
                    407:  * an empty line, and there is no old pattern, it is an error.
                    408:  * Display the old pattern, in the style of Jeff Lomicka. There is
                    409:  * some do-it-yourself control expansion.
                    410:  */
1.6       millert   411: static int
1.12      cloder    412: re_readpattern(char *prompt)
1.5       millert   413: {
1.6       millert   414:        static int      dofree = 0;
1.13    ! vincent   415:        int             flags, error, s;
        !           416:        char            tpat[NPAT], *rep;
1.5       millert   417:
                    418:        if (re_pat[0] == '\0')
1.13    ! vincent   419:                rep = ereply("%s: ", tpat, NPAT, prompt);
1.5       millert   420:        else
1.13    ! vincent   421:                rep = ereply("%s: (default %s) ", tpat, NPAT, prompt, re_pat);
1.1       deraadt   422:
1.13    ! vincent   423:        if (rep != NULL && *rep != '\0') {
1.5       millert   424:                /* New pattern given */
1.10      vincent   425:                (void)strlcpy(re_pat, tpat, sizeof re_pat);
1.5       millert   426:                if (casefoldsearch)
                    427:                        flags = REG_EXTENDED | REG_ICASE;
                    428:                else
                    429:                        flags = REG_EXTENDED;
                    430:                if (dofree)
                    431:                        regfree(&re_buff);
                    432:                error = regcomp(&re_buff, re_pat, flags);
1.6       millert   433:                if (error != 0) {
                    434:                        char    message[256];
1.5       millert   435:                        regerror(error, &re_buff, message, sizeof(message));
                    436:                        ewprintf("Regex Error: %s", message);
                    437:                        re_pat[0] = '\0';
                    438:                        return (FALSE);
                    439:                }
                    440:                dofree = 1;
1.13    ! vincent   441:                s = TRUE;
        !           442:        } else if (rep[0] == '\0' && re_pat[0] != '\0')
1.5       millert   443:                /* Just using old pattern */
                    444:                s = TRUE;
1.13    ! vincent   445:        else
        !           446:                s = FALSE;
1.1       deraadt   447:        return (s);
                    448: }
                    449:
1.5       millert   450: /*
                    451:  * Cause case to not matter in searches.  This is the default. If called
                    452:  * with argument cause case to matter.
1.1       deraadt   453:  */
1.6       millert   454: int
1.12      cloder    455: setcasefold(int f, int n)
1.5       millert   456: {
                    457:        if (f & FFARG) {
                    458:                casefoldsearch = FALSE;
                    459:                ewprintf("Case-fold-search unset");
                    460:        } else {
                    461:                casefoldsearch = TRUE;
                    462:                ewprintf("Case-fold-search set");
                    463:        }
1.1       deraadt   464:
1.5       millert   465:        /*
                    466:         * Invalidate the regular expression pattern since I'm too lazy to
                    467:         * recompile it.
                    468:         */
                    469:        re_pat[0] = '\0';
                    470:        return (TRUE);
1.6       millert   471: }
1.1       deraadt   472:
                    473:
1.5       millert   474: /*
                    475:  * Delete all lines after dot that contain a string matching regex
1.1       deraadt   476:  */
1.6       millert   477: int
1.12      cloder    478: delmatchlines(int f, int n)
1.5       millert   479: {
1.6       millert   480:        int     s;
1.1       deraadt   481:
1.9       mickey    482:        if ((s = re_readpattern("Flush lines (containing match for regexp)"))
1.6       millert   483:            != TRUE)
1.5       millert   484:                return (s);
1.1       deraadt   485:
1.5       millert   486:        s = killmatches(TRUE);
                    487:        return (s);
1.1       deraadt   488: }
                    489:
1.5       millert   490: /*
                    491:  * Delete all lines after dot that don't contain a string matching regex
1.1       deraadt   492:  */
1.6       millert   493: int
1.12      cloder    494: delnonmatchlines(int f, int n)
1.5       millert   495: {
1.6       millert   496:        int     s;
1.1       deraadt   497:
1.9       mickey    498:        if ((s = re_readpattern("Keep lines (containing match for regexp)"))
1.6       millert   499:            != TRUE)
1.5       millert   500:                return (s);
1.1       deraadt   501:
1.5       millert   502:        s = killmatches(FALSE);
                    503:        return (s);
1.1       deraadt   504: }
                    505:
1.9       mickey    506: /*
                    507:  * This function does the work of deleting matching lines
1.6       millert   508:  */
                    509: static int
1.12      cloder    510: killmatches(int cond)
1.1       deraadt   511: {
1.6       millert   512:        int      s, error;
                    513:        int      count = 0;
                    514:        LINE    *clp;
1.5       millert   515:
                    516:        clp = curwp->w_dotp;
                    517:        if (curwp->w_doto == llength(clp))
                    518:                /* Consider dot on next line */
                    519:                clp = lforw(clp);
                    520:
                    521:        while (clp != (curbp->b_linep)) {
                    522:                /* see if line matches */
                    523:                re_match[0].rm_so = 0;
                    524:                re_match[0].rm_eo = llength(clp);
1.9       mickey    525:                error = regexec(&re_buff, ltext(clp), RE_NMATCH, re_match,
1.6       millert   526:                    REG_STARTEND);
1.5       millert   527:
                    528:                /* Delete line when appropriate */
                    529:                if ((cond == FALSE && error) || (cond == TRUE && !error)) {
                    530:                        curwp->w_doto = 0;
                    531:                        curwp->w_dotp = clp;
                    532:                        count++;
                    533:                        s = ldelete(llength(clp) + 1, KNONE);
                    534:                        clp = curwp->w_dotp;
                    535:                        curwp->w_flag |= WFMOVE;
                    536:                        if (s == FALSE)
                    537:                                return (FALSE);
                    538:                } else
                    539:                        clp = lforw(clp);
                    540:        }
1.1       deraadt   541:
1.5       millert   542:        ewprintf("%d line(s) deleted", count);
                    543:        if (count > 0)
                    544:                curwp->w_flag |= WFMOVE;
1.1       deraadt   545:
1.5       millert   546:        return (TRUE);
1.1       deraadt   547: }
                    548:
1.5       millert   549: /*
                    550:  * Count lines matching regex
1.1       deraadt   551:  */
1.6       millert   552: int
1.12      cloder    553: cntmatchlines(int f, int n)
1.5       millert   554: {
1.6       millert   555:        int     s;
1.1       deraadt   556:
1.5       millert   557:        if ((s = re_readpattern("Count lines (matching regexp)")) != TRUE)
                    558:                return (s);
                    559:        s = countmatches(TRUE);
                    560:        return (s);
1.1       deraadt   561: }
                    562:
1.5       millert   563: /*
                    564:  * Count lines that fail to match regex
1.1       deraadt   565:  */
1.6       millert   566: int
1.12      cloder    567: cntnonmatchlines(int f, int n)
1.5       millert   568: {
1.6       millert   569:        int     s;
1.1       deraadt   570:
1.5       millert   571:        if ((s = re_readpattern("Count lines (not matching regexp)")) != TRUE)
                    572:                return (s);
1.1       deraadt   573:
1.5       millert   574:        s = countmatches(FALSE);
1.1       deraadt   575:
1.5       millert   576:        return (s);
1.1       deraadt   577: }
                    578:
1.6       millert   579: /*
                    580:  * This function does the work of counting matching lines.
                    581:  */
                    582: int
1.12      cloder    583: countmatches(int cond)
1.1       deraadt   584: {
1.6       millert   585:        int      error;
                    586:        int      count = 0;
                    587:        LINE    *clp;
1.5       millert   588:
                    589:        clp = curwp->w_dotp;
                    590:        if (curwp->w_doto == llength(clp))
                    591:                /* Consider dot on next line */
                    592:                clp = lforw(clp);
                    593:
                    594:        while (clp != (curbp->b_linep)) {
                    595:                /* see if line matches */
                    596:                re_match[0].rm_so = 0;
                    597:                re_match[0].rm_eo = llength(clp);
1.9       mickey    598:                error = regexec(&re_buff, ltext(clp), RE_NMATCH, re_match,
1.6       millert   599:                    REG_STARTEND);
1.5       millert   600:
                    601:                /* Count line when appropriate */
                    602:                if ((cond == FALSE && error) || (cond == TRUE && !error))
                    603:                        count++;
                    604:                clp = lforw(clp);
                    605:        }
1.1       deraadt   606:
1.5       millert   607:        if (cond)
                    608:                ewprintf("Number of lines matching: %d", count);
                    609:        else
                    610:                ewprintf("Number of lines not matching: %d", count);
                    611:
                    612:        return (TRUE);
1.1       deraadt   613: }
1.6       millert   614: #endif /* REGEX */