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

1.1       deraadt     1: /*
1.5     ! millert     2:  *             regular expression search commands for Mg
1.1       deraadt     3:  *
                      4:  * This file contains functions to implement several of gnuemacs'
1.5     ! millert     5:  * regular expression functions for Mg.  Several of the routines
        !             6:  * below are just minor rearrangements of the Mg non-regular
        !             7:  * expression search functions.  Hence some of them date back in
        !             8:  * essential structure to the original MicroEMACS; others are modifications
1.1       deraadt     9:  * of Rich Ellison's code.  I, Peter Newton, wrote about half from scratch.
                     10:  */
                     11:
                     12:
                     13: #ifdef REGEX
1.2       millert    14: #include <sys/types.h>
                     15: #include <regex.h>
                     16:
1.1       deraadt    17: #include       "def.h"
                     18: #include       "macro.h"
                     19:
1.5     ! millert    20: #define SRCH_BEGIN     (0)     /* Search sub-codes.     */
1.1       deraadt    21: #define SRCH_FORW      (-1)
                     22: #define SRCH_BACK      (-2)
                     23: #define SRCH_NOPR      (-3)
                     24: #define SRCH_ACCM      (-4)
                     25: #define SRCH_MARK      (-5)
                     26:
1.5     ! millert    27: #define RE_NMATCH      10      /* max number of matches */
1.2       millert    28:
1.5     ! millert    29: char            re_pat[NPAT];  /* Regex pattern                 */
        !            30: int             re_srch_lastdir = SRCH_NOPR;   /* Last search flags. */
        !            31: int             casefoldsearch = TRUE; /* Does search ignore case ? */
1.1       deraadt    32:
                     33: /* Indexed by a character, gives the upper case equivalent of the character */
                     34:
1.5     ! millert    35: static char     upcase[0400] =
        !            36: {000, 001, 002, 003, 004, 005, 006, 007,
        !            37:        010, 011, 012, 013, 014, 015, 016, 017,
        !            38:        020, 021, 022, 023, 024, 025, 026, 027,
        !            39:        030, 031, 032, 033, 034, 035, 036, 037,
        !            40:        040, 041, 042, 043, 044, 045, 046, 047,
        !            41:        050, 051, 052, 053, 054, 055, 056, 057,
        !            42:        060, 061, 062, 063, 064, 065, 066, 067,
        !            43:        070, 071, 072, 073, 074, 075, 076, 077,
        !            44:        0100, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
        !            45:        0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
        !            46:        0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
        !            47:        0130, 0131, 0132, 0133, 0134, 0135, 0136, 0137,
        !            48:        0140, 0101, 0102, 0103, 0104, 0105, 0106, 0107,
        !            49:        0110, 0111, 0112, 0113, 0114, 0115, 0116, 0117,
        !            50:        0120, 0121, 0122, 0123, 0124, 0125, 0126, 0127,
        !            51:        0130, 0131, 0132, 0173, 0174, 0175, 0176, 0177,
        !            52:        0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
        !            53:        0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
        !            54:        0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
        !            55:        0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
        !            56:        0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
        !            57:        0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
        !            58:        0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
        !            59:        0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
        !            60:        0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
        !            61:        0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
        !            62:        0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
        !            63:        0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
        !            64:        0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
        !            65:        0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
        !            66:        0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
        !            67:        0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
        !            68: };
1.1       deraadt    69:
                     70: /*
                     71:  * Search forward.
                     72:  * Get a search string from the user, and search for it,
                     73:  * starting at ".". If found, "." gets moved to just after the
                     74:  * matched characters, and display does all the hard stuff.
                     75:  * If not found, it just prints a message.
                     76:  */
1.5     ! millert    77: /* ARGSUSED */
        !            78: re_forwsearch(f, n)
        !            79: {
        !            80:        register int    s;
1.1       deraadt    81:
1.5     ! millert    82:        if ((s = re_readpattern("RE Search")) != TRUE)
1.1       deraadt    83:                return (s);
                     84:        if (re_forwsrch() == FALSE) {
                     85:                ewprintf("Search failed: \"%s\"", re_pat);
                     86:                return (FALSE);
                     87:        }
                     88:        re_srch_lastdir = SRCH_FORW;
                     89:        return (TRUE);
                     90: }
                     91:
                     92: /*
                     93:  * Reverse search.
                     94:  * Get a search string from the         user, and search, starting at "."
                     95:  * and proceeding toward the front of the buffer. If found "." is left
                     96:  * pointing at the first character of the pattern [the last character that
                     97:  * was matched].
                     98:  */
