yin parser CHANGE parse known extension subelements correctly finished
diff --git a/src/common.h b/src/common.h
index 342e144..744b1c5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -546,7 +546,7 @@
if (ARRAY){free((uint32_t*)(ARRAY) - 1);}
/**
- * @brief insert item into linked list.
+ * @brief Insert item into linked list.
*
* @param[in,out] LIST Linked list to add to.
* @param[in] NEW_ITEM New item, that will be appended to the list, must be already allocated.
@@ -564,7 +564,7 @@
}
/**
- * @brief allocate and insert new item into linked list.
+ * @brief Allocate and insert new item into linked list, return in case of error.
*
* @param[in] CTX used for logging.
* @param[in,out] LIST Linked list to add to.
@@ -577,7 +577,7 @@
LY_LIST_INSERT(LIST, NEW_ITEM, LINKER)
/**
- * @brief allocate and insert new item into linked list.
+ * @brief Allocate and insert new item into linked list, goto specified label in case of error.
*
* @param[in] CTX used for logging.
* @param[in,out] LIST Linked list to add to.
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 3576471..914f6f9 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -3210,20 +3210,28 @@
return LY_SUCCESS;
}
-LY_ERR
-yin_parse_arg_inext_known(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum ly_stmt elem_type,
- enum ly_stmt parent, struct lysp_stmt **args)
+/**
+ * @brief Parse argument of extension subelement that is classic yang keyword and not another instance of extension.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of extension instance.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] elem_type Type of element that is currently being parsed.
+ * @param[out] arg Value to write to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_arg_inext_known(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum ly_stmt elem_type,
+ const char **arg)
{
LY_ERR ret = LY_SUCCESS;
- struct lysp_stmt *arg;
char *out = NULL;
const char *name, *prefix;
size_t out_len, name_len, prefix_len;
int dynamic;
enum ly_stmt child;
- LY_LIST_NEW_RET(ctx->xml_ctx.ctx, args, arg, next);
-
switch (elem_type) {
case LY_STMT_ACTION:
case LY_STMT_ANYDATA:
@@ -3251,12 +3259,12 @@
case LY_STMT_TYPEDEF:
case LY_STMT_UNITS:
case LY_STMT_USES:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_AUGMENT:
case LY_STMT_DEVIATION:
case LY_STMT_REFINE:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_CONFIG:
case LY_STMT_DEFAULT:
@@ -3281,30 +3289,30 @@
case LY_STMT_VALUE:
case LY_STMT_YANG_VERSION:
case LY_STMT_YIN_ELEMENT:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_IMPORT:
case LY_STMT_INCLUDE:
case LY_STMT_BELONGS_TO:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_INPUT:
case LY_STMT_OUTPUT:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_MUST:
case LY_STMT_WHEN:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_CONDITION, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_CONDITION, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_NAMESPACE:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_URI, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_URI, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_REVISION:
case LY_STMT_REVISION_DATE:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, arg, Y_MAYBE_STR_ARG, elem_type));
break;
case LY_STMT_UNIQUE:
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TAG, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TAG, arg, Y_MAYBE_STR_ARG, elem_type));
break;
/* argument is mapped to yin element */
case LY_STMT_CONTACT:
@@ -3312,22 +3320,29 @@
case LY_STMT_ORGANIZATION:
case LY_STMT_REFERENCE:
case LY_STMT_ERROR_MESSAGE:
- /* there should be no attribute, argument is supposed to be first subelement */
- LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, &arg->arg, Y_MAYBE_STR_ARG, elem_type));
+ /* there shouldn't be any attribute, argument is supposed to be first subelement */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, arg, Y_MAYBE_STR_ARG, elem_type));
ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
- /* TODO fix message */
- LY_CHECK_ERR_RET(ret != LY_EINVAL, LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_FIRT_SUBELEM, ly_stmt2str(elem_type), parent), LY_EVALID);
+ LY_CHECK_ERR_RET(ret != LY_EINVAL, LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_FIRT_SUBELEM,
+ elem_type == LY_STMT_ERROR_MESSAGE ? "value" : "text", ly_stmt2str(elem_type)),
+ LY_EVALID);
LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
child = yin_match_keyword(ctx, name, name_len, prefix, prefix_len, elem_type);
- if ((elem_type == LY_STMT_ERROR_MESSAGE && child != LY_STMT_ARG_VALUE) || child != LY_STMT_ARG_TEXT) {
- LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, elem_type);
+ if ((elem_type == LY_STMT_ERROR_MESSAGE && child == LY_STMT_ARG_VALUE) ||
+ (elem_type != LY_STMT_ERROR_MESSAGE && child == LY_STMT_ARG_TEXT)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, ly_stmt2str(elem_type));
return LY_EVALID;
}
/* load and save content */
LY_CHECK_RET(lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic));
- INSERT_STRING(ctx->xml_ctx.ctx, arg->arg, dynamic, out, out_len);
- /* load closing tag */
+ INSERT_STRING(ctx->xml_ctx.ctx, *arg, dynamic, out, out_len);
+ LY_CHECK_RET(!*arg, LY_EMEM);
+ /* load closing tag of subelement */
LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+ /* if only subelement was parsed as argument, load also closing tag */
+ if (ctx->xml_ctx.status == LYXML_ELEMENT) {
+ LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+ }
break;
default:
LOGINT(ctx->xml_ctx.ctx);
@@ -3338,7 +3353,7 @@
}
LY_ERR
-yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len, enum ly_stmt parent,
+yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len, enum ly_stmt parent,
const char **data, struct lysp_stmt **element)
{
LY_ERR ret = LY_SUCCESS;
@@ -3359,23 +3374,23 @@
ret = yin_load_attributes(ctx, data, &attrs);
LY_CHECK_GOTO(ret, cleanup);
- (*element)->kw = yin_match_keyword(ctx, name, name_len, prefix, prefix_len, LY_STMT_EXTENSION_INSTANCE);
+ (*element)->kw = yin_match_keyword(ctx, name, name_len, prefix, prefix_len, parent);
last = (*element)->child;
if ((*element)->kw == LY_STMT_NONE) {
/* unrecognized element */
- /* TODO set parrent correctly */
- LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, ly_stmt2str(LY_STMT_EXTENSION_INSTANCE));
- return LY_EVALID;
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, ly_stmt2str(parent));
+ ret = LY_EVALID;
+ goto cleanup;
} else if ((*element)->kw != LY_STMT_EXTENSION_INSTANCE) {
/* element is known yang keyword, which means argument can be parsed correctly. */
- LY_CHECK_RET(yin_parse_arg_inext_known(ctx, attrs, data, (*element)->kw, parent, &(*element)->child));
+ ret = yin_parse_arg_inext_known(ctx, attrs, data, (*element)->kw, &(*element)->arg);
+ LY_CHECK_GOTO(ret, cleanup);
} else {
- /* load attributes in generic way
- /* save all attributes in linked list */
+ /* load attributes in generic way, save all attributes in linked list */
LY_ARRAY_FOR(attrs, struct yin_arg_record, iter) {
new = calloc(1, sizeof(*last));
- LY_CHECK_ERR_RET(!new, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ LY_CHECK_ERR_GOTO(!new, LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, cleanup);
if (!(*element)->child) {
/* save first */
(*element)->child = new;
@@ -3390,7 +3405,7 @@
/* attributes with prefix are ignored */
if (!iter->prefix) {
INSERT_STRING(ctx->xml_ctx.ctx, last->arg, iter->dynamic_content, iter->content, iter->content_len);
- LY_CHECK_RET(!last->arg, LY_EMEM);
+ LY_CHECK_ERR_GOTO(!last->arg, ret = LY_EMEM, cleanup);
/* string is no longer supposed to be freed when the array is freed */
iter->dynamic_content = 0;
}
@@ -3403,12 +3418,14 @@
if (ret == LY_EINVAL) {
while (ctx->xml_ctx.status == LYXML_ELEMENT) {
/* parse subelements */
- LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len));
+ ret = lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len);
+ LY_CHECK_GOTO(ret , cleanup);
if (!temp_name) {
/* end of element reached */
break;
}
- LY_CHECK_RET(yin_parse_element_generic(ctx, temp_name, temp_name_len, temp_prefix, temp_prefix_len, (*element)->kw, data, &new));
+ ret = yin_parse_element_generic(ctx, temp_name, temp_name_len, temp_prefix, temp_prefix_len, (*element)->kw, data, &new);
+ LY_CHECK_GOTO(ret, cleanup);
if (!(*element)->child) {
/* save first */
(*element)->child = new;
@@ -3419,15 +3436,16 @@
}
ret = LY_SUCCESS;
} else {
- LY_CHECK_RET(ret);
+ LY_CHECK_GOTO(ret, cleanup);
/* save element content */
if (out_len != 0) {
INSERT_STRING(ctx->xml_ctx.ctx, (*element)->arg, dynamic, out, out_len);
- LY_CHECK_RET(!(*element)->arg, LY_EMEM);
+ LY_CHECK_ERR_GOTO(!(*element)->arg, ret = LY_EMEM, cleanup);
}
/* read closing tag */
- LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len));
+ ret = lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len);
+ LY_CHECK_GOTO(ret, cleanup);
}
}
diff --git a/src/parser_yin.h b/src/parser_yin.h
index 2e6bc93..0e5d56c 100644
--- a/src/parser_yin.h
+++ b/src/parser_yin.h
@@ -215,7 +215,7 @@
* @return yang_keyword values.
*/
enum ly_stmt yin_match_keyword(struct yin_parser_ctx *ctx, const char *name, size_t name_len,
- const char *prefix, size_t prefix_len, enum ly_stmt parrent);
+ const char *prefix, size_t prefix_len, enum ly_stmt parrent);
/**
* @brief Load all attributes of element into ([sized array](@ref sizedarrays)). Caller is suposed to free the array.
@@ -260,7 +260,7 @@
*
* @return LY_ERR values.
*/
-LY_ERR yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len, enum ly_stmt parent,
+LY_ERR yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char *prefix, size_t prefix_len, enum ly_stmt parent,
const char **data, struct lysp_stmt **element);
/**
diff --git a/tests/src/test_parser_yin.c b/tests/src/test_parser_yin.c
index 63d0ef8..80736c9 100644
--- a/tests/src/test_parser_yin.c
+++ b/tests/src/test_parser_yin.c
@@ -66,7 +66,7 @@
int store = -1; /* negative for infinite logging, positive for limited logging */
/* set to 0 to printing error messages to stderr instead of checking them in code */
-#define ENABLE_LOGGER_CHECKING 1
+#define ENABLE_LOGGER_CHECKING 0
#if ENABLE_LOGGER_CHECKING
static void
@@ -531,6 +531,42 @@
LY_ARRAY_FREE(exts);
exts = NULL;
args = NULL;
+ st = reset_state(state);
+
+ data = "<myext:extension-elem xmlns:myext=\"urn:example:extensions\" xmlns:yin=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<yin:action name=\"act-name\" pre:prefixed=\"ignored\"/>"
+ "<yin:augment target-node=\"target\"/>"
+ "<yin:status value=\"value\"/>"
+ "<yin:include module=\"mod\"/>"
+ "<yin:input />"
+ "<yin:must condition=\"cond\"/>"
+ "<yin:namespace uri=\"uri\"/>"
+ "<yin:revision date=\"data\"/>"
+ "<yin:unique tag=\"tag\"/>"
+ "<yin:contact><text>contact-val</text></yin:contact>"
+ "<yin:error-message><value>err-msg</value></yin:error-message>"
+ "</myext:extension-elem>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &args);
+ ret = yin_parse_extension_instance(st->yin_ctx, args, &data, name, name_len, LYEXT_SUBSTMT_CONTACT, 0, &exts);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(exts->child->arg, "act-name");
+ assert_string_equal(exts->child->next->arg, "target");
+ assert_string_equal(exts->child->next->next->arg, "value");
+ assert_string_equal(exts->child->next->next->next->arg, "mod");
+ assert_null(exts->child->next->next->next->next->arg);
+ assert_string_equal(exts->child->next->next->next->next->next->arg, "cond");
+ assert_string_equal(exts->child->next->next->next->next->next->next->arg, "uri");
+ assert_string_equal(exts->child->next->next->next->next->next->next->next->arg, "data");
+ assert_string_equal(exts->child->next->next->next->next->next->next->next->next->arg, "tag");
+ assert_string_equal(exts->child->next->next->next->next->next->next->next->next->next->arg, "contact-val");
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ LY_ARRAY_FREE(args);
+ lysp_ext_instance_free(st->ctx, exts);
+ LY_ARRAY_FREE(exts);
+ exts = NULL;
+ args = NULL;
+ st = reset_state(state);
st->finished_correctly = true;
}
@@ -546,12 +582,12 @@
"<myext:custom xmlns:myext=\"urn:example:extensions\">"
"totally amazing extension"
"</myext:custom>"
- "<myext:extension name=\"ext\" xmlns:myext=\"urn:example:extensions\">"
+ "<extension name=\"ext\">"
"<argument name=\"argname\"></argument>"
"<description><text>desc</text></description>"
"<reference><text>ref</text></reference>"
"<status value=\"deprecated\"></status>"
- "</myext:extension>"
+ "</extension>"
"<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
"<if-feature name=\"foo\"></if-feature>"
"<when condition=\"condition...\">"
@@ -613,7 +649,7 @@
assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
/* check parsed values */
assert_string_equal(def, "default-value");
- assert_string_equal(exts->name, "custom");
+ assert_string_equal(exts->name, "myext:custom");
assert_string_equal(exts->argument, "totally amazing extension");
assert_string_equal(value, "wsefsdf");
assert_string_equal(units, "radians");