aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-05-16 12:18:04 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-05-16 12:21:25 +0300
commitaa31497d9f0a3e96801d3752dd2d8f4ea20a2f4c (patch)
tree3bdf880ec5c4bd2c97d7d7ff665e13a7ca4b0a76 /src
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 (limited to 'src')
-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
4 files changed, 308 insertions, 3 deletions
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
24 GRECS_EXTRA_BIND = bind-gram.h 24 GRECS_EXTRA_BIND = bind-gram.h
25endif 25endif
26 26
27if GRECS_COND_GIT_PARSER
28 GRECS_PARSER_GIT = git-parser.c
29endif
30
27GRECS_SRC = \ 31GRECS_SRC = \
28 asprintf.c\ 32 asprintf.c\
29 diag.c\ 33 diag.c\
@@ -45,6 +49,7 @@ GRECS_SRC = \
45 version.c\ 49 version.c\
46 wordsplit.c\ 50 wordsplit.c\
47 $(GRECS_PARSER_BIND)\ 51 $(GRECS_PARSER_BIND)\
52 $(GRECS_PARSER_GIT)\
48 $(GRECS_PARSER_META1) 53 $(GRECS_PARSER_META1)
49 54
50noinst_HEADERS = 55noinst_HEADERS =
diff --git a/src/git-parser.c b/src/git-parser.c
new file mode 100644
index 0000000..e0675ef
--- /dev/null
+++ b/src/git-parser.c
@@ -0,0 +1,297 @@
1/* Git-style configuration file parser for Grecs.
2 Copyright (C) 2011 Sergey Poznyakoff
3
4 Grecs is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 Grecs is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with Grecs. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdlib.h>
21#include <string.h>
22#include <ctype.h>
23#include <errno.h>
24#include <grecs.h>
25
26static FILE *infile;
27static int input_char;
28static struct grecs_txtacc *acc;
29
30#define TOK_EOF 0
31#define TOK_EQ '='
32#define TOK_SECTION 256
33#define TOK_KEYWORD 257
34#define TOK_VALUE 258
35#define TOK_ERR -1
36
37struct token {
38 int type;
39 char *buf;
40 char *tag;
41 char chbuf[2];
42 int putback;
43} tok;
44
45#define ISSPACE(c) (strchr(" \t\r\f\n", c) != NULL)
46#define ISIDENT(c) ((isascii(c) && isalnum(c)) || (c) == '_')
47#define ISINITIAL(c) ((isascii(c) && isalpha(c)) || (c) == '_')
48
49static int
50input()
51{
52 if (!infile || feof(infile))
53 return 0;
54 input_char = fgetc(infile);
55 if (input_char == '\n')
56 grecs_current_locus.line++;
57 return input_char;
58}
59
60static void
61unput()
62{
63 if (!input_char)
64 return;
65 if (input_char == '\n')
66 grecs_current_locus.line--;
67 ungetc(input_char, infile);
68}
69
70static void
71error_recovery()
72{
73 while (input() && input_char != '\n')
74 ;
75}
76
77static void
78collect_tag()
79{
80 while (input() &&
81 !(ISSPACE(input_char) || input_char == ']'))
82 grecs_txtacc_grow_char(acc, input_char);
83 grecs_txtacc_grow_char(acc, 0);
84 tok.tag = grecs_txtacc_finish(acc, 0);
85}
86
87static void
88collect_string()
89{
90 while (input()) {
91 if (input_char == '\\') {
92 if (!input()) {
93 grecs_error(&grecs_current_locus, 0,
94 "unexpected EOF in string");
95 break;
96 }
97 } else if (input_char == '"')
98 break;
99 grecs_txtacc_grow_char(acc, input_char);
100 }
101 grecs_txtacc_grow_char(acc, 0);
102 tok.tag = grecs_txtacc_finish(acc, 0);
103}
104
105static void
106gettoken(void)
107{
108 int putback = tok.putback;
109 tok.putback = 0;
110 if (putback)
111 return;
112
113 tok.buf = tok.tag = NULL;
114 /* Skip whitespace */
115 while (input() && ISSPACE(input_char))
116 ;
117
118 if (input_char <= 0) {
119 tok.type = TOK_EOF;
120 return;
121 }
122
123 if (input_char == '[') {
124 tok.type = TOK_SECTION;
125 while (input() &&
126 !(ISSPACE(input_char) || input_char == ']'))
127 grecs_txtacc_grow_char(acc, input_char);
128 grecs_txtacc_grow_char(acc, 0);
129 tok.buf = grecs_txtacc_finish(acc, 0);
130 if (input_char != ']') {
131 while (input() && ISSPACE(input_char))
132 ;
133 if (input_char == '"')
134 collect_string();
135 else if (input_char != ']')
136 collect_tag();
137 }
138 if (input_char != ']') {
139 while (input() && ISSPACE(input_char))
140 ;
141 if (input_char != ']') {
142 if (isascii(input_char) && isprint(input_char))
143 grecs_error(&grecs_current_locus, 0,
144 "expected `]' but found `%c'",
145 input_char);
146 else if (!input_char)
147 grecs_error(&grecs_current_locus, 0,
148 "expected `]' but found EOF");
149 else
150 grecs_error(&grecs_current_locus, 0,
151 "expected `]' but found \\%03o",
152 (unsigned char)input_char);
153 tok.type = TOK_ERR;
154 }
155 }
156 return;
157 }
158
159 if (ISINITIAL(input_char)) {
160 tok.type = TOK_KEYWORD;
161 do
162 grecs_txtacc_grow_char(acc, input_char);
163 while (input() && ISIDENT(input_char));
164 unput();
165 grecs_txtacc_grow_char(acc, 0);
166 tok.buf = grecs_txtacc_finish(acc, 0);
167 return;
168 }
169
170 tok.chbuf[0] = input_char;
171 tok.chbuf[1] = 0;
172 tok.buf = tok.chbuf;
173 tok.type = input_char;
174}
175
176static struct grecs_value *
177getvalue()
178{
179 int len;
180 struct grecs_value *val = grecs_malloc(sizeof(*val));
181 while (input() && ISSPACE(input_char) && input_char != '\n')
182 ;
183 if (input_char != '\n')
184 do
185 grecs_txtacc_grow_char(acc, input_char);
186 while (input() && input_char != '\n');
187 grecs_txtacc_grow_char(acc, 0);
188 tok.type = TOK_VALUE;
189 tok.buf = grecs_txtacc_finish(acc, 1);
190 len = strlen(tok.buf);
191 while (len > 0 && ISSPACE(tok.buf[len-1]))
192 tok.buf[--len] = 0;
193 val->type = GRECS_TYPE_STRING;
194 val->v.string = tok.buf;
195 return val;
196}
197
198static int
199read_statement(struct grecs_node *parent)
200{
201 struct grecs_node *node;
202
203 gettoken();
204 if (tok.type == TOK_EOF || tok.type == TOK_SECTION) {
205 tok.putback = 1;
206 return 0;
207 }
208 if (tok.type != TOK_KEYWORD) {
209 grecs_error(&grecs_current_locus, 0, "syntax error");
210 error_recovery();