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, ®s);
! 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, ®s);
! 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: ®s);
! 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: ®s);
! 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