Commit 2454ce78 by Carlos Martín Nieto

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>
parent 9f1b54d6
...@@ -34,7 +34,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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 */
if (line == NULL)
return GIT_ENOMEM;
strip_comments(line);
switch (line[0]) { switch (c) {
case '\0': /* empty line (only whitespace) */ case '\0': /* We've arrived at the end of the file */
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, &current_section, line); error = parse_section_header(cfg_file, &current_section);
break; break;
default: /* assume variable declaration */ case ';':
error = parse_variable(line, &var_name, &var_value); case '#':
cfg_consume_line(cfg_file); cfg_consume_line(cfg_file);
break;
default: /* assume variable declaration */
error = parse_variable(cfg_file, &var_name, &var_value);
if (error < GIT_SUCCESS) if (error < GIT_SUCCESS)
break; break;
...@@ -894,8 +916,6 @@ static int config_parse(git_config *cfg_file) ...@@ -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) ...@@ -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) ...@@ -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;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment