From: Fabien Parent <fpar...@baylibre.com>

Add the ability to check whether a property has a given value or not.
Add as well 7 test files for this feature.

abc {
   prop1 = <0 1 2 3>;
   prop2 = "value0", "value1", "value3";
};

====

To check whether an integer array contains value from a given range
use the following constraint:
    prop1 {
        type = "integer";
        value = <0x0 0xF>;
    };

To check whether a string array contains value that match a given pattern
use the following constraint:
    prop2 {
        type = "string";
        value = "value[0-9]";
    };

To check whether a particular element of an array has the correct value one
can use the following constraint:
    prop1 {
        type = "integer";
        value@2 = <2>;
    };

or

    prop2 {
        type = "string";
        value@1 = "value1";
    };

Signed-off-by: Fabien Parent <fpar...@baylibre.com>
Signed-off-by: Benoit Cousson <bcous...@baylibre.com>
---
 scripts/dtc/schema-test.c                          |  20 ++
 scripts/dtc/schema.c                               | 288 +++++++++++++++++++++
 scripts/dtc/tests/schemas/integer-array-1.schema   |  16 ++
 scripts/dtc/tests/schemas/integer-array-2.schema   |   9 +
 scripts/dtc/tests/schemas/integer-array-3.schema   |   8 +
 .../dtc/tests/schemas/pattern-matching-1.schema    |  10 +
 .../dtc/tests/schemas/pattern-matching-2.schema    |  10 +
 scripts/dtc/tests/schemas/string-array-1.schema    |  20 ++
 scripts/dtc/tests/schemas/string-array-2.schema    |   9 +
 scripts/dtc/tests/test1.dts                        |   4 +
 10 files changed, 394 insertions(+)
 create mode 100644 scripts/dtc/tests/schemas/integer-array-1.schema
 create mode 100644 scripts/dtc/tests/schemas/integer-array-2.schema
 create mode 100644 scripts/dtc/tests/schemas/integer-array-3.schema
 create mode 100644 scripts/dtc/tests/schemas/pattern-matching-1.schema
 create mode 100644 scripts/dtc/tests/schemas/pattern-matching-2.schema
 create mode 100644 scripts/dtc/tests/schemas/string-array-1.schema
 create mode 100644 scripts/dtc/tests/schemas/string-array-2.schema

diff --git a/scripts/dtc/schema-test.c b/scripts/dtc/schema-test.c
index bfc9e43..a8a5664 100644
--- a/scripts/dtc/schema-test.c
+++ b/scripts/dtc/schema-test.c
@@ -45,6 +45,26 @@ static struct schema_test tests[] = {
         "tests/schemas/array-size-3.schema", 0},
        {"Array Size #4", "tests/test1.dts",
         "tests/schemas/array-size-4.schema", 0},
+
+       /* String Array */
+       {"String Array Values #1", "tests/test1.dts",
+        "tests/schemas/string-array-1.schema", 1},
+       {"String Array Values #2", "tests/test1.dts",
+        "tests/schemas/string-array-2.schema", 0},
+
+       /* Integer Array */
+       {"Integer Array Values #1", "tests/test1.dts",
+        "tests/schemas/integer-array-1.schema", 1},
+       {"Integer Array Values #2", "tests/test1.dts",
+        "tests/schemas/integer-array-2.schema", 0},
+       {"Integer Array Values #3", "tests/test1.dts",
+        "tests/schemas/integer-array-3.schema", 0},
+
+       /* Pattern Matching */
+       {"Pattern Matching #1", "tests/test1.dts",
+        "tests/schemas/pattern-matching-1.schema", 1},
+       {"Pattern Matching #2", "tests/test1.dts",
+        "tests/schemas/pattern-matching-2.schema", 0},
 };
 
 int main(void)
diff --git a/scripts/dtc/schema.c b/scripts/dtc/schema.c
index 95ad925..d96129f 100644
--- a/scripts/dtc/schema.c
+++ b/scripts/dtc/schema.c
@@ -7,6 +7,26 @@
 #include <stdio.h>
 #include <limits.h>
 
