ce9d4eedc884899a0855a14d821f7c67a2d7f8d6
[strongswan.git] / src / libstrongswan / settings / settings_lexer.l
1 %{
2 /*
3  * Copyright (C) 2014 Tobias Brunner
4  * 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 #include <utils/parser_helper.h>
18
19 #include "settings_parser.h"
20
21 bool settings_parser_open_next_file(parser_helper_t *ctx);
22
23 static void include_files(parser_helper_t *ctx);
24
25 %}
26 %option debug
27 %option warn
28
29 /* use start conditions stack */
30 %option stack
31
32 /* do not declare unneded functions */
33 %option noinput noyywrap
34
35 /* don't use global variables, and interact properly with bison */
36 %option reentrant bison-bridge
37
38 /* maintain the line number */
39 %option yylineno
40
41 /* don't generate a default rule */
42 %option nodefault
43
44 /* prefix function/variable declarations */
45 %option prefix="settings_parser_"
46 /* don't change the name of the output file otherwise autotools has issues */
47 %option outfile="lex.yy.c"
48
49 /* type of our extra data */
50 %option extra-type="parser_helper_t*"
51
52 /* state used to scan include file patterns */
53 %x inc
54 /* state used to scan quoted strings */
55 %x str
56
57 %%
58
59 [\t ]*#[^\n]*                   /* eat comments */
60 [\t ]+                                  /* eat whitespace */
61 \n|#.*\n                                return NEWLINE; /* also eats comments at the end of a line */
62
63 "{"                                             |
64 "}"                                             |
65 "="                                             return yytext[0];
66
67 "include"[\t ]+/[^=]    {
68         yyextra->string_init(yyextra);
69         yy_push_state(inc, yyscanner);
70 }
71
72 "\""                                    {
73         yyextra->string_init(yyextra);
74         yy_push_state(str, yyscanner);
75 }
76
77 [^#{}="\n\t ]+                  {
78         yylval->s = strdup(yytext);
79         return NAME;
80 }
81
82 <inc>{
83         /* we allow all characters except #, } and spaces, they can be escaped */
84         <<EOF>>                         |
85         [#}\n\t ]                       {
86                 if (*yytext)
87                 {
88                         switch (yytext[0])
89                         {
90                                 case '\n':
91                                         /* put the newline back to fix the line numbers */
92                                         unput('\n');
93                                         yy_set_bol(0);
94                                         break;
95                                 case '#':
96                                 case '}':
97                                         /* these are parsed outside of this start condition */
98                                         unput(yytext[0]);
99                                         break;
100                         }
101                 }
102                 include_files(yyextra);
103                 yy_pop_state(yyscanner);
104         }
105         "\""                            {       /* string include */
106                 yy_push_state(str, yyscanner);
107         }
108         \\                                      {
109                 yyextra->string_add(yyextra, yytext);
110         }
111         \\["#} ]                        {
112                 yyextra->string_add(yyextra, yytext+1);
113         }
114         [^"\\#}\n\t ]+ {
115                 yyextra->string_add(yyextra, yytext);
116         }
117 }
118
119 <str>{
120         "\""                            |
121         <<EOF>>                         |
122         \\                                      {
123                 if (!streq(yytext, "\""))
124                 {
125                         PARSER_DBG1(yyextra, "unterminated string detected");
126                         return STRING_ERROR;
127                 }
128                 if (yy_top_state(yyscanner) == inc)
129                 {       /* string include */
130                         include_files(yyextra);
131                         yy_pop_state(yyscanner);
132                         yy_pop_state(yyscanner);
133                 }
134                 else
135                 {
136                         yy_pop_state(yyscanner);
137                         yylval->s = yyextra->string_get(yyextra);
138                         return STRING;
139                 }
140         }
141         \\n     yyextra->string_add(yyextra, "\n");
142         \\r     yyextra->string_add(yyextra, "\r");
143         \\t     yyextra->string_add(yyextra, "\t");
144         \\\r?\n /* merge lines that end with EOL characters */
145         \\.     yyextra->string_add(yyextra, yytext+1);
146         [^\\"]+                 {
147                 yyextra->string_add(yyextra, yytext);
148         }
149 }
150
151 <<EOF>>                                 {
152         settings_parser_pop_buffer_state(yyscanner);
153         if (!settings_parser_open_next_file(yyextra) && !YY_CURRENT_BUFFER)
154         {
155                 yyterminate();
156         }
157 }
158
159 %%
160
161 /**
162  * Open the next file, if any is queued and readable, otherwise returns FALSE.
163  */
164 bool settings_parser_open_next_file(parser_helper_t *ctx)
165 {
166         FILE *file;
167
168         file = ctx->file_next(ctx);
169         if (!file)
170         {
171                 return FALSE;
172         }
173
174         settings_parser_set_in(file, ctx->scanner);
175         settings_parser_push_buffer_state(
176                         settings_parser__create_buffer(file, YY_BUF_SIZE,
177                                                                                    ctx->scanner), ctx->scanner);
178         return TRUE;
179 }
180
181 /**
182  * Assumes that the file pattern to include is currently stored as string on
183  * the helper object.
184  */
185 static void include_files(parser_helper_t *ctx)
186 {
187         char *pattern = ctx->string_get(ctx);
188
189         ctx->file_include(ctx, pattern);
190         free(pattern);
191
192         settings_parser_open_next_file(ctx);
193 }
194
195 /**
196  * Load the given string to be parsed next
197  */
198 void settings_parser_load_string(parser_helper_t *ctx, const char *content)
199 {
200         settings_parser__scan_string(content, ctx->scanner);
201 }