settings_parser.y 8.3 KB

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