git-stash.sh: fix flawed fix of invalid ref handling (commit da65e7c1)
[gitweb.git] / grep.c
diff --git a/grep.c b/grep.c
index fcc676230282e4c5bda4f9f97c5ae65c1a6beb30..706351197fc26efa10c4666d38433f8fbdf1d6b5 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1,5 +1,19 @@
 #include "cache.h"
 #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)
@@ -232,17 +246,6 @@ static void show_line(struct grep_opt *opt, const char *bol, const char *eol,
        printf("%.*s\n", (int)(eol-bol), bol);
 }
 
-/*
- * NEEDSWORK: share code with diff.c
- */
-#define FIRST_FEW_BYTES 8000
-static int buffer_is_binary(const char *ptr, unsigned long size)
-{
-       if (FIRST_FEW_BYTES < size)
-               size = FIRST_FEW_BYTES;
-       return !!memchr(ptr, 0, size);
-}
-
 static int fixmatch(const char *pattern, char *line, regmatch_t *match)
 {
        char *hit = strstr(line, pattern);
@@ -257,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;
@@ -308,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;
 }