diff options
Diffstat (limited to 'src/path-parser.c')
-rw-r--r-- | src/path-parser.c | 172 |
1 files changed, 111 insertions, 61 deletions
diff --git a/src/path-parser.c b/src/path-parser.c index c66f8ca..f42ac60 100644 --- a/src/path-parser.c +++ b/src/path-parser.c @@ -23,17 +23,25 @@ #include <errno.h> #include <grecs.h> -static size_t -trimnl(char *buf) +static int +next_char(FILE *infile) { - size_t len = strlen(buf); - - if (len && buf[len-1] == '\n') { - buf[--len] = 0; - if (len && buf[len-1] == '\r') - buf[--len] = 0; + int c = fgetc(infile); + if (c == '\n') + grecs_locus_point_advance_line(grecs_current_locus_point); + else { + grecs_current_locus_point.col++; + if (c == '\\') { + int nc = fgetc(infile); + if (nc == '\n') { + grecs_locus_point_advance_line(grecs_current_locus_point); + c = fgetc(infile); + grecs_current_locus_point.col++; + } else + ungetc(nc, infile); + } } - return len; + return c; } struct grecs_node * @@ -41,84 +49,126 @@ grecs_path_parser(const char *name, int traceflags) { struct grecs_node *root, *subtree = NULL, *node; FILE *infile; - char *buf = NULL; - size_t size = 0; struct grecs_txtacc *acc = NULL; - char *prevptr = NULL; - char *ptr, *p; - int inquote, cont = 0; + char *kw, *val; + grecs_locus_t kwloc, valloc, rootloc; + int inquote; + int lookahead; + int err = 0; + unsigned prev_col; infile = fopen(name, "r"); if (!infile) { grecs_error(NULL, errno, _("cannot open `%s'"), name); return NULL; } - grecs_current_locus.file = grecs_install_text(name); - grecs_current_locus.line = 0; + grecs_current_locus_point.file = grecs_install_text(name); + grecs_current_locus_point.line = 1; + grecs_current_locus_point.col = 0; + rootloc.beg = grecs_current_locus_point; + rootloc.beg.col++; + + acc = grecs_txtacc_create(); - while (grecs_getline(&buf, &size, infile) >= 0) { - size_t len; - - ++grecs_current_locus.line; - len = trimnl(buf); - if (len && buf[len-1] == '\\') { - if (!acc) - acc = grecs_txtacc_create(); - else if (prevptr) { - grecs_txtacc_free_string(acc, prevptr); - prevptr = NULL; + while ((lookahead = next_char(infile)) > 0) { + while (1) { + while (lookahead == ' ' || lookahead == '\t') + lookahead = next_char(infile); + + if (lookahead == '#') { + while ((lookahead = next_char(infile)) && + lookahead != '\n') + ; + continue; } - grecs_txtacc_grow(acc, buf, len - 1); - cont = 1; - continue; - } else { - if (cont) - ptr = prevptr = grecs_txtacc_finish(acc, 0); - else - ptr = buf; - cont = 0; + break; } + + if (lookahead <= 0) + break; + + kwloc.beg = grecs_current_locus_point; - while (*ptr && (*ptr == ' ' || *ptr == '\t')) - ptr++; - if (!*ptr || *ptr == '#') - continue; inquote = 0; - for (p = ptr; *p && *p != ':'; p++) { + for (; lookahead > 0 && lookahead != ':'; + lookahead = next_char(infile)) { if (inquote) { - if (inquote == '"' && *p == '\\') - p++; - else if (*p == inquote) + if (inquote == '"' && lookahead == '\\') { + lookahead = next_char(infile); + if (lookahead <= 0) + break; + } else if (lookahead == inquote) inquote = 0; - } else if (*p == '\'' || *p == '"') - inquote = *p; + } else if (lookahead == '\'' || lookahead == '"') + inquote = lookahead; + grecs_txtacc_grow_char(acc, lookahead); } - if (!*p) { - grecs_error(&grecs_current_locus, 0, - _("syntax error")); - continue; + + if (lookahead <= 0) { + grecs_error(&kwloc, 0, _("unexpected end of file")); + err = 1; + break; } - *p++ = 0; - while (*p && (*p == ' ' || *p == '\t')) - p++; + + grecs_txtacc_grow_char(acc, 0); + kw = grecs_txtacc_finish(acc, 0); + + kwloc.end = grecs_current_locus_point; + kwloc.end.col--; + + while ((lookahead = next_char(infile)) > 0 && + (lookahead == ' ' || lookahead == '\t')); + + if (lookahead <= 0) { + grecs_error(&kwloc, 0, _("unexpected end of file")); + err = 1; + break; + } + + valloc.beg = grecs_current_locus_point; + do { + grecs_txtacc_grow_char(acc, lookahead); + prev_col = grecs_current_locus_point.col; + } while ((lookahead = next_char(infile)) > 0 && + lookahead != '\n'); + valloc.end = grecs_current_locus_point; + valloc.end.line--; + valloc.end.col = prev_col; + + grecs_txtacc_grow_char(acc, 0); + val = grecs_txtacc_finish(acc, 0); + + node = grecs_node_from_path_locus(kw, val, &kwloc, &valloc); + if (!node) { + grecs_error(&kwloc, 0, _("parse error")); + err = 1; + break; + } + node->locus.end = valloc.end; + node->idloc = kwloc; - node = grecs_node_from_path_locus(ptr, p, - &grecs_current_locus); if (!subtree) subtree = node; else grecs_node_bind(subtree, node, 0); + grecs_txtacc_free_string(acc, kw); + grecs_txtacc_free_string(acc, val); } fclose(infile); - free(buf); grecs_txtacc_free(acc); - root = grecs_node_create(grecs_node_root, &grecs_current_locus); - root->v.texttab = grecs_text_table(); - grecs_node_bind(root, subtree, 1); - grecs_tree_reduce(root, NULL, 0); - + if (err) { + grecs_tree_free(subtree); + root = NULL; + } else { + rootloc.end = grecs_current_locus_point; + root = grecs_node_create(grecs_node_root, &rootloc); + root->v.texttab = grecs_text_table(); + grecs_node_bind(root, subtree, 1); + grecs_tree_reduce(root, NULL, 0); + } + return root; } |