The syntax is: [include "filename"] which is somewhat branch/remote-alike. There are a few differences, though: filenames happen to be long, so a backslash is supported to split the names into multiple lines. No bare LF allowed, so this is illegal: [include "path/ name"] On the other hand, this is allowed: [include "path/\ name"] Backslash is just to quote characters (as in shell). Only one quoted string allowed, so this is bad too: [include "path/" "name"] Signed-off-by: Alex Riesen <raa.lkml@xxxxxxxxx> --- This is a resend, I have no idea what happened to original, but it never appeared on vger. And this will probably horribly garbled by gmail. Will see. Alex Riesen, Thu, Feb 15, 2007 12:35:57 +0100:
I suggest to ignore /etc/gitconfig completely if ~/.gitconfig exists, but allow inclusion of /etc/gitconfig from ~/.gitconfig (there are very singular and preciuos exceptions).
config.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 100 insertions(+), 3 deletions(-) diff --git a/config.c b/config.c index d821071..b42a7ea 100644 --- a/config.c +++ b/config.c @@ -12,6 +12,57 @@ static FILE *config_file; static const char *config_file_name; static int config_linenr; + +struct fileinfo +{ + char *name; + int linenr; + FILE *file; + struct fileinfo *prev; +}; +static struct fileinfo *config_stack = NULL; + +static void include_file(const char *filename) +{ + struct fileinfo *prev; + FILE *file; + file = fopen(filename, "r"); + if (!file) { + error("ignored \"%s\": %s", filename, strerror(errno)); + return; + } + prev = malloc(sizeof(*prev)); + prev->name = (char *)config_file_name; + prev->linenr = config_linenr; + prev->file = config_file; + prev->prev = config_stack; + config_stack = prev; + + config_file = file; + config_file_name = xstrdup(filename); + config_linenr = 0; +} + +static FILE *pop_file(void) +{ + struct fileinfo *prev; + + if (!config_stack) + /* The last file on stack does not belong to us. + * Free the names and close all included files. */ + return NULL; + + free((void*)config_file_name); + fclose(config_file); + config_file = config_stack->file; + config_file_name = config_stack->name; + config_linenr = 0; + prev = config_stack->prev; + free(config_stack); + config_stack = prev; + return config_file; +} + static int get_next_char(void) { int c; @@ -31,13 +82,51 @@ static int get_next_char(void) if (c == '\n') config_linenr++; if (c == EOF) { - config_file = NULL; + config_file = pop_file(); c = '\n'; } } return c; } +static int parse_include(void) +{ + char name[PATH_MAX]; + int quote = 0, len = 0; + + for (;;) { + int c = get_next_char(); + if (len >= sizeof(name)) + return -1; + if (c == '"') { + quote++; + continue; + } + if (c == '\n') + /* do not allow bare \n anywhere in path */ + return -1; + if (quote == 1) { + if (c == '\\') { + c = get_next_char(); + if (c == '\n') + continue; + } + name[len++] = c; + } + if (quote == 2 && c == ']') { + do + c = get_next_char(); + while (c != '\n'); + break; + } + if ((quote < 1 || quote >= 2) && !isspace(c) ) + return -1; + } + name[len] = '\0'; + include_file(name); + return 0; +} + static char *parse_value(void) { static char value[1024]; @@ -181,8 +270,13 @@ static int get_base_var(char *name) int c = get_next_char(); if (c == EOF) return -1; + if (!isalpha(c) && !strncmp(name, "include", baselen) && + config_file) { + ungetc(c, config_file); + return parse_include(); + } if (c == ']') - return baselen; + return baselen ? baselen: -1; if (isspace(c)) return get_extended_base_var(name, baselen, c); if (!iskeychar(c) && c != '.') @@ -216,8 +310,11 @@ static int git_parse_file(config_fn_t fn) } if (c == '[') { baselen = get_base_var(var); - if (baselen <= 0) + if (baselen < 0) break; + if (!baselen) + /* [include "..."]*/ + continue; var[baselen++] = '.'; var[baselen] = 0; continue; -- 1.5.0.138.g36f81 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html