Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-03-11 09:38:53 +0400
committerRussell Belfer <rb@github.com>2013-03-11 09:38:53 +0400
commit61c7b61e6fe2542deeb8d2aadbea90a8f5b3c9cd (patch)
treed3bd3b665bad772e9e7b9815c290c26d282f81a8 /src/iterator.c
parenta03beb7ba6017181c29d77e64112e4730f690271 (diff)
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.
Diffstat (limited to 'src/iterator.c')
-rw-r--r--src/iterator.c95
1 files changed, 65 insertions, 30 deletions
diff --git a/src/iterator.c b/src/iterator.c
index 84664c0f8..53ec6f61b 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -189,11 +189,30 @@ typedef struct {
tree_iterator_frame *head, *top;
git_index_entry entry;
git_buf path;
+ int path_ambiguities;
bool path_has_filename;
int (*strcomp)(const char *a, const char *b);
int (*strncomp)(const char *a, const char *b, size_t sz);
} 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(
tree_iterator *ti, const git_tree_entry *te)
{
@@ -210,39 +229,27 @@ static char *tree_iterator__current_filename(
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 *top = git__calloc(sz, sizeof(char));
- GITERR_CHECK_ALLOC(top);
+ tree_iterator_frame *scan = ti->head;
+ size_t current = scan->current;
+ ssize_t strpos = ti->path.size;
+ const git_tree_entry *te;
- 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;
+ while (scan && scan->parent) {
+ tree_iterator_entry *entry = &scan->entries[current];
- 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(
- 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];
+ current = entry->parent_entry_index;
+ scan = scan->parent;
}
-
- 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)
@@ -290,6 +297,9 @@ static int tree_iterator__set_next(tree_iterator *ti, tree_iterator_frame *tf)
last_te = te;
}
+ if (tf->next > tf->current + 1)
+ ti->path_ambiguities++;
+
if (last_te && !tree_iterator__current_filename(ti, last_te))
return -1;
@@ -376,8 +386,12 @@ static int tree_iterator__push_frame(tree_iterator *ti)
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) {
if (tf->parent && 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)
if (!tf->parent)
return false;
- tree_iterator__move_to_next(tf);
+ tree_iterator__move_to_next(ti, tf);
ti->head = tf->parent;
ti->head->child = NULL;
@@ -427,6 +441,9 @@ static int tree_iterator__current(
if (ti->entry.path == NULL)
return -1;
+ if (ti->path_ambiguities > 0)
+ tree_iterator__rewrite_filename(ti);
+
if (iterator__past_end(ti, ti->entry.path)) {
while (tree_iterator__pop_frame(ti)) /* pop to top */;
ti->head->current = ti->head->n_entries;
@@ -478,7 +495,7 @@ static int tree_iterator__advance(
}
/* 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;
/* find next and load trees */
@@ -510,6 +527,7 @@ static int tree_iterator__reset(
if (iterator__reset_range(self, start, end) < 0)
return -1;
git_buf_clear(&ti->path);
+ ti->path_ambiguities = 0;
return tree_iterator__push_frame(ti); /* re-expand top tree */
}
@@ -537,6 +555,23 @@ static void tree_iterator__free(git_iterator *self)
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(
git_iterator **iter,
git_tree *tree,