diff options
author | Carlos Martín Nieto <carlos@cmartin.tk> | 2011-10-01 19:56:04 +0200 |
---|---|---|
committer | Carlos Martín Nieto <carlos@cmartin.tk> | 2011-10-01 19:58:26 +0200 |
commit | 9ac581bf7fffaf809214fdd950bb62d242ee52fe (patch) | |
tree | d794ce4c31f6a9dd8e69ff6bd5f844c6730ea941 | |
parent | 92be7908bd0fa344dc086d43685225ebd082eae2 (diff) | |
download | libgit2-9ac581bf7fffaf809214fdd950bb62d242ee52fe.tar.gz |
config: behave like git with [section.subsection]
The documentation is a bit misleading. The subsection name is always
case-sensitive, but with a [section.subsection] header, the subsection
is transformed to lowercase when the configuration is parsed.
Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
-rw-r--r-- | src/config_file.c | 93 | ||||
-rw-r--r-- | tests/resources/config/config9 | 5 | ||||
-rw-r--r-- | tests/t15-config.c | 21 |
3 files changed, 54 insertions, 65 deletions
diff --git a/src/config_file.c b/src/config_file.c index f76efed97..64d57c5c5 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -9,6 +9,7 @@ #include "config.h" #include "fileops.h" #include "filebuf.h" +#include "buffer.h" #include "git2/config.h" #include "git2/types.h" @@ -107,46 +108,37 @@ static void cvar_list_free(cvar_t_list *list) } /* - * Compare two strings according to the git section-subsection - * rules. The order of the strings is important because local is - * assumed to have the internal format (only the section name and with - * case information) and input the normalized one (only dots, no case - * information). + * Compare according to the git rules. Section contains the section as + * it's stored internally. query is the full name as would be given to + * 'git config'. */ -static int cvar_match_section(const char *local, const char *input) +static int cvar_match_section(const char *section, const char *query) { - char *first_dot; - char *local_sp = strchr(local, ' '); - size_t comparison_len; + const char *sdot, *qdot, *qsub; + size_t section_len; - /* - * If the local section name doesn't contain a space, then we can - * just do a case-insensitive compare. - */ - if (local_sp == NULL) - return !strncasecmp(local, input, strlen(local)); + sdot = strchr(section, '.'); - /* - * From here onwards, there is a space diving the section and the - * subsection. Anything before the space in local is - * case-insensitive. - */ - if (strncasecmp(local, input, local_sp - local)) - return 0; + /* If the section doesn't have any dots, it's easy */ + if (sdot == NULL) + return !strncasecmp(section, query, strlen(section)); /* - * We compare starting from the first character after the - * quotation marks, which is two characters beyond the space. For - * the input, we start one character beyond the dot. If the names - * have different lengths, then we can fail early, as we know they - * can't be the same. - * The length is given by the length between the quotation marks. + * If it does have dots, compare the sections + * case-insensitively. The comparison includes the dots. */ + section_len = sdot - section + 1; + if (strncasecmp(section, query, sdot - section)) + return 0; - first_dot = strchr(input, '.'); - comparison_len = strlen(local_sp + 2) - 1; + qsub = query + section_len; + qdot = strchr(qsub, '.'); + /* Make sure the subsections are the same length */ + if (strlen(sdot + 1) != qdot - qsub) + return 0; - return !strncmp(local_sp + 2, first_dot + 1, comparison_len); + /* The subsection is case-sensitive */ + return !strncmp(sdot + 1, qsub, strlen(sdot + 1)); } static int cvar_match_name(const cvar_t *var, const char *str) @@ -581,10 +573,9 @@ GIT_INLINE(int) config_keychar(int c) static int parse_section_header_ext(const char *line, const char *base_name, char **section_name) { - size_t buf_len, total_len; - int pos, rpos; - int c, ret; - char *subsection, *first_quote, *last_quote; + int c, rpos; + char *first_quote, *last_quote; + git_buf buf = GIT_BUF_INIT; int error = GIT_SUCCESS; int quote_marks; /* @@ -599,13 +590,9 @@ static int parse_section_header_ext(const char *line, const char *base_name, cha if (last_quote - first_quote == 0) return git__throw(GIT_EOBJCORRUPTED, "Failed to parse ext header. There is no final quotation mark"); - buf_len = last_quote - first_quote + 2; - - subsection = git__malloc(buf_len + 2); - if (subsection == NULL) - return GIT_ENOMEM; + git_buf_grow(&buf, strlen(base_name) + last_quote - first_quote + 2); + git_buf_printf(&buf, "%s.", base_name); - pos = 0; rpos = 0; quote_marks = 0; @@ -626,7 +613,7 @@ static int parse_section_header_ext(const char *line, const char *base_name, cha switch (c) { case '"': ++quote_marks; - break; + continue; case '\\': c = line[rpos++]; switch (c) { @@ -642,28 +629,12 @@ static int parse_section_header_ext(const char *line, const char *base_name, cha break; } - subsection[pos++] = (char) c; + git_buf_putc(&buf, c); } while ((c = line[rpos++]) != ']'); - subsection[pos] = '\0'; - - total_len = strlen(base_name) + strlen(subsection) + 2; - *section_name = git__malloc(total_len); - if (*section_name == NULL) { - error = GIT_ENOMEM; - goto out; - } - - ret = p_snprintf(*section_name, total_len, "%s %s", base_name, subsection); - if (ret < 0) { - error = git__throw(GIT_EOSERR, "Failed to parse ext header. OS error: %s", strerror(errno)); - goto out; - } - - git__strntolower(*section_name, strchr(*section_name, ' ') - *section_name); - + *section_name = git__strdup(git_buf_cstr(&buf)); out: - free(subsection); + git_buf_free(&buf); return error; } diff --git a/tests/resources/config/config9 b/tests/resources/config/config9 index 2179b2e6c..fcaac424e 100644 --- a/tests/resources/config/config9 +++ b/tests/resources/config/config9 @@ -2,3 +2,8 @@ dummy2 = 42 verylong = 1 dummy = 1 + +[remote "ab"] + url = http://example.com/git/ab +[remote "abba"] + url = http://example.com/git/abba diff --git a/tests/t15-config.c b/tests/t15-config.c index 3ec54feea..c4cb590f5 100644 --- a/tests/t15-config.c +++ b/tests/t15-config.c @@ -107,10 +107,8 @@ BEGIN_TEST(config3, "parse a [section.subsection] header") must_pass(git_config_get_string(cfg, "section.subsection.var", &str)); must_be_true(!strcmp(str, "hello")); - /* Avoid a false positive */ - str = "nohello"; - must_pass(git_config_get_string(cfg, "section.subSectIon.var", &str)); - must_be_true(!strcmp(str, "hello")); + /* The subsection is transformed to lower-case */ + must_fail(git_config_get_string(cfg, "section.subSectIon.var", &str)); git_config_free(cfg); END_TEST @@ -324,6 +322,20 @@ BEGIN_TEST(config16, "add a variable in a new section") must_pass(git_filebuf_commit(&buf)); END_TEST +BEGIN_TEST(config17, "prefixes aren't broken") + git_config *cfg; + const char *str; + + must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); + must_pass(git_config_get_string(cfg, "remote.ab.url", &str)); + must_be_true(strcmp(str, "http://example.com/git/ab") == 0); + + must_pass(git_config_get_string(cfg, "remote.abba.url", &str)); + must_be_true(strcmp(str, "http://example.com/git/abba") == 0); + + git_config_free(cfg); +END_TEST + BEGIN_SUITE(config) ADD_TEST(config0); ADD_TEST(config1); @@ -342,4 +354,5 @@ BEGIN_SUITE(config) ADD_TEST(config14); ADD_TEST(config15); ADD_TEST(config16); + ADD_TEST(config17); END_SUITE |