summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2011-05-16 09:18:04 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2011-05-16 09:21:25 (GMT)
commitaa31497d9f0a3e96801d3752dd2d8f4ea20a2f4c (patch) (side-by-side diff)
tree3bdf880ec5c4bd2c97d7d7ff665e13a7ca4b0a76
parent8eb1be8941228d01438436b53dd46b422ba980a3 (diff)
downloadgrecs-aa31497d9f0a3e96801d3752dd2d8f4ea20a2f4c.tar.gz
grecs-aa31497d9f0a3e96801d3752dd2d8f4ea20a2f4c.tar.bz2
Implement parser for git-style config files.
* am/grecs.m4: New option: parser-git * doc/GRECS_SETUP.3: Document new options. * src/git-parser.c: New file. * src/Make.am [GRECS_COND_GIT_PARSER]: Define GRECS_PARSER_GIT. (GRECS_SRC): Add GRECS_PARSER_GIT. * src/grecs.h (grecs_git_parser): New proto. * src/txtacc.c (grecs_txtacc_free): Ignore NULL argument.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--am/grecs.m44
-rw-r--r--doc/GRECS_SETUP.38
-rw-r--r--src/Make.am5
-rw-r--r--src/git-parser.c297
-rw-r--r--src/grecs.h1
-rw-r--r--src/txtacc.c8
6 files changed, 319 insertions, 4 deletions
diff --git a/am/grecs.m4 b/am/grecs.m4
index 9685bca..5611e04 100644
--- a/am/grecs.m4
+++ b/am/grecs.m4
@@ -156,6 +156,10 @@ AC_DEFUN([GRECS_SETUP],[
_GRECS_OPTION_SWITCH([parser-bind],[true],
[all-parsers],[true],
[false]))
+ AM_CONDITIONAL([GRECS_COND_GIT_PARSER],
+ _GRECS_OPTION_SWITCH([parser-git],[true],
+ [all-parsers],[true],
+ [false]))
AC_SUBST([GRECS_SRCDIR],$1)
AC_SUBST([GRECS_BUILD_AUX])
AC_SUBST([GRECS_INCLUDES])
diff --git a/doc/GRECS_SETUP.3 b/doc/GRECS_SETUP.3
index 13b568e..58d1ebe 100644
--- a/doc/GRECS_SETUP.3
+++ b/doc/GRECS_SETUP.3
@@ -14,7 +14,7 @@
.\" You should have received a copy of the GNU General Public License
.\" along with Grecs. If not, see <http://www.gnu.org/licenses/>.
.\"
-.TH GRECS_SETUP 3 "May 15, 2011" "GRECS" "Grecs User Reference"
+.TH GRECS_SETUP 3 "May 16, 2011" "GRECS" "Grecs User Reference"
.SH NAME
GRECS_SETUP \- Initialize \fBgrecs\fR submodule.
.SH SYNOPSIS
@@ -47,6 +47,12 @@ are understood:
.B all-parsers
Compile all available parsers.
.TP
+.B parser-bind
+Build the parser for BIND configuration files.
+.TP
+.B parser-git
+Build the parser for GIT-style configuration files.
+.TP
.B parser-meta1
Build the parser for MeTA1 configuration files.
.TP
diff --git a/src/Make.am b/src/Make.am
index e05afc5..312c734 100644
--- a/src/Make.am
+++ b/src/Make.am
@@ -24,6 +24,10 @@ if GRECS_COND_BIND_PARSER
GRECS_EXTRA_BIND = bind-gram.h
endif
+if GRECS_COND_GIT_PARSER
+ GRECS_PARSER_GIT = git-parser.c
+endif
+
GRECS_SRC = \
asprintf.c\
diag.c\
@@ -45,6 +49,7 @@ GRECS_SRC = \
version.c\
wordsplit.c\
$(GRECS_PARSER_BIND)\
+ $(GRECS_PARSER_GIT)\
$(GRECS_PARSER_META1)
noinst_HEADERS =
diff --git a/src/git-parser.c b/src/git-parser.c
new file mode 100644
index 0000000..e0675ef
--- a/dev/null
+++ b/src/git-parser.c
@@ -0,0 +1,297 @@
+/* Git-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 FILE *infile;
+static int input_char;
+static struct grecs_txtacc *acc;
+
+#define TOK_EOF 0
+#define TOK_EQ '='
+#define TOK_SECTION 256
+#define TOK_KEYWORD 257
+#define TOK_VALUE 258
+#define TOK_ERR -1
+
+struct token {
+ int type;
+ char *buf;
+ char *tag;
+ char chbuf[2];
+ int putback;
+} tok;
+
+#define ISSPACE(c) (strchr(" \t\r\f\n", c) != NULL)
+#define ISIDENT(c) ((isascii(c) && isalnum(c)) || (c) == '_')
+#define ISINITIAL(c) ((isascii(c) && isalpha(c)) || (c) == '_')
+
+static int
+input()
+{
+ if (!infile || feof(infile))
+ return 0;
+ input_char = fgetc(infile);
+ if (input_char == '\n')
+ grecs_current_locus.line++;
+ return input_char;
+}
+
+static void
+unput()
+{
+ if (!input_char)
+ return;
+ if (input_char == '\n')
+ grecs_current_locus.line--;
+ ungetc(input_char, infile);
+}
+
+static void
+error_recovery()
+{
+ while (input() && input_char != '\n')
+ ;
+}
+
+static void
+collect_tag()
+{
+ while (input() &&
+ !(ISSPACE(input_char) || input_char == ']'))
+ grecs_txtacc_grow_char(acc, input_char);
+ grecs_txtacc_grow_char(acc, 0);
+ tok.tag = grecs_txtacc_finish(acc, 0);
+}
+
+static void
+collect_string()
+{
+ while (input()) {
+ if (input_char == '\\') {
+ if (!input()) {
+ grecs_error(&grecs_current_locus, 0,
+ "unexpected EOF in string");
+ break;
+ }
+ } else if (input_char == '"')
+ break;
+ grecs_txtacc_grow_char(acc, input_char);
+ }
+ grecs_txtacc_grow_char(acc, 0);
+ tok.tag = grecs_txtacc_finish(acc, 0);
+}
+
+static void
+gettoken(void)
+{
+ int putback = tok.putback;
+ tok.putback = 0;
+ if (putback)
+ return;
+
+ tok.buf = tok.tag = NULL;
+ /* Skip whitespace */
+ while (input() && ISSPACE(input_char))
+ ;
+
+ if (input_char <= 0) {
+ tok.type = TOK_EOF;
+ return;
+ }
+
+ if (input_char == '[') {
+ 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);
+ tok.type = TOK_ERR;
+ }
+ }
+ return;
+ }
+
+ if (ISINITIAL(input_char)) {
+ tok.type = TOK_KEYWORD;
+ do
+ grecs_txtacc_grow_char(acc, input_char);
+ while (input() && ISIDENT(input_char));
+ unput();
+ grecs_txtacc_grow_char(acc, 0);
+ tok.buf = grecs_txtacc_finish(acc, 0);
+ return;
+ }
+
+ tok.chbuf[0] = input_char;
+ tok.chbuf[1] = 0;
+ tok.buf = tok.chbuf;
+ tok.type = input_char;
+}
+
+static struct grecs_value *
+getvalue()
+{
+ int len;
+ struct grecs_value *val = grecs_malloc(sizeof(*val));
+ while (input() && ISSPACE(input_char) && input_char != '\n')
+ ;
+ if (input_char != '\n')
+ do
+ grecs_txtacc_grow_char(acc, input_char);
+ while (input() && input_char != '\n');
+ grecs_txtacc_grow_char(acc, 0);
+ tok.type = TOK_VALUE;
+ tok.buf = grecs_txtacc_finish(acc, 1);
+ len = strlen(tok.buf);
+ while (len > 0 && ISSPACE(tok.buf[len-1]))
+ tok.buf[--len] = 0;
+ val->type = GRECS_TYPE_STRING;
+ val->v.string = tok.buf;
+ return val;
+}
+
+static int
+read_statement(struct grecs_node *parent)
+{
+ struct grecs_node *node;
+
+ gettoken();
+ if (tok.type == TOK_EOF || tok.type == TOK_SECTION) {
+ tok.putback = 1;
+ return 0;
+ }
+ if (tok.type != TOK_KEYWORD) {
+ grecs_error(&grecs_current_locus, 0, "syntax error");
+ error_recovery();
+ return 1;
+ }
+
+ node = grecs_node_create(grecs_node_stmt, &grecs_current_locus);
+ node->ident = grecs_strdup(tok.buf);
+
+ gettoken();
+ if (tok.type == TOK_EOF) {
+ grecs_error(&grecs_current_locus, 0, "unexpected EOF");
+ grecs_node_free(node);
+ return 0;
+ }
+ if (tok.type != TOK_EQ) {
+ grecs_error(&grecs_current_locus, 0,
+ "expected `=', but found `%s'", tok.buf);
+ error_recovery();
+ grecs_node_free(node);
+ return 1;
+ }
+ node->v.value = getvalue();
+ grecs_node_bind(parent, node, 1);
+ return 1;
+}
+
+static void
+read_statement_list(struct grecs_node *parent)
+{
+ while (read_statement(parent))
+ ;
+}
+
+static int
+read_section(struct grecs_node *parent)
+{
+ gettoken();
+ 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);
+ read_statement_list(node);
+ } else if (tok.type == TOK_KEYWORD) {
+ read_statement(parent);
+ } else {
+ grecs_error(&grecs_current_locus, 0, "syntax error");
+ error_recovery();
+ }
+ return 1;
+}
+
+/* FIXME: traceflags not used */
+struct grecs_node *
+grecs_git_parser(const char *name, int traceflags)
+{
+ struct grecs_node *root;
+
+ 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 = 1;
+
+ acc = grecs_txtacc_create();
+
+ root = grecs_node_create(grecs_node_root, &grecs_current_locus);
+
+ while (read_section(root))
+ ;
+ fclose(infile);
+ grecs_txtacc_free(acc);
+ if (grecs_error_count) {
+ grecs_tree_free(root);
+ root = NULL;
+ }
+ return root;
+}
diff --git a/src/grecs.h b/src/grecs.h
index 48b53ae..b839d71 100644
--- a/src/grecs.h
+++ b/src/grecs.h
@@ -218,6 +218,7 @@ extern struct grecs_node *(*grecs_parser_fun)(const char *name, int trace);
struct grecs_node *grecs_grecs_parser(const char *name, int traceflags);
struct grecs_node *grecs_meta1_parser(const char *name, int traceflags);
struct grecs_node *grecs_bind_parser(const char *name, int traceflags);
+struct grecs_node *grecs_git_parser(const char *name, int traceflags);
struct grecs_list *_grecs_simple_list_create(int dispose);
diff --git a/src/txtacc.c b/src/txtacc.c
index ff13e42..5ff9ec6 100644
--- a/src/txtacc.c
+++ b/src/txtacc.c
@@ -105,9 +105,11 @@ grecs_txtacc_create()
void
grecs_txtacc_free(struct grecs_txtacc *acc)
{
- grecs_list_free (acc->cur);
- grecs_list_free (acc->mem);
- free (acc);
+ if (acc) {
+ grecs_list_free (acc->cur);
+ grecs_list_free (acc->mem);
+ free (acc);
+ }
}
void

Return to:

Send suggestions and report system problems to the System administrator.