Commit a603c191 by Nico von Geyso Committed by Carlos Martín Nieto

replaced foreach() with non callback based iterations in git_config_backend

new functions in struct git_config_backend:
  * iterator_new(...)
  * iterator_free(...)
  * next(...)

The old callback based foreach style can still be used with `git_config_backend_foreach_match`
parent 6385fc5f
......@@ -61,6 +61,7 @@ typedef struct {
} git_config_entry;
typedef int (*git_config_foreach_cb)(const git_config_entry *, void *);
typedef struct git_config_backend_iter* git_config_backend_iter;
typedef enum {
GIT_CVAR_FALSE = 0,
......@@ -535,6 +536,25 @@ GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value);
GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value);
/**
* Perform an operation on each config variable in given config backend
* matching a regular expression.
*
* This behaviors like `git_config_foreach_match` except instead of all config
* entries it just enumerates through the given backend entry.
*
* @param backend where to get the variables from
* @param regexp regular expression to match against config names (can be NULL)
* @param callback the function to call on each variable
* @param payload the data to pass to the callback
*/
GIT_EXTERN(int) git_config_backend_foreach_match(
git_config_backend *backend,
const char *regexp,
int (*fn)(const git_config_entry *, void *),
void *data);
/** @} */
GIT_END_DECL
#endif
......@@ -35,7 +35,9 @@ struct git_config_backend {
int (*set)(struct git_config_backend *, const char *key, const char *value);
int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value);
int (*del)(struct git_config_backend *, const char *key);
int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload);
int (*iterator_new)(git_config_backend_iter **, struct git_config_backend *);
void (*iterator_free)(git_config_backend_iter *);
int (*next)(git_config_backend_iter *, git_config_entry *, struct git_config_backend *);
int (*refresh)(struct git_config_backend *);
void (*free)(struct git_config_backend *);
};
......
......@@ -321,6 +321,50 @@ int git_config_foreach(
return git_config_foreach_match(cfg, NULL, cb, payload);
}
int git_config_backend_foreach_match(
git_config_backend *backend,
const char *regexp,
int (*fn)(const git_config_entry *, void *),
void *data)
{
git_config_entry entry;
git_config_backend_iter iter;
regex_t regex;
int result = 0;
if (regexp != NULL) {
if ((result = regcomp(&regex, regexp, REG_EXTENDED)) < 0) {
giterr_set_regex(&regex, result);
regfree(&regex);
return -1;
}
}
if (backend->iterator_new(&iter, backend) < 0)
return 0;
while(!(backend->next(&iter, &entry, backend) < 0)) {
/* skip non-matching keys if regexp was provided */
if (regexp && regexec(&regex, entry.name, 0, NULL, 0) != 0)
continue;
/* abort iterator on non-zero return value */
if (fn(&entry, data)) {
giterr_clear();
result = GIT_EUSER;
goto cleanup;
}
}
cleanup:
if (regexp != NULL)
regfree(&regex);
backend->iterator_free(iter);
return result;
}
int git_config_foreach_match(
const git_config *cfg,
const char *regexp,
......@@ -335,7 +379,7 @@ int git_config_foreach_match(
for (i = 0; i < cfg->files.length && ret == 0; ++i) {
internal = git_vector_get(&cfg->files, i);
file = internal->file;
ret = file->foreach(file, regexp, cb, payload);
ret = git_config_backend_foreach_match(file, regexp, cb, payload);
}
return ret;
......
......@@ -27,6 +27,12 @@ typedef struct cvar_t {
git_config_entry *entry;
} cvar_t;
typedef struct git_config_file_iter {
git_strmap_iter iter;
cvar_t* next;
} git_config_file_iter;
#define CVAR_LIST_HEAD(list) ((list)->head)
#define CVAR_LIST_TAIL(list) ((list)->tail)
......@@ -247,52 +253,60 @@ static void backend_free(git_config_backend *_backend)
git__free(backend);
}
static int file_foreach(
git_config_backend *backend,
const char *regexp,
int (*fn)(const git_config_entry *, void *),
void *data)
static int config_iterator_new(
git_config_backend_iter *iter,
struct git_config_backend* backend)
{
diskfile_backend *b = (diskfile_backend *)backend;
cvar_t *var, *next_var;
const char *key;
regex_t regex;
int result = 0;
git_config_file_iter **it= ((git_config_file_iter**) iter);
if (!b->values)
return 0;
if (!b->values || git_strmap_num_entries(b->values) < 1)
return -1;
if (regexp != NULL) {
if ((result = regcomp(&regex, regexp, REG_EXTENDED)) < 0) {
giterr_set_regex(&regex, result);
regfree(&regex);
return -1;
}
}
*it = git__calloc(1, sizeof(git_config_file_iter));
GITERR_CHECK_ALLOC(it);
git_strmap_iter iter = git_strmap_begin(b->values);
while (!(git_strmap_next(&key, (void**) &var, &iter, b->values) < 0)) {
for (; var != NULL; var = next_var) {
next_var = CVAR_LIST_NEXT(var);
(*it)->iter = git_strmap_begin(b->values);
(*it)->next = NULL;
/* skip non-matching keys if regexp was provided */
if (regexp && regexec(&regex, key, 0, NULL, 0) != 0)
continue;
return 0;
}
/* abort iterator on non-zero return value */
if (fn(var->entry, data)) {
giterr_clear();
result = GIT_EUSER;
goto cleanup;
}
}
static void config_iterator_free(
git_config_backend_iter iter)
{
git__free(iter);
}
static int config_next(
git_config_backend_iter *iter,
git_config_entry* entry,
struct git_config_backend* backend)
{
diskfile_backend *b = (diskfile_backend *)backend;
git_config_file_iter *it = *((git_config_file_iter**) iter);
int err;
cvar_t * var;
const char* key;
if (it->next == NULL) {
err = git_strmap_next(&key, (void**) &var, &(it->iter), b->values);
} else {
key = it->next->entry->name;
var = it->next;
}
cleanup:
if (regexp != NULL)
regfree(&regex);
if (err < 0) {
it->next = NULL;
return -1;
}
return result;
entry->name = key;
entry->value = var->entry->value;
entry->level = var->entry->level;
it->next = CVAR_LIST_NEXT(var);
return 0;
}
static int config_set(git_config_backend *cfg, const char *name, const char *value)
......@@ -595,7 +609,9 @@ int git_config_file__ondisk(git_config_backend **out, const char *path)
backend->parent.set = config_set;
backend->parent.set_multivar = config_set_multivar;
backend->parent.del = config_delete;
backend->parent.foreach = file_foreach;
backend->parent.iterator_new = config_iterator_new;
backend->parent.iterator_free = config_iterator_free;
backend->parent.next = config_next;
backend->parent.refresh = config_refresh;
backend->parent.free = backend_free;
......
......@@ -42,7 +42,7 @@ GIT_INLINE(int) git_config_file_foreach(
int (*fn)(const git_config_entry *entry, void *data),
void *data)
{
return cfg->foreach(cfg, NULL, fn, data);
return git_config_backend_foreach_match(cfg, NULL, fn, data);
}
GIT_INLINE(int) git_config_file_foreach_match(
......@@ -51,7 +51,7 @@ GIT_INLINE(int) git_config_file_foreach_match(
int (*fn)(const git_config_entry *entry, void *data),
void *data)
{
return cfg->foreach(cfg, regexp, fn, data);
return git_config_backend_foreach_match(cfg, regexp, fn, data);
}
extern int git_config_file_normalize_section(char *start, char *end);
......
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