Subject: [PATCH 5/5] diff: support --exclude

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Thu, 10 Mar 2011 10:13:39 +0700

diff_setup_done() will update diff_options.pathspec, so if you give

--exclude '*.h' -- src/

then the final pathspec looks like

 - src/
 - *.h (negated)

The code is protected against multiple call because setup_revisions()
may call it once, then the outer code calls it again. I'm not sure if
doing it this way is correct though.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 diff.c |   41 ++++++++++++++++++++++++++++++++++++++++-
 diff.h |    1 +
 2 files changed, 41 insertions(+), 1 deletions(-)

diff --git a/diff.c b/diff.c
index 6f206a9..14f1cfc 100644
--- a/diff.c
+++ b/diff.c
@@ -2973,6 +2973,34 @@ int diff_setup_done(struct diff_options *options)
 		DIFF_OPT_SET(options, EXIT_WITH_STATUS);
 	}
 
+	/*
+	 * Adjust options->pathspec. All --exclude will be appended to
+	 * options->pathspec with to_exclude set.
+	 */
+	if (options->paths &&
+	    options->pathspec.raw != options->paths) { /* avoid being called twice */
+		int i, nr, new_nr, exc;
+
+		nr = options->pathspec.nr ? options->pathspec.nr : 1;
+		for (exc = 0; options->paths[exc]; exc++)
+			;			  /* nothing */
+		new_nr = nr + exc;
+
+		options->paths = xrealloc(options->paths, sizeof(char*) * (new_nr + 1));
+		memmove(options->paths + nr, options->paths, sizeof(char*) * (exc + 1));
+		if (options->pathspec.nr)
+			memcpy(options->paths, options->pathspec.raw, sizeof(char*) * nr);
+		else
+			options->paths[0] = "";
+
+		free_pathspec(&options->pathspec);
+		init_pathspec(&options->pathspec, options->paths);
+		for (i = nr; i < new_nr; i++) {
+			struct pathspec_item *item = options->pathspec.items + i;
+			item->to_exclude = 1;
+		}
+	}
+
 	return 0;
 }
 
@@ -2980,6 +3008,7 @@ int diff_setup_done(struct diff_options *options)
 void release_diff(struct diff_options *o)
 {
 	free_pathspec(&o->pathspec);
+	free(o->paths);
 }
 
 static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
@@ -3347,7 +3376,17 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 			die_errno("Could not open '%s'", optarg);
 		options->close_file = 1;
 		return argcount;
-	} else
+	}
+	else if ((argcount = parse_long_opt("exclude", av, &optarg))) {
+		int i = 1;
+		while (options->paths && options->paths[i])
+			i++;
+		options->paths = xrealloc(options->paths, sizeof(char*) * (i + 1));
+		options->paths[i - 1] = optarg;
+		options->paths[i] = 0;
+		return argcount;
+	}
+	else
 		return 0;
 	return 1;
 }
diff --git a/diff.h b/diff.h
index 12a9907..b60057c 100644
--- a/diff.h
+++ b/diff.h
@@ -134,6 +134,7 @@ struct diff_options {
 	int close_file;
 
 	struct pathspec pathspec;
+	const char **paths;
 	change_fn_t change;
 	add_remove_fn_t add_remove;
 	diff_format_fn_t format_callback;
-- 
1.7.3.1.256.g2539c.dirty