From 99dfb538addc06c2f40d29371c52dd43f0d6ceb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 8 Aug 2013 17:57:59 +0200 Subject: [PATCH] config: working multivar iterator Implement the foreach version as a wrapper around the iterator. --- include/git2/config.h | 10 ++++ include/git2/sys/config.h | 2 +- src/config.c | 89 +++++++++++++++++++++++------------- src/config_file.c | 20 ++++---- tests-clar/config/multivar.c | 14 +++--- 5 files changed, 83 insertions(+), 52 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index 950312548..e1d34b997 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -341,6 +341,16 @@ GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, c */ GIT_EXTERN(int) git_config_get_multivar_foreach(const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb callback, void *payload); +/** + * Get each value of a multivar + * + * @param out pointer to store the iterator + * @param cfg where to look for the variable + * @param name the variable's name + * @param regexp regular expression to filter which variables we're + * interested in. Use NULL to indicate all + */ +GIT_EXTERN(int) git_config_get_multivar(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp); /** * Set the value of an integer config variable in the config file * with the highest level (usually the local one). diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index d5b450a6c..e369fb8ab 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -39,7 +39,7 @@ struct git_config_iterator { * Return the current entry and advance the iterator. The * memory belongs to the library. */ - int (*next)(git_config_entry *entry, git_config_iterator *iter); + int (*next)(git_config_entry **entry, git_config_iterator *iter); /** * Free the iterator diff --git a/src/config.c b/src/config.c index f34d5dd29..63a386de3 100644 --- a/src/config.c +++ b/src/config.c @@ -327,7 +327,7 @@ int git_config_backend_foreach_match( int (*fn)(const git_config_entry *, void *), void *data) { - git_config_entry entry; + git_config_entry *entry; git_config_iterator* iter; regex_t regex; int result = 0; @@ -347,11 +347,11 @@ int git_config_backend_foreach_match( while(!(iter->next(&entry, iter) < 0)) { /* skip non-matching keys if regexp was provided */ - if (regexp && regexec(®ex, entry.name, 0, NULL, 0) != 0) + if (regexp && regexec(®ex, entry->name, 0, NULL, 0) != 0) continue; /* abort iterator on non-zero return value */ - if (fn(&entry, data)) { + if (fn(entry, data)) { giterr_clear(); result = GIT_EUSER; goto cleanup; @@ -578,35 +578,36 @@ int git_config_get_multivar_foreach( const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb cb, void *payload) { - file_internal *internal; - git_config_backend *file; - int ret = GIT_ENOTFOUND, err; - size_t i; + int err, found; + git_config_iterator *iter; + git_config_entry *entry; - /* - * This loop runs the "wrong" way 'round because we need to - * look at every value from the most general to most specific - */ - for (i = cfg->files.length; i > 0; --i) { - internal = git_vector_get(&cfg->files, i - 1); - if (!internal || !internal->file) - continue; - file = internal->file; + if ((err = git_config_get_multivar(&iter, cfg, name, regexp)) < 0) + return err; - if (!(err = file->get_multivar_foreach(file, name, regexp, cb, payload))) - ret = 0; - else if (err != GIT_ENOTFOUND) - return err; + found = 0; + while ((err = iter->next(&entry, iter)) == 0) { + found = 1; + if(cb(entry, payload)) { + iter->free(iter); + return GIT_EUSER; + } } - return (ret == GIT_ENOTFOUND) ? config_error_notfound(name) : 0; + if (err == GIT_ITEROVER) + err = 0; + + if (found == 0 && err == 0) + err = config_error_notfound(name); + + return err; } typedef struct { git_config_iterator parent; git_config_iterator *current; - const char *name; - const char *regexp; + char *name; + char *regexp; const git_config *cfg; size_t i; } multivar_iter; @@ -627,7 +628,7 @@ static int find_next_backend(size_t *out, const git_config *cfg, size_t i) return -1; } -static int multivar_iter_next_empty(git_config_entry *entry, git_config_iterator *_iter) +static int multivar_iter_next_empty(git_config_entry **entry, git_config_iterator *_iter) { GIT_UNUSED(entry); GIT_UNUSED(_iter); @@ -635,20 +636,21 @@ static int multivar_iter_next_empty(git_config_entry *entry, git_config_iterator return GIT_ITEROVER; } -static int multivar_iter_next(git_config_entry *entry, git_config_iterator *_iter) +static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter) { multivar_iter *iter = (multivar_iter *) _iter; git_config_iterator *current = iter->current; file_internal *internal; git_config_backend *backend; size_t i; - int error; + int error = 0; if (current != NULL && - (error = current->next(entry, current)) == 0) + (error = current->next(entry, current)) == 0) { return 0; + } - if (error != GIT_ITEROVER) + if (error < 0 && error != GIT_ITEROVER) return error; do { @@ -657,10 +659,15 @@ static int multivar_iter_next(git_config_entry *entry, git_config_iterator *_ite internal = git_vector_get(&iter->cfg->files, i - 1); backend = internal->file; - if ((error = backend->get_multivar(&iter->current, backend, iter->name, iter->regexp)) < 0) - return -1; + iter->i = i - 1; + + error = backend->get_multivar(&iter->current, backend, iter->name, iter->regexp); + if (error == GIT_ENOTFOUND) + continue; + + if (error < 0) + return error; - iter->i = i; return iter->current->next(entry, iter->current); } while(1); @@ -668,6 +675,15 @@ static int multivar_iter_next(git_config_entry *entry, git_config_iterator *_ite return GIT_ITEROVER; } +void multivar_iter_free(git_config_iterator *_iter) +{ + multivar_iter *iter = (multivar_iter *) _iter; + + git__free(iter->name); + git__free(iter->regexp); + git__free(iter); +} + int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp) { multivar_iter *iter; @@ -676,6 +692,15 @@ int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, co iter = git__calloc(1, sizeof(multivar_iter)); GITERR_CHECK_ALLOC(iter); + iter->name = git__strdup(name); + GITERR_CHECK_ALLOC(iter->name); + + if (regexp != NULL) { + iter->regexp = git__strdup(regexp); + GITERR_CHECK_ALLOC(iter->regexp); + } + + iter->parent.free = multivar_iter_free; if (find_next_backend(&i, cfg, cfg->files.length) < 0) iter->parent.next = multivar_iter_next_empty; else @@ -683,8 +708,6 @@ int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, co iter->i = cfg->files.length; iter->cfg = cfg; - iter->name = name; - iter->regexp = regexp; *out = (git_config_iterator *) iter; diff --git a/src/config_file.c b/src/config_file.c index 74b200073..38cb9f8b8 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -261,7 +261,7 @@ static void config_iterator_free( } static int config_iterator_next( - git_config_entry *entry, + git_config_entry **entry, git_config_iterator *iter) { git_config_file_iter *it = (git_config_file_iter *) iter; @@ -282,9 +282,7 @@ static int config_iterator_next( return -1; } - entry->name = key; - entry->value = var->entry->value; - entry->level = var->entry->level; + *entry = var->entry; it->next_var = CVAR_LIST_NEXT(var); return 0; @@ -433,19 +431,18 @@ static void foreach_iter_free(git_config_iterator *_iter) git__free(iter); } -static int foreach_iter_next(git_config_entry *out, git_config_iterator *_iter) +static int foreach_iter_next(git_config_entry **out, git_config_iterator *_iter) { foreach_iter *iter = (foreach_iter *) _iter; cvar_t* var = iter->var; + if (var == NULL) return GIT_ITEROVER; if (!iter->have_regex) { - out->name = var->entry->name; - out->value = var->entry->value; - + *out = var->entry; iter->var = var->next; return 0; } @@ -455,10 +452,11 @@ static int foreach_iter_next(git_config_entry *out, git_config_iterator *_iter) git_config_entry *entry = var->entry; regex_t *regex = &iter->regex;; if (regexec(regex, entry->value, 0, NULL, 0) == 0) { - out->name = entry->name; - out->value = entry->value; + *out = entry; + iter->var = var->next; return 0; } + var = var->next; } while(var != NULL); return GIT_ITEROVER; @@ -550,7 +548,7 @@ static int config_get_multivar_foreach( if (regexec(®ex, var->entry->value, 0, NULL, 0) == 0) { /* early termination by the user is not an error; * just break and return successfully */ - if (fn(var->entry, data) < 0) + if (fn(var->entry, data)) break; } diff --git a/tests-clar/config/multivar.c b/tests-clar/config/multivar.c index 390b24c6b..b7283b32f 100644 --- a/tests-clar/config/multivar.c +++ b/tests-clar/config/multivar.c @@ -114,11 +114,11 @@ void test_config_multivar__add(void) n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n)); - cl_assert(n == 3); + cl_assert_equal_i(n, 3); n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n)); - cl_assert(n == 1); + cl_assert_equal_i(n, 1); git_config_free(cfg); @@ -128,11 +128,11 @@ void test_config_multivar__add(void) n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n)); - cl_assert(n == 3); + cl_assert_equal_i(n, 3); n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n)); - cl_assert(n == 1); + cl_assert_equal_i(n, 1); git_config_free(cfg); } @@ -148,7 +148,7 @@ void test_config_multivar__add_new(void) cl_git_pass(git_config_set_multivar(cfg, var, "", "variable")); n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, var, NULL, cb, &n)); - cl_assert(n == 1); + cl_assert_equal_i(n, 1); git_config_free(cfg); } @@ -191,7 +191,7 @@ void test_config_multivar__replace_multiple(void) n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n)); - cl_assert(n == 2); + cl_assert_equal_i(n, 2); git_config_free(cfg); @@ -199,7 +199,7 @@ void test_config_multivar__replace_multiple(void) n = 0; cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n)); - cl_assert(n == 2); + cl_assert_equal_i(n, 2); git_config_free(cfg); }