Unverified Commit 5d346c11 by Edward Thomson Committed by GitHub

Merge pull request #4525 from pks-t/pks/config-iterate-in-order

Configuration entry iteration in order
parents 2b967226 6a15f657
...@@ -64,6 +64,7 @@ typedef enum { ...@@ -64,6 +64,7 @@ typedef enum {
typedef struct git_config_entry { typedef struct git_config_entry {
const char *name; /**< Name of the entry (normalised) */ const char *name; /**< Name of the entry (normalised) */
const char *value; /**< String value of the entry */ const char *value; /**< String value of the entry */
unsigned int include_depth; /**< Depth of includes where this variable was found */
git_config_level_t level; /**< Which config file this was found in */ git_config_level_t level; /**< Which config file this was found in */
void (*free)(struct git_config_entry *entry); /**< Free function for this entry */ void (*free)(struct git_config_entry *entry); /**< Free function for this entry */
void *payload; /**< Opaque value for the free function. Do not read or write */ void *payload; /**< Opaque value for the free function. Do not read or write */
......
...@@ -23,69 +23,30 @@ ...@@ -23,69 +23,30 @@
#include <sys/types.h> #include <sys/types.h>
#include <regex.h> #include <regex.h>
typedef struct cvar_t { typedef struct config_entry_list {
struct cvar_t *next; struct config_entry_list *next;
git_config_entry *entry; git_config_entry *entry;
bool included; /* whether this is part of [include] */ } config_entry_list;
} cvar_t;
typedef struct git_config_file_iter { typedef struct git_config_file_iter {
git_config_iterator parent; git_config_iterator parent;
git_strmap_iter iter; config_entry_list *head;
cvar_t* next_var;
} git_config_file_iter; } git_config_file_iter;
/* Max depth for [include] directives */ /* Max depth for [include] directives */
#define MAX_INCLUDE_DEPTH 10 #define MAX_INCLUDE_DEPTH 10
#define CVAR_LIST_HEAD(list) ((list)->head)
#define CVAR_LIST_TAIL(list) ((list)->tail)
#define CVAR_LIST_NEXT(var) ((var)->next)
#define CVAR_LIST_EMPTY(list) ((list)->head == NULL)
#define CVAR_LIST_APPEND(list, var) do {\
if (CVAR_LIST_EMPTY(list)) {\
CVAR_LIST_HEAD(list) = CVAR_LIST_TAIL(list) = var;\
} else {\
CVAR_LIST_NEXT(CVAR_LIST_TAIL(list)) = var;\
CVAR_LIST_TAIL(list) = var;\
}\
} while(0)
#define CVAR_LIST_REMOVE_HEAD(list) do {\
CVAR_LIST_HEAD(list) = CVAR_LIST_NEXT(CVAR_LIST_HEAD(list));\
} while(0)
#define CVAR_LIST_REMOVE_AFTER(var) do {\
CVAR_LIST_NEXT(var) = CVAR_LIST_NEXT(CVAR_LIST_NEXT(var));\
} while(0)
#define CVAR_LIST_FOREACH(list, iter)\
for ((iter) = CVAR_LIST_HEAD(list);\
(iter) != NULL;\
(iter) = CVAR_LIST_NEXT(iter))
/*
* Inspired by the FreeBSD functions
*/
#define CVAR_LIST_FOREACH_SAFE(start, iter, tmp)\
for ((iter) = CVAR_LIST_HEAD(vars);\
(iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\
(iter) = (tmp))
typedef struct { typedef struct {
git_atomic refcount; git_atomic refcount;
git_strmap *values; git_strmap *map;
} refcounted_strmap; config_entry_list *list;
} diskfile_entries;
typedef struct { typedef struct {
git_config_backend parent; git_config_backend parent;
/* mutex to coordinate accessing the values */ /* mutex to coordinate accessing the values */
git_mutex values_mutex; git_mutex values_mutex;
refcounted_strmap *values; diskfile_entries *entries;
const git_repository *repo; const git_repository *repo;
git_config_level_t level; git_config_level_t level;
} diskfile_header; } diskfile_header;
...@@ -108,7 +69,15 @@ typedef struct { ...@@ -108,7 +69,15 @@ typedef struct {
diskfile_backend *snapshot_from; diskfile_backend *snapshot_from;
} diskfile_readonly_backend; } diskfile_readonly_backend;
static int config_read(git_strmap *values, const git_repository *repo, git_config_file *file, git_config_level_t level, int depth); typedef struct {
const git_repository *repo;
const char *file_path;
diskfile_entries *entries;
git_config_level_t level;
unsigned int depth;
} diskfile_parse_state;
static int config_read(diskfile_entries *entries, const git_repository *repo, git_config_file *file, git_config_level_t level, int depth);
static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char *value); static int config_write(diskfile_backend *cfg, const char *orig_key, const char *key, const regex_t *preg, const char *value);
static char *escape_value(const char *ptr); static char *escape_value(const char *ptr);
...@@ -121,15 +90,20 @@ static int config_error_readonly(void) ...@@ -121,15 +90,20 @@ static int config_error_readonly(void)
return -1; return -1;
} }
static void cvar_free(cvar_t *var) static void config_entry_list_free(config_entry_list *list)
{ {
if (var == NULL) config_entry_list *next;
return;
git__free((char*)var->entry->name); while (list != NULL) {
git__free((char *)var->entry->value); next = list->next;
git__free(var->entry);
git__free(var); git__free((char*) list->entry->name);
git__free((char *) list->entry->value);
git__free(list->entry);
git__free(list);
list = next;
};
} }
int git_config_file_normalize_section(char *start, char *end) int git_config_file_normalize_section(char *start, char *end)
...@@ -155,57 +129,70 @@ int git_config_file_normalize_section(char *start, char *end) ...@@ -155,57 +129,70 @@ int git_config_file_normalize_section(char *start, char *end)
return 0; return 0;
} }
static void config_entry_list_append(config_entry_list **list, config_entry_list *entry)
{
config_entry_list *head = *list;
if (head) {
while (head->next != NULL)
head = head->next;
head->next = entry;
} else {
*list = entry;
}
}
/* Add or append the new config option */ /* Add or append the new config option */
static int append_entry(git_strmap *values, cvar_t *var) static int diskfile_entries_append(diskfile_entries *entries, git_config_entry *entry)
{ {
git_strmap_iter pos; git_strmap_iter pos;
cvar_t *existing; config_entry_list *existing, *var;
int error = 0; int error = 0;
pos = git_strmap_lookup_index(values, var->entry->name); var = git__calloc(1, sizeof(config_entry_list));
if (!git_strmap_valid_index(values, pos)) { GITERR_CHECK_ALLOC(var);
git_strmap_insert(values, var->entry->name, var, &error); var->entry = entry;
pos = git_strmap_lookup_index(entries->map, entry->name);
if (!git_strmap_valid_index(entries->map, pos)) {
git_strmap_insert(entries->map, entry->name, var, &error);
if (error > 0)
error = 0;
} else { } else {
existing = git_strmap_value_at(values, pos); existing = git_strmap_value_at(entries->map, pos);
while (existing->next != NULL) { config_entry_list_append(&existing, var);
existing = existing->next;
}
existing->next = var;
} }
if (error > 0) var = git__calloc(1, sizeof(config_entry_list));
error = 0; GITERR_CHECK_ALLOC(var);
var->entry = entry;
config_entry_list_append(&entries->list, var);
return error; return error;
} }
static void free_vars(git_strmap *values) static void diskfile_entries_free(diskfile_entries *entries)
{ {
cvar_t *var = NULL; config_entry_list *list = NULL, *next;
if (values == NULL) if (!entries)
return; return;
git_strmap_foreach_value(values, var, if (git_atomic_dec(&entries->refcount) != 0)
while (var != NULL) {
cvar_t *next = CVAR_LIST_NEXT(var);
cvar_free(var);
var = next;
});
git_strmap_free(values);
}
static void refcounted_strmap_free(refcounted_strmap *map)
{
if (!map)
return; return;
if (git_atomic_dec(&map->refcount) != 0) git_strmap_foreach_value(entries->map, list, config_entry_list_free(list));
return; git_strmap_free(entries->map);
list = entries->list;
while (list != NULL) {
next = list->next;
git__free(list);
list = next;
}
free_vars(map->values); git__free(entries);
git__free(map);
} }
/** /**
...@@ -213,37 +200,37 @@ static void refcounted_strmap_free(refcounted_strmap *map) ...@@ -213,37 +200,37 @@ static void refcounted_strmap_free(refcounted_strmap *map)
* refcount. This is its own function to make sure we use the mutex to * refcount. This is its own function to make sure we use the mutex to
* avoid the map pointer from changing under us. * avoid the map pointer from changing under us.
*/ */
static refcounted_strmap *refcounted_strmap_take(diskfile_header *h) static diskfile_entries *diskfile_entries_take(diskfile_header *h)
{ {
refcounted_strmap *map; diskfile_entries *entries;
if (git_mutex_lock(&h->values_mutex) < 0) { if (git_mutex_lock(&h->values_mutex) < 0) {
giterr_set(GITERR_OS, "failed to lock config backend"); giterr_set(GITERR_OS, "failed to lock config backend");
return NULL; return NULL;
} }
map = h->values; entries = h->entries;
git_atomic_inc(&map->refcount); git_atomic_inc(&entries->refcount);
git_mutex_unlock(&h->values_mutex); git_mutex_unlock(&h->values_mutex);
return map; return entries;
} }
static int refcounted_strmap_alloc(refcounted_strmap **out) static int diskfile_entries_alloc(diskfile_entries **out)
{ {
refcounted_strmap *map; diskfile_entries *entries;
int error; int error;
map = git__calloc(1, sizeof(refcounted_strmap)); entries = git__calloc(1, sizeof(diskfile_entries));
GITERR_CHECK_ALLOC(map); GITERR_CHECK_ALLOC(entries);
git_atomic_set(&map->refcount, 1); git_atomic_set(&entries->refcount, 1);
if ((error = git_strmap_alloc(&map->values)) < 0) if ((error = git_strmap_alloc(&entries->map)) < 0)
git__free(map); git__free(entries);
else else
*out = map; *out = entries;
return error; return error;
} }
...@@ -272,15 +259,15 @@ static int config_open(git_config_backend *cfg, git_config_level_t level, const ...@@ -272,15 +259,15 @@ static int config_open(git_config_backend *cfg, git_config_level_t level, const
b->header.level = level; b->header.level = level;
b->header.repo = repo; b->header.repo = repo;
if ((res = refcounted_strmap_alloc(&b->header.values)) < 0) if ((res = diskfile_entries_alloc(&b->header.entries)) < 0)
return res; return res;
if (!git_path_exists(b->file.path)) if (!git_path_exists(b->file.path))
return 0; return 0;
if (res < 0 || (res = config_read(b->header.values->values, repo, &b->file, level, 0)) < 0) { if (res < 0 || (res = config_read(b->header.entries, repo, &b->file, level, 0)) < 0) {
refcounted_strmap_free(b->header.values); diskfile_entries_free(b->header.entries);
b->header.values = NULL; b->header.entries = NULL;
} }
return res; return res;
...@@ -321,7 +308,7 @@ out: ...@@ -321,7 +308,7 @@ out:
static int config_refresh(git_config_backend *cfg) static int config_refresh(git_config_backend *cfg)
{ {
diskfile_backend *b = (diskfile_backend *)cfg; diskfile_backend *b = (diskfile_backend *)cfg;
refcounted_strmap *values = NULL, *tmp; diskfile_entries *entries = NULL, *tmp;
git_config_file *include; git_config_file *include;
int error, modified; int error, modified;
uint32_t i; uint32_t i;
...@@ -336,7 +323,7 @@ static int config_refresh(git_config_backend *cfg) ...@@ -336,7 +323,7 @@ static int config_refresh(git_config_backend *cfg)
if (!modified) if (!modified)
return 0; return 0;
if ((error = refcounted_strmap_alloc(&values)) < 0) if ((error = diskfile_entries_alloc(&entries)) < 0)
goto out; goto out;
/* Reparse the current configuration */ /* Reparse the current configuration */
...@@ -345,7 +332,7 @@ static int config_refresh(git_config_backend *cfg) ...@@ -345,7 +332,7 @@ static int config_refresh(git_config_backend *cfg)
} }
git_array_clear(b->file.includes); git_array_clear(b->file.includes);
if ((error = config_read(values->values, b->header.repo, &b->file, b->header.level, 0)) < 0) if ((error = config_read(entries, b->header.repo, &b->file, b->header.level, 0)) < 0)
goto out; goto out;
if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) { if ((error = git_mutex_lock(&b->header.values_mutex)) < 0) {
...@@ -353,14 +340,14 @@ static int config_refresh(git_config_backend *cfg) ...@@ -353,14 +340,14 @@ static int config_refresh(git_config_backend *cfg)
goto out; goto out;
} }
tmp = b->header.values; tmp = b->header.entries;
b->header.values = values; b->header.entries = entries;
values = tmp; entries = tmp;
git_mutex_unlock(&b->header.values_mutex); git_mutex_unlock(&b->header.values_mutex);
out: out:
refcounted_strmap_free(values); diskfile_entries_free(entries);
return (error == GIT_ENOTFOUND) ? 0 : error; return (error == GIT_ENOTFOUND) ? 0 : error;
} }
...@@ -373,7 +360,7 @@ static void backend_free(git_config_backend *_backend) ...@@ -373,7 +360,7 @@ static void backend_free(git_config_backend *_backend)
return; return;
config_file_clear(&backend->file); config_file_clear(&backend->file);
refcounted_strmap_free(backend->header.values); diskfile_entries_free(backend->header.entries);
git_mutex_free(&backend->header.values_mutex); git_mutex_free(&backend->header.values_mutex);
git__free(backend); git__free(backend);
} }
...@@ -390,24 +377,12 @@ static int config_iterator_next( ...@@ -390,24 +377,12 @@ static int config_iterator_next(
git_config_iterator *iter) git_config_iterator *iter)
{ {
git_config_file_iter *it = (git_config_file_iter *) iter; git_config_file_iter *it = (git_config_file_iter *) iter;
diskfile_header *h = (diskfile_header *) it->parent.backend;
git_strmap *values = h->values->values;
int err = 0;
cvar_t * var;
if (it->next_var == NULL) {
err = git_strmap_next((void**) &var, &(it->iter), values);
} else {
var = it->next_var;
}
if (err < 0) { if (!it->head)
it->next_var = NULL; return GIT_ITEROVER;
return err;
}
*entry = var->entry; *entry = it->head->entry;
it->next_var = CVAR_LIST_NEXT(var); it->head = it->head->next;
return 0; return 0;
} }
...@@ -433,15 +408,11 @@ static int config_iterator_new( ...@@ -433,15 +408,11 @@ static int config_iterator_new(
h = (diskfile_header *)snapshot; h = (diskfile_header *)snapshot;
/* strmap_begin() is currently a macro returning 0 */
GIT_UNUSED(h);
it->parent.backend = snapshot; it->parent.backend = snapshot;
it->iter = git_strmap_begin(h->values); it->head = h->entries->list;
it->next_var = NULL;
it->parent.next = config_iterator_next; it->parent.next = config_iterator_next;
it->parent.free = config_iterator_free; it->parent.free = config_iterator_free;
*iter = (git_config_iterator *) it; *iter = (git_config_iterator *) it;
return 0; return 0;
...@@ -450,8 +421,8 @@ static int config_iterator_new( ...@@ -450,8 +421,8 @@ static int config_iterator_new(
static int config_set(git_config_backend *cfg, const char *name, const char *value) static int config_set(git_config_backend *cfg, const char *name, const char *value)
{ {
diskfile_backend *b = (diskfile_backend *)cfg; diskfile_backend *b = (diskfile_backend *)cfg;
refcounted_strmap *map; diskfile_entries *entries;
git_strmap *values; git_strmap *entry_map;
char *key, *esc_value = NULL; char *key, *esc_value = NULL;
khiter_t pos; khiter_t pos;
int rval, ret; int rval, ret;
...@@ -459,17 +430,17 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val ...@@ -459,17 +430,17 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
if ((rval = git_config__normalize_name(name, &key)) < 0) if ((rval = git_config__normalize_name(name, &key)) < 0)
return rval; return rval;
if ((map = refcounted_strmap_take(&b->header)) == NULL) if ((entries = diskfile_entries_take(&b->header)) == NULL)
return -1; return -1;
values = map->values; entry_map = entries->map;
/* /*
* Try to find it in the existing values and update it if it * Try to find it in the existing values and update it if it
* only has one value. * only has one value.
*/ */
pos = git_strmap_lookup_index(values, key); pos = git_strmap_lookup_index(entry_map, key);
if (git_strmap_valid_index(values, pos)) { if (git_strmap_valid_index(entry_map, pos)) {
cvar_t *existing = git_strmap_value_at(values, pos); config_entry_list *existing = git_strmap_value_at(entry_map, pos);
if (existing->next != NULL) { if (existing->next != NULL) {
giterr_set(GITERR_CONFIG, "multivar incompatible with simple set"); giterr_set(GITERR_CONFIG, "multivar incompatible with simple set");
...@@ -477,7 +448,7 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val ...@@ -477,7 +448,7 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
goto out; goto out;
} }
if (existing->included) { if (existing->entry->include_depth) {
giterr_set(GITERR_CONFIG, "modifying included variable is not supported"); giterr_set(GITERR_CONFIG, "modifying included variable is not supported");
ret = -1; ret = -1;
goto out; goto out;
...@@ -505,17 +476,17 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val ...@@ -505,17 +476,17 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val
ret = config_refresh(cfg); ret = config_refresh(cfg);
out: out:
refcounted_strmap_free(map); diskfile_entries_free(entries);
git__free(esc_value); git__free(esc_value);
git__free(key); git__free(key);
return ret; return ret;
} }
/* release the map containing the entry as an equivalent to freeing it */ /* release the map containing the entry as an equivalent to freeing it */
static void release_map(git_config_entry *entry) static void free_diskfile_entry(git_config_entry *entry)
{ {
refcounted_strmap *map = (refcounted_strmap *) entry->payload; diskfile_entries *map = (diskfile_entries *) entry->payload;
refcounted_strmap_free(map); diskfile_entries_free(map);
} }
/* /*
...@@ -524,34 +495,34 @@ static void release_map(git_config_entry *entry) ...@@ -524,34 +495,34 @@ static void release_map(git_config_entry *entry)
static int config_get(git_config_backend *cfg, const char *key, git_config_entry **out) static int config_get(git_config_backend *cfg, const char *key, git_config_entry **out)
{ {
diskfile_header *h = (diskfile_header *)cfg; diskfile_header *h = (diskfile_header *)cfg;
refcounted_strmap *map; diskfile_entries *entries;
git_strmap *values; git_strmap *entry_map;
khiter_t pos; khiter_t pos;
cvar_t *var; config_entry_list *var;
int error = 0; int error = 0;
if (!h->parent.readonly && ((error = config_refresh(cfg)) < 0)) if (!h->parent.readonly && ((error = config_refresh(cfg)) < 0))
return error; return error;
if ((map = refcounted_strmap_take(h)) == NULL) if ((entries = diskfile_entries_take(h)) == NULL)
return -1; return -1;
values = map->values; entry_map = entries->map;
pos = git_strmap_lookup_index(values, key); pos = git_strmap_lookup_index(entry_map, key);
/* no error message; the config system will write one */ /* no error message; the config system will write one */
if (!git_strmap_valid_index(values, pos)) { if (!git_strmap_valid_index(entry_map, pos)) {
refcounted_strmap_free(map); diskfile_entries_free(entries);
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
var = git_strmap_value_at(values, pos); var = git_strmap_value_at(entry_map, pos);
while (var->next) while (var->next)
var = var->next; var = var->next;
*out = var->entry; *out = var->entry;
(*out)->free = release_map; (*out)->free = free_diskfile_entry;
(*out)->payload = map; (*out)->payload = entries;
return error; return error;
} }
...@@ -591,9 +562,10 @@ out: ...@@ -591,9 +562,10 @@ out:
static int config_delete(git_config_backend *cfg, const char *name) static int config_delete(git_config_backend *cfg, const char *name)
{ {
cvar_t *var; config_entry_list *var;
diskfile_backend *b = (diskfile_backend *)cfg; diskfile_backend *b = (diskfile_backend *)cfg;
refcounted_strmap *map; git_strmap *values; diskfile_entries *map;
git_strmap *entry_map;
char *key; char *key;
int result; int result;
khiter_t pos; khiter_t pos;
...@@ -601,23 +573,23 @@ static int config_delete(git_config_backend *cfg, const char *name) ...@@ -601,23 +573,23 @@ static int config_delete(git_config_backend *cfg, const char *name)
if ((result = git_config__normalize_name(name, &key)) < 0) if ((result = git_config__normalize_name(name, &key)) < 0)
return result; return result;
if ((map = refcounted_strmap_take(&b->header)) == NULL) if ((map = diskfile_entries_take(&b->header)) == NULL)
return -1; return -1;
values = b->header.values->values; entry_map = b->header.entries->map;
pos = git_strmap_lookup_index(values, key); pos = git_strmap_lookup_index(entry_map, key);
git__free(key); git__free(key);
if (!git_strmap_valid_index(values, pos)) { if (!git_strmap_valid_index(entry_map, pos)) {
refcounted_strmap_free(map); diskfile_entries_free(map);
giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name); giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name);
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
var = git_strmap_value_at(values, pos); var = git_strmap_value_at(entry_map, pos);
refcounted_strmap_free(map); diskfile_entries_free(map);
if (var->included) { if (var->entry->include_depth) {
giterr_set(GITERR_CONFIG, "cannot delete included variable"); giterr_set(GITERR_CONFIG, "cannot delete included variable");
return -1; return -1;
} }
...@@ -636,8 +608,8 @@ static int config_delete(git_config_backend *cfg, const char *name) ...@@ -636,8 +608,8 @@ static int config_delete(git_config_backend *cfg, const char *name)
static int config_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp) static int config_delete_multivar(git_config_backend *cfg, const char *name, const char *regexp)
{ {
diskfile_backend *b = (diskfile_backend *)cfg; diskfile_backend *b = (diskfile_backend *)cfg;
refcounted_strmap *map; diskfile_entries *map;
git_strmap *values; git_strmap *entry_map;
char *key; char *key;
regex_t preg; regex_t preg;
int result; int result;
...@@ -646,20 +618,20 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con ...@@ -646,20 +618,20 @@ static int config_delete_multivar(git_config_backend *cfg, const char *name, con
if ((result = git_config__normalize_name(name, &key)) < 0) if ((result = git_config__normalize_name(name, &key)) < 0)
return result; return result;
if ((map = refcounted_strmap_take(&b->header)) == NULL) if ((map = diskfile_entries_take(&b->header)) == NULL)
return -1; return -1;
values = b->header.values->values; entry_map = b->header.entries->map;
pos = git_strmap_lookup_index(values, key); pos = git_strmap_lookup_index(entry_map, key);
if (!git_strmap_valid_index(values, pos)) { if (!git_strmap_valid_index(entry_map, pos)) {
refcounted_strmap_free(map); diskfile_entries_free(map);
git__free(key); git__free(key);
giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name); giterr_set(GITERR_CONFIG, "could not find key '%s' to delete", name);
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
refcounted_strmap_free(map); diskfile_entries_free(map);
result = p_regcomp(&preg, regexp, REG_EXTENDED); result = p_regcomp(&preg, regexp, REG_EXTENDED);
if (result != 0) { if (result != 0) {
...@@ -812,7 +784,7 @@ static void backend_readonly_free(git_config_backend *_backend) ...@@ -812,7 +784,7 @@ static void backend_readonly_free(git_config_backend *_backend)
if (backend == NULL) if (backend == NULL)
return; return;
refcounted_strmap_free(backend->header.values); diskfile_entries_free(backend->header.entries);
git_mutex_free(&backend->header.values_mutex); git_mutex_free(&backend->header.values_mutex);
git__free(backend); git__free(backend);
} }
...@@ -822,7 +794,7 @@ static int config_readonly_open(git_config_backend *cfg, git_config_level_t leve ...@@ -822,7 +794,7 @@ static int config_readonly_open(git_config_backend *cfg, git_config_level_t leve
diskfile_readonly_backend *b = (diskfile_readonly_backend *) cfg; diskfile_readonly_backend *b = (diskfile_readonly_backend *) cfg;
diskfile_backend *src = b->snapshot_from; diskfile_backend *src = b->snapshot_from;
diskfile_header *src_header = &src->header; diskfile_header *src_header = &src->header;
refcounted_strmap *src_map; diskfile_entries *entries;
int error; int error;
if (!src_header->parent.readonly && (error = config_refresh(&src_header->parent)) < 0) if (!src_header->parent.readonly && (error = config_refresh(&src_header->parent)) < 0)
...@@ -832,9 +804,9 @@ static int config_readonly_open(git_config_backend *cfg, git_config_level_t leve ...@@ -832,9 +804,9 @@ static int config_readonly_open(git_config_backend *cfg, git_config_level_t leve
GIT_UNUSED(level); GIT_UNUSED(level);
GIT_UNUSED(repo); GIT_UNUSED(repo);
if ((src_map = refcounted_strmap_take(src_header)) == NULL) if ((entries = diskfile_entries_take(src_header)) == NULL)
return -1; return -1;
b->header.values = src_map; b->header.entries = entries;
return 0; return 0;
} }
...@@ -912,16 +884,8 @@ static char *escape_value(const char *ptr) ...@@ -912,16 +884,8 @@ static char *escape_value(const char *ptr)
return git_buf_detach(&buf); return git_buf_detach(&buf);
} }
struct parse_data {
const git_repository *repo;
const char *file_path;
git_strmap *values;
git_config_level_t level;
int depth;
};
static int parse_include(git_config_parser *reader, static int parse_include(git_config_parser *reader,
struct parse_data *parse_data, const char *file) diskfile_parse_state *parse_data, const char *file)
{ {
struct config_file *include; struct config_file *include;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
...@@ -943,7 +907,7 @@ static int parse_include(git_config_parser *reader, ...@@ -943,7 +907,7 @@ static int parse_include(git_config_parser *reader,
git_array_init(include->includes); git_array_init(include->includes);
include->path = git_buf_detach(&path); include->path = git_buf_detach(&path);
result = config_read(parse_data->values, parse_data->repo, result = config_read(parse_data->entries, parse_data->repo,
include, parse_data->level, parse_data->depth+1); include, parse_data->level, parse_data->depth+1);
if (result == GIT_ENOTFOUND) { if (result == GIT_ENOTFOUND) {
...@@ -1023,7 +987,7 @@ static const struct { ...@@ -1023,7 +987,7 @@ static const struct {
}; };
static int parse_conditional_include(git_config_parser *reader, static int parse_conditional_include(git_config_parser *reader,
struct parse_data *parse_data, const char *section, const char *file) diskfile_parse_state *parse_data, const char *section, const char *file)
{ {
char *condition; char *condition;
size_t i; size_t i;
...@@ -1064,9 +1028,9 @@ static int read_on_variable( ...@@ -1064,9 +1028,9 @@ static int read_on_variable(
size_t line_len, size_t line_len,
void *data) void *data)
{ {
struct parse_data *parse_data = (struct parse_data *)data; diskfile_parse_state *parse_data = (diskfile_parse_state *)data;
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
cvar_t *var; git_config_entry *entry;
int result = 0; int result = 0;
GIT_UNUSED(line); GIT_UNUSED(line);
...@@ -1081,41 +1045,38 @@ static int read_on_variable( ...@@ -1081,41 +1045,38 @@ static int read_on_variable(
return -1; return -1;
} }
var = git__calloc(1, sizeof(cvar_t)); entry = git__calloc(1, sizeof(git_config_entry));
GITERR_CHECK_ALLOC(var); GITERR_CHECK_ALLOC(entry);
var->entry = git__calloc(1, sizeof(git_config_entry)); entry->name = git_buf_detach(&buf);
GITERR_CHECK_ALLOC(var->entry); entry->value = var_value;
entry->level = parse_data->level;
var->entry->name = git_buf_detach(&buf); entry->include_depth = parse_data->depth;
var->entry->value = var_value;
var->entry->level = parse_data->level;
var->included = !!parse_data->depth;
if ((result = append_entry(parse_data->values, var)) < 0) if ((result = diskfile_entries_append(parse_data->entries, entry)) < 0)
return result; return result;
result = 0; result = 0;
/* Add or append the new config option */ /* Add or append the new config option */
if (!git__strcmp(var->entry->name, "include.path")) if (!git__strcmp(entry->name, "include.path"))
result = parse_include(reader, parse_data, var->entry->value); result = parse_include(reader, parse_data, entry->value);
else if (!git__prefixcmp(var->entry->name, "includeif.") && else if (!git__prefixcmp(entry->name, "includeif.") &&
!git__suffixcmp(var->entry->name, ".path")) !git__suffixcmp(entry->name, ".path"))
result = parse_conditional_include(reader, parse_data, result = parse_conditional_include(reader, parse_data,
var->entry->name, var->entry->value); entry->name, entry->value);
return result; return result;
} }
static int config_read( static int config_read(
git_strmap *values, diskfile_entries *entries,
const git_repository *repo, const git_repository *repo,
git_config_file *file, git_config_file *file,
git_config_level_t level, git_config_level_t level,
int depth) int depth)
{ {
struct parse_data parse_data; diskfile_parse_state parse_data;
git_config_parser reader; git_config_parser reader;
git_buf contents = GIT_BUF_INIT; git_buf contents = GIT_BUF_INIT;
int error; int error;
...@@ -1143,7 +1104,7 @@ static int config_read( ...@@ -1143,7 +1104,7 @@ static int config_read(
parse_data.repo = repo; parse_data.repo = repo;
parse_data.file_path = file->path; parse_data.file_path = file->path;
parse_data.values = values; parse_data.entries = entries;
parse_data.level = level; parse_data.level = level;
parse_data.depth = depth; parse_data.depth = depth;
......
...@@ -306,6 +306,15 @@ void test_config_read__foreach(void) ...@@ -306,6 +306,15 @@ void test_config_read__foreach(void)
void test_config_read__iterator(void) void test_config_read__iterator(void)
{ {
const char *keys[] = {
"core.dummy2",
"core.verylong",
"core.dummy",
"remote.ab.url",
"remote.abba.url",
"core.dummy2",
"core.global"
};
git_config *cfg; git_config *cfg;
git_config_iterator *iter; git_config_iterator *iter;
git_config_entry *entry; git_config_entry *entry;
...@@ -321,6 +330,7 @@ void test_config_read__iterator(void) ...@@ -321,6 +330,7 @@ void test_config_read__iterator(void)
cl_git_pass(git_config_iterator_new(&iter, cfg)); cl_git_pass(git_config_iterator_new(&iter, cfg));
while ((ret = git_config_next(&entry, iter)) == 0) { while ((ret = git_config_next(&entry, iter)) == 0) {
cl_assert_equal_s(entry->name, keys[count]);
count++; count++;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment