options: improve handling of negations when parsing space separated values
authorJo-Philipp Wich <jo@mein.io>
Fri, 26 May 2017 16:42:05 +0000 (18:42 +0200)
committerJo-Philipp Wich <jo@mein.io>
Fri, 26 May 2017 16:52:28 +0000 (18:52 +0200)
Improve the space separated list parser to interprete "val1 ! val2"
as ("val1", "!val2") instead of ("val1", "!", "val2").

This corrects parsing of sections like ...

    config rule
        option sec_ip '! 1.1.1.0/24'

... which previously errored out with:

    Warning: Option @rule[0].src_ip has invalid value '!'

Fixes FS#806.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
options.c

index d88d3ba09b50b6f17173af7fbac5071a692fe440..ae6bf5dbd89ec0da9462a75ce3ece2567f4cc249 100644 (file)
--- a/options.c
+++ b/options.c
@@ -891,7 +891,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                   struct uci_section *section)
 {
        char *p, *v;
-       bool known;
+       bool known, inv;
        struct uci_element *e, *l;
        struct uci_option *o;
        const struct fw3_option *opt;
@@ -953,10 +953,30 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                }
                                else
                                {
+                                       inv = false;
                                        dest = (struct list_head *)((char *)s + opt->offset);
 
                                        for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
                                        {
+                                               /* If we encounter a sole "!" token, assume that it
+                                                * is meant to be part of the next token, so silently
+                                                * skip it and remember the state... */
+                                               if (!strcmp(p, "!"))
+                                               {
+                                                       inv = true;
+                                                       continue;
+                                               }
+
+                                               /* The previous token was a sole "!", rewind pointer
+                                                * back by one byte to precede the value with an
+                                                * exclamation mark which effectively turns
+                                                * ("!", "foo") into ("!foo") */
+                                               if (inv)
+                                               {
+                                                       *--p = '!';
+                                                       inv = false;
+                                               }
+
                                                if (!opt->parse(dest, p, true))
                                                {
                                                        warn_elem(e, "has invalid value '%s'", p);
@@ -964,6 +984,15 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                                        continue;
                                                }
                                        }
+
+                                       /* The last token was a sole "!" without any subsequent
+                                        * text, so pass it to the option parser as-is. */
+                                       if (inv && !opt->parse(dest, "!", true))
+                                       {
+                                               warn_elem(e, "has invalid value '%s'", p);
+                                               valid = false;
+                                               continue;
+                                       }
                                }
                        }