Convert git_path_walk_up to regular function This gets rid of the crazy macro version of git_path_walk_up and makes it into a normal function that takes a callback parameter. This turned out not to be too messy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
diff --git a/src/attr.c b/src/attr.c
index 0c08fc0..06a6601 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -256,6 +256,17 @@ cleanup:
#define push_attrs(R,S,B,F) \
git_attr_cache__push_file((R),(S),(B),(F),git_attr_file__from_file)
+typedef struct {
+ git_repository *repo;
+ git_vector *files;
+} attr_walk_up_info;
+
+static int push_one_attr(void *ref, git_buf *path)
+{
+ attr_walk_up_info *info = (attr_walk_up_info *)ref;
+ return push_attrs(info->repo, info->files, path->ptr, GIT_ATTR_FILE);
+}
+
static int collect_attr_files(
git_repository *repo, const char *path, git_vector *files)
{
@@ -263,6 +274,7 @@ static int collect_attr_files(
git_buf dir = GIT_BUF_INIT;
git_config *cfg;
const char *workdir = git_repository_workdir(repo);
+ attr_walk_up_info info;
if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS)
goto cleanup;
@@ -284,20 +296,9 @@ static int collect_attr_files(
if (error < GIT_SUCCESS)
goto cleanup;
- if (workdir && git__prefixcmp(dir.ptr, workdir) == 0) {
- ssize_t rootlen = (ssize_t)strlen(workdir);
-
- do {
- error = push_attrs(repo, files, dir.ptr, GIT_ATTR_FILE);
- if (error == GIT_SUCCESS) {
- git_path_dirname_r(&dir, dir.ptr);
- git_path_to_dir(&dir);
- error = git_buf_lasterror(&dir);
- }
- } while (!error && dir.size >= rootlen);
- } else {
- error = push_attrs(repo, files, dir.ptr, GIT_ATTR_FILE);
- }
+ info.repo = repo;
+ info.files = files;
+ error = git_path_walk_up(&dir, workdir, push_one_attr, &info);
if (error < GIT_SUCCESS)
goto cleanup;
diff --git a/src/ignore.c b/src/ignore.c
index 7639b7b..fa71d49 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -64,12 +64,24 @@ static int load_ignore_file(
#define push_ignore(R,S,B,F) \
git_attr_cache__push_file((R),(S),(B),(F),load_ignore_file)
+typedef struct {
+ git_repository *repo;
+ git_vector *stack;
+} ignore_walk_up_info;
+
+static int push_one_ignore(void *ref, git_buf *path)
+{
+ ignore_walk_up_info *info = (ignore_walk_up_info *)ref;
+ return push_ignore(info->repo, info->stack, path->ptr, GIT_IGNORE_FILE);
+}
+
int git_ignore__for_path(git_repository *repo, const char *path, git_vector *stack)
{
int error = GIT_SUCCESS;
- git_buf dir = GIT_BUF_INIT, scan;
+ git_buf dir = GIT_BUF_INIT;
git_config *cfg;
const char *workdir = git_repository_workdir(repo);
+ ignore_walk_up_info info;
if ((error = git_attr_cache__init(repo)) < GIT_SUCCESS)
goto cleanup;
@@ -82,11 +94,9 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_vector *sta
goto cleanup;
/* load .gitignore up the path */
- git_path_walk_up(&dir, &scan, workdir, {
- error = push_ignore(repo, stack, scan.ptr, GIT_IGNORE_FILE);
- if (error < GIT_SUCCESS) break;
- });
- if (error < GIT_SUCCESS)
+ info.repo = repo;
+ info.stack = stack;
+ if ((error = git_path_walk_up(&dir, workdir, push_one_ignore, &info)) < GIT_SUCCESS)
goto cleanup;
/* load .git/info/exclude */
diff --git a/src/path.c b/src/path.c
index f9663b7..4888123 100644
--- a/src/path.c
+++ b/src/path.c
@@ -305,3 +305,45 @@ int git_path_fromurl(git_buf *local_path_out, const char *file_url)
return error;
}
+
+int git_path_walk_up(
+ git_buf *path,
+ const char *ceiling,
+ int (*cb)(void *data, git_buf *),
+ void *data)
+{
+ int error = GIT_SUCCESS;
+ git_buf iter;
+ ssize_t stop = 0, scan;
+ char oldc = '\0';
+
+ assert(path && cb);
+
+ if (ceiling != NULL) {
+ if (git__prefixcmp(path->ptr, ceiling) == GIT_SUCCESS)
+ stop = (ssize_t)strlen(ceiling);
+ else
+ stop = path->size;
+ }
+ scan = path->size;
+
+ iter.ptr = path->ptr;
+ iter.size = path->size;
+
+ while (scan >= stop) {
+ if ((error = cb(data, &iter)) < GIT_SUCCESS)
+ break;
+ iter.ptr[scan] = oldc;
+ scan = git_buf_rfind_next(&iter, '/');
+ if (scan >= 0) {
+ scan++;
+ oldc = iter.ptr[scan];
+ iter.size = scan;
+ iter.ptr[scan] = '\0';
+ }
+ }
+
+ iter.ptr[scan] = oldc;
+
+ return error;
+}
diff --git a/src/path.h b/src/path.h
index ceb3bb5..e59c19a 100644
--- a/src/path.h
+++ b/src/path.h
@@ -77,27 +77,18 @@ GIT_INLINE(void) git_path_mkposix(char *path)
extern int git__percent_decode(git_buf *decoded_out, const char *input);
extern int git_path_fromurl(git_buf *local_path_out, const char *file_url);
-/*
- * Use as:
- *
- * git_path_walk_up(
- * git_buf *path, git_buf *iterator, const char *root_path,
- * ... CALLBACK CODE ...)
+/**
+ * Invoke callback directory by directory up the path until the ceiling
+ * is reached (inclusive of a final call at the root_path).
*
- * to invoke callback directory by directory up the path until the root_path
- * is reached (inclusive of a final call at the root_path). If root path is
- * NULL or the path is not contained in the root_path, then the callback
- * code will be invoked just once on input path.
+ * If the ceiling is NULL, this will walk all the way up to the root.
+ * If the ceiling is not a prefix of the path, the callback will be
+ * invoked a single time on the verbatim input path. Returning anything
+ * other than GIT_SUCCESS from the callback function will stop the
+ * iteration and propogate the error to the caller.
*/
-#define git_path_walk_up(B,IB,ROOT,CODE) do { \
- ssize_t _stop = ((ROOT) && git__prefixcmp((B)->ptr, (ROOT))) ? (ssize_t)strlen(ROOT) : (B)->size; \
- ssize_t _scan = (B)->size; char _oldc = '\0'; \
- (IB)->ptr = (B)->ptr; (IB)->size = (B)->size; \
- while (_scan >= _stop) { \
- CODE; \
- (IB)->ptr[_scan] = _oldc; \
- _scan = git_buf_rfind_next((IB), '/'); \
- if (_scan >= 0) { _scan++; _oldc = (IB)->ptr[_scan]; (IB)->size = _scan; (IB)->ptr[_scan] = '\0'; } \
- } (IB)->ptr[_scan] = _oldc; } while (0)
+extern int git_path_walk_up(
+ git_buf *path, const char *ceiling,
+ int (*cb)(void *data, git_buf *), void *data);
#endif
diff --git a/tests-clay/core/path.c b/tests-clay/core/path.c
index 712ceb4..1a77a1f 100644
--- a/tests-clay/core/path.c
+++ b/tests-clay/core/path.c
@@ -337,9 +337,23 @@ void test_core_path__10_fromurl(void)
check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0);
}
+typedef struct {
+ int expect_idx;
+ char **expect;
+} check_walkup_info;
+
+static int check_one_walkup_step(void *ref, git_buf *path)
+{
+ check_walkup_info *info = (check_walkup_info *)ref;
+ cl_assert(info->expect[info->expect_idx] != NULL);
+ cl_assert_strequal(info->expect[info->expect_idx], path->ptr);
+ info->expect_idx++;
+ return GIT_SUCCESS;
+}
+
void test_core_path__11_walkup(void)
{
- git_buf p = GIT_BUF_INIT, iter;
+ git_buf p = GIT_BUF_INIT;
char *expect[] = {
"/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
"/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
@@ -353,16 +367,18 @@ void test_core_path__11_walkup(void)
};
char *root[] = { NULL, NULL, "/", "", "/a/b", "/a/b/", NULL, NULL, NULL };
int i, j;
+ check_walkup_info info;
+
+ info.expect = expect;
for (i = 0, j = 0; expect[i] != NULL; i++, j++) {
- int cb_count = 0;
git_buf_sets(&p, expect[i]);
- git_path_walk_up(&p, &iter, root[j], {
- cl_assert(expect[i + cb_count] != NULL);
- cl_assert_strequal(expect[i + cb_count], iter.ptr);
- cb_count++; });
+ info.expect_idx = i;
+ cl_git_pass(
+ git_path_walk_up(&p, root[j], check_one_walkup_step, &info)
+ );
cl_assert_strequal(p.ptr, expect[i]);