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

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