[PATCH] Teach "log -F --author=<match>" to behave better

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To handle --author=<match> request, the code created a grep instruction
that tried to match a line that begins with 'author ' and <match>
somewhere on the same line.  "begins with 'author '" obviously needs to be
expressed with an regexp '^author '.

When the user specifies --fixed-string, this does not work at all.

This extends the grep machinery so that a match insn can ignore user
specified --fixed-string request, and uses the '( -e A --and -e B )'
construct from the grep machinery in order to express "has to begin with
'^author ', and also the same line must match the given pattern".

Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx>
---

 * A variant of this would be to make the --author match always ignore -F,
   which is now possible with the enhancement to the grep machinery.  But
   it is unlikely that you would have regexp metacharacters in author
   field, so it might not be necessary.

   "log -F --author=1220485514" would match the timestamp part of the
   author line.  This will not likely to change but it is not likely to
   cause issues in real world either, so I would not bother to address it
   myself.

 grep.c     |   16 ++++++++++++----
 grep.h     |    3 +++
 revision.c |   44 ++++++++++++++++++++++++++++++++++++++++++++
 revision.h |    7 +++++++
 4 files changed, 66 insertions(+), 4 deletions(-)

diff --git c/grep.c w/grep.c
index f67d671..dd71b78 100644
--- c/grep.c
+++ w/grep.c
@@ -2,19 +2,27 @@
 #include "grep.h"
 #include "xdiff-interface.h"
 
-void append_grep_pattern(struct grep_opt *opt, const char *pat,
-			 const char *origin, int no, enum grep_pat_token t)
+void append_grep_pattern_special(struct grep_opt *opt, const char *pat,
+				const char *origin, int no,
+				enum grep_pat_token t, unsigned flags)
 {
 	struct grep_pat *p = xcalloc(1, sizeof(*p));
 	p->pattern = pat;
 	p->origin = origin;
 	p->no = no;
 	p->token = t;
+	p->flags = flags;
 	*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)
+{
+	append_grep_pattern_special(opt, pat, origin, no, t, 0);
+}
+
 static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
 {
 	int err = regcomp(&p->regexp, p->pattern, opt->regflags);
@@ -146,7 +154,7 @@ void compile_grep_patterns(struct grep_opt *opt)
 		case GREP_PATTERN: /* atom */
 		case GREP_PATTERN_HEAD:
 		case GREP_PATTERN_BODY:
-			if (!opt->fixed)
+			if (!opt->fixed || (p->flags & GREP_ALWAYS_REGEXP))
 				compile_regexp(p, opt);
 			break;
 		default:
@@ -258,7 +266,7 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol
 		return 0;
 
  again:
-	if (!opt->fixed) {
+	if (!opt->fixed || (p->flags & GREP_ALWAYS_REGEXP)) {
 		regex_t *exp = &p->regexp;
 		hit = !regexec(exp, bol, ARRAY_SIZE(pmatch),
 			       pmatch, 0);
diff --git c/grep.h w/grep.h
index d252dd2..b03d89d 100644
--- c/grep.h
+++ w/grep.h
@@ -21,6 +21,8 @@ struct grep_pat {
 	struct grep_pat *next;
 	const char *origin;
 	int no;
+	unsigned flags;
+#define GREP_ALWAYS_REGEXP 01
 	enum grep_pat_token token;
 	const char *pattern;
 	regex_t regexp;
@@ -73,6 +75,7 @@ struct grep_opt {
 	unsigned post_context;
 };
 
+extern void append_grep_pattern_special(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t, unsigned);
 extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
 extern void compile_grep_patterns(struct grep_opt *opt);
 extern void free_grep_patterns(struct grep_opt *opt);
diff --git c/revision.c w/revision.c
index 83478ef..65d22f5 100644
--- c/revision.c
+++ w/revision.c
@@ -955,6 +955,17 @@ static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token
 
 static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern)
 {
+	struct pending_header_grep *p = xcalloc(1, sizeof(*p));
+	p->next = revs->pending_header_grep;
+	p->field = field;
+	p->pattern = pattern;
+	revs->pending_header_grep = p;;
+}
+
+static void add_header_grep_regexp(struct rev_info *revs, struct pending_header_grep *p)
+{
+	const char *field = p->field;
+	const char *pattern = p->pattern;
 	char *pat;
 	const char *prefix, *suffix;
 	int patlen, fldlen;
@@ -977,6 +988,38 @@ static void add_header_grep(struct rev_info *revs, const char *field, const char
 	add_grep(revs, pat, GREP_PATTERN_HEAD);
 }
 
+static void add_header_grep_fixed(struct rev_info *revs, struct pending_header_grep *p)
+{
+	char *field = xmalloc(strlen(p->field) + 2);
+	strcpy(field + 1, p->field);
+	field[0] = '^';
+	append_grep_pattern(&revs->grep_filter, "(",
+			    "header grep", 0, GREP_OPEN_PAREN);
+	append_grep_pattern_special(&revs->grep_filter, field,
+				    "header grep", 0, GREP_PATTERN_HEAD,
+				    GREP_ALWAYS_REGEXP);
+	append_grep_pattern(&revs->grep_filter, "--and",
+			    "header grep", 0, GREP_AND);
+	add_grep(revs, p->pattern, GREP_PATTERN_HEAD);
+	append_grep_pattern(&revs->grep_filter, ")",
+			    "header grep", 0, GREP_CLOSE_PAREN);
+}
+
+static void finish_header_grep(struct rev_info *revs)
+{
+	struct pending_header_grep *q, *p = revs->pending_header_grep;
+
+	while (p) {
+		if (revs->grep_filter.fixed)
+			add_header_grep_fixed(revs, p);
+		else
+			add_header_grep_regexp(revs, p);
+		q = p->next;
+		free(p);
+		p = q;
+	}
+}
+
 static void add_message_grep(struct rev_info *revs, const char *pattern)
 {
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
@@ -1347,6 +1390,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 	if (diff_setup_done(&revs->diffopt) < 0)
 		die("diff_setup_done failed");
 
+	finish_header_grep(revs);
 	compile_grep_patterns(&revs->grep_filter);
 
 	if (revs->reverse && revs->reflog_info)
diff --git c/revision.h w/revision.h
index 91f1944..f9cfa26 100644
--- c/revision.h
+++ w/revision.h
@@ -18,6 +18,12 @@
 struct rev_info;
 struct log_info;
 
+struct pending_header_grep {
+	struct pending_header_grep *next;
+	const char *field;
+	const char *pattern;
+};
+
 struct rev_info {
 	/* Starting list */
 	struct commit_list *commits;
@@ -94,6 +100,7 @@ struct rev_info {
 
 	/* Filter by commit log message */
 	struct grep_opt	grep_filter;
+	struct pending_header_grep *pending_header_grep;
 
 	/* Display history graph */
 	struct git_graph *graph;
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux