mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-05 22:36:08 +00:00
config: don't mix buffer reading methods
Make header and variable parse functions use their own buffers instead of giving them the line they need to read as a parameter which they mostly ignore. This is in preparation for multiline configuration variables. Signed-off-by: Carlos Martín Nieto <cmn@elego.de>
This commit is contained in:
parent
9f1b54d6d0
commit
2454ce784f
126
src/config.c
126
src/config.c
@ -34,7 +34,7 @@
|
|||||||
* Forward declarations
|
* Forward declarations
|
||||||
***********************/
|
***********************/
|
||||||
static int config_parse(git_config *cfg_file);
|
static int config_parse(git_config *cfg_file);
|
||||||
static int parse_variable(const char *line, char **var_name, char **var_value);
|
static int parse_variable(git_config *cfg, char **var_name, char **var_value);
|
||||||
void git_config_free(git_config *cfg);
|
void git_config_free(git_config *cfg);
|
||||||
|
|
||||||
static git_cvar *cvar_free(git_cvar *var)
|
static git_cvar *cvar_free(git_cvar *var)
|
||||||
@ -492,6 +492,30 @@ static int cfg_getchar(git_config *cfg_file, int flags)
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the next char, but don't move the reading pointer.
|
||||||
|
*/
|
||||||
|
static int cfg_peek(git_config *cfg, int flags)
|
||||||
|
{
|
||||||
|
void *old_read_ptr;
|
||||||
|
int old_lineno, old_eof;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
assert(cfg->reader.read_ptr);
|
||||||
|
|
||||||
|
old_read_ptr = cfg->reader.read_ptr;
|
||||||
|
old_lineno = cfg->reader.line_number;
|
||||||
|
old_eof = cfg->reader.eof;
|
||||||
|
|
||||||
|
ret = cfg_getchar(cfg, flags);
|
||||||
|
|
||||||
|
cfg->reader.read_ptr = old_read_ptr;
|
||||||
|
cfg->reader.line_number = old_lineno;
|
||||||
|
cfg->reader.eof = old_eof;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *LINEBREAK_UNIX = "\\\n";
|
static const char *LINEBREAK_UNIX = "\\\n";
|
||||||
static const char *LINEBREAK_WIN32 = "\\\r\n";
|
static const char *LINEBREAK_WIN32 = "\\\r\n";
|
||||||
|
|
||||||
@ -502,7 +526,7 @@ static int is_linebreak(const char *pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a line, but don't consume it
|
* Read and consume a line, returning it in newly-allocated memory.
|
||||||
*/
|
*/
|
||||||
static char *cfg_readline(git_config *cfg)
|
static char *cfg_readline(git_config *cfg)
|
||||||
{
|
{
|
||||||
@ -554,10 +578,8 @@ static char *cfg_readline(git_config *cfg)
|
|||||||
if (*line_end == '\0')
|
if (*line_end == '\0')
|
||||||
cfg->reader.eof = 1;
|
cfg->reader.eof = 1;
|
||||||
|
|
||||||
/*
|
|
||||||
cfg->reader.line_number++;
|
cfg->reader.line_number++;
|
||||||
cfg->reader.read_ptr = line_end;
|
cfg->reader.read_ptr = line_end;
|
||||||
*/
|
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
@ -624,11 +646,11 @@ static char *build_varname(const char *section, const char *name)
|
|||||||
return varname;
|
return varname;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_section_header_ext(git_config *cfg, const char *base_name, const char *line, char **section_name)
|
static int parse_section_header_ext(const char *line, const char *base_name, char **section_name)
|
||||||
{
|
{
|
||||||
int buf_len, total_len, pos;
|
int buf_len, total_len, pos, rpos;
|
||||||
int c;
|
int c;
|
||||||
char *subsection;
|
char *subsection, *first_quote, *last_quote;
|
||||||
int error = GIT_SUCCESS;
|
int error = GIT_SUCCESS;
|
||||||
int quote_marks;
|
int quote_marks;
|
||||||
/*
|
/*
|
||||||
@ -637,18 +659,25 @@ static int parse_section_header_ext(git_config *cfg, const char *base_name, cons
|
|||||||
* sync so we only really use it to calculate the length.
|
* sync so we only really use it to calculate the length.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
buf_len = strrchr(line, '"') - strchr(line, '"') + 2;
|
first_quote = strchr(line, '"');
|
||||||
if(!buf_len)
|
last_quote = strrchr(line, '"');
|
||||||
|
|
||||||
|
if (last_quote - first_quote == 0)
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
|
buf_len = last_quote - first_quote + 2;
|
||||||
|
|
||||||
subsection = git__malloc(buf_len + 2);
|
subsection = git__malloc(buf_len + 2);
|
||||||
if(subsection == NULL)
|
if(subsection == NULL)
|
||||||
return GIT_ENOMEM;
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
pos = 0;
|
pos = 0;
|
||||||
c = cfg_getchar(cfg, 0);
|
rpos = 0;
|
||||||
quote_marks = 0;
|
quote_marks = 0;
|
||||||
|
|
||||||
|
line = first_quote;
|
||||||
|
c = line[rpos++];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At the end of each iteration, whatever is stored in c will be
|
* At the end of each iteration, whatever is stored in c will be
|
||||||
* added to the string. In case of error, jump to out
|
* added to the string. In case of error, jump to out
|
||||||
@ -660,7 +689,7 @@ static int parse_section_header_ext(git_config *cfg, const char *base_name, cons
|
|||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
break;
|
break;
|
||||||
case '\\':
|
case '\\':
|
||||||
c = cfg_getchar(cfg, 0);
|
c = line[rpos++];
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '"':
|
case '"':
|
||||||
case '\\':
|
case '\\':
|
||||||
@ -674,15 +703,10 @@ static int parse_section_header_ext(git_config *cfg, const char *base_name, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
subsection[pos++] = c;
|
subsection[pos++] = c;
|
||||||
} while ((c = cfg_getchar(cfg, 0)) != ']');
|
} while ((c = line[rpos++]) != ']');
|
||||||
|
|
||||||
subsection[pos] = '\0';
|
subsection[pos] = '\0';
|
||||||
|
|
||||||
if (cfg_getchar(cfg, 0) != '\n'){
|
|
||||||
error = GIT_EOBJCORRUPTED;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
total_len = strlen(base_name) + strlen(subsection) + 2;
|
total_len = strlen(base_name) + strlen(subsection) + 2;
|
||||||
*section_name = git__malloc(total_len);
|
*section_name = git__malloc(total_len);
|
||||||
if (*section_name == NULL) {
|
if (*section_name == NULL) {
|
||||||
@ -699,11 +723,16 @@ static int parse_section_header_ext(git_config *cfg, const char *base_name, cons
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_section_header(git_config *cfg, char **section_out, const char *line)
|
static int parse_section_header(git_config *cfg, char **section_out)
|
||||||
{
|
{
|
||||||
char *name, *name_end;
|
char *name, *name_end;
|
||||||
int name_length, c;
|
int name_length, c, pos;
|
||||||
int error = GIT_SUCCESS;
|
int error = GIT_SUCCESS;
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
line = cfg_readline(cfg);
|
||||||
|
if (line == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
/* find the end of the variable's name */
|
/* find the end of the variable's name */
|
||||||
name_end = strchr(line, ']');
|
name_end = strchr(line, ']');
|
||||||
@ -715,15 +744,16 @@ static int parse_section_header(git_config *cfg, char **section_out, const char
|
|||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
|
|
||||||
name_length = 0;
|
name_length = 0;
|
||||||
|
pos = 0;
|
||||||
|
|
||||||
/* Make sure we were given a section header */
|
/* Make sure we were given a section header */
|
||||||
c = cfg_getchar(cfg, SKIP_WHITESPACE | SKIP_COMMENTS);
|
c = line[pos++];
|
||||||
if(c != '['){
|
if(c != '['){
|
||||||
error = GIT_EOBJCORRUPTED;
|
error = GIT_EOBJCORRUPTED;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = cfg_getchar(cfg, SKIP_WHITESPACE | SKIP_COMMENTS);
|
c = line[pos++];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (cfg->reader.eof){
|
if (cfg->reader.eof){
|
||||||
@ -733,7 +763,8 @@ static int parse_section_header(git_config *cfg, char **section_out, const char
|
|||||||
|
|
||||||
if (isspace(c)){
|
if (isspace(c)){
|
||||||
name[name_length] = '\0';
|
name[name_length] = '\0';
|
||||||
error = parse_section_header_ext(cfg, name, line, section_out);
|
error = parse_section_header_ext(line, name, section_out);
|
||||||
|
free(line);
|
||||||
free(name);
|
free(name);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -745,23 +776,16 @@ static int parse_section_header(git_config *cfg, char **section_out, const char
|
|||||||
|
|
||||||
name[name_length++] = tolower(c);
|
name[name_length++] = tolower(c);
|
||||||
|
|
||||||
} while ((c = cfg_getchar(cfg, SKIP_COMMENTS)) != ']');
|
} while ((c = line[pos++]) != ']');
|
||||||
|
|
||||||
/*
|
|
||||||
* Here, we enforce that a section name needs to be on its own
|
|
||||||
* line
|
|
||||||
*/
|
|
||||||
if(cfg_getchar(cfg, SKIP_COMMENTS) != '\n'){
|
|
||||||
error = GIT_EOBJCORRUPTED;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
name[name_length] = 0;
|
name[name_length] = 0;
|
||||||
|
free(line);
|
||||||
strtolower(name);
|
strtolower(name);
|
||||||
*section_out = name;
|
*section_out = name;
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
free(line);
|
||||||
free(name);
|
free(name);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -841,7 +865,7 @@ static void strip_comments(char *line)
|
|||||||
|
|
||||||
static int config_parse(git_config *cfg_file)
|
static int config_parse(git_config *cfg_file)
|
||||||
{
|
{
|
||||||
int error = GIT_SUCCESS;
|
int error = GIT_SUCCESS, c;
|
||||||
char *current_section = NULL;
|
char *current_section = NULL;
|
||||||
char *var_name;
|
char *var_name;
|
||||||
char *var_value;
|
char *var_value;
|
||||||
@ -855,26 +879,24 @@ static int config_parse(git_config *cfg_file)
|
|||||||
|
|
||||||
while (error == GIT_SUCCESS && !cfg_file->reader.eof) {
|
while (error == GIT_SUCCESS && !cfg_file->reader.eof) {
|
||||||
|
|
||||||
char *line = cfg_readline(cfg_file);
|
c = cfg_peek(cfg_file, SKIP_WHITESPACE);
|
||||||
|
|
||||||
/* not enough memory to allocate line */
|
switch (c) {
|
||||||
if (line == NULL)
|
case '\0': /* We've arrived at the end of the file */
|
||||||
return GIT_ENOMEM;
|
|
||||||
|
|
||||||
strip_comments(line);
|
|
||||||
|
|
||||||
switch (line[0]) {
|
|
||||||
case '\0': /* empty line (only whitespace) */
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '[': /* section header, new section begins */
|
case '[': /* section header, new section begins */
|
||||||
free(current_section);
|
free(current_section);
|
||||||
error = parse_section_header(cfg_file, ¤t_section, line);
|
error = parse_section_header(cfg_file, ¤t_section);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ';':
|
||||||
|
case '#':
|
||||||
|
cfg_consume_line(cfg_file);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* assume variable declaration */
|
default: /* assume variable declaration */
|
||||||
error = parse_variable(line, &var_name, &var_value);
|
error = parse_variable(cfg_file, &var_name, &var_value);
|
||||||
cfg_consume_line(cfg_file);
|
|
||||||
|
|
||||||
if (error < GIT_SUCCESS)
|
if (error < GIT_SUCCESS)
|
||||||
break;
|
break;
|
||||||
@ -894,8 +916,6 @@ static int config_parse(git_config *cfg_file)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current_section)
|
if(current_section)
|
||||||
@ -904,12 +924,19 @@ static int config_parse(git_config *cfg_file)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_variable(const char *line, char **var_name, char **var_value)
|
static int parse_variable(git_config *cfg, char **var_name, char **var_value)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
const char *var_end = NULL;
|
const char *var_end = NULL;
|
||||||
const char *value_start = NULL;
|
const char *value_start = NULL;
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
line = cfg_readline(cfg);
|
||||||
|
if (line == NULL)
|
||||||
|
return GIT_ENOMEM;
|
||||||
|
|
||||||
|
strip_comments(line);
|
||||||
|
|
||||||
var_end = strchr(line, '=');
|
var_end = strchr(line, '=');
|
||||||
|
|
||||||
@ -948,8 +975,11 @@ static int parse_variable(const char *line, char **var_name, char **var_value)
|
|||||||
*var_value = tmp;
|
*var_value = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
|
||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
free(line);
|
||||||
return GIT_EOBJCORRUPTED;
|
return GIT_EOBJCORRUPTED;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user