]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/settings/settings_parser.y
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libstrongswan / settings / settings_parser.y
1 %{
2 /*
3 * Copyright (C) 2014-2018 Tobias Brunner
4 *
5 * Copyright (C) secunet Security Networks AG
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #define _GNU_SOURCE /* for asprintf() */
19 #include <stdio.h>
20
21 #include <library.h>
22 #include <collections/array.h>
23 #include <settings/settings_types.h>
24 #include <utils/parser_helper.h>
25
26 #include "settings_parser.h"
27
28 #define YYDEBUG 1
29
30 /**
31 * Defined by the lexer
32 */
33 int settings_parser_lex(YYSTYPE *lvalp, void *scanner);
34 int settings_parser_lex_init_extra(parser_helper_t *extra, void *scanner);
35 int settings_parser_lex_destroy(void *scanner);
36 int settings_parser_set_in(FILE *in, void *scanner);
37 void settings_parser_set_debug(int debug, void *scanner);
38 char *settings_parser_get_text(void *scanner);
39 int settings_parser_get_leng(void *scanner);
40 int settings_parser_get_lineno(void *scanner);
41 /* Custom functions in lexer */
42 bool settings_parser_open_next_file(parser_helper_t *ctx);
43 bool settings_parser_load_string(parser_helper_t *ctx, const char *content);
44
45 /**
46 * Forward declarations
47 */
48 static void settings_parser_error(parser_helper_t *ctx, const char *s);
49 static section_t *push_section(parser_helper_t *ctx, char *name);
50 static section_t *pop_section(parser_helper_t *ctx);
51 static void add_section(parser_helper_t *ctx, section_t *section);
52 static void add_setting(parser_helper_t *ctx, kv_t *kv);
53 static void add_references(parser_helper_t *ctx, array_t *references);
54
55 /**
56 * Make sure to call lexer with the proper context
57 */
58 #undef yylex
59 static int yylex(SETTINGS_PARSER_STYPE *yylval, parser_helper_t *ctx)
60 {
61 return settings_parser_lex(yylval, ctx->scanner);
62 }
63
64 %}
65 %debug
66
67 /* generate verbose error messages */
68 %define parse.error verbose
69 /* generate a reentrant parser */
70 %define api.pure
71 /* prefix function/variable declarations */
72 %define api.prefix {settings_parser_}
73 /* make sure flex uses the right definition */
74 %code provides
75 {
76 #define YY_DECL \
77 int settings_parser_lex(SETTINGS_PARSER_STYPE *yylval, void *yyscanner)
78 YY_DECL;
79 }
80
81 /* interact properly with the reentrant lexer */
82 %lex-param {parser_helper_t *ctx}
83 %parse-param {parser_helper_t *ctx}
84
85 /* types for terminal symbols... (can't use the typedef'd types) */
86 %union {
87 char *s;
88 struct section_t *sec;
89 struct kv_t *kv;
90 array_t *refs;
91 }
92 %token <s> NAME STRING
93 %token DOT "."
94 %token COMMA ","
95 %token COLON ":"
96 %token NEWLINE STRING_ERROR
97
98 /* ...and other symbols */
99 %type <s> value valuepart
100 %type <sec> section_start section
101 %type <kv> setting
102 %type <refs> references
103
104 /* properly destroy string tokens that are strdup()ed on error */
105 %destructor { free($$); } NAME STRING value valuepart
106 /* properly destroy parse results on error */
107 %destructor { pop_section(ctx); settings_section_destroy($$, NULL); } section_start section
108 %destructor { settings_kv_destroy($$, NULL); } setting
109 %destructor { array_destroy_function($$, (void*)free, NULL); } references
110
111 /* there are two shift/reduce conflicts because of the "NAME = NAME" and
112 * "NAME {" ambiguity, and the "NAME =" rule) */
113 %expect 2
114
115 %%
116
117 /**
118 * strongswan.conf grammar rules
119 */
120 statements:
121 /* empty */
122 | statements NEWLINE
123 | statements statement
124 ;
125
126 statement:
127 section
128 {
129 add_section(ctx, $section);
130 }
131 | setting
132 {
133 add_setting(ctx, $setting);
134 }
135 ;
136
137 section:
138 section_start statements '}'
139 {
140 pop_section(ctx);
141 $$ = $section_start;
142 }
143 ;
144
145 section_start:
146 NAME '{'
147 {
148 $$ = push_section(ctx, $NAME);
149 }
150 |
151 NAME ":" references '{'
152 {
153 $$ = push_section(ctx, $NAME);
154 add_references(ctx, $references);
155 array_destroy($references);
156 }
157 ;
158
159 references:
160 NAME
161 {
162 $$ = array_create(0, 0);
163 array_insert($$, ARRAY_TAIL, $1);
164 }
165 | references "," NAME
166 {
167 array_insert($1, ARRAY_TAIL, $3);
168 $$ = $1;
169 }
170 ;
171
172 setting:
173 NAME '=' value
174 {
175 $$ = settings_kv_create($NAME, $value);
176 }
177 |
178 NAME '='
179 {
180 $$ = settings_kv_create($NAME, NULL);
181 }
182 ;
183
184 value:
185 valuepart
186 | value valuepart
187 { /* just put a single space between them, use strings for more */
188 if (asprintf(&$$, "%s %s", $1, $2) < 0)
189 {
190 free($1);
191 free($2);
192 YYERROR;
193 }
194 free($1);
195 free($2);
196 }
197 ;
198
199 valuepart:
200 NAME
201 | STRING
202 ;
203
204 %%
205
206 /**
207 * Referenced by the generated parser
208 */
209 static void settings_parser_error(parser_helper_t *ctx, const char *s)
210 {
211 PARSER_DBG1(ctx, "%s", s);
212 }
213
214 /**
215 * Create a section and push it to the stack (the name is adopted), returns
216 * the created section
217 */
218 static section_t *push_section(parser_helper_t *ctx, char *name)
219 {
220 array_t *sections = (array_t*)ctx->context;
221 section_t *section;
222
223 section = settings_section_create(name);
224 array_insert(sections, ARRAY_TAIL, section);
225 return section;
226 }
227
228 /**
229 * Removes the top section of the stack and returns it
230 */
231 static section_t *pop_section(parser_helper_t *ctx)
232 {
233 array_t *sections = (array_t*)ctx->context;
234 section_t *section;
235
236 array_remove(sections, ARRAY_TAIL, &section);
237 return section;
238 }
239
240 /**
241 * Adds the given section to the section on top of the stack
242 */
243 static void add_section(parser_helper_t *ctx, section_t *section)
244 {
245 array_t *sections = (array_t*)ctx->context;
246 section_t *parent;
247
248 array_get(sections, ARRAY_TAIL, &parent);
249 settings_section_add(parent, section, NULL);
250 }
251
252 /**
253 * Adds the given key/value pair to the section on top of the stack
254 */
255 static void add_setting(parser_helper_t *ctx, kv_t *kv)
256 {
257 array_t *sections = (array_t*)ctx->context;
258 section_t *section;
259
260 array_get(sections, ARRAY_TAIL, &section);
261 settings_kv_add(section, kv, NULL);
262 }
263
264 /**
265 * Adds the given references to the section on top of the stack
266 */
267 static void add_references(parser_helper_t *ctx, array_t *references)
268 {
269 array_t *sections = (array_t*)ctx->context;
270 section_t *section;
271 enumerator_t *refs;
272 char *ref;
273
274 array_get(sections, ARRAY_TAIL, &section);
275
276 refs = array_create_enumerator(references);
277 while (refs->enumerate(refs, &ref))
278 {
279 settings_reference_add(section, ref, FALSE);
280 array_remove_at(references, refs);
281 }
282 refs->destroy(refs);
283 }
284
285 /**
286 * Parse the given file and add all sections and key/value pairs to the
287 * given section.
288 */
289 bool settings_parser_parse_file(section_t *root, char *name)
290 {
291 parser_helper_t *helper;
292 array_t *sections = NULL;
293 bool success = FALSE;
294
295 array_insert_create(&sections, ARRAY_TAIL, root);
296 helper = parser_helper_create(sections);
297 helper->get_lineno = settings_parser_get_lineno;
298 if (settings_parser_lex_init_extra(helper, &helper->scanner) != 0)
299 {
300 helper->destroy(helper);
301 array_destroy(sections);
302 return FALSE;
303 }
304 helper->file_include(helper, name);
305 if (!settings_parser_open_next_file(helper))
306 {
307 if (lib->conf && streq(name, lib->conf))
308 {
309 DBG2(DBG_CFG, "failed to open config file '%s'", name);
310 }
311 else
312 {
313 DBG1(DBG_CFG, "failed to open config file '%s'", name);
314 }
315 }
316 else
317 {
318 if (getenv("DEBUG_SETTINGS_PARSER"))
319 {
320 yydebug = 1;
321 settings_parser_set_debug(1, helper->scanner);
322 }
323 success = yyparse(helper) == 0;
324 if (!success)
325 {
326 DBG1(DBG_CFG, "invalid config file '%s'", name);
327 }
328 }
329 array_destroy(sections);
330 settings_parser_lex_destroy(helper->scanner);
331 helper->destroy(helper);
332 return success;
333 }
334
335 /**
336 * Parse the given string and add all sections and key/value pairs to the
337 * given section.
338 */
339 bool settings_parser_parse_string(section_t *root, char *settings)
340 {
341 parser_helper_t *helper;
342 array_t *sections = NULL;
343 bool success = FALSE;
344
345 array_insert_create(&sections, ARRAY_TAIL, root);
346 helper = parser_helper_create(sections);
347 helper->get_lineno = settings_parser_get_lineno;
348 if (settings_parser_lex_init_extra(helper, &helper->scanner) != 0)
349 {
350 helper->destroy(helper);
351 array_destroy(sections);
352 return FALSE;
353 }
354 settings_parser_load_string(helper, settings);
355 if (getenv("DEBUG_SETTINGS_PARSER"))
356 {
357 yydebug = 1;
358 settings_parser_set_debug(1, helper->scanner);
359 }
360 success = yyparse(helper) == 0;
361 if (!success)
362 {
363 DBG1(DBG_CFG, "failed to parse settings '%s'", settings);
364 }
365 array_destroy(sections);
366 settings_parser_lex_destroy(helper->scanner);
367 helper->destroy(helper);
368 return success;
369 }