+#define sorted_list_add(x, e) \
+       do { \
+               typeof(x) prev, i; \
+               if (!x) {\
+                       x = e; \
+                       break; \
+               } \
+               for (prev = x, i = x->next; \
+                        i && i->id < e->id; \
+                        prev = i, i = i->next) \
+                       ; \
+               e->next = i; \
+               prev->next = e; \
+       } while (0)
+
+#define for_each_safe(list, iter, iter_next) \
+       for (iter = list, iter_next = list ? list->next : NULL;\
+            iter; \
+            iter = iter_next, iter_next = iter_next ? iter_next->next : NULL)
+
 #define DT_ERROR(path, p, format, ...) \
        do { \
                dt_error(path, p, format, ##__VA_ARGS__); \
@@ -32,6 +52,21 @@ struct node_list {
        struct node_list *next;
 };
 
+struct range {
+       uint32_t low;
+       uint32_t high;
+       int id;
+
+       struct range *next;
+};
+
+struct pattern {
+       const char *text;
+       int id;
+
+       struct pattern *next;
+};
+
 struct prop_constraints {
        const char *name;
        char *type;
@@ -39,6 +74,12 @@ struct prop_constraints {
        int can_be_inherited;
        size_t min_length;
        size_t max_length;
+
+       union {
+               struct pattern *patterns;
+               struct range *ranges;
+       } value;
+       enum datatype value_type;
 };
 
 struct node_constraints {
@@ -207,11 +248,139 @@ static void dt_error(struct node_list *path,
                exit(1);
 }
 
+static void load_property_value_constraints(struct prop_constraints *pc,
+                                           struct node *schema)
+{
+       struct property *p;
+       struct pattern *pattern;
+       struct range *r;
+       uint32_t low;
+       uint32_t high;
+       int offset;
+
+       assert(pc);
+       assert(schema);
+
+       p = get_property(schema, "value");
+       if (p) {
+               switch (p->val.type) {
+               case STRING:
+                       pc->value.patterns = xmalloc(sizeof(*pattern));
+                       memset(pc->value.patterns, 0,
+                              sizeof(*pc->value.patterns));
+                       pc->value.patterns->text = p->val.val;
+                       pc->value.patterns->id = -1;
+                       pc->value_type = STRING;
+                       break;
+
+               case INTEGER:
+                       /**
+                        * Constraints:
+                        * value = <0x0 0xFF>;
+                        *
+                        * The value for each element of the cells
+                        * must be between 0x0 and 0xFF.
+                        */
+                       assert(p->val.array_size <= 2);
+
+                       low = prop_val_to_uint32(p, 0);
+                       high = p->val.array_size == 2
+                                  ? prop_val_to_uint32(p, 1)
+                                  : low;
+
+                       pc->value.ranges = xmalloc(sizeof(*r));
+                       memset(pc->value.ranges, 0, sizeof(*pc->value.ranges));
+                       pc->value.ranges->low = low;
+                       pc->value.ranges->high = high;
+                       pc->value_type = INTEGER;
+                       pc->value.ranges->id = -1;
+                       break;
+
+               default:
+                       die("Reach unreachable\n");
+               }
+       }
+
+       /**
+        * One can put a constraints on a specific cell without
+        * having to put this constraint on all the cells
+        *
+        * This can also be used to override a constraint that has
+        * been put on on cells.
+        *
+        * Ex:
+        * value = <0x0 0xFF>;
+        * value@1 = <0x24>;
+        *
+        * This will only accept cell that have a value between
+        * 0x0 and 0xFF, and will require that the second element
+        * to be equal to 0x24
+        * Ex:
+        *  - This is valid:   myprop = <0x13 0x24 0x6F 0x2D>;
+        *  - This is invalid: myprop = <0x13 0xFE 0x6F 0x2D>;
+        */
+       for (p = schema->proplist; p; p = p->next) {
+               assert(p->name);
+
+               if (strstr(p->name, "value@") != p->name)
+                       continue;
+
+               if (sscanf(p->name, "value@%u", &offset) != 1)
+                       continue;
+
+               if (offset >= pc->max_length) {
+                       die("Value offset must be lower to the "
+                               "number of elements in the array.");
+               }
+
+               if (p->val.type == INTEGER) {
+                       assert(pc->value_type == INTEGER
+                              || pc->value_type == UNDEFINED);
+                       assert(p->val.array_size <= 2);
+
+                       pc->value_type = INTEGER;
+
+                       low = prop_val_to_uint32(p, 0);
+                       high = p->val.array_size == 2
+                              ? prop_val_to_uint32(p, 1)
+                              : low;
+
+                       r = xmalloc(sizeof(*r));
+                       memset(r, 0, sizeof(*r));
+                       r->low = low;
+                       r->high = high;
+                       r->id = offset;
+                       sorted_list_add(pc->value.ranges, r);
+               } else if (p->val.type == STRING) {
+                       assert(pc->value_type == STRING
+                              || pc->value_type == UNDEFINED);
+
+                       pc->value_type = STRING;
+                       pattern = xmalloc(sizeof(*pattern));
+                       memset(pattern, 0, sizeof(*pattern));
+                       pattern->text = p->val.val;
+                       pattern->id = offset;
+                       sorted_list_add(pc->value.patterns, pattern);
+               }
+       }
+}
+
 static void free_property_constraints(struct prop_constraints *pc)
 {
+       struct pattern *p, *p_next;
+       struct range *r, *r_next;
+
        if (!pc)
                return;
 
+       if (pc->value_type == STRING) {
+               for_each_safe(pc->value.patterns, p, p_next)
+                       free(p);
+       } else if (pc->value_type == INTEGER) {
+               for_each_safe(pc->value.ranges, r, r_next)
+                       free(r);
+       }
+
        free(pc);
 }
 
@@ -256,6 +425,7 @@ load_property_constraints(struct node *schema)
                pc->max_length = prop_val_to_uint32(p, 0);
        }
 
+       load_property_value_constraints(pc, schema);
        return pc;
 }
 
@@ -287,6 +457,121 @@ static int check_types(struct property *p, struct 
prop_constraints *pc)
        return 0;
 }
 
+static inline struct range*
+find_range_for_elem_num(struct prop_constraints *pc, int num)
+{
+       struct range *r;
+
+       assert(pc);
+       assert(pc->value_type == INTEGER);
+       assert(pc->value.ranges);
+
+       for (r = pc->value.ranges; r && r->id != num; r = r->next)
+               ;
+
+       if (!r && pc->value.ranges->id == -1)
+               r = pc->value.ranges;
+
+       return r;
+}
+
+static int check_integer_value(struct property *p, struct prop_constraints *pc)
+{
+       int i;
+       struct range *r;
+       uint32_t int_value;
+
+       assert(p);
+       assert(pc);
+       assert(p->val.type == INTEGER);
+       assert(pc->value_type == INTEGER);
+       assert(pc->value.ranges);
+
+       for (i = 0; i < p->val.array_size; i++, r = r->next) {
+               r = find_range_for_elem_num(pc, i);
+               if (!r)
+                       break;
+
+               int_value = prop_val_to_uint32(p, i);
+               if (int_value < r->low || int_value > r->high)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static inline struct pattern*
+find_pattern_for_elem_num(struct prop_constraints *pc, int num)
+{
+       struct pattern *pattern;
+
+       assert(pc);
+       assert(pc->value_type == STRING);
+       assert(pc->value.patterns);
+
+       for (pattern = pc->value.patterns;
+            pattern && pattern->id != num;
+            pattern = pattern->next)
+               ;
+
+       if (!pattern && pc->value.patterns->id == -1)
+               pattern = pc->value.patterns;
+
+       return pattern;
+}
+
+static int check_string_value(struct property *p, struct prop_constraints *pc)
+{
+       pcre *re;
+       struct pattern *pattern;
+       int i;
+       int str_offset = 0;
+       int res;
+
+       assert(p);
+       assert(pc);
+       assert(p->val.type == STRING);
+
+       for (i = 0; i < p->val.array_size; i++) {
+               pattern = find_pattern_for_elem_num(pc, i);
+               if (!pattern)
+                       break;
+
+               assert(pattern->text);
+               re = compile_pattern(pattern->text);
+               if (!re)
+                       die("Invalid pattern '%s' in schema\n", pattern->text);
+
+               assert(str_offset >= 0);
+               res = pcre_exec(re, 0, p->val.val + str_offset,
+                               strlen(p->val.val + str_offset),
+                               0, 0, NULL, 0) >= 0;
+               pcre_free(re);
+
+               str_offset = get_next_string_offset(p, str_offset);
+               if (!res)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int check_value(struct property *p, struct prop_constraints *pc)
+{
+       assert(p);
+       assert(pc);
+
+       if (pc->value_type == UNDEFINED)
+               return 1;
+
+       if (p->val.type == STRING)
+               return check_string_value(p, pc);
+       else if (p->val.type == INTEGER)
+               return check_integer_value(p, pc);
+
+       return 1;
+}
+
 static int validate_properties(struct node *n,
                               struct node *schema,
                               struct node_list *path);
@@ -332,6 +617,9 @@ static int validate_property(struct node *n,
                         pc->max_length, p->val.array_size);
        }
 
+       if (!check_value(p, pc))
+               DT_ERROR(path, p, "Incorrect value.\n");
+
 end:
        free_property_constraints(pc);
        return ret;
diff --git a/scripts/dtc/tests/schemas/integer-array-1.schema 
b/scripts/dtc/tests/schemas/integer-array-1.schema
new file mode 100644
index 0000000..b7de822
--- /dev/null
+++ b/scripts/dtc/tests/schemas/integer-array-1.schema
@@ -0,0 +1,16 @@
+/dts-v1/;
+/ {
+       compatible = "compat1";
+
+       mypropint {
+               type = "integer";
+               value@0 = <0>;
+               value@1 = <2>;
+               value@2 = <4>;
+       };
+
+       mypropint2 {
+               type = "integer";
+               value = <0 5>;
+       };
+};
diff --git a/scripts/dtc/tests/schemas/integer-array-2.schema 
b/scripts/dtc/tests/schemas/integer-array-2.schema
new file mode 100644
index 0000000..a6e7628
--- /dev/null
+++ b/scripts/dtc/tests/schemas/integer-array-2.schema
@@ -0,0 +1,9 @@
+/dts-v1/;
+/ {
+       compatible = "compat1";
+       mypropint {
+               type = "integer";
+               value@0 = <0>;
+               value@1 = <3>;
+       };
+};
diff --git a/scripts/dtc/tests/schemas/integer-array-3.schema 
b/scripts/dtc/tests/schemas/integer-array-3.schema
new file mode 100644
index 0000000..b9ccc1c
--- /dev/null
+++ b/scripts/dtc/tests/schemas/integer-array-3.schema
@@ -0,0 +1,8 @@
+/dts-v1/;
+/ {
+       compatible = "compat1";
+       mypropint {
+               type = "integer";
+               value = <0 3>;
+       };
+};
diff --git a/scripts/dtc/tests/schemas/pattern-matching-1.schema 
b/scripts/dtc/tests/schemas/pattern-matching-1.schema
new file mode 100644
index 0000000..093851e
--- /dev/null
+++ b/scripts/dtc/tests/schemas/pattern-matching-1.schema
@@ -0,0 +1,10 @@
+/dts-v1/;
+/ {
+       compatible = "compat[0-9]";
+
+       abc {
+               name = "every.+";
+               is-required;
+               can-be-inherited;
+       };
+};
diff --git a/scripts/dtc/tests/schemas/pattern-matching-2.schema 
b/scripts/dtc/tests/schemas/pattern-matching-2.schema
new file mode 100644
index 0000000..0d73a15
--- /dev/null
+++ b/scripts/dtc/tests/schemas/pattern-matching-2.schema
@@ -0,0 +1,10 @@
+/dts-v1/;
+/ {
+       compatible = "compat[0-9]";
+
+       abc {
+               name = "never.+";
+               is-required;
+               can-be-inherited;
+       };
+};
diff --git a/scripts/dtc/tests/schemas/string-array-1.schema 
b/scripts/dtc/tests/schemas/string-array-1.schema
new file mode 100644
index 0000000..3d753e2
--- /dev/null
+++ b/scripts/dtc/tests/schemas/string-array-1.schema
@@ -0,0 +1,20 @@
+/dts-v1/;
+/ {
+       compatible = "compat1";
+
+       mypropstr {
+               type = "string";
+               value = "value[0-9]+";
+       };
+
+       mypropstr2 {
+               type = "string";
+               value = "value[0-9]+";
+               value@1 = "test";
+       };
+
+       mypropstr3 {
+               type = "string";
+               value@0 = "test";
+       };
+};
diff --git a/scripts/dtc/tests/schemas/string-array-2.schema 
b/scripts/dtc/tests/schemas/string-array-2.schema
new file mode 100644
index 0000000..ee1f441
--- /dev/null
+++ b/scripts/dtc/tests/schemas/string-array-2.schema
@@ -0,0 +1,9 @@
+/dts-v1/;
+/ {
+       compatible = "compat1";
+
+       mypropstr2 {
+               type = "string";
+               value = "value[0-9]+";
+       };
+};
diff --git a/scripts/dtc/tests/test1.dts b/scripts/dtc/tests/test1.dts
index a296591..7d8d745 100644
--- a/scripts/dtc/tests/test1.dts
+++ b/scripts/dtc/tests/test1.dts
@@ -1,11 +1,15 @@
 /dts-v1/;
 / {
        compatible = "root", "node";
+       everywhere = <0xf 0xa 0xb>;
 
        node1 {
                compatible = "compat1";
                mypropint = <0 2 4 6>;
+               mypropint2 = <1 2 3>;
                mypropstr = "value0", "value1", "value2";
+               mypropstr2 = "value0", "test", "value2";
+               mypropstr3 = "test", "toto", "tata";
 
                subnode1 {
                        compatible = "compat2";
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to