diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-16 12:18:04 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-05-16 12:21:25 +0300 |
commit | aa31497d9f0a3e96801d3752dd2d8f4ea20a2f4c (patch) | |
tree | 3bdf880ec5c4bd2c97d7d7ff665e13a7ca4b0a76 /src | |
parent | 8eb1be8941228d01438436b53dd46b422ba980a3 (diff) | |
download | grecs-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.am | 5 | ||||
-rw-r--r-- | src/git-parser.c | 297 | ||||
-rw-r--r-- | src/grecs.h | 1 | ||||
-rw-r--r-- | src/txtacc.c | 8 |
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 |
25 | endif | 25 | endif |
26 | 26 | ||
27 | if GRECS_COND_GIT_PARSER | ||
28 | GRECS_PARSER_GIT = git-parser.c | ||
29 | endif | ||
30 | |||
27 | GRECS_SRC = \ | 31 | GRECS_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 | ||
50 | noinst_HEADERS = | 55 | noinst_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 | |||
26 | static FILE *infile; | ||
27 | static int input_char; | ||
28 | static 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 | |||
37 | struct 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 | |||
49 | static int | ||
50 | input() | ||
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 | |||
60 | static void | ||
61 | unput() | ||
62 | { | ||
63 | if (!input_char) | ||
64 | return; | ||
65 | if (input_char == '\n') | ||
66 | grecs_current_locus.line--; | ||
67 | ungetc(input_char, infile); | ||
68 | } | ||
69 | |||
70 | static void | ||
71 | error_recovery() | ||
72 | { | ||
73 | while (input() && input_char != '\n') | ||
74 | ; | ||
75 | } | ||
76 | |||
77 | static void | ||
78 | collect_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 | |||
87 | static void | ||
88 | collect_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 | |||
105 | static void | ||
106 | gettoken(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 | |||
176 | static struct grecs_value * | ||
177 | getvalue() | ||
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 | |||
198 | static int | ||
199 | read_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(); | ||