From 3a7ffc29c9416c5d182835c7f18c04437366f218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 8 Aug 2013 16:18:07 +0200 Subject: [PATCH] config: initial multivar iterator --- include/git2/sys/config.h | 6 ++- src/config.c | 18 ++++++++ src/config_file.c | 90 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/include/git2/sys/config.h b/include/git2/sys/config.h index 45599dc69..477d47271 100644 --- a/include/git2/sys/config.h +++ b/include/git2/sys/config.h @@ -36,9 +36,10 @@ struct git_config_iterator { unsigned int flags; /** - * Return the current entry and advance the iterator + * Return the current entry and advance the iterator. The + * memory belongs to the library. */ - int (*next)(git_config_entry *entry, git_config_iterator *iter); + int (*next)(const git_config_entry *entry, git_config_iterator *iter); /** * Free the iterator @@ -58,6 +59,7 @@ struct git_config_backend { int (*open)(struct git_config_backend *, git_config_level_t level); int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); int (*get_multivar_foreach)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload); + int (*get_multivar)(git_config_iterator **, struct git_config_backend *, const char *name, const char *regexp); 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); diff --git a/src/config.c b/src/config.c index 5bec0f040..77c558022 100644 --- a/src/config.c +++ b/src/config.c @@ -602,6 +602,24 @@ int git_config_get_multivar_foreach( return (ret == GIT_ENOTFOUND) ? config_error_notfound(name) : 0; } +struct config_multivar_iter { + git_config_iterator parent; +}; + +int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp) +{ + struct config_multivar_iter *iter; + + iter = git__calloc(1, sizeof(struct config_multivar_iter)); + GITERR_CHECK_ALLOC(iter); + + /* get multivar from each */ + + *out = (git_config_iterator *) iter; + + return 0; +} + int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) { git_config_backend *file; diff --git a/src/config_file.c b/src/config_file.c index 3e0c6cc0b..5559bd406 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -416,6 +416,95 @@ static int config_get(const git_config_backend *cfg, const char *name, const git return 0; } +typedef struct { + git_config_iterator parent; + cvar_t *var; + regex_t regex; + int have_regex; +} foreach_iter; + +static void foreach_iter_free(git_config_iterator *_iter) +{ + foreach_iter *iter = (foreach_iter *) _iter; + + if (iter->have_regex) + regfree(&iter->regex); + + git__free(iter); +} + +static int foreach_iter_next(git_config_entry **out, git_config_iterator *_iter) +{ + foreach_iter *iter = (foreach_iter *) _iter; + + cvar_t* var = iter->var; + + if (var == NULL) + return GIT_ITEROVER; + + if (!iter->have_regex) { + *out = var->entry; + iter->var = var->next; + return 0; + } + + /* For the regex case, we must loop until we find something we like */ + do { + git_config_entry *entry = var->entry; + regex_t *regex = &iter->regex;; + if (regexec(regex, entry->value, 0, NULL, 0) == 0) { + *out = entry; + return 0; + } + } while(var != NULL); + + return GIT_ITEROVER; +} + +static int config_get_multivar(git_config_iterator **out, git_config_backend *_backend, + const char *name, const char *regexp) +{ + foreach_iter *iter; + diskfile_backend *b = (diskfile_backend *) _backend; + + char *key; + khiter_t pos; + int error = 0; + + if ((error = normalize_name(name, &key)) < 0) + return error; + + pos = git_strmap_lookup_index(b->values, key); + git__free(key); + + if (!git_strmap_valid_index(b->values, pos)) + return GIT_ENOTFOUND; + + iter = git__calloc(1, sizeof(foreach_iter)); + GITERR_CHECK_ALLOC(iter); + + iter->var = git_strmap_value_at(b->values, pos); + + if (regexp != NULL) { + int result; + + result = regcomp(&iter->regex, regexp, REG_EXTENDED); + if (result < 0) { + giterr_set_regex(&iter->regex, result); + regfree(&iter->regex); + return -1; + } + iter->have_regex = 1; + } + + iter->parent.free = foreach_iter_free; + iter->parent.next = foreach_iter_next; + + *out = (git_config_iterator *) iter; + + return 0; + } + static int config_get_multivar_foreach( git_config_backend *cfg, const char *name, @@ -607,6 +696,7 @@ int git_config_file__ondisk(git_config_backend **out, const char *path) backend->parent.open = config_open; backend->parent.get = config_get; backend->parent.get_multivar_foreach = config_get_multivar_foreach; + backend->parent.get_multivar = config_get_multivar; backend->parent.set = config_set; backend->parent.set_multivar = config_set_multivar; backend->parent.del = config_delete;