diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/git-parser.c | 157 |
1 files changed, 102 insertions, 55 deletions
diff --git a/src/git-parser.c b/src/git-parser.c index 37eeab7..4ab64be 100644 --- a/src/git-parser.c +++ b/src/git-parser.c @@ -37,9 +37,9 @@ static struct grecs_txtacc *acc; struct token { int type; char *buf; - char *tag; char chbuf[2]; int putback; + struct grecs_list *path; } tok; #define ISSPACE(c) (strchr(" \t\r\f\n", c) != NULL) @@ -50,10 +50,12 @@ static int rawinput() { if (!infile || feof(infile)) - return 0; + return input_char = 0; input_char = fgetc(infile); if (input_char == '\n') grecs_current_locus.line++; + else if (input_char < 0) + input_char == 0; return input_char; } @@ -86,13 +88,23 @@ error_recovery() } static void -collect_tag() +collect_unquoted() { + do + grecs_txtacc_grow_char(acc, input_char); while (input() && - !(ISSPACE(input_char) || input_char == ']')) + !(ISSPACE(input_char) || input_char == ']')); + +} + +static void +collect_subsection_name() +{ + do grecs_txtacc_grow_char(acc, input_char); - grecs_txtacc_grow_char(acc, 0); - tok.tag = grecs_txtacc_finish(acc, 0); + while (input() && + (isalnum(input_char) || input_char == '_' || + input_char == '-')); } static void @@ -122,14 +134,6 @@ collect_substring() } static void -collect_string() -{ - collect_substring(); - grecs_txtacc_grow_char(acc, 0); - tok.tag = grecs_txtacc_finish(acc, 0); -} - -static void gettoken(void) { int putback = tok.putback; @@ -137,7 +141,7 @@ gettoken(void) if (putback) return; - tok.buf = tok.tag = NULL; + tok.buf = NULL; /* Skip whitespace */ while (input() && ISSPACE(input_char)) ; @@ -148,38 +152,70 @@ gettoken(void) } if (input_char == '[') { + int dot_delimited = -1; + tok.type = TOK_SECTION; - while (input() && - !(ISSPACE(input_char) || input_char == ']')) - grecs_txtacc_grow_char(acc, input_char); - grecs_txtacc_grow_char(acc, 0); - tok.buf = grecs_txtacc_finish(acc, 0); - if (input_char != ']') { - while (input() && ISSPACE(input_char)) - ; - if (input_char == '"') - collect_string(); - else if (input_char != ']') - collect_tag(); - } - if (input_char != ']') { - while (input() && ISSPACE(input_char)) - ; - if (input_char != ']') { - if (isascii(input_char) && isprint(input_char)) - grecs_error(&grecs_current_locus, 0, - "expected `]' but found `%c'", - input_char); - else if (!input_char) - grecs_error(&grecs_current_locus, 0, - "expected `]' but found EOF"); - else - grecs_error(&grecs_current_locus, 0, - "expected `]' but found \\%03o", - (unsigned char)input_char); + grecs_list_clear(tok.path); + input(); + for (;;) { + char *p; + + if (!dot_delimited) + while (ISSPACE(input_char)) + input(); + else { + if (input_char == ']') + break; + if (dot_delimited == 1) + input(); + } + + if (input_char == TOK_EOF) { + grecs_error(&grecs_current_locus, 0, + "unexpected EOF in section header"); + tok.type = TOK_ERR; + return; + } + if (input_char == ']') + break; + if (input_char == '\n') { + grecs_error(&grecs_current_locus, 0, + "unexpect newline in in section header"); tok.type = TOK_ERR; + return; } + + if (dot_delimited != 1 && input_char == '"') { + collect_substring(); + input(); + dot_delimited = 0; + } else if (dot_delimited == 1) + collect_subsection_name(); + else + collect_unquoted(); + if (dot_delimited == -1) + dot_delimited = input_char == '.'; + else if (dot_delimited == 1) { + if (input_char != '.' && input_char != ']') { + grecs_error(&grecs_current_locus, 0, + "unexpected character in section header"); + tok.type = TOK_ERR; + return; + } + } + grecs_txtacc_grow_char(acc, 0); + p = grecs_txtacc_finish(acc, 0); + grecs_list_append(tok.path, p); + } + + if (grecs_list_size(tok.path) == 0) { + grecs_error(&grecs_current_locus, 0, + "empty section header"); + tok.type = TOK_ERR; + return; } + + tok.type = TOK_SECTION; return; } @@ -293,6 +329,26 @@ read_statement_list(struct grecs_node *parent) ; } +struct grecs_node * +create_subsection_node(struct grecs_node *root) +{ + struct grecs_list_entry *ep; + struct grecs_node *p; + + for (ep = tok.path->head; ep; ep = ep->next) { + char *ident = ep->data; + p = grecs_find_node(root, ident); + if (!p) { + p = grecs_node_create(grecs_node_block, + &grecs_current_locus); + p->ident = grecs_strdup(ident); + grecs_node_bind(root, p, 1); + } + root = p; + } + return root; +} + static int read_section(struct grecs_node *parent) { @@ -300,17 +356,7 @@ read_section(struct grecs_node *parent) if (tok.type == TOK_EOF) return 0; else if (tok.type == TOK_SECTION) { - struct grecs_node *node = - grecs_node_create(grecs_node_block, - &grecs_current_locus); - node->ident = grecs_strdup(tok.buf); - if (tok.tag) { - struct grecs_value *val= grecs_malloc(sizeof(val[0])); - val->type = GRECS_TYPE_STRING; - val->v.string = grecs_strdup(tok.tag); - node->v.value = val; - } - grecs_node_bind(parent, node, 1); + struct grecs_node *node = create_subsection_node(parent); read_statement_list(node); } else if (tok.type == TOK_KEYWORD) { read_statement(parent); @@ -336,13 +382,14 @@ grecs_git_parser(const char *name, int traceflags) grecs_current_locus.line = 1; acc = grecs_txtacc_create(); - + tok.path = grecs_list_create(); root = grecs_node_create(grecs_node_root, &grecs_current_locus); while (read_section(root)) ; fclose(infile); grecs_txtacc_free(acc); + grecs_list_free(tok.path); if (grecs_error_count) { grecs_tree_free(root); root = NULL; |