1.5     ! millert    99: /* ARGSUSED */
        !           100: re_backsearch(f, n)
        !           101: {
        !           102:        register int    s;
1.1       deraadt   103:
1.5     ! millert   104:        if ((s = re_readpattern("RE Search backward")) != TRUE)
1.1       deraadt   105:                return (s);
                    106:        if (re_backsrch() == FALSE) {
                    107:                ewprintf("Search failed: \"%s\"", re_pat);
                    108:                return (FALSE);
                    109:        }
                    110:        re_srch_lastdir = SRCH_BACK;
                    111:        return (TRUE);
                    112: }
                    113:
                    114:
                    115:
                    116: /*
                    117:  * Search again, using the same search string
                    118:  * and direction as the last search command. The direction
                    119:  * has been saved in "srch_lastdir", so you know which way
                    120:  * to go.
                    121:  */
1.5     ! millert   122: /* ARGSUSED */
        !           123: /*
        !           124:  * This code has problems-- some incompatibility(?) with extend.c causes
        !           125:  * match to fail when it should not.
        !           126:  */
        !           127: re_searchagain(f, n)
        !           128: {
        !           129:
        !           130:        if (re_srch_lastdir == SRCH_NOPR) {
        !           131:                ewprintf("No last search");
        !           132:                return (FALSE);
        !           133:        }
        !           134:        if (re_srch_lastdir == SRCH_FORW) {
        !           135:                if (re_forwsrch() == FALSE) {
        !           136:                        ewprintf("Search failed: \"%s\"", re_pat);
        !           137:                        return (FALSE);
        !           138:                }
        !           139:                return (TRUE);
        !           140:        }
        !           141:        if (re_srch_lastdir == SRCH_BACK) {
        !           142:                if (re_backsrch() == FALSE) {
        !           143:                        ewprintf("Search failed: \"%s\"", re_pat);
        !           144:                        return (FALSE);
        !           145:                }
        !           146:                return (TRUE);
        !           147:        }
1.1       deraadt   148: }
                    149:
                    150:
                    151: /* Compiled regex goes here-- changed only when new pattern read */
1.5     ! millert   152: static regex_t  re_buff;
1.2       millert   153: static regmatch_t re_match[RE_NMATCH];
1.1       deraadt   154:
                    155: /*
                    156:  * Re-Query Replace.
                    157:  *     Replace strings selectively.  Does a search and replace operation.
                    158:  */
