diff options
Diffstat (limited to 'diffcore-pickaxe.c')
-rw-r--r-- | diffcore-pickaxe.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c new file mode 100644 index 0000000000..af9fffe6e8 --- /dev/null +++ b/diffcore-pickaxe.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2005 Junio C Hamano + */ +#include "cache.h" +#include "diff.h" +#include "diffcore.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; + if (!len) + return 0; + + sz = one->size; + data = one->data; + cnt = 0; + + if (regexp) { + regmatch_t regmatch; + int flags = 0; + + while (*data && !regexec(regexp, data, 1, ®match, 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++; + } + } + } + diff_free_filespec_data(one); + return cnt; +} + +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(®ex, needle, REG_EXTENDED | REG_NEWLINE); + if (err) { + /* The POSIX.2 people are surely sick */ + char errbuf[1024]; + regerror(err, ®ex, errbuf, 1024); + regfree(®ex); + die("invalid pickaxe regex: %s", errbuf); + } + regexp = ®ex; + } + + if (opts & DIFF_PICKAXE_ALL) { + /* Showing the whole changeset if needle exists */ + for (i = has_changes = 0; !has_changes && i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + if (!DIFF_FILE_VALID(p->one)) { + if (!DIFF_FILE_VALID(p->two)) + continue; /* ignore unmerged */ + /* created */ + if (contains(p->two, needle, len, regexp)) + has_changes++; + } + else if (!DIFF_FILE_VALID(p->two)) { + if (contains(p->one, needle, len, regexp)) + has_changes++; + } + else if (!diff_unmodified_pair(p) && + contains(p->one, needle, len, regexp) != + contains(p->two, needle, len, regexp)) + has_changes++; + } + if (has_changes) + return; /* not munge the queue */ + + /* otherwise we will clear the whole queue + * by copying the empty outq at the end of this + * function, but first clear the current entries + * in the queue. + */ + for (i = 0; i < q->nr; i++) + diff_free_filepair(q->queue[i]); + } + else + /* Showing only the filepairs that has the needle */ + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + has_changes = 0; + if (!DIFF_FILE_VALID(p->one)) { + if (!DIFF_FILE_VALID(p->two)) + ; /* ignore unmerged */ + /* created */ + else if (contains(p->two, needle, len, regexp)) + has_changes = 1; + } + else if (!DIFF_FILE_VALID(p->two)) { + if (contains(p->one, needle, len, regexp)) + has_changes = 1; + } + else if (!diff_unmodified_pair(p) && + contains(p->one, needle, len, regexp) != + contains(p->two, needle, len, regexp)) + has_changes = 1; + + if (has_changes) + diff_q(&outq, p); + else + diff_free_filepair(p); + } + + if (opts & DIFF_PICKAXE_REGEX) { + regfree(®ex); + } + + free(q->queue); + *q = outq; + return; +} |