diff --git a/src/config.c b/src/config.c index 41db3c5ca..d537fd8a5 100644 --- a/src/config.c +++ b/src/config.c @@ -48,11 +48,15 @@ static git_cvar *cvar_free(git_cvar *var) return next; } -static void cvar_list_free(git_cvar *start) +static void cvar_list_free(git_cvar_list *list) { - git_cvar *iter = start; + git_cvar *cur; - while ((iter = cvar_free(iter)) != NULL); + while (!CVAR_LIST_EMPTY(list)) { + cur = CVAR_LIST_HEAD(list); + CVAR_LIST_REMOVE_HEAD(list); + cvar_free(cur); + } } /* @@ -112,11 +116,11 @@ static int cvar_name_match(const char *local, const char *input) return !strcasecmp(input_dot, local_dot); } -static git_cvar *cvar_list_find(git_cvar *start, const char *name) +static git_cvar *cvar_list_find(git_cvar_list *list, const char *name) { git_cvar *iter; - CVAR_LIST_FOREACH (start, iter) { + CVAR_LIST_FOREACH (list, iter) { if (cvar_name_match(iter->name, name)) return iter; } @@ -205,8 +209,7 @@ int git_config_open(git_config **cfg_out, const char *path) return error; cleanup: - if (cfg->vars) - cvar_list_free(cfg->vars); + cvar_list_free(&cfg->var_list); if (cfg->file_path) free(cfg->file_path); gitfo_free_buf(&cfg->reader.buffer); @@ -221,7 +224,7 @@ void git_config_free(git_config *cfg) return; free(cfg->file_path); - cvar_list_free(cfg->vars); + cvar_list_free(&cfg->var_list); free(cfg); } @@ -236,7 +239,7 @@ int git_config_foreach(git_config *cfg, int (*fn)(const char *, void *), void *d git_cvar *var; char *normalized; - CVAR_LIST_FOREACH(cfg->vars, var) { + CVAR_LIST_FOREACH(&cfg->var_list, var) { ret = cvar_name_normalize(var->name, &normalized); if (ret < GIT_SUCCESS) return ret; @@ -266,7 +269,7 @@ static int config_set(git_config *cfg, const char *name, const char *value) /* * If it already exists, we just need to update its value. */ - existing = cvar_list_find(cfg->vars, name); + existing = cvar_list_find(&cfg->var_list, name); if (existing != NULL) { char *tmp = value ? git__strdup(value) : NULL; if (tmp == NULL && value != NULL) @@ -304,13 +307,7 @@ static int config_set(git_config *cfg, const char *name, const char *value) var->next = NULL; - if (cfg->vars_tail == NULL) { - cfg->vars = cfg->vars_tail = var; - } - else { - cfg->vars_tail->next = var; - cfg->vars_tail = var; - } + CVAR_LIST_APPEND(&cfg->var_list, var); out: if (error < GIT_SUCCESS) @@ -369,7 +366,7 @@ static int config_get(git_config *cfg, const char *name, const char **out) git_cvar *var; int error = GIT_SUCCESS; - var = cvar_list_find(cfg->vars, name); + var = cvar_list_find(&cfg->var_list, name); if (var == NULL) return GIT_ENOTFOUND; diff --git a/src/config.h b/src/config.h index 1e954ff81..e54933d5f 100644 --- a/src/config.h +++ b/src/config.h @@ -3,9 +3,13 @@ #include "git2/config.h" +typedef struct { + git_cvar *head; + git_cvar *tail; +} git_cvar_list; + struct git_config { - git_cvar *vars; - git_cvar *vars_tail; + git_cvar_list var_list; struct { gitfo_buf buffer; @@ -23,12 +27,44 @@ struct git_cvar { char *value; }; +#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)) + /* - * If you're going to delete something inside this loop, it's such a - * hassle that you should use the for-loop directly. + * Inspired by the FreeBSD functions */ -#define CVAR_LIST_FOREACH(start, iter) \ - for ((iter) = (start); (iter) != NULL; (iter) = (iter)->next) +#define CVAR_LIST_FOREACH_SAFE(start, iter, tmp)\ + for ((iter) = CVAR_LIST_HEAD(vars);\ + (iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\ + (iter) = (tmp)) + void git__strtolower(char *str); void git__strntolower(char *str, int len);