1.5     ! millert   159: /* ARGSUSED */
        !           160: re_queryrepl(f, n)
        !           161: {
        !           162:        register int    s;
        !           163:        register int    rcnt = 0;       /* Replacements made so far      */
        !           164:        register int    plen;   /* length of found string        */
        !           165:        char            news[NPAT];     /* replacement string            */
1.1       deraadt   166:
                    167:        /* Casefold check */
1.5     ! millert   168:        if (!casefoldsearch)
        !           169:                f = TRUE;
1.1       deraadt   170:
1.5     ! millert   171:        if ((s = re_readpattern("RE Query replace")) != TRUE)
1.1       deraadt   172:                return (s);
1.5     ! millert   173:        if ((s = ereply("Query replace %s with: ", news, NPAT, re_pat)) == ABORT)
1.1       deraadt   174:                return (s);
                    175:        if (s == FALSE)
                    176:                news[0] = '\0';
                    177:        ewprintf("Query replacing %s with %s:", re_pat, news);
                    178:
                    179:        /*
                    180:         * Search forward repeatedly, checking each time whether to insert
                    181:         * or not.  The "!" case makes the check always true, so it gets put
                    182:         * into a tighter loop for efficiency.
                    183:         */
                    184:
                    185:        while (re_forwsrch() == TRUE) {
1.5     ! millert   186: retry:
1.1       deraadt   187:                update();
                    188:                switch (getkey(FALSE)) {
                    189:                case ' ':
1.2       millert   190:                        plen = re_match[0].rm_eo - re_match[0].rm_so;
1.1       deraadt   191:                        if (re_doreplace((RSIZE) plen, news, f) == FALSE)
                    192:                                return (FALSE);
                    193:                        rcnt++;
                    194:                        break;
                    195:
                    196:                case '.':
1.2       millert   197:                        plen = re_match[0].rm_eo - re_match[0].rm_so;
1.1       deraadt   198:                        if (re_doreplace((RSIZE) plen, news, f) == FALSE)
                    199:                                return (FALSE);
                    200:                        rcnt++;
                    201:                        goto stopsearch;
                    202:
1.5     ! millert   203:                case CCHR('G'):/* ^G */
1.1       deraadt   204:                        (VOID) ctrlg(FFRAND, 0);
1.5     ! millert   205:                case CCHR('['):/* ESC */
1.1       deraadt   206:                case '`':
                    207:                        goto stopsearch;
                    208:
                    209:                case '!':
                    210:                        do {
1.2       millert   211:                                plen = re_match[0].rm_eo - re_match[0].rm_so;
1.1       deraadt   212:                                if (re_doreplace((RSIZE) plen, news, f) == FALSE)
                    213:                                        return (FALSE);
                    214:                                rcnt++;
                    215:                        } while (re_forwsrch() == TRUE);
                    216:                        goto stopsearch;
                    217:
1.5     ! millert   218:                case CCHR('?'):/* To not replace */
1.1       deraadt   219:                        break;
                    220:
                    221:                default:
1.5     ! millert   222:                        ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
1.1       deraadt   223:                        goto retry;
                    224:                }
                    225:        }
                    226: stopsearch:
                    227:        curwp->w_flag |= WFHARD;
                    228:        update();
                    229:        if (!inmacro) {
                    230:                if (rcnt == 0)
                    231:                        ewprintf("(No replacements done)");
                    232:                else if (rcnt == 1)
                    233:                        ewprintf("(1 replacement done)");
                    234:                else
                    235:                        ewprintf("(%d replacements done)", rcnt);
                    236:        }
                    237:        return TRUE;
                    238: }
                    239:
                    240:
                    241:
1.5     ! millert   242: /*
        !           243:  * Routine re_doreplace calls lreplace to make replacements needed by
        !           244:  * re_query replace.  Its reason for existence is to deal with \1, \2. etc.
1.1       deraadt   245:  */
                    246:
                    247: /* Maximum length of replacement string */
                    248: #define REPLEN 256
                    249:
                    250: re_doreplace(plen, st, f)
