diff --git a/include/git2/config.h b/include/git2/config.h index 9ae54f112..78a1f622a 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -37,6 +37,32 @@ */ GIT_BEGIN_DECL +/** + * Generic backend that implements the interface to + * access a configuration file + */ +struct git_config_file { + struct git_config *cfg; + + /* Open means open the file/database and parse if necessary */ + int (*open)(struct git_config_file *); + int (*get)(struct git_config_file *, const char *key, const char **value); + int (*set)(struct git_config_file *, const char *key, const char *value); + int (*foreach)(struct git_config_file *, int (*fn)(const char *, void *), void *data); + void (*free)(struct git_config_file *); +}; + +/** + * Create a configuration file backend for ondisk files + * + * These are the normal `.gitconfig` files that Core Git + * processes. + * + * @param out the new backend + * @path where the config file is located + */ +GIT_EXTERN(int) git_config_file__ondisk(struct git_config_file **out, const char *path); + /** * Allocate a new configuration */ @@ -48,7 +74,7 @@ GIT_EXTERN(int) git_config_new(git_config **out); * @param cfg_out pointer to the configuration data * @param path where to load the confiration from */ -GIT_EXTERN(int) git_config_open_bare(git_config **cfg_out, const char *path); +GIT_EXTERN(int) git_config_open_file(git_config **cfg_out, const char *path); /** * Open the global configuration file at $HOME/.gitconfig @@ -67,7 +93,7 @@ GIT_EXTERN(int) git_config_open_global(git_config **cfg); * @param backend the backend to add * @param priority the priority the backend should have */ -GIT_EXTERN(int) git_config_add_backend(git_config *cfg, git_config_backend *backend, int priority); +GIT_EXTERN(int) git_config_add_file(git_config *cfg, git_config_file *file, int priority); /** * Free the configuration and its associated memory diff --git a/include/git2/config_backend.h b/include/git2/config_backend.h deleted file mode 100644 index 427cd95dd..000000000 --- a/include/git2/config_backend.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * In addition to the permissions in the GNU General Public License, - * the authors give you unlimited permission to link the compiled - * version of this file into combinations with other programs, - * and to distribute those combinations without any restriction - * coming from the use of this file. (The General Public License - * restrictions do apply in other respects; for example, they cover - * modification of the file, and distribution when not linked into - * a combined executable.) - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDE_git_config_backend_h__ -#define INCLUDE_git_config_backend_h__ - -#include "common.h" -#include "types.h" -#include "config.h" - -GIT_BEGIN_DECL - -struct git_config; - -struct git_config_backend { - struct git_config *cfg; - /* Open means open the file/database and parse if necessary */ - int (*open)(struct git_config_backend *); - int (* get)(struct git_config_backend *, const char *key, const char **value); - int (* set)(struct git_config_backend *, const char *key, const char *value); - int (*foreach)(struct git_config_backend *, int (*fn)(const char *, void *), void *data); - void (*free)(struct git_config_backend *); -}; - -/** - * Create a file-backed configuration backend - * - * @param out the new backend - * @path where the config file is located - */ -GIT_EXTERN(int) git_config_backend_file(struct git_config_backend **out, const char *path); - -GIT_END_DECL - -#endif diff --git a/include/git2/types.h b/include/git2/types.h index ab7dc523e..b569e83c1 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -130,11 +130,11 @@ typedef struct git_treebuilder git_treebuilder; /** Memory representation of an index file. */ typedef struct git_index git_index; -/** Memory representation of a config file */ +/** Memory representation of a set of config files */ typedef struct git_config git_config; -/** A specific implementation of a config backend */ -typedef struct git_config_backend git_config_backend; +/** Interface to access a configuration file */ +typedef struct git_config_file git_config_file; /** Time in a signature */ typedef struct git_time { diff --git a/src/config.c b/src/config.c index 3b6c23b18..061eba606 100644 --- a/src/config.c +++ b/src/config.c @@ -27,47 +27,48 @@ #include "fileops.h" #include "hashtable.h" #include "config.h" -#include "git2/config_backend.h" +#include "git2/config.h" #include "vector.h" #include typedef struct { - git_config_backend *backend; + git_config_file *file; int priority; -} backend_internal; +} file_internal; -int git_config_open_bare(git_config **out, const char *path) +int git_config_open_file(git_config **out, const char *path) { - git_config_backend *backend = NULL; + git_config_file *file = NULL; git_config *cfg = NULL; int error = GIT_SUCCESS; error = git_config_new(&cfg); if (error < GIT_SUCCESS) - goto error; + return error; - error = git_config_backend_file(&backend, path); - if (error < GIT_SUCCESS) - goto error; + error = git_config_file__ondisk(&file, path); + if (error < GIT_SUCCESS) { + git_config_free(cfg); + return error; + } - error = git_config_add_backend(cfg, backend, 1); - if (error < GIT_SUCCESS) - goto error; + error = git_config_add_file(cfg, file, 1); + if (error < GIT_SUCCESS) { + file->free(file); + git_config_free(cfg); + return error; + } - error = backend->open(backend); - if (error < GIT_SUCCESS) - goto error; + error = file->open(file); + if (error < GIT_SUCCESS) { + git_config_free(cfg); + return git__rethrow(error, "Failed to open config file"); + } *out = cfg; - return error; - - error: - if(backend) - backend->free(backend); - - return error; + return GIT_SUCCESS; } int git_config_open_global(git_config **out) @@ -81,30 +82,30 @@ int git_config_open_global(git_config **out) git__joinpath(full_path, home, GIT_CONFIG_FILENAME); - return git_config_open_bare(out, filename); + return git_config_open_file(out, full_path); } void git_config_free(git_config *cfg) { unsigned int i; - git_config_backend *backend; - backend_internal *internal; + git_config_file *file; + file_internal *internal; - for(i = 0; i < cfg->backends.length; ++i){ - internal = git_vector_get(&cfg->backends, i); - backend = internal->backend; - backend->free(backend); + for(i = 0; i < cfg->files.length; ++i){ + internal = git_vector_get(&cfg->files, i); + file = internal->file; + file->free(file); free(internal); } - git_vector_free(&cfg->backends); + git_vector_free(&cfg->files); free(cfg); } static int config_backend_cmp(const void *a, const void *b) { - const backend_internal *bk_a = *(const backend_internal **)(a); - const backend_internal *bk_b = *(const backend_internal **)(b); + const file_internal *bk_a = *(const file_internal **)(a); + const file_internal *bk_b = *(const file_internal **)(b); return bk_b->priority - bk_a->priority; } @@ -119,7 +120,7 @@ int git_config_new(git_config **out) memset(cfg, 0x0, sizeof(git_config)); - if (git_vector_init(&cfg->backends, 3, config_backend_cmp) < 0) { + if (git_vector_init(&cfg->files, 3, config_backend_cmp) < 0) { free(cfg); return GIT_ENOMEM; } @@ -129,26 +130,26 @@ int git_config_new(git_config **out) return GIT_SUCCESS; } -int git_config_add_backend(git_config *cfg, git_config_backend *backend, int priority) +int git_config_add_file(git_config *cfg, git_config_file *file, int priority) { - backend_internal *internal; + file_internal *internal; - assert(cfg && backend); + assert(cfg && file); - internal = git__malloc(sizeof(backend_internal)); + internal = git__malloc(sizeof(file_internal)); if (internal == NULL) return GIT_ENOMEM; - internal->backend = backend; + internal->file = file; internal->priority = priority; - if (git_vector_insert(&cfg->backends, internal) < 0) { + if (git_vector_insert(&cfg->files, internal) < 0) { free(internal); return GIT_ENOMEM; } - git_vector_sort(&cfg->backends); - internal->backend->cfg = cfg; + git_vector_sort(&cfg->files); + internal->file->cfg = cfg; return GIT_SUCCESS; } @@ -161,13 +162,13 @@ int git_config_foreach(git_config *cfg, int (*fn)(const char *, void *), void *d { int ret = GIT_SUCCESS; unsigned int i; - backend_internal *internal; - git_config_backend *backend; + file_internal *internal; + git_config_file *file; - for(i = 0; i < cfg->backends.length && ret == 0; ++i) { - internal = git_vector_get(&cfg->backends, i); - backend = internal->backend; - ret = backend->foreach(backend, fn, data); + for(i = 0; i < cfg->files.length && ret == 0; ++i) { + internal = git_vector_get(&cfg->files, i); + file = internal->file; + ret = file->foreach(file, fn, data); } return ret; @@ -221,15 +222,16 @@ int git_config_set_bool(git_config *cfg, const char *name, int value) int git_config_set_string(git_config *cfg, const char *name, const char *value) { - backend_internal *internal; - git_config_backend *backend; + file_internal *internal; + git_config_file *file; - assert(cfg->backends.length > 0); + if (cfg->files.length == 0) + return git__throw(GIT_EINVALIDARGS, "Cannot set variable value; no files open in the `git_config` instance"); - internal = git_vector_get(&cfg->backends, 0); - backend = internal->backend; + internal = git_vector_get(&cfg->files, 0); + file = internal->file; - return backend->set(backend, name, value); + return file->set(file, name, value); } /*********** @@ -324,14 +326,15 @@ int git_config_get_bool(git_config *cfg, const char *name, int *out) int git_config_get_string(git_config *cfg, const char *name, const char **out) { - backend_internal *internal; - git_config_backend *backend; + file_internal *internal; + git_config_file *file; - assert(cfg->backends.length > 0); + if (cfg->files.length == 0) + return git__throw(GIT_EINVALIDARGS, "Cannot get variable value; no files open in the `git_config` instance"); - internal = git_vector_get(&cfg->backends, 0); - backend = internal->backend; + internal = git_vector_get(&cfg->files, 0); + file = internal->file; - return backend->get(backend, name, out); + return file->get(file, name, out); } diff --git a/src/config.h b/src/config.h index 104e01633..8b521543c 100644 --- a/src/config.h +++ b/src/config.h @@ -8,7 +8,7 @@ #define GIT_CONFIG_FILENAME ".gitconfig" struct git_config { - git_vector backends; + git_vector files; }; #endif diff --git a/src/config_file.c b/src/config_file.c index 40829eb49..a5addf18f 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -26,7 +26,7 @@ #include "common.h" #include "config.h" #include "fileops.h" -#include "git2/config_backend.h" +#include "git2/config.h" #include "git2/types.h" #include @@ -81,10 +81,8 @@ typedef struct { (iter) && (((tmp) = CVAR_LIST_NEXT(iter) || 1));\ (iter) = (tmp)) - - typedef struct { - git_config_backend parent; + git_config_file parent; cvar_t_list var_list; @@ -96,10 +94,10 @@ typedef struct { } reader; char *file_path; -} file_backend; +} diskfile_backend; -static int config_parse(file_backend *cfg_file); -static int parse_variable(file_backend *cfg, char **var_name, char **var_value); +static int config_parse(diskfile_backend *cfg_file); +static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value); static void cvar_free(cvar_t *var) { @@ -243,10 +241,10 @@ static int cvar_normalize_name(cvar_t *var, char **output) return GIT_SUCCESS; } -static int config_open(git_config_backend *cfg) +static int config_open(git_config_file *cfg) { int error; - file_backend *b = (file_backend *)cfg; + diskfile_backend *b = (diskfile_backend *)cfg; error = gitfo_read_file(&b->reader.buffer, b->file_path); if(error < GIT_SUCCESS) @@ -268,9 +266,9 @@ static int config_open(git_config_backend *cfg) return error; } -static void backend_free(git_config_backend *_backend) +static void backend_free(git_config_file *_backend) { - file_backend *backend = (file_backend *)_backend; + diskfile_backend *backend = (diskfile_backend *)_backend; if (backend == NULL) return; @@ -281,14 +279,15 @@ static void backend_free(git_config_backend *_backend) free(backend); } -static int file_foreach(git_config_backend *backend, int (*fn)(const char *, void *), void *data) +static int file_foreach(git_config_file *backend, int (*fn)(const char *, void *), void *data) { int ret = GIT_SUCCESS; cvar_t *var; - char *normalized; - file_backend *b = (file_backend *)backend; + diskfile_backend *b = (diskfile_backend *)backend; CVAR_LIST_FOREACH(&b->var_list, var) { + char *normalized = NULL; + ret = cvar_normalize_name(var, &normalized); if (ret < GIT_SUCCESS) return ret; @@ -302,13 +301,13 @@ static int file_foreach(git_config_backend *backend, int (*fn)(const char *, voi return ret; } -static int config_set(git_config_backend *cfg, const char *name, const char *value) +static int config_set(git_config_file *cfg, const char *name, const char *value) { cvar_t *var = NULL; cvar_t *existing = NULL; int error = GIT_SUCCESS; const char *last_dot; - file_backend *b = (file_backend *)cfg; + diskfile_backend *b = (diskfile_backend *)cfg; /* * If it already exists, we just need to update its value. @@ -370,11 +369,11 @@ static int config_set(git_config_backend *cfg, const char *name, const char *val /* * Internal function that actually gets the value in string form */ -static int config_get(git_config_backend *cfg, const char *name, const char **out) +static int config_get(git_config_file *cfg, const char *name, const char **out) { cvar_t *var; int error = GIT_SUCCESS; - file_backend *b = (file_backend *)cfg; + diskfile_backend *b = (diskfile_backend *)cfg; var = cvar_list_find(&b->var_list, name); @@ -386,15 +385,15 @@ static int config_get(git_config_backend *cfg, const char *name, const char **ou return error; } -int git_config_backend_file(git_config_backend **out, const char *path) +int git_config_file__ondisk(git_config_file **out, const char *path) { - file_backend *backend; + diskfile_backend *backend; - backend = git__malloc(sizeof(file_backend)); + backend = git__malloc(sizeof(diskfile_backend)); if (backend == NULL) return GIT_ENOMEM; - memset(backend, 0x0, sizeof(file_backend)); + memset(backend, 0x0, sizeof(diskfile_backend)); backend->file_path = git__strdup(path); if (backend->file_path == NULL) { @@ -408,12 +407,12 @@ int git_config_backend_file(git_config_backend **out, const char *path) backend->parent.foreach = file_foreach; backend->parent.free = backend_free; - *out = (git_config_backend *)backend; + *out = (git_config_file *)backend; return GIT_SUCCESS; } -static int cfg_getchar_raw(file_backend *cfg) +static int cfg_getchar_raw(diskfile_backend *cfg) { int c; @@ -442,7 +441,7 @@ static int cfg_getchar_raw(file_backend *cfg) #define SKIP_WHITESPACE (1 << 1) #define SKIP_COMMENTS (1 << 2) -static int cfg_getchar(file_backend *cfg_file, int flags) +static int cfg_getchar(diskfile_backend *cfg_file, int flags) { const int skip_whitespace = (flags & SKIP_WHITESPACE); const int skip_comments = (flags & SKIP_COMMENTS); @@ -464,7 +463,7 @@ static int cfg_getchar(file_backend *cfg_file, int flags) /* * Read the next char, but don't move the reading pointer. */ -static int cfg_peek(file_backend *cfg, int flags) +static int cfg_peek(diskfile_backend *cfg, int flags) { void *old_read_ptr; int old_lineno, old_eof; @@ -497,7 +496,7 @@ static int is_linebreak(const char *pos) /* * Read and consume a line, returning it in newly-allocated memory. */ -static char *cfg_readline(file_backend *cfg) +static char *cfg_readline(diskfile_backend *cfg) { char *line = NULL; char *line_src, *line_end; @@ -557,7 +556,7 @@ static char *cfg_readline(file_backend *cfg) /* * Consume a line, without storing it anywhere */ -void cfg_consume_line(file_backend *cfg) +void cfg_consume_line(diskfile_backend *cfg) { char *line_start, *line_end; @@ -669,7 +668,7 @@ static int parse_section_header_ext(const char *line, const char *base_name, cha return error; } -static int parse_section_header(file_backend *cfg, char **section_out) +static int parse_section_header(diskfile_backend *cfg, char **section_out) { char *name, *name_end; int name_length, c, pos; @@ -736,7 +735,7 @@ error: return error; } -static int skip_bom(file_backend *cfg) +static int skip_bom(diskfile_backend *cfg) { static const char *utf8_bom = "\xef\xbb\xbf"; @@ -809,7 +808,7 @@ static void strip_comments(char *line) } } -static int config_parse(file_backend *cfg_file) +static int config_parse(diskfile_backend *cfg_file) { int error = GIT_SUCCESS, c; char *current_section = NULL; @@ -888,7 +887,7 @@ static int is_multiline_var(const char *str) return *end == '\\'; } -static int parse_multiline_variable(file_backend *cfg, const char *first, char **out) +static int parse_multiline_variable(diskfile_backend *cfg, const char *first, char **out) { char *line = NULL, *end; int error = GIT_SUCCESS, len, ret; @@ -953,7 +952,7 @@ static int parse_multiline_variable(file_backend *cfg, const char *first, char * return error; } -static int parse_variable(file_backend *cfg, char **var_name, char **var_value) +static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value) { char *tmp; int error = GIT_SUCCESS; diff --git a/tests/t15-config.c b/tests/t15-config.c index 50d473580..c2e146cf1 100644 --- a/tests/t15-config.c +++ b/tests/t15-config.c @@ -36,7 +36,7 @@ BEGIN_TEST(config0, "read a simple configuration") git_config *cfg; int i; - must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config0")); + must_pass(git_config_open_file(&cfg, CONFIG_BASE "/config0")); must_pass(git_config_get_int(cfg, "core.repositoryformatversion", &i)); must_be_true(i == 0); must_pass(git_config_get_bool(cfg, "core.filemode", &i)); @@ -58,7 +58,7 @@ BEGIN_TEST(config1, "case sensitivity") int i; const char *str; - must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config1")); + must_pass(git_config_open_file(&cfg, CONFIG_BASE "/config1")); must_pass(git_config_get_string(cfg, "this.that.other", &str)); must_be_true(!strcmp(str, "true")); @@ -84,7 +84,7 @@ BEGIN_TEST(config2, "parse a multiline value") git_config *cfg; const char *str; - must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config2")); + must_pass(git_config_open_file(&cfg, CONFIG_BASE "/config2")); must_pass(git_config_get_string(cfg, "this.That.and", &str)); must_be_true(!strcmp(str, "one one one two two three three")); @@ -99,7 +99,7 @@ BEGIN_TEST(config3, "parse a [section.subsection] header") git_config *cfg; const char *str; - must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config3")); + must_pass(git_config_open_file(&cfg, CONFIG_BASE "/config3")); must_pass(git_config_get_string(cfg, "section.subsection.var", &str)); must_be_true(!strcmp(str, "hello")); @@ -117,7 +117,7 @@ BEGIN_TEST(config4, "a variable name on its own is valid") const char *str; int i; - must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config4")); + must_pass(git_config_open_file(&cfg, CONFIG_BASE "/config4")); must_pass(git_config_get_string(cfg, "some.section.variable", &str)); must_be_true(str == NULL); @@ -133,7 +133,7 @@ BEGIN_TEST(config5, "test number suffixes") git_config *cfg; long int i; - must_pass(git_config_open_bare(&cfg, CONFIG_BASE "/config5")); + must_pass(git_config_open_file(&cfg, CONFIG_BASE "/config5")); must_pass(git_config_get_long(cfg, "number.simple", &i)); must_be_true(i == 1);