Extend string syntax in config
And actually test the results of string parsing.
This commit is contained in:
parent
7e8e085c97
commit
f545be725d
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2014 - 2020, Přemysl Eric Janouch <p@janouch.name>
|
Copyright (c) 2014 - 2022, Přemysl Eric Janouch <p@janouch.name>
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted.
|
purpose with or without fee is hereby granted.
|
||||||
|
|
52
liberty.c
52
liberty.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* liberty.c: the ultimate C unlibrary
|
* liberty.c: the ultimate C unlibrary
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014 - 2020, Přemysl Eric Janouch <p@janouch.name>
|
* Copyright (c) 2014 - 2022, Přemysl Eric Janouch <p@janouch.name>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted.
|
* purpose with or without fee is hereby granted.
|
||||||
|
@ -4412,7 +4412,9 @@ socket_io_try_write (int socket_fd, struct str *wb)
|
||||||
// object = lws '{' entries endobj
|
// object = lws '{' entries endobj
|
||||||
// endobj = lws '}'
|
// endobj = lws '}'
|
||||||
//
|
//
|
||||||
// string = lws '"' ('\\' escape / ![\\"] char)* '"'
|
// quoted = lws '"' ('\\' escape / ![\\"] char)* '"'
|
||||||
|
// / lws '`' ![`]* '`'
|
||||||
|
// string = (quoted)+
|
||||||
// char = [\0-\177] # or any Unicode codepoint in the UTF-8 encoding
|
// char = [\0-\177] # or any Unicode codepoint in the UTF-8 encoding
|
||||||
// escape = [\\"abfnrtv] / [xX][0-9A-Fa-f][0-9A-Fa-f]? / [0-7][0-7]?[0-7]?
|
// escape = [\\"abfnrtv] / [xX][0-9A-Fa-f][0-9A-Fa-f]? / [0-7][0-7]?[0-7]?
|
||||||
//
|
//
|
||||||
|
@ -5039,10 +5041,10 @@ config_tokenizer_escape_sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
config_tokenizer_string
|
config_tokenizer_dq_string (struct config_tokenizer *self, struct str *output,
|
||||||
(struct config_tokenizer *self, struct str *output, struct error **e)
|
struct error **e)
|
||||||
{
|
{
|
||||||
unsigned char c;
|
unsigned char c = config_tokenizer_advance (self);
|
||||||
while (self->len)
|
while (self->len)
|
||||||
{
|
{
|
||||||
if ((c = config_tokenizer_advance (self)) == '"')
|
if ((c = config_tokenizer_advance (self)) == '"')
|
||||||
|
@ -5056,6 +5058,44 @@ config_tokenizer_string
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
config_tokenizer_bt_string (struct config_tokenizer *self, struct str *output,
|
||||||
|
struct error **e)
|
||||||
|
{
|
||||||
|
unsigned char c = config_tokenizer_advance (self);
|
||||||
|
while (self->len)
|
||||||
|
{
|
||||||
|
if ((c = config_tokenizer_advance (self)) == '`')
|
||||||
|
return true;
|
||||||
|
str_append_c (output, c);
|
||||||
|
}
|
||||||
|
config_tokenizer_error (self, e, "premature end of string");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
config_tokenizer_string (struct config_tokenizer *self, struct str *output,
|
||||||
|
struct error **e)
|
||||||
|
{
|
||||||
|
// Go-like strings, with C/AWK-like automatic concatenation
|
||||||
|
while (self->len)
|
||||||
|
{
|
||||||
|
bool ok = true;
|
||||||
|
if (isspace_ascii (*self->p) && *self->p != '\n')
|
||||||
|
config_tokenizer_advance (self);
|
||||||
|
else if (*self->p == '"')
|
||||||
|
ok = config_tokenizer_dq_string (self, output, e);
|
||||||
|
else if (*self->p == '`')
|
||||||
|
ok = config_tokenizer_bt_string (self, output, e);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static enum config_token
|
static enum config_token
|
||||||
config_tokenizer_next (struct config_tokenizer *self, struct error **e)
|
config_tokenizer_next (struct config_tokenizer *self, struct error **e)
|
||||||
{
|
{
|
||||||
|
@ -5080,7 +5120,7 @@ config_tokenizer_next (struct config_tokenizer *self, struct error **e)
|
||||||
return CONFIG_T_ABORT;
|
return CONFIG_T_ABORT;
|
||||||
|
|
||||||
case '"':
|
case '"':
|
||||||
config_tokenizer_advance (self);
|
case '`':
|
||||||
str_reset (&self->string);
|
str_reset (&self->string);
|
||||||
if (!config_tokenizer_string (self, &self->string, e))
|
if (!config_tokenizer_string (self, &self->string, e))
|
||||||
return CONFIG_T_ABORT;
|
return CONFIG_T_ABORT;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* tests/liberty.c
|
* tests/liberty.c
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015 - 2016, Přemysl Eric Janouch <p@janouch.name>
|
* Copyright (c) 2015 - 2022, Přemysl Eric Janouch <p@janouch.name>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted.
|
* purpose with or without fee is hereby granted.
|
||||||
|
@ -649,7 +649,7 @@ static struct config_schema g_config_test[] =
|
||||||
.default_ = "1" },
|
.default_ = "1" },
|
||||||
{ .name = "foobar",
|
{ .name = "foobar",
|
||||||
.type = CONFIG_ITEM_STRING,
|
.type = CONFIG_ITEM_STRING,
|
||||||
.default_ = "\"qux\\x01\"" },
|
.default_ = "\"qux\\x01`\" \"\"`a`" },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -675,6 +675,9 @@ test_config (void)
|
||||||
"top.bar", NULL), invalid, NULL));
|
"top.bar", NULL), invalid, NULL));
|
||||||
config_item_destroy (invalid);
|
config_item_destroy (invalid);
|
||||||
|
|
||||||
|
hard_assert (!strcmp ("qux\001`a",
|
||||||
|
config_item_get (config.root, "top.foobar", NULL)->value.string.str));
|
||||||
|
|
||||||
struct str s = str_make ();
|
struct str s = str_make ();
|
||||||
config_item_write (config.root, true, &s);
|
config_item_write (config.root, true, &s);
|
||||||
struct config_item *parsed = config_item_parse (s.str, s.len, false, NULL);
|
struct config_item *parsed = config_item_parse (s.str, s.len, false, NULL);
|
||||||
|
|
Loading…
Reference in New Issue