Fix random sha1 in error message in http-fetch and http-push
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index b08d28a5780cf242a4de78e0f5c4007b7041f392..3dd2f35f7364341bcb5f4507ea36d03925fdc938 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -146,7 +146,7 @@ int git_diff_ui_config(const char *var, const char *value)
                return 0;
        }
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
-               diff_use_color_default = git_config_colorbool(var, value);
+               diff_use_color_default = git_config_colorbool(var, value, -1);
                return 0;
        }
        if (!strcmp(var, "diff.renames")) {
@@ -439,7 +439,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
        ecb.outf = xdiff_outf;
        ecb.priv = diff_words;
        diff_words->xm.consume = fn_out_diff_words_aux;
-       xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
+       xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
 
        free(minus.ptr);
        free(plus.ptr);
@@ -454,6 +454,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
 struct emit_callback {
        struct xdiff_emit_state xm;
        int nparents, color_diff;
+       unsigned ws_rule;
        const char **label_path;
        struct diff_words_data *diff_words;
        int *found_changesp;
@@ -493,8 +494,8 @@ static void emit_line(const char *set, const char *reset, const char *line, int
 }
 
 static void emit_line_with_ws(int nparents,
-               const char *set, const char *reset, const char *ws,
-               const char *line, int len)
+                             const char *set, const char *reset, const char *ws,
+                             const char *line, int len, unsigned ws_rule)
 {
        int col0 = nparents;
        int last_tab_in_indent = -1;
@@ -502,13 +503,17 @@ static void emit_line_with_ws(int nparents,
        int i;
        int tail = len;
        int need_highlight_leading_space = 0;
-       /* The line is a newly added line.  Does it have funny leading
-        * whitespaces?  In indent, SP should never precede a TAB.
+       /*
+        * The line is a newly added line.  Does it have funny leading
+        * whitespaces?  In indent, SP should never precede a TAB.  In
+        * addition, under "indent with non tab" rule, there should not
+        * be more than 8 consecutive spaces.
         */
        for (i = col0; i < len; i++) {
                if (line[i] == '\t') {
                        last_tab_in_indent = i;
-                       if (0 <= last_space_in_indent)
+                       if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
+                           0 <= last_space_in_indent)
                                need_highlight_leading_space = 1;
                }
                else if (line[i] == ' ')
@@ -516,6 +521,13 @@ static void emit_line_with_ws(int nparents,
                else
                        break;
        }
+       if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
+           0 <= last_space_in_indent &&
+           last_tab_in_indent < 0 &&
+           8 <= (i - col0)) {
+               last_tab_in_indent = i;
+               need_highlight_leading_space = 1;
+       }
        fputs(set, stdout);
        fwrite(line, col0, 1, stdout);
        fputs(reset, stdout);
@@ -540,10 +552,12 @@ static void emit_line_with_ws(int nparents,
        tail = len - 1;
        if (line[tail] == '\n' && i < tail)
                tail--;
-       while (i < tail) {
-               if (!isspace(line[tail]))
-                       break;
-               tail--;
+       if (ws_rule & WS_TRAILING_SPACE) {
+               while (i < tail) {
+                       if (!isspace(line[tail]))
+                               break;
+                       tail--;
+               }
        }
        if ((i < tail && line[tail + 1] != '\n')) {
                /* This has whitespace between tail+1..len */
@@ -565,7 +579,7 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons
                emit_line(set, reset, line, len);
        else
                emit_line_with_ws(ecbdata->nparents, set, reset, ws,
-                               line, len);
+                                 line, len, ecbdata->ws_rule);
 }
 
 static void fn_out_consume(void *priv, char *line, unsigned long len)
@@ -720,7 +734,9 @@ struct diffstat_t {
        int nr;
        int alloc;
        struct diffstat_file {
+               char *from_name;
                char *name;
+               char *print_name;
                unsigned is_unmerged:1;
                unsigned is_binary:1;
                unsigned is_renamed:1;
@@ -741,11 +757,14 @@ static struct diffstat_file *diffstat_add(struct diffstat_t *diffstat,
        }
        diffstat->files[diffstat->nr++] = x;
        if (name_b) {
-               x->name = pprint_rename(name_a, name_b);
+               x->from_name = xstrdup(name_a);
+               x->name = xstrdup(name_b);
                x->is_renamed = 1;
        }
-       else
+       else {
+               x->from_name = NULL;
                x->name = xstrdup(name_a);
+       }
        return x;
 }
 
@@ -789,6 +808,28 @@ static void show_graph(char ch, int cnt, const char *set, const char *reset)
        printf("%s", reset);
 }
 
+static void fill_print_name(struct diffstat_file *file)
+{
+       char *pname;
+
+       if (file->print_name)
+               return;
+
+       if (!file->is_renamed) {
+               struct strbuf buf;
+               strbuf_init(&buf, 0);
+               if (quote_c_style(file->name, &buf, NULL, 0)) {
+                       pname = strbuf_detach(&buf, NULL);
+               } else {
+                       pname = file->name;
+                       strbuf_release(&buf);
+               }
+       } else {
+               pname = pprint_rename(file->from_name, file->name);
+       }
+       file->print_name = pname;
+}
+
 static void show_stats(struct diffstat_t* data, struct diff_options *options)
 {
        int i, len, add, del, total, adds = 0, dels = 0;
@@ -822,19 +863,8 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
                int change = file->added + file->deleted;
-
-               if (!file->is_renamed) {  /* renames are already quoted by pprint_rename */
-                       struct strbuf buf;
-                       strbuf_init(&buf, 0);
-                       if (quote_c_style(file->name, &buf, NULL, 0)) {
-                               free(file->name);
-                               file->name = strbuf_detach(&buf, NULL);
-                       } else {
-                               strbuf_release(&buf);
-                       }
-               }
-
-               len = strlen(file->name);
+               fill_print_name(file);
+               len = strlen(file->print_name);
                if (max_len < len)
                        max_len = len;
 
@@ -859,7 +889,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
 
        for (i = 0; i < data->nr; i++) {
                const char *prefix = "";
-               char *name = data->files[i]->name;
+               char *name = data->files[i]->print_name;
                int added = data->files[i]->added;
                int deleted = data->files[i]->deleted;
                int name_len;
@@ -887,17 +917,17 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                        printf("%s%d%s", add_c, added, reset);
                        printf(" bytes");
                        printf("\n");
-                       goto free_diffstat_file;
+                       continue;
                }
                else if (data->files[i]->is_unmerged) {
                        show_name(prefix, name, len, reset, set);
                        printf("  Unmerged\n");
-                       goto free_diffstat_file;
+                       continue;
                }
                else if (!data->files[i]->is_renamed &&
                         (added + deleted == 0)) {
                        total_files--;
-                       goto free_diffstat_file;
+                       continue;
                }
 
                /*
@@ -919,11 +949,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options)
                show_graph('+', add, add_c, reset);
                show_graph('-', del, del_c, reset);
                putchar('\n');
-       free_diffstat_file:
-               free(data->files[i]->name);
-               free(data->files[i]);
        }
-       free(data->files);
        printf("%s %d files changed, %d insertions(+), %d deletions(-)%s\n",
               set, total_files, adds, dels, reset);
 }
@@ -948,11 +974,7 @@ static void show_shortstats(struct diffstat_t* data)
                                dels += deleted;
                        }
                }
-               free(data->files[i]->name);
-               free(data->files[i]);
        }
-       free(data->files);
-
        printf(" %d files changed, %d insertions(+), %d deletions(-)\n",
               total_files, adds, dels);
 }
@@ -961,6 +983,9 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
 {
        int i;
 
+       if (data->nr == 0)
+               return;
+
        for (i = 0; i < data->nr; i++) {
                struct diffstat_file *file = data->files[i];
 
@@ -968,19 +993,44 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
                        printf("-\t-\t");
                else
                        printf("%d\t%d\t", file->added, file->deleted);
-               if (!file->is_renamed) {
-                       write_name_quoted(file->name, stdout, options->line_termination);
+               if (options->line_termination) {
+                       fill_print_name(file);
+                       if (!file->is_renamed)
+                               write_name_quoted(file->name, stdout,
+                                                 options->line_termination);
+                       else {
+                               fputs(file->print_name, stdout);
+                               putchar(options->line_termination);
+                       }
                } else {
-                       fputs(file->name, stdout);
-                       putchar(options->line_termination);
+                       if (file->is_renamed) {
+                               putchar('\0');
+                               write_name_quoted(file->from_name, stdout, '\0');
+                       }
+                       write_name_quoted(file->name, stdout, '\0');
                }
        }
 }
 
+static void free_diffstat_info(struct diffstat_t *diffstat)
+{
+       int i;
+       for (i = 0; i < diffstat->nr; i++) {
+               struct diffstat_file *f = diffstat->files[i];
+               if (f->name != f->print_name)
+                       free(f->print_name);
+               free(f->name);
+               free(f->from_name);
+               free(f);
+       }
+       free(diffstat->files);
+}
+
 struct checkdiff_t {
        struct xdiff_emit_state xm;
        const char *filename;
        int lineno, color_diff;
+       unsigned ws_rule;
 };
 
 static void checkdiff_consume(void *priv, char *line, unsigned long len)
@@ -994,13 +1044,20 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
                int i, spaces = 0, space_before_tab = 0, white_space_at_end = 0;
 
                /* check space before tab */
-               for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
+               for (i = 1; i < len; i++) {
                        if (line[i] == ' ')
                                spaces++;
-               if (line[i - 1] == '\t' && spaces)
-                       space_before_tab = 1;
+                       else if (line[i] == '\t') {
+                               if (spaces) {
+                                       space_before_tab = 1;
+                                       break;
+                               }
+                       }
+                       else
+                               break;
+               }
 
-               /* check white space at line end */
+               /* check whitespace at line end */
                if (line[len - 1] == '\n')
                        len--;
                if (isspace(line[len - 1]))
@@ -1014,9 +1071,10 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
                                        putchar(',');
                        }
                        if (white_space_at_end)
-                               printf("white space at end");
+                               printf("whitespace at end");
                        printf(":%s ", reset);
-                       emit_line_with_ws(1, set, reset, ws, line, len);
+                       emit_line_with_ws(1, set, reset, ws, line, len,
+                                         data->ws_rule);
                }
 
                data->lineno++;
@@ -1317,6 +1375,7 @@ static void builtin_diff(const char *name_a,
                ecbdata.label_path = lbl;
                ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
                ecbdata.found_changesp = &o->found_changes;
+               ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
@@ -1334,7 +1393,7 @@ static void builtin_diff(const char *name_a,
                if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
                        ecbdata.diff_words =
                                xcalloc(1, sizeof(struct diff_words_data));
-               xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+               xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
                if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
                        free_diff_words_data(&ecbdata);
        }
@@ -1387,7 +1446,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                ecb.outf = xdiff_outf;
                ecb.priv = diffstat;
-               xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+               xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
        }
 
  free_and_return:
@@ -1410,6 +1469,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        data.filename = name_b ? name_b : name_a;
        data.lineno = 0;
        data.color_diff = DIFF_OPT_TST(o, COLOR_DIFF);
+       data.ws_rule = whitespace_rule(data.filename);
 
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
@@ -1426,7 +1486,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
                xpp.flags = XDF_NEED_MINIMAL;
                ecb.outf = xdiff_outf;
                ecb.priv = &data;
-               xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+               xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
        }
  free_and_return:
        diff_free_filespec_data(one);
@@ -2716,7 +2776,7 @@ static void diff_summary(struct diff_filepair *p)
                break;
        default:
                if (p->score) {
-                       puts(" rewrite ");
+                       fputs(" rewrite ", stdout);
                        write_name_quoted(p->two->path, stdout, ' ');
                        printf("(%d%%)\n", similarity_index(p));
                }
@@ -2838,7 +2898,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
                xecfg.flags = XDL_EMIT_FUNCNAMES;
                ecb.outf = xdiff_outf;
                ecb.priv = &data;
-               xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+               xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
        }
 
        SHA1_Final(sha1, &ctx);
@@ -2925,8 +2985,9 @@ void diff_flush(struct diff_options *options)
                        show_numstat(&diffstat, options);
                if (output_format & DIFF_FORMAT_DIFFSTAT)
                        show_stats(&diffstat, options);
-               else if (output_format & DIFF_FORMAT_SHORTSTAT)
+               if (output_format & DIFF_FORMAT_SHORTSTAT)
                        show_shortstats(&diffstat);
+               free_diffstat_info(&diffstat);
                separator++;
        }