fa1ecac102bb05bbd133fc8dfea731472bbb33d0
[strongswan.git] / src / libstrongswan / settings / settings_lexer.l
1 %{
2 /*
3  * Copyright (C) 2014 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 #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 values */
53 %x val
54 /* state used to scan include file patterns */
55 %x inc
56 /* state used to scan quoted strings */
57 %x str
58
59 %%
60
61 [\t ]*#[^\r\n]*                 /* eat comments */
62 [\t\r ]+                                /* eat whitespace */
63 \n|#.*\n                                return NEWLINE; /* also eats comments at the end of a line */
64
65 "{"                                             |
66 "}"                                             return yytext[0];
67
68 "="                                             {
69         yy_push_state(val, yyscanner);
70         return yytext[0];
71 }
72
73 "include"[\t ]+/[^=]    {
74         yyextra->string_init(yyextra);
75         yy_push_state(inc, yyscanner);
76 }
77
78 "\""                                    {
79         PARSER_DBG1(yyextra, "unexpected string detected");
80         return STRING_ERROR;
81 }
82
83 [^#{}="\r\n\t ]+                        {
84         yylval->s = strdup(yytext);
85         return NAME;
86 }
87
88 <val>{
89         \r                                      /* just ignore these */
90         [\t ]+
91         <<EOF>>                         |
92         [#}\n]                  {
93                 if (*yytext)
94                 {
95                         switch (yytext[0])
96                         {
97                                 case '\n':
98                                         /* put the newline back to fix the line numbers */
99                                         unput('\n');
100                                         yy_set_bol(0);
101                                         break;
102                                 case '#':
103                                 case '}':
104                                         /* these are parsed outside of this start condition */
105                                         unput(yytext[0]);
106                                         break;
107                         }
108                 }
109                 yy_pop_state(yyscanner);
110         }
111
112         "\""                                    {
113                 yyextra->string_init(yyextra);
114                 yy_push_state(str, yyscanner);
115         }
116
117         /* same as above, but allow more characters */
118         [^#}"\r\n\t ]+                  {
119                 yylval->s = strdup(yytext);
120                 return NAME;
121         }
122 }
123
124 <inc>{
125         \r                                      /* just ignore these */
126         /* we allow all characters except #, } and spaces, they can be escaped */
127         <<EOF>>                         |
128         [#}\n\t ]                       {
129                 if (*yytext)
130                 {
131                         switch (yytext[0])
132                         {
133                                 case '\n':
134                                         /* put the newline back to fix the line numbers */
135                                         unput('\n');
136                                         yy_set_bol(0);
137                                         break;
138                                 case '#':
139                                 case '}':
140                                         /* these are parsed outside of this start condition */
141                                         unput(yytext[0]);
142                                         break;
143                         }
144                 }
145                 include_files(yyextra);
146                 yy_pop_state(yyscanner);
147         }
148         "\""                            {       /* string include */
149                 yy_push_state(str, yyscanner);
150         }
151         \\                                      {
152                 yyextra->string_add(yyextra, yytext);
153         }
154         \\["#} ]                        {
155                 yyextra->string_add(yyextra, yytext+1);
156         }
157         [^"\\#}\r\n\t ]+ {
158                 yyextra->string_add(yyextra, yytext);
159         }
160 }
161
162 <str>{
163         \r                                      /* just ignore these */
164         "\""                            |
165         <<EOF>>                         |
166         \\                                      {
167                 if (!streq(yytext, "\""))
168                 {
169                         PARSER_DBG1(yyextra, "unterminated string detected");
170                         return STRING_ERROR;
171                 }
172                 if (yy_top_state(yyscanner) == inc)
173                 {       /* string include */
174                         include_files(yyextra);
175                         yy_pop_state(yyscanner);
176                         yy_pop_state(yyscanner);
177                 }
178                 else
179                 {
180                         yy_pop_state(yyscanner);
181                         yylval->s = yyextra->string_get(yyextra);
182                         return STRING;
183                 }
184         }
185
186         \\n     yyextra->string_add(yyextra, "\n");
187         \\r     yyextra->string_add(yyextra, "\r");
188         \\t     yyextra->string_add(yyextra, "\t");
189         \\\r?\n /* merge lines that end with escaped EOL characters */
190         \\.     yyextra->string_add(yyextra, yytext+1);
191         [^\\\r"]+                       {
192                 yyextra->string_add(yyextra, yytext);
193         }
194 }
195
196 <<EOF>>                                 {
197         settings_parser_pop_buffer_state(yyscanner);
198         if (!settings_parser_open_next_file(yyextra) && !YY_CURRENT_BUFFER)
199         {
200                 yyterminate();
201         }
202 }
203
204 %%
205
206 /**
207  * Open the next file, if any is queued and readable, otherwise returns FALSE.
208  */
209 bool settings_parser_open_next_file(parser_helper_t *ctx)
210 {
211         FILE *file;
212
213         file = ctx->file_next(ctx);
214         if (!file)
215         {
216                 return FALSE;
217         }
218
219         settings_parser_set_in(file, ctx->scanner);
220         settings_parser_push_buffer_state(
221                         settings_parser__create_buffer(file, YY_BUF_SIZE,
222                                                                                    ctx->scanner), ctx->scanner);
223         return TRUE;
224 }
225
226 /**
227  * Assumes that the file pattern to include is currently stored as string on
228  * the helper object.
229  */
230 static void include_files(parser_helper_t *ctx)
231 {
232         char *pattern = ctx->string_get(ctx);
233
234         ctx->file_include(ctx, pattern);
235         free(pattern);
236
237         settings_parser_open_next_file(ctx);
238 }
239
240 /**
241  * Load the given string to be parsed next
242  */
243 void settings_parser_load_string(parser_helper_t *ctx, const char *content)
244 {
245         settings_parser__scan_string(content, ctx->scanner);
246 }