summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/git2/config.h20
-rw-r--r--include/git2/sys/config.h4
-rw-r--r--src/config.c46
-rw-r--r--src/config_file.c90
-rw-r--r--src/config_file.h4
5 files changed, 123 insertions, 41 deletions
diff --git a/include/git2/config.h b/include/git2/config.h
index 827d43544..f6fc74ee1 100644
--- a/include/git2/config.h
+++ b/include/git2/config.h
@@ -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
diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h
index 11e59cf03..61dcce544 100644
--- a/include/git2/sys/config.h
+++ b/include/git2/sys/config.h
@@ -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 *);
};
diff --git a/src/config.c b/src/config.c
index 2a058549f..b421b3be1 100644
--- a/src/config.c
+++ b/src/config.c
@@ -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;
diff --git a/src/config_file.c b/src/config_file.c
index 088f6190d..ff8f8fc15 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -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;
diff --git a/src/config_file.h b/src/config_file.h
index 7445859c4..d4a1a4061 100644
--- a/src/config_file.h
+++ b/src/config_file.h
@@ -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);