summaryrefslogtreecommitdiff
path: root/match-trees.c
diff options
context:
space:
mode:
Diffstat (limited to 'match-trees.c')
-rw-r--r--match-trees.c132
1 files changed, 53 insertions, 79 deletions
diff --git a/match-trees.c b/match-trees.c
index 26f7ed143e..1ce0954a3e 100644
--- a/match-trees.c
+++ b/match-trees.c
@@ -47,6 +47,29 @@ static int score_matches(unsigned mode1, unsigned mode2, const char *path)
return score;
}
+static void *fill_tree_desc_strict(struct tree_desc *desc,
+ const unsigned char *hash)
+{
+ void *buffer;
+ enum object_type type;
+ unsigned long size;
+
+ buffer = read_sha1_file(hash, &type, &size);
+ if (!buffer)
+ die("unable to read tree (%s)", sha1_to_hex(hash));
+ if (type != OBJ_TREE)
+ die("%s is not a tree", sha1_to_hex(hash));
+ init_tree_desc(desc, buffer, size);
+ return buffer;
+}
+
+static int base_name_entries_compare(const struct name_entry *a,
+ const struct name_entry *b)
+{
+ return base_name_compare(a->path, tree_entry_len(a), a->mode,
+ b->path, tree_entry_len(b), b->mode);
+}
+
/*
* Inspect two trees, and give a score that tells how similar they are.
*/
@@ -54,71 +77,39 @@ static int score_trees(const unsigned char *hash1, const unsigned char *hash2)
{
struct tree_desc one;
struct tree_desc two;
- void *one_buf, *two_buf;
+ void *one_buf = fill_tree_desc_strict(&one, hash1);
+ void *two_buf = fill_tree_desc_strict(&two, hash2);
int score = 0;
- enum object_type type;
- unsigned long size;
- one_buf = read_sha1_file(hash1, &type, &size);
- if (!one_buf)
- die("unable to read tree (%s)", sha1_to_hex(hash1));
- if (type != OBJ_TREE)
- die("%s is not a tree", sha1_to_hex(hash1));
- init_tree_desc(&one, one_buf, size);
- two_buf = read_sha1_file(hash2, &type, &size);
- if (!two_buf)
- die("unable to read tree (%s)", sha1_to_hex(hash2));
- if (type != OBJ_TREE)
- die("%s is not a tree", sha1_to_hex(hash2));
- init_tree_desc(&two, two_buf, size);
- while (one.size | two.size) {
- const unsigned char *elem1 = elem1;
- const unsigned char *elem2 = elem2;
- const char *path1 = path1;
- const char *path2 = path2;
- unsigned mode1 = mode1;
- unsigned mode2 = mode2;
+ for (;;) {
+ struct name_entry e1, e2;
+ int got_entry_from_one = tree_entry(&one, &e1);
+ int got_entry_from_two = tree_entry(&two, &e2);
int cmp;
- if (one.size)
- elem1 = tree_entry_extract(&one, &path1, &mode1);
- if (two.size)
- elem2 = tree_entry_extract(&two, &path2, &mode2);
-
- if (!one.size) {
- /* two has more entries */
- score += score_missing(mode2, path2);
- update_tree_entry(&two);
- continue;
- }
- if (!two.size) {
+ if (got_entry_from_one && got_entry_from_two)
+ cmp = base_name_entries_compare(&e1, &e2);
+ else if (got_entry_from_one)
/* two lacks this entry */
- score += score_missing(mode1, path1);
- update_tree_entry(&one);
- continue;
- }
- cmp = base_name_compare(path1, strlen(path1), mode1,
- path2, strlen(path2), mode2);
- if (cmp < 0) {
+ cmp = -1;
+ else if (got_entry_from_two)
+ /* two has more entries */
+ cmp = 1;
+ else
+ break;
+
+ if (cmp < 0)
/* path1 does not appear in two */
- score += score_missing(mode1, path1);
- update_tree_entry(&one);
- continue;
- }
- else if (cmp > 0) {
+ score += score_missing(e1.mode, e1.path);
+ else if (cmp > 0)
/* path2 does not appear in one */
- score += score_missing(mode2, path2);
- update_tree_entry(&two);
- continue;
- }
- else if (hashcmp(elem1, elem2))
+ score += score_missing(e2.mode, e2.path);
+ else if (hashcmp(e1.sha1, e2.sha1))
/* they are different */
- score += score_differs(mode1, mode2, path1);
+ score += score_differs(e1.mode, e2.mode, e1.path);
else
/* same subtree or blob */
- score += score_matches(mode1, mode2, path1);
- update_tree_entry(&one);
- update_tree_entry(&two);
+ score += score_matches(e1.mode, e2.mode, e1.path);
}
free(one_buf);
free(two_buf);
@@ -136,16 +127,7 @@ static void match_trees(const unsigned char *hash1,
int recurse_limit)
{
struct tree_desc one;
- void *one_buf;
- enum object_type type;
- unsigned long size;
-
- one_buf = read_sha1_file(hash1, &type, &size);
- if (!one_buf)
- die("unable to read tree (%s)", sha1_to_hex(hash1));
- if (type != OBJ_TREE)
- die("%s is not a tree", sha1_to_hex(hash1));
- init_tree_desc(&one, one_buf, size);
+ void *one_buf = fill_tree_desc_strict(&one, hash1);
while (one.size) {
const char *path;
@@ -158,17 +140,12 @@ static void match_trees(const unsigned char *hash1,
goto next;
score = score_trees(elem, hash2);
if (*best_score < score) {
- char *newpath;
- newpath = xmalloc(strlen(base) + strlen(path) + 1);
- sprintf(newpath, "%s%s", base, path);
free(*best_match);
- *best_match = newpath;
+ *best_match = xstrfmt("%s%s", base, path);
*best_score = score;
}
if (recurse_limit) {
- char *newbase;
- newbase = xmalloc(strlen(base) + strlen(path) + 2);
- sprintf(newbase, "%s%s/", base, path);
+ char *newbase = xstrfmt("%s%s/", base, path);
match_trees(elem, hash2, best_score, best_match,
newbase, recurse_limit - 1);
free(newbase);
@@ -200,13 +177,10 @@ static int splice_tree(const unsigned char *hash1,
enum object_type type;
int status;
- subpath = strchr(prefix, '/');
- if (!subpath)
- toplen = strlen(prefix);
- else {
- toplen = subpath - prefix;
+ subpath = strchrnul(prefix, '/');
+ toplen = subpath - prefix;
+ if (*subpath)
subpath++;
- }
buf = read_sha1_file(hash1, &type, &sz);
if (!buf)
@@ -233,7 +207,7 @@ static int splice_tree(const unsigned char *hash1,
if (!rewrite_here)
die("entry %.*s not found in tree %s",
toplen, prefix, sha1_to_hex(hash1));
- if (subpath) {
+ if (*subpath) {
status = splice_tree(rewrite_here, subpath, hash2, subtree);
if (status)
return status;