parsers FEATURE if-feature Y1.1 expressions
diff --git a/src/resolve.c b/src/resolve.c
index 92169aa..227bc1b 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -955,6 +955,238 @@
}
/**
+ * @brief Resolve (find) a feature definition. Logs directly.
+ *
+ * @param[in] feat_name Feature name to resolve.
+ * @param[in] len Length of \p feat_name.
+ * @param[in] node Node with the if-feature expression.
+ *
+ * @return 0 on disabled, 1 on enabled, 2 on forward reference, -1 on error.
+ */
+static int
+resolve_iffeature_feature(const char *feat_name, uint16_t len, const struct lys_node *node)
+{
+ char *str;
+ const char *mod_name, *name;
+ int mod_name_len, nam_len, i, j;
+ const struct lys_module *module;
+
+ /* check prefix */
+ if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
+ LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
+ return -1;
+ }
+
+ module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
+ if (!module) {
+ /* identity refers unknown data model */
+ LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
+ return -1;
+ }
+
+ /* search in the identified module ... */
+ for (j = 0; j < module->features_size; j++) {
+ if (!strcmp(name, module->features[j].name)) {
+ /* check status */
+ if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
+ module->features[j].module, module->features[j].name, node)) {
+ return -1;
+ }
+ return (module->features[j].flags & LYS_FENABLED ? 1 : 0);
+ }
+ }
+ /* ... and all its submodules */
+ for (i = 0; i < module->inc_size; i++) {
+ if (!module->inc[i].submodule) {
+ /* not yet resolved */
+ continue;
+ }
+ for (j = 0; j < module->inc[i].submodule->features_size; j++) {
+ if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
+ /* check status */
+ if (lyp_check_status(node->flags, lys_node_module(node), node->name,
+ module->inc[i].submodule->features[j].flags,
+ module->inc[i].submodule->features[j].module,
+ module->inc[i].submodule->features[j].name, node)) {
+ return -1;
+ }
+ return (module->inc[i].submodule->features[j].flags & LYS_FENABLED ? 1 : 0);
+ }
+ }
+ }
+
+ /* not found */
+ str = strndup(feat_name, len);
+ LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
+ free(str);
+ return 2;
+}
+
+static int
+resolve_iffeature_factor(const char *factor, uint16_t len, const struct lys_node *node)
+{
+ uint16_t cur_len;
+ int ret;
+
+ if (isspace(factor[0])) {
+ LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, factor[0], factor);
+ return -1;
+ }
+
+ if ((len > 4) && (factor[0] == 'n') && (factor[1] == 'o') && (factor[2] == 't') && isspace(factor[3])) {
+ /* not-keyword sep if-feature-factor */
+ cur_len = 4;
+ while (isspace(factor[cur_len])) {
+ ++cur_len;
+ if (cur_len > len) {
+ LOGVAL(LYE_EOF, LY_VLOG_NONE, NULL);
+ return -1;
+ }
+ }
+
+ ret = resolve_iffeature_factor(factor + cur_len, len - cur_len, node);
+ if ((ret == -1) || (ret == 2)) {
+ return ret;;
+ }
+ return !ret;
+ } else if (factor[0] == '(') {
+ /* "(" sep if-feature-expr sep ")" */
+ if (factor[len] != ')') {
+ LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, factor[len], &factor[len]);
+ return -1;
+ }
+ cur_len = 1;
+ while (isspace(factor[cur_len])) {
+ ++cur_len;
+ }
+
+ --len;
+ while (isspace(factor[len])) {
+ --len;
+ }
+
+ return resolve_iffeature_expr(factor + cur_len, len - cur_len, node);
+ } else {
+ /* identifier-ref-arg */
+ return resolve_iffeature_feature(factor, len, node);
+ }
+}
+
+static int
+resolve_iffeature_term(const char *term, uint16_t len, const struct lys_node *node)
+{
+ uint16_t cur_len, factor_len, and_len;
+ int ret1, ret2;
+
+ if (isspace(term[0])) {
+ LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, term[0], term);
+ return -1;
+ }
+
+ cur_len = 0;
+ factor_len = 0;
+ and_len = 0;
+ while (cur_len < len) {
+ ++cur_len;
+ if ((cur_len > 1) && isspace(term[cur_len - 2]) && !and_len && (term[cur_len - 1] == 'a')) {
+ and_len = 1;
+ } else if ((and_len == 1) && (term[cur_len - 1] == 'n')) {
+ and_len = 2;
+ } else if ((and_len == 2) && (term[cur_len - 1] == 'd')) {
+ and_len = 3;
+ } else if ((and_len == 3) && isspace(term[cur_len - 1])) {
+ and_len = 4;
+ break;
+ } else if (!isspace(term[cur_len - 1])) {
+ factor_len = cur_len;
+ }
+ }
+
+ if (and_len == 4) {
+ /* if-feature-factor sep and-keyword sep if-feature-term */
+ while (isspace(term[cur_len])) {
+ ++cur_len;
+ if (cur_len > len) {
+ LOGVAL(LYE_EOF, LY_VLOG_NONE, NULL);
+ return -1;
+ }
+ }
+ ret1 = resolve_iffeature_factor(term, factor_len, node);
+ if ((ret1 == -1) || (ret1 == 2)) {
+ return ret1;
+ }
+ ret2 = resolve_iffeature_term(term + cur_len, len - cur_len, node);
+ if ((ret2 == -1) || (ret2 == 2)) {
+ return ret2;
+ }
+ return ret1 && ret2;
+
+ } else {
+ /* if-feature-factor */
+ if (and_len) {
+ factor_len = cur_len;
+ }
+ return resolve_iffeature_factor(term, factor_len, node);
+ }
+}
+
+int
+resolve_iffeature_expr(const char *expr, uint16_t len, const struct lys_node *node)
+{
+ uint16_t cur_len, term_len, or_len;
+ int ret1, ret2;
+
+ if (isspace(expr[0])) {
+ LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, expr[0], expr);
+ return -1;
+ }
+
+ cur_len = 0;
+ term_len = 0;
+ or_len = 0;
+ while (cur_len < len) {
+ ++cur_len;
+ if ((cur_len > 1) && isspace(expr[cur_len - 2]) && !or_len && (expr[cur_len - 1] == 'o')) {
+ or_len = 1;
+ } else if ((or_len == 1) && (expr[cur_len - 1] == 'r')) {
+ or_len = 2;
+ } else if ((or_len == 2) && isspace(expr[cur_len - 1])) {
+ or_len = 3;
+ break;
+ } else if (!isspace(expr[cur_len - 1])) {
+ term_len = cur_len;
+ }
+ }
+
+ if (or_len == 3) {
+ /* if-feature-term sep or-keyword sep if-feature-expr */
+ while (isspace(expr[cur_len])) {
+ ++cur_len;
+ if (cur_len > len) {
+ LOGVAL(LYE_EOF, LY_VLOG_NONE, NULL);
+ return -1;
+ }
+ }
+ ret1 = resolve_iffeature_term(expr, term_len, node);
+ if ((ret1 == -1) || (ret1 == 2)) {
+ return ret1;
+ }
+ ret2 = resolve_iffeature_expr(expr + cur_len, len - cur_len, node);
+ if ((ret2 == -1) || (ret2 == 2)) {
+ return ret2;
+ }
+ return ret1 || ret2;
+
+ } else {
+ /* if-feature-term */
+ if (or_len) {
+ term_len = cur_len;
+ }
+ return resolve_iffeature_term(expr, term_len, node);
+ }
+}
+
+/**
* @brief Resolve (find) a data node based on a schema-nodeid.
*
* Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
@@ -2501,82 +2733,6 @@
return rc;
}
-/**
- * @brief Resolve (find) a feature definition. Logs directly.
- *
- * @param[in] name Feature name.
- * @param[in] module Module to search in.
- * @param[out] ret Pointer to the resolved feature. Can be NULL.
- *
- * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
- */
-static int
-resolve_feature(const char *id, const struct lys_module *module, struct lys_feature **ret)
-{
- const char *mod_name, *name;
- int mod_name_len, nam_len, i, j;
- struct lys_node *node;
-
- assert(id);
- assert(module);
-
- /* check prefix */
- if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
- LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, id[-i], &id[-i]);
- return -1;
- }
-
- module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
- if (!module) {
- /* identity refers unknown data model */
- LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
- return -1;
- }
-
- /* search in the identified module ... */
- for (j = 0; j < module->features_size; j++) {
- if (!strcmp(name, module->features[j].name)) {
- if (ret) {
- /* check status */
- node = (struct lys_node *)*ret;
- if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
- module->features[j].module, module->features[j].name, node)) {
- return -1;
- }
- *ret = &module->features[j];
- }
- return EXIT_SUCCESS;
- }
- }
- /* ... and all its submodules */
- for (i = 0; i < module->inc_size; i++) {
- if (!module->inc[i].submodule) {
- /* not yet resolved */
- continue;
- }
- for (j = 0; j < module->inc[i].submodule->features_size; j++) {
- if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
- if (ret) {
- /* check status */
- node = (struct lys_node *)*ret;
- if (lyp_check_status(node->flags, node->module, node->name,
- module->inc[i].submodule->features[j].flags,
- module->inc[i].submodule->features[j].module,
- module->inc[i].submodule->features[j].name, node)) {
- return -1;
- }
- *ret = &(module->inc[i].submodule->features[j]);
- }
- return EXIT_SUCCESS;
- }
- }
- }
-
- /* not found */
- LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", id);
- return EXIT_FAILURE;
-}
-
void
unres_data_del(struct unres_data *unres, uint32_t i)
{
@@ -4475,31 +4631,31 @@
resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
struct unres_schema *unres)
{
+ /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
int rc = -1, has_str = 0, tpdf_flag = 0;
struct lys_node *node;
- const char *base_name;
+ const char *expr;
struct lys_ident *ident;
struct lys_type *stype;
- struct lys_feature **feat_ptr;
struct lys_node_choice *choic;
struct lyxml_elem *yin;
struct yang_type *yang;
switch (type) {
case UNRES_IDENT:
- base_name = str_snode;
+ expr = str_snode;
has_str = 1;
ident = item;
- rc = resolve_base_ident(mod, ident, base_name, "identity", NULL);
+ rc = resolve_base_ident(mod, ident, expr, "identity", NULL);
break;
case UNRES_TYPE_IDENTREF:
- base_name = str_snode;
+ expr = str_snode;
has_str = 1;
stype = item;
- rc = resolve_base_ident(mod, NULL, base_name, "type", stype);
+ rc = resolve_base_ident(mod, NULL, expr, "type", stype);
break;
case UNRES_TYPE_LEAFREF:
node = str_snode;
@@ -4565,28 +4721,32 @@
}
break;
case UNRES_IFFEAT:
- base_name = str_snode;
- has_str = 1;
- feat_ptr = item;
+ node = str_snode;
+ expr = item;
- rc = resolve_feature(base_name, mod, feat_ptr);
+ rc = resolve_iffeature_expr(expr, strlen(expr), node);
+ if (rc == 2) {
+ rc = EXIT_FAILURE;
+ } else if (rc == 1) {
+ rc = EXIT_SUCCESS;
+ }
break;
case UNRES_USES:
rc = resolve_unres_schema_uses(item, unres);
break;
case UNRES_TYPE_DFLT:
- base_name = str_snode;
+ expr = str_snode;
has_str = 1;
stype = item;
- rc = check_default(stype, base_name, mod);
+ rc = check_default(stype, expr, mod);
break;
case UNRES_CHOICE_DFLT:
- base_name = str_snode;
+ expr = str_snode;
has_str = 1;
choic = item;
- choic->dflt = resolve_choice_dflt(choic, base_name);
+ choic->dflt = resolve_choice_dflt(choic, expr);
if (choic->dflt) {
rc = EXIT_SUCCESS;
} else {
@@ -4654,7 +4814,7 @@
LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
break;
case UNRES_IFFEAT:
- LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)str_node);
+ LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)item);
break;
case UNRES_USES:
LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
@@ -4959,7 +5119,6 @@
break;
case UNRES_IDENT:
case UNRES_TYPE_IDENTREF:
- case UNRES_IFFEAT:
case UNRES_TYPE_DFLT:
case UNRES_CHOICE_DFLT:
case UNRES_LIST_KEYS: