Commit 61c7b61e by Russell Belfer

Use correct case path in icase tree iterator

If there are case-ambiguities in the path of a case insensitive
tree iterator, it will now rewrite the entire path when it gives
the path name to an entry, so a tree with "A/b/C/d.txt" and
"a/B/c/E.txt" will give the true full paths (instead of case-
folding them both to "A/B/C/d.txt" or "a/b/c/E.txt" or something
like that.
parent a03beb7b
...@@ -189,11 +189,30 @@ typedef struct { ...@@ -189,11 +189,30 @@ typedef struct {
tree_iterator_frame *head, *top; tree_iterator_frame *head, *top;
git_index_entry entry; git_index_entry entry;
git_buf path; git_buf path;
int path_ambiguities;
bool path_has_filename; bool path_has_filename;
int (*strcomp)(const char *a, const char *b); int (*strcomp)(const char *a, const char *b);
int (*strncomp)(const char *a, const char *b, size_t sz); int (*strncomp)(const char *a, const char *b, size_t sz);
} tree_iterator; } tree_iterator;
static const git_tree_entry *tree_iterator__get_tree_entry(
tree_iterator_frame *tf, const tree_iterator_entry *entry, size_t i)
{
git_tree *tree;
if (!entry) {
if (i >= tf->n_entries)
return NULL;
entry = &tf->entries[i];
}
tree = tf->parent->entries[entry->parent_entry_index].tree;
if (!tree)
return NULL;
return git_tree_entry_byindex(tree, entry->parent_tree_index);
}
static char *tree_iterator__current_filename( static char *tree_iterator__current_filename(
tree_iterator *ti, const git_tree_entry *te) tree_iterator *ti, const git_tree_entry *te)
{ {
...@@ -210,39 +229,27 @@ static char *tree_iterator__current_filename( ...@@ -210,39 +229,27 @@ static char *tree_iterator__current_filename(
return ti->path.ptr; return ti->path.ptr;
} }
static int tree_iterator__create_top_frame(tree_iterator *ti, git_tree *tree) static void tree_iterator__rewrite_filename(tree_iterator *ti)
{ {
size_t sz = sizeof(tree_iterator_frame) + sizeof(tree_iterator_entry); tree_iterator_frame *scan = ti->head;
tree_iterator_frame *top = git__calloc(sz, sizeof(char)); size_t current = scan->current;
GITERR_CHECK_ALLOC(top); ssize_t strpos = ti->path.size;
const git_tree_entry *te;
top->n_entries = 1; while (scan && scan->parent) {
top->next = 1; tree_iterator_entry *entry = &scan->entries[current];
top->start = ti->base.start;
top->startlen = top->start ? strlen(top->start) : 0;
top->entries[0].tree = tree;
ti->head = ti->top = top; te = tree_iterator__get_tree_entry(scan, entry, 0);
if (!te)
break;
return 0; strpos -= te->filename_len;
} memcpy(&ti->path.ptr[strpos], te->filename, te->filename_len);
strpos -= 1; /* separator */
static const git_tree_entry *tree_iterator__get_tree_entry( current = entry->parent_entry_index;
tree_iterator_frame *tf, const tree_iterator_entry *entry, size_t i) scan = scan->parent;
{
git_tree *tree;
if (!entry) {
if (i >= tf->n_entries)
return NULL;
entry = &tf->entries[i];
} }
tree = tf->parent->entries[entry->parent_entry_index].tree;
if (!tree)
return NULL;
return git_tree_entry_byindex(tree, entry->parent_tree_index);
} }
static int tree_iterator__entry_cmp(const void *a, const void *b, void *p) static int tree_iterator__entry_cmp(const void *a, const void *b, void *p)
...@@ -290,6 +297,9 @@ static int tree_iterator__set_next(tree_iterator *ti, tree_iterator_frame *tf) ...@@ -290,6 +297,9 @@ static int tree_iterator__set_next(tree_iterator *ti, tree_iterator_frame *tf)
last_te = te; last_te = te;
} }
if (tf->next > tf->current + 1)
ti->path_ambiguities++;
if (last_te && !tree_iterator__current_filename(ti, last_te)) if (last_te && !tree_iterator__current_filename(ti, last_te))
return -1; return -1;
...@@ -376,8 +386,12 @@ static int tree_iterator__push_frame(tree_iterator *ti) ...@@ -376,8 +386,12 @@ static int tree_iterator__push_frame(tree_iterator *ti)
return 0; return 0;
} }
static bool tree_iterator__move_to_next(tree_iterator_frame *tf) static bool tree_iterator__move_to_next(
tree_iterator *ti, tree_iterator_frame *tf)
{ {
if (tf->next > tf->current + 1)
ti->path_ambiguities--;
while (tf->current < tf->next) { while (tf->current < tf->next) {
if (tf->parent && tf->entries[tf->current].tree) { if (tf->parent && tf->entries[tf->current].tree) {
git_tree_free(tf->entries[tf->current].tree); git_tree_free(tf->entries[tf->current].tree);
...@@ -396,7 +410,7 @@ static bool tree_iterator__pop_frame(tree_iterator *ti) ...@@ -396,7 +410,7 @@ static bool tree_iterator__pop_frame(tree_iterator *ti)
if (!tf->parent) if (!tf->parent)
return false; return false;
tree_iterator__move_to_next(tf); tree_iterator__move_to_next(ti, tf);
ti->head = tf->parent; ti->head = tf->parent;
ti->head->child = NULL; ti->head->child = NULL;
...@@ -427,6 +441,9 @@ static int tree_iterator__current( ...@@ -427,6 +441,9 @@ static int tree_iterator__current(
if (ti->entry.path == NULL) if (ti->entry.path == NULL)
return -1; return -1;
if (ti->path_ambiguities > 0)
tree_iterator__rewrite_filename(ti);
if (iterator__past_end(ti, ti->entry.path)) { if (iterator__past_end(ti, ti->entry.path)) {
while (tree_iterator__pop_frame(ti)) /* pop to top */; while (tree_iterator__pop_frame(ti)) /* pop to top */;
ti->head->current = ti->head->n_entries; ti->head->current = ti->head->n_entries;
...@@ -478,7 +495,7 @@ static int tree_iterator__advance( ...@@ -478,7 +495,7 @@ static int tree_iterator__advance(
} }
/* scan forward and up, advancing in frame or popping frame when done */ /* scan forward and up, advancing in frame or popping frame when done */
while (!tree_iterator__move_to_next(tf) && tree_iterator__pop_frame(ti)) while (!tree_iterator__move_to_next(ti, tf) && tree_iterator__pop_frame(ti))
tf = ti->head; tf = ti->head;
/* find next and load trees */ /* find next and load trees */
...@@ -510,6 +527,7 @@ static int tree_iterator__reset( ...@@ -510,6 +527,7 @@ static int tree_iterator__reset(
if (iterator__reset_range(self, start, end) < 0) if (iterator__reset_range(self, start, end) < 0)
return -1; return -1;
git_buf_clear(&ti->path); git_buf_clear(&ti->path);
ti->path_ambiguities = 0;
return tree_iterator__push_frame(ti); /* re-expand top tree */ return tree_iterator__push_frame(ti); /* re-expand top tree */
} }
...@@ -537,6 +555,23 @@ static void tree_iterator__free(git_iterator *self) ...@@ -537,6 +555,23 @@ static void tree_iterator__free(git_iterator *self)
git_buf_free(&ti->path); git_buf_free(&ti->path);
} }
static int tree_iterator__create_top_frame(tree_iterator *ti, git_tree *tree)
{
size_t sz = sizeof(tree_iterator_frame) + sizeof(tree_iterator_entry);
tree_iterator_frame *top = git__calloc(sz, sizeof(char));
GITERR_CHECK_ALLOC(top);
top->n_entries = 1;
top->next = 1;
top->start = ti->base.start;
top->startlen = top->start ? strlen(top->start) : 0;
top->entries[0].tree = tree;
ti->head = ti->top = top;
return 0;
}
int git_iterator_for_tree( int git_iterator_for_tree(
git_iterator **iter, git_iterator **iter,
git_tree *tree, git_tree *tree,
......
...@@ -456,7 +456,7 @@ void test_repo_iterator__tree_case_conflicts(void) ...@@ -456,7 +456,7 @@ void test_repo_iterator__tree_case_conflicts(void)
const char *expect_cs[] = { const char *expect_cs[] = {
"A/1.file", "A/3.file", "a/2.file", "a/4.file" }; "A/1.file", "A/3.file", "a/2.file", "a/4.file" };
const char *expect_ci[] = { const char *expect_ci[] = {
"a/1.file", "a/2.file", "a/3.file", "a/4.file" }; "A/1.file", "a/2.file", "A/3.file", "a/4.file" };
g_repo = cl_git_sandbox_init("icase"); g_repo = cl_git_sandbox_init("icase");
...@@ -479,7 +479,7 @@ void test_repo_iterator__tree_case_conflicts(void) ...@@ -479,7 +479,7 @@ void test_repo_iterator__tree_case_conflicts(void)
cl_git_pass(git_iterator_for_tree( cl_git_pass(git_iterator_for_tree(
&i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL)); &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
expect_iterator_items(i, 4, expect_ci, -4, expect_ci); expect_iterator_items(i, 4, expect_ci, 4, expect_ci);
git_iterator_free(i); git_iterator_free(i);
git_tree_free(tree); git_tree_free(tree);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment