yin parser: CHANGE: review code and validity checks according to RFC 6020 sec 7.7
- list statement with key and unique substatements
diff --git a/src/parser/yin.c b/src/parser/yin.c
index 3466362..f555d52 100644
--- a/src/parser/yin.c
+++ b/src/parser/yin.c
@@ -220,6 +220,52 @@
return EXIT_SUCCESS;
}
+static int check_key(struct ly_mnode_leaf *key, uint8_t flags, struct ly_mnode_leaf **list, int index, unsigned int line, const char *name, int len)
+{
+ char *dup = NULL;
+ int j;
+
+ /* existence */
+ if (!key) {
+ if (name[len] != '\0') {
+ dup = strdup(name);
+ dup[len] = '\0';
+ name = dup;
+ }
+ LOGVAL(VE_KEY_MISS, line, name);
+ free(dup);
+ return EXIT_FAILURE;
+ }
+
+ /* uniqueness */
+ for (j = index - 1; j >= 0; j--) {
+ if (list[index] == list[j]) {
+ LOGVAL(VE_KEY_DUP, line, key->name);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* key is a leaf */
+ if (key->nodetype != LY_NODE_LEAF) {
+ LOGVAL(VE_KEY_NLEAF, line, key->name);
+ return EXIT_FAILURE;
+ }
+
+ /* type of the leaf is not built-in empty */
+ if (key->type.base == LY_TYPE_EMPTY) {
+ LOGVAL(VE_KEY_TYPE, line, key->name);
+ return EXIT_FAILURE;
+ }
+
+ /* config attribute is the same as of the list */
+ if ((flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
+ LOGVAL(VE_KEY_CONFIG, line, key->name);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
static int check_default(struct ly_type *type, const char* value)
{
/* TODO - RFC 6020, sec. 7.3.4 */
@@ -1349,29 +1395,31 @@
static struct ly_mnode *read_yin_list(struct ly_module *module,
struct ly_mnode *parent,
- struct lyxml_elem *node)
+ struct lyxml_elem *yin)
{
struct ly_mnode *retval, *mnode;
struct ly_mnode_list *list;
- struct ly_mnode_leaf *key;
- struct lyxml_elem *sub, *next, root = {0};
- int i, j, r;
+ struct ly_unique *uniq_s;
+ struct lyxml_elem *sub, *next, root = {0}, uniq = {0};
+ int i, r;
size_t len;
- int c_tpdf = 0;
- const char *key_str = NULL, *s;
- char *dup;
+ int c_tpdf = 0, c_must = 0, c_uniq = 0;
+ int f_ordr = 0, f_max = 0, f_min = 0;
+ const char *key_str = NULL, *uniq_str, *value;
+ char *auxs;
+ unsigned long val;
list = calloc(1, sizeof *list);
list->nodetype = LY_NODE_LIST;
list->prev = (struct ly_mnode *)list;
retval = (struct ly_mnode *)list;
- if (read_yin_common(module, parent, retval, node, 1)) {
+ if (read_yin_common(module, parent, retval, yin, 1)) {
goto error;
}
/* process list's specific children */
- LY_TREE_FOR_SAFE(node->child, next, sub) {
+ LY_TREE_FOR_SAFE(yin->child, next, sub) {
/* data statements */
if (!strcmp(sub->name, "container") ||
!strcmp(sub->name, "leaf-list") ||
@@ -1387,56 +1435,180 @@
} else if (!strcmp(sub->name, "key")) {
/* check cardinality 0..1 */
if (list->keys_size) {
- LOGVAL(VE_TOOMANY, LOGLINE(sub), "key", list->name);
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, list->name);
goto error;
}
/* count the number of keys */
- key_str = s = lyxml_get_attr(sub, "value", NULL);
- if (!s) {
- LOGVAL(VE_MISSARG, LOGLINE(sub), "value", "key");
- goto error;
- }
- while((s = strpbrk(s, " \t\n"))) {
+ GETVAL(value, sub, "value");
+ key_str = value;
+ while((value = strpbrk(value, " \t\n"))) {
list->keys_size++;
- while(isspace(*s)) {
- s++;
+ while(isspace(*value)) {
+ value++;
}
}
list->keys_size++;
-
list->keys = calloc(list->keys_size, sizeof *list->keys);
-
+ } else if (!strcmp(sub->name, "unique")) {
+ c_uniq++;
+ lyxml_unlink_elem(sub);
+ lyxml_add_child(&uniq, sub);
} else if (!strcmp(sub->name, "typedef")) {
c_tpdf++;
+ } else if (!strcmp(sub->name, "must")) {
+ c_must++;
+
+ /* optional stetments */
+ } else if (!strcmp(sub->name, "ordered-by")) {
+ if (f_ordr) {
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
+ goto error;
+ }
+ /* just checking the flags in llist is not sufficient, we would
+ * allow multiple ordered-by statements with the "system" value
+ */
+ f_ordr = 1;
+
+ if (list->flags & LY_NODE_CONFIG_R) {
+ /* RFC 6020, 7.7.5 - ignore ordering when the list represents
+ * state data
+ */
+ lyxml_free_elem(module->ctx, sub);
+ continue;
+ }
+
+ GETVAL(value, sub, "value");
+ if (!strcmp(value, "user")) {
+ list->flags |= LY_NODE_USERORDERED;
+ } else if (strcmp(value, "system")) {
+ LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
+ goto error;
+ } /* else system is the default value, so we can ignore it */
+
+ lyxml_free_elem(module->ctx, sub);
+ } else if (!strcmp(sub->name, "min-elements")) {
+ if (f_min) {
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
+ goto error;
+ }
+ f_min = 1;
+
+ GETVAL(value, sub, "value");
+ while(isspace(value[0])) {
+ value++;
+ }
+
+ /* convert it to uint32_t */
+ errno = 0;
+ auxs = NULL;
+ val = strtoul(value, &auxs, 10);
+ if (*auxs || value[0] == '-' || errno || val > UINT32_MAX) {
+ LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
+ goto error;
+ }
+ list->min = (uint32_t)val;
+ lyxml_free_elem(module->ctx, sub);
+ } else if (!strcmp(sub->name, "max-elements")) {
+ if (f_max) {
+ LOGVAL(VE_TOOMANY, LOGLINE(sub), sub->name, yin->name);
+ goto error;
+ }
+ f_max = 1;
+
+ GETVAL(value, sub, "value");
+ while(isspace(value[0])) {
+ value++;
+ }
+
+ /* convert it to uint32_t */
+ errno = 0;
+ auxs = NULL;
+ val = strtoul(value, &auxs, 10);
+ if (*auxs || value[0] == '-' || errno || val == 0 || val > UINT32_MAX) {
+ LOGVAL(VE_INARG, LOGLINE(sub), value, sub->name);
+ goto error;
+ }
+ list->max = (uint32_t)val;
+ lyxml_free_elem(module->ctx, sub);
}
}
/* check - if list is configuration, key statement is mandatory */
if ((list->flags & LY_NODE_CONFIG_W) && !key_str) {
- LOGVAL(VE_MISSSTMT2, LOGLINE(node), "key", "list");
+ LOGVAL(VE_MISSSTMT2, LOGLINE(yin), "key", "list");
+ goto error;
+ }
+ if (list->max && list->min > list->max) {
+ LOGVAL(VE_SPEC, LOGLINE(yin), "\"min-elements\" is bigger than \"max-elements\".");
goto error;
}
/* middle part - process nodes with cardinality of 0..n except the data nodes */
if (c_tpdf) {
- list->tpdf_size = c_tpdf;
list->tpdf = calloc(c_tpdf, sizeof *list->tpdf);
- c_tpdf = 0;
}
- LY_TREE_FOR_SAFE(node->child, next, sub) {
+ LY_TREE_FOR_SAFE(yin->child, next, sub) {
if (!strcmp(sub->name, "typedef")) {
- r = fill_yin_typedef(module, retval, sub, &list->tpdf[c_tpdf]);
- c_tpdf++;
+ r = fill_yin_typedef(module, retval, sub, &list->tpdf[list->tpdf_size]);
+ list->tpdf_size++;
if (r) {
- list->tpdf_size = c_tpdf;
goto error;
}
lyxml_free_elem(module->ctx, sub);
}
}
+ /* process unique statements */
+ if (c_uniq) {
+ list->unique = calloc(c_uniq, sizeof *list->unique);
+ }
+ LY_TREE_FOR_SAFE(uniq.child, next, sub) {
+ /* count the number of unique values */
+ GETVAL(value, sub, "value");
+ uniq_str = value;
+ uniq_s = &list->unique[list->unique_size];
+ while((value = strpbrk(value, " \t\n"))) {
+ uniq_s->leafs_size++;
+ while(isspace(*value)) {
+ value++;
+ }
+ }
+ uniq_s->leafs_size++;
+ uniq_s->leafs = calloc(uniq_s->leafs_size, sizeof *uniq_s->leafs);
+ list->unique_size++;
+
+ /* interconnect unique values with the leafs */
+ /* TODO - include searching in uses/grouping */
+ for (i = 0; i < uniq_s->leafs_size; i++) {
+ if ((value = strpbrk(uniq_str, " \t\n"))) {
+ len = value - uniq_str;
+ while(isspace(*value)) {
+ value++;
+ }
+ } else {
+ len = strlen(uniq_str);
+ }
+ LY_TREE_FOR(list->child, mnode) {
+ if (!strncmp(mnode->name, uniq_str, len) && !mnode->name[len]) {
+ uniq_s->leafs[i] = (struct ly_mnode_leaf *)mnode;
+ break;
+ }
+ }
+
+ if (check_key(uniq_s->leafs[i], list->flags, uniq_s->leafs, i, LOGLINE(yin), uniq_str, len)) {
+ goto error;
+ }
+
+ /* prepare for next iteration */
+ while (value && isspace(*value)) {
+ value++;
+ }
+ uniq_str = value;
+ }
+ }
+
/* last part - process data nodes */
LY_TREE_FOR_SAFE(root.child, next, sub) {
if (!strcmp(sub->name, "container")) {
@@ -1477,65 +1649,30 @@
/* TODO - include searching in uses/grouping */
for (i = 0; i < list->keys_size; i++) {
/* get the key name */
- if ((s = strpbrk(key_str, " \t\n"))) {
- len = s - key_str;
+ if ((value = strpbrk(key_str, " \t\n"))) {
+ len = value - key_str;
+ while(isspace(*value)) {
+ value++;
+ }
} else {
len = strlen(key_str);
}
LY_TREE_FOR(list->child, mnode) {
if (!strncmp(mnode->name, key_str, len) && !mnode->name[len]) {
- list->keys[i] = mnode;
+ list->keys[i] = (struct ly_mnode_leaf *)mnode;
break;
}
}
- key = (struct ly_mnode_leaf *)list->keys[i];
- /* existence */
- if (!key) {
- if ((s = strpbrk(key_str, " \t\n"))) {
- len = s - key_str;
- dup = strdup(key_str);
- dup[len] = '\0';
- key_str = dup;
- }
- LOGVAL(VE_KEY_MISS, LOGLINE(node), key_str);
- if (s) {
- free(dup);
- }
- goto error;
- }
-
- /* uniqueness */
- for (j = i - 1; j >= 0; j--) {
- if (list->keys[i] == list->keys[j]) {
- LOGVAL(VE_KEY_DUP, LOGLINE(node), key->name, list->name);
- goto error;
- }
- }
-
- /* key is a leaf */
- if (key->nodetype != LY_NODE_LEAF) {
- LOGVAL(VE_KEY_NLEAF, LOGLINE(node), key->name, list->name);
- goto error;
- }
-
- /* type of the leaf is not built-in empty */
- if (key->type.base == LY_TYPE_EMPTY) {
- LOGVAL(VE_KEY_TYPE, LOGLINE(node), key->name, list->name);
- goto error;
- }
-
- /* config attribute is the same as of the list */
- if ((list->flags & LY_NODE_CONFIG_MASK) != (key->flags & LY_NODE_CONFIG_MASK)) {
- LOGVAL(VE_KEY_CONFIG, LOGLINE(node), key->name, list->name);
+ if (check_key(list->keys[i], list->flags, list->keys, i, LOGLINE(yin), key_str, len)) {
goto error;
}
/* prepare for next iteration */
- while (s && isspace(*s)) {
- s++;
+ while (value && isspace(*value)) {
+ value++;
}
- key_str = s;
+ key_str = value;
}
return retval;