summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <carlos@cmartin.tk>2011-10-01 19:56:04 +0200
committerCarlos Martín Nieto <carlos@cmartin.tk>2011-10-01 19:58:26 +0200
commit9ac581bf7fffaf809214fdd950bb62d242ee52fe (patch)
treed794ce4c31f6a9dd8e69ff6bd5f844c6730ea941
parent92be7908bd0fa344dc086d43685225ebd082eae2 (diff)
downloadlibgit2-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.c93
-rw-r--r--tests/resources/config/config95
-rw-r--r--tests/t15-config.c21
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