Git 1.8.0-rc1
[gitweb.git] / grep.c
diff --git a/grep.c b/grep.c
index 04e3ec6c6e90e8bd96495c7b40bcb014384b07d8..edc7776677ed201dbe117c207a680e1f832737e3 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -3,6 +3,10 @@
 #include "userdiff.h"
 #include "xdiff-interface.h"
 
+static int grep_source_load(struct grep_source *gs);
+static int grep_source_is_binary(struct grep_source *gs);
+
+
 static struct grep_pat *create_grep_pat(const char *pat, size_t patlen,
                                        const char *origin, int no,
                                        enum grep_pat_token t,
@@ -60,6 +64,8 @@ void append_header_grep_pattern(struct grep_opt *opt,
 {
        struct grep_pat *p = create_grep_pat(pat, strlen(pat), "header", 0,
                                             GREP_PATTERN_HEAD, field);
+       if (field == GREP_HEADER_REFLOG)
+               opt->use_reflog_filter = 1;
        do_append_grep_pat(&opt->header_tail, p);
 }
 
@@ -332,6 +338,87 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
        return compile_pattern_or(list);
 }
 
+static void indent(int in)
+{
+       while (in-- > 0)
+               fputc(' ', stderr);
+}
+
+static void dump_grep_pat(struct grep_pat *p)
+{
+       switch (p->token) {
+       case GREP_AND: fprintf(stderr, "*and*"); break;
+       case GREP_OPEN_PAREN: fprintf(stderr, "*(*"); break;
+       case GREP_CLOSE_PAREN: fprintf(stderr, "*)*"); break;
+       case GREP_NOT: fprintf(stderr, "*not*"); break;
+       case GREP_OR: fprintf(stderr, "*or*"); break;
+
+       case GREP_PATTERN: fprintf(stderr, "pattern"); break;
+       case GREP_PATTERN_HEAD: fprintf(stderr, "pattern_head"); break;
+       case GREP_PATTERN_BODY: fprintf(stderr, "pattern_body"); break;
+       }
+
+       switch (p->token) {
+       default: break;
+       case GREP_PATTERN_HEAD:
+               fprintf(stderr, "<head %d>", p->field); break;
+       case GREP_PATTERN_BODY:
+               fprintf(stderr, "<body>"); break;
+       }
+       switch (p->token) {
+       default: break;
+       case GREP_PATTERN_HEAD:
+       case GREP_PATTERN_BODY:
+       case GREP_PATTERN:
+               fprintf(stderr, "%.*s", (int)p->patternlen, p->pattern);
+               break;
+       }
+       fputc('\n', stderr);
+}
+
+static void dump_grep_expression_1(struct grep_expr *x, int in)
+{
+       indent(in);
+       switch (x->node) {
+       case GREP_NODE_TRUE:
+               fprintf(stderr, "true\n");
+               break;
+       case GREP_NODE_ATOM:
+               dump_grep_pat(x->u.atom);
+               break;
+       case GREP_NODE_NOT:
+               fprintf(stderr, "(not\n");
+               dump_grep_expression_1(x->u.unary, in+1);
+               indent(in);
+               fprintf(stderr, ")\n");
+               break;
+       case GREP_NODE_AND:
+               fprintf(stderr, "(and\n");
+               dump_grep_expression_1(x->u.binary.left, in+1);
+               dump_grep_expression_1(x->u.binary.right, in+1);
+               indent(in);
+               fprintf(stderr, ")\n");
+               break;
+       case GREP_NODE_OR:
+               fprintf(stderr, "(or\n");
+               dump_grep_expression_1(x->u.binary.left, in+1);
+               dump_grep_expression_1(x->u.binary.right, in+1);
+               indent(in);
+               fprintf(stderr, ")\n");
+               break;
+       }
+}
+
+static void dump_grep_expression(struct grep_opt *opt)
+{
+       struct grep_expr *x = opt->pattern_expression;
+
+       if (opt->all_match)
+               fprintf(stderr, "[all-match]\n");
+       dump_grep_expression_1(x, 0);
+       fflush(NULL);
+}
+
 static struct grep_expr *grep_true_expr(void)
 {
        struct grep_expr *z = xcalloc(1, sizeof(*z));
@@ -395,7 +482,23 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
        return header_expr;
 }
 
-void compile_grep_patterns(struct grep_opt *opt)
+static struct grep_expr *grep_splice_or(struct grep_expr *x, struct grep_expr *y)
+{
+       struct grep_expr *z = x;
+
+       while (x) {
+               assert(x->node == GREP_NODE_OR);
+               if (x->u.binary.right &&
+                   x->u.binary.right->node == GREP_NODE_TRUE) {
+                       x->u.binary.right = y;
+                       break;
+               }
+               x = x->u.binary.right;
+       }
+       return z;
+}
+
+static void compile_grep_patterns_real(struct grep_opt *opt)
 {
        struct grep_pat *p;
        struct grep_expr *header_expr = prep_header_patterns(opt);
@@ -415,7 +518,7 @@ void compile_grep_patterns(struct grep_opt *opt)
 
        if (opt->all_match || header_expr)
                opt->extended = 1;
-       else if (!opt->extended)
+       else if (!opt->extended && !opt->debug)
                return;
 
        p = opt->pattern_list;
@@ -429,12 +532,22 @@ void compile_grep_patterns(struct grep_opt *opt)
 
        if (!opt->pattern_expression)
                opt->pattern_expression = header_expr;
+       else if (opt->all_match)
+               opt->pattern_expression = grep_splice_or(header_expr,
+                                                        opt->pattern_expression);
        else
                opt->pattern_expression = grep_or_expr(opt->pattern_expression,
                                                       header_expr);
        opt->all_match = 1;
 }
 
+void compile_grep_patterns(struct grep_opt *opt)
+{
+       compile_grep_patterns_real(opt);
+       if (opt->debug)
+               dump_grep_expression(opt);
+}
+
 static void free_pattern_expr(struct grep_expr *x)
 {
        switch (x->node) {
@@ -586,6 +699,7 @@ static struct {
 } header_field[] = {
        { "author ", 7 },
        { "committer ", 10 },
+       { "reflog ", 7 },
 };
 
 static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
@@ -609,7 +723,14 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
                if (strncmp(bol, field, len))
                        return 0;
                bol += len;
-               saved_ch = strip_timestamp(bol, &eol);
+               switch (p->field) {
+               case GREP_HEADER_AUTHOR:
+               case GREP_HEADER_COMMITTER:
+                       saved_ch = strip_timestamp(bol, &eol);
+                       break;
+               default:
+                       break;
+               }
        }
 
  again:
@@ -1358,7 +1479,7 @@ static int grep_source_load_file(struct grep_source *gs)
        return 0;
 }
 
-int grep_source_load(struct grep_source *gs)
+static int grep_source_load(struct grep_source *gs)
 {
        if (gs->buf)
                return 0;
@@ -1386,7 +1507,7 @@ void grep_source_load_driver(struct grep_source *gs)
        grep_attr_unlock();
 }
 
-int grep_source_is_binary(struct grep_source *gs)
+static int grep_source_is_binary(struct grep_source *gs)
 {
        grep_source_load_driver(gs);
        if (gs->driver->binary != -1)