yin parser FEATURE in YANG 1.1 support enumeration and bits restrictions
Allow restriction on derived types from some other enumeration/bits based
type.
diff --git a/src/common.h b/src/common.h
index 72f34dc..a41f78a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -149,9 +149,13 @@
LYE_DUPLEAFLIST,
LYE_DUPLIST,
LYE_NOUNIQ,
+ LYE_ENUM_INVAL,
+ LYE_ENUM_INNAME,
LYE_ENUM_DUPVAL,
LYE_ENUM_DUPNAME,
LYE_ENUM_WS,
+ LYE_BITS_INVAL,
+ LYE_BITS_INNAME,
LYE_BITS_DUPVAL,
LYE_BITS_DUPNAME,
LYE_INMOD,
diff --git a/src/libyang.h b/src/libyang.h
index d915b9d..cf22c4d 100644
--- a/src/libyang.h
+++ b/src/libyang.h
@@ -1169,11 +1169,15 @@
LYVE_DUPLEAFLIST, /**< multiple instances of leaf-list */
LYVE_DUPLIST, /**< multiple instances of list */
LYVE_NOUNIQ, /**< unique leaves match on 2 list instances (data) */
- LYVE_ENUM_DUPVAL, /**< duplicated enum value (schema) */
- LYVE_ENUM_DUPNAME, /**< duplicated enum name (schema) */
+ LYVE_ENUM_INVAL, /**< invalid enum value (schema) */
+ LYVE_ENUM_INNAME, /**< invalid enum name (schema) */
+ /* */
+ /* */
LYVE_ENUM_WS, /**< enum name with leading/trailing whitespaces (schema) */
- LYVE_BITS_DUPVAL, /**< duplicated bits value (schema) */
- LYVE_BITS_DUPNAME, /**< duplicated bits name (schema) */
+ LYVE_BITS_INVAL, /**< invalid bits value (schema) */
+ LYVE_BITS_INNAME, /**< invalid bits name (schema) */
+ /* */
+ /* */
LYVE_INMOD, /**< invalid module name */
/* */
LYVE_KEY_NLEAF, /**< list key is not a leaf (schema) */
diff --git a/src/log.c b/src/log.c
index a8626e8..81bb922 100644
--- a/src/log.c
+++ b/src/log.c
@@ -146,10 +146,14 @@
/* LYE_DUPLEAFLIST */ "Duplicated instance of \"%s\" leaf-list (\"%s\").",
/* LYE_DUPLIST */ "Duplicated instance of \"%s\" list.",
/* LYE_NOUNIQ */ "Unique data leaf(s) \"%s\" not satisfied in \"%s\" and \"%s\".",
-/* LYE_ENUM_DUPVAL */ "The value \"%d\" of \"%s\" enum has already been assigned to another enum value.",
+/* LYE_ENUM_INVAL */ "Invalid value \"%d\" of \"%s\" enum - restricted enum value does not match the base type value.",
+/* LYE_ENUM_INNAME */ "Invalid enum name \"%s\" - restricted enum must use only base type enum names.",
+/* LYE_ENUM_DUPVAL */ "The value \"%d\" of \"%s\" enum has already been assigned to \"%s\" enum.",
/* LYE_ENUM_DUPNAME */ "The enum name \"%s\" has already been assigned to another enum.",
/* LYE_ENUM_WS */ "The enum name \"%s\" includes invalid leading or trailing whitespaces.",
-/* LYE_BITS_DUPVAL */ "The position \"%d\" of \"%s\" bits has already been used to another named bit.",
+/* LYE_BITS_INVAL */ "Invalid position \"%d\" of \"%s\" bit - restricted bits position does not match the base type position.",
+/* LYE_BITS_INNAME */ "Invalid bit name \"%s\" - restricted bits must use only base type bits names.",
+/* LYE_BITS_DUPVAL */ "The position \"%d\" of \"%s\" bit has already been assigned to \"%s\" bit.",
/* LYE_BITS_DUPNAME */ "The bit name \"%s\" has already been assigned to another bit.",
/* LYE_INMOD */ "Module name \"%s\" refers to an unknown module.",
/* LYE_INMOD_LEN */ "Module name \"%.*s\" refers to an unknown module.",
@@ -233,11 +237,15 @@
LYVE_DUPLEAFLIST, /* LYE_DUPLEAFLIST */
LYVE_DUPLIST, /* LYE_DUPLIST */
LYVE_NOUNIQ, /* LYE_NOUNIQ */
- LYVE_ENUM_DUPVAL, /* LYE_ENUM_DUPVAL */
- LYVE_ENUM_DUPNAME, /* LYE_ENUM_DUPNAME */
+ LYVE_ENUM_INVAL, /* LYE_ENUM_INVAL */
+ LYVE_ENUM_INNAME, /* LYE_ENUM_INNAME */
+ LYVE_ENUM_INVAL, /* LYE_ENUM_DUPVAL */
+ LYVE_ENUM_INNAME, /* LYE_ENUM_DUPNAME */
LYVE_ENUM_WS, /* LYE_ENUM_WS */
- LYVE_BITS_DUPVAL, /* LYE_BITS_DUPVAL */
- LYVE_BITS_DUPNAME, /* LYE_BITS_DUPNAME */
+ LYVE_BITS_INVAL, /* LYE_BITS_INVAL */
+ LYVE_BITS_INNAME, /* LYE_BITS_INNAME */
+ LYVE_BITS_INVAL, /* LYE_BITS_DUPVAL */
+ LYVE_BITS_INNAME, /* LYE_BITS_DUPNAME */
LYVE_INMOD, /* LYE_INMOD */
LYVE_INMOD, /* LYE_INMOD_LEN */
LYVE_KEY_NLEAF, /* LYE_KEY_NLEAF */
diff --git a/src/parser.c b/src/parser.c
index 8a9e819..1647b18 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -869,8 +869,10 @@
break;
case LY_TYPE_BITS:
- /* locate bits structure with the bits definitions */
- for (type = stype; type->der->type.der; type = &type->der->type);
+ /* locate bits structure with the bits definitions
+ * since YANG 1.1 allows restricted bits, it is the first
+ * bits type with some explicit bit specification */
+ for (type = stype; !type->info.bits.count; type = &type->der->type);
/* allocate the array of pointers to bits definition */
node->value.bit = calloc(type->info.bits.count, sizeof *node->value.bit);
@@ -1025,8 +1027,10 @@
return EXIT_FAILURE;
}
- /* locate enums structure with the enumeration definitions */
- for (type = stype; type->der->type.der; type = &type->der->type);
+ /* locate enums structure with the enumeration definitions,
+ * since YANG 1.1 allows restricted enums, it is the first
+ * enum type with some explicit enum specification */
+ for (type = stype; !type->info.enums.count; type = &type->der->type);
/* find matching enumeration value */
for (i = 0; i < type->info.enums.count; i++) {
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 5008d38..3dc30e9 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -1279,7 +1279,8 @@
for (i = 0; i < j; i++) {
if (typ->type->info.enums.enm[i].value == typ->type->info.enums.enm[j].value) {
LOGVAL(LYE_ENUM_DUPVAL, LY_VLOG_NONE, NULL,
- typ->type->info.enums.enm[j].value, typ->type->info.enums.enm[j].name);
+ typ->type->info.enums.enm[j].value, typ->type->info.enums.enm[j].name,
+ typ->type->info.enums.enm[i].name);
goto error;
}
}
@@ -1339,7 +1340,7 @@
/* check that the value is unique */
for (i = 0; i < j; i++) {
if (typ->type->info.bits.bit[i].pos == bit->pos) {
- LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL, bit->pos, bit->name);
+ LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL, bit->pos, bit->name, typ->type->info.bits.bit[i].name);
goto error;
}
}
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 98ee822..73592b8 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -241,7 +241,9 @@
struct lys_node *siter;
struct lyxml_elem *next, *node;
struct lys_restr **restr;
- struct lys_type_bit bit;
+ struct lys_type_bit bit, *bits_sc;
+ struct lys_type_enum *enms_sc; /* shortcut */
+ struct lys_type *dertype;
int i, j, rc, val_set;
int ret = -1;
int64_t v, v_;
@@ -314,15 +316,21 @@
goto error;
}
}
- if (!type->der->type.der && !type->info.bits.count) {
- /* type is derived directly from buit-in bits type and bit statement is required */
- LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "bit", "type");
- goto error;
- }
- if (type->der->type.der && type->info.bits.count) {
- /* type is not directly derived from buit-in bits type and bit statement is prohibited */
- LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "bit");
- goto error;
+ dertype = &type->der->type;
+ if (!dertype->der) {
+ if (!type->info.bits.count) {
+ /* type is derived directly from buit-in bits type and bit statement is required */
+ LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "bit", "type");
+ goto error;
+ }
+ } else {
+ for (; !dertype->info.enums.count; dertype = &dertype->der->type);
+ if (module->version < 2 && type->info.bits.count) {
+ /* type is not directly derived from buit-in bits type and bit statement is prohibited,
+ * since YANG 1.1 the bit statements can be used to restrict the base bits type */
+ LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "bit");
+ goto error;
+ }
}
type->info.bits.bit = calloc(type->info.bits.count, sizeof *type->info.bits.bit);
@@ -346,15 +354,31 @@
goto error;
}
- /* check the name uniqueness */
- for (j = 0; j < i; j++) {
- if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
- LOGVAL(LYE_BITS_DUPNAME, LY_VLOG_NONE, NULL, type->info.bits.bit[i].name);
+ if (!dertype->der) { /* directly derived type from bits built-in type */
+ /* check the name uniqueness */
+ for (j = 0; j < i; j++) {
+ if (!strcmp(type->info.bits.bit[j].name, type->info.bits.bit[i].name)) {
+ LOGVAL(LYE_BITS_DUPNAME, LY_VLOG_NONE, NULL, type->info.bits.bit[i].name);
+ type->info.bits.count = i + 1;
+ goto error;
+ }
+ }
+ } else {
+ /* restricted bits type - the name MUST be used in the base type */
+ bits_sc = dertype->info.bits.bit;
+ for (j = 0; j < dertype->info.bits.count; j++) {
+ if (ly_strequal(bits_sc[j].name, value, 1)) {
+ break;
+ }
+ }
+ if (j == dertype->info.bits.count) {
+ LOGVAL(LYE_BITS_INNAME, LY_VLOG_NONE, NULL, value);
type->info.bits.count = i + 1;
goto error;
}
}
+
p_ = -1;
LY_TREE_FOR(next->child, node) {
if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
@@ -363,6 +387,12 @@
}
if (!strcmp(node->name, "position")) {
+ if (p_ != -1) {
+ LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
+ type->info.bits.count = i + 1;
+ goto error;
+ }
+
GETVAL(value, node, "value");
p_ = strtoll(value, NULL, 10);
@@ -374,18 +404,21 @@
}
type->info.bits.bit[i].pos = (uint32_t)p_;
- /* keep the highest enum value for automatic increment */
- if (type->info.bits.bit[i].pos >= p) {
- p = type->info.bits.bit[i].pos;
- p++;
- } else {
- /* check that the value is unique */
- for (j = 0; j < i; j++) {
- if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
- LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL,
- type->info.bits.bit[i].pos, type->info.bits.bit[i].name);
- type->info.bits.count = i + 1;
- goto error;
+ if (!dertype->der) { /* directly derived type from bits built-in type */
+ /* keep the highest enum value for automatic increment */
+ if (type->info.bits.bit[i].pos >= p) {
+ p = type->info.bits.bit[i].pos;
+ p++;
+ } else {
+ /* check that the value is unique */
+ for (j = 0; j < i; j++) {
+ if (type->info.bits.bit[j].pos == type->info.bits.bit[i].pos) {
+ LOGVAL(LYE_BITS_DUPVAL, LY_VLOG_NONE, NULL,
+ type->info.bits.bit[i].pos, type->info.bits.bit[i].name,
+ type->info.bits.bit[j].name);
+ type->info.bits.count = i + 1;
+ goto error;
+ }
}
}
}
@@ -394,16 +427,36 @@
goto error;
}
}
- if (p_ == -1) {
- /* assign value automatically */
- if (p > UINT32_MAX) {
- LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "4294967295", "bit/position");
- type->info.bits.count = i + 1;
- goto error;
+
+ if (!dertype->der) { /* directly derived type from bits built-in type */
+ if (p_ == -1) {
+ /* assign value automatically */
+ if (p > UINT32_MAX) {
+ LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "4294967295", "bit/position");
+ type->info.bits.count = i + 1;
+ goto error;
+ }
+ type->info.bits.bit[i].pos = (uint32_t)p;
+ type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
+ p++;
}
- type->info.bits.bit[i].pos = (uint32_t)p;
- type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
- p++;
+ } else { /* restricted bits type */
+ if (p_ == -1) {
+ /* automatically assign position from base type */
+ type->info.bits.bit[i].pos = bits_sc[j].pos;
+ type->info.bits.bit[i].flags |= LYS_AUTOASSIGNED;
+ } else {
+ /* check that the assigned position corresponds to the original
+ * position of the bit in the base type */
+ if (p_ != bits_sc[j].pos) {
+ /* p_ - assigned position in restricted bits
+ * bits_sc[j].pos - position assigned to the corresponding bit (detected above) in base type */
+ LOGVAL(LYE_BITS_INVAL, LY_VLOG_NONE, NULL, type->info.bits.bit[i].pos,
+ type->info.bits.bit[i].name);
+ type->info.bits.count = i + 1;
+ goto error;
+ }
+ }
}
/* keep them ordered by position */
@@ -503,15 +556,21 @@
goto error;
}
}
- if (!type->der->type.der && !type->info.enums.count) {
- /* type is derived directly from buit-in enumeartion type and enum statement is required */
- LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "enum", "type");
- goto error;
- }
- if (type->der->type.der && type->info.enums.count) {
- /* type is not directly derived from buit-in enumeration type and enum statement is prohibited */
- LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "enum");
- goto error;
+ dertype = &type->der->type;
+ if (!dertype->der) {
+ if (!type->info.enums.count) {
+ /* type is derived directly from buit-in enumeartion type and enum statement is required */
+ LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "enum", "type");
+ goto error;
+ }
+ } else {
+ for (; !dertype->info.enums.count; dertype = &dertype->der->type);
+ if (module->version < 2 && type->info.enums.count) {
+ /* type is not directly derived from built-in enumeration type and enum statement is prohibited
+ * in YANG 1.0, since YANG 1.1 enum statements can be used to restrict the base enumeration type */
+ LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "enum");
+ goto error;
+ }
}
type->info.enums.enm = calloc(type->info.enums.count, sizeof *type->info.enums.enm);
@@ -520,7 +579,7 @@
goto error;
}
- val_set = v = 0;
+ v = 0;
i = -1;
LY_TREE_FOR(yin->child, next) {
i++;
@@ -545,15 +604,31 @@
goto error;
}
- /* check the name uniqueness */
- for (j = 0; j < i; j++) {
- if (!strcmp(type->info.enums.enm[j].name, type->info.enums.enm[i].name)) {
- LOGVAL(LYE_ENUM_DUPNAME, LY_VLOG_NONE, NULL, type->info.enums.enm[i].name);
+ if (!dertype->der) { /* directly derived type from enumeration built-in type */
+ /* check the name uniqueness */
+ for (j = 0; j < i; j++) {
+ if (ly_strequal(type->info.enums.enm[j].name, value, 1)) {
+ LOGVAL(LYE_ENUM_DUPNAME, LY_VLOG_NONE, NULL, value);
+ type->info.enums.count = i + 1;
+ goto error;
+ }
+ }
+ } else {
+ /* restricted enumeration type - the name MUST be used in the base type */
+ enms_sc = dertype->info.enums.enm;
+ for (j = 0; j < dertype->info.enums.count; j++) {
+ if (ly_strequal(enms_sc[j].name, value, 1)) {
+ break;
+ }
+ }
+ if (j == dertype->info.enums.count) {
+ LOGVAL(LYE_ENUM_INNAME, LY_VLOG_NONE, NULL, value);
type->info.enums.count = i + 1;
goto error;
}
}
+ val_set = 0;
LY_TREE_FOR(next->child, node) {
if (!node->ns || strcmp(node->ns->value, LY_NSYIN)) {
/* garbage */
@@ -561,6 +636,12 @@
}
if (!strcmp(node->name, "value")) {
+ if (val_set) {
+ LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, node->name, next->name);
+ type->info.enums.count = i + 1;
+ goto error;
+ }
+
GETVAL(value, node, "value");
v_ = strtoll(value, NULL, 10);
@@ -572,18 +653,21 @@
}
type->info.enums.enm[i].value = v_;
- /* keep the highest enum value for automatic increment */
- if (!val_set || type->info.enums.enm[i].value > v) {
- v = type->info.enums.enm[i].value;
- v++;
- } else {
- /* check that the value is unique */
- for (j = 0; j < i; j++) {
- if (type->info.enums.enm[j].value == type->info.enums.enm[i].value) {
- LOGVAL(LYE_ENUM_DUPVAL, LY_VLOG_NONE, NULL,
- type->info.enums.enm[i].value, type->info.enums.enm[i].name);
- type->info.enums.count = i + 1;
- goto error;
+ if (!dertype->der) { /* directly derived type from enumeration built-in type */
+ /* keep the highest enum value for automatic increment */
+ if (type->info.enums.enm[i].value > v) {
+ v = type->info.enums.enm[i].value;
+ v++;
+ } else {
+ /* check that the value is unique */
+ for (j = 0; j < i; j++) {
+ if (type->info.enums.enm[j].value == type->info.enums.enm[i].value) {
+ LOGVAL(LYE_ENUM_DUPVAL, LY_VLOG_NONE, NULL,
+ type->info.enums.enm[i].value, type->info.enums.enm[i].name,
+ type->info.enums.enm[j].name);
+ type->info.enums.count = i + 1;
+ goto error;
+ }
}
}
}
@@ -593,16 +677,36 @@
goto error;
}
}
- if (!val_set) {
- /* assign value automatically */
- if (v > INT32_MAX) {
- LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "2147483648", "enum/value");
- type->info.enums.count = i + 1;
- goto error;
+
+ if (!dertype->der) { /* directly derived type from enumeration */
+ if (!val_set) {
+ /* assign value automatically */
+ if (v > INT32_MAX) {
+ LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, "2147483648", "enum/value");
+ type->info.enums.count = i + 1;
+ goto error;
+ }
+ type->info.enums.enm[i].value = v;
+ type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
+ v++;
}
- type->info.enums.enm[i].value = v;
- type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
- v++;
+ } else { /* restricted enum type */
+ if (!val_set) {
+ /* automatically assign value from base type */
+ type->info.enums.enm[i].value = enms_sc[j].value;
+ type->info.enums.enm[i].flags |= LYS_AUTOASSIGNED;
+ } else {
+ /* check that the assigned value corresponds to the original
+ * value of the enum in the base type */
+ if (v_ != enms_sc[j].value) {
+ /* v_ - assigned value in restricted enum
+ * enms_sc[j].value - value assigned to the corresponding enum (detected above) in base type */
+ LOGVAL(LYE_ENUM_INVAL, LY_VLOG_NONE, NULL,
+ type->info.enums.enm[i].value, type->info.enums.enm[i].name);
+ type->info.enums.count = i + 1;
+ goto error;
+ }
+ }
}
}
break;