Merge branch 'jc/maint-log-grep' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 10 Sep 2008 09:15:08 +0000 (02:15 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 10 Sep 2008 09:15:08 +0000 (02:15 -0700)
* jc/maint-log-grep:
log --author/--committer: really match only with name part

grep.c
grep.h
revision.c
t/t7002-grep.sh
diff --git a/grep.c b/grep.c
index f67d6716ea5f42c3384a7a4cb2eb973b02785fba..706351197fc26efa10c4666d38433f8fbdf1d6b5 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -2,6 +2,19 @@
 #include "grep.h"
 #include "xdiff-interface.h"
 
+void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat)
+{
+       struct grep_pat *p = xcalloc(1, sizeof(*p));
+       p->pattern = pat;
+       p->origin = "header";
+       p->no = 0;
+       p->token = GREP_PATTERN_HEAD;
+       p->field = field;
+       *opt->pattern_tail = p;
+       opt->pattern_tail = &p->next;
+       p->next = NULL;
+}
+
 void append_grep_pattern(struct grep_opt *opt, const char *pat,
                         const char *origin, int no, enum grep_pat_token t)
 {
@@ -247,16 +260,53 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match)
        }
 }
 
+static int strip_timestamp(char *bol, char **eol_p)
+{
+       char *eol = *eol_p;
+       int ch;
+
+       while (bol < --eol) {
+               if (*eol != '>')
+                       continue;
+               *eol_p = ++eol;
+               ch = *eol;
+               *eol = '\0';
+               return ch;
+       }
+       return 0;
+}
+
+static struct {
+       const char *field;
+       size_t len;
+} header_field[] = {
+       { "author ", 7 },
+       { "committer ", 10 },
+};
+
 static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx)
 {
        int hit = 0;
        int at_true_bol = 1;
+       int saved_ch = 0;
        regmatch_t pmatch[10];
 
        if ((p->token != GREP_PATTERN) &&
            ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD)))
                return 0;
 
+       if (p->token == GREP_PATTERN_HEAD) {
+               const char *field;
+               size_t len;
+               assert(p->field < ARRAY_SIZE(header_field));
+               field = header_field[p->field].field;
+               len = header_field[p->field].len;
+               if (strncmp(bol, field, len))
+                       return 0;
+               bol += len;
+               saved_ch = strip_timestamp(bol, &eol);
+       }
+
  again:
        if (!opt->fixed) {
                regex_t *exp = &p->regexp;
@@ -298,6 +348,8 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
                        goto again;
                }
        }
+       if (p->token == GREP_PATTERN_HEAD && saved_ch)
+               *eol = saved_ch;
        return hit;
 }
 
diff --git a/grep.h b/grep.h
index d252dd25f81526d9b8663b4d3c9585d69a901397..59b3f871ea63619f8d3caae74c41b4da1e9a2b9f 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -17,12 +17,18 @@ enum grep_context {
        GREP_CONTEXT_BODY,
 };
 
+enum grep_header_field {
+       GREP_HEADER_AUTHOR = 0,
+       GREP_HEADER_COMMITTER,
+};
+
 struct grep_pat {
        struct grep_pat *next;
        const char *origin;
        int no;
        enum grep_pat_token token;
        const char *pattern;
+       enum grep_header_field field;
        regex_t regexp;
 };
 
@@ -74,6 +80,7 @@ struct grep_opt {
 };
 
 extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
+extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
 extern void compile_grep_patterns(struct grep_opt *opt);
 extern void free_grep_patterns(struct grep_opt *opt);
 extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size);
index 36291b6b864a1213841aba91d58693324d1c88c7..270294af8321c0b81f720db0f36e8f7f9eddbc88 100644 (file)
@@ -953,22 +953,9 @@ static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token
        append_grep_pattern(&revs->grep_filter, ptn, "command line", 0, what);
 }
 
-static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern)
+static void add_header_grep(struct rev_info *revs, enum grep_header_field field, const char *pattern)
 {
-       char *pat;
-       const char *prefix;
-       int patlen, fldlen;
-
-       fldlen = strlen(field);
-       patlen = strlen(pattern);
-       pat = xmalloc(patlen + fldlen + 10);
-       prefix = ".*";
-       if (*pattern == '^') {
-               prefix = "";
-               pattern++;
-       }
-       sprintf(pat, "^%s %s%s", field, prefix, pattern);
-       add_grep(revs, pat, GREP_PATTERN_HEAD);
+       append_header_grep_pattern(&revs->grep_filter, field, pattern);
 }
 
 static void add_message_grep(struct rev_info *revs, const char *pattern)
@@ -1154,9 +1141,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
         * Grepping the commit log
         */
        else if (!prefixcmp(arg, "--author=")) {
-               add_header_grep(revs, "author", arg+9);
+               add_header_grep(revs, GREP_HEADER_AUTHOR, arg+9);
        } else if (!prefixcmp(arg, "--committer=")) {
-               add_header_grep(revs, "committer", arg+12);
+               add_header_grep(revs, GREP_HEADER_COMMITTER, arg+12);
        } else if (!prefixcmp(arg, "--grep=")) {
                add_message_grep(revs, arg+7);
        } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
index c8b4f65f380f3941c75bd6ed52975777d2b28d67..5e359cb561b6d6f7c1bae678b7b823ed2ce34cf1 100755 (executable)
@@ -22,6 +22,7 @@ test_expect_success setup '
        mkdir t &&
        echo test >t/t &&
        git add file x y z t/t &&
+       test_tick &&
        git commit -m initial
 '
 
@@ -113,4 +114,54 @@ do
 
 done
 
+test_expect_success 'log grep setup' '
+       echo a >>file &&
+       test_tick &&
+       GIT_AUTHOR_NAME="With * Asterisk" \
+       GIT_AUTHOR_EMAIL="xyzzy@frotz.com" \
+       git commit -a -m "second" &&
+
+       echo a >>file &&
+       test_tick &&
+       git commit -a -m "third"
+
+'
+
+test_expect_success 'log grep (1)' '
+       git log --author=author --pretty=tformat:%s >actual &&
+       ( echo third ; echo initial ) >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (2)' '
+       git log --author=" * " -F --pretty=tformat:%s >actual &&
+       ( echo second ) >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (3)' '
+       git log --author="^A U" --pretty=tformat:%s >actual &&
+       ( echo third ; echo initial ) >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (4)' '
+       git log --author="frotz\.com>$" --pretty=tformat:%s >actual &&
+       ( echo second ) >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (5)' '
+       git log --author=Thor -F --grep=Thu --pretty=tformat:%s >actual &&
+       ( echo third ; echo initial ) >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log grep (6)' '
+       git log --author=-0700  --pretty=tformat:%s >actual &&
+       >expect &&
+       test_cmp expect actual
+
+'
+
 test_done