summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-10-27 22:33:31 -0700
committerVicent Marti <tanoku@gmail.com>2011-10-27 22:33:31 -0700
commitda37654d04617b4dacce6e7a4796007d2854624d (patch)
tree4af06d8774d5e369e8d62c84b56e2644ad672ddc /src
parent4849dbb8b9273337593aa3f06dc11c28137fa13d (diff)
downloadlibgit2-da37654d04617b4dacce6e7a4796007d2854624d.tar.gz
tree: Add traversal in post-order
Diffstat (limited to 'src')
-rw-r--r--src/tree.c56
1 files changed, 54 insertions, 2 deletions
diff --git a/src/tree.c b/src/tree.c
index 00aefc295..77034fa43 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -15,6 +15,8 @@
#define MAX_FILEMODE 0777777
#define MAX_FILEMODE_BYTES 6
+#define ENTRY_IS_TREE(e) ((e)->attr & 040000)
+
static int valid_attributes(const int attributes)
{
return attributes >= 0 && attributes <= MAX_FILEMODE;
@@ -31,8 +33,8 @@ static int entry_sort_cmp(const void *a, const void *b)
const git_tree_entry *entry_b = (const git_tree_entry *)(b);
return git_futils_cmp_path(
- entry_a->filename, entry_a->filename_len, entry_a->attr & 040000,
- entry_b->filename, entry_b->filename_len, entry_b->attr & 040000);
+ entry_a->filename, entry_a->filename_len, ENTRY_IS_TREE(entry_a),
+ entry_b->filename, entry_b->filename_len, ENTRY_IS_TREE(entry_b));
}
@@ -654,3 +656,53 @@ int git_tree_frompath(git_tree **parent_out, git_tree *root, const char *treeent
strcpy(buffer, treeentry_path);
return tree_frompath(parent_out, root, buffer, 0);
}
+
+static int tree_walk_post(git_tree *tree, git_treewalk_cb callback, char *root, size_t root_len)
+{
+ int error;
+ unsigned int i;
+
+ for (i = 0; i < tree->entries.length; ++i) {
+ git_tree_entry *entry = tree->entries.contents[i];
+
+ root[root_len] = '\0';
+
+ if (callback(root, entry) < 0)
+ continue;
+
+ if (ENTRY_IS_TREE(entry)) {
+ git_tree *subtree;
+
+ if ((error = git_tree_lookup(&subtree, tree->object.repo, &entry->oid)) < 0)
+ return error;
+
+ strcpy(root + root_len, entry->filename);
+ root[root_len + entry->filename_len] = '/';
+
+ tree_walk_post(subtree, callback, root, root_len + entry->filename_len + 1);
+
+ git_tree_close(subtree);
+ }
+ }
+
+ return GIT_SUCCESS;
+}
+
+int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode)
+{
+ char root_path[GIT_PATH_MAX];
+
+ root_path[0] = '\0';
+ switch (mode) {
+ case GIT_TREEWALK_POST:
+ return tree_walk_post(tree, callback, root_path, 0);
+
+ case GIT_TREEWALK_PRE:
+ return git__throw(GIT_ENOTIMPLEMENTED,
+ "Preorder tree walking is still not implemented");
+
+ default:
+ return git__throw(GIT_EINVALIDARGS,
+ "Invalid walking mode for tree walk");
+ }
+}