diff options
| author | Carlos Martín Nieto <cmn@dwim.me> | 2013-09-05 19:24:20 +0200 |
|---|---|---|
| committer | Carlos Martín Nieto <cmn@dwim.me> | 2013-09-07 20:51:26 +0200 |
| commit | d8d25acb9a2e560a5fce66d4b1c9bdf4969ea2c4 (patch) | |
| tree | 0239305b76721c18df7c8d5b131437e4c42dbc59 /src/config_file.c | |
| parent | d209cc47515d2feeaa30de20882ded5cb4039736 (diff) | |
| download | libgit2-d8d25acb9a2e560a5fce66d4b1c9bdf4969ea2c4.tar.gz | |
config: add support for include directives
Relative, absolute and home-relative paths are supported. The
recursion limit it set at 10, just like in git.
Diffstat (limited to 'src/config_file.c')
| -rw-r--r-- | src/config_file.c | 57 |
1 files changed, 52 insertions, 5 deletions
diff --git a/src/config_file.c b/src/config_file.c index fa8aba061..891bc29d3 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -34,6 +34,8 @@ typedef struct git_config_file_iter { cvar_t* next_var; } git_config_file_iter; +/* Max depth for [include] directives */ +#define MAX_INCLUDE_DEPTH 10 #define CVAR_LIST_HEAD(list) ((list)->head) @@ -74,6 +76,8 @@ typedef struct git_config_file_iter { (iter) = (tmp)) struct reader { + time_t file_mtime; + size_t file_size; char *file_path; git_buf buffer; char *read_ptr; @@ -89,8 +93,6 @@ typedef struct { struct reader reader; char *file_path; - time_t file_mtime; - size_t file_size; git_config_level_t level; } diskfile_backend; @@ -169,7 +171,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level) git_buf_init(&b->reader.buffer, 0); res = git_futils_readbuffer_updated( - &b->reader.buffer, b->file_path, &b->file_mtime, &b->file_size, NULL); + &b->reader.buffer, b->file_path, &b->reader.file_mtime, &b->reader.file_size, NULL); /* It's fine if the file doesn't exist */ if (res == GIT_ENOTFOUND) @@ -191,7 +193,7 @@ static int config_refresh(git_config_backend *cfg) git_strmap *old_values; res = git_futils_readbuffer_updated( - &b->reader.buffer, b->file_path, &b->file_mtime, &b->file_size, &updated); + &b->reader.buffer, b->file_path, &b->reader.file_mtime, &b->reader.file_size, &updated); if (res < 0 || !updated) return (res == GIT_ENOTFOUND) ? 0 : res; @@ -899,6 +901,15 @@ static int strip_comments(char *line, int in_quotes) return quote_count; } +static int included_path(git_buf *out, const char *dir, const char *path) +{ + /* From the user's home */ + if (path[0] == '~' && path[1] == '/') + return git_futils_find_global_file(out, &path[1]); + + return git_path_join_unrooted(out, path, dir, NULL); +} + static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth) { int c; @@ -910,6 +921,10 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c int result = 0; khiter_t pos; + /* FIXME: should we return an error? */ + if (depth >= MAX_INCLUDE_DEPTH) + return 0; + /* Initialize the reading position */ reader->read_ptr = reader->buffer.ptr; reader->eof = 0; @@ -979,6 +994,38 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c existing->next = var; } + if (!git__strcmp(var->entry->name, "include.path")) { + struct reader r; + git_buf path = GIT_BUF_INIT; + char *dir; + + memset(&r, 0, sizeof(r)); + if ((result = git_path_dirname_r(&path, reader->file_path)) < 0) + break; + + dir = git_buf_detach(&path); + result = included_path(&path, dir, var->entry->value); + git__free(dir); + + if (result < 0) + break; + + r.file_path = git_buf_detach(&path); + git_buf_init(&r.buffer, 0); + if ((result = git_futils_readbuffer_updated(&r.buffer, r.file_path, &r.file_mtime, + &r.file_size, NULL)) < 0) { + git__free(r.file_path); + break; + } + + result = config_parse(cfg_file, &r, level, depth+1); + git__free(r.file_path); + git_buf_free(&r.buffer); + + if (result < 0) + break; + } + break; } } @@ -1199,7 +1246,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p git__free(current_section); /* refresh stats - if this errors, then commit will error too */ - (void)git_filebuf_stats(&cfg->file_mtime, &cfg->file_size, &file); + (void)git_filebuf_stats(&cfg->reader.file_mtime, &cfg->reader.file_size, &file); result = git_filebuf_commit(&file, GIT_CONFIG_FILE_MODE); git_buf_free(&cfg->reader.buffer); |
