settings: Parse assigned values in a different context
authorTobias Brunner <tobias@strongswan.org>
Mon, 7 May 2018 16:24:48 +0000 (18:24 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 23 May 2018 10:01:50 +0000 (12:01 +0200)
This allows us to accept characters like = or { without having to use
quoted strings.  And we can also properly warn about unexpected quoted
strings.

src/libstrongswan/settings/settings_lexer.l
src/libstrongswan/tests/suites/test_settings.c

index 48e16de..c45e30c 100644 (file)
@@ -49,6 +49,8 @@ static void include_files(parser_helper_t *ctx);
 /* type of our extra data */
 %option extra-type="parser_helper_t*"
 
+/* state used to scan values */
+%x val
 /* state used to scan include file patterns */
 %x inc
 /* state used to scan quoted strings */
@@ -61,8 +63,12 @@ static void include_files(parser_helper_t *ctx);
 \n|#.*\n                               return NEWLINE; /* also eats comments at the end of a line */
 
 "{"                                            |
-"}"                                            |
-"="                                            return yytext[0];
+"}"                                            return yytext[0];
+
+"="                                            {
+       yy_push_state(val, yyscanner);
+       return yytext[0];
+}
 
 "include"[\t ]+/[^=]   {
        yyextra->string_init(yyextra);
@@ -70,8 +76,8 @@ static void include_files(parser_helper_t *ctx);
 }
 
 "\""                                   {
-       yyextra->string_init(yyextra);
-       yy_push_state(str, yyscanner);
+       PARSER_DBG1(yyextra, "unexpected string detected");
+       return STRING_ERROR;
 }
 
 [^#{}="\r\n\t ]+                       {
@@ -79,6 +85,42 @@ static void include_files(parser_helper_t *ctx);
        return NAME;
 }
 
+<val>{
+       \r                                      /* just ignore these */
+       [\t ]+
+       <<EOF>>                         |
+       [#}\n]                  {
+               if (*yytext)
+               {
+                       switch (yytext[0])
+                       {
+                               case '\n':
+                                       /* put the newline back to fix the line numbers */
+                                       unput('\n');
+                                       yy_set_bol(0);
+                                       break;
+                               case '#':
+                               case '}':
+                                       /* these are parsed outside of this start condition */
+                                       unput(yytext[0]);
+                                       break;
+                       }
+               }
+               yy_pop_state(yyscanner);
+       }
+
+       "\""                                    {
+               yyextra->string_init(yyextra);
+               yy_push_state(str, yyscanner);
+       }
+
+       /* same as above, but allow more characters */
+       [^#}"\r\n\t ]+                  {
+               yylval->s = strdup(yytext);
+               return NAME;
+       }
+}
+
 <inc>{
        \r                                      /* just ignore these */
        /* we allow all characters except #, } and spaces, they can be escaped */
index d291b16..c203ad7 100644 (file)
@@ -1109,6 +1109,12 @@ START_TEST(test_valid)
                "}\n");
        ck_assert(chunk_write(contents, path, 0022, TRUE));
        ck_assert(settings->load_files(settings, path, FALSE));
+
+       contents = chunk_from_str(
+               "equals = a setting with = and { character");
+       ck_assert(chunk_write(contents, path, 0022, TRUE));
+       ck_assert(settings->load_files(settings, path, FALSE));
+       verify_string("a setting with = and { character", "equals");
 }
 END_TEST
 
@@ -1148,7 +1154,7 @@ START_TEST(test_invalid)
        ck_assert(!settings->load_files(settings, path, FALSE));
 
        contents = chunk_from_str(
-               "only = a single setting = per line");
+               "\"unexpected\" = string");
        ck_assert(chunk_write(contents, path, 0022, TRUE));
        ck_assert(!settings->load_files(settings, path, FALSE));
 }