Author: emaste
Date: Mon Apr  3 23:16:51 2017
New Revision: 316477
URL: https://svnweb.freebsd.org/changeset/base/316477

Log:
  bsdgrep: fix matching behaviour
  
  - Set REG_NOTBOL if we've already matched beginning of line and we're
    examining later parts
  
  - For each pattern we examine, apply it to the remaining bits of the
    line rather than (potentially) smaller subsets
  
  - Check for REG_NOSUB after we've looked at all patterns initially
    matching the line
  
  - Keep track of the last match we made to later determine if we're
    simply not matching any longer or if we need to proceed another byte
    because we hit a zero-length match
  
  - Match the earliest and longest bit of each line before moving the
    beginning of what we match to further in the line, past the end of the
    longest match; this generally matches how gnugrep(1) seems to behave,
    and seems like pretty good behavior to me
  
  - Finally, bail out of printing any matches if we were set to print all
    (empty pattern) but -o (output matches) was set
  
  PR:           195763, 180990, 197555, 197531, 181263, 209116
  Submitted by: "Kyle Evans" <kevan...@ksu.edu>
  Reviewed by:  cem
  MFC after:    1 month
  Relnotes:     Yes
  Differential Revision:        https://reviews.freebsd.org/D10104

Modified:
  head/usr.bin/grep/util.c

Modified: head/usr.bin/grep/util.c
==============================================================================
--- head/usr.bin/grep/util.c    Mon Apr  3 22:36:45 2017        (r316476)
+++ head/usr.bin/grep/util.c    Mon Apr  3 23:16:51 2017        (r316477)
@@ -276,28 +276,29 @@ static int
 procline(struct str *l, int nottext)
 {
        regmatch_t matches[MAX_LINE_MATCHES];
-       regmatch_t pmatch;
-       size_t st = 0;
+       regmatch_t pmatch, lastmatch;
+       size_t st = 0, nst = 0;
        unsigned int i;
-       int c = 0, m = 0, r = 0;
+       int c = 0, m = 0, r = 0, lastmatches = 0, leflags = eflags;
+       int startm = 0;
 
        /* Loop to process the whole line */
        while (st <= l->len) {
-               pmatch.rm_so = st;
-               pmatch.rm_eo = l->len;
-
+               lastmatches = 0;
+               startm = m;
+               if (st > 0)
+                       leflags |= REG_NOTBOL;
                /* Loop to compare with all the patterns */
                for (i = 0; i < patterns; i++) {
+                       pmatch.rm_so = st;
+                       pmatch.rm_eo = l->len;
                        if (fg_pattern[i].pattern)
                                r = fastexec(&fg_pattern[i],
-                                   l->dat, 1, &pmatch, eflags);
+                                   l->dat, 1, &pmatch, leflags);
                        else
                                r = regexec(&r_pattern[i], l->dat, 1,
-                                   &pmatch, eflags);
+                                   &pmatch, leflags);
                        r = (r == 0) ? 0 : REG_NOMATCH;
-                       st = (cflags & REG_NOSUB)
-                               ? (size_t)l->len
-                               : (size_t)pmatch.rm_eo;
                        if (r == REG_NOMATCH)
                                continue;
                        /* Check for full match */
@@ -324,10 +325,29 @@ procline(struct str *l, int nottext)
                                        r = REG_NOMATCH;
                        }
                        if (r == 0) {
+                               lastmatches++;
+                               lastmatch = pmatch;
+                               /* Skip over zero-length matches */
+                               if (pmatch.rm_so == pmatch.rm_eo)
+                                       continue;
                                if (m == 0)
                                        c++;
-                               if (m < MAX_LINE_MATCHES)
-                                       matches[m++] = pmatch;
+
+                               if (m < MAX_LINE_MATCHES) {
+                                       /* Replace previous match if the new 
one is earlier and/or longer */
+                                       if (m > startm) {
+                                               if (pmatch.rm_so < 
matches[m-1].rm_so ||
+                                                   (pmatch.rm_so == 
matches[m-1].rm_so && (pmatch.rm_eo - pmatch.rm_so) > (matches[m-1].rm_eo - 
matches[m-1].rm_so))) {
+                                                       matches[m-1] = pmatch;
+                                                       nst = pmatch.rm_eo;
+                                               }
+                                       } else {
+                                               /* Advance as normal if not */
+                                               matches[m++] = pmatch;
+                                               nst = pmatch.rm_eo;
+                                       }
+                               }
+
                                /* matches - skip further patterns */
                                if ((color == NULL && !oflag) ||
                                    qflag || lflag)
@@ -344,8 +364,19 @@ procline(struct str *l, int nottext)
                if (!wflag && ((color == NULL && !oflag) || qflag || lflag || 
Lflag))
                        break;
 
-               if (st == (size_t)pmatch.rm_so)
-                       break;  /* No matches */
+               /* If we didn't have any matches or REG_NOSUB set */
+               if (lastmatches == 0 || (cflags & REG_NOSUB))
+                       nst = l->len;
+
+               if (lastmatches == 0)
+                       /* No matches */
+                       break;
+               else if (st == nst && lastmatch.rm_so == lastmatch.rm_eo)
+                       /* Zero-length match -- advance one more so we don't 
get stuck */
+                       nst++;
+
+               /* Advance st based on previous matches */
+               st = nst;
        }
 
 
@@ -444,6 +475,10 @@ printline(struct str *line, int sep, reg
        size_t a = 0;
        int i, n = 0;
 
+       /* If matchall, everything matches but don't actually print for -o */
+       if (oflag && matchall)
+               return;
+
        if (!hflag) {
                if (!nullflag) {
                        fputs(line->file, stdout);
@@ -474,13 +509,13 @@ printline(struct str *line, int sep, reg
                                fwrite(line->dat + a, matches[i].rm_so - a, 1,
                                    stdout);
                        if (color) 
-                               fprintf(stdout, "\33[%sm\33[K", color);
+                               fprintf(stdout, "\33[%sm", color);
 
                                fwrite(line->dat + matches[i].rm_so, 
                                    matches[i].rm_eo - matches[i].rm_so, 1,
                                    stdout);
                        if (color) 
-                               fprintf(stdout, "\33[m\33[K");
+                               fprintf(stdout, "\33[00m\33[K");
                        a = matches[i].rm_eo;
                        if (oflag)
                                putchar('\n');
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to