repository: free fields before overwriting them
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index f598d8a3a04c5125e2bbd758e518c79b1ba25a18..3d3e553a98bc4fd83d2f79515056c4116086b5df 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -21,6 +21,7 @@
 #include "string-list.h"
 #include "argv-array.h"
 #include "graph.h"
+#include "packfile.h"
 
 #ifdef NO_FAST_WORKING_DIRECTORY
 #define FAST_WORKING_DIRECTORY 0
@@ -357,9 +358,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (git_color_config(var, value, cb) < 0)
-               return -1;
-
        return git_diff_basic_config(var, value, cb);
 }
 
@@ -404,9 +402,6 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
                return 0;
        }
 
-       if (starts_with(var, "submodule."))
-               return parse_submodule_config_option(var, value);
-
        if (git_diff_heuristic_config(var, value, cb) < 0)
                return -1;
 
@@ -467,8 +462,6 @@ static struct diff_tempfile {
        struct tempfile tempfile;
 } diff_temp[2];
 
-typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len);
-
 struct emit_callback {
        int color_diff;
        unsigned ws_rule;
@@ -476,7 +469,6 @@ struct emit_callback {
        int blank_at_eof_in_postimage;
        int lno_in_preimage;
        int lno_in_postimage;
-       sane_truncate_fn truncate;
        const char **label_path;
        struct diff_words_data *diff_words;
        struct diff_options *opt;
@@ -864,19 +856,31 @@ static int shrink_potential_moved_blocks(struct moved_entry **pmb,
 /*
  * If o->color_moved is COLOR_MOVED_PLAIN, this function does nothing.
  *
- * Otherwise, if the last block has fewer lines than
- * COLOR_MOVED_MIN_BLOCK_LENGTH, unset DIFF_SYMBOL_MOVED_LINE on all lines in
+ * Otherwise, if the last block has fewer alphanumeric characters than
+ * COLOR_MOVED_MIN_ALNUM_COUNT, unset DIFF_SYMBOL_MOVED_LINE on all lines in
  * that block.
  *
  * The last block consists of the (n - block_length)'th line up to but not
  * including the nth line.
+ *
+ * NEEDSWORK: This uses the same heuristic as blame_entry_score() in blame.c.
+ * Think of a way to unify them.
  */
 static void adjust_last_block(struct diff_options *o, int n, int block_length)
 {
-       int i;
-       if (block_length >= COLOR_MOVED_MIN_BLOCK_LENGTH ||
-           o->color_moved == COLOR_MOVED_PLAIN)
+       int i, alnum_count = 0;
+       if (o->color_moved == COLOR_MOVED_PLAIN)
                return;
+       for (i = 1; i < block_length + 1; i++) {
+               const char *c = o->emitted_symbols->buf[n - i].line;
+               for (; *c; c++) {
+                       if (!isalnum(*c))
+                               continue;
+                       alnum_count++;
+                       if (alnum_count >= COLOR_MOVED_MIN_ALNUM_COUNT)
+                               return;
+               }
+       }
        for (i = 1; i < block_length + 1; i++)
                o->emitted_symbols->buf[n - i].flags &= ~DIFF_SYMBOL_MOVED_LINE;
 }
@@ -923,7 +927,6 @@ static void mark_color_as_moved(struct diff_options *o,
                }
 
                l->flags |= DIFF_SYMBOL_MOVED_LINE;
-               block_length++;
 
                if (o->color_moved == COLOR_MOVED_PLAIN)
                        continue;
@@ -953,8 +956,13 @@ static void mark_color_as_moved(struct diff_options *o,
                        }
 
                        flipped_block = (flipped_block + 1) % 2;
+
+                       adjust_last_block(o, n, block_length);
+                       block_length = 0;
                }
 
+               block_length++;
+
                if (flipped_block)
                        l->flags |= DIFF_SYMBOL_MOVED_LINE_ALT;
        }
@@ -1986,8 +1994,6 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u
        unsigned long allot;
        size_t l = len;
 
-       if (ecb->truncate)
-               return ecb->truncate(line, len);
        cp = line;
        allot = l;
        while (0 < l) {
@@ -2832,7 +2838,7 @@ static void show_dirstat_by_line(struct diffstat_t *data, struct diff_options *o
                         * bytes per "line".
                         * This is stupid and ugly, but very cheap...
                         */
-                       damage = (damage + 63) / 64;
+                       damage = DIV_ROUND_UP(damage, 64);
                ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
                dir.files[dir.nr].name = file->name;
                dir.files[dir.nr].changed = damage;
@@ -4003,7 +4009,7 @@ static void diff_fill_oid_info(struct diff_filespec *one)
                        }
                        if (lstat(one->path, &st) < 0)
                                die_errno("stat '%s'", one->path);
-                       if (index_path(one->oid.hash, one->path, &st, 0))
+                       if (index_path(&one->oid, one->path, &st, 0))
                                die("cannot hash %s", one->path);
                }
        }