Code

merge-recursive.c: guard config parser from value=NULL
[git.git] / diff.c
diff --git a/diff.c b/diff.c
index 44aa477c41e2d6b68e43d3c74a7996bf21a630a9..4d2e23ae1b7dd4bd43d5c03871ce8ab519272115 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -10,6 +10,7 @@
 #include "color.h"
 #include "attr.h"
 #include "run-command.h"
+#include "utf8.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -59,14 +60,6 @@ static struct ll_diff_driver {
        char *cmd;
 } *user_diff, **user_diff_tail;
 
-static void read_config_if_needed(void)
-{
-       if (!user_diff_tail) {
-               user_diff_tail = &user_diff;
-               git_config(git_diff_ui_config);
-       }
-}
-
 /*
  * Currently there is only "diff.<drivername>.command" variable;
  * because there are "diff.color.<slot>" variables, we are parsing
@@ -165,6 +158,8 @@ int git_diff_ui_config(const char *var, const char *value)
                return 0;
        }
        if (!strcmp(var, "diff.external")) {
+               if (!value)
+                       return config_error_nonbool(var);
                external_diff_cmd_cfg = xstrdup(value);
                return 0;
        }
@@ -172,10 +167,11 @@ int git_diff_ui_config(const char *var, const char *value)
                const char *ep = strrchr(var, '.');
 
                if (ep != var + 4) {
-                       if (!strcmp(ep, ".command"))
+                       if (!strcmp(ep, ".command")) {
+                               if (!value)
+                                       return config_error_nonbool(var);
                                return parse_lldiff_command(var, ep, value);
-                       if (!strcmp(ep, ".funcname"))
-                               return parse_funcname_pattern(var, ep, value);
+                       }
                }
        }
 
@@ -186,10 +182,23 @@ int git_diff_basic_config(const char *var, const char *value)
 {
        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
+               if (!value)
+                       return config_error_nonbool(var);
                color_parse(value, var, diff_colors[slot]);
                return 0;
        }
 
+       if (!prefixcmp(var, "diff.")) {
+               const char *ep = strrchr(var, '.');
+               if (ep != var + 4) {
+                       if (!strcmp(ep, ".funcname")) {
+                               if (!value)
+                                       return config_error_nonbool(var);
+                               return parse_funcname_pattern(var, ep, value);
+                       }
+               }
+       }
+
        return git_default_config(var, value);
 }
 
@@ -471,10 +480,13 @@ static void diff_words_show(struct diff_words_data *diff_words)
        }
 }
 
+typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
+
 struct emit_callback {
        struct xdiff_emit_state xm;
        int nparents, color_diff;
        unsigned ws_rule;
+       sane_truncate_fn truncate;
        const char **label_path;
        struct diff_words_data *diff_words;
        int *found_changesp;
@@ -527,12 +539,31 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons
        }
 }
 
+static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len)
+{
+       const char *cp;
+       unsigned long allot;
+       size_t l = len;
+
+       if (ecb->truncate)
+               return ecb->truncate(line, len);
+       cp = line;
+       allot = l;
+       while (0 < l) {
+               (void) utf8_width(&cp, &l);
+               if (!cp)
+                       break; /* truncated in the middle? */
+       }
+       return allot - l;
+}
+
 static void fn_out_consume(void *priv, char *line, unsigned long len)
 {
        int i;
        int color;
        struct emit_callback *ecbdata = priv;
-       const char *set = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
+       const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO);
+       const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN);
        const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET);
 
        *(ecbdata->found_changesp) = 1;
@@ -544,9 +575,9 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
                name_b_tab = strchr(ecbdata->label_path[1], ' ') ? "\t" : "";
 
                printf("%s--- %s%s%s\n",
-                      set, ecbdata->label_path[0], reset, name_a_tab);
+                      meta, ecbdata->label_path[0], reset, name_a_tab);
                printf("%s+++ %s%s%s\n",
-                      set, ecbdata->label_path[1], reset, name_b_tab);
+                      meta, ecbdata->label_path[1], reset, name_b_tab);
                ecbdata->label_path[0] = ecbdata->label_path[1] = NULL;
        }
 
@@ -557,13 +588,15 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
                ;
        if (2 <= i && i < len && line[i] == ' ') {
                ecbdata->nparents = i - 1;
+               len = sane_truncate_line(ecbdata, line, len);
                emit_line(diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO),
                          reset, line, len);
+               if (line[len-1] != '\n')
+                       putchar('\n');
                return;
        }
 
        if (len < ecbdata->nparents) {
-               set = reset;
                emit_line(reset, reset, line, len);
                return;
        }
@@ -587,7 +620,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
                        diff_words_show(ecbdata->diff_words);
                line++;
                len--;
-               emit_line(set, reset, line, len);
+               emit_line(plain, reset, line, len);
                return;
        }
        for (i = 0; i < ecbdata->nparents && len; i++) {
@@ -1160,7 +1193,6 @@ static const char *funcname_pattern(const char *ident)
 {
        struct funcname_pattern *pp;
 
-       read_config_if_needed();
        for (pp = funcname_pattern_list; pp; pp = pp->next)
                if (!strcmp(ident, pp->name))
                        return pp->pattern;
@@ -1202,7 +1234,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
 
        /*
         * And define built-in fallback patterns here.  Note that
-        * these can be overriden by the user's config settings.
+        * these can be overridden by the user's config settings.
         */
        for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
                if (!strcmp(ident, builtin_funcname_pattern[i].name))
@@ -1817,7 +1849,6 @@ static const char *external_diff_attr(const char *name)
                    !ATTR_UNSET(value)) {
                        struct ll_diff_driver *drv;
 
-                       read_config_if_needed();
                        for (drv = user_diff; drv; drv = drv->next)
                                if (!strcmp(drv->name, value))
                                        return drv->cmd;