summaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2013-08-14 00:45:05 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2013-08-14 00:45:05 +0200
commitf4be8209afd3cc996667196a1e437aac21485691 (patch)
tree9501c07058c7a1b6b8cafc3208346e80274e46cb /src/config.c
parent43e5dda70249ede020a57f3888356a0dcb96da48 (diff)
downloadlibgit2-f4be8209afd3cc996667196a1e437aac21485691.tar.gz
config: don't special-case the multivar iterator
Build it on top of the normal iterator instead, which lets use re-use a lot of code.
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c123
1 files changed, 74 insertions, 49 deletions
diff --git a/src/config.c b/src/config.c
index ae4e4816a..c98d6a52d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -747,7 +747,7 @@ int git_config_get_multivar_foreach(
git_config_iterator *iter;
git_config_entry *entry;
- if ((err = git_config_get_multivar(&iter, cfg, name, regexp)) < 0)
+ if ((err = git_config_multivar_iterator_new(&iter, cfg, name, regexp)) < 0)
return err;
found = 0;
@@ -771,92 +771,82 @@ int git_config_get_multivar_foreach(
typedef struct {
git_config_iterator parent;
- git_config_iterator *current;
+ git_config_iterator *iter;
char *name;
- char *regexp;
- const git_config *cfg;
- size_t i;
+ regex_t regex;
+ int have_regex;
} multivar_iter;
static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter)
{
multivar_iter *iter = (multivar_iter *) _iter;
- git_config_iterator *current = iter->current;
- file_internal *internal;
- git_config_backend *backend;
- size_t i;
int error = 0;
- if (current != NULL &&
- (error = current->next(entry, 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(current);
-
- iter->current = NULL;
- error = backend->get_multivar(&iter->current, backend, iter->name, iter->regexp);
- if (error == GIT_ENOTFOUND)
+ while ((error = iter->iter->next(entry, iter->iter)) == 0) {
+ if (git__strcmp(iter->name, (*entry)->name))
continue;
- if (error < 0)
- return error;
-
- return iter->current->next(entry, iter->current);
+ if (!iter->have_regex)
+ return 0;
- } while(1);
+ if (regexec(&iter->regex, (*entry)->value, 0, NULL, 0) == 0)
+ return 0;
+ }
- return GIT_ITEROVER;
+ return error;
}
void multivar_iter_free(git_config_iterator *_iter)
{
multivar_iter *iter = (multivar_iter *) _iter;
- if (iter->current)
- iter->current->free(iter->current);
+ iter->iter->free(iter->iter);
git__free(iter->name);
- git__free(iter->regexp);
+ regfree(&iter->regex);
git__free(iter);
}
-int git_config_get_multivar(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp)
+int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp)
{
- multivar_iter *iter;
+ multivar_iter *iter = NULL;
+ git_config_iterator *inner = NULL;
+ int error;
+
+ if ((error = git_config_iterator_new(&inner, cfg)) < 0)
+ return error;
iter = git__calloc(1, sizeof(multivar_iter));
GITERR_CHECK_ALLOC(iter);
- iter->name = git__strdup(name);
- GITERR_CHECK_ALLOC(iter->name);
+ if ((error = git_config__normalize_name(name, &iter->name)) < 0)
+ goto on_error;
if (regexp != NULL) {
- iter->regexp = git__strdup(regexp);
- GITERR_CHECK_ALLOC(iter->regexp);
+ error = regcomp(&iter->regex, regexp, REG_EXTENDED);
+ if (error < 0) {
+ giterr_set_regex(&iter->regex, error);
+ error = -1;
+ regfree(&iter->regex);
+ goto on_error;
+ }
+
+ iter->have_regex = 1;
}
+ iter->iter = inner;
iter->parent.free = multivar_iter_free;
iter->parent.next = multivar_iter_next;
- iter->i = cfg->files.length;
- iter->cfg = cfg;
-
*out = (git_config_iterator *) iter;
return 0;
+
+on_error:
+
+ inner->free(inner);
+ git__free(iter);
+ return error;
}
int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value)
@@ -1125,6 +1115,41 @@ fail_parse:
return -1;
}
+/* Take something the user gave us and make it nice for our hash function */
+int git_config__normalize_name(const char *in, char **out)
+{
+ char *name, *fdot, *ldot;
+
+ assert(in && out);
+
+ name = git__strdup(in);
+ GITERR_CHECK_ALLOC(name);
+
+ fdot = strchr(name, '.');
+ ldot = strrchr(name, '.');
+
+ if (fdot == NULL || fdot == name || ldot == NULL || !ldot[1])
+ goto invalid;
+
+ /* Validate and downcase up to first dot and after last dot */
+ if (git_config_file_normalize_section(name, fdot) < 0 ||
+ git_config_file_normalize_section(ldot + 1, NULL) < 0)
+ goto invalid;
+
+ /* If there is a middle range, make sure it doesn't have newlines */
+ while (fdot < ldot)
+ if (*fdot++ == '\n')
+ goto invalid;
+
+ *out = name;
+ return 0;
+
+invalid:
+ git__free(name);
+ giterr_set(GITERR_CONFIG, "Invalid config item name '%s'", in);
+ return GIT_EINVALIDSPEC;
+}
+
struct rename_data {
git_config *config;
git_buf *name;