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