diff options
Diffstat (limited to 'src/path-parser.c')
-rw-r--r-- | src/path-parser.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/path-parser.c b/src/path-parser.c new file mode 100644 index 0000000..c66f8ca --- /dev/null +++ b/src/path-parser.c @@ -0,0 +1,124 @@ +/* Path-style configuration file parser for Grecs. + Copyright (C) 2011 Sergey Poznyakoff + + Grecs is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + Grecs is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with Grecs. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <grecs.h> + +static size_t +trimnl(char *buf) +{ + size_t len = strlen(buf); + + if (len && buf[len-1] == '\n') { + buf[--len] = 0; + if (len && buf[len-1] == '\r') + buf[--len] = 0; + } + return len; +} + +struct grecs_node * +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; + + 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; + + 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; + } + 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; + } + + while (*ptr && (*ptr == ' ' || *ptr == '\t')) + ptr++; + if (!*ptr || *ptr == '#') + continue; + inquote = 0; + for (p = ptr; *p && *p != ':'; p++) { + if (inquote) { + if (inquote == '"' && *p == '\\') + p++; + else if (*p == inquote) + inquote = 0; + } else if (*p == '\'' || *p == '"') + inquote = *p; + } + if (!*p) { + grecs_error(&grecs_current_locus, 0, + _("syntax error")); + continue; + } + *p++ = 0; + while (*p && (*p == ' ' || *p == '\t')) + p++; + + node = grecs_node_from_path_locus(ptr, p, + &grecs_current_locus); + if (!subtree) + subtree = node; + else + grecs_node_bind(subtree, node, 0); + } + + 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); + + return root; +} + |