1.5     ! millert   251:        register RSIZE  plen;   /* length to remove          */
        !           252:        char           *st;     /* replacement string        */
        !           253:        int             f;      /* case hack disable         */
        !           254: {
        !           255:        int             s;
        !           256:        int             num, k;
        !           257:        register int    j;
        !           258:        int             more, state;
        !           259:        LINE           *clp;
        !           260:        char            repstr[REPLEN];
        !           261:
        !           262:        clp = curwp->w_dotp;
        !           263:        more = TRUE;
        !           264:        j = 0;
        !           265:        state = 0;
        !           266:
        !           267:        /* The following FSA parses the replacement string */
        !           268:        while (more) {
        !           269:                switch (state) {
        !           270:
        !           271:                case 0:
        !           272:                        if (*st == '\\') {
        !           273:                                st++;
        !           274:                                state = 1;
        !           275:                        } else if (*st == '\0')
        !           276:                                more = FALSE;
        !           277:                        else {
        !           278:                                repstr[j] = *st;
        !           279:                                j++;
        !           280:                                if (j >= REPLEN)
        !           281:                                        return (FALSE);
        !           282:                                st++;
        !           283:                        }
        !           284:                        break;
        !           285:                case 1:
        !           286:                        if (*st >= '0' && *st <= '9') {
        !           287:                                num = *st - '0';
        !           288:                                st++;
        !           289:                                state = 2;
        !           290:                        } else if (*st == '\0')
        !           291:                                more = FALSE;
        !           292:                        else {
        !           293:                                repstr[j] = *st;
        !           294:                                j++;
        !           295:                                if (j >= REPLEN)
        !           296:                                        return (FALSE);
        !           297:                                st++;
        !           298:                                state = 0;
        !           299:                        }
        !           300:                        break;
        !           301:                case 2:
        !           302:                        if (*st >= '0' && *st <= '9') {
        !           303:                                num = 10 * num + *st - '0';
        !           304:                                st++;
        !           305:                        } else {
        !           306:                                if (num >= RE_NMATCH)
        !           307:                                        return (FALSE);
        !           308:                                k = re_match[num].rm_eo - re_match[num].rm_so;
        !           309:                                if (j + k >= REPLEN)
        !           310:                                        return (FALSE);
        !           311:                                bcopy(&(clp->l_text[re_match[num].rm_so]), &repstr[j], k);
        !           312:                                j += k;
        !           313:                                if (*st == '\0')
        !           314:                                        more = FALSE;
        !           315:                                if (*st == '\\') {
        !           316:                                        st++;
        !           317:                                        state = 1;
        !           318:                                } else {
        !           319:                                        repstr[j] = *st;
        !           320:                                        j++;
        !           321:                                        if (j >= REPLEN)
        !           322:                                                return (FALSE);
        !           323:                                        st++;
        !           324:                                        state = 0;
        !           325:                                }
        !           326:                        }
        !           327:                        break;
        !           328:                }               /* end case */
        !           329:        }                       /* end while */
1.1       deraadt   330:
1.5     ! millert   331:        repstr[j] = '\0';
1.1       deraadt   332:
1.5     ! millert   333:        s = lreplace(plen, repstr, f);
1.1       deraadt   334:
1.5     ! millert   335:        return (s);
1.1       deraadt   336: }
                    337:
                    338:
                    339:
                    340: /*
                    341:  * This routine does the real work of a
                    342:  * forward search. The pattern is sitting in the external
                    343:  * variable "pat". If found, dot is updated, the window system
                    344:  * is notified of the change, and TRUE is returned. If the
                    345:  * string isn't found, FALSE is returned.
                    346:  */
1.5     ! millert   347: re_forwsrch()
        !           348: {
        !           349:
        !           350:        register LINE  *clp;
        !           351:        register int    tbo;
        !           352:        int             error, plen;
        !           353:
        !           354:        clp = curwp->w_dotp;
        !           355:        tbo = curwp->w_doto;
        !           356:
        !           357:        if (tbo == clp->l_used)
        !           358:                /*
        !           359:                 * Don't start matching off end of line-- must move to
        !           360:                 * beginning of next line, unless at end
        !           361:                 */
        !           362:                if (clp != curbp->b_linep) {
        !           363:                        clp = lforw(clp);
        !           364:                        tbo = 0;
        !           365:                }
        !           366:        /*
        !           367:         * Note this loop does not process the last line, but this editor
        !           368:         * always makes the last line empty so this is good.
        !           369:         */
1.1       deraadt   370:
1.5     ! millert   371:        while (clp != (curbp->b_linep)) {
        !           372:
        !           373:                re_match[0].rm_so = tbo;
        !           374:                re_match[0].rm_eo = llength(clp);
        !           375:                error = regexec(&re_buff, ltext(clp), RE_NMATCH, re_match, REG_STARTEND);
        !           376:
        !           377:                if (error) {
        !           378:                        clp = lforw(clp);
        !           379:                        tbo = 0;
        !           380:                } else {
        !           381:                        curwp->w_doto = re_match[0].rm_eo;
        !           382:                        curwp->w_dotp = clp;
        !           383:                        curwp->w_flag |= WFMOVE;
        !           384:                        return (TRUE);
        !           385:                }
1.1       deraadt   386:
1.5     ! millert   387:        }
1.1       deraadt   388:
1.5     ! millert   389:        return (FALSE);
1.1       deraadt   390:
                    391: }
                    392:
                    393:
                    394: /*
                    395:  * This routine does the real work of a
                    396:  * backward search. The pattern is sitting in the external
                    397:  * variable "re_pat". If found, dot is updated, the window system
                    398:  * is notified of the change, and TRUE is returned. If the
                    399:  * string isn't found, FALSE is returned.
                    400:  */
