mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-09 16:45:49 +00:00
Merge pull request #1772 from libgit2/config-iter
Configuration iterators redux
This commit is contained in:
commit
b8b22d774e
@ -61,6 +61,7 @@ typedef struct {
|
||||
} git_config_entry;
|
||||
|
||||
typedef int (*git_config_foreach_cb)(const git_config_entry *, void *);
|
||||
typedef struct git_config_iterator git_config_iterator;
|
||||
|
||||
typedef enum {
|
||||
GIT_CVAR_FALSE = 0,
|
||||
@ -327,7 +328,7 @@ GIT_EXTERN(int) git_config_get_bool(int *out, const git_config *cfg, const char
|
||||
GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, const char *name);
|
||||
|
||||
/**
|
||||
* Get each value of a multivar.
|
||||
* Get each value of a multivar in a foreach callback
|
||||
*
|
||||
* The callback will be called on each variable found
|
||||
*
|
||||
@ -338,7 +339,34 @@ GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, c
|
||||
* @param callback the function to be called on each value of the variable
|
||||
* @param payload opaque pointer to pass to the callback
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_multivar(const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb callback, void *payload);
|
||||
GIT_EXTERN(int) git_config_get_multivar_foreach(const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb callback, void *payload);
|
||||
|
||||
/**
|
||||
* Get each value of a multivar
|
||||
*
|
||||
* @param out pointer to store the iterator
|
||||
* @param cfg where to look for the variable
|
||||
* @param name the variable's name
|
||||
* @param regexp regular expression to filter which variables we're
|
||||
* interested in. Use NULL to indicate all
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp);
|
||||
|
||||
/**
|
||||
* Return the current entry and advance the iterator
|
||||
*
|
||||
* @param entry pointer to store the entry
|
||||
* @param iter the iterator
|
||||
* @return 0 or an error code. GIT_ITEROVER if the iteration has completed
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_next(git_config_entry **entry, git_config_iterator *iter);
|
||||
|
||||
/**
|
||||
* Free a config iterator
|
||||
*
|
||||
* @param iter the iterator to free
|
||||
*/
|
||||
GIT_EXTERN(void) git_config_iterator_free(git_config_iterator *iter);
|
||||
|
||||
/**
|
||||
* Set the value of an integer config variable in the config file
|
||||
@ -424,6 +452,29 @@ GIT_EXTERN(int) git_config_foreach(
|
||||
git_config_foreach_cb callback,
|
||||
void *payload);
|
||||
|
||||
/**
|
||||
* Iterate over all the config variables
|
||||
*
|
||||
* Use `git_config_next` to advance the iteration and
|
||||
* `git_config_iterator_free` when done.
|
||||
*
|
||||
* @param out pointer to store the iterator
|
||||
* @param cfg where to ge the variables from
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_iterator_new(git_config_iterator **out, const git_config *cfg);
|
||||
|
||||
/**
|
||||
* Iterate over all the config variables whose name matches a pattern
|
||||
*
|
||||
* Use `git_config_next` to advance the iteration and
|
||||
* `git_config_iterator_free` when done.
|
||||
*
|
||||
* @param out pointer to store the iterator
|
||||
* @param cfg where to ge the variables from
|
||||
* @param regexp regular expression to match the names
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp);
|
||||
|
||||
/**
|
||||
* Perform an operation on each config variable matching a regular expression.
|
||||
*
|
||||
@ -535,6 +586,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
|
||||
|
@ -20,6 +20,33 @@
|
||||
*/
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/**
|
||||
* Every iterator must have this struct as its first element, so the
|
||||
* API can talk to it. You'd define your iterator as
|
||||
*
|
||||
* struct my_iterator {
|
||||
* git_config_iterator parent;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* and assign `iter->parent.backend` to your `git_config_backend`.
|
||||
*/
|
||||
struct git_config_iterator {
|
||||
git_config_backend *backend;
|
||||
unsigned int flags;
|
||||
|
||||
/**
|
||||
* Return the current entry and advance the iterator. The
|
||||
* memory belongs to the library.
|
||||
*/
|
||||
int (*next)(git_config_entry **entry, git_config_iterator *iter);
|
||||
|
||||
/**
|
||||
* Free the iterator
|
||||
*/
|
||||
void (*free)(git_config_iterator *iter);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic backend that implements the interface to
|
||||
* access a configuration file
|
||||
@ -31,11 +58,10 @@ struct git_config_backend {
|
||||
/* Open means open the file/database and parse if necessary */
|
||||
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)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload);
|
||||
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)(git_config_iterator **, struct git_config_backend *);
|
||||
int (*refresh)(struct git_config_backend *);
|
||||
void (*free)(struct git_config_backend *);
|
||||
};
|
||||
|
394
src/config.c
394
src/config.c
@ -315,30 +315,241 @@ int git_config_refresh(git_config *cfg)
|
||||
* Loop over all the variables
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
git_config_iterator parent;
|
||||
git_config_iterator *current;
|
||||
const git_config *cfg;
|
||||
regex_t regex;
|
||||
int has_regex;
|
||||
size_t i;
|
||||
} all_iter;
|
||||
|
||||
static int find_next_backend(size_t *out, const git_config *cfg, size_t i)
|
||||
{
|
||||
file_internal *internal;
|
||||
|
||||
for (; i > 0; --i) {
|
||||
internal = git_vector_get(&cfg->files, i - 1);
|
||||
if (!internal || !internal->file)
|
||||
continue;
|
||||
|
||||
*out = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter)
|
||||
{
|
||||
all_iter *iter = (all_iter *) _iter;
|
||||
file_internal *internal;
|
||||
git_config_backend *backend;
|
||||
size_t i;
|
||||
int error = 0;
|
||||
|
||||
if (iter->current != NULL &&
|
||||
(error = iter->current->next(entry, iter->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(iter->current);
|
||||
|
||||
iter->current = NULL;
|
||||
error = backend->iterator(&iter->current, backend);
|
||||
if (error == GIT_ENOTFOUND)
|
||||
continue;
|
||||
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
error = iter->current->next(entry, iter->current);
|
||||
/* If this backend is empty, then keep going */
|
||||
if (error == GIT_ITEROVER)
|
||||
continue;
|
||||
|
||||
return error;
|
||||
|
||||
} while(1);
|
||||
|
||||
return GIT_ITEROVER;
|
||||
}
|
||||
|
||||
static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_iter)
|
||||
{
|
||||
int error;
|
||||
all_iter *iter = (all_iter *) _iter;
|
||||
|
||||
/*
|
||||
* We use the "normal" function to grab the next one across
|
||||
* backends and then apply the regex
|
||||
*/
|
||||
while ((error = all_iter_next(entry, _iter)) == 0) {
|
||||
/* skip non-matching keys if regexp was provided */
|
||||
if (regexec(&iter->regex, (*entry)->name, 0, NULL, 0) != 0)
|
||||
continue;
|
||||
|
||||
/* and simply return if we like the entry's name */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void all_iter_free(git_config_iterator *_iter)
|
||||
{
|
||||
all_iter *iter = (all_iter *) _iter;
|
||||
|
||||
if (iter->current)
|
||||
iter->current->free(iter->current);
|
||||
|
||||
git__free(iter);
|
||||
}
|
||||
|
||||
static void all_iter_glob_free(git_config_iterator *_iter)
|
||||
{
|
||||
all_iter *iter = (all_iter *) _iter;
|
||||
|
||||
regfree(&iter->regex);
|
||||
all_iter_free(_iter);
|
||||
}
|
||||
|
||||
int git_config_iterator_new(git_config_iterator **out, const git_config *cfg)
|
||||
{
|
||||
all_iter *iter;
|
||||
|
||||
iter = git__calloc(1, sizeof(all_iter));
|
||||
GITERR_CHECK_ALLOC(iter);
|
||||
|
||||
iter->parent.free = all_iter_free;
|
||||
iter->parent.next = all_iter_next;
|
||||
|
||||
iter->i = cfg->files.length;
|
||||
iter->cfg = cfg;
|
||||
|
||||
*out = (git_config_iterator *) iter;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp)
|
||||
{
|
||||
all_iter *iter;
|
||||
int result;
|
||||
|
||||
if (regexp == NULL)
|
||||
return git_config_iterator_new(out, cfg);
|
||||
|
||||
iter = git__calloc(1, sizeof(all_iter));
|
||||
GITERR_CHECK_ALLOC(iter);
|
||||
|
||||
if ((result = regcomp(&iter->regex, regexp, REG_EXTENDED)) < 0) {
|
||||
giterr_set_regex(&iter->regex, result);
|
||||
regfree(&iter->regex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iter->parent.next = all_iter_glob_next;
|
||||
iter->parent.free = all_iter_glob_free;
|
||||
iter->i = cfg->files.length;
|
||||
iter->cfg = cfg;
|
||||
|
||||
*out = (git_config_iterator *) iter;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_config_foreach(
|
||||
const git_config *cfg, git_config_foreach_cb cb, void *payload)
|
||||
{
|
||||
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_iterator* iter;
|
||||
regex_t regex;
|
||||
int result = 0;
|
||||
|
||||
if (regexp != NULL) {
|
||||
if ((result = regcomp(®ex, regexp, REG_EXTENDED)) < 0) {
|
||||
giterr_set_regex(®ex, result);
|
||||
regfree(®ex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((result = backend->iterator(&iter, backend)) < 0) {
|
||||
iter = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(!(iter->next(&entry, iter) < 0)) {
|
||||
/* skip non-matching keys if regexp was provided */
|
||||
if (regexp && regexec(®ex, 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(®ex);
|
||||
|
||||
iter->free(iter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int git_config_foreach_match(
|
||||
const git_config *cfg,
|
||||
const char *regexp,
|
||||
git_config_foreach_cb cb,
|
||||
void *payload)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t i;
|
||||
file_internal *internal;
|
||||
git_config_backend *file;
|
||||
int error;
|
||||
git_config_iterator *iter;
|
||||
git_config_entry *entry;
|
||||
|
||||
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);
|
||||
if ((error = git_config_iterator_glob_new(&iter, cfg, regexp)) < 0)
|
||||
return error;
|
||||
|
||||
while ((error = git_config_next(&entry, iter)) == 0) {
|
||||
if(cb(entry, payload)) {
|
||||
giterr_clear();
|
||||
error = GIT_EUSER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
git_config_iterator_free(iter);
|
||||
|
||||
if (error == GIT_ITEROVER)
|
||||
error = 0;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**************
|
||||
@ -528,32 +739,114 @@ int git_config_get_entry(const git_config_entry **out, const git_config *cfg, co
|
||||
return config_error_notfound(name);
|
||||
}
|
||||
|
||||
int git_config_get_multivar(
|
||||
int git_config_get_multivar_foreach(
|
||||
const git_config *cfg, const char *name, const char *regexp,
|
||||
git_config_foreach_cb cb, void *payload)
|
||||
{
|
||||
file_internal *internal;
|
||||
git_config_backend *file;
|
||||
int ret = GIT_ENOTFOUND, err;
|
||||
size_t i;
|
||||
int err, found;
|
||||
git_config_iterator *iter;
|
||||
git_config_entry *entry;
|
||||
|
||||
/*
|
||||
* This loop runs the "wrong" way 'round because we need to
|
||||
* look at every value from the most general to most specific
|
||||
*/
|
||||
for (i = cfg->files.length; i > 0; --i) {
|
||||
internal = git_vector_get(&cfg->files, i - 1);
|
||||
if (!internal || !internal->file)
|
||||
continue;
|
||||
file = internal->file;
|
||||
if ((err = git_config_multivar_iterator_new(&iter, cfg, name, regexp)) < 0)
|
||||
return err;
|
||||
|
||||
if (!(err = file->get_multivar(file, name, regexp, cb, payload)))
|
||||
ret = 0;
|
||||
else if (err != GIT_ENOTFOUND)
|
||||
return err;
|
||||
found = 0;
|
||||
while ((err = iter->next(&entry, iter)) == 0) {
|
||||
found = 1;
|
||||
if(cb(entry, payload)) {
|
||||
iter->free(iter);
|
||||
return GIT_EUSER;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret == GIT_ENOTFOUND) ? config_error_notfound(name) : 0;
|
||||
iter->free(iter);
|
||||
if (err == GIT_ITEROVER)
|
||||
err = 0;
|
||||
|
||||
if (found == 0 && err == 0)
|
||||
err = config_error_notfound(name);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
git_config_iterator parent;
|
||||
git_config_iterator *iter;
|
||||
char *name;
|
||||
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;
|
||||
int error = 0;
|
||||
|
||||
while ((error = iter->iter->next(entry, iter->iter)) == 0) {
|
||||
if (git__strcmp(iter->name, (*entry)->name))
|
||||
continue;
|
||||
|
||||
if (!iter->have_regex)
|
||||
return 0;
|
||||
|
||||
if (regexec(&iter->regex, (*entry)->value, 0, NULL, 0) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void multivar_iter_free(git_config_iterator *_iter)
|
||||
{
|
||||
multivar_iter *iter = (multivar_iter *) _iter;
|
||||
|
||||
iter->iter->free(iter->iter);
|
||||
|
||||
git__free(iter->name);
|
||||
regfree(&iter->regex);
|
||||
git__free(iter);
|
||||
}
|
||||
|
||||
int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp)
|
||||
{
|
||||
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);
|
||||
|
||||
if ((error = git_config__normalize_name(name, &iter->name)) < 0)
|
||||
goto on_error;
|
||||
|
||||
if (regexp != NULL) {
|
||||
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;
|
||||
|
||||
*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)
|
||||
@ -569,6 +862,16 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex
|
||||
return file->set_multivar(file, name, regexp, value);
|
||||
}
|
||||
|
||||
int git_config_next(git_config_entry **entry, git_config_iterator *iter)
|
||||
{
|
||||
return iter->next(entry, iter);
|
||||
}
|
||||
|
||||
void git_config_iterator_free(git_config_iterator *iter)
|
||||
{
|
||||
iter->free(iter);
|
||||
}
|
||||
|
||||
static int git_config__find_file_to_path(
|
||||
char *out, size_t outlen, int (*find)(git_buf *buf))
|
||||
{
|
||||
@ -812,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;
|
||||
|
@ -49,4 +49,7 @@ extern int git_config_rename_section(
|
||||
*/
|
||||
extern int git_config_file__ondisk(struct git_config_backend **out, const char *path);
|
||||
|
||||
extern int git_config__normalize_name(const char *in, char **out);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -27,6 +27,13 @@ typedef struct cvar_t {
|
||||
git_config_entry *entry;
|
||||
} cvar_t;
|
||||
|
||||
typedef struct git_config_file_iter {
|
||||
git_config_iterator parent;
|
||||
git_strmap_iter iter;
|
||||
cvar_t* next_var;
|
||||
} git_config_file_iter;
|
||||
|
||||
|
||||
#define CVAR_LIST_HEAD(list) ((list)->head)
|
||||
|
||||
#define CVAR_LIST_TAIL(list) ((list)->tail)
|
||||
@ -129,41 +136,6 @@ int git_config_file_normalize_section(char *start, char *end)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Take something the user gave us and make it nice for our hash function */
|
||||
static int 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;
|
||||
}
|
||||
|
||||
static void free_vars(git_strmap *values)
|
||||
{
|
||||
cvar_t *var = NULL;
|
||||
@ -247,51 +219,56 @@ 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 void config_iterator_free(
|
||||
git_config_iterator* iter)
|
||||
{
|
||||
diskfile_backend *b = (diskfile_backend *)backend;
|
||||
cvar_t *var, *next_var;
|
||||
const char *key;
|
||||
regex_t regex;
|
||||
int result = 0;
|
||||
git__free(iter);
|
||||
}
|
||||
|
||||
if (!b->values)
|
||||
return 0;
|
||||
static int config_iterator_next(
|
||||
git_config_entry **entry,
|
||||
git_config_iterator *iter)
|
||||
{
|
||||
git_config_file_iter *it = (git_config_file_iter *) iter;
|
||||
diskfile_backend *b = (diskfile_backend *) it->parent.backend;
|
||||
int err = 0;
|
||||
cvar_t * var;
|
||||
|
||||
if (regexp != NULL) {
|
||||
if ((result = regcomp(®ex, regexp, REG_EXTENDED)) < 0) {
|
||||
giterr_set_regex(®ex, result);
|
||||
regfree(®ex);
|
||||
return -1;
|
||||
}
|
||||
if (it->next_var == NULL) {
|
||||
err = git_strmap_next((void**) &var, &(it->iter), b->values);
|
||||
} else {
|
||||
var = it->next_var;
|
||||
}
|
||||
|
||||
git_strmap_foreach(b->values, key, var,
|
||||
for (; var != NULL; var = next_var) {
|
||||
next_var = CVAR_LIST_NEXT(var);
|
||||
if (err < 0) {
|
||||
it->next_var = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* skip non-matching keys if regexp was provided */
|
||||
if (regexp && regexec(®ex, key, 0, NULL, 0) != 0)
|
||||
continue;
|
||||
*entry = var->entry;
|
||||
it->next_var = CVAR_LIST_NEXT(var);
|
||||
|
||||
/* abort iterator on non-zero return value */
|
||||
if (fn(var->entry, data)) {
|
||||
giterr_clear();
|
||||
result = GIT_EUSER;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (regexp != NULL)
|
||||
regfree(®ex);
|
||||
static int config_iterator_new(
|
||||
git_config_iterator **iter,
|
||||
struct git_config_backend* backend)
|
||||
{
|
||||
diskfile_backend *b = (diskfile_backend *)backend;
|
||||
git_config_file_iter *it = git__calloc(1, sizeof(git_config_file_iter));
|
||||
|
||||
return result;
|
||||
GITERR_CHECK_ALLOC(it);
|
||||
|
||||
it->parent.backend = backend;
|
||||
it->iter = git_strmap_begin(b->values);
|
||||
it->next_var = NULL;
|
||||
|
||||
it->parent.next = config_iterator_next;
|
||||
it->parent.free = config_iterator_free;
|
||||
*iter = (git_config_iterator *) it;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_set(git_config_backend *cfg, const char *name, const char *value)
|
||||
@ -302,7 +279,7 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
|
||||
khiter_t pos;
|
||||
int rval, ret;
|
||||
|
||||
if ((rval = normalize_name(name, &key)) < 0)
|
||||
if ((rval = git_config__normalize_name(name, &key)) < 0)
|
||||
return rval;
|
||||
|
||||
/*
|
||||
@ -385,7 +362,7 @@ static int config_get(const git_config_backend *cfg, const char *name, const git
|
||||
khiter_t pos;
|
||||
int error;
|
||||
|
||||
if ((error = normalize_name(name, &key)) < 0)
|
||||
if ((error = git_config__normalize_name(name, &key)) < 0)
|
||||
return error;
|
||||
|
||||
pos = git_strmap_lookup_index(b->values, key);
|
||||
@ -400,70 +377,6 @@ static int config_get(const git_config_backend *cfg, const char *name, const git
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_get_multivar(
|
||||
git_config_backend *cfg,
|
||||
const char *name,
|
||||
const char *regex_str,
|
||||
int (*fn)(const git_config_entry *, void *),
|
||||
void *data)
|
||||
{
|
||||
cvar_t *var;
|
||||
diskfile_backend *b = (diskfile_backend *)cfg;
|
||||
char *key;
|
||||
khiter_t pos;
|
||||
int error;
|
||||
|
||||
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;
|
||||
|
||||
var = git_strmap_value_at(b->values, pos);
|
||||
|
||||
if (regex_str != NULL) {
|
||||
regex_t regex;
|
||||
int result;
|
||||
|
||||
/* regex matching; build the regex */
|
||||
result = regcomp(®ex, regex_str, REG_EXTENDED);
|
||||
if (result < 0) {
|
||||
giterr_set_regex(®ex, result);
|
||||
regfree(®ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* and throw the callback only on the variables that
|
||||
* match the regex */
|
||||
do {
|
||||
if (regexec(®ex, var->entry->value, 0, NULL, 0) == 0) {
|
||||
/* early termination by the user is not an error;
|
||||
* just break and return successfully */
|
||||
if (fn(var->entry, data) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
var = var->next;
|
||||
} while (var != NULL);
|
||||
regfree(®ex);
|
||||
} else {
|
||||
/* no regex; go through all the variables */
|
||||
do {
|
||||
/* early termination by the user is not an error;
|
||||
* just break and return successfully */
|
||||
if (fn(var->entry, data) < 0)
|
||||
break;
|
||||
|
||||
var = var->next;
|
||||
} while (var != NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_set_multivar(
|
||||
git_config_backend *cfg, const char *name, const char *regexp, const char *value)
|
||||
{
|
||||
@ -477,7 +390,7 @@ static int config_set_multivar(
|
||||
|
||||
assert(regexp);
|
||||
|
||||
if ((result = normalize_name(name, &key)) < 0)
|
||||
if ((result = git_config__normalize_name(name, &key)) < 0)
|
||||
return result;
|
||||
|
||||
pos = git_strmap_lookup_index(b->values, key);
|
||||
@ -550,7 +463,7 @@ static int config_delete(git_config_backend *cfg, const char *name)
|
||||
int result;
|
||||
khiter_t pos;
|
||||
|
||||
if ((result = normalize_name(name, &key)) < 0)
|
||||
if ((result = git_config__normalize_name(name, &key)) < 0)
|
||||
return result;
|
||||
|
||||
pos = git_strmap_lookup_index(b->values, key);
|
||||
@ -590,11 +503,10 @@ 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 = config_get_multivar;
|
||||
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 = config_iterator_new;
|
||||
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);
|
||||
|
@ -187,7 +187,7 @@ static int git_diff_driver_load(
|
||||
|
||||
git_buf_truncate(&name, namelen + strlen("diff.."));
|
||||
git_buf_put(&name, "xfuncname", strlen("xfuncname"));
|
||||
if ((error = git_config_get_multivar(
|
||||
if ((error = git_config_get_multivar_foreach(
|
||||
cfg, name.ptr, NULL, diff_driver_xfuncname, drv)) < 0) {
|
||||
if (error != GIT_ENOTFOUND)
|
||||
goto done;
|
||||
@ -196,7 +196,7 @@ static int git_diff_driver_load(
|
||||
|
||||
git_buf_truncate(&name, namelen + strlen("diff.."));
|
||||
git_buf_put(&name, "funcname", strlen("funcname"));
|
||||
if ((error = git_config_get_multivar(
|
||||
if ((error = git_config_get_multivar_foreach(
|
||||
cfg, name.ptr, NULL, diff_driver_funcname, drv)) < 0) {
|
||||
if (error != GIT_ENOTFOUND)
|
||||
goto done;
|
||||
|
@ -242,7 +242,7 @@ static int get_optional_config(
|
||||
return -1;
|
||||
|
||||
if (cb != NULL)
|
||||
error = git_config_get_multivar(config, key, NULL, cb, payload);
|
||||
error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
|
||||
else
|
||||
error = git_config_get_string(payload, config, key);
|
||||
|
||||
|
32
src/strmap.c
Normal file
32
src/strmap.c
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
|
||||
#include "strmap.h"
|
||||
|
||||
int git_strmap_next(
|
||||
void **data,
|
||||
git_strmap_iter* iter,
|
||||
git_strmap *map)
|
||||
{
|
||||
if (!map)
|
||||
return GIT_ERROR;
|
||||
|
||||
while (*iter != git_strmap_end(map)) {
|
||||
if (!(git_strmap_has_data(map, *iter))) {
|
||||
++(*iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
*data = git_strmap_value_at(map, *iter);
|
||||
|
||||
++(*iter);
|
||||
|
||||
return GIT_OK;
|
||||
}
|
||||
|
||||
return GIT_ITEROVER;
|
||||
}
|
11
src/strmap.h
11
src/strmap.h
@ -17,6 +17,7 @@
|
||||
|
||||
__KHASH_TYPE(str, const char *, void *);
|
||||
typedef khash_t(str) git_strmap;
|
||||
typedef khiter_t git_strmap_iter;
|
||||
|
||||
#define GIT__USE_STRMAP \
|
||||
__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal)
|
||||
@ -31,7 +32,9 @@ typedef khash_t(str) git_strmap;
|
||||
#define git_strmap_valid_index(h, idx) (idx != kh_end(h))
|
||||
|
||||
#define git_strmap_exists(h, k) (kh_get(str, h, k) != kh_end(h))
|
||||
#define git_strmap_has_data(h, idx) kh_exist(h, idx)
|
||||
|
||||
#define git_strmap_key(h, idx) kh_key(h, idx)
|
||||
#define git_strmap_value_at(h, idx) kh_val(h, idx)
|
||||
#define git_strmap_set_value_at(h, idx, v) kh_val(h, idx) = v
|
||||
#define git_strmap_delete_at(h, idx) kh_del(str, h, idx)
|
||||
@ -61,4 +64,12 @@ typedef khash_t(str) git_strmap;
|
||||
#define git_strmap_foreach kh_foreach
|
||||
#define git_strmap_foreach_value kh_foreach_value
|
||||
|
||||
#define git_strmap_begin kh_begin
|
||||
#define git_strmap_end kh_end
|
||||
|
||||
int git_strmap_next(
|
||||
void **data,
|
||||
git_strmap_iter* iter,
|
||||
git_strmap *map);
|
||||
|
||||
#endif
|
||||
|
@ -46,60 +46,78 @@ static int cb(const git_config_entry *entry, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void check_get_multivar(
|
||||
static void check_get_multivar_foreach(
|
||||
git_config *cfg, int expected, int expected_patterned)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (expected > 0) {
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n));
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
|
||||
cl_assert_equal_i(expected, n);
|
||||
} else {
|
||||
cl_assert_equal_i(GIT_ENOTFOUND,
|
||||
git_config_get_multivar(cfg, _name, NULL, cb, &n));
|
||||
git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
if (expected_patterned > 0) {
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, "example", cb, &n));
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "example", cb, &n));
|
||||
cl_assert_equal_i(expected_patterned, n);
|
||||
} else {
|
||||
cl_assert_equal_i(GIT_ENOTFOUND,
|
||||
git_config_get_multivar(cfg, _name, "example", cb, &n));
|
||||
git_config_get_multivar_foreach(cfg, _name, "example", cb, &n));
|
||||
}
|
||||
}
|
||||
|
||||
static void check_get_multivar(git_config *cfg, int expected)
|
||||
{
|
||||
git_config_iterator *iter;
|
||||
git_config_entry *entry;
|
||||
int n = 0;
|
||||
|
||||
cl_git_pass(git_config_multivar_iterator_new(&iter, cfg, _name, NULL));
|
||||
|
||||
while (git_config_next(&entry, iter) == 0)
|
||||
n++;
|
||||
|
||||
cl_assert_equal_i(expected, n);
|
||||
git_config_iterator_free(iter);
|
||||
|
||||
}
|
||||
|
||||
void test_config_multivar__get(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
|
||||
check_get_multivar(cfg, 2, 1);
|
||||
check_get_multivar_foreach(cfg, 2, 1);
|
||||
|
||||
/* add another that has the _name entry */
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config9", GIT_CONFIG_LEVEL_SYSTEM, 1));
|
||||
check_get_multivar(cfg, 3, 2);
|
||||
check_get_multivar_foreach(cfg, 3, 2);
|
||||
|
||||
/* add another that does not have the _name entry */
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config0", GIT_CONFIG_LEVEL_GLOBAL, 1));
|
||||
check_get_multivar(cfg, 3, 2);
|
||||
check_get_multivar_foreach(cfg, 3, 2);
|
||||
|
||||
/* add another that does not have the _name entry at the end */
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config1", GIT_CONFIG_LEVEL_APP, 1));
|
||||
check_get_multivar(cfg, 3, 2);
|
||||
check_get_multivar_foreach(cfg, 3, 2);
|
||||
|
||||
/* drop original file */
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config2", GIT_CONFIG_LEVEL_LOCAL, 1));
|
||||
check_get_multivar(cfg, 1, 1);
|
||||
check_get_multivar_foreach(cfg, 1, 1);
|
||||
|
||||
/* drop other file with match */
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config3", GIT_CONFIG_LEVEL_SYSTEM, 1));
|
||||
check_get_multivar(cfg, 0, 0);
|
||||
check_get_multivar_foreach(cfg, 0, 0);
|
||||
|
||||
/* reload original file (add different place in order) */
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config11", GIT_CONFIG_LEVEL_SYSTEM, 1));
|
||||
check_get_multivar(cfg, 2, 1);
|
||||
check_get_multivar_foreach(cfg, 2, 1);
|
||||
|
||||
check_get_multivar(cfg, 2);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
@ -113,12 +131,12 @@ void test_config_multivar__add(void)
|
||||
cl_git_pass(git_config_set_multivar(cfg, _name, "nonexistant", "git://git.otherplace.org/libgit2"));
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n));
|
||||
cl_assert(n == 3);
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
|
||||
cl_assert_equal_i(n, 3);
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert(n == 1);
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert_equal_i(n, 1);
|
||||
|
||||
git_config_free(cfg);
|
||||
|
||||
@ -127,12 +145,12 @@ void test_config_multivar__add(void)
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n));
|
||||
cl_assert(n == 3);
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
|
||||
cl_assert_equal_i(n, 3);
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert(n == 1);
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert_equal_i(n, 1);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
@ -147,8 +165,8 @@ void test_config_multivar__add_new(void)
|
||||
|
||||
cl_git_pass(git_config_set_multivar(cfg, var, "", "variable"));
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, var, NULL, cb, &n));
|
||||
cl_assert(n == 1);
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, var, NULL, cb, &n));
|
||||
cl_assert_equal_i(n, 1);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
@ -161,13 +179,13 @@ void test_config_multivar__replace(void)
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n));
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
|
||||
cl_assert(n == 2);
|
||||
|
||||
cl_git_pass(git_config_set_multivar(cfg, _name, "github", "git://git.otherplace.org/libgit2"));
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n));
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
|
||||
cl_assert(n == 2);
|
||||
|
||||
git_config_free(cfg);
|
||||
@ -175,7 +193,7 @@ void test_config_multivar__replace(void)
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, NULL, cb, &n));
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
|
||||
cl_assert(n == 2);
|
||||
|
||||
git_config_free(cfg);
|
||||
@ -190,16 +208,16 @@ void test_config_multivar__replace_multiple(void)
|
||||
cl_git_pass(git_config_set_multivar(cfg, _name, "git://", "git://git.otherplace.org/libgit2"));
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert(n == 2);
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert_equal_i(n, 2);
|
||||
|
||||
git_config_free(cfg);
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
|
||||
|
||||
n = 0;
|
||||
cl_git_pass(git_config_get_multivar(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert(n == 2);
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
|
||||
cl_assert_equal_i(n, 2);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
@ -245,6 +245,37 @@ void test_config_read__foreach(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_read__iterator(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
git_config_iterator *iter;
|
||||
git_config_entry *entry;
|
||||
int count, ret;
|
||||
|
||||
cl_git_pass(git_config_new(&cfg));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
|
||||
GIT_CONFIG_LEVEL_SYSTEM, 0));
|
||||
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
|
||||
GIT_CONFIG_LEVEL_GLOBAL, 0));
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(git_config_iterator_new(&iter, cfg));
|
||||
|
||||
while ((ret = git_config_next(&entry, iter)) == 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
git_config_iterator_free(iter);
|
||||
cl_assert_equal_i(GIT_ITEROVER, ret);
|
||||
cl_assert_equal_i(7, count);
|
||||
|
||||
count = 3;
|
||||
cl_git_pass(git_config_iterator_new(&iter, cfg));
|
||||
|
||||
git_config_iterator_free(iter);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static int count_cfg_entries(const git_config_entry *entry, void *payload)
|
||||
{
|
||||
int *count = payload;
|
||||
@ -288,6 +319,38 @@ void test_config_read__foreach_match(void)
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
static void check_glob_iter(git_config *cfg, const char *regexp, int expected)
|
||||
{
|
||||
git_config_iterator *iter;
|
||||
git_config_entry *entry;
|
||||
int count, error;
|
||||
|
||||
cl_git_pass(git_config_iterator_glob_new(&iter, cfg, regexp));
|
||||
|
||||
count = 0;
|
||||
while ((error = git_config_next(&entry, iter)) == 0)
|
||||
count++;
|
||||
|
||||
cl_assert_equal_i(GIT_ITEROVER, error);
|
||||
cl_assert_equal_i(expected, count);
|
||||
git_config_iterator_free(iter);
|
||||
}
|
||||
|
||||
void test_config_read__iterator_glob(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
|
||||
|
||||
check_glob_iter(cfg, "core.*", 3);
|
||||
check_glob_iter(cfg, "remote\\.ab.*", 2);
|
||||
check_glob_iter(cfg, ".*url$", 2);
|
||||
check_glob_iter(cfg, ".*dummy.*", 2);
|
||||
check_glob_iter(cfg, ".*nomatch.*", 0);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_config_read__whitespace_not_required_around_assignment(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
@ -28,7 +28,7 @@ static void assert_invalid_config_key_name(const char *name)
|
||||
GIT_EINVALIDSPEC);
|
||||
cl_git_fail_with(git_config_delete_entry(cfg, name),
|
||||
GIT_EINVALIDSPEC);
|
||||
cl_git_fail_with(git_config_get_multivar(cfg, name, "*", NULL, NULL),
|
||||
cl_git_fail_with(git_config_get_multivar_foreach(cfg, name, "*", NULL, NULL),
|
||||
GIT_EINVALIDSPEC);
|
||||
cl_git_fail_with(git_config_set_multivar(cfg, name, "*", "42"),
|
||||
GIT_EINVALIDSPEC);
|
||||
|
Loading…
Reference in New Issue
Block a user