3 * Copyright (C) 2014-2018 Tobias Brunner
5 * Copyright (C) secunet Security Networks AG
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>.
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
18 #define _GNU_SOURCE /* for asprintf() */
22 #include <collections/array.h>
23 #include <settings/settings_types.h>
24 #include <utils/parser_helper.h>
26 #include "settings_parser.h"
31 * Defined by the lexer
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);
46 * Forward declarations
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);
56 * Make sure to call lexer with the proper context
59 static int yylex(SETTINGS_PARSER_STYPE *yylval, parser_helper_t *ctx)
61 return settings_parser_lex(yylval, ctx->scanner);
67 /* generate verbose error messages */
68 %define parse.error verbose
69 /* generate a reentrant parser */
71 /* prefix function/variable declarations */
72 %define api.prefix {settings_parser_}
73 /* make sure flex uses the right definition */
77 int settings_parser_lex(SETTINGS_PARSER_STYPE *yylval, void *yyscanner)
81 /* interact properly with the reentrant lexer */
82 %lex-param {parser_helper_t *ctx}
83 %parse-param {parser_helper_t *ctx}
85 /* types for terminal symbols... (can't use the typedef'd types) */
88 struct section_t *sec;
92 %token <s> NAME STRING
96 %token NEWLINE STRING_ERROR
98 /* ...and other symbols */
99 %type <s> value valuepart
100 %type <sec> section_start section
102 %type <refs> references
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
111 /* there are two shift/reduce conflicts because of the "NAME = NAME" and
112 * "NAME {" ambiguity, and the "NAME =" rule) */
118 * strongswan.conf grammar rules
123 | statements statement
129 add_section(ctx, $section);
133 add_setting(ctx, $setting);
138 section_start statements '}'
148 $$ = push_section(ctx, $NAME);
151 NAME ":" references '{'
153 $$ = push_section(ctx, $NAME);
154 add_references(ctx, $references);
155 array_destroy($references);
162 $$ = array_create(0, 0);
163 array_insert($$, ARRAY_TAIL, $1);
165 | references "," NAME
167 array_insert($1, ARRAY_TAIL, $3);
175 $$ = settings_kv_create($NAME, $value);
180 $$ = settings_kv_create($NAME, NULL);
187 { /* just put a single space between them, use strings for more */
188 if (asprintf(&$$, "%s %s", $1, $2) < 0)
207 * Referenced by the generated parser
209 static void settings_parser_error(parser_helper_t *ctx, const char *s)
211 PARSER_DBG1(ctx, "%s", s);
215 * Create a section and push it to the stack (the name is adopted), returns
216 * the created section
218 static section_t *push_section(parser_helper_t *ctx, char *name)
220 array_t *sections = (array_t*)ctx->context;
223 section = settings_section_create(name);
224 array_insert(sections, ARRAY_TAIL, section);
229 * Removes the top section of the stack and returns it
231 static section_t *pop_section(parser_helper_t *ctx)
233 array_t *sections = (array_t*)ctx->context;
236 array_remove(sections, ARRAY_TAIL, §ion);
241 * Adds the given section to the section on top of the stack
243 static void add_section(parser_helper_t *ctx, section_t *section)
245 array_t *sections = (array_t*)ctx->context;
248 array_get(sections, ARRAY_TAIL, &parent);
249 settings_section_add(parent, section, NULL);
253 * Adds the given key/value pair to the section on top of the stack
255 static void add_setting(parser_helper_t *ctx, kv_t *kv)
257 array_t *sections = (array_t*)ctx->context;
260 array_get(sections, ARRAY_TAIL, §ion);
261 settings_kv_add(section, kv, NULL);
265 * Adds the given references to the section on top of the stack
267 static void add_references(parser_helper_t *ctx, array_t *references)
269 array_t *sections = (array_t*)ctx->context;
274 array_get(sections, ARRAY_TAIL, §ion);
276 refs = array_create_enumerator(references);
277 while (refs->enumerate(refs, &ref))
279 settings_reference_add(section, ref, FALSE);
280 array_remove_at(references, refs);
286 * Parse the given file and add all sections and key/value pairs to the
289 bool settings_parser_parse_file(section_t *root, char *name)
291 parser_helper_t *helper;
292 array_t *sections = NULL;
293 bool success = FALSE;
295 array_insert_create(§ions, 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)
300 helper->destroy(helper);
301 array_destroy(sections);
304 helper->file_include(helper, name);
305 if (!settings_parser_open_next_file(helper))
307 if (lib->conf && streq(name, lib->conf))
309 DBG2(DBG_CFG, "failed to open config file '%s'", name);
313 DBG1(DBG_CFG, "failed to open config file '%s'", name);
318 if (getenv("DEBUG_SETTINGS_PARSER"))
321 settings_parser_set_debug(1, helper->scanner);
323 success = yyparse(helper) == 0;
326 DBG1(DBG_CFG, "invalid config file '%s'", name);
329 array_destroy(sections);
330 settings_parser_lex_destroy(helper->scanner);
331 helper->destroy(helper);
336 * Parse the given string and add all sections and key/value pairs to the
339 bool settings_parser_parse_string(section_t *root, char *settings)
341 parser_helper_t *helper;
342 array_t *sections = NULL;
343 bool success = FALSE;
345 array_insert_create(§ions, 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)
350 helper->destroy(helper);
351 array_destroy(sections);
354 settings_parser_load_string(helper, settings);
355 if (getenv("DEBUG_SETTINGS_PARSER"))
358 settings_parser_set_debug(1, helper->scanner);
360 success = yyparse(helper) == 0;
363 DBG1(DBG_CFG, "failed to parse settings '%s'", settings);
365 array_destroy(sections);
366 settings_parser_lex_destroy(helper->scanner);
367 helper->destroy(helper);