diff options
| -rw-r--r-- | src/config_file.c | 38 | ||||
| -rw-r--r-- | src/config_parse.c | 199 | ||||
| -rw-r--r-- | src/config_parse.h | 6 |
3 files changed, 48 insertions, 195 deletions
diff --git a/src/config_file.c b/src/config_file.c index 8765259b3..792a3de7a 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -1115,6 +1115,7 @@ static int config_read( { struct parse_data parse_data; git_config_parser reader; + git_buf contents = GIT_BUF_INIT; int error; if (depth >= MAX_INCLUDE_DEPTH) { @@ -1122,22 +1123,20 @@ static int config_read( return -1; } - git_buf_init(&reader.buffer, 0); - - if ((error = git_futils_readbuffer(&reader.buffer, file->path)) < 0) + if ((error = git_futils_readbuffer(&contents, file->path)) < 0) goto out; - if ((error = git_hash_buf(&file->checksum, reader.buffer.ptr, reader.buffer.size)) < 0) + git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size); + + if ((error = git_hash_buf(&file->checksum, contents.ptr, contents.size)) < 0) goto out; /* Initialize the reading position */ reader.file = file; - reader.line_number = 0; - reader.read_ptr = reader.buffer.ptr; - reader.eof = 0; + git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size); /* If the file is empty, there's nothing for us to do */ - if (*reader.read_ptr == '\0') + if (!reader.ctx.content || *reader.ctx.content == '\0') goto out; parse_data.repo = repo; @@ -1149,7 +1148,7 @@ static int config_read( error = git_config_parse(&reader, NULL, read_on_variable, NULL, NULL, &parse_data); out: - git_buf_free(&reader.buffer); + git_buf_free(&contents); return error; } @@ -1384,36 +1383,30 @@ static int config_write(diskfile_backend *cfg, const char *orig_key, const char int result; char *orig_section, *section, *orig_name, *name, *ldot; git_filebuf file = GIT_FILEBUF_INIT; - git_buf buf = GIT_BUF_INIT; + git_buf buf = GIT_BUF_INIT, contents = GIT_BUF_INIT; git_config_parser reader; struct write_data write_data; memset(&reader, 0, sizeof(reader)); - git_buf_init(&reader.buffer, 0); reader.file = &cfg->file; if (cfg->locked) { - result = git_buf_puts(&reader.buffer, git_buf_cstr(&cfg->locked_content)); + result = git_buf_puts(&contents, git_buf_cstr(&cfg->locked_content)); } else { /* Lock the file */ if ((result = git_filebuf_open( &file, cfg->file.path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) { - git_buf_free(&reader.buffer); + git_buf_free(&contents); return result; } /* We need to read in our own config file */ - result = git_futils_readbuffer(&reader.buffer, cfg->file.path); + result = git_futils_readbuffer(&contents, cfg->file.path); } /* Initialise the reading position */ - if (result == GIT_ENOTFOUND) { - reader.read_ptr = NULL; - reader.eof = 1; - git_buf_clear(&reader.buffer); - } else if (result == 0) { - reader.read_ptr = reader.buffer.ptr; - reader.eof = 0; + if (result == 0 || result == GIT_ENOTFOUND) { + git_parse_ctx_init(&reader.ctx, contents.ptr, contents.size); } else { git_filebuf_cleanup(&file); return -1; /* OS error when reading the file */ @@ -1467,6 +1460,7 @@ static int config_write(diskfile_backend *cfg, const char *orig_key, const char done: git_buf_free(&buf); - git_buf_free(&reader.buffer); + git_buf_free(&contents); + git_parse_ctx_clear(&reader.ctx); return result; } diff --git a/src/config_parse.c b/src/config_parse.c index 9d0ee797c..586bba8ed 100644 --- a/src/config_parse.c +++ b/src/config_parse.c @@ -13,154 +13,10 @@ static void set_parse_error(git_config_parser *reader, int col, const char *error_str) { - giterr_set(GITERR_CONFIG, "failed to parse config file: %s (in %s:%d, column %d)", - error_str, reader->file->path, reader->line_number, col); + giterr_set(GITERR_CONFIG, "failed to parse config file: %s (in %s:%"PRIuZ", column %d)", + error_str, reader->file->path, reader->ctx.line_num, col); } -static int reader_getchar_raw(git_config_parser *reader) -{ - int c; - - c = *reader->read_ptr++; - - /* - Win 32 line breaks: if we find a \r\n sequence, - return only the \n as a newline - */ - if (c == '\r' && *reader->read_ptr == '\n') { - reader->read_ptr++; - c = '\n'; - } - - if (c == '\n') - reader->line_number++; - - if (c == 0) { - reader->eof = 1; - c = '\0'; - } - - return c; -} - -#define SKIP_WHITESPACE (1 << 1) -#define SKIP_COMMENTS (1 << 2) - -static int reader_getchar(git_config_parser *reader, int flags) -{ - const int skip_whitespace = (flags & SKIP_WHITESPACE); - const int skip_comments = (flags & SKIP_COMMENTS); - int c; - - assert(reader->read_ptr); - - do { - c = reader_getchar_raw(reader); - } while (c != '\n' && c != '\0' && skip_whitespace && git__isspace(c)); - - if (skip_comments && (c == '#' || c == ';')) { - do { - c = reader_getchar_raw(reader); - } while (c != '\n' && c != '\0'); - } - - return c; -} - -/* - * Read the next char, but don't move the reading pointer. - */ -static int reader_peek(git_config_parser *reader, int flags) -{ - void *old_read_ptr; - int old_lineno, old_eof; - int ret; - - assert(reader->read_ptr); - - old_read_ptr = reader->read_ptr; - old_lineno = reader->line_number; - old_eof = reader->eof; - - ret = reader_getchar(reader, flags); - - reader->read_ptr = old_read_ptr; - reader->line_number = old_lineno; - reader->eof = old_eof; - - return ret; -} - -/* - * Read and consume a line, returning it in newly-allocated memory. - */ -static char *reader_readline(git_config_parser *reader, bool skip_whitespace) -{ - char *line = NULL; - char *line_src, *line_end; - size_t line_len, alloc_len; - - line_src = reader->read_ptr; - - if (skip_whitespace) { - /* Skip empty empty lines */ - while (git__isspace(*line_src)) - ++line_src; - } - - line_end = strchr(line_src, '\n'); - - /* no newline at EOF */ - if (line_end == NULL) - line_end = strchr(line_src, 0); - - line_len = line_end - line_src; - - if (GIT_ADD_SIZET_OVERFLOW(&alloc_len, line_len, 1) || - (line = git__malloc(alloc_len)) == NULL) { - return NULL; - } - - memcpy(line, line_src, line_len); - - do line[line_len] = '\0'; - while (line_len-- > 0 && git__isspace(line[line_len])); - - if (*line_end == '\n') - line_end++; - - if (*line_end == '\0') - reader->eof = 1; - - reader->line_number++; - reader->read_ptr = line_end; - - return line; -} - -/* - * Consume a line, without storing it anywhere - */ -static void reader_consume_line(git_config_parser *reader) -{ - char *line_start, *line_end; - - line_start = reader->read_ptr; - line_end = strchr(line_start, '\n'); - /* No newline at EOF */ - if(line_end == NULL){ - line_end = strchr(line_start, '\0'); - } - - if (*line_end == '\n') - line_end++; - - if (*line_end == '\0') - reader->eof = 1; - - reader->line_number++; - reader->read_ptr = line_end; -} GIT_INLINE(int) config_keychar(int c) { @@ -295,7 +151,8 @@ static int parse_section_header(git_config_parser *reader, char **section_out) char *line; size_t line_len; - line = reader_readline(reader, true); + git_parse_advance_ws(&reader->ctx); + line = git__strndup(reader->ctx.line, reader->ctx.line_len); if (line == NULL) return -1; @@ -356,14 +213,14 @@ fail_parse: return -1; } -static int skip_bom(git_config_parser *reader) +static int skip_bom(git_parse_ctx *parser) { + git_buf buf = GIT_BUF_INIT_CONST(parser->content, parser->content_len); git_bom_t bom; - int bom_offset = git_buf_text_detect_bom(&bom, - &reader->buffer, reader->read_ptr - reader->buffer.ptr); + int bom_offset = git_buf_text_detect_bom(&bom, &buf, parser->content_len); if (bom == GIT_BOM_UTF8) - reader->read_ptr += bom_offset; + git_parse_advance_chars(parser, bom_offset); /* TODO: reference implementation is pretty stupid with BoM */ @@ -463,7 +320,8 @@ static int parse_multiline_variable(git_config_parser *reader, git_buf *value, i bool multiline; /* Check that the next line exists */ - line = reader_readline(reader, false); + git_parse_advance_line(&reader->ctx); + line = git__strndup(reader->ctx.line, reader->ctx.line_len); if (line == NULL) return -1; @@ -550,7 +408,8 @@ static int parse_variable(git_config_parser *reader, char **var_name, char **var int quote_count; bool multiline; - line = reader_readline(reader, true); + git_parse_advance_ws(&reader->ctx); + line = git__strndup(reader->ctx.line, reader->ctx.line_len); if (line == NULL) return -1; @@ -603,56 +462,58 @@ int git_config_parse( git_config_parser_eof_cb on_eof, void *data) { - char *current_section = NULL, *var_name, *var_value, *line_start; - char c; - size_t line_len; + git_parse_ctx *ctx; + char *current_section = NULL, *var_name, *var_value; int result = 0; - skip_bom(parser); + ctx = &parser->ctx; - while (result == 0 && !parser->eof) { - line_start = parser->read_ptr; + skip_bom(ctx); - c = reader_peek(parser, SKIP_WHITESPACE); + for (; ctx->remain_len > 0; git_parse_advance_line(ctx)) { + const char *line_start = parser->ctx.line; + size_t line_len = parser->ctx.line_len; + char c; - switch (c) { - case '\0': /* EOF when peeking, set EOF in the parser to exit the loop */ - parser->eof = 1; - break; + if (git_parse_peek(&c, ctx, GIT_PARSE_PEEK_SKIP_WHITESPACE) < 0 && + git_parse_peek(&c, ctx, 0) < 0) + continue; + switch (c) { case '[': /* section header, new section begins */ git__free(current_section); current_section = NULL; if ((result = parse_section_header(parser, ¤t_section)) == 0 && on_section) { - line_len = parser->read_ptr - line_start; result = on_section(parser, current_section, line_start, line_len, data); } break; case '\n': /* comment or whitespace-only */ + case ' ': + case '\t': case ';': case '#': - reader_consume_line(parser); - if (on_comment) { - line_len = parser->read_ptr - line_start; result = on_comment(parser, line_start, line_len, data); } break; default: /* assume variable declaration */ if ((result = parse_variable(parser, &var_name, &var_value)) == 0 && on_variable) { - line_len = parser->read_ptr - line_start; result = on_variable(parser, current_section, var_name, var_value, line_start, line_len, data); } break; } + + if (result < 0) + goto out; } if (on_eof) result = on_eof(parser, current_section, data); +out: git__free(current_section); return result; } diff --git a/src/config_parse.h b/src/config_parse.h index a3d53d2ae..6c1863952 100644 --- a/src/config_parse.h +++ b/src/config_parse.h @@ -8,6 +8,7 @@ #include "common.h" #include "array.h" #include "oid.h" +#include "parse.h" static const char *git_config_escapes = "ntb\"\\"; static const char *git_config_escaped = "\n\t\b\"\\"; @@ -20,10 +21,7 @@ typedef struct config_file { typedef struct { struct config_file *file; - git_buf buffer; - char *read_ptr; - int line_number; - int eof; + git_parse_ctx ctx; } git_config_parser; typedef int (*git_config_parser_section_cb)( |
