diff --color: use $GIT_DIR/config

This lets you use something like this in your $GIT_DIR/config
file.

	[diff]
		color = auto

	[diff.color]
		new = blue
		old = yellow
		frag = reverse

When diff.color is set to "auto", colored diff is enabled when
the standard output is the terminal.  Other choices are "always",
and "never".  Usual boolean true/false can also be used.

The colormap entries can specify colors for the following slots:

	plain	- lines that appear in both old and new file (context)
	meta	- diff --git header and extended git diff headers
	frag	- @@ -n,m +l,k @@ lines (hunk header)
	old	- lines deleted from old file
	new	- lines added to new file

The following color names can be used:

	normal, bold, dim, l, blink, reverse, reset,
	black, red, green, yellow, blue, magenta, cyan,
	white

Signed-off-by: Junio C Hamano <junkio@cox.net>
diff --git a/cache.h b/cache.h
index 14358a8..8719939 100644
--- a/cache.h
+++ b/cache.h
@@ -181,7 +181,6 @@
 extern int prefer_symlink_refs;
 extern int log_all_ref_updates;
 extern int warn_ambiguous_refs;
-extern int diff_rename_limit_default;
 extern int shared_repository;
 extern const char *apply_default_whitespace;
 
diff --git a/diff.c b/diff.c
index 834b166..e73c0c3 100644
--- a/diff.c
+++ b/diff.c
@@ -13,17 +13,8 @@
 
 static int use_size_cache;
 
-int diff_rename_limit_default = -1;
-
-int git_diff_config(const char *var, const char *value)
-{
-	if (!strcmp(var, "diff.renamelimit")) {
-		diff_rename_limit_default = git_config_int(var, value);
-		return 0;
-	}
-
-	return git_default_config(var, value);
-}
+static int diff_rename_limit_default = -1;
+static int diff_use_color_default = 0;
 
 enum color_diff {
 	DIFF_RESET = 0,
@@ -51,9 +42,6 @@
 #define COLOR_CYAN    "\033[36m"
 #define COLOR_WHITE   "\033[37m"
 
-#define COLOR_CYANBG  "\033[46m"
-#define COLOR_GRAYBG  "\033[47m"	// Good for xterm
-
 static const char *diff_colors[] = {
 	[DIFF_RESET]    = COLOR_RESET,
 	[DIFF_PLAIN]    = COLOR_NORMAL,
@@ -63,6 +51,83 @@
 	[DIFF_FILE_NEW] = COLOR_GREEN,
 };
 
+static int parse_diff_color_slot(const char *var, int ofs)
+{
+	if (!strcasecmp(var+ofs, "plain"))
+		return DIFF_PLAIN;
+	if (!strcasecmp(var+ofs, "meta"))
+		return DIFF_METAINFO;
+	if (!strcasecmp(var+ofs, "frag"))
+		return DIFF_FRAGINFO;
+	if (!strcasecmp(var+ofs, "old"))
+		return DIFF_FILE_OLD;
+	if (!strcasecmp(var+ofs, "new"))
+		return DIFF_FILE_NEW;
+	die("bad config variable '%s'", var);
+}
+
+static const char *parse_diff_color_value(const char *value, const char *var)
+{
+	if (!strcasecmp(value, "normal"))
+		return COLOR_NORMAL;
+	if (!strcasecmp(value, "bold"))
+		return COLOR_BOLD;
+	if (!strcasecmp(value, "dim"))
+		return COLOR_DIM;
+	if (!strcasecmp(value, "ul"))
+		return COLOR_UL;
+	if (!strcasecmp(value, "blink"))
+		return COLOR_BLINK;
+	if (!strcasecmp(value, "reverse"))
+		return COLOR_REVERSE;
+	if (!strcasecmp(value, "reset"))
+		return COLOR_RESET;
+	if (!strcasecmp(value, "black"))
+		return COLOR_BLACK;
+	if (!strcasecmp(value, "red"))
+		return COLOR_RED;
+	if (!strcasecmp(value, "green"))
+		return COLOR_GREEN;
+	if (!strcasecmp(value, "yellow"))
+		return COLOR_YELLOW;
+	if (!strcasecmp(value, "blue"))
+		return COLOR_BLUE;
+	if (!strcasecmp(value, "magenta"))
+		return COLOR_MAGENTA;
+	if (!strcasecmp(value, "cyan"))
+		return COLOR_CYAN;
+	if (!strcasecmp(value, "white"))
+		return COLOR_WHITE;
+	die("bad config value '%s' for variable '%s'", value, var);
+}
+
+int git_diff_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "diff.renamelimit")) {
+		diff_rename_limit_default = git_config_int(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "diff.color")) {
+		if (!value)
+			diff_use_color_default = 1; /* bool */
+		else if (!strcasecmp(value, "auto"))
+			diff_use_color_default = isatty(1);
+		else if (!strcasecmp(value, "never"))
+			diff_use_color_default = 0;
+		else if (!strcasecmp(value, "always"))
+			diff_use_color_default = 1;
+		else
+			diff_use_color_default = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strncmp(var, "diff.color.", 11)) {
+		int slot = parse_diff_color_slot(var, 11);
+		diff_colors[slot] = parse_diff_color_value(value, var);
+		return 0;
+	}
+	return git_default_config(var, value);
+}
+
 static char *quote_one(const char *str)
 {
 	int needlen;
@@ -1362,6 +1427,7 @@
 
 	options->change = diff_change;
 	options->add_remove = diff_addremove;
+	options->color_diff = diff_use_color_default;
 }
 
 int diff_setup_done(struct diff_options *options)