1.5     ! millert   401: re_backsrch()
        !           402: {
        !           403:
        !           404:        register LINE  *clp;
        !           405:        register int    tbo;
        !           406:        regmatch_t      lastmatch;
        !           407:        char            m[1];
        !           408:
        !           409:        clp = curwp->w_dotp;
        !           410:        tbo = curwp->w_doto;
        !           411:
        !           412:        /* Start search one position to the left of dot */
        !           413:        tbo = tbo - 1;
        !           414:        if (tbo < 0) {
        !           415:                /* must move up one line */
        !           416:                clp = lback(clp);
        !           417:                tbo = llength(clp);
        !           418:        }
        !           419:        /*
        !           420:         * Note this loop does not process the last line, but this editor
        !           421:         * always makes the last line empty so this is good.
        !           422:         */
        !           423:
        !           424:        while (clp != (curbp->b_linep)) {
1.1       deraadt   425:
1.5     ! millert   426:                re_match[0].rm_so = 0;
        !           427:                re_match[0].rm_eo = llength(clp);
        !           428:                lastmatch.rm_so = -1;
        !           429:                /*
        !           430:                 * Keep searching until we don't match any longer.  Assumes a
        !           431:                 * non-match does not modify the re_match array.  We have to
        !           432:                 * do this character-by-character after the first match since
        !           433:                 * POSIX regexps don't give you a way to do reverse matches.
        !           434:                 */
        !           435:                while (!regexec(&re_buff, ltext(clp), RE_NMATCH, re_match,
        !           436:                    REG_STARTEND) && re_match[0].rm_so < tbo) {
        !           437:                        memcpy(&lastmatch, &re_match[0], sizeof(regmatch_t));
        !           438:                        re_match[0].rm_so++;
        !           439:                        re_match[0].rm_eo = llength(clp);
        !           440:                }
        !           441:
        !           442:                if (lastmatch.rm_so == -1) {
        !           443:                        clp = lback(clp);
        !           444:                        tbo = llength(clp);
        !           445:                } else {
        !           446:                        memcpy(&re_match[0], &lastmatch, sizeof(regmatch_t));
        !           447:                        curwp->w_doto = re_match[0].rm_so;
        !           448:                        curwp->w_dotp = clp;
        !           449:                        curwp->w_flag |= WFMOVE;
        !           450:                        return (TRUE);
        !           451:                }
1.1       deraadt   452:
1.5     ! millert   453:        }
1.1       deraadt   454:
1.5     ! millert   455:        return (FALSE);
1.1       deraadt   456:
                    457: }
                    458:
                    459:
                    460: /*
                    461:  * Read a pattern.
                    462:  * Stash it in the external variable "re_pat". The "pat" is
                    463:  * not updated if the user types in an empty line. If the user typed
                    464:  * an empty line, and there is no old pattern, it is an error.
                    465:  * Display the old pattern, in the style of Jeff Lomicka. There is
                    466:  * some do-it-yourself control expansion.
                    467:  */
1.5     ! millert   468: re_readpattern(prompt)
        !           469:        char           *prompt;
        !           470: {
        !           471:        int             s;
        !           472:        int             flags;
        !           473:        int             error;
        !           474:        char            tpat[NPAT];
        !           475:        static int      dofree = 0;
        !           476:
        !           477:        if (re_pat[0] == '\0')
        !           478:                s = ereply("%s: ", tpat, NPAT, prompt);
        !           479:        else
        !           480:                s = ereply("%s: (default %s) ", tpat, NPAT, prompt, re_pat);
1.1       deraadt   481:
                    482:        if (s == TRUE) {
1.5     ! millert   483:                /* New pattern given */
        !           484:                (VOID) strcpy(re_pat, tpat);
        !           485:                if (casefoldsearch)
        !           486:                        flags = REG_EXTENDED | REG_ICASE;
        !           487:                else
        !           488:                        flags = REG_EXTENDED;
        !           489:                if (dofree)
        !           490:                        regfree(&re_buff);
        !           491:                error = regcomp(&re_buff, re_pat, flags);
        !           492:                if (error) {
        !           493:                        char            message[256];
        !           494:                        regerror(error, &re_buff, message, sizeof(message));
        !           495:                        ewprintf("Regex Error: %s", message);
        !           496:                        re_pat[0] = '\0';
        !           497:                        return (FALSE);
        !           498:                }
        !           499:                dofree = 1;
        !           500:        } else if (s == FALSE && re_pat[0] != '\0')
        !           501:                /* Just using old pattern */
        !           502:                s = TRUE;
1.1       deraadt   503:        return (s);
                    504: }
                    505:
                    506:
                    507:
1.5     ! millert   508: /*
        !           509:  * Cause case to not matter in searches.  This is the default. If called
        !           510:  * with argument cause case to matter.
1.1       deraadt   511:  */
1.5     ! millert   512: setcasefold(f, n)
        !           513: {
1.1       deraadt   514:
1.5     ! millert   515:        if (f & FFARG) {
        !           516:                casefoldsearch = FALSE;
        !           517:                ewprintf("Case-fold-search unset");
        !           518:        } else {
        !           519:                casefoldsearch = TRUE;
        !           520:                ewprintf("Case-fold-search set");
        !           521:        }
1.1       deraadt   522:
1.5     ! millert   523:        /*
        !           524:         * Invalidate the regular expression pattern since I'm too lazy to
        !           525:         * recompile it.
        !           526:         */
1.1       deraadt   527:
1.5     ! millert   528:        re_pat[0] = '\0';
1.1       deraadt   529:
1.5     ! millert   530:        return (TRUE);
1.1       deraadt   531:
1.5     ! millert   532: }                              /* end setcasefold */
1.1       deraadt   533:
                    534:
1.5     ! millert   535: /*
        !           536:  * Delete all lines after dot that contain a string matching regex
1.1       deraadt   537:  */
1.5     ! millert   538: delmatchlines(f, n)
        !           539: {
        !           540:        int             s;
1.1       deraadt   541:
1.5     ! millert   542:        if ((s = re_readpattern("Flush lines (containing match for regexp)")) != TRUE)
        !           543:                return (s);
1.1       deraadt   544:
1.5     ! millert   545:        s = killmatches(TRUE);
1.1       deraadt   546:
1.5     ! millert   547:        return (s);
1.1       deraadt   548: }
                    549:
                    550:
                    551:
1.5     ! millert   552: /*
        !           553:  * Delete all lines after dot that don't contain a string matching regex
1.1       deraadt   554:  */
1.5     ! millert   555: delnonmatchlines(f, n)
        !           556: {
        !           557:        int             s;
1.1       deraadt   558:
                    559:
1.5     ! millert   560:        if ((s = re_readpattern("Keep lines (containing match for regexp)")) != TRUE)
        !           561:                return (s);
1.1       deraadt   562:
1.5     ! millert   563:        s = killmatches(FALSE);
1.1       deraadt   564:
1.5     ! millert   565:        return (s);
1.1       deraadt   566: }
                    567:
                    568:
                    569:
                    570: /* This function does the work of deleting matching lines */
                    571: killmatches(cond)
