aboutsummaryrefslogtreecommitdiff
path: root/src/path-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/path-parser.c')
-rw-r--r--src/path-parser.c172
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;
}

Return to:

Send suggestions and report system problems to the System administrator.