Imported Upstream version 2.21.0
[platform/upstream/git.git] / combine-diff.c
index 59501db..23d8fab 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "object-store.h"
 #include "commit.h"
 #include "blob.h"
 #include "diff.h"
@@ -162,7 +163,7 @@ enum coalesce_direction { MATCH, BASE, NEW };
 
 /* Coalesce new lines into base by finding LCS */
 static struct lline *coalesce_lines(struct lline *base, int *lenbase,
-                                   struct lline *new, int lennew,
+                                   struct lline *newline, int lennew,
                                    unsigned long parent, long flags)
 {
        int **lcs;
@@ -170,12 +171,12 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
        struct lline *baseend, *newend = NULL;
        int i, j, origbaselen = *lenbase;
 
-       if (new == NULL)
+       if (newline == NULL)
                return base;
 
        if (base == NULL) {
                *lenbase = lennew;
-               return new;
+               return newline;
        }
 
        /*
@@ -200,7 +201,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
                directions[0][j] = NEW;
 
        for (i = 1, baseend = base; i < origbaselen + 1; i++) {
-               for (j = 1, newend = new; j < lennew + 1; j++) {
+               for (j = 1, newend = newline; j < lennew + 1; j++) {
                        if (match_string_spaces(baseend->line, baseend->len,
                                                newend->line, newend->len, flags)) {
                                lcs[i][j] = lcs[i - 1][j - 1] + 1;
@@ -241,7 +242,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
                        if (lline->prev)
                                lline->prev->next = lline->next;
                        else
-                               new = lline->next;
+                               newline = lline->next;
                        if (lline->next)
                                lline->next->prev = lline->prev;
 
@@ -270,7 +271,7 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
                }
        }
 
-       newend = new;
+       newend = newline;
        while (newend) {
                struct lline *lline = newend;
                newend = newend->next;
@@ -284,7 +285,8 @@ static struct lline *coalesce_lines(struct lline *base, int *lenbase,
        return base;
 }
 
-static char *grab_blob(const struct object_id *oid, unsigned int mode,
+static char *grab_blob(struct repository *r,
+                      const struct object_id *oid, unsigned int mode,
                       unsigned long *size, struct userdiff_driver *textconv,
                       const char *path)
 {
@@ -292,20 +294,21 @@ static char *grab_blob(const struct object_id *oid, unsigned int mode,
        enum object_type type;
 
        if (S_ISGITLINK(mode)) {
-               blob = xmalloc(100);
-               *size = snprintf(blob, 100,
-                                "Subproject commit %s\n", oid_to_hex(oid));
+               struct strbuf buf = STRBUF_INIT;
+               strbuf_addf(&buf, "Subproject commit %s\n", oid_to_hex(oid));
+               *size = buf.len;
+               blob = strbuf_detach(&buf, NULL);
        } else if (is_null_oid(oid)) {
                /* deleted blob */
                *size = 0;
                return xcalloc(1, 1);
        } else if (textconv) {
                struct diff_filespec *df = alloc_filespec(path);
-               fill_filespec(df, oid->hash, 1, mode);
-               *size = fill_textconv(textconv, df, &blob);
+               fill_filespec(df, oid, 1, mode);
+               *size = fill_textconv(r, textconv, df, &blob);
                free_filespec(df);
        } else {
-               blob = read_sha1_file(oid->hash, &type, size);
+               blob = read_object_file(oid, &type, size);
                if (type != OBJ_BLOB)
                        die("object '%s' is not a blob!", oid_to_hex(oid));
        }
@@ -342,38 +345,43 @@ struct combine_diff_state {
        struct sline *lost_bucket;
 };
 
-static void consume_line(void *state_, char *line, unsigned long len)
+static void consume_hunk(void *state_,
+                        long ob, long on,
+                        long nb, long nn,
+                        const char *funcline, long funclen)
 {
        struct combine_diff_state *state = state_;
-       if (5 < len && !memcmp("@@ -", line, 4)) {
-               if (parse_hunk_header(line, len,
-                                     &state->ob, &state->on,
-                                     &state->nb, &state->nn))
-                       return;
-               state->lno = state->nb;
-               if (state->nn == 0) {
-                       /* @@ -X,Y +N,0 @@ removed Y lines
-                        * that would have come *after* line N
-                        * in the result.  Our lost buckets hang
-                        * to the line after the removed lines,
-                        *
-                        * Note that this is correct even when N == 0,
-                        * in which case the hunk removes the first
-                        * line in the file.
-                        */
-                       state->lost_bucket = &state->sline[state->nb];
-                       if (!state->nb)
-                               state->nb = 1;
-               } else {
-                       state->lost_bucket = &state->sline[state->nb-1];
-               }
-               if (!state->sline[state->nb-1].p_lno)
-                       state->sline[state->nb-1].p_lno =
-                               xcalloc(state->num_parent,
-                                       sizeof(unsigned long));
-               state->sline[state->nb-1].p_lno[state->n] = state->ob;
-               return;
+
+       state->ob = ob;
+       state->on = on;
+       state->nb = nb;
+       state->nn = nn;
+       state->lno = state->nb;
+       if (state->nn == 0) {
+               /* @@ -X,Y +N,0 @@ removed Y lines
+                * that would have come *after* line N
+                * in the result.  Our lost buckets hang
+                * to the line after the removed lines,
+                *
+                * Note that this is correct even when N == 0,
+                * in which case the hunk removes the first
+                * line in the file.
+                */
+               state->lost_bucket = &state->sline[state->nb];
+               if (!state->nb)
+                       state->nb = 1;
+       } else {
+               state->lost_bucket = &state->sline[state->nb-1];
        }
+       if (!state->sline[state->nb-1].p_lno)
+               state->sline[state->nb-1].p_lno =
+                       xcalloc(state->num_parent, sizeof(unsigned long));
+       state->sline[state->nb-1].p_lno[state->n] = state->ob;
+}
+
+static void consume_line(void *state_, char *line, unsigned long len)
+{
+       struct combine_diff_state *state = state_;
        if (!state->lost_bucket)
                return; /* not in any hunk yet */
        switch (line[0]) {
@@ -387,7 +395,8 @@ static void consume_line(void *state_, char *line, unsigned long len)
        }
 }
 
-static void combine_diff(const struct object_id *parent, unsigned int mode,
+static void combine_diff(struct repository *r,
+                        const struct object_id *parent, unsigned int mode,
                         mmfile_t *result_file,
                         struct sline *sline, unsigned int cnt, int n,
                         int num_parent, int result_deleted,
@@ -405,7 +414,7 @@ static void combine_diff(const struct object_id *parent, unsigned int mode,
        if (result_deleted)
                return; /* result deleted */
 
-       parent_file.ptr = grab_blob(parent, mode, &sz, textconv, path);
+       parent_file.ptr = grab_blob(r, parent, mode, &sz, textconv, path);
        parent_file.size = sz;
        memset(&xpp, 0, sizeof(xpp));
        xpp.flags = flags;
@@ -417,8 +426,8 @@ static void combine_diff(const struct object_id *parent, unsigned int mode,
        state.num_parent = num_parent;
        state.n = n;
 
-       if (xdi_diff_outf(&parent_file, result_file, consume_line, &state,
-                         &xpp, &xecfg))
+       if (xdi_diff_outf(&parent_file, result_file, consume_hunk,
+                         consume_line, &state, &xpp, &xecfg))
                die("unable to generate combined diff for %s",
                    oid_to_hex(parent));
        free(parent_file.ptr);
@@ -897,7 +906,7 @@ static void show_combined_header(struct combine_diff_path *elem,
                                 int show_file_header)
 {
        struct diff_options *opt = &rev->diffopt;
-       int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
+       int abbrev = opt->flags.full_index ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
        const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/";
        const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/";
        const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO);
@@ -914,11 +923,11 @@ static void show_combined_header(struct combine_diff_path *elem,
                         "", elem->path, line_prefix, c_meta, c_reset);
        printf("%s%sindex ", line_prefix, c_meta);
        for (i = 0; i < num_parent; i++) {
-               abb = find_unique_abbrev(elem->parent[i].oid.hash,
+               abb = find_unique_abbrev(&elem->parent[i].oid,
                                         abbrev);
                printf("%s%s", i ? "," : "", abb);
        }
-       abb = find_unique_abbrev(elem->oid.hash, abbrev);
+       abb = find_unique_abbrev(&elem->oid, abbrev);
        printf("..%s%s\n", abb, c_reset);
 
        if (mode_differs) {
@@ -983,15 +992,15 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        const char *line_prefix = diff_line_prefix(opt);
 
        context = opt->context;
-       userdiff = userdiff_find_by_path(elem->path);
+       userdiff = userdiff_find_by_path(opt->repo->index, elem->path);
        if (!userdiff)
                userdiff = userdiff_find_by_name("default");
-       if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV))
-               textconv = userdiff_get_textconv(userdiff);
+       if (opt->flags.allow_textconv)
+               textconv = userdiff_get_textconv(opt->repo, userdiff);
 
        /* Read the result of merge first */
        if (!working_tree_file)
-               result = grab_blob(&elem->oid, elem->mode, &result_size,
+               result = grab_blob(opt->repo, &elem->oid, elem->mode, &result_size,
                                   textconv, elem->path);
        else {
                /* Used by diff-tree to read from the working tree */
@@ -1013,16 +1022,17 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        elem->mode = canon_mode(st.st_mode);
                } else if (S_ISDIR(st.st_mode)) {
                        struct object_id oid;
-                       if (resolve_gitlink_ref(elem->path, "HEAD", oid.hash) < 0)
-                               result = grab_blob(&elem->oid, elem->mode,
-                                                  &result_size, NULL, NULL);
+                       if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
+                               result = grab_blob(opt->repo, &elem->oid,
+                                                  elem->mode, &result_size,
+                                                  NULL, NULL);
                        else
-                               result = grab_blob(&oid, elem->mode,
+                               result = grab_blob(opt->repo, &oid, elem->mode,
                                                   &result_size, NULL, NULL);
                } else if (textconv) {
                        struct diff_filespec *df = alloc_filespec(elem->path);
-                       fill_filespec(df, null_sha1, 0, st.st_mode);
-                       result_size = fill_textconv(textconv, df, &result);
+                       fill_filespec(df, &null_oid, 0, st.st_mode);
+                       result_size = fill_textconv(opt->repo, textconv, df, &result);
                        free_filespec(df);
                } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
                        size_t len = xsize_t(st.st_size);
@@ -1052,7 +1062,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        if (is_file) {
                                struct strbuf buf = STRBUF_INIT;
 
-                               if (convert_to_git(elem->path, result, len, &buf, safe_crlf)) {
+                               if (convert_to_git(rev->diffopt.repo->index,
+                                                  elem->path, result, len, &buf, global_conv_flags_eol)) {
                                        free(result);
                                        result = strbuf_detach(&buf, &len);
                                        result_size = len;
@@ -1087,7 +1098,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                for (i = 0; !is_binary && i < num_parent; i++) {
                        char *buf;
                        unsigned long size;
-                       buf = grab_blob(&elem->parent[i].oid,
+                       buf = grab_blob(opt->repo,
+                                       &elem->parent[i].oid,
                                        elem->parent[i].mode,
                                        &size, NULL, NULL);
                        if (buffer_is_binary(buf, size))
@@ -1136,14 +1148,15 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        for (i = 0; i < num_parent; i++) {
                int j;
                for (j = 0; j < i; j++) {
-                       if (!oidcmp(&elem->parent[i].oid,
-                                    &elem->parent[j].oid)) {
+                       if (oideq(&elem->parent[i].oid,
+                                 &elem->parent[j].oid)) {
                                reuse_combine_diff(sline, cnt, i, j);
                                break;
                        }
                }
                if (i <= j)
-                       combine_diff(&elem->parent[i].oid,
+                       combine_diff(opt->repo,
+                                    &elem->parent[i].oid,
                                     elem->parent[i].mode,
                                     &result_file, sline,
                                     cnt, i, num_parent, result_deleted,
@@ -1308,10 +1321,18 @@ static const char *path_path(void *obj)
        return path->path;
 }
 
+/*
+ * Diff stat formats which we always compute solely against the first parent.
+ */
+#define STAT_FORMAT_MASK (DIFF_FORMAT_NUMSTAT \
+                         | DIFF_FORMAT_SHORTSTAT \
+                         | DIFF_FORMAT_SUMMARY \
+                         | DIFF_FORMAT_DIRSTAT \
+                         | DIFF_FORMAT_DIFFSTAT)
 
 /* find set of paths that every parent touches */
-static struct combine_diff_path *find_paths_generic(const unsigned char *sha1,
-       const struct sha1_array *parents, struct diff_options *opt)
+static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
+       const struct oid_array *parents, struct diff_options *opt)
 {
        struct combine_diff_path *paths = NULL;
        int i, num_parent = parents->nr;
@@ -1329,13 +1350,12 @@ static struct combine_diff_path *find_paths_generic(const unsigned char *sha1,
                 * show stat against the first parent even when doing
                 * combined diff.
                 */
-               int stat_opt = (output_format &
-                               (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT));
+               int stat_opt = output_format & STAT_FORMAT_MASK;
                if (i == 0 && stat_opt)
                        opt->output_format = stat_opt;
                else
                        opt->output_format = DIFF_FORMAT_NO_OUTPUT;
-               diff_tree_sha1(parents->sha1[i], sha1, "", opt);
+               diff_tree_oid(&parents->oid[i], oid, "", opt);
                diffcore_std(opt);
                paths = intersect_paths(paths, i, num_parent);
 
@@ -1359,32 +1379,32 @@ static struct combine_diff_path *find_paths_generic(const unsigned char *sha1,
  * rename/copy detection, etc, comparing all trees simultaneously (= faster).
  */
 static struct combine_diff_path *find_paths_multitree(
-       const unsigned char *sha1, const struct sha1_array *parents,
+       const struct object_id *oid, const struct oid_array *parents,
        struct diff_options *opt)
 {
        int i, nparent = parents->nr;
-       const unsigned char **parents_sha1;
+       const struct object_id **parents_oid;
        struct combine_diff_path paths_head;
        struct strbuf base;
 
-       ALLOC_ARRAY(parents_sha1, nparent);
+       ALLOC_ARRAY(parents_oid, nparent);
        for (i = 0; i < nparent; i++)
-               parents_sha1[i] = parents->sha1[i];
+               parents_oid[i] = &parents->oid[i];
 
        /* fake list head, so worker can assume it is non-NULL */
        paths_head.next = NULL;
 
        strbuf_init(&base, PATH_MAX);
-       diff_tree_paths(&paths_head, sha1, parents_sha1, nparent, &base, opt);
+       diff_tree_paths(&paths_head, oid, parents_oid, nparent, &base, opt);
 
        strbuf_release(&base);
-       free(parents_sha1);
+       free(parents_oid);
        return paths_head.next;
 }
 
 
-void diff_tree_combined(const unsigned char *sha1,
-                       const struct sha1_array *parents,
+void diff_tree_combined(const struct object_id *oid,
+                       const struct oid_array *parents,
                        int dense,
                        struct rev_info *rev)
 {
@@ -1412,8 +1432,8 @@ void diff_tree_combined(const unsigned char *sha1,
 
        diffopts = *opt;
        copy_pathspec(&diffopts.pathspec, &opt->pathspec);
-       DIFF_OPT_SET(&diffopts, RECURSIVE);
-       DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
+       diffopts.flags.recursive = 1;
+       diffopts.flags.allow_external = 0;
 
        /* find set of paths that everybody touches
         *
@@ -1434,10 +1454,10 @@ void diff_tree_combined(const unsigned char *sha1,
         * NOTE please keep this semantically in sync with diffcore_std()
         */
        need_generic_pathscan = opt->skip_stat_unmatch  ||
-                       DIFF_OPT_TST(opt, FOLLOW_RENAMES)       ||
+                       opt->flags.follow_renames       ||
                        opt->break_opt != -1    ||
                        opt->detect_rename      ||
-                       opt->pickaxe            ||
+                       (opt->pickaxe_opts & DIFF_PICKAXE_KINDS_MASK)   ||
                        opt->filter;
 
 
@@ -1447,22 +1467,21 @@ void diff_tree_combined(const unsigned char *sha1,
                 * diff(sha1,parent_i) for all i to do the job, specifically
                 * for parent0.
                 */
-               paths = find_paths_generic(sha1, parents, &diffopts);
+               paths = find_paths_generic(oid, parents, &diffopts);
        }
        else {
                int stat_opt;
-               paths = find_paths_multitree(sha1, parents, &diffopts);
+               paths = find_paths_multitree(oid, parents, &diffopts);
 
                /*
                 * show stat against the first parent even
                 * when doing combined diff.
                 */
-               stat_opt = (opt->output_format &
-                               (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT));
+               stat_opt = opt->output_format & STAT_FORMAT_MASK;
                if (stat_opt) {
                        diffopts.output_format = stat_opt;
 
-                       diff_tree_sha1(parents->sha1[0], sha1, "", &diffopts);
+                       diff_tree_oid(&parents->oid[0], oid, "", &diffopts);
                        diffcore_std(&diffopts);
                        if (opt->orderfile)
                                diffcore_order(opt->orderfile);
@@ -1502,8 +1521,7 @@ void diff_tree_combined(const unsigned char *sha1,
                                show_raw_diff(p, num_parent, rev);
                        needsep = 1;
                }
-               else if (opt->output_format &
-                        (DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIFFSTAT))
+               else if (opt->output_format & STAT_FORMAT_MASK)
                        needsep = 1;
                else if (opt->output_format & DIFF_FORMAT_CALLBACK)
                        handle_combined_callback(opt, paths, num_parent, num_paths);
@@ -1532,12 +1550,12 @@ void diff_tree_combined_merge(const struct commit *commit, int dense,
                              struct rev_info *rev)
 {
        struct commit_list *parent = get_saved_parents(rev, commit);
-       struct sha1_array parents = SHA1_ARRAY_INIT;
+       struct oid_array parents = OID_ARRAY_INIT;
 
        while (parent) {
-               sha1_array_append(&parents, parent->item->object.oid.hash);
+               oid_array_append(&parents, &parent->item->object.oid);
                parent = parent->next;
        }
-       diff_tree_combined(commit->object.oid.hash, &parents, dense, rev);
-       sha1_array_clear(&parents);
+       diff_tree_combined(&commit->object.oid, &parents, dense, rev);
+       oid_array_clear(&parents);
 }