123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- %{
- /*
- * Copyright (C) 2014-2018 Tobias Brunner
- * HSR Hochschule fuer Technik Rapperswil
- *
- * This program 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 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program 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.
- */
- #define _GNU_SOURCE /* for asprintf() */
- #include <stdio.h>
- #include <library.h>
- #include <collections/array.h>
- #include <settings/settings_types.h>
- #include <utils/parser_helper.h>
- #include "settings_parser.h"
- #define YYDEBUG 1
- /**
- * Defined by the lexer
- */
- int settings_parser_lex(YYSTYPE *lvalp, void *scanner);
- int settings_parser_lex_init_extra(parser_helper_t *extra, void *scanner);
- int settings_parser_lex_destroy(void *scanner);
- int settings_parser_set_in(FILE *in, void *scanner);
- void settings_parser_set_debug(int debug, void *scanner);
- char *settings_parser_get_text(void *scanner);
- int settings_parser_get_leng(void *scanner);
- int settings_parser_get_lineno(void *scanner);
- /* Custom functions in lexer */
- bool settings_parser_open_next_file(parser_helper_t *ctx);
- bool settings_parser_load_string(parser_helper_t *ctx, const char *content);
- /**
- * Forward declarations
- */
- static void settings_parser_error(parser_helper_t *ctx, const char *s);
- static section_t *push_section(parser_helper_t *ctx, char *name);
- static section_t *pop_section(parser_helper_t *ctx);
- static void add_section(parser_helper_t *ctx, section_t *section);
- static void add_setting(parser_helper_t *ctx, kv_t *kv);
- static void add_references(parser_helper_t *ctx, array_t *references);
- /**
- * Make sure to call lexer with the proper context
- */
- #undef yylex
- static int yylex(YYSTYPE *lvalp, parser_helper_t *ctx)
- {
- return settings_parser_lex(lvalp, ctx->scanner);
- }
- %}
- %debug
- /* generate verbose error messages */
- %error-verbose
- /* generate a reentrant parser */
- %define api.pure
- /* prefix function/variable declarations */
- %name-prefix "settings_parser_"
- /* interact properly with the reentrant lexer */
- %lex-param {parser_helper_t *ctx}
- %parse-param {parser_helper_t *ctx}
- /* types for terminal symbols... (can't use the typedef'd types) */
- %union {
- char *s;
- struct section_t *sec;
- struct kv_t *kv;
- array_t *refs;
- }
- %token <s> NAME STRING
- %token DOT "."
- %token COMMA ","
- %token COLON ":"
- %token NEWLINE STRING_ERROR
- /* ...and other symbols */
- %type <s> value valuepart
- %type <sec> section_start section
- %type <kv> setting
- %type <refs> references
- /* properly destroy string tokens that are strdup()ed on error */
- %destructor { free($$); } NAME STRING value valuepart
- /* properly destroy parse results on error */
- %destructor { pop_section(ctx); settings_section_destroy($$, NULL); } section_start section
- %destructor { settings_kv_destroy($$, NULL); } setting
- %destructor { array_destroy_function($$, (void*)free, NULL); } references
- /* there are two shift/reduce conflicts because of the "NAME = NAME" and
- * "NAME {" ambiguity, and the "NAME =" rule) */
- %expect 2
- %%
- /**
- * strongswan.conf grammar rules
- */
- statements:
- /* empty */
- | statements NEWLINE
- | statements statement
- ;
- statement:
- section
- {
- add_section(ctx, $section);
- }
- | setting
- {
- add_setting(ctx, $setting);
- }
- ;
- section:
- section_start statements '}'
- {
- pop_section(ctx);
- $$ = $section_start;
- }
- ;
- section_start:
- NAME '{'
- {
- $$ = push_section(ctx, $NAME);
- }
- |
- NAME ":" references '{'
- {
- $$ = push_section(ctx, $NAME);
- add_references(ctx, $references);
- array_destroy($references);
- }
- ;
- references:
- NAME
- {
- $$ = array_create(0, 0);
- array_insert($$, ARRAY_TAIL, $1);
- }
- | references "," NAME
- {
- array_insert($1, ARRAY_TAIL, $3);
- $$ = $1;
- }
- ;
- setting:
- NAME '=' value
- {
- $$ = settings_kv_create($NAME, $value);
- }
- |
- NAME '='
- {
- $$ = settings_kv_create($NAME, NULL);
- }
- ;
- value:
- valuepart
- | value valuepart
- { /* just put a single space between them, use strings for more */
- if (asprintf(&$$, "%s %s", $1, $2) < 0)
- {
- free($1);
- free($2);
- YYERROR;
- }
- free($1);
- free($2);
- }
- ;
- valuepart:
- NAME
- | STRING
- ;
- %%
- /**
- * Referenced by the generated parser
- */
- static void settings_parser_error(parser_helper_t *ctx, const char *s)
- {
- char *text = settings_parser_get_text(ctx->scanner);
- int len = settings_parser_get_leng(ctx->scanner);
- if (len && text[len-1] == '\n')
- { /* cut off newline at the end to avoid muti-line log messages */
- len--;
- }
- PARSER_DBG1(ctx, "%s [%.*s]", s, len, text);
- }
- /**
- * Create a section and push it to the stack (the name is adopted), returns
- * the created section
- */
- static section_t *push_section(parser_helper_t *ctx, char *name)
- {
- array_t *sections = (array_t*)ctx->context;
- section_t *section;
- section = settings_section_create(name);
- array_insert(sections, ARRAY_TAIL, section);
- return section;
- }
- /**
- * Removes the top section of the stack and returns it
- */
- static section_t *pop_section(parser_helper_t *ctx)
- {
- array_t *sections = (array_t*)ctx->context;
- section_t *section;
- array_remove(sections, ARRAY_TAIL, §ion);
- return section;
- }
- /**
- * Adds the given section to the section on top of the stack
- */
- static void add_section(parser_helper_t *ctx, section_t *section)
- {
- array_t *sections = (array_t*)ctx->context;
- section_t *parent;
- array_get(sections, ARRAY_TAIL, &parent);
- settings_section_add(parent, section, NULL);
- }
- /**
- * Adds the given key/value pair to the section on top of the stack
- */
- static void add_setting(parser_helper_t *ctx, kv_t *kv)
- {
- array_t *sections = (array_t*)ctx->context;
- section_t *section;
- array_get(sections, ARRAY_TAIL, §ion);
- settings_kv_add(section, kv, NULL);
- }
- /**
- * Adds the given references to the section on top of the stack
- */
- static void add_references(parser_helper_t *ctx, array_t *references)
- {
- array_t *sections = (array_t*)ctx->context;
- section_t *section;
- enumerator_t *refs;
- char *ref;
- array_get(sections, ARRAY_TAIL, §ion);
- refs = array_create_enumerator(references);
- while (refs->enumerate(refs, &ref))
- {
- settings_reference_add(section, ref, FALSE);
- array_remove_at(references, refs);
- }
- refs->destroy(refs);
- }
- /**
- * Parse the given file and add all sections and key/value pairs to the
- * given section.
- */
- bool settings_parser_parse_file(section_t *root, char *name)
- {
- parser_helper_t *helper;
- array_t *sections = NULL;
- bool success = FALSE;
- array_insert_create(§ions, ARRAY_TAIL, root);
- helper = parser_helper_create(sections);
- helper->get_lineno = settings_parser_get_lineno;
- if (settings_parser_lex_init_extra(helper, &helper->scanner) != 0)
- {
- helper->destroy(helper);
- array_destroy(sections);
- return FALSE;
- }
- helper->file_include(helper, name);
- if (!settings_parser_open_next_file(helper))
- {
- if (lib->conf && streq(name, lib->conf))
- {
- DBG2(DBG_CFG, "failed to open config file '%s'", name);
- }
- else
- {
- DBG1(DBG_CFG, "failed to open config file '%s'", name);
- }
- }
- else
- {
- if (getenv("DEBUG_SETTINGS_PARSER"))
- {
- yydebug = 1;
- settings_parser_set_debug(1, helper->scanner);
- }
- success = yyparse(helper) == 0;
- if (!success)
- {
- DBG1(DBG_CFG, "invalid config file '%s'", name);
- }
- }
- array_destroy(sections);
- settings_parser_lex_destroy(helper->scanner);
- helper->destroy(helper);
- return success;
- }
- /**
- * Parse the given string and add all sections and key/value pairs to the
- * given section.
- */
- bool settings_parser_parse_string(section_t *root, char *settings)
- {
- parser_helper_t *helper;
- array_t *sections = NULL;
- bool success = FALSE;
- array_insert_create(§ions, ARRAY_TAIL, root);
- helper = parser_helper_create(sections);
- helper->get_lineno = settings_parser_get_lineno;
- if (settings_parser_lex_init_extra(helper, &helper->scanner) != 0)
- {
- helper->destroy(helper);
- array_destroy(sections);
- return FALSE;
- }
- settings_parser_load_string(helper, settings);
- if (getenv("DEBUG_SETTINGS_PARSER"))
- {
- yydebug = 1;
- settings_parser_set_debug(1, helper->scanner);
- }
- success = yyparse(helper) == 0;
- if (!success)
- {
- DBG1(DBG_CFG, "failed to parse settings '%s'", settings);
- }
- array_destroy(sections);
- settings_parser_lex_destroy(helper->scanner);
- helper->destroy(helper);
- return success;
- }
|