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

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