diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2013-08-14 00:45:05 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2013-08-14 00:45:05 +0200 |
commit | f4be8209afd3cc996667196a1e437aac21485691 (patch) | |
tree | 9501c07058c7a1b6b8cafc3208346e80274e46cb /src/config.c | |
parent | 43e5dda70249ede020a57f3888356a0dcb96da48 (diff) | |
download | libgit2-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.c | 123 |
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; |