git-svn: add a message encouraging use of SVN::* libraries
[gitweb.git] / diffcore-pickaxe.c
index 4c26b422f9d4ea16581bc44cf8a2ce4f5586a7f1..cfcce315babb0edb7ad7be7f2ab2437aaf41eb9d 100644 (file)
@@ -5,19 +5,46 @@
 #include "diff.h"
 #include "diffcore.h"
 
-static int contains(struct diff_filespec *one,
-                   const char *needle, unsigned long len)
+#include <regex.h>
+
+static unsigned int contains(struct diff_filespec *one,
+                            const char *needle, unsigned long len,
+                            regex_t *regexp)
 {
+       unsigned int cnt;
        unsigned long offset, sz;
        const char *data;
        if (diff_populate_filespec(one, 0))
                return 0;
+
        sz = one->size;
        data = one->data;
-       for (offset = 0; offset + len <= sz; offset++)
-                    if (!strncmp(needle, data + offset, len))
-                            return 1;
-       return 0;
+       cnt = 0;
+
+       if (regexp) {
+               regmatch_t regmatch;
+               int flags = 0;
+
+               while (*data && !regexec(regexp, data, 1, &regmatch, flags)) {
+                       flags |= REG_NOTBOL;
+                       data += regmatch.rm_so;
+                       if (*data) data++;
+                       cnt++;
+               }
+
+       } else { /* Classic exact string match */
+               /* Yes, I've heard of strstr(), but the thing is *data may
+                * not be NUL terminated.  Sue me.
+                */
+               for (offset = 0; offset + len <= sz; offset++) {
+                       /* we count non-overlapping occurrences of needle */
+                       if (!memcmp(needle, data + offset, len)) {
+                               offset += len - 1;
+                               cnt++;
+                       }
+               }
+       }
+       return cnt;
 }
 
 void diffcore_pickaxe(const char *needle, int opts)
@@ -25,10 +52,24 @@ void diffcore_pickaxe(const char *needle, int opts)
        struct diff_queue_struct *q = &diff_queued_diff;
        unsigned long len = strlen(needle);
        int i, has_changes;
+       regex_t regex, *regexp = NULL;
        struct diff_queue_struct outq;
        outq.queue = NULL;
        outq.nr = outq.alloc = 0;
 
+       if (opts & DIFF_PICKAXE_REGEX) {
+               int err;
+               err = regcomp(&regex, needle, REG_EXTENDED | REG_NEWLINE);
+               if (err) {
+                       /* The POSIX.2 people are surely sick */
+                       char errbuf[1024];
+                       regerror(err, &regex, errbuf, 1024);
+                       regfree(&regex);
+                       die("invalid pickaxe regex: %s", errbuf);
+               }
+               regexp = &regex;
+       }
+
        if (opts & DIFF_PICKAXE_ALL) {
                /* Showing the whole changeset if needle exists */
                for (i = has_changes = 0; !has_changes && i < q->nr; i++) {
@@ -37,16 +78,16 @@ void diffcore_pickaxe(const char *needle, int opts)
                                if (!DIFF_FILE_VALID(p->two))
                                        continue; /* ignore unmerged */
                                /* created */
-                               if (contains(p->two, needle, len))
+                               if (contains(p->two, needle, len, regexp))
                                        has_changes++;
                        }
                        else if (!DIFF_FILE_VALID(p->two)) {
-                               if (contains(p->one, needle, len))
+                               if (contains(p->one, needle, len, regexp))
                                        has_changes++;
                        }
                        else if (!diff_unmodified_pair(p) &&
-                                contains(p->one, needle, len) !=
-                                contains(p->two, needle, len))
+                                contains(p->one, needle, len, regexp) !=
+                                contains(p->two, needle, len, regexp))
                                has_changes++;
                }
                if (has_changes)
@@ -69,16 +110,16 @@ void diffcore_pickaxe(const char *needle, int opts)
                                if (!DIFF_FILE_VALID(p->two))
                                        ; /* ignore unmerged */
                                /* created */
-                               else if (contains(p->two, needle, len))
+                               else if (contains(p->two, needle, len, regexp))
                                        has_changes = 1;
                        }
                        else if (!DIFF_FILE_VALID(p->two)) {
-                               if (contains(p->one, needle, len))
+                               if (contains(p->one, needle, len, regexp))
                                        has_changes = 1;
                        }
                        else if (!diff_unmodified_pair(p) &&
-                                contains(p->one, needle, len) !=
-                                contains(p->two, needle, len))
+                                contains(p->one, needle, len, regexp) !=
+                                contains(p->two, needle, len, regexp))
                                has_changes = 1;
 
                        if (has_changes)
@@ -87,6 +128,10 @@ void diffcore_pickaxe(const char *needle, int opts)
                                diff_free_filepair(p);
                }
 
+       if (opts & DIFF_PICKAXE_REGEX) {
+               regfree(&regex);
+       }
+
        free(q->queue);
        *q = outq;
        return;