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