fast-import: Improve robustness when D->F changes provided in wrong order
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 2daa732a360b2e846791156be5ceb33b85b4eac9..d0ecbc35406c88f89556a34f1514b77024944d09 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -14,6 +14,7 @@
 #include "userdiff.h"
 #include "sigchain.h"
 #include "submodule.h"
+#include "ll-merge.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -550,6 +551,10 @@ static void emit_rewrite_diff(const char *name_a,
                emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
        if (lc_b)
                emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
+       if (textconv_one)
+               free((char *)data_one);
+       if (textconv_two)
+               free((char *)data_two);
 }
 
 struct diff_words_buffer {
@@ -948,7 +953,7 @@ struct diffstat_t {
                unsigned is_unmerged:1;
                unsigned is_binary:1;
                unsigned is_renamed:1;
-               unsigned int added, deleted;
+               uintmax_t added, deleted;
        } **files;
 };
 
@@ -1040,7 +1045,7 @@ static void fill_print_name(struct diffstat_file *file)
 static void show_stats(struct diffstat_t *data, struct diff_options *options)
 {
        int i, len, add, del, adds = 0, dels = 0;
-       int max_change = 0, max_len = 0;
+       uintmax_t max_change = 0, max_len = 0;
        int total_files = data->nr;
        int width, name_width;
        const char *reset, *set, *add_c, *del_c;
@@ -1069,7 +1074,7 @@ 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;
+               uintmax_t change = file->added + file->deleted;
                fill_print_name(file);
                len = strlen(file->print_name);
                if (max_len < len)
@@ -1097,8 +1102,8 @@ 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]->print_name;
-               int added = data->files[i]->added;
-               int deleted = data->files[i]->deleted;
+               uintmax_t added = data->files[i]->added;
+               uintmax_t deleted = data->files[i]->deleted;
                int name_len;
 
                /*
@@ -1119,9 +1124,11 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                if (data->files[i]->is_binary) {
                        show_name(options->file, prefix, name, len);
                        fprintf(options->file, "  Bin ");
-                       fprintf(options->file, "%s%d%s", del_c, deleted, reset);
+                       fprintf(options->file, "%s%"PRIuMAX"%s",
+                               del_c, deleted, reset);
                        fprintf(options->file, " -> ");
-                       fprintf(options->file, "%s%d%s", add_c, added, reset);
+                       fprintf(options->file, "%s%"PRIuMAX"%s",
+                               add_c, added, reset);
                        fprintf(options->file, " bytes");
                        fprintf(options->file, "\n");
                        continue;
@@ -1150,7 +1157,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                        del = scale_linear(del, width, max_change);
                }
                show_name(options->file, prefix, name, len);
-               fprintf(options->file, "%5d%s", added + deleted,
+               fprintf(options->file, "%5"PRIuMAX"%s", added + deleted,
                                added + deleted ? " " : "");
                show_graph(options->file, '+', add, add_c, reset);
                show_graph(options->file, '-', del, del_c, reset);
@@ -1200,7 +1207,8 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options)
                        fprintf(options->file, "-\t-\t");
                else
                        fprintf(options->file,
-                               "%d\t%d\t", file->added, file->deleted);
+                               "%"PRIuMAX"\t%"PRIuMAX"\t",
+                               file->added, file->deleted);
                if (options->line_termination) {
                        fill_print_name(file);
                        if (!file->is_renamed)
@@ -1370,37 +1378,32 @@ static void free_diffstat_info(struct diffstat_t *diffstat)
 struct checkdiff_t {
        const char *filename;
        int lineno;
+       int conflict_marker_size;
        struct diff_options *o;
        unsigned ws_rule;
        unsigned status;
 };
 
-static int is_conflict_marker(const char *line, unsigned long len)
+static int is_conflict_marker(const char *line, int marker_size, unsigned long len)
 {
        char firstchar;
        int cnt;
 
-       if (len < 8)
+       if (len < marker_size + 1)
                return 0;
        firstchar = line[0];
        switch (firstchar) {
-       case '=': case '>': case '<':
+       case '=': case '>': case '<': case '|':
                break;
        default:
                return 0;
        }
-       for (cnt = 1; cnt < 7; cnt++)
+       for (cnt = 1; cnt < marker_size; cnt++)
                if (line[cnt] != firstchar)
                        return 0;
-       /* line[0] thru line[6] are same as firstchar */
-       if (firstchar == '=') {
-               /* divider between ours and theirs? */
-               if (len != 8 || line[7] != '\n')
-                       return 0;
-       } else if (len < 8 || !isspace(line[7])) {
-               /* not divider before ours nor after theirs */
+       /* line[1] thru line[marker_size-1] are same as firstchar */
+       if (len < marker_size + 1 || !isspace(line[marker_size]))
                return 0;
-       }
        return 1;
 }
 
@@ -1408,6 +1411,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
 {
        struct checkdiff_t *data = priv;
        int color_diff = DIFF_OPT_TST(data->o, COLOR_DIFF);
+       int marker_size = data->conflict_marker_size;
        const char *ws = diff_get_color(color_diff, DIFF_WHITESPACE);
        const char *reset = diff_get_color(color_diff, DIFF_RESET);
        const char *set = diff_get_color(color_diff, DIFF_FILE_NEW);
@@ -1416,7 +1420,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
        if (line[0] == '+') {
                unsigned bad;
                data->lineno++;
-               if (is_conflict_marker(line + 1, len - 1)) {
+               if (is_conflict_marker(line + 1, marker_size, len - 1)) {
                        data->status |= 1;
                        fprintf(data->o->file,
                                "%s:%d: leftover conflict marker\n",
@@ -1860,6 +1864,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        data.lineno = 0;
        data.o = o;
        data.ws_rule = whitespace_rule(attr_path);
+       data.conflict_marker_size = ll_merge_marker_size(attr_path);
 
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");