Commit 19d77ce10937a5b86e114192f816fef9ba7e23b3

Vicent Marti 2014-05-29T14:51:25

Merge pull request #2381 from ecoffey/example_log_author_filter Add support for --author flag in example log implementation

diff --git a/PROJECTS.md b/PROJECTS.md
index 9472fb4..d172144 100644
--- a/PROJECTS.md
+++ b/PROJECTS.md
@@ -39,12 +39,6 @@ These are good small projects to get started with libgit2.
       the data is available, you would just need to add the code into the
       `print_commit()` routine (along with a way of passing the option
       into that function).
-    * For `examples/log.c`, implement any one of `--author=<...>`,
-      `--committer=<...>`, or `--grep=<...>` but just use simple string
-      match with `strstr()` instead of full regular expression
-      matching. (I.e. I'm suggesting implementing this as if
-      `--fixed-strings` was always turned on, because it will be a simpler
-      project.)
     * As an extension to the matching idea for `examples/log.c`, add the
       `-i` option to use `strcasestr()` for matches.
     * For `examples/log.c`, implement the `--first-parent` option now that
diff --git a/examples/log.c b/examples/log.c
index 471c5ff..d5f75a2 100644
--- a/examples/log.c
+++ b/examples/log.c
@@ -54,8 +54,9 @@ struct log_options {
 	int min_parents, max_parents;
 	git_time_t before;
 	git_time_t after;
-	char *author;
-	char *committer;
+	const char *author;
+	const char *committer;
+	const char *grep;
 };
 
 /** utility functions that parse options and help with log output */
@@ -65,6 +66,9 @@ static void print_time(const git_time *intime, const char *prefix);
 static void print_commit(git_commit *commit);
 static int match_with_parent(git_commit *commit, int i, git_diff_options *);
 
+/** utility functions for filtering */
+static int signature_matches(const git_signature *sig, const char *filter);
+static int log_message_matches(const git_commit *commit, const char *filter);
 
 int main(int argc, char *argv[])
 {
@@ -128,6 +132,15 @@ int main(int argc, char *argv[])
 				continue;
 		}
 
+		if (!signature_matches(git_commit_author(commit), opt.author))
+			continue;
+
+		if (!signature_matches(git_commit_committer(commit), opt.committer))
+			continue;
+
+		if (!log_message_matches(commit, opt.grep))
+			continue;
+
 		if (count++ < opt.skip)
 			continue;
 		if (opt.limit != -1 && printed++ >= opt.limit) {
@@ -172,6 +185,32 @@ int main(int argc, char *argv[])
 	return 0;
 }
 
+/** Determine if the given git_signature does not contain the filter text. */
+static int signature_matches(const git_signature *sig, const char *filter) {
+	if (filter == NULL)
+		return 1;
+
+	if (sig != NULL &&
+		(strstr(sig->name, filter) != NULL ||
+		strstr(sig->email, filter) != NULL))
+		return 1;
+
+	return 0;
+}
+
+static int log_message_matches(const git_commit *commit, const char *filter) {
+	const char *message = NULL;
+
+	if (filter == NULL)
+		return 1;
+
+	if ((message = git_commit_message(commit)) != NULL &&
+		strstr(message, filter) != NULL)
+		return 1;
+
+	return 0;
+}
+
 /** Push object (for hide or show) onto revwalker. */
 static void push_rev(struct log_state *s, git_object *obj, int hide)
 {
@@ -401,6 +440,12 @@ static int parse_options(
 			set_sorting(s, GIT_SORT_TOPOLOGICAL);
 		else if (!strcmp(a, "--reverse"))
 			set_sorting(s, GIT_SORT_REVERSE);
+		else if (match_str_arg(&opt->author, &args, "--author"))
+			/** Found valid --author */;
+		else if (match_str_arg(&opt->committer, &args, "--committer"))
+			/** Found valid --committer */;
+		else if (match_str_arg(&opt->grep, &args, "--grep"))
+			/** Found valid --grep */;
 		else if (match_str_arg(&s->repodir, &args, "--git-dir"))
 			/** Found git-dir. */;
 		else if (match_int_arg(&opt->skip, &args, "--skip", 0))