diffcore-pickaxe.con commit commit-tree: encourage UTF-8 commit messages. (9e83266)
   1/*
   2 * Copyright (C) 2005 Junio C Hamano
   3 */
   4#include "cache.h"
   5#include "diff.h"
   6#include "diffcore.h"
   7
   8static unsigned int contains(struct diff_filespec *one,
   9                             const char *needle, unsigned long len,
  10                             regex_t *regexp)
  11{
  12        unsigned int cnt;
  13        unsigned long offset, sz;
  14        const char *data;
  15        if (diff_populate_filespec(one, 0))
  16                return 0;
  17
  18        sz = one->size;
  19        data = one->data;
  20        cnt = 0;
  21
  22        if (regexp) {
  23                regmatch_t regmatch;
  24                int flags = 0;
  25
  26                while (*data && !regexec(regexp, data, 1, &regmatch, flags)) {
  27                        flags |= REG_NOTBOL;
  28                        data += regmatch.rm_so;
  29                        if (*data) data++;
  30                        cnt++;
  31                }
  32
  33        } else { /* Classic exact string match */
  34                /* Yes, I've heard of strstr(), but the thing is *data may
  35                 * not be NUL terminated.  Sue me.
  36                 */
  37                for (offset = 0; offset + len <= sz; offset++) {
  38                        /* we count non-overlapping occurrences of needle */
  39                        if (!memcmp(needle, data + offset, len)) {
  40                                offset += len - 1;
  41                                cnt++;
  42                        }
  43                }
  44        }
  45        return cnt;
  46}
  47
  48void diffcore_pickaxe(const char *needle, int opts)
  49{
  50        struct diff_queue_struct *q = &diff_queued_diff;
  51        unsigned long len = strlen(needle);
  52        int i, has_changes;
  53        regex_t regex, *regexp = NULL;
  54        struct diff_queue_struct outq;
  55        outq.queue = NULL;
  56        outq.nr = outq.alloc = 0;
  57
  58        if (opts & DIFF_PICKAXE_REGEX) {
  59                int err;
  60                err = regcomp(&regex, needle, REG_EXTENDED | REG_NEWLINE);
  61                if (err) {
  62                        /* The POSIX.2 people are surely sick */
  63                        char errbuf[1024];
  64                        regerror(err, &regex, errbuf, 1024);
  65                        regfree(&regex);
  66                        die("invalid pickaxe regex: %s", errbuf);
  67                }
  68                regexp = &regex;
  69        }
  70
  71        if (opts & DIFF_PICKAXE_ALL) {
  72                /* Showing the whole changeset if needle exists */
  73                for (i = has_changes = 0; !has_changes && i < q->nr; i++) {
  74                        struct diff_filepair *p = q->queue[i];
  75                        if (!DIFF_FILE_VALID(p->one)) {
  76                                if (!DIFF_FILE_VALID(p->two))
  77                                        continue; /* ignore unmerged */
  78                                /* created */
  79                                if (contains(p->two, needle, len, regexp))
  80                                        has_changes++;
  81                        }
  82                        else if (!DIFF_FILE_VALID(p->two)) {
  83                                if (contains(p->one, needle, len, regexp))
  84                                        has_changes++;
  85                        }
  86                        else if (!diff_unmodified_pair(p) &&
  87                                 contains(p->one, needle, len, regexp) !=
  88                                 contains(p->two, needle, len, regexp))
  89                                has_changes++;
  90                }
  91                if (has_changes)
  92                        return; /* not munge the queue */
  93
  94                /* otherwise we will clear the whole queue
  95                 * by copying the empty outq at the end of this
  96                 * function, but first clear the current entries
  97                 * in the queue.
  98                 */
  99                for (i = 0; i < q->nr; i++)
 100                        diff_free_filepair(q->queue[i]);
 101        }
 102        else 
 103                /* Showing only the filepairs that has the needle */
 104                for (i = 0; i < q->nr; i++) {
 105                        struct diff_filepair *p = q->queue[i];
 106                        has_changes = 0;
 107                        if (!DIFF_FILE_VALID(p->one)) {
 108                                if (!DIFF_FILE_VALID(p->two))
 109                                        ; /* ignore unmerged */
 110                                /* created */
 111                                else if (contains(p->two, needle, len, regexp))
 112                                        has_changes = 1;
 113                        }
 114                        else if (!DIFF_FILE_VALID(p->two)) {
 115                                if (contains(p->one, needle, len, regexp))
 116                                        has_changes = 1;
 117                        }
 118                        else if (!diff_unmodified_pair(p) &&
 119                                 contains(p->one, needle, len, regexp) !=
 120                                 contains(p->two, needle, len, regexp))
 121                                has_changes = 1;
 122
 123                        if (has_changes)
 124                                diff_q(&outq, p);
 125                        else
 126                                diff_free_filepair(p);
 127                }
 128
 129        if (opts & DIFF_PICKAXE_REGEX) {
 130                regfree(&regex);
 131        }
 132
 133        free(q->queue);
 134        *q = outq;
 135        return;
 136}