581f8347f1719cf11ba84398906e52ee0b05b152
[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         \n                                      |
123         \\                                      {
124                 if (!streq(yytext, "\""))
125                 {
126                         if (streq(yytext, "\n"))
127                         {       /* put the newline back to fix the line numbers */
128                                 unput('\n');
129                                 yy_set_bol(0);
130                         }
131                         PARSER_DBG1(yyextra, "unterminated string detected");
132                 }
133                 if (yy_top_state(yyscanner) == inc)
134                 {       /* string include */
135                         include_files(yyextra);
136                         yy_pop_state(yyscanner);
137                         yy_pop_state(yyscanner);
138                 }
139                 else
140                 {
141                         yy_pop_state(yyscanner);
142                         yylval->s = yyextra->string_get(yyextra);
143                         return STRING;
144                 }
145         }
146         \\n     yyextra->string_add(yyextra, "\n");
147         \\r     yyextra->string_add(yyextra, "\r");
148         \\t     yyextra->string_add(yyextra, "\t");
149         \\\r?\n /* merge lines that end with EOL characters */
150         \\.     yyextra->string_add(yyextra, yytext+1);
151         [^\\\n"]+                       {
152                 yyextra->string_add(yyextra, yytext);
153         }
154 }
155
156 <<EOF>>                                 {
157         settings_parser_pop_buffer_state(yyscanner);
158         if (!settings_parser_open_next_file(yyextra) && !YY_CURRENT_BUFFER)
159         {
160                 yyterminate();
161         }
162 }
163
164 %%
165
166 /**
167  * Open the next file, if any is queued and readable, otherwise returns FALSE.
168  */
169 bool settings_parser_open_next_file(parser_helper_t *ctx)
170 {
171         FILE *file;
172
173         file = ctx->file_next(ctx);
174         if (!file)
175         {
176                 return FALSE;
177         }
178
179         settings_parser_set_in(file, ctx->scanner);
180         settings_parser_push_buffer_state(
181                         settings_parser__create_buffer(file, YY_BUF_SIZE,
182                                                                                    ctx->scanner), ctx->scanner);
183         return TRUE;
184 }
185
186 /**
187  * Assumes that the file pattern to include is currently stored as string on
188  * the helper object.
189  */
190 static void include_files(parser_helper_t *ctx)
191 {
192         char *pattern = ctx->string_get(ctx);
193
194         ctx->file_include(ctx, pattern);
195         free(pattern);
196
197         settings_parser_open_next_file(ctx);
198 }