compat: Add simplified merge sort implementation from glibc
[gitweb.git] / builtin-blame.c
index 55a3c0bc5e3aa9c893468f5f97eab17681ddc673..9b4c02e87f7ef4a20d269ab9315b6977cf7fb3fb 100644 (file)
@@ -125,11 +125,18 @@ static void origin_decref(struct origin *o)
        if (o && --o->refcnt <= 0) {
                if (o->file.ptr)
                        free(o->file.ptr);
-               memset(o, 0, sizeof(*o));
                free(o);
        }
 }
 
+static void drop_origin_blob(struct origin *o)
+{
+       if (o->file.ptr) {
+               free(o->file.ptr);
+               o->file.ptr = NULL;
+       }
+}
+
 /*
  * Each group of lines is described by a blame_entry; it can be split
  * as we pass blame to the parents.  They form a linked list in the
@@ -335,7 +342,7 @@ static struct origin *find_origin(struct scoreboard *sb,
         * same and diff-tree is fairly efficient about this.
         */
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.detect_rename = 0;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        paths[0] = origin->path;
@@ -380,6 +387,7 @@ static struct origin *find_origin(struct scoreboard *sb,
                }
        }
        diff_flush(&diff_opts);
+       diff_tree_release_paths(&diff_opts);
        if (porigin) {
                /*
                 * Create a freestanding copy that is not part of
@@ -409,7 +417,7 @@ static struct origin *find_rename(struct scoreboard *sb,
        const char *paths[2];
 
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.detect_rename = DIFF_DETECT_RENAME;
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diff_opts.single_follow = origin->path;
@@ -436,6 +444,7 @@ static struct origin *find_rename(struct scoreboard *sb,
                }
        }
        diff_flush(&diff_opts);
+       diff_tree_release_paths(&diff_opts);
        return porigin;
 }
 
@@ -532,7 +541,7 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o,
        state.ret->chunks = NULL;
        state.ret->num = 0;
 
-       xdl_diff(file_p, file_o, &xpp, &xecfg, &ecb);
+       xdi_diff(file_p, file_o, &xpp, &xecfg, &ecb);
 
        if (state.ret->num) {
                struct chunk *chunk;
@@ -597,7 +606,7 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
 
 /*
  * src typically is on-stack; we want to copy the information in it to
- * an malloced blame_entry that is already on the linked list of the
+ * a malloced blame_entry that is already on the linked list of the
  * scoreboard.  The origin of dst loses a refcnt while the origin of src
  * gains one.
  */
@@ -1075,7 +1084,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
                return 1; /* nothing remains for this target */
 
        diff_setup(&diff_opts);
-       diff_opts.recursive = 1;
+       DIFF_OPT_SET(&diff_opts, RECURSIVE);
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 
        paths[0] = NULL;
@@ -1093,7 +1102,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
        if ((opt & PICKAXE_BLAME_COPY_HARDEST)
            || ((opt & PICKAXE_BLAME_COPY_HARDER)
                && (!porigin || strcmp(target->path, porigin->path))))
-               diff_opts.find_copies_harder = 1;
+               DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
 
        if (is_null_sha1(target->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -1102,7 +1111,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
                               target->commit->tree->object.sha1,
                               "", &diff_opts);
 
-       if (!diff_opts.find_copies_harder)
+       if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
                diffcore_std(&diff_opts);
 
        retval = 0;
@@ -1157,7 +1166,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
                }
        }
        diff_flush(&diff_opts);
-
+       diff_tree_release_paths(&diff_opts);
        return retval;
 }
 
@@ -1274,8 +1283,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
                }
 
  finish:
-       for (i = 0; i < MAXPARENT; i++)
-               origin_decref(parent_origin[i]);
+       for (i = 0; i < MAXPARENT; i++) {
+               if (parent_origin[i]) {
+                       drop_origin_blob(parent_origin[i]);
+                       origin_decref(parent_origin[i]);
+               }
+       }
+       drop_origin_blob(origin);
 }
 
 /*
@@ -2295,6 +2309,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        else if (i != argc - 1)
                                usage(blame_usage); /* garbage at end */
 
+                       setup_work_tree();
                        if (!has_path_in_work_tree(path))
                                die("cannot stat path %s: %s",
                                    path, strerror(errno));