Commit 5880962d by Carlos Martín Nieto

config: introduce _iterator_new()

As the name suggests, it iterates over all the entries
parent a319ffae
......@@ -453,6 +453,17 @@ GIT_EXTERN(int) git_config_foreach(
void *payload);
/**
* Iterate over all the config variables
*
* 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
*/
GIT_EXTERN(int) git_config_iterator_new(git_config_iterator **out, const git_config *cfg);
/**
* Perform an operation on each config variable matching a regular expression.
*
* This behaviors like `git_config_foreach` with an additional filter of a
......
......@@ -315,6 +315,99 @@ int git_config_refresh(git_config *cfg)
* Loop over all the variables
*/
typedef struct {
git_config_iterator parent;
git_config_iterator *current;
const git_config *cfg;
size_t i;
} all_iter;
static int find_next_backend(size_t *out, const git_config *cfg, size_t i)
{
file_internal *internal;
for (; i > 0; --i) {
internal = git_vector_get(&cfg->files, i - 1);
if (!internal || !internal->file)
continue;
*out = i;
return 0;
}
return -1;
}
static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter)
{
all_iter *iter = (all_iter *) _iter;
file_internal *internal;
git_config_backend *backend;
size_t i;
int error = 0;
if (iter->current != NULL &&
(error = iter->current->next(entry, iter->current)) == 0) {
return 0;
}
if (error < 0 && error != GIT_ITEROVER)
return error;
do {
if (find_next_backend(&i, iter->cfg, iter->i) < 0)
return GIT_ITEROVER;
internal = git_vector_get(&iter->cfg->files, i - 1);
backend = internal->file;
iter->i = i - 1;
if (iter->current)
iter->current->free(iter->current);
iter->current = NULL;
error = backend->iterator(&iter->current, backend);
if (error == GIT_ENOTFOUND)
continue;
if (error < 0)
return error;
return iter->current->next(entry, iter->current);
} while(1);
return GIT_ITEROVER;
}
static void all_iter_free(git_config_iterator *_iter)
{
all_iter *iter = (all_iter *) _iter;
if (iter->current)
iter->current->free(iter->current);
git__free(iter);
}
int git_config_iterator_new(git_config_iterator **out, const git_config *cfg)
{
all_iter *iter;
iter = git__calloc(1, sizeof(all_iter));
GITERR_CHECK_ALLOC(iter);
iter->parent.free = all_iter_free;
iter->parent.next = all_iter_next;
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)
{
......@@ -613,30 +706,6 @@ typedef struct {
size_t i;
} multivar_iter;
static int find_next_backend(size_t *out, const git_config *cfg, size_t i)
{
file_internal *internal;
for (; i > 0; --i) {
internal = git_vector_get(&cfg->files, i - 1);
if (!internal || !internal->file)
continue;
*out = i;
return 0;
}
return -1;
}
static int multivar_iter_next_empty(git_config_entry **entry, git_config_iterator *_iter)
{
GIT_UNUSED(entry);
GIT_UNUSED(_iter);
return GIT_ITEROVER;
}
static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter)
{
multivar_iter *iter = (multivar_iter *) _iter;
......@@ -695,7 +764,6 @@ void multivar_iter_free(git_config_iterator *_iter)
int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp)
{
multivar_iter *iter;
size_t i;
iter = git__calloc(1, sizeof(multivar_iter));
GITERR_CHECK_ALLOC(iter);
......@@ -709,10 +777,7 @@ int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, co
}
iter->parent.free = multivar_iter_free;
if (find_next_backend(&i, cfg, cfg->files.length) < 0)
iter->parent.next = multivar_iter_next_empty;
else
iter->parent.next = multivar_iter_next;
iter->parent.next = multivar_iter_next;
iter->i = cfg->files.length;
iter->cfg = cfg;
......
......@@ -279,7 +279,7 @@ static int config_iterator_next(
if (err < 0) {
it->next_var = NULL;
return -1;
return err;
}
*entry = var->entry;
......
......@@ -245,6 +245,36 @@ void test_config_read__foreach(void)
git_config_free(cfg);
}
void test_config_read__iterator(void)
{
git_config *cfg;
git_config_iterator *iter;
git_config_entry *entry;
int count, ret;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_SYSTEM, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
GIT_CONFIG_LEVEL_GLOBAL, 0));
count = 0;
cl_git_pass(git_config_iterator_new(&iter, cfg));
while ((ret = git_config_next(&entry, iter)) == 0) {
count++;
}
cl_assert_equal_i(GIT_ITEROVER, ret);
cl_assert_equal_i(7, count);
count = 3;
cl_git_pass(git_config_iterator_new(&iter, cfg));
git_config_iterator_free(iter);
git_config_free(cfg);
}
static int count_cfg_entries(const git_config_entry *entry, void *payload)
{
int *count = payload;
......
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