summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2013-08-09 10:29:11 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2013-08-12 11:40:57 +0200
commit54f3a572b4fac419008afa83da56c1b0daee1257 (patch)
tree5a89bdbb596c65128646b42b02a17096beadafae
parent5880962d90958bc37c08c21d37c9da480ef20e7f (diff)
downloadlibgit2-54f3a572b4fac419008afa83da56c1b0daee1257.tar.gz
config: introduce a regex-filtering iterator
-rw-r--r--include/git2/config.h12
-rw-r--r--src/config.c61
-rw-r--r--tests-clar/config/read.c33
3 files changed, 106 insertions, 0 deletions
diff --git a/include/git2/config.h b/include/git2/config.h
index aed720fc8..28216467b 100644
--- a/include/git2/config.h
+++ b/include/git2/config.h
@@ -464,6 +464,18 @@ GIT_EXTERN(int) git_config_foreach(
GIT_EXTERN(int) git_config_iterator_new(git_config_iterator **out, const git_config *cfg);
/**
+ * Iterate over all the config variables whose name matches a pattern
+ *
+ * Use `git_config_next` to advance the iteration and
+ * `git_config_iterator_free` when done.
+ *
+ * @param out pointer to store the iterator
+ * @param cfg where to ge the variables from
+ * @param regexp regular expression to match the names
+ */
+GIT_EXTERN(int) git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp);
+
+/**
* Perform an operation on each config variable matching a regular expression.
*
* This behaviors like `git_config_foreach` with an additional filter of a
diff --git a/src/config.c b/src/config.c
index f7ea6f795..9d809f8f1 100644
--- a/src/config.c
+++ b/src/config.c
@@ -319,6 +319,8 @@ typedef struct {
git_config_iterator parent;
git_config_iterator *current;
const git_config *cfg;
+ regex_t regex;
+ int has_regex;
size_t i;
} all_iter;
@@ -380,6 +382,27 @@ static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter)
return GIT_ITEROVER;
}
+static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_iter)
+{
+ int error;
+ all_iter *iter = (all_iter *) _iter;
+
+ /*
+ * We use the "normal" function to grab the next one across
+ * backends and then apply the regex
+ */
+ while ((error = all_iter_next(entry, _iter)) == 0) {
+ /* skip non-matching keys if regexp was provided */
+ if (regexec(&iter->regex, (*entry)->name, 0, NULL, 0) != 0)
+ continue;
+
+ /* and simply return if we like the entry's name */
+ return 0;
+ }
+
+ return error;
+}
+
static void all_iter_free(git_config_iterator *_iter)
{
all_iter *iter = (all_iter *) _iter;
@@ -390,6 +413,14 @@ static void all_iter_free(git_config_iterator *_iter)
git__free(iter);
}
+static void all_iter_glob_free(git_config_iterator *_iter)
+{
+ all_iter *iter = (all_iter *) _iter;
+
+ regfree(&iter->regex);
+ all_iter_free(_iter);
+}
+
int git_config_iterator_new(git_config_iterator **out, const git_config *cfg)
{
all_iter *iter;
@@ -408,6 +439,36 @@ int git_config_iterator_new(git_config_iterator **out, const git_config *cfg)
return 0;
}
+int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp)
+{
+ all_iter *iter;
+ int result;
+
+ iter = git__calloc(1, sizeof(all_iter));
+ GITERR_CHECK_ALLOC(iter);
+
+ if (regexp != NULL) {
+ if ((result = regcomp(&iter->regex, regexp, REG_EXTENDED)) < 0) {
+ giterr_set_regex(&iter->regex, result);
+ regfree(&iter->regex);
+ return -1;
+ }
+
+ iter->parent.next = all_iter_glob_next;
+ } else {
+ iter->parent.next = all_iter_next;
+ }
+
+ iter->parent.free = all_iter_glob_free;
+
+ iter->i = cfg->files.length;
+ iter->cfg = cfg;
+
+ *out = (git_config_iterator *) iter;
+
+ return 0;
+}
+
int git_config_foreach(
const git_config *cfg, git_config_foreach_cb cb, void *payload)
{
diff --git a/tests-clar/config/read.c b/tests-clar/config/read.c
index 2fb511d9d..395f1cfdb 100644
--- a/tests-clar/config/read.c
+++ b/tests-clar/config/read.c
@@ -265,6 +265,7 @@ void test_config_read__iterator(void)
count++;
}
+ git_config_iterator_free(iter);
cl_assert_equal_i(GIT_ITEROVER, ret);
cl_assert_equal_i(7, count);
@@ -318,6 +319,38 @@ void test_config_read__foreach_match(void)
git_config_free(cfg);
}
+static void check_glob_iter(git_config *cfg, const char *regexp, int expected)
+{
+ git_config_iterator *iter;
+ git_config_entry *entry;
+ int count, error;
+
+ cl_git_pass(git_config_iterator_glob_new(&iter, cfg, regexp));
+
+ count = 0;
+ while ((error = git_config_next(&entry, iter)) == 0)
+ count++;
+
+ cl_assert_equal_i(GIT_ITEROVER, error);
+ cl_assert_equal_i(expected, count);
+ git_config_iterator_free(iter);
+}
+
+void test_config_read__iterator_glob(void)
+{
+ git_config *cfg;
+
+ cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
+
+ check_glob_iter(cfg, "core.*", 3);
+ check_glob_iter(cfg, "remote\\.ab.*", 2);
+ check_glob_iter(cfg, ".*url$", 2);
+ check_glob_iter(cfg, ".*dummy.*", 2);
+ check_glob_iter(cfg, ".*nomatch.*", 0);
+
+ git_config_free(cfg);
+}
+
void test_config_read__whitespace_not_required_around_assignment(void)
{
git_config *cfg;