1.5     ! millert   572:        int             cond;
1.1       deraadt   573: {
1.5     ! millert   574:        int             s, error;
        !           575:        int             count = 0;
        !           576:        LINE           *clp;
        !           577:
        !           578:        clp = curwp->w_dotp;
        !           579:        if (curwp->w_doto == llength(clp))
        !           580:                /* Consider dot on next line */
        !           581:                clp = lforw(clp);
        !           582:
        !           583:        while (clp != (curbp->b_linep)) {
        !           584:
        !           585:                /* see if line matches */
        !           586:                re_match[0].rm_so = 0;
        !           587:                re_match[0].rm_eo = llength(clp);
        !           588:                error = regexec(&re_buff, ltext(clp), RE_NMATCH, re_match, REG_STARTEND);
        !           589:
        !           590:                /* Delete line when appropriate */
        !           591:                if ((cond == FALSE && error) || (cond == TRUE && !error)) {
        !           592:                        curwp->w_doto = 0;
        !           593:                        curwp->w_dotp = clp;
        !           594:                        count++;
        !           595:                        s = ldelete(llength(clp) + 1, KNONE);
        !           596:                        clp = curwp->w_dotp;
        !           597:                        curwp->w_flag |= WFMOVE;
        !           598:                        if (s == FALSE)
        !           599:                                return (FALSE);
        !           600:                } else
        !           601:                        clp = lforw(clp);
        !           602:        }
1.1       deraadt   603:
1.5     ! millert   604:        ewprintf("%d line(s) deleted", count);
        !           605:        if (count > 0)
        !           606:                curwp->w_flag |= WFMOVE;
1.1       deraadt   607:
1.5     ! millert   608:        return (TRUE);
1.1       deraadt   609: }
                    610:
                    611:
1.5     ! millert   612: petersfunc(f, n)
        !           613: {
1.1       deraadt   614:
1.5     ! millert   615:        int             s;
        !           616:        LINE           *clp;
        !           617:        char            c;
        !           618:
        !           619:        curwp->w_doto = 0;
        !           620:        s = ldelete(llength(curwp->w_dotp) + 1, KNONE);
        !           621:        curwp->w_flag |= WFMOVE;
        !           622:        return (s);
1.1       deraadt   623:
                    624: }
                    625:
                    626:
1.5     ! millert   627: /*
        !           628:  * Count lines matching regex
1.1       deraadt   629:  */
1.5     ! millert   630: cntmatchlines(f, n)
        !           631: {
        !           632:        int             s;
1.1       deraadt   633:
1.5     ! millert   634:        if ((s = re_readpattern("Count lines (matching regexp)")) != TRUE)
        !           635:                return (s);
1.1       deraadt   636:
1.5     ! millert   637:        s = countmatches(TRUE);
1.1       deraadt   638:
1.5     ! millert   639:        return (s);
1.1       deraadt   640: }
                    641:
                    642:
                    643:
1.5     ! millert   644: /*
        !           645:  * Count lines that fail to match regex
1.1       deraadt   646:  */
1.5     ! millert   647: cntnonmatchlines(f, n)
        !           648: {
        !           649:        int             s;
1.1       deraadt   650:
                    651:
1.5     ! millert   652:        if ((s = re_readpattern("Count lines (not matching regexp)")) != TRUE)
        !           653:                return (s);
1.1       deraadt   654:
1.5     ! millert   655:        s = countmatches(FALSE);
1.1       deraadt   656:
1.5     ! millert   657:        return (s);
1.1       deraadt   658: }
                    659:
                    660:
                    661:
                    662: /* This function does the work of counting matching lines */
                    663: countmatches(cond)
1.5     ! millert   664:        int             cond;
1.1       deraadt   665: {
1.5     ! millert   666:        int             s, error;
        !           667:        int             count = 0;
        !           668:        LINE           *clp;
        !           669:
        !           670:        clp = curwp->w_dotp;
        !           671:        if (curwp->w_doto == llength(clp))
        !           672:                /* Consider dot on next line */
        !           673:                clp = lforw(clp);
        !           674:
        !           675:        while (clp != (curbp->b_linep)) {
        !           676:
        !           677:                /* see if line matches */
        !           678:                re_match[0].rm_so = 0;
        !           679:                re_match[0].rm_eo = llength(clp);
        !           680:                error = regexec(&re_buff, ltext(clp), RE_NMATCH, re_match, REG_STARTEND);
        !           681:
        !           682:                /* Count line when appropriate */
        !           683:                if ((cond == FALSE && error) || (cond == TRUE && !error))
        !           684:                        count++;
        !           685:                clp = lforw(clp);
        !           686:        }
1.1       deraadt   687:
1.5     ! millert   688:        if (cond)
        !           689:                ewprintf("Number of lines matching: %d", count);
        !           690:        else
        !           691:                ewprintf("Number of lines not matching: %d", count);
        !           692:
        !           693:        return (TRUE);
1.1       deraadt   694: }
                    695: #endif