settings: Parse assigned values in a different context

This allows us to accept characters like = or { without having to use
quoted strings.  And we can also properly warn about unexpected quoted
strings.
This commit is contained in:
Tobias Brunner 2018-05-07 18:24:48 +02:00
parent f8c20fb1c2
commit 740133b12d
2 changed files with 53 additions and 5 deletions

View 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 */

View 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));
}