yin parser FEATURE support length restriction in binary type
TODO - it is not yet checked whether the new restriction breaks the
restriction set by the type from which the new type is derived.
diff --git a/src/parser/yin.c b/src/parser/yin.c
index ef5d907..6b9cb09 100644
--- a/src/parser/yin.c
+++ b/src/parser/yin.c
@@ -400,6 +400,132 @@
return EXIT_FAILURE;
}
+static int
+check_length(const char *expr, struct ly_type *type, unsigned int line)
+{
+ const char *c = expr;
+ char *tail;
+ uint64_t limit = 0, n;
+ int flg = 1; /* first run flag */
+
+ assert(expr);
+
+ /* TODO check compatibility with the restriction defined on type from which this type is derived,
+ * it will be the same function to check that the value from instance data respect the restriction */
+ (void)type;
+
+lengthpart:
+
+ while (isspace(*c)) {
+ c++;
+ }
+
+ /* lower boundary or explicit number */
+ if (!strncmp(c, "max", 3)) {
+max:
+ c += 3;
+ while (isspace(*c)) {
+ c++;
+ }
+ if (*c != '\0') {
+ goto error;
+ }
+
+ return EXIT_SUCCESS;
+
+ } else if (!strncmp(c, "min", 3)) {
+ if (!flg) {
+ /* min cannot be used elsewhere than in the first length-part */
+ goto error;
+ } else {
+ flg = 0;
+ /* remember value/lower boundary */
+ limit = 0;
+ }
+ c += 3;
+ while (isspace(*c)) {
+ c++;
+ }
+
+ if (*c == '|') {
+ c++;
+ /* process next length-parth */
+ goto lengthpart;
+ } else if (*c == '\0') {
+ return EXIT_SUCCESS;
+ } else if (!strncmp(c, "..", 2)) {
+upper:
+ c += 2;
+ while (isspace(*c)) {
+ c++;
+ }
+ if (*c == '\0') {
+ goto error;
+ }
+
+ /* upper boundary */
+ if (!strncmp(c, "max", 3)) {
+ goto max;
+ }
+
+ if (!isdigit(*c)) {
+ goto error;
+ }
+
+ n = strtol(c, &tail, 10);
+ c = tail;
+ while (isspace(*c)) {
+ c++;
+ }
+ if (n <= limit) {
+ goto error;
+ }
+ if (*c == '\0') {
+ return EXIT_SUCCESS;
+ } else if (*c == '|') {
+ c++;
+ /* remember the uppre boundary for check in next part */
+ limit = n;
+ /* process next length-parth */
+ goto lengthpart;
+ } else {
+ goto error;
+ }
+ } else {
+ goto error;
+ }
+
+ } else if (isdigit(*c)) {
+ /* number */
+ n = strtol(c, &tail, 10);
+ c = tail;
+ while (isspace(*c)) {
+ c++;
+ }
+ /* skip limit check in first length-part check */
+ if (!flg && n <= limit) {
+ goto error;
+ }
+ flg = 0;
+ limit = n;
+
+ if (*c == '|') {
+ c++;
+ /* process next length-parth */
+ goto lengthpart;
+ } else if (*c == '\0') {
+ return EXIT_SUCCESS;
+ } else if (!strncmp(c, "..", 2)) {
+ goto upper;
+ }
+ } /* else error */
+
+error:
+
+ LOGVAL(VE_INARG, line, expr, "length");
+ return EXIT_FAILURE;
+}
+
static const char *
read_yin_subnode(struct ly_ctx *ctx, struct lyxml_elem *node, const char *name)
{
@@ -648,6 +774,59 @@
}
static int
+read_restr_substmt(struct ly_ctx *ctx, struct ly_must *restr, struct lyxml_elem *yin)
+{
+ struct lyxml_elem *next, *child;
+
+ LY_TREE_FOR_SAFE(yin->child, next, child) {
+ if (!strcmp(child->name, "description")) {
+ if (restr->dsc) {
+ LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
+ return EXIT_FAILURE;
+ }
+ restr->dsc = read_yin_subnode(ctx, child, "text");
+ if (!restr->dsc) {
+ return EXIT_FAILURE;
+ }
+ } else if (!strcmp(child->name, "reference")) {
+ if (restr->ref) {
+ LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
+ return EXIT_FAILURE;
+ }
+ restr->ref = read_yin_subnode(ctx, child, "text");
+ if (!restr->ref) {
+ return EXIT_FAILURE;
+ }
+ } else if (!strcmp(child->name, "error-app-tag")) {
+ if (restr->eapptag) {
+ LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
+ return EXIT_FAILURE;
+ }
+ restr->eapptag = read_yin_subnode(ctx, child, "value");
+ if (!restr->eapptag) {
+ return EXIT_FAILURE;
+ }
+ } else if (!strcmp(child->name, "error-message")) {
+ if (restr->emsg) {
+ LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
+ return EXIT_FAILURE;
+ }
+ restr->emsg = read_yin_subnode(ctx, child, "value");
+ if (!restr->emsg) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
+ return EXIT_FAILURE;
+ }
+
+ lyxml_free_elem(ctx, child);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int
fill_yin_type(struct ly_module *module, struct ly_mnode *parent, struct lyxml_elem *yin, struct ly_type *type)
{
const char *value, *delim;
@@ -674,10 +853,30 @@
switch (type->base) {
case LY_TYPE_BINARY:
- /* TODO length, 9.4.4
- * - optional, 0..1, rekurzivni - omezuje, string (podobne jako range),
- * hodnoty se musi vejit do 64b, podelementy
- */
+ /* RFC 6020 9.8.1, 9.4.4 - length, number of octets it contains */
+ LY_TREE_FOR_SAFE(yin->child, next, node) {
+ if (!strcmp(node->name, "length")) {
+ if (type->info.binary.length) {
+ LOGVAL(VE_TOOMANY, LOGLINE(node), node->name, yin->name);
+ goto error;
+ }
+
+ GETVAL(value, node, "value");
+ if (check_length(value, type, LOGLINE(node))) {
+ goto error;
+ }
+ type->info.binary.length = calloc(1, sizeof *type->info.binary.length);
+ type->info.binary.length->expr = lydict_insert(module->ctx, value, 0);
+
+ /* get possible substatements */
+ if (read_restr_substmt(module->ctx, (struct ly_must *)type->info.binary.length, node)) {
+ goto error;
+ }
+ } else {
+ LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
+ goto error;
+ }
+ }
break;
case LY_TYPE_BITS:
@@ -689,12 +888,11 @@
lyxml_unlink_elem(node);
lyxml_add_child(&root, node);
type->info.bits.count++;
+ } else {
+ LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
+ goto error;
}
}
- if (yin->child) {
- LOGVAL(VE_INSTMT, LOGLINE(yin->child), yin->child->name);
- goto error;
- }
if (!type->info.bits.count) {
if (type->der->type.der) {
/* this is just a derived type with no bit specified */
@@ -1124,60 +1322,14 @@
static int
fill_yin_must(struct ly_module *module, struct lyxml_elem *yin, struct ly_must *must)
{
- struct lyxml_elem *child, *next;
const char *value;
GETVAL(value, yin, "condition");
must->cond = lydict_insert(module->ctx, value, strlen(value));
- LY_TREE_FOR_SAFE(yin->child, next, child) {
- if (!strcmp(child->name, "description")) {
- if (must->dsc) {
- LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
- goto error;
- }
- must->dsc = read_yin_subnode(module->ctx, child, "text");
- if (!must->dsc) {
- goto error;
- }
- } else if (!strcmp(child->name, "reference")) {
- if (must->ref) {
- LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
- goto error;
- }
- must->ref = read_yin_subnode(module->ctx, child, "text");
- if (!must->ref) {
- goto error;
- }
- } else if (!strcmp(child->name, "error-app-tag")) {
- if (must->eapptag) {
- LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
- goto error;
- }
- must->eapptag = read_yin_subnode(module->ctx, child, "value");
- if (!must->eapptag) {
- goto error;
- }
- } else if (!strcmp(child->name, "error-message")) {
- if (must->emsg) {
- LOGVAL(VE_TOOMANY, LOGLINE(child), child->name, yin->name);
- goto error;
- }
- must->emsg = read_yin_subnode(module->ctx, child, "value");
- if (!must->emsg) {
- goto error;
- }
- } else {
- LOGVAL(VE_INSTMT, LOGLINE(child), child->name);
- goto error;
- }
+ return read_restr_substmt(module->ctx, must, yin);
- lyxml_free_elem(module->ctx, child);
- }
-
- return EXIT_SUCCESS;
-
-error:
+error: /* GETVAL requires this label */
return EXIT_FAILURE;
}