mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 03:15:46 +00:00
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>
This commit is contained in:
parent
92be7908bd
commit
9ac581bf7f
@ -9,6 +9,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fileops.h"
|
#include "fileops.h"
|
||||||
#include "filebuf.h"
|
#include "filebuf.h"
|
||||||
|
#include "buffer.h"
|
||||||
#include "git2/config.h"
|
#include "git2/config.h"
|
||||||
#include "git2/types.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
|
* Compare according to the git rules. Section contains the section as
|
||||||
* rules. The order of the strings is important because local is
|
* it's stored internally. query is the full name as would be given to
|
||||||
* assumed to have the internal format (only the section name and with
|
* 'git config'.
|
||||||
* case information) and input the normalized one (only dots, no case
|
|
||||||
* information).
|
|
||||||
*/
|
*/
|
||||||
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;
|
const char *sdot, *qdot, *qsub;
|
||||||
char *local_sp = strchr(local, ' ');
|
size_t section_len;
|
||||||
size_t comparison_len;
|
|
||||||
|
sdot = strchr(section, '.');
|
||||||
|
|
||||||
|
/* If the section doesn't have any dots, it's easy */
|
||||||
|
if (sdot == NULL)
|
||||||
|
return !strncasecmp(section, query, strlen(section));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the local section name doesn't contain a space, then we can
|
* If it does have dots, compare the sections
|
||||||
* just do a case-insensitive compare.
|
* case-insensitively. The comparison includes the dots.
|
||||||
*/
|
*/
|
||||||
if (local_sp == NULL)
|
section_len = sdot - section + 1;
|
||||||
return !strncasecmp(local, input, strlen(local));
|
if (strncasecmp(section, query, sdot - 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;
|
return 0;
|
||||||
|
|
||||||
/*
|
qsub = query + section_len;
|
||||||
* We compare starting from the first character after the
|
qdot = strchr(qsub, '.');
|
||||||
* quotation marks, which is two characters beyond the space. For
|
/* Make sure the subsections are the same length */
|
||||||
* the input, we start one character beyond the dot. If the names
|
if (strlen(sdot + 1) != qdot - qsub)
|
||||||
* have different lengths, then we can fail early, as we know they
|
return 0;
|
||||||
* can't be the same.
|
|
||||||
* The length is given by the length between the quotation marks.
|
|
||||||
*/
|
|
||||||
|
|
||||||
first_dot = strchr(input, '.');
|
/* The subsection is case-sensitive */
|
||||||
comparison_len = strlen(local_sp + 2) - 1;
|
return !strncmp(sdot + 1, qsub, strlen(sdot + 1));
|
||||||
|
|
||||||
return !strncmp(local_sp + 2, first_dot + 1, comparison_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cvar_match_name(const cvar_t *var, const char *str)
|
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)
|
static int parse_section_header_ext(const char *line, const char *base_name, char **section_name)
|
||||||
{
|
{
|
||||||
size_t buf_len, total_len;
|
int c, rpos;
|
||||||
int pos, rpos;
|
char *first_quote, *last_quote;
|
||||||
int c, ret;
|
git_buf buf = GIT_BUF_INIT;
|
||||||
char *subsection, *first_quote, *last_quote;
|
|
||||||
int error = GIT_SUCCESS;
|
int error = GIT_SUCCESS;
|
||||||
int quote_marks;
|
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)
|
if (last_quote - first_quote == 0)
|
||||||
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse ext header. There is no final quotation mark");
|
return git__throw(GIT_EOBJCORRUPTED, "Failed to parse ext header. There is no final quotation mark");
|
||||||
|
|
||||||
buf_len = last_quote - first_quote + 2;
|
git_buf_grow(&buf, strlen(base_name) + last_quote - first_quote + 2);
|
||||||
|
git_buf_printf(&buf, "%s.", base_name);
|
||||||
|
|
||||||
subsection = git__malloc(buf_len + 2);
|
|
||||||
if (subsection == NULL)
|
|
||||||
return GIT_ENOMEM;
|
|
||||||
|
|
||||||
pos = 0;
|
|
||||||
rpos = 0;
|
rpos = 0;
|
||||||
quote_marks = 0;
|
quote_marks = 0;
|
||||||
|
|
||||||
@ -626,7 +613,7 @@ static int parse_section_header_ext(const char *line, const char *base_name, cha
|
|||||||
switch (c) {
|
switch (c) {
|
||||||
case '"':
|
case '"':
|
||||||
++quote_marks;
|
++quote_marks;
|
||||||
break;
|
continue;
|
||||||
case '\\':
|
case '\\':
|
||||||
c = line[rpos++];
|
c = line[rpos++];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
@ -642,28 +629,12 @@ static int parse_section_header_ext(const char *line, const char *base_name, cha
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
subsection[pos++] = (char) c;
|
git_buf_putc(&buf, c);
|
||||||
} while ((c = line[rpos++]) != ']');
|
} while ((c = line[rpos++]) != ']');
|
||||||
|
|
||||||
subsection[pos] = '\0';
|
*section_name = git__strdup(git_buf_cstr(&buf));
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(subsection);
|
git_buf_free(&buf);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -107,10 +107,8 @@ BEGIN_TEST(config3, "parse a [section.subsection] header")
|
|||||||
must_pass(git_config_get_string(cfg, "section.subsection.var", &str));
|
must_pass(git_config_get_string(cfg, "section.subsection.var", &str));
|
||||||
must_be_true(!strcmp(str, "hello"));
|
must_be_true(!strcmp(str, "hello"));
|
||||||
|
|
||||||
/* Avoid a false positive */
|
/* The subsection is transformed to lower-case */
|
||||||
str = "nohello";
|
must_fail(git_config_get_string(cfg, "section.subSectIon.var", &str));
|
||||||
must_pass(git_config_get_string(cfg, "section.subSectIon.var", &str));
|
|
||||||
must_be_true(!strcmp(str, "hello"));
|
|
||||||
|
|
||||||
git_config_free(cfg);
|
git_config_free(cfg);
|
||||||
END_TEST
|
END_TEST
|
||||||
@ -324,6 +322,20 @@ BEGIN_TEST(config16, "add a variable in a new section")
|
|||||||
must_pass(git_filebuf_commit(&buf));
|
must_pass(git_filebuf_commit(&buf));
|
||||||
END_TEST
|
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)
|
BEGIN_SUITE(config)
|
||||||
ADD_TEST(config0);
|
ADD_TEST(config0);
|
||||||
ADD_TEST(config1);
|
ADD_TEST(config1);
|
||||||
@ -342,4 +354,5 @@ BEGIN_SUITE(config)
|
|||||||
ADD_TEST(config14);
|
ADD_TEST(config14);
|
||||||
ADD_TEST(config15);
|
ADD_TEST(config15);
|
||||||
ADD_TEST(config16);
|
ADD_TEST(config16);
|
||||||
|
ADD_TEST(config17);
|
||||||
END_SUITE
|
END_SUITE
|
||||||
|
Loading…
Reference in New Issue
Block a user