[PATCH 7/8] bootconfig: Add append value operator support

From: Masami Hiramatsu
Date: Thu Feb 20 2020 - 02:27:47 EST


Add append value operator "+=" support to bootconfig syntax.
With this operator, user can add new value to the key as
an entry of array instead of overwriting.
For example,

foo = bar
...
foo += baz

Then the key "foo" has "bar" and "baz" values as an array.

Signed-off-by: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
---
Documentation/admin-guide/bootconfig.rst | 8 ++++++++
lib/bootconfig.c | 14 ++++++++++----
tools/bootconfig/test-bootconfig.sh | 13 +++++++++++++
3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/Documentation/admin-guide/bootconfig.rst b/Documentation/admin-guide/bootconfig.rst
index 0c18e3f540e6..abe2432b8eec 100644
--- a/Documentation/admin-guide/bootconfig.rst
+++ b/Documentation/admin-guide/bootconfig.rst
@@ -74,6 +74,14 @@ For example,::
In this case ``bar`` and ``baz`` is overwritten by ``qux``, and ``foo = qux``
remains.

+If you want to append the value to existing key as an array member,
+you can use ``+=`` operator. For example::
+
+ foo = bar, baz
+ foo += qux
+
+In this case, the key ``foo`` has ``bar``, ``baz`` and ``qux``.
+
Note that a sub-key and a value can not co-exist under a parent key.
For example, following config is NOT allowed.::

diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index 9a094162ea3e..4afc768489cd 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -586,7 +586,7 @@ static void xbc_node_overwrite(struct xbc_node *node, char *v)
node->next = 0;
}

-static int __init xbc_parse_kv(char **k, char *v)
+static int __init xbc_parse_kv(char **k, char *v, int op)
{
struct xbc_node *prev_parent = last_parent;
struct xbc_node *child;
@@ -605,7 +605,7 @@ static int __init xbc_parse_kv(char **k, char *v)
if (c < 0)
return c;

- if (!child) {
+ if (op == '+' || !child) {
if (!xbc_add_sibling(v, XBC_VALUE))
return -ENOMEM;
} else
@@ -781,7 +781,7 @@ int __init xbc_init(char *buf)

p = buf;
do {
- q = strpbrk(p, "{}=;\n#");
+ q = strpbrk(p, "{}=+;\n#");
if (!q) {
p = skip_spaces(p);
if (*p != '\0')
@@ -792,8 +792,14 @@ int __init xbc_init(char *buf)
c = *q;
*q++ = '\0';
switch (c) {
+ case '+':
+ if (*q++ != '=') {
+ ret = xbc_parse_error("Wrong + operator", q - 2);
+ break;
+ }
+ /* Fall through */
case '=':
- ret = xbc_parse_kv(&p, q);
+ ret = xbc_parse_kv(&p, q, c);
break;
case '{':
ret = xbc_open_brace(&p, q);
diff --git a/tools/bootconfig/test-bootconfig.sh b/tools/bootconfig/test-bootconfig.sh
index f6948790c693..04f65548ca1e 100755
--- a/tools/bootconfig/test-bootconfig.sh
+++ b/tools/bootconfig/test-bootconfig.sh
@@ -108,6 +108,19 @@ xfail grep -q "bar" $OUTFILE
xfail grep -q "baz" $OUTFILE
xpass grep -q "qux" $OUTFILE

+echo "Adding same-key values"
+cat > $TEMPCONF << EOF
+key = bar, baz
+key += qux
+EOF
+echo > $INITRD
+
+xpass $BOOTCONF -a $TEMPCONF $INITRD
+$BOOTCONF $INITRD > $OUTFILE
+xpass grep -q "bar" $OUTFILE
+xpass grep -q "baz" $OUTFILE
+xpass grep -q "qux" $OUTFILE
+
echo "=== expected failure cases ==="
for i in samples/bad-* ; do
xfail $BOOTCONF -a $i $INITRD