Commit 54f3a572 by Carlos Martín Nieto

config: introduce a regex-filtering iterator

parent 5880962d
...@@ -464,6 +464,18 @@ GIT_EXTERN(int) git_config_foreach( ...@@ -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); 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. * Perform an operation on each config variable matching a regular expression.
* *
* This behaviors like `git_config_foreach` with an additional filter of a * This behaviors like `git_config_foreach` with an additional filter of a
......
...@@ -319,6 +319,8 @@ typedef struct { ...@@ -319,6 +319,8 @@ typedef struct {
git_config_iterator parent; git_config_iterator parent;
git_config_iterator *current; git_config_iterator *current;
const git_config *cfg; const git_config *cfg;
regex_t regex;
int has_regex;
size_t i; size_t i;
} all_iter; } all_iter;
...@@ -380,6 +382,27 @@ static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter) ...@@ -380,6 +382,27 @@ static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter)
return GIT_ITEROVER; 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) static void all_iter_free(git_config_iterator *_iter)
{ {
all_iter *iter = (all_iter *) _iter; all_iter *iter = (all_iter *) _iter;
...@@ -390,6 +413,14 @@ static void all_iter_free(git_config_iterator *_iter) ...@@ -390,6 +413,14 @@ static void all_iter_free(git_config_iterator *_iter)
git__free(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) int git_config_iterator_new(git_config_iterator **out, const git_config *cfg)
{ {
all_iter *iter; all_iter *iter;
...@@ -408,6 +439,36 @@ int git_config_iterator_new(git_config_iterator **out, const git_config *cfg) ...@@ -408,6 +439,36 @@ int git_config_iterator_new(git_config_iterator **out, const git_config *cfg)
return 0; 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( int git_config_foreach(
const git_config *cfg, git_config_foreach_cb cb, void *payload) const git_config *cfg, git_config_foreach_cb cb, void *payload)
{ {
......
...@@ -265,6 +265,7 @@ void test_config_read__iterator(void) ...@@ -265,6 +265,7 @@ void test_config_read__iterator(void)
count++; count++;
} }
git_config_iterator_free(iter);
cl_assert_equal_i(GIT_ITEROVER, ret); cl_assert_equal_i(GIT_ITEROVER, ret);
cl_assert_equal_i(7, count); cl_assert_equal_i(7, count);
...@@ -318,6 +319,38 @@ void test_config_read__foreach_match(void) ...@@ -318,6 +319,38 @@ void test_config_read__foreach_match(void)
git_config_free(cfg); 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) void test_config_read__whitespace_not_required_around_assignment(void)
{ {
git_config *cfg; git_config *cfg;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment