Merge branch 'libyang2' of https://github.com/CESNET/libyang into libyang2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 879b6e7..9b325cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,6 +42,8 @@
option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
option(ENABLE_COVERAGE "Build code coverage report from tests" OFF)
endif()
+
+option(ENABLE_FUZZ_TARGETS "Build target programs suitable for fuzzing with AFL" OFF)
#option(ENABLE_CALLGRIND_TESTS "Build performance tests to be run with callgrind" OFF)
#option(ENABLE_CACHE "Enable data caching for schemas and hash tables for data (time-efficient at the cost of increased space-complexity)" ON)
@@ -217,6 +219,7 @@
src/tree_schema_compile.c
src/tree_schema_helpers.c
src/parser_yang.c
+ src/parser_yin.c
src/printer.c
src/printer_schema.c
src/printer_yang.c
@@ -408,6 +411,10 @@
endif(CMOCKA_FOUND)
endif(ENABLE_BUILD_TESTS)
+if(ENABLE_FUZZ_TARGETS)
+ add_subdirectory(tests/fuzz)
+endif(ENABLE_FUZZ_TARGETS)
+
#if(GEN_LANGUAGE_BINDINGS AND GEN_CPP_BINDINGS)
# add_subdirectory(swig)
#endif()
diff --git a/README.md b/README.md
index a185d0b..f5c641b 100644
--- a/README.md
+++ b/README.md
@@ -252,5 +252,9 @@
* JavaScript
* cmake option: `JAVASCRIPT_BINDING`
* [README](./swig/javascript/README.md)
+
+## Fuzzing
+A YANG fuzzing target and fuzzing instructions are available in the `tests/fuzz` directory.
+An asciinema example describing the process of fuzzing libyang2 with the yangfuzz fuzz harness is available at https://asciinema.org/a/260417.
diff --git a/src/common.c b/src/common.c
index 6f8cfe9..a59d5af 100644
--- a/src/common.c
+++ b/src/common.c
@@ -54,7 +54,7 @@
[YANG_FEATURE] = "feature",
[YANG_FRACTION_DIGITS] = "fraction-digits",
[YANG_GROUPING] = "grouping",
- [YANG_IDENTITY] = "identitiy",
+ [YANG_IDENTITY] = "identity",
[YANG_IF_FEATURE] = "if-feature",
[YANG_IMPORT] = "import",
[YANG_INCLUDE] = "include",
@@ -101,6 +101,8 @@
[YANG_SEMICOLON] = ";",
[YANG_LEFT_BRACE] = "{",
[YANG_RIGHT_BRACE] = "}",
+ [YIN_TEXT] = "text",
+ [YIN_VALUE] = "value",
};
const char *const lyext_substmt_list[] = {
diff --git a/src/common.h b/src/common.h
index 021eca8..10637ee 100644
--- a/src/common.h
+++ b/src/common.h
@@ -178,6 +178,12 @@
#define LY_VCODE_EOF LYVE_SYNTAX, "Unexpected end-of-input."
#define LY_VCODE_NTERM LYVE_SYNTAX, "%s not terminated."
#define LY_VCODE_NSUPP LYVE_SYNTAX, "%s not supported."
+#define LY_VCODE_MOD_SUBOMD LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\"."
+#define LY_VCODE_TRAILING_MOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input."
+#define LY_VCODE_TRAILING_SUBMOD LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input."
+
+#define LY_VCODE_INVAL_MINMAX LYVE_SEMANTICS, "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u."
+
#define LY_VCODE_INSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
#define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
#define LY_VCODE_INCHILDSTMT2 LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
@@ -191,8 +197,24 @@
#define LY_VCODE_OOB LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
#define LY_VCODE_INDEV LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
#define LY_VCODE_INREGEXP LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
+
+#define LY_VCODE_INSUBELEM2 LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
+#define LY_VCODE_INVAL_YIN LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected sub-element \"%.*s\" of \"%s\" element."
+#define LY_VCODE_INDEV_YIN LYVE_SYNTAX_YIN, "Deviate of this type doesn't allow \"%s\" as it's sub-element."
+#define LY_VCODE_INORDER_YIN LYVE_SYNTAX_YIN, "Invalid order of %s\'s sub-elements \"%s\" can't appear after \"%s\"."
+#define LY_VCODE_OOB_YIN LYVE_SYNTAX_YIN, "Value \"%s\" of \"%s\" attribute in \"%s\" element is out of bounds."
+#define LY_VCODE_INCHILDSTMSCOMB_YIN LYVE_SYNTAX_YIN, "Invalid combination of sub-elemnts \"%s\" and \"%s\" in \"%s\" element."
+#define LY_VCODE_DUP_ATTR LYVE_SYNTAX_YIN, "Duplicit definition of \"%s\" attribute in \"%s\" element."
+#define LY_VCODE_UNEXP_ATTR LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of \"%s\" element."
+#define LY_VCODE_MAND_SUBELEM LYVE_SYNTAX_YIN, "Missing mandatory sub-element \"%s\" of \"%s\" element."
+#define LY_VCODE_FIRT_SUBELEM LYVE_SYNTAX_YIN, "Sub-element \"%s\" of \"%s\" element must be defined as it's first sub-element."
+#define LY_VCODE_NAME_COL LYVE_SYNTAX_YIN, "Name collision between module and submodule of name \"%s\"."
+#define LY_VCODE_SUBELEM_REDEF LYVE_SYNTAX_YIN, "Redefinition of \"%s\" sub-element in \"%s\" element."
+
#define LY_VCODE_XP_EOE LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
#define LY_VCODE_XP_INEXPR LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
+
#define LY_VCODE_DEV_NODETYPE LYVE_REFERENCE, "Invalid deviation of %s node - it is not possible to %s \"%s\" property."
#define LY_VCODE_DEV_NOT_PRESENT LYVE_REFERENCE, "Invalid deviation %s \"%s\" property \"%s\" which is not present."
@@ -320,7 +342,10 @@
YANG_SEMICOLON,
YANG_LEFT_BRACE,
YANG_RIGHT_BRACE,
- YANG_CUSTOM
+ YANG_CUSTOM,
+
+ YIN_TEXT,
+ YIN_VALUE
};
/* list of the YANG statements strings */
@@ -599,4 +624,36 @@
*/
#define LY_ARRAY_FREE(ARRAY) \
if (ARRAY){free((uint32_t*)(ARRAY) - 1);}
+
+/**
+ * @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.
+ * @param[in] LINKER name of structuin member that is used to connect items together.
+ */
+#define LY_LIST_INSERT(LIST, NEW_ITEM, LINKER)\
+ if (!(*LIST)) { \
+ *LIST = (__typeof__(*(LIST)))NEW_ITEM; \
+ } else { \
+ do { \
+ __typeof__(*(LIST)) iterator; \
+ for (iterator = *(LIST); iterator->LINKER; iterator = iterator->LINKER); \
+ iterator->LINKER = (__typeof__(*(LIST)))NEW_ITEM; \
+ } while (0); \
+ }
+
+/**
+ * @brief allocate and insert new item inro linked list.
+ *
+ * @param[in] CTX used for loggin.
+ * @param[in,out] LIST Linker list to add to.
+ * @param[out] NEW_ITEM New item that was appended to the list.
+ * @param[in] LINKER name of structuin member that is used to connect items together.
+ */
+#define LY_LIST_NEW_RET(CTX, LIST, NEW_ITEM, LINKER) \
+ NEW_ITEM = calloc(1, sizeof *NEW_ITEM); \
+ LY_CHECK_ERR_RET(!(NEW_ITEM), LOGMEM(CTX), LY_EMEM); \
+ LY_LIST_INSERT(LIST, NEW_ITEM, LINKER)
+
#endif /* LY_COMMON_H_ */
diff --git a/src/hash_table.c b/src/hash_table.c
index f26d04c..2d9af2a 100644
--- a/src/hash_table.c
+++ b/src/hash_table.c
@@ -206,6 +206,9 @@
} else {
/* lyht_insert returned error */
LOGINT(ctx);
+ if (zerocopy) {
+ free(value);
+ }
return NULL;
}
diff --git a/src/log.h b/src/log.h
index 83fc240..c7ee0a3 100644
--- a/src/log.h
+++ b/src/log.h
@@ -167,6 +167,7 @@
LYVE_SUCCESS = 0, /**< no error */
LYVE_SYNTAX, /**< generic syntax error */
LYVE_SYNTAX_YANG, /**< YANG-related syntax error */
+ LYVE_SYNTAX_YIN, /**< YIN-related syntax error */
LYVE_REFERENCE, /**< invalid referencing or using an item */
LYVE_XPATH, /**< invalid XPath expression */
LYVE_SEMANTICS, /**< generic semantic error */
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 34db6e5..3949b4a 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -31,38 +31,6 @@
#include "tree_schema.h"
#include "tree_schema_internal.h"
-/* Macro to check YANG's yang-char grammar rule */
-#define is_yangutf8char(c) ((c >= 0x20 && c <= 0xd7ff) || c == 0x09 || c == 0x0a || c == 0x0d || \
- (c >= 0xe000 && c <= 0xfdcf) || (c >= 0xfdf0 && c <= 0xfffd) || \
- (c >= 0x10000 && c <= 0x1fffd) || (c >= 0x20000 && c <= 0x2fffd) || \
- (c >= 0x30000 && c <= 0x3fffd) || (c >= 0x40000 && c <= 0x2fffd) || \
- (c >= 0x50000 && c <= 0x5fffd) || (c >= 0x60000 && c <= 0x6fffd) || \
- (c >= 0x70000 && c <= 0x7fffd) || (c >= 0x80000 && c <= 0x8fffd) || \
- (c >= 0x90000 && c <= 0x9fffd) || (c >= 0xa0000 && c <= 0xafffd) || \
- (c >= 0xb0000 && c <= 0xbfffd) || (c >= 0xc0000 && c <= 0xcfffd) || \
- (c >= 0xd0000 && c <= 0xdfffd) || (c >= 0xe0000 && c <= 0xefffd) || \
- (c >= 0xf0000 && c <= 0xffffd) || (c >= 0x100000 && c <= 0x10fffd))
-
-/**
- * @brief Try to find object with MEMBER string matching the IDENT in the given ARRAY.
- * Macro logs an error message and returns LY_EVALID in case of existence of a matching object.
- *
- * @param[in] CTX yang parser context for logging.
- * @param[in] ARRAY [sized array](@ref sizedarrays) of a generic objects with member named MEMBER to search.
- * @param[in] MEMBER Name of the member of the objects in the ARRAY to compare.
- * @param[in] STMT Name of the compared YANG statements for logging.
- * @param[in] IDENT String trying to find in the ARRAY's objects inside the MEMBER member.
- */
-#define CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, STMT, IDENT) \
- if (ARRAY) { \
- for (unsigned int u = 0; u < LY_ARRAY_SIZE(ARRAY) - 1; ++u) { \
- if (!strcmp((ARRAY)[u].MEMBER, IDENT)) { \
- LOGVAL_YANG(CTX, LY_VCODE_DUPIDENT, IDENT, STMT); \
- return LY_EVALID; \
- } \
- } \
- }
-
/**
* @brief Insert WORD into the libyang context's dictionary and store as TARGET.
* @param[in] CTX yang parser context to access libyang context.
@@ -102,7 +70,7 @@
return LY_SUCCESS; \
} \
if (KW != YANG_LEFT_BRACE) { \
- LOGVAL_YANG(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
+ LOGVAL_PARSER(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
return LY_EVALID; \
} \
for (ERR = get_keyword(CTX, DATA, &KW, &WORD, &WORD_LEN); \
@@ -117,12 +85,7 @@
* @param[in] PARENT parent statement where the KW is present - for logging.
*/
#define YANG_CHECK_STMTVER2_RET(CTX, KW, PARENT) \
- if ((CTX)->mod_version < 2) {LOGVAL_YANG((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
-
-#define YANG_CHECK_NONEMPTY(CTX, OBJECT, VALUE_LEN, STMT) \
- if (!VALUE_LEN) { \
- LOGWRN((CTX)->ctx, "Empty argument of %s statement does not make sense.", STMT); \
- }
+ if ((CTX)->mod_version < 2) {LOGVAL_PARSER((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
LY_ERR parse_container(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
LY_ERR parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
@@ -131,9 +94,6 @@
LY_ERR parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
LY_ERR parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
-static LY_ERR parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
- struct lysp_action *actions, struct lysp_notif *notifs);
-
/**
* @brief Add another character to dynamic buffer, a low-level function.
*
@@ -169,62 +129,6 @@
}
/**
- * @brief Check that \p c is valid UTF8 code point for YANG string.
- *
- * @param[in] ctx yang parser context for logging.
- * @param[in] c UTF8 code point of a character to check.
- * @return LY_ERR values.
- */
-static LY_ERR
-check_stringchar(struct lys_parser_ctx *ctx, unsigned int c)
-{
- if (!is_yangutf8char(c)) {
- LOGVAL_YANG(ctx, LY_VCODE_INCHAR, c);
- return LY_EVALID;
- }
- return LY_SUCCESS;
-}
-
-/**
- * @brief Check that \p c is valid UTF8 code point for YANG identifier.
- *
- * @param[in] ctx yang parser context for logging.
- * @param[in] c UTF8 code point of a character to check.
- * @param[in] first Flag to check the first character of an identifier, which is more restricted.
- * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
- * 0 - colon not yet found (no prefix)
- * 1 - \p c is the colon character
- * 2 - prefix already processed, now processing the identifier
- *
- * If the identifier cannot be prefixed, NULL is expected.
- * @return LY_ERR values.
- */
-LY_ERR
-check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix)
-{
- if (first || (prefix && (*prefix) == 1)) {
- if (!is_yangidentstartchar(c)) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '%c'.", c);
- return LY_EVALID;
- }
- if (prefix) {
- if (first) {
- (*prefix) = 0;
- } else {
- (*prefix) = 2;
- }
- }
- } else if (c == ':' && prefix && (*prefix) == 0) {
- (*prefix) = 1;
- } else if (!is_yangidentchar(c)) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Invalid identifier character '%c'.", c);
- return LY_EVALID;
- }
-
- return LY_SUCCESS;
-}
-
-/**
* @brief Store a single UTF8 character. It depends whether in a dynamically-allocated buffer or just as a pointer to the data.
*
* @param[in] ctx yang parser context for logging.
@@ -237,14 +141,17 @@
* @param[in,out] word_b Word buffer. Is kept NULL as long as it is not requested (word is a substring of the data).
* @param[in,out] buf_len Current length of \p word_b.
* @param[in] need_buf Flag if the dynamically allocated buffer is required.
+ * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
+ * 0 - colon not yet found (no prefix)
+ * 1 - \p c is the colon character
+ * 2 - prefix already processed, now processing the identifier
*
* @return LY_ERR values.
*/
LY_ERR
-buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg,
- char **word_p, size_t *word_len, char **word_b, size_t *buf_len, int need_buf)
+buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg, char **word_p,
+ size_t *word_len, char **word_b, size_t *buf_len, int need_buf, int *prefix)
{
- int prefix = 0;
unsigned int c;
size_t len;
@@ -253,7 +160,7 @@
/* get UTF8 code point (and number of bytes coding the character) */
LY_CHECK_ERR_RET(ly_getutf8(input, &c, &len),
- LOGVAL_YANG(ctx, LY_VCODE_INCHAR, (*input)[-len]), LY_EVALID);
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (*input)[-len]), LY_EVALID);
(*input) -= len;
if (c == '\n') {
ctx->indent = 0;
@@ -265,14 +172,14 @@
/* check character validity */
switch (arg) {
case Y_IDENTIF_ARG:
- LY_CHECK_RET(check_identifierchar(ctx, c, !(*word_len), NULL));
+ LY_CHECK_RET(lysp_check_identifierchar(ctx, c, !(*word_len), NULL));
break;
case Y_PREF_IDENTIF_ARG:
- LY_CHECK_RET(check_identifierchar(ctx, c, !(*word_len), &prefix));
+ LY_CHECK_RET(lysp_check_identifierchar(ctx, c, !(*word_len), prefix));
break;
case Y_STR_ARG:
case Y_MAYBE_STR_ARG:
- LY_CHECK_RET(check_stringchar(ctx, c));
+ LY_CHECK_RET(lysp_check_stringchar(ctx, c));
break;
}
@@ -370,7 +277,7 @@
}
if (!**data && (comment > 1)) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX, "Unexpected end-of-input, non-terminated comment.");
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX, "Unexpected end-of-input, non-terminated comment.");
return LY_EVALID;
}
@@ -402,6 +309,7 @@
* 5 - string continues after +, skipping whitespaces */
unsigned int string, block_indent = 0, current_indent = 0, need_buf = 0;
const char *c;
+ int prefix = 0;
if (**data == '\"') {
string = 2;
@@ -423,7 +331,7 @@
break;
default:
/* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+ LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
break;
}
break;
@@ -445,7 +353,7 @@
MOVE_INPUT(ctx, data, 1);
} else {
/* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+ LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
}
break;
case '\t':
@@ -456,12 +364,12 @@
for (; current_indent > block_indent; --current_indent, --ctx->indent) {
/* store leftover spaces from the tab */
c = " ";
- LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf));
+ LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
}
++(*data);
} else {
/* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+ LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
/* additional characters for indentation - only 1 was count in buf_store_char */
ctx->indent += 7;
}
@@ -481,7 +389,7 @@
}
/* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+ LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
/* maintain line number */
++ctx->line;
@@ -494,7 +402,7 @@
current_indent = block_indent;
/* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf));
+ LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
break;
}
break;
@@ -514,12 +422,12 @@
c = *data;
break;
default:
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Double-quoted string unknown special character '\\%c'.", **data);
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Double-quoted string unknown special character '\\%c'.", **data);
return LY_EVALID;
}
/* check and store character */
- LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf));
+ LY_CHECK_RET(buf_store_char(ctx, &c, arg, word_p, word_len, word_b, buf_len, need_buf, &prefix));
string = 2;
++(*data);
@@ -561,7 +469,7 @@
break;
default:
/* it must be quoted again */
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Both string parts divided by '+' must be quoted.");
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Both string parts divided by '+' must be quoted.");
return LY_EVALID;
}
MOVE_INPUT(ctx, data, 1);
@@ -574,7 +482,7 @@
string_end:
if (arg <= Y_PREF_IDENTIF_ARG && !(*word_len)) {
/* empty identifier */
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Statement argument is required.");
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Statement argument is required.");
return LY_EVALID;
}
return LY_SUCCESS;
@@ -599,7 +507,7 @@
uint16_t *flags, char **word_p, char **word_b, size_t *word_len)
{
size_t buf_len = 0;
-
+ int prefix = 0;
/* word buffer - dynamically allocated */
*word_b = NULL;
@@ -613,7 +521,7 @@
case '\"':
if (*word_len) {
/* invalid - quotes cannot be in unquoted string and only optsep, ; or { can follow it */
- LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, 1, *data,
+ LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, *data,
"unquoted string character, optsep, semicolon or opening brace");
return LY_EVALID;
}
@@ -633,7 +541,7 @@
LY_CHECK_RET(skip_comment(ctx, data, 2));
} else {
/* not a comment after all */
- LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0));
+ LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0, &prefix));
}
break;
case ' ':
@@ -673,21 +581,21 @@
goto str_end;
}
- LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, 1, *data, "an argument");
+ LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, *data, "an argument");
return LY_EVALID;
case '}':
/* invalid - braces cannot be in unquoted string (opening braces terminates the string and can follow it) */
- LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, 1, *data,
+ LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, 1, *data,
"unquoted string character, optsep, semicolon or opening brace");
return LY_EVALID;
default:
- LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0));
+ LY_CHECK_RET(buf_store_char(ctx, data, arg, word_p, word_len, word_b, &buf_len, 0, &prefix));
break;
}
}
/* unexpected end of loop */
- LOGVAL_YANG(ctx, LY_VCODE_EOF);
+ LOGVAL_PARSER(ctx, LY_VCODE_EOF);
return LY_EVALID;
str_end:
@@ -740,7 +648,7 @@
LY_CHECK_RET(skip_comment(ctx, data, 2));
} else {
/* error - not a comment after all, keyword cannot start with slash */
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '/'.");
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '/'.");
return LY_EVALID;
}
continue;
@@ -765,197 +673,14 @@
++(*data);
}
-#define IF_KW(STR, LEN, STMT) if (!strncmp(*(data), STR, LEN)) {MOVE_INPUT(ctx, data, LEN);*kw=STMT;}
-#define IF_KW_PREFIX(STR, LEN) if (!strncmp(*(data), STR, LEN)) {MOVE_INPUT(ctx, data, LEN);
-#define IF_KW_PREFIX_END }
-
keyword_start:
word_start = *data;
- *kw = YANG_NONE;
+ *kw = lysp_match_kw(ctx, data);
- /* read the keyword itself */
- switch (**data) {
- case 'a':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("rgument", 7, YANG_ARGUMENT)
- else IF_KW("ugment", 6, YANG_AUGMENT)
- else IF_KW("ction", 5, YANG_ACTION)
- else IF_KW_PREFIX("ny", 2)
- IF_KW("data", 4, YANG_ANYDATA)
- else IF_KW("xml", 3, YANG_ANYXML)
- IF_KW_PREFIX_END
- break;
- case 'b':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("ase", 3, YANG_BASE)
- else IF_KW("elongs-to", 9, YANG_BELONGS_TO)
- else IF_KW("it", 2, YANG_BIT)
- break;
- case 'c':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("ase", 3, YANG_CASE)
- else IF_KW("hoice", 5, YANG_CHOICE)
- else IF_KW_PREFIX("on", 2)
- IF_KW("fig", 3, YANG_CONFIG)
- else IF_KW_PREFIX("ta", 2)
- IF_KW("ct", 2, YANG_CONTACT)
- else IF_KW("iner", 4, YANG_CONTAINER)
- IF_KW_PREFIX_END
- IF_KW_PREFIX_END
- break;
- case 'd':
- MOVE_INPUT(ctx, data, 1);
- IF_KW_PREFIX("e", 1)
- IF_KW("fault", 5, YANG_DEFAULT)
- else IF_KW("scription", 9, YANG_DESCRIPTION)
- else IF_KW_PREFIX("viat", 4)
- IF_KW("e", 1, YANG_DEVIATE)
- else IF_KW("ion", 3, YANG_DEVIATION)
- IF_KW_PREFIX_END
- IF_KW_PREFIX_END
- break;
- case 'e':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("num", 3, YANG_ENUM)
- else IF_KW_PREFIX("rror-", 5)
- IF_KW("app-tag", 7, YANG_ERROR_APP_TAG)
- else IF_KW("message", 7, YANG_ERROR_MESSAGE)
- IF_KW_PREFIX_END
- else IF_KW("xtension", 8, YANG_EXTENSION)
- break;
- case 'f':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("eature", 6, YANG_FEATURE)
- else IF_KW("raction-digits", 14, YANG_FRACTION_DIGITS)
- break;
- case 'g':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("rouping", 7, YANG_GROUPING)
- break;
- case 'i':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("dentity", 7, YANG_IDENTITY)
- else IF_KW("f-feature", 9, YANG_IF_FEATURE)
- else IF_KW("mport", 5, YANG_IMPORT)
- else IF_KW_PREFIX("n", 1)
- IF_KW("clude", 5, YANG_INCLUDE)
- else IF_KW("put", 3, YANG_INPUT)
- IF_KW_PREFIX_END
- break;
- case 'k':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("ey", 2, YANG_KEY)
- break;
- case 'l':
- MOVE_INPUT(ctx, data, 1);
- IF_KW_PREFIX("e", 1)
- IF_KW("af-list", 7, YANG_LEAF_LIST)
- else IF_KW("af", 2, YANG_LEAF)
- else IF_KW("ngth", 4, YANG_LENGTH)
- IF_KW_PREFIX_END
- else IF_KW("ist", 3, YANG_LIST)
- break;
- case 'm':
- MOVE_INPUT(ctx, data, 1);
- IF_KW_PREFIX("a", 1)
- IF_KW("ndatory", 7, YANG_MANDATORY)
- else IF_KW("x-elements", 10, YANG_MAX_ELEMENTS)
- IF_KW_PREFIX_END
- else IF_KW("in-elements", 11, YANG_MIN_ELEMENTS)
- else IF_KW("ust", 3, YANG_MUST)
- else IF_KW_PREFIX("od", 2)
- IF_KW("ule", 3, YANG_MODULE)
- else IF_KW("ifier", 5, YANG_MODIFIER)
- IF_KW_PREFIX_END
- break;
- case 'n':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("amespace", 8, YANG_NAMESPACE)
- else IF_KW("otification", 11, YANG_NOTIFICATION)
- break;
- case 'o':
- MOVE_INPUT(ctx, data, 1);
- IF_KW_PREFIX("r", 1)
- IF_KW("dered-by", 8, YANG_ORDERED_BY)
- else IF_KW("ganization", 10, YANG_ORGANIZATION)
- IF_KW_PREFIX_END
- else IF_KW("utput", 5, YANG_OUTPUT)
- break;
- case 'p':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("ath", 3, YANG_PATH)
- else IF_KW("attern", 6, YANG_PATTERN)
- else IF_KW("osition", 7, YANG_POSITION)
- else IF_KW_PREFIX("re", 2)
- IF_KW("fix", 3, YANG_PREFIX)
- else IF_KW("sence", 5, YANG_PRESENCE)
- IF_KW_PREFIX_END
- break;
- case 'r':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("ange", 4, YANG_RANGE)
- else IF_KW_PREFIX("e", 1)
- IF_KW_PREFIX("f", 1)
- IF_KW("erence", 6, YANG_REFERENCE)
- else IF_KW("ine", 3, YANG_REFINE)
- IF_KW_PREFIX_END
- else IF_KW("quire-instance", 14, YANG_REQUIRE_INSTANCE)
- else IF_KW("vision-date", 11, YANG_REVISION_DATE)
- else IF_KW("vision", 6, YANG_REVISION)
- IF_KW_PREFIX_END
- else IF_KW("pc", 2, YANG_RPC)
- break;
- case 's':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("tatus", 5, YANG_STATUS)
- else IF_KW("ubmodule", 8, YANG_SUBMODULE)
- break;
- case 't':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("ypedef", 6, YANG_TYPEDEF)
- else IF_KW("ype", 3, YANG_TYPE)
- break;
- case 'u':
- MOVE_INPUT(ctx, data, 1);
- IF_KW_PREFIX("ni", 2)
- IF_KW("que", 3, YANG_UNIQUE)
- else IF_KW("ts", 2, YANG_UNITS)
- IF_KW_PREFIX_END
- else IF_KW("ses", 3, YANG_USES)
- break;
- case 'v':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("alue", 4, YANG_VALUE)
- break;
- case 'w':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("hen", 3, YANG_WHEN)
- break;
- case 'y':
- MOVE_INPUT(ctx, data, 1);
- IF_KW("ang-version", 11, YANG_YANG_VERSION)
- else IF_KW("in-element", 10, YANG_YIN_ELEMENT)
- break;
- case ';':
- MOVE_INPUT(ctx, data, 1);
- *kw = YANG_SEMICOLON;
+ if (*kw == YANG_SEMICOLON || *kw == YANG_LEFT_BRACE || *kw == YANG_RIGHT_BRACE) {
goto success;
- case '{':
- MOVE_INPUT(ctx, data, 1);
- *kw = YANG_LEFT_BRACE;
- goto success;
- case '}':
- MOVE_INPUT(ctx, data, 1);
- *kw = YANG_RIGHT_BRACE;
- goto success;
- default:
- break;
}
-#undef IF_KW
-#undef IF_KW_PREFIX
-#undef IF_KW_PREFIX_END
-
if (*kw != YANG_NONE) {
/* make sure we have the whole keyword */
switch (**data) {
@@ -979,7 +704,7 @@
/* fallthrough */
default:
MOVE_INPUT(ctx, data, 1);
- LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start,
+ LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start,
"a keyword followed by a separator");
return LY_EVALID;
}
@@ -989,19 +714,19 @@
extension:
while (**data && (**data != ' ') && (**data != '\t') && (**data != '\n') && (**data != '{') && (**data != ';')) {
LY_CHECK_ERR_RET(ly_getutf8(data, &c, &len),
- LOGVAL_YANG(ctx, LY_VCODE_INCHAR, (*data)[-len]), LY_EVALID);
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, (*data)[-len]), LY_EVALID);
++ctx->indent;
/* check character validity */
- LY_CHECK_RET(check_identifierchar(ctx, c, *data - len == word_start ? 1 : 0, &prefix));
+ LY_CHECK_RET(lysp_check_identifierchar(ctx, c, *data - len == word_start ? 1 : 0, &prefix));
}
if (!**data) {
- LOGVAL_YANG(ctx, LY_VCODE_EOF);
+ LOGVAL_PARSER(ctx, LY_VCODE_EOF);
return LY_EVALID;
}
/* prefix is mandatory for extension instances */
if (prefix != 2) {
- LOGVAL_YANG(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start, "a keyword");
+ LOGVAL_PARSER(ctx, LY_VCODE_INSTREXP, (int)(*data - word_start), word_start, "a keyword");
return LY_EVALID;
}
@@ -1133,7 +858,7 @@
enum yang_keyword kw;
if (*value) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, lyext_substmt2str(substmt));
return LY_EVALID;
}
@@ -1149,7 +874,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, substmt, substmt_index, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
return LY_EVALID;
}
}
@@ -1175,7 +900,7 @@
enum yang_keyword kw;
if (*version) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "yang-version");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yang-version");
return LY_EVALID;
}
@@ -1187,7 +912,7 @@
} else if ((word_len == 3) && !strncmp(word, "1.1", word_len)) {
*version = LYS_VERSION_1_1;
} else {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "yang-version");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yang-version");
free(buf);
return LY_EVALID;
}
@@ -1199,7 +924,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_VERSION, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
return LY_EVALID;
}
}
@@ -1226,7 +951,7 @@
enum yang_keyword kw;
if (*belongsto) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "belongs-to");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "belongs-to");
return LY_EVALID;
}
@@ -1244,7 +969,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_BELONGSTO, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
return LY_EVALID;
}
}
@@ -1252,7 +977,7 @@
checks:
/* mandatory substatements */
if (!*prefix) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "belongs-to");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "belongs-to");
return LY_EVALID;
}
return ret;
@@ -1277,7 +1002,7 @@
enum yang_keyword kw;
if (rev[0]) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "revision-date");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "revision-date");
return LY_EVALID;
}
@@ -1300,7 +1025,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REVISIONDATE, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
return LY_EVALID;
}
}
@@ -1336,7 +1061,7 @@
/* submodules share the namespace with the module names, so there must not be
* a module of the same name in the context, no need for revision matching */
if (!strcmp(module_name, inc->name) || ly_ctx_get_module_latest(ctx->ctx, inc->name)) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", inc->name);
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", inc->name);
return LY_EVALID;
}
@@ -1357,7 +1082,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inc->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
return LY_EVALID;
}
}
@@ -1410,14 +1135,14 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &imp->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
/* mandatory substatements */
- LY_CHECK_ERR_RET(!imp->prefix, LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "import"), LY_EVALID);
+ LY_CHECK_ERR_RET(!imp->prefix, LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "import"), LY_EVALID);
return ret;
}
@@ -1447,6 +1172,7 @@
/* check value */
if (lysp_check_date(ctx, word, word_len, "revision")) {
+ free(buf);
return LY_EVALID;
}
@@ -1465,7 +1191,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rev->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
return LY_EVALID;
}
}
@@ -1507,7 +1233,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, substmt, LY_ARRAY_SIZE(*texts) - 1, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), lyext_substmt2str(substmt));
return LY_EVALID;
}
}
@@ -1533,7 +1259,7 @@
enum yang_keyword kw;
if (*flags & LYS_CONFIG_MASK) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "config");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "config");
return LY_EVALID;
}
@@ -1545,7 +1271,7 @@
} else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
*flags |= LYS_CONFIG_R;
} else {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "config");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "config");
free(buf);
return LY_EVALID;
}
@@ -1557,7 +1283,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_CONFIG, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
return LY_EVALID;
}
}
@@ -1583,7 +1309,7 @@
enum yang_keyword kw;
if (*flags & LYS_MAND_MASK) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "mandatory");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "mandatory");
return LY_EVALID;
}
@@ -1595,7 +1321,7 @@
} else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
*flags |= LYS_MAND_FALSE;
} else {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "mandatory");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "mandatory");
free(buf);
return LY_EVALID;
}
@@ -1607,7 +1333,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MANDATORY, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
return LY_EVALID;
}
}
@@ -1635,7 +1361,7 @@
/* get value */
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
- YANG_CHECK_NONEMPTY(ctx, NULL, word_len, ly_stmt2str(restr_kw));
+ YANG_CHECK_NONEMPTY(ctx, word_len, ly_stmt2str(restr_kw));
INSERT_WORD(ctx, buf, restr->arg, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
switch (kw) {
@@ -1655,7 +1381,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
return LY_EVALID;
}
}
@@ -1700,7 +1426,7 @@
enum yang_keyword kw;
if (*flags & LYS_STATUS_MASK) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "status");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "status");
return LY_EVALID;
}
@@ -1714,7 +1440,7 @@
} else if ((word_len == 8) && !strncmp(word, "obsolete", word_len)) {
*flags |= LYS_STATUS_OBSLT;
} else {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "status");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "status");
free(buf);
return LY_EVALID;
}
@@ -1726,7 +1452,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_STATUS, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
return LY_EVALID;
}
}
@@ -1752,7 +1478,7 @@
struct lysp_when *when;
if (*when_p) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "when");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "when");
return LY_EVALID;
}
@@ -1761,7 +1487,7 @@
/* get value */
LY_CHECK_ERR_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len), free(when), LY_EMEM);
- YANG_CHECK_NONEMPTY(ctx, when, word_len, "when");
+ YANG_CHECK_NONEMPTY(ctx, word_len, "when");
INSERT_WORD(ctx, buf, when->cond, word, word_len);
*when_p = when;
@@ -1778,7 +1504,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &when->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "when");
return LY_EVALID;
}
}
@@ -1801,23 +1527,14 @@
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
size_t word_len;
- struct lysp_node *iter;
struct lysp_node_anydata *any;
- /* create structure */
- any = calloc(1, sizeof *any);
- LY_CHECK_ERR_RET(!any, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create new structure and insert into siblings */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, any, next);
+
any->nodetype = kw == YANG_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
any->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)any;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)any;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, any->name, word, word_len);
@@ -1853,7 +1570,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &any->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
(any->nodetype & LYS_ANYDATA) == LYS_ANYDATA ? ly_stmt2str(YANG_ANYDATA) : ly_stmt2str(YANG_ANYXML));
return LY_EVALID;
}
@@ -1873,7 +1590,7 @@
*
* @return LY_ERR values.
*/
-static LY_ERR
+LY_ERR
parse_type_enum_value_pos(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
struct lysp_ext_instance **exts)
{
@@ -1885,7 +1602,7 @@
enum yang_keyword kw;
if (*flags & LYS_SET_VALUE) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
return LY_EVALID;
}
*flags |= LYS_SET_VALUE;
@@ -1893,8 +1610,8 @@
/* get value */
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
- if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == YANG_VALUE) && !strncmp(word, "-0", 2))) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+ if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == YANG_POSITION) && !strncmp(word, "-0", 2))) {
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
goto error;
}
@@ -1902,23 +1619,23 @@
if (val_kw == YANG_VALUE) {
num = strtol(word, &ptr, 10);
if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
goto error;
}
} else {
unum = strtoul(word, &ptr, 10);
if (unum > UINT64_C(4294967295)) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
goto error;
}
}
/* we have not parsed the whole argument */
if ((size_t)(ptr - word) != word_len) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
goto error;
}
if (errno == ERANGE) {
- LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
goto error;
}
if (val_kw == YANG_VALUE) {
@@ -1934,7 +1651,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, val_kw == YANG_VALUE ? LYEXT_SUBSTMT_VALUE : LYEXT_SUBSTMT_POSITION, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
return LY_EVALID;
}
}
@@ -1960,7 +1677,7 @@
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
- size_t word_len, u;
+ size_t word_len;
enum yang_keyword kw;
struct lysp_type_enum *enm;
@@ -1969,29 +1686,13 @@
/* get value */
LY_CHECK_RET(get_argument(ctx, data, enum_kw == YANG_ENUM ? Y_STR_ARG : Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
if (enum_kw == YANG_ENUM) {
- if (!word_len) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
- free(buf);
- return LY_EVALID;
- } else if (isspace(word[0]) || isspace(word[word_len - 1])) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Enum name must not have any leading or trailing whitespaces (\"%.*s\").",
- word_len, word);
- free(buf);
- return LY_EVALID;
- } else {
- for (u = 0; u < word_len; ++u) {
- if (iscntrl(word[u])) {
- LOGWRN(ctx->ctx, "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
- word_len, word, u + 1);
- break;
- }
- }
- }
+ ret = lysp_check_enum_name(ctx, (const char *)word, word_len);
+ LY_CHECK_ERR_RET(ret, free(buf), ret);
} else { /* YANG_BIT */
}
if (enum_kw == YANG_ENUM) {
- YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "enum");
+ YANG_CHECK_NONEMPTY(ctx, word_len, "enum");
}
INSERT_WORD(ctx, buf, enm->name, word, word_len);
CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
@@ -2012,14 +1713,20 @@
LY_CHECK_RET(parse_status(ctx, data, &enm->flags, &enm->exts));
break;
case YANG_VALUE:
+ LY_CHECK_ERR_RET(enum_kw == YANG_BIT, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
+ ly_stmt2str(enum_kw)), LY_EVALID);
+ LY_CHECK_RET(parse_type_enum_value_pos(ctx, data, kw, &enm->value, &enm->flags, &enm->exts));
+ break;
case YANG_POSITION:
+ LY_CHECK_ERR_RET(enum_kw == YANG_ENUM, LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw),
+ ly_stmt2str(enum_kw)), LY_EVALID);
LY_CHECK_RET(parse_type_enum_value_pos(ctx, data, kw, &enm->value, &enm->flags, &enm->exts));
break;
case YANG_CUSTOM:
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &enm->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
return LY_EVALID;
}
}
@@ -2046,7 +1753,7 @@
enum yang_keyword kw;
if (*fracdig) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "fraction-digits");
return LY_EVALID;
}
@@ -2054,7 +1761,7 @@
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
free(buf);
return LY_EVALID;
}
@@ -2063,12 +1770,12 @@
num = strtoul(word, &ptr, 10);
/* we have not parsed the whole argument */
if ((size_t)(ptr - word) != word_len) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
free(buf);
return LY_EVALID;
}
if ((errno == ERANGE) || (num > 18)) {
- LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, "fraction-digits");
+ LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "fraction-digits");
free(buf);
return LY_EVALID;
}
@@ -2081,7 +1788,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_FRACDIGITS, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
return LY_EVALID;
}
}
@@ -2109,7 +1816,7 @@
enum yang_keyword kw;
if (*flags & LYS_SET_REQINST) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "require-instance");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "require-instance");
return LY_EVALID;
}
*flags |= LYS_SET_REQINST;
@@ -2120,7 +1827,7 @@
if ((word_len == 4) && !strncmp(word, "true", word_len)) {
*reqinst = 1;
} else if ((word_len != 5) || strncmp(word, "false", word_len)) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "require-instance");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "require-instance");
free(buf);
return LY_EVALID;
}
@@ -2132,7 +1839,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_REQINSTANCE, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
return LY_EVALID;
}
}
@@ -2158,7 +1865,7 @@
enum yang_keyword kw;
if ((*pat)[0] == 0x15) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "modifier");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "modifier");
return LY_EVALID;
}
@@ -2166,7 +1873,7 @@
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if ((word_len != 12) || strncmp(word, "invert-match", word_len)) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "modifier");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "modifier");
free(buf);
return LY_EVALID;
}
@@ -2188,7 +1895,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MODIFIER, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
return LY_EVALID;
}
}
@@ -2253,7 +1960,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &restr->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
return LY_EVALID;
}
}
@@ -2279,7 +1986,7 @@
struct lysp_type *nest_type;
if (type->name) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "type");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "type");
return LY_EVALID;
}
@@ -2307,7 +2014,7 @@
break;
case YANG_LENGTH:
if (type->length) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
return LY_EVALID;
}
type->length = calloc(1, sizeof *type->length);
@@ -2326,11 +2033,11 @@
break;
case YANG_RANGE:
if (type->range) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
return LY_EVALID;
}
type->range = calloc(1, sizeof *type->range);
- LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->ctx), LY_EVALID);
+ LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->ctx), LY_EMEM);
LY_CHECK_RET(parse_restr(ctx, data, kw, type->range));
type->flags |= LYS_SET_RANGE;
@@ -2348,7 +2055,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &type->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
return LY_EVALID;
}
}
@@ -2371,23 +2078,13 @@
char *buf, *word;
size_t word_len;
enum yang_keyword kw;
- struct lysp_node *iter;
struct lysp_node_leaf *leaf;
- /* create structure */
- leaf = calloc(1, sizeof *leaf);
- LY_CHECK_ERR_RET(!leaf, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create new leaf structure */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, leaf, next);
leaf->nodetype = LYS_LEAF;
leaf->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)leaf;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)leaf;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, leaf->name, word, word_len);
@@ -2432,7 +2129,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &leaf->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
return LY_EVALID;
}
}
@@ -2440,11 +2137,11 @@
checks:
/* mandatory substatements */
if (!leaf->type.name) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "type", "leaf");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf");
return LY_EVALID;
}
if ((leaf->flags & LYS_MAND_TRUE) && (leaf->dflt)) {
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "leaf");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "leaf");
return LY_EVALID;
}
@@ -2472,7 +2169,7 @@
enum yang_keyword kw;
if (*flags & LYS_SET_MAX) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "max-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "max-elements");
return LY_EVALID;
}
*flags |= LYS_SET_MAX;
@@ -2481,7 +2178,7 @@
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
free(buf);
return LY_EVALID;
}
@@ -2491,12 +2188,12 @@
num = strtoul(word, &ptr, 10);
/* we have not parsed the whole argument */
if ((size_t)(ptr - word) != word_len) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
free(buf);
return LY_EVALID;
}
if ((errno == ERANGE) || (num > UINT32_MAX)) {
- LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, "max-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "max-elements");
free(buf);
return LY_EVALID;
}
@@ -2511,7 +2208,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MAX, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
return LY_EVALID;
}
}
@@ -2539,7 +2236,7 @@
enum yang_keyword kw;
if (*flags & LYS_SET_MIN) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "min-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "min-elements");
return LY_EVALID;
}
*flags |= LYS_SET_MIN;
@@ -2548,7 +2245,7 @@
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
free(buf);
return LY_EVALID;
}
@@ -2557,12 +2254,12 @@
num = strtoul(word, &ptr, 10);
/* we have not parsed the whole argument */
if ((size_t)(ptr - word) != word_len) {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
free(buf);
return LY_EVALID;
}
if ((errno == ERANGE) || (num > UINT32_MAX)) {
- LOGVAL_YANG(ctx, LY_VCODE_OOB, word_len, word, "min-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "min-elements");
free(buf);
return LY_EVALID;
}
@@ -2575,7 +2272,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_MIN, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
return LY_EVALID;
}
}
@@ -2601,7 +2298,7 @@
enum yang_keyword kw;
if (*flags & LYS_ORDBY_MASK) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "ordered-by");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "ordered-by");
return LY_EVALID;
}
@@ -2613,7 +2310,7 @@
} else if ((word_len == 4) && !strncmp(word, "user", word_len)) {
*flags |= LYS_ORDBY_USER;
} else {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "ordered-by");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "ordered-by");
free(buf);
return LY_EVALID;
}
@@ -2625,7 +2322,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ORDEREDBY, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
return LY_EVALID;
}
}
@@ -2648,23 +2345,13 @@
char *buf, *word;
size_t word_len;
enum yang_keyword kw;
- struct lysp_node *iter;
struct lysp_node_leaflist *llist;
- /* create structure */
- llist = calloc(1, sizeof *llist);
- LY_CHECK_ERR_RET(!llist, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create new leaf-list structure */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, llist, next);
llist->nodetype = LYS_LEAFLIST;
llist->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)llist;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)llist;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, llist->name, word, word_len);
@@ -2716,7 +2403,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &llist->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
return LY_EVALID;
}
}
@@ -2724,15 +2411,15 @@
checks:
/* mandatory substatements */
if (!llist->type.name) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "type", "leaf-list");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf-list");
return LY_EVALID;
}
if ((llist->min) && (llist->dflts)) {
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMSCOMB, "min-elements", "default", "leaf-list");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMSCOMB, "min-elements", "default", "leaf-list");
return LY_EVALID;
}
if (llist->max && llist->min > llist->max) {
- LOGVAL_YANG(ctx, LYVE_SEMANTICS,
+ LOGVAL_PARSER(ctx, LYVE_SEMANTICS,
"Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u.",
llist->min, llist->max);
return LY_EVALID;
@@ -2763,7 +2450,7 @@
/* get value */
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
- YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "refine");
+ YANG_CHECK_NONEMPTY(ctx, word_len, "refine");
INSERT_WORD(ctx, buf, rf->nodeid, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -2803,7 +2490,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &rf->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
return LY_EVALID;
}
}
@@ -2859,7 +2546,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &tpdf->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
return LY_EVALID;
}
}
@@ -2867,13 +2554,13 @@
checks:
/* mandatory substatements */
if (!tpdf->type.name) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "type", "typedef");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "typedef");
return LY_EVALID;
}
/* store data for collision check */
if (parent && !(parent->nodetype & (LYS_GROUPING | LYS_ACTION | LYS_INOUT | LYS_NOTIF))) {
- ly_set_add(&ctx->tpdfs_nodes, parent, 0);
+ LY_CHECK_RET(ly_set_add(&ctx->tpdfs_nodes, parent, 0) == -1, LY_EMEM);
}
return ret;
@@ -2898,7 +2585,7 @@
enum yang_keyword kw;
if (inout_p->nodetype) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
return LY_EVALID;
}
@@ -2947,14 +2634,14 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &inout_p->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, inout_p->groupings, NULL, NULL, NULL));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, inout_p->groupings, NULL, NULL, NULL));
return ret;
}
@@ -3017,14 +2704,14 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &act->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, act->groupings, NULL, NULL, NULL));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, act->groupings, NULL, NULL, NULL));
return ret;
}
@@ -3109,14 +2796,14 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, ¬if->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, notif->groupings, NULL, NULL, NULL));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, notif->groupings, NULL, NULL, NULL));
return ret;
}
@@ -3202,20 +2889,20 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &grp->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "grouping");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "grouping");
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, grp->groupings, NULL, grp->actions, grp->notifs));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, grp->groupings, NULL, grp->actions, grp->notifs));
return ret;
}
/**
- * @brief Parse the refine statement.
+ * @brief Parse the augment statement.
*
* @param[in] ctx yang parser context for logging.
* @param[in,out] data Data to read from, always moved to currently handled character.
@@ -3236,7 +2923,7 @@
/* get value */
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
- YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "augment");
+ YANG_CHECK_NONEMPTY(ctx, word_len, "augment");
INSERT_WORD(ctx, buf, aug->nodeid, word, word_len);
aug->nodetype = LYS_AUGMENT;
aug->parent = parent;
@@ -3299,119 +2986,19 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &aug->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, NULL, NULL, aug->actions, aug->notifs));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, NULL, NULL, aug->actions, aug->notifs));
return ret;
}
/**
- * @brief Finalize some of the structures in case they are stored in sized array,
- * which can be possibly reallocated and some other data may point to them.
- *
- * Update parent pointers in the nodes inside grouping/augment/RPC/Notification, which could be reallocated.
- *
- * @param[in] mod Parsed module to be updated.
- * @return LY_ERR value (currently only LY_SUCCESS, but it can change in future).
- */
-static LY_ERR
-parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
- struct lysp_action *actions, struct lysp_notif *notifs)
-{
- unsigned int u, v;
- struct lysp_node *child;
-
- /* finalize parent pointers to the reallocated items */
-
- /* gropings */
- LY_ARRAY_FOR(groupings, u) {
- LY_LIST_FOR(groupings[u].data, child) {
- child->parent = (struct lysp_node*)&groupings[u];
- }
- LY_ARRAY_FOR(groupings[u].actions, v) {
- groupings[u].actions[v].parent = (struct lysp_node*)&groupings[u];
- }
- LY_ARRAY_FOR(groupings[u].notifs, v) {
- groupings[u].notifs[v].parent = (struct lysp_node*)&groupings[u];
- }
- LY_ARRAY_FOR(groupings[u].groupings, v) {
- groupings[u].groupings[v].parent = (struct lysp_node*)&groupings[u];
- }
- if (groupings[u].typedefs) {
- ly_set_add(&ctx->tpdfs_nodes, &groupings[u], 0);
- }
- }
-
- /* augments */
- LY_ARRAY_FOR(augments, u) {
- LY_LIST_FOR(augments[u].child, child) {
- child->parent = (struct lysp_node*)&augments[u];
- }
- LY_ARRAY_FOR(augments[u].actions, v) {
- augments[u].actions[v].parent = (struct lysp_node*)&augments[u];
- }
- LY_ARRAY_FOR(augments[u].notifs, v) {
- augments[u].notifs[v].parent = (struct lysp_node*)&augments[u];
- }
- }
-
- /* actions */
- LY_ARRAY_FOR(actions, u) {
- if (actions[u].input.parent) {
- actions[u].input.parent = (struct lysp_node*)&actions[u];
- LY_LIST_FOR(actions[u].input.data, child) {
- child->parent = (struct lysp_node*)&actions[u].input;
- }
- LY_ARRAY_FOR(actions[u].input.groupings, v) {
- actions[u].input.groupings[v].parent = (struct lysp_node*)&actions[u].input;
- }
- if (actions[u].input.typedefs) {
- ly_set_add(&ctx->tpdfs_nodes, &actions[u].input, 0);
- }
- }
- if (actions[u].output.parent) {
- actions[u].output.parent = (struct lysp_node*)&actions[u];
- LY_LIST_FOR(actions[u].output.data, child) {
- child->parent = (struct lysp_node*)&actions[u].output;
- }
- LY_ARRAY_FOR(actions[u].output.groupings, v) {
- actions[u].output.groupings[v].parent = (struct lysp_node*)&actions[u].output;
- }
- if (actions[u].output.typedefs) {
- ly_set_add(&ctx->tpdfs_nodes, &actions[u].output, 0);
- }
- }
- LY_ARRAY_FOR(actions[u].groupings, v) {
- actions[u].groupings[v].parent = (struct lysp_node*)&actions[u];
- }
- if (actions[u].typedefs) {
- ly_set_add(&ctx->tpdfs_nodes, &actions[u], 0);
- }
- }
-
- /* notifications */
- LY_ARRAY_FOR(notifs, u) {
- LY_LIST_FOR(notifs[u].data, child) {
- child->parent = (struct lysp_node*)¬ifs[u];
- }
- LY_ARRAY_FOR(notifs[u].groupings, v) {
- notifs[u].groupings[v].parent = (struct lysp_node*)¬ifs[u];
- }
- if (notifs[u].typedefs) {
- ly_set_add(&ctx->tpdfs_nodes, ¬ifs[u], 0);
- }
- }
-
- return LY_SUCCESS;
-}
-
-/**
* @brief Parse the uses statement.
*
* @param[in] ctx yang parser context for logging.
@@ -3427,23 +3014,13 @@
char *buf, *word;
size_t word_len;
enum yang_keyword kw;
- struct lysp_node *iter;
struct lysp_node_uses *uses;
- /* create structure */
- uses = calloc(1, sizeof *uses);
- LY_CHECK_ERR_RET(!uses, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create uses structure */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, uses, next);
uses->nodetype = LYS_USES;
uses->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)uses;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)uses;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, uses->name, word, word_len);
@@ -3477,13 +3054,13 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &uses->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
return LY_EVALID;
}
}
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, NULL, uses->augments, NULL, NULL));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, NULL, uses->augments, NULL, NULL));
return ret;
}
@@ -3504,23 +3081,13 @@
char *buf, *word;
size_t word_len;
enum yang_keyword kw;
- struct lysp_node *iter;
struct lysp_node_case *cas;
- /* create structure */
- cas = calloc(1, sizeof *cas);
- LY_CHECK_ERR_RET(!cas, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create new case structure */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, cas, next);
cas->nodetype = LYS_CASE;
cas->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)cas;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)cas;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, cas->name, word, word_len);
@@ -3572,7 +3139,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cas->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
return LY_EVALID;
}
}
@@ -3595,23 +3162,13 @@
char *buf, *word;
size_t word_len;
enum yang_keyword kw;
- struct lysp_node *iter;
struct lysp_node_choice *choice;
- /* create structure */
- choice = calloc(1, sizeof *choice);
- LY_CHECK_ERR_RET(!choice, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create new choice structure */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, choice, next);
choice->nodetype = LYS_CHOICE;
choice->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)choice;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)choice;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, choice->name, word, word_len);
@@ -3673,14 +3230,14 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &choice->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
if ((choice->flags & LYS_MAND_TRUE) && choice->dflt) {
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "choice");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMSCOMB, "mandatory", "default", "choice");
return LY_EVALID;
}
return ret;
@@ -3702,23 +3259,13 @@
char *buf, *word;
size_t word_len;
enum yang_keyword kw;
- struct lysp_node *iter;
struct lysp_node_container *cont;
- /* create structure */
- cont = calloc(1, sizeof *cont);
- LY_CHECK_ERR_RET(!cont, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create new container structure */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, cont, next);
cont->nodetype = LYS_CONTAINER;
cont->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)cont;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)cont;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, cont->name, word, word_len);
@@ -3794,13 +3341,13 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &cont->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
return LY_EVALID;
}
}
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, cont->groupings, NULL, cont->actions, cont->notifs));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, cont->groupings, NULL, cont->actions, cont->notifs));
return ret;
}
@@ -3820,23 +3367,13 @@
char *buf, *word;
size_t word_len;
enum yang_keyword kw;
- struct lysp_node *iter;
struct lysp_node_list *list;
- /* create structure */
- list = calloc(1, sizeof *list);
- LY_CHECK_ERR_RET(!list, LOGMEM(ctx->ctx), LY_EMEM);
+ /* create new list structure */
+ LY_LIST_NEW_RET(ctx->ctx, siblings, list, next);
list->nodetype = LYS_LIST;
list->parent = parent;
- /* insert into siblings */
- if (!*siblings) {
- *siblings = (struct lysp_node *)list;
- } else {
- for (iter = *siblings; iter->next; iter = iter->next);
- iter->next = (struct lysp_node *)list;
- }
-
/* get name */
LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, list->name, word, word_len);
@@ -3924,17 +3461,17 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &list->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "list");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "list");
return LY_EVALID;
}
}
LY_CHECK_RET(ret);
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, list->groupings, NULL, list->actions, list->notifs));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, list->groupings, NULL, list->actions, list->notifs));
if (list->max && list->min > list->max) {
- LOGVAL_YANG(ctx, LYVE_SEMANTICS,
+ LOGVAL_PARSER(ctx, LYVE_SEMANTICS,
"Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u.",
list->min, list->max);
return LY_EVALID;
@@ -3962,7 +3499,7 @@
enum yang_keyword kw;
if (*flags & LYS_YINELEM_MASK) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "yin-element");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "yin-element");
return LY_EVALID;
}
@@ -3974,7 +3511,7 @@
} else if ((word_len == 5) && !strncmp(word, "false", word_len)) {
*flags |= LYS_YINELEM_FALSE;
} else {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "yin-element");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "yin-element");
free(buf);
return LY_EVALID;
}
@@ -3986,7 +3523,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_YINELEM, 0, exts));
LY_CHECK_RET(ret); break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
return LY_EVALID;
}
}
@@ -3994,7 +3531,7 @@
}
/**
- * @brief Parse the yin-element statement.
+ * @brief Parse the argument statement.
*
* @param[in] ctx yang parser context for logging.
* @param[in,out] data Data to read from, always moved to currently handled character.
@@ -4013,12 +3550,12 @@
enum yang_keyword kw;
if (*argument) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, "argument");
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, "argument");
return LY_EVALID;
}
/* get value */
- LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
+ LY_CHECK_RET(get_argument(ctx, data, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
INSERT_WORD(ctx, buf, *argument, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
@@ -4030,7 +3567,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_ARGUMENT, 0, exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
return LY_EVALID;
}
}
@@ -4079,7 +3616,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ex->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
return LY_EVALID;
}
}
@@ -4102,7 +3639,7 @@
char *buf, *word;
size_t word_len, dev_mod;
enum yang_keyword kw;
- struct lysp_deviate *iter, *d;
+ struct lysp_deviate *d;
struct lysp_deviate_add *d_add = NULL;
struct lysp_deviate_rpl *d_rpl = NULL;
struct lysp_deviate_del *d_del = NULL;
@@ -4123,7 +3660,7 @@
} else if ((word_len == 6) && !strncmp(word, "delete", word_len)) {
dev_mod = LYS_DEV_DELETE;
} else {
- LOGVAL_YANG(ctx, LY_VCODE_INVAL, word_len, word, "deviate");
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "deviate");
free(buf);
return LY_EVALID;
}
@@ -4164,7 +3701,6 @@
d_uniques = &d_del->uniques;
d_dflts = &d_del->dflts;
d_musts = &d_del->musts;
- d_flags = &d_del->flags;
break;
default:
assert(0);
@@ -4173,12 +3709,7 @@
d->mod = dev_mod;
/* insert into siblings */
- if (!*deviates) {
- *deviates = d;
- } else {
- for (iter = *deviates; iter->next; iter = iter->next);
- iter->next = d;
- }
+ LY_LIST_INSERT(deviates, d, next);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
switch (kw) {
@@ -4186,7 +3717,7 @@
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
case LYS_DEV_DELETE:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
LY_CHECK_RET(parse_config(ctx, data, d_flags, &d->exts));
@@ -4196,7 +3727,7 @@
case YANG_DEFAULT:
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
case LYS_DEV_REPLACE:
LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DEFAULT, 0, &d_rpl->dflt, Y_STR_ARG, &d->exts));
@@ -4210,7 +3741,7 @@
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
case LYS_DEV_DELETE:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
LY_CHECK_RET(parse_mandatory(ctx, data, d_flags, &d->exts));
@@ -4221,7 +3752,7 @@
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
case LYS_DEV_DELETE:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
LY_CHECK_RET(parse_maxelements(ctx, data, d_max, d_flags, &d->exts));
@@ -4232,7 +3763,7 @@
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
case LYS_DEV_DELETE:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
LY_CHECK_RET(parse_minelements(ctx, data, d_min, d_flags, &d->exts));
@@ -4243,7 +3774,7 @@
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
case LYS_DEV_REPLACE:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
LY_CHECK_RET(parse_restrs(ctx, data, kw, d_musts));
@@ -4255,11 +3786,11 @@
case LYS_DEV_NOT_SUPPORTED:
case LYS_DEV_ADD:
case LYS_DEV_DELETE:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
if (d_rpl->type) {
- LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(kw));
return LY_EVALID;
}
d_rpl->type = calloc(1, sizeof *d_rpl->type);
@@ -4272,7 +3803,7 @@
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
case LYS_DEV_REPLACE:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_UNIQUE, d_uniques, Y_STR_ARG, &d->exts));
@@ -4282,7 +3813,7 @@
case YANG_UNITS:
switch (dev_mod) {
case LYS_DEV_NOT_SUPPORTED:
- LOGVAL_YANG(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
+ LOGVAL_PARSER(ctx, LY_VCODE_INDEV, ly_devmod2str(dev_mod), ly_stmt2str(kw));
return LY_EVALID;
default:
LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_UNITS, 0, d_units, Y_STR_ARG, &d->exts));
@@ -4293,7 +3824,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &d->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviate");
return LY_EVALID;
}
}
@@ -4322,7 +3853,7 @@
/* get value */
LY_CHECK_RET(get_argument(ctx, data, Y_STR_ARG, NULL, &word, &buf, &word_len));
- YANG_CHECK_NONEMPTY(ctx, NULL, word_len, "deviation");
+ YANG_CHECK_NONEMPTY(ctx, word_len, "deviation");
INSERT_WORD(ctx, buf, dev->nodeid, word, word_len);
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
@@ -4340,7 +3871,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &dev->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "deviation");
return LY_EVALID;
}
}
@@ -4348,7 +3879,7 @@
checks:
/* mandatory substatements */
if (!dev->deviates) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "deviate", "deviation");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "deviate", "deviation");
return LY_EVALID;
}
@@ -4397,7 +3928,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &feat->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
return LY_EVALID;
}
}
@@ -4445,7 +3976,7 @@
break;
case YANG_BASE:
if (ident->bases && ctx->mod_version < 2) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Identity can be derived from multiple base identities only in YANG 1.1 modules");
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Identity can be derived from multiple base identities only in YANG 1.1 modules");
return LY_EVALID;
}
LY_CHECK_RET(parse_text_fields(ctx, data, LYEXT_SUBSTMT_BASE, &ident->bases, Y_PREF_IDENTIF_ARG, &ident->exts));
@@ -4454,7 +3985,7 @@
LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &ident->exts));
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
return LY_EVALID;
}
}
@@ -4487,7 +4018,7 @@
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
#define CHECK_ORDER(SECTION) \
- if (mod_stmt > SECTION) {LOGVAL_YANG(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
+ if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
switch (kw) {
/* module header */
@@ -4641,7 +4172,7 @@
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
return LY_EVALID;
}
}
@@ -4649,14 +4180,14 @@
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, mod->groupings, mod->augments, mod->rpcs, mod->notifs));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, mod->groupings, mod->augments, mod->rpcs, mod->notifs));
/* mandatory substatements */
if (!mod->mod->ns) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "namespace", "module");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "namespace", "module");
return LY_EVALID;
} else if (!mod->mod->prefix) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "prefix", "module");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "module");
return LY_EVALID;
}
@@ -4664,7 +4195,7 @@
* a submodule of the same name in the context, no need for revision matching */
dup = ly_ctx_get_submodule(ctx->ctx, NULL, mod->mod->name, NULL);
if (dup) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", mod->mod->name);
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", mod->mod->name);
return LY_EVALID;
}
@@ -4697,7 +4228,7 @@
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
#define CHECK_ORDER(SECTION) \
- if (mod_stmt > SECTION) {LOGVAL_YANG(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
+ if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
switch (kw) {
/* module header */
@@ -4847,7 +4378,7 @@
break;
default:
- LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
return LY_EVALID;
}
}
@@ -4855,11 +4386,11 @@
checks:
/* finalize parent pointers to the reallocated items */
- LY_CHECK_RET(parse_finalize_reallocated(ctx, submod->groupings, submod->augments, submod->rpcs, submod->notifs));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated(ctx, submod->groupings, submod->augments, submod->rpcs, submod->notifs));
/* mandatory substatements */
if (!submod->belongsto) {
- LOGVAL_YANG(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
+ LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
return LY_EVALID;
}
@@ -4867,7 +4398,7 @@
* a submodule of the same name in the context, no need for revision matching */
dup = ly_ctx_get_submodule(ctx->ctx, NULL, submod->name, NULL);
if (dup && strcmp(dup->belongsto, submod->belongsto)) {
- LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between submodules of name \"%s\".", dup->name);
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Name collision between submodules of name \"%s\".", dup->name);
return LY_EVALID;
}
@@ -4875,7 +4406,7 @@
}
LY_ERR
-yang_parse_submodule(struct lys_parser_ctx *context, const char *data, struct lysp_submodule **submod)
+yang_parse_submodule(struct lys_parser_ctx **context, struct ly_ctx *ly_ctx, struct lys_parser_ctx *main_ctx, const char *data, struct lysp_submodule **submod)
{
LY_ERR ret = LY_SUCCESS;
char *word;
@@ -4883,27 +4414,36 @@
enum yang_keyword kw;
struct lysp_submodule *mod_p = NULL;
+ /* create context */
+ *context = calloc(1, sizeof **context);
+ LY_CHECK_ERR_RET(!(*context), LOGMEM(ly_ctx), LY_EMEM);
+ (*context)->ctx = ly_ctx;
+ (*context)->line = 1;
+
+ /* map the typedefs and groupings list from main context to the submodule's context */
+ memcpy(&(*context)->tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+ memcpy(&(*context)->grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
+
/* "module"/"submodule" */
- ret = get_keyword(context, &data, &kw, &word, &word_len);
+ ret = get_keyword(*context, &data, &kw, &word, &word_len);
LY_CHECK_GOTO(ret, cleanup);
if (kw == YANG_MODULE) {
- LOGERR(context->ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
+ LOGERR((*context)->ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
ret = LY_EINVAL;
goto cleanup;
} else if (kw != YANG_SUBMODULE) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
- ly_stmt2str(kw));
+ LOGVAL_PARSER(*context, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
ret = LY_EVALID;
goto cleanup;
}
mod_p = calloc(1, sizeof *mod_p);
- LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(context->ctx), cleanup);
+ LY_CHECK_ERR_GOTO(!mod_p, LOGMEM((*context)->ctx), cleanup);
mod_p->parsing = 1;
/* substatements */
- ret = parse_submodule(context, &data, mod_p);
+ ret = parse_submodule(*context, &data, mod_p);
LY_CHECK_GOTO(ret, cleanup);
/* read some trailing spaces or new lines */
@@ -4911,8 +4451,7 @@
data++;
}
if (*data) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input.",
- 15, data, strlen(data) > 15 ? "..." : "");
+ LOGVAL_PARSER(*context, LY_VCODE_TRAILING_SUBMOD, 15, data, strlen(data) > 15 ? "..." : "");
ret = LY_EVALID;
goto cleanup;
}
@@ -4922,14 +4461,16 @@
cleanup:
if (ret) {
- lysp_submodule_free(context->ctx, mod_p);
+ lysp_submodule_free((*context)->ctx, mod_p);
+ lys_parser_ctx_free(*context);
+ *context = NULL;
}
return ret;
}
LY_ERR
-yang_parse_module(struct lys_parser_ctx *context, const char *data, struct lys_module *mod)
+yang_parse_module(struct lys_parser_ctx **context, const char *data, struct lys_module *mod)
{
LY_ERR ret = LY_SUCCESS;
char *word;
@@ -4937,28 +4478,33 @@
enum yang_keyword kw;
struct lysp_module *mod_p = NULL;
+ /* create context */
+ *context = calloc(1, sizeof **context);
+ LY_CHECK_ERR_RET(!(*context), LOGMEM(mod->ctx), LY_EMEM);
+ (*context)->ctx = mod->ctx;
+ (*context)->line = 1;
+
/* "module"/"submodule" */
- ret = get_keyword(context, &data, &kw, &word, &word_len);
+ ret = get_keyword(*context, &data, &kw, &word, &word_len);
LY_CHECK_GOTO(ret, cleanup);
if (kw == YANG_SUBMODULE) {
- LOGERR(context->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
+ LOGERR((*context)->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
ret = LY_EINVAL;
goto cleanup;
} else if (kw != YANG_MODULE) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
- ly_stmt2str(kw));
+ LOGVAL_PARSER((*context), LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
ret = LY_EVALID;
goto cleanup;
}
mod_p = calloc(1, sizeof *mod_p);
- LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(context->ctx), cleanup);
+ LY_CHECK_ERR_GOTO(!mod_p, LOGMEM((*context)->ctx), cleanup);
mod_p->mod = mod;
mod_p->parsing = 1;
/* substatements */
- ret = parse_module(context, &data, mod_p);
+ ret = parse_module(*context, &data, mod_p);
LY_CHECK_GOTO(ret, cleanup);
/* read some trailing spaces or new lines */
@@ -4966,8 +4512,7 @@
data++;
}
if (*data) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input.",
- 15, data, strlen(data) > 15 ? "..." : "");
+ LOGVAL_PARSER(*context, LY_VCODE_TRAILING_MOD, 15, data, strlen(data) > 15 ? "..." : "");
ret = LY_EVALID;
goto cleanup;
}
@@ -4978,6 +4523,8 @@
cleanup:
if (ret) {
lysp_module_free(mod_p);
+ lys_parser_ctx_free(*context);
+ *context = NULL;
}
return ret;
diff --git a/src/parser_yin.c b/src/parser_yin.c
new file mode 100644
index 0000000..2ce5ccc
--- /dev/null
+++ b/src/parser_yin.c
@@ -0,0 +1,3556 @@
+/**
+ * @file parser_yin.c
+ * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
+ * @brief YIN parser.
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+#include "common.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include "context.h"
+#include "dict.h"
+#include "xml.h"
+#include "tree.h"
+#include "tree_schema.h"
+#include "tree_schema_internal.h"
+#include "parser_yin.h"
+
+/**
+ * @brief check if given string is URI of yin namespace.
+ *
+ * @param ns Namespace URI to check.
+ *
+ * @return true if ns equals YIN_NS_URI false otherwise.
+ */
+#define IS_YIN_NS(ns) (strcmp(ns, YIN_NS_URI) == 0)
+
+const char *const yin_attr_list[] = {
+ [YIN_ARG_NAME] = "name",
+ [YIN_ARG_TARGET_NODE] = "target-node",
+ [YIN_ARG_MODULE] = "module",
+ [YIN_ARG_VALUE] = "value",
+ [YIN_ARG_TEXT] = "text",
+ [YIN_ARG_CONDITION] = "condition",
+ [YIN_ARG_URI] = "uri",
+ [YIN_ARG_DATE] = "date",
+ [YIN_ARG_TAG] = "tag",
+};
+
+enum yang_keyword
+yin_match_keyword(struct yin_parser_ctx *ctx, const char *name, size_t name_len,
+ const char *prefix, size_t prefix_len, enum yang_keyword parrent)
+{
+ const char *start = NULL;
+ enum yang_keyword kw = YANG_NONE;
+ const struct lyxml_ns *ns = NULL;
+
+ if (!name || name_len == 0) {
+ return YANG_NONE;
+ }
+
+ ns = lyxml_ns_get(&ctx->xml_ctx, prefix, prefix_len);
+ if (ns) {
+ if (!IS_YIN_NS(ns->uri)) {
+ return YANG_CUSTOM;
+ }
+ } else {
+ /* elements without namespace are automatically unknown */
+ return YANG_NONE;
+ }
+
+ start = name;
+ kw = lysp_match_kw(NULL, &name);
+
+ if (name - start == (long int)name_len) {
+ /* this is done because of collision in yang statement value and yang argument mapped to yin element value */
+ if (kw == YANG_VALUE && parrent == YANG_ERROR_MESSAGE) {
+ return YIN_VALUE;
+ }
+ return kw;
+ } else {
+ if (strncmp(start, "text", name_len) == 0) {
+ return YIN_TEXT;
+ } else {
+ return YANG_NONE;
+ }
+ }
+}
+
+enum yin_argument
+yin_match_argument_name(const char *name, size_t len)
+{
+ enum yin_argument arg = YIN_ARG_UNKNOWN;
+ size_t already_read = 0;
+ LY_CHECK_RET(len == 0, YIN_ARG_NONE);
+
+#define IF_ARG(STR, LEN, STMT) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;arg=STMT;}
+#define IF_ARG_PREFIX(STR, LEN) if (!strncmp((name) + already_read, STR, LEN)) {already_read+=LEN;
+#define IF_ARG_PREFIX_END }
+
+ switch (*name) {
+ case 'c':
+ already_read += 1;
+ IF_ARG("ondition", 8, YIN_ARG_CONDITION);
+ break;
+
+ case 'd':
+ already_read += 1;
+ IF_ARG("ate", 3, YIN_ARG_DATE);
+ break;
+
+ case 'm':
+ already_read += 1;
+ IF_ARG("odule", 5, YIN_ARG_MODULE);
+ break;
+
+ case 'n':
+ already_read += 1;
+ IF_ARG("ame", 3, YIN_ARG_NAME);
+ break;
+
+ case 't':
+ already_read += 1;
+ IF_ARG_PREFIX("a", 1)
+ IF_ARG("g", 1, YIN_ARG_TAG)
+ else IF_ARG("rget-node", 9, YIN_ARG_TARGET_NODE)
+ IF_ARG_PREFIX_END
+ else IF_ARG("ext", 3, YIN_ARG_TEXT)
+ break;
+
+ case 'u':
+ already_read += 1;
+ IF_ARG("ri", 2, YIN_ARG_URI)
+ break;
+
+ case 'v':
+ already_read += 1;
+ IF_ARG("alue", 4, YIN_ARG_VALUE);
+ break;
+ }
+
+ /* whole argument must be matched */
+ if (already_read != len) {
+ arg = YIN_ARG_UNKNOWN;
+ }
+
+#undef IF_ARG
+#undef IF_ARG_PREFIX
+#undef IF_ARG_PREFIX_END
+
+ return arg;
+}
+
+void free_arg_rec(struct yin_parser_ctx *ctx, struct yin_arg_record *record) {
+ (void)ctx; /* unused */
+ if (record && record->dynamic_content) {
+ free(record->content);
+ }
+}
+
+#define IS_NODE_ELEM(kw) (kw == YANG_ANYXML || kw == YANG_ANYDATA || kw == YANG_LEAF || kw == YANG_LEAF_LIST || \
+ kw == YANG_TYPEDEF || kw == YANG_USES || kw == YANG_LIST || kw == YANG_NOTIFICATION || \
+ kw == YANG_GROUPING || kw == YANG_CONTAINER || kw == YANG_CASE || kw == YANG_CHOICE || \
+ kw == YANG_ACTION || kw == YANG_RPC || kw == YANG_AUGMENT)
+
+#define HAS_META(kw) (IS_NODE_ELEM(kw) || kw == YANG_IMPORT || kw == YANG_INCLUDE || kw == YANG_INPUT || kw == YANG_OUTPUT)
+
+/**
+ * @brief Free subelems information allocated on heap.
+ *
+ * @param[in] count Size of subelems array.
+ * @param[in] subelems Subelems array to free.
+ */
+static void
+subelems_deallocator(size_t count, struct yin_subelement *subelems)
+{
+ for(size_t i = 0; i < count; ++i) {
+ if (HAS_META(subelems[i].type)) {
+ free(subelems[i].dest);
+ }
+ }
+
+ free(subelems);
+}
+
+/**
+ * @brief Allocate subelems information on heap.
+ *
+ * @param[in] ctx YIN parser context, used for logging.
+ * @param[in] count Number of subelements.
+ * @param[in] parent Parent node if any.
+ * @param[out] result Allocated subelems array.
+ *
+ * @return LY_SUCCESS on success LY_EMEM on memmory allocation failure.
+ */
+static LY_ERR
+subelems_allocator(struct yin_parser_ctx *ctx, size_t count, struct lysp_node *parent,
+ struct yin_subelement **result, ...)
+{
+ va_list ap;
+
+ *result = calloc(count, sizeof **result);
+ LY_CHECK_GOTO(!(*result), mem_err);
+
+ va_start(ap, result);
+ for (size_t i = 0; i < count; ++i) {
+ /* TYPE */
+ (*result)[i].type = va_arg(ap, enum yang_keyword);
+ /* DEST */
+ if (IS_NODE_ELEM((*result)[i].type)) {
+ struct tree_node_meta *node_meta = NULL;
+ node_meta = calloc(1, sizeof *node_meta);
+ LY_CHECK_GOTO(!node_meta, mem_err);
+ node_meta->parent = parent;
+ node_meta->nodes = va_arg(ap, void *);
+ (*result)[i].dest = node_meta;
+ } else if ((*result)[i].type == YANG_IMPORT) {
+ struct import_meta *imp_meta = NULL;
+ imp_meta = calloc(1, sizeof *imp_meta);
+ LY_CHECK_GOTO(!imp_meta, mem_err);
+ imp_meta->prefix = va_arg(ap, const char *);
+ imp_meta->imports = va_arg(ap, struct lysp_import **);
+ (*result)[i].dest = imp_meta;
+ } else if ((*result)[i].type == YANG_INCLUDE) {
+ struct include_meta *inc_meta = NULL;
+ inc_meta = calloc(1, sizeof *inc_meta);
+ LY_CHECK_GOTO(!inc_meta, mem_err);
+ inc_meta->name = va_arg(ap, const char *);
+ inc_meta->includes = va_arg(ap, struct lysp_include **);
+ (*result)[i].dest = inc_meta;
+ } else if ((*result)[i].type == YANG_INPUT || (*result)[i].type == YANG_OUTPUT) {
+ struct inout_meta *inout_meta = NULL;
+ inout_meta = calloc(1, sizeof *inout_meta);
+ LY_CHECK_GOTO(!inout_meta, mem_err);
+ inout_meta->parent = parent;
+ inout_meta->inout_p = va_arg(ap, struct lysp_action_inout *);
+ (*result)[i].dest = inout_meta;
+ } else {
+ (*result)[i].dest = va_arg(ap, void *);
+ }
+ /* FLAGS */
+ (*result)[i].flags = va_arg(ap, int);
+ }
+ va_end(ap);
+
+ return LY_SUCCESS;
+
+mem_err:
+ subelems_deallocator(count, *result);
+ LOGMEM(ctx->xml_ctx.ctx);
+ return LY_EMEM;
+}
+
+LY_ERR
+yin_load_attributes(struct yin_parser_ctx *ctx, const char **data, struct yin_arg_record **attrs)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_arg_record *argument_record = NULL;
+ const char *prefix, *name;
+ size_t prefix_len, name_len;
+
+ /* load all attributes */
+ while (ctx->xml_ctx.status == LYXML_ATTRIBUTE) {
+ ret = lyxml_get_attribute(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ if (ctx->xml_ctx.status == LYXML_ATTR_CONTENT) {
+ LY_ARRAY_NEW_GOTO(ctx->xml_ctx.ctx, *attrs, argument_record, ret, cleanup);
+ argument_record->name = name;
+ argument_record->name_len = name_len;
+ argument_record->prefix = prefix;
+ argument_record->prefix_len = prefix_len;
+ ret = lyxml_get_string(&ctx->xml_ctx, data, &argument_record->content, &argument_record->content_len,
+ &argument_record->content, &argument_record->content_len, &argument_record->dynamic_content);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ }
+
+cleanup:
+ if (ret != LY_SUCCESS) {
+ FREE_ARRAY(ctx, *attrs, free_arg_rec);
+ *attrs = NULL;
+ }
+ return ret;
+}
+
+LY_ERR
+yin_validate_value(struct yin_parser_ctx *ctx, enum yang_arg val_type, char *val, size_t len)
+{
+ int prefix = 0;
+ unsigned int c;
+ size_t utf8_char_len;
+ size_t already_read = 0;
+ while (already_read < len) {
+ LY_CHECK_ERR_RET(ly_getutf8((const char **)&val, &c, &utf8_char_len),
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INCHAR, (val)[-utf8_char_len]), LY_EVALID);
+ already_read += utf8_char_len;
+ LY_CHECK_ERR_RET(already_read > len, LOGINT(ctx->xml_ctx.ctx), LY_EINT);
+
+ switch (val_type) {
+ case Y_IDENTIF_ARG:
+ LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !already_read, NULL));
+ break;
+ case Y_PREF_IDENTIF_ARG:
+ LY_CHECK_RET(lysp_check_identifierchar((struct lys_parser_ctx *)ctx, c, !already_read, &prefix));
+ break;
+ case Y_STR_ARG:
+ case Y_MAYBE_STR_ARG:
+ LY_CHECK_RET(lysp_check_stringchar((struct lys_parser_ctx *)ctx, c));
+ break;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse yin attribute.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs ([Sized array](@ref sizedarrays)) of attributes.
+ * @param[in] arg_type Type of argument that is expected in parsed element (use YIN_ARG_NONE for elements without
+ * special argument).
+ * @param[out] arg_val Where value of argument should be stored. Can be NULL iff arg_type is specified as YIN_ARG_NONE.
+ * @param[in] val_type Type of expected value of attribute.
+ * @param[in] current_element Identification of current element, used for logging.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_attribute(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, enum yin_argument arg_type,
+ const char **arg_val, enum yang_arg val_type, enum yang_keyword current_element)
+{
+ enum yin_argument arg = YIN_ARG_UNKNOWN;
+ struct yin_arg_record *iter = NULL;
+ bool found = false;
+
+ /* validation of attributes */
+ LY_ARRAY_FOR(attrs, struct yin_arg_record, iter) {
+ /* yin arguments represented as attributes have no namespace, which in this case means no prefix */
+ if (!iter->prefix) {
+ arg = yin_match_argument_name(iter->name, iter->name_len);
+ if (arg == YIN_ARG_NONE) {
+ continue;
+ } else if (arg == arg_type) {
+ LY_CHECK_ERR_RET(found, LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_DUP_ATTR,
+ yin_attr2str(arg), ly_stmt2str(current_element)), LY_EVALID);
+ found = true;
+ LY_CHECK_RET(yin_validate_value(ctx, val_type, iter->content, iter->content_len));
+ INSERT_STRING(ctx->xml_ctx.ctx, *arg_val, iter->dynamic_content, iter->content, iter->content_len);
+ iter->dynamic_content = 0;
+ LY_CHECK_RET(!(*arg_val), LY_EMEM);
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_ATTR, iter->name_len, iter->name, ly_stmt2str(current_element));
+ return LY_EVALID;
+ }
+ }
+ }
+
+ /* anything else than Y_MAYBE_STR_ARG is mandatory */
+ if (val_type != Y_MAYBE_STR_ARG && !found) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YIN, "Missing mandatory attribute %s of %s element.", yin_attr2str(arg_type), ly_stmt2str(current_element));
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Get record with given type. Array must be sorted in ascending order by array[n].type.
+ *
+ * @param[in] type Type of wanted record.
+ * @param[in] array_size Size of array.
+ * @param[in] array Searched array.
+ *
+ * @return Pointer to desired record on success, NULL if element is not in the array.
+ */
+static struct yin_subelement *
+get_record(enum yang_keyword type, signed char array_size, struct yin_subelement *array)
+{
+ signed char left = 0, right = array_size - 1, middle;
+
+ while (left <= right) {
+ middle = left + (right - left) / 2;
+
+ if (array[middle].type == type) {
+ return &array[middle];
+ }
+
+ if (array[middle].type < type) {
+ left = middle + 1;
+ } else {
+ right = middle - 1;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * @brief Helper function to check mandatory constraint of subelement.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] subelem_info Array of information about subelements.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ * @param[in] current_element Identification of element that is currently being parsed, used for logging.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_check_subelem_mandatory_constraint(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
+ signed char subelem_info_size, enum yang_keyword current_element)
+{
+ for (signed char i = 0; i < subelem_info_size; ++i) {
+ /* if there is element that is mandatory and isn't parsed log error and return LY_EVALID */
+ if (subelem_info[i].flags & YIN_SUBELEM_MANDATORY && !(subelem_info[i].flags & YIN_SUBELEM_PARSED)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_MAND_SUBELEM,
+ ly_stmt2str(subelem_info[i].type), ly_stmt2str(current_element));
+ return LY_EVALID;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Helper function to check "first" constraint of subelement.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] subelem_info Array of information about subelements.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ * @param[in] current_element Identification of element that is currently being parsed, used for logging.
+ * @param[in] exp_first Record in subelem_info array that is expected to be defined as first subelement, used for logging.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_check_subelem_first_constraint(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info,
+ signed char subelem_info_size, enum yang_keyword current_element,
+ struct yin_subelement *exp_first)
+{
+ for (signed char i = 0; i < subelem_info_size; ++i) {
+ if (subelem_info[i].flags & YIN_SUBELEM_PARSED) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_FIRT_SUBELEM,
+ ly_stmt2str(exp_first->type), ly_stmt2str(current_element));
+ return LY_EVALID;
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Helper function to check if array of information about subelements is in ascending order.
+ *
+ * @param[in] subelem_info Array of information about subelements.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ *
+ * @return True iff subelem_info array is in ascending order, False otherwise.
+ */
+#ifndef NDEBUG
+static bool
+is_ordered(struct yin_subelement *subelem_info, signed char subelem_info_size)
+{
+ enum yang_keyword current = YANG_NONE; /* 0 (minimal value) */
+
+ for (signed char i = 0; i < subelem_info_size; ++i) {
+ if (subelem_info[i].type <= current) {
+ return false;
+ }
+ current = subelem_info[i].type;
+ }
+
+ return true;
+}
+#endif
+
+/**
+ * @brief Parse simple element without any special constraints and argument mapped to yin attribute,
+ * for example prefix or namespace element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[out] value Where value of attribute should be stored.
+ * @param[in] arg_type Expected type of attribute.
+ * @param[in] arg_val_type Type of expected value of attribute.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_simple_element(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+ const char **value, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+{
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, arg_type, value, arg_val_type, kw));
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ return yin_parse_content(ctx, subelems, 1, data, kw, NULL, exts);
+}
+
+/**
+ * @brief Parse path element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_path(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+ struct lysp_type *type)
+{
+ LY_CHECK_RET(yin_parse_simple_element(ctx, attrs, data, kw, &type->path,
+ YIN_ARG_VALUE, Y_STR_ARG, &type->exts));
+ type->flags |= LYS_SET_PATH;
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse pattern element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_pattern(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_type *type)
+{
+ const char *real_value = NULL;
+ char *saved_value = NULL;
+ struct lysp_restr *restr;
+
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->patterns, restr, LY_EMEM);
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &real_value, Y_STR_ARG, YANG_PATTERN));
+ size_t len = strlen(real_value);
+
+ saved_value = malloc(len + 2);
+ LY_CHECK_ERR_RET(!saved_value, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ memmove(saved_value + 1, real_value, len);
+ FREE_STRING(ctx->xml_ctx.ctx, real_value);
+ saved_value[0] = 0x06;
+ saved_value[len + 1] = '\0';
+ restr->arg = lydict_insert_zc(ctx->xml_ctx.ctx, saved_value);
+ LY_CHECK_ERR_RET(!restr->arg, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ type->flags |= LYS_SET_PATTERN;
+
+ struct yin_subelement subelems[6] = {
+ {YANG_DESCRIPTION, &restr->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_ERROR_APP_TAG, &restr->eapptag, YIN_SUBELEM_UNIQUE},
+ {YANG_ERROR_MESSAGE, &restr->emsg, YIN_SUBELEM_UNIQUE},
+ {YANG_MODIFIER, &restr->arg, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &restr->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+ return yin_parse_content(ctx, subelems, 6, data, YANG_PATTERN, NULL, &restr->exts);
+}
+
+/**
+ * @brief Parse fraction-digits element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_fracdigits(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_type *type)
+{
+ const char *temp_val = NULL;
+ char *ptr;
+ unsigned long int num;
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_FRACTION_DIGITS));
+
+ if (temp_val[0] == '\0' || (temp_val[0] == '0') || !isdigit(temp_val[0])) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "fraction-digits");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+
+ errno = 0;
+ num = strtoul(temp_val, &ptr, 10);
+ if (*ptr != '\0') {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "fraction-digits");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ if ((errno == ERANGE) || (num > 18)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "fraction-digits");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ type->fraction_digits = num;
+ type->flags |= LYS_SET_FRDIGITS;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+ return yin_parse_content(ctx, subelems, 1, data, YANG_FRACTION_DIGITS, NULL, &type->exts);
+}
+
+/**
+ * @brief Parse enum element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_enum(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_type *type)
+{
+ struct lysp_type_enum *en;
+
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->enums, en, LY_EMEM);
+ type->flags |= LYS_SET_ENUM;
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &en->name, Y_IDENTIF_ARG, YANG_ENUM));
+ LY_CHECK_RET(lysp_check_enum_name((struct lys_parser_ctx *)ctx, en->name, strlen(en->name)));
+ YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(en->name), "enum");
+ CHECK_UNIQUENESS((struct lys_parser_ctx *)ctx, type->enums, name, "enum", en->name);
+
+ struct yin_subelement subelems[6] = {
+ {YANG_DESCRIPTION, &en->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &en->iffeatures, 0},
+ {YANG_REFERENCE, &en->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &en->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_VALUE, en, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+ return yin_parse_content(ctx, subelems, 6, data, YANG_ENUM, NULL, &en->exts);
+}
+
+/**
+ * @brief Parse bit element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] type Type structure to store parsed value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_bit(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_type *type)
+{
+ struct lysp_type_enum *en;
+
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->bits, en, LY_EMEM);
+ type->flags |= LYS_SET_BIT;
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &en->name, Y_IDENTIF_ARG, YANG_BIT));
+ CHECK_UNIQUENESS((struct lys_parser_ctx *)ctx, type->enums, name, "bit", en->name);
+
+ struct yin_subelement subelems[6] = {
+ {YANG_DESCRIPTION, &en->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &en->iffeatures, 0},
+ {YANG_POSITION, en, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &en->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &en->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+ return yin_parse_content(ctx, subelems, 6, data, YANG_BIT, NULL, &en->exts);
+}
+
+/**
+ * @brief Parse simple element without any special constraints and argument mapped to yin attribute, that can have
+ * more instances, such as base or if-feature.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[out] values Parsed values to add to.
+ * @param[in] arg_type Expected type of attribute.
+ * @param[in] arg_val_type Type of expected value of attribute.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_simple_elements(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+ const char ***values, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+{
+ const char **value;
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *values, value, LY_EMEM);
+ uint32_t index = LY_ARRAY_SIZE(*values) - 1;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, &index, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, arg_type, value, arg_val_type, kw));
+
+ return yin_parse_content(ctx, subelems, 1, data, kw, NULL, exts);
+}
+
+/**
+ * @brief Parse simple element without any special constraints and argument mapped to yin attribute.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element.
+ * @param[in] subinfo Information about subelement, is used to determin which function should be called and where to store parsed value.
+ * @param[in] arg_type Expected type of attribute.
+ * @param[in] arg_val_type Type of expected value of attribute.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_simple_elem(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword kw,
+ struct yin_subelement *subinfo, enum yin_argument arg_type, enum yang_arg arg_val_type, struct lysp_ext_instance **exts)
+{
+ if (subinfo->flags & YIN_SUBELEM_UNIQUE) {
+ LY_CHECK_RET(yin_parse_simple_element(ctx, attrs, data, kw, (const char **)subinfo->dest,
+ arg_type, arg_val_type, exts));
+ } else {
+ LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, kw, (const char ***)subinfo->dest,
+ arg_type, arg_val_type, exts));
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse base element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] parent Identification of parent element.
+ * @param[out] dest Where parsed values should be stored.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_base(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword parent,
+ void *dest, struct lysp_ext_instance **exts)
+{
+ struct lysp_type *type = NULL;
+
+ if (parent == YANG_TYPE) {
+ type = (struct lysp_type *)dest;
+ LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, YANG_BASE, &type->bases, YIN_ARG_NAME,
+ Y_PREF_IDENTIF_ARG, exts));
+ type->flags |= LYS_SET_BASE;
+ } else if (parent == YANG_IDENTITY) {
+ LY_CHECK_RET(yin_parse_simple_elements(ctx, attrs, data, YANG_BASE, (const char ***)dest,
+ YIN_ARG_NAME, Y_PREF_IDENTIF_ARG, exts));
+ } else {
+ LOGINT(ctx->xml_ctx.ctx);
+ return LY_EINT;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse require-instance element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @prama[out] type Type structure to store value, flag and extensions.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_pasrse_reqinstance(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs,
+ const char **data, struct lysp_type *type)
+{
+ const char *temp_val = NULL;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ type->flags |= LYS_SET_REQINST;
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_REQUIRE_INSTANCE));
+ if (strcmp(temp_val, "true") == 0) {
+ type->require_instance = 1;
+ } else if (strcmp(temp_val, "false") != 0) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+ "require-instance", "true", "false");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_REQUIRE_INSTANCE, NULL, &type->exts);
+}
+
+/**
+ * @brief Parse modifier element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] pat Value to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_modifier(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ const char **pat, struct lysp_ext_instance **exts)
+{
+ assert(**pat == 0x06);
+ const char *temp_val;
+ char *modified_val;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MODIFIER));
+ if (strcmp(temp_val, "invert-match") != 0) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS1, temp_val, "value",
+ "modifier", "invert-match");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ lydict_remove(ctx->xml_ctx.ctx, temp_val);
+
+ /* allocate new value */
+ modified_val = malloc(strlen(*pat) + 1);
+ LY_CHECK_ERR_RET(!modified_val, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ strcpy(modified_val, *pat);
+ lydict_remove(ctx->xml_ctx.ctx, *pat);
+
+ /* modify the new value */
+ modified_val[0] = 0x15;
+ *pat = lydict_insert_zc(ctx->xml_ctx.ctx, modified_val);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_MODIFIER, NULL, exts);
+}
+
+/**
+ * @brief Parse a restriction element (length, range or one instance of must).
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] restr_kw Identificaton of element that is being parsed, can be set to YANG_MUST, YANG_LENGTH or YANG_RANGE.
+ * @param[in] restr Value to write to.
+ */
+static LY_ERR
+yin_parse_restriction(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ enum yang_keyword restr_kw, struct lysp_restr *restr)
+{
+ assert(restr_kw == YANG_MUST || restr_kw == YANG_LENGTH || restr_kw == YANG_RANGE);
+ struct yin_subelement subelems[5] = {
+ {YANG_DESCRIPTION, &restr->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_ERROR_APP_TAG, &restr->eapptag, YIN_SUBELEM_UNIQUE},
+ {YANG_ERROR_MESSAGE, &restr->emsg, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &restr->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+ /* argument of must is called condition, but argument of length and range is called value */
+ enum yin_argument arg_type = (restr_kw == YANG_MUST) ? YIN_ARG_CONDITION : YIN_ARG_VALUE;
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, arg_type, &restr->arg, Y_STR_ARG, restr_kw));
+
+ return yin_parse_content(ctx, subelems, 5, data, restr_kw, NULL, &restr->exts);
+}
+
+/**
+ * @brief Parse range element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] type Type structure to store parsed value and flags.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_range(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs,
+ const char **data, struct lysp_type *type)
+{
+ type->range = calloc(1, sizeof *type->range);
+ LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ LY_CHECK_RET(yin_parse_restriction(ctx, attrs, data, YANG_RANGE, type->range));
+ type->flags |= LYS_SET_RANGE;
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse length element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] type Type structure to store parsed value and flags.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_length(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs,
+ const char **data, struct lysp_type *type)
+{
+ type->length = calloc(1, sizeof *type->length);
+ LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ LY_CHECK_RET(yin_parse_restriction(ctx, attrs, data, YANG_LENGTH, type->length));
+ type->flags |= LYS_SET_LENGTH;
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse must element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] restrs Restrictions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_must(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_restr **restrs)
+{
+ struct lysp_restr *restr;
+
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *restrs, restr, LY_EMEM);
+ return yin_parse_restriction(ctx, attrs, data, YANG_MUST, restr);
+}
+
+/**
+ * @brief Parse position or value element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] kw Type of current element, can be set to YANG_POSITION or YANG_VALUE.
+ * @param[out] enm Enum structure to save value, flags and extension instances.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_value_pos(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ enum yang_keyword kw, struct lysp_type_enum *enm)
+{
+ assert(kw == YANG_POSITION || kw == YANG_VALUE);
+ const char *temp_val = NULL;
+ char *ptr;
+ long int num;
+ unsigned long int unum;
+
+ /* set value flag */
+ enm->flags |= LYS_SET_VALUE;
+
+ /* get attribute value */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, kw));
+ if (!temp_val || temp_val[0] == '\0' || (temp_val[0] == '+') ||
+ ((temp_val[0] == '0') && (temp_val[1] != '\0')) || ((kw == YANG_POSITION) && !strcmp(temp_val, "-0"))) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+ goto error;
+ }
+
+ /* convert value */
+ errno = 0;
+ if (kw == YANG_VALUE) {
+ num = strtol(temp_val, &ptr, 10);
+ if (num < INT64_C(-2147483648) || num > INT64_C(2147483647)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+ goto error;
+ }
+ } else {
+ unum = strtoul(temp_val, &ptr, 10);
+ if (unum > UINT64_C(4294967295)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+ goto error;
+ }
+ }
+ /* check if whole argument value was converted */
+ if (*ptr != '\0') {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
+ goto error;
+ }
+ if (errno == ERANGE) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", ly_stmt2str(kw));
+ goto error;
+ }
+ /* save correctly ternary operator can't be used because num and unum have different signes */
+ if (kw == YANG_VALUE) {
+ enm->value = num;
+ } else {
+ enm->value = unum;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+ /* parse subelements */
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+ return yin_parse_content(ctx, subelems, 1, data, kw, NULL, &enm->exts);
+
+error:
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+}
+
+
+/**
+ * @brief Parse belongs-to element.
+ *
+ * @param[in] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] submod Structure of submodule that is being parsed.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values
+ */
+static LY_ERR
+yin_parse_belongs_to(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_submodule *submod, struct lysp_ext_instance **exts)
+{
+ struct yin_subelement subelems[2] = {
+ {YANG_PREFIX, &submod->prefix, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &submod->belongsto, Y_IDENTIF_ARG, YANG_BELONGS_TO));
+
+ return yin_parse_content(ctx, subelems, 2, data, YANG_BELONGS_TO, NULL, exts);
+}
+
+/**
+ * @brief Function to parse meta tags (description, contact, ...) eg. elements with
+ * text element as child.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] elem_type Type of element can be set to YANG_ORGANIZATION or YANG_CONTACT or YANG_DESCRIPTION or YANG_REFERENCE.
+ * @param[out] value Where the content of meta element should be stored.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_meta(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ enum yang_keyword elem_type, const char **value, struct lysp_ext_instance **exts)
+{
+ assert(elem_type == YANG_ORGANIZATION || elem_type == YANG_CONTACT || elem_type == YANG_DESCRIPTION || elem_type == YANG_REFERENCE);
+
+ struct yin_subelement subelems[2] = {
+ {YANG_CUSTOM, NULL, 0},
+ {YIN_TEXT, value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE | YIN_SUBELEM_FIRST}
+ };
+ /* check attributes */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, elem_type));
+
+ /* parse content */
+ return yin_parse_content(ctx, subelems, 2, data, elem_type, NULL, exts);
+}
+
+/**
+ * @brief Parse error-message element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from.
+ * @param[out] value Where the content of error-message element should be stored.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_err_msg(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ const char **value, struct lysp_ext_instance **exts)
+{
+ struct yin_subelement subelems[2] = {
+ {YANG_CUSTOM, NULL, 0},
+ {YIN_VALUE, value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE | YIN_SUBELEM_FIRST}
+ };
+
+ /* check attributes */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, YANG_ERROR_MESSAGE));
+
+ return yin_parse_content(ctx, subelems, 2, data, YANG_ERROR_MESSAGE, NULL, exts);
+}
+
+/**
+ * @brief Parse type element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] parent Identification of parent element.
+ * @param[in,out] type Type to write to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_type(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ enum yang_keyword parent, struct yin_subelement *subinfo)
+{
+ struct lysp_type *type = NULL;
+ if (parent == YANG_DEVIATE) {
+ *(struct lysp_type **)subinfo->dest = calloc(1, sizeof **(struct lysp_type **)subinfo->dest);
+ LY_CHECK_ERR_RET(!(*(struct lysp_type **)subinfo->dest), LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ type = *((struct lysp_type **)subinfo->dest);
+ } else {
+ type = (struct lysp_type *)subinfo->dest;
+ }
+ /* type as child of another type */
+ if (parent == YANG_TYPE) {
+ struct lysp_type *nested_type = NULL;
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->types, nested_type, LY_EMEM);
+ type->flags |= LYS_SET_TYPE;
+ type = nested_type;
+ }
+ struct yin_subelement subelems[11] = {
+ {YANG_BASE, type, 0},
+ {YANG_BIT, type, 0},
+ {YANG_ENUM, type, 0},
+ {YANG_FRACTION_DIGITS, type, YIN_SUBELEM_UNIQUE},
+ {YANG_LENGTH, type, YIN_SUBELEM_UNIQUE},
+ {YANG_PATH, type, YIN_SUBELEM_UNIQUE},
+ {YANG_PATTERN, type, 0},
+ {YANG_RANGE, type, YIN_SUBELEM_UNIQUE},
+ {YANG_REQUIRE_INSTANCE, type, YIN_SUBELEM_UNIQUE},
+ {YANG_TYPE, type},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &type->name, Y_PREF_IDENTIF_ARG, YANG_TYPE));
+ return yin_parse_content(ctx, subelems, 11, data, YANG_TYPE, NULL, &type->exts);
+}
+
+/**
+ * @brief Parse max-elements element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] max Value to write to.
+ * @param[in] flags Flags to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_maxelements(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint32_t *max,
+ uint16_t *flags, struct lysp_ext_instance **exts)
+{
+ const char *temp_val = NULL;
+ char *ptr;
+ unsigned long int num;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0},
+ };
+
+ *flags |= LYS_SET_MAX;
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MAX_ELEMENTS));
+ if (!temp_val || temp_val[0] == '\0' || temp_val[0] == '0' || (temp_val[0] != 'u' && !isdigit(temp_val[0]))) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "max-elements");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+
+ if (strcmp(temp_val, "unbounded")) {
+ errno = 0;
+ num = strtoul(temp_val, &ptr, 10);
+ if (*ptr != '\0') {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "max-elements");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ if ((errno == ERANGE) || (num > UINT32_MAX)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", "max-elements");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ *max = num;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return yin_parse_content(ctx, subelems, 1, data, YANG_MAX_ELEMENTS, NULL, exts);
+}
+
+/**
+ * @brief Parse min-elements element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] min Value to write to.
+ * @param[in] flags Flags to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_minelements(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint32_t *min,
+ uint16_t *flags, struct lysp_ext_instance **exts)
+{
+ const char *temp_val = NULL;
+ char *ptr;
+ unsigned long int num;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0},
+ };
+
+ *flags |= LYS_SET_MIN;
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MIN_ELEMENTS));
+
+ if (!temp_val || temp_val[0] == '\0' || (temp_val[0] == '0' && temp_val[1] != '\0')) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "min-elements");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+
+ errno = 0;
+ num = strtoul(temp_val, &ptr, 10);
+ if (ptr[0] != 0) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "min-elements");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ if (errno == ERANGE || num > UINT32_MAX) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", "min-elements");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ *min = num;
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return yin_parse_content(ctx, subelems, 1, data, YANG_MIN_ELEMENTS, NULL, exts);
+}
+
+/**
+ * @brief Parse min-elements or max-elements element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] parent Identification of parent element.
+ * @param[in] current Identification of current element.
+ * @param[in] dest Where the parsed value and flags should be stored.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_minmax(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ enum yang_keyword parent, enum yang_keyword current, void *dest)
+{
+ assert(current == YANG_MAX_ELEMENTS || current == YANG_MIN_ELEMENTS);
+ assert(parent == YANG_LEAF_LIST || parent == YANG_REFINE || parent == YANG_LIST || parent == YANG_DEVIATE);
+ uint32_t *lim;
+ uint16_t *flags;
+ struct lysp_ext_instance **exts;
+
+ if (parent == YANG_LEAF_LIST) {
+ lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_node_leaflist *)dest)->max : &((struct lysp_node_leaflist *)dest)->min;
+ flags = &((struct lysp_node_leaflist *)dest)->flags;
+ exts = &((struct lysp_node_leaflist *)dest)->exts;
+ } else if (parent == YANG_REFINE) {
+ lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_refine *)dest)->max : &((struct lysp_refine *)dest)->min;
+ flags = &((struct lysp_refine *)dest)->flags;
+ exts = &((struct lysp_refine *)dest)->exts;
+ } else if (parent == YANG_LIST) {
+ lim = (current == YANG_MAX_ELEMENTS) ? &((struct lysp_node_list *)dest)->max : &((struct lysp_node_list *)dest)->min;
+ flags = &((struct lysp_node_list *)dest)->flags;
+ exts = &((struct lysp_node_list *)dest)->exts;
+ } else {
+ lim = ((struct minmax_dev_meta *)dest)->lim;
+ flags = ((struct minmax_dev_meta *)dest)->flags;
+ exts = ((struct minmax_dev_meta *)dest)->exts;
+ }
+
+ if (current == YANG_MAX_ELEMENTS) {
+ LY_CHECK_RET(yin_parse_maxelements(ctx, attrs, data, lim, flags, exts));
+ } else {
+ LY_CHECK_RET(yin_parse_minelements(ctx, attrs, data, lim, flags, exts));
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse ordered-by element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] flags Flags to write to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_orderedby(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ uint16_t *flags, struct lysp_ext_instance **exts)
+{
+ const char *temp_val;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0},
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_ORDERED_BY));
+ if (strcmp(temp_val, "system") == 0) {
+ *flags |= LYS_ORDBY_SYSTEM;
+ } else if (strcmp(temp_val, "user") == 0) {
+ *flags |= LYS_ORDBY_USER;
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+ "ordered-by", "system", "user");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_ORDERED_BY, NULL, exts);
+}
+
+/**
+ * @brief Parse any-data or any-xml element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] any_kw Identification of current element, can be set to YANG_ANY_DATA or YANG_ANY_XML
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_any(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ enum yang_keyword any_kw, struct tree_node_meta *node_meta)
+{
+ struct lysp_node_anydata *any;
+
+ /* create new sibling */
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, any, next);
+ any->nodetype = (any_kw == YANG_ANYDATA) ? LYS_ANYDATA : LYS_ANYXML;
+ any->parent = node_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &any->name, Y_IDENTIF_ARG, any_kw));
+
+ struct yin_subelement subelems[9] = {
+ {YANG_CONFIG, &any->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_DESCRIPTION, &any->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &any->iffeatures, 0},
+ {YANG_MANDATORY, &any->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_MUST, &any->musts, 0},
+ {YANG_REFERENCE, &any->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &any->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_WHEN, &any->when, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 9, data, any_kw, NULL, &any->exts);
+}
+
+/**
+ * @brief parse leaf element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_leaf(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *node_meta)
+{
+ struct lysp_node_leaf *leaf;
+
+ /* create structure new leaf */
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, leaf, next);
+ leaf->nodetype = LYS_LEAF;
+ leaf->parent = node_meta->parent;
+
+ /* parser argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &leaf->name, Y_IDENTIF_ARG, YANG_LEAF));
+
+ /* parse content */
+ struct yin_subelement subelems[12] = {
+ {YANG_CONFIG, &leaf->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_DEFAULT, &leaf->dflt, YIN_SUBELEM_UNIQUE},
+ {YANG_DESCRIPTION, &leaf->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &leaf->iffeatures, 0},
+ {YANG_MANDATORY, &leaf->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_MUST, &leaf->musts, 0},
+ {YANG_REFERENCE, &leaf->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &leaf->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_TYPE, &leaf->type, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_MANDATORY},
+ {YANG_UNITS, &leaf->units, YIN_SUBELEM_UNIQUE},
+ {YANG_WHEN, &leaf->when, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 12, data, YANG_LEAF, NULL, &leaf->exts);
+}
+
+/**
+ * @brief Parse leaf-list element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_leaflist(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *node_meta)
+{
+ struct lysp_node_leaflist *llist;
+
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, llist, next);
+
+ llist->nodetype = LYS_LEAFLIST;
+ llist->parent = node_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &llist->name, Y_IDENTIF_ARG, YANG_LEAF_LIST));
+
+ /* parse content */
+ struct yin_subelement subelems[14] = {
+ {YANG_CONFIG, &llist->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_DEFAULT, &llist->dflts, 0},
+ {YANG_DESCRIPTION, &llist->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &llist->iffeatures, 0},
+ {YANG_MAX_ELEMENTS, llist, YIN_SUBELEM_UNIQUE},
+ {YANG_MIN_ELEMENTS, llist, YIN_SUBELEM_UNIQUE},
+ {YANG_MUST, &llist->musts, 0},
+ {YANG_ORDERED_BY, &llist->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &llist->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &llist->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_TYPE, &llist->type, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_MANDATORY},
+ {YANG_UNITS, &llist->units, YIN_SUBELEM_UNIQUE},
+ {YANG_WHEN, &llist->when, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ LY_CHECK_RET(yin_parse_content(ctx, subelems, 14, data, YANG_LEAF_LIST, NULL, &llist->exts));
+
+ /* check invalid combination of subelements */
+ if ((llist->min) && (llist->dflts)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INCHILDSTMSCOMB_YIN, "min-elements", "default", "leaf-list");
+ return LY_EVALID;
+ }
+ if (llist->max && llist->min > llist->max) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_MINMAX, llist->min, llist->max);
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse typedef element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] typedef_meta Meta information about parent node and typedefs to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_typedef(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *typedef_meta)
+{
+ struct lysp_tpdf *tpdf;
+ struct lysp_tpdf **tpdfs = (struct lysp_tpdf **)typedef_meta->nodes;
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *tpdfs, tpdf, LY_EMEM);
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &tpdf->name, Y_IDENTIF_ARG, YANG_TYPEDEF));
+
+ /* parse content */
+ struct yin_subelement subelems[7] = {
+ {YANG_DEFAULT, &tpdf->dflt, YIN_SUBELEM_UNIQUE},
+ {YANG_DESCRIPTION, &tpdf->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &tpdf->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &tpdf->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_TYPE, &tpdf->type, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_MANDATORY},
+ {YANG_UNITS, &tpdf->units, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ LY_CHECK_RET(yin_parse_content(ctx, subelems, 7, data, YANG_TYPEDEF, NULL, &tpdf->exts));
+
+ /* store data for collision check */
+ if (typedef_meta->parent && !(typedef_meta->parent->nodetype & (LYS_GROUPING | LYS_ACTION | LYS_INOUT | LYS_NOTIF))) {
+ LY_CHECK_RET(ly_set_add(&ctx->tpdfs_nodes, typedef_meta->parent, 0) == -1, LY_EMEM);
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse refine element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] refines Refines to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_refine(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_refine **refines)
+{
+ struct lysp_refine *rf;
+
+ /* allocate new refine */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *refines, rf, LY_EMEM);
+
+ /* parse attribute */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &rf->nodeid, Y_STR_ARG, YANG_REFINE));
+ YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(rf->nodeid), "refine");
+
+ /* parse content */
+ struct yin_subelement subelems[11] = {
+ {YANG_CONFIG, &rf->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_DEFAULT, &rf->dflts, 0},
+ {YANG_DESCRIPTION, &rf->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &rf->iffeatures, 0},
+ {YANG_MANDATORY, &rf->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_MAX_ELEMENTS, rf, YIN_SUBELEM_UNIQUE},
+ {YANG_MIN_ELEMENTS, rf, YIN_SUBELEM_UNIQUE},
+ {YANG_MUST, &rf->musts, 0},
+ {YANG_PRESENCE, &rf->presence, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &rf->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 11, data, YANG_REFINE, NULL, &rf->exts);
+}
+
+/**
+ * @brief Parse uses element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_uses(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *node_meta)
+{
+ struct lysp_node_uses *uses;
+
+ /* create new uses */
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, uses, next);
+ uses->nodetype = LYS_USES;
+ uses->parent = node_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &uses->name, Y_PREF_IDENTIF_ARG, YANG_USES));
+
+ /* parse content */
+ struct tree_node_meta augments = {(struct lysp_node *)uses, (struct lysp_node **)&uses->augments};
+ struct yin_subelement subelems[8] = {
+ {YANG_AUGMENT, &augments, 0},
+ {YANG_DESCRIPTION, &uses->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &uses->iffeatures, 0},
+ {YANG_REFERENCE, &uses->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_REFINE, &uses->refines, 0},
+ {YANG_STATUS, &uses->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_WHEN, &uses->when, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ LY_CHECK_RET(yin_parse_content(ctx, subelems, 8, data, YANG_USES, NULL, &uses->exts));
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, NULL, uses->augments, NULL, NULL));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse revision element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] revs Parsed revisions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_revision(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_revision **revs)
+{
+ struct lysp_revision *rev;
+ const char *temp_date = NULL;
+
+ /* allocate new reivison */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *revs, rev, LY_EMEM);
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, &temp_date, Y_STR_ARG, YANG_REVISION));
+ /* check value */
+ if (lysp_check_date((struct lys_parser_ctx *)ctx, temp_date, strlen(temp_date), "revision")) {
+ FREE_STRING(ctx->xml_ctx.ctx, temp_date);
+ return LY_EVALID;
+ }
+ strcpy(rev->date, temp_date);
+ FREE_STRING(ctx->xml_ctx.ctx, temp_date);
+
+ /* parse content */
+ struct yin_subelement subelems[3] = {
+ {YANG_DESCRIPTION, &rev->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &rev->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 3, data, YANG_REVISION, NULL, &rev->exts);
+}
+
+/**
+ * @brief Parse include element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] inc_meta Meta informatinou about module/submodule name and includes to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_include(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct include_meta *inc_meta)
+{
+ struct lysp_include *inc;
+
+ /* allocate new include */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *inc_meta->includes, inc, LY_EMEM);
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &inc->name, Y_IDENTIF_ARG, YANG_INCLUDE));
+
+ /* submodules share the namespace with the module names, so there must not be
+ * a module of the same name in the context, no need for revision matching */
+ if (!strcmp(inc_meta->name, inc->name) || ly_ctx_get_module_latest(ctx->xml_ctx.ctx, inc->name)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_NAME_COL, inc->name);
+ return LY_EVALID;
+ }
+
+ /* parse content */
+ struct yin_subelement subelems[4] = {
+ {YANG_DESCRIPTION, &inc->dsc, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_VER2},
+ {YANG_REFERENCE, &inc->ref, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_VER2},
+ {YANG_REVISION_DATE, &inc->rev, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 4, data, YANG_INCLUDE, NULL, &inc->exts);
+}
+
+/**
+ * @brief Parse revision-date element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of revision-date element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] rev Array to store the parsed value in.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_revision_date(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, char *rev,
+ struct lysp_ext_instance **exts)
+{
+ const char *temp_rev;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_DATE, &temp_rev, Y_STR_ARG, YANG_REVISION_DATE));
+ LY_CHECK_ERR_RET(lysp_check_date((struct lys_parser_ctx *)ctx, temp_rev, strlen(temp_rev), "revision-date") != LY_SUCCESS,
+ FREE_STRING(ctx->xml_ctx.ctx, temp_rev), LY_EVALID);
+
+ strcpy(rev, temp_rev);
+ FREE_STRING(ctx->xml_ctx.ctx, temp_rev);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_REVISION_DATE, NULL, exts);
+}
+
+/**
+ * @brief Parse config element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of import element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] flags Flags to add to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_config(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint16_t *flags,
+ struct lysp_ext_instance **exts)
+{
+ const char *temp_val = NULL;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_CONFIG));
+ if (strcmp(temp_val, "true") == 0) {
+ *flags |= LYS_CONFIG_W;
+ } else if (strcmp(temp_val, "false") == 0) {
+ *flags |= LYS_CONFIG_R;
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value", "config",
+ "true", "false");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_CONFIG, NULL, exts);
+}
+
+/**
+ * @brief Parse yang-version element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of yang-version element.
+ * @param[in] data Data to read from, always moved to currently handled character.
+ * @param[out] version Storage for the parsed information.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_yangversion(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint8_t *version,
+ struct lysp_ext_instance **exts)
+{
+ const char *temp_version = NULL;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_version, Y_STR_ARG, YANG_YANG_VERSION));
+ if (strcmp(temp_version, "1.0") == 0) {
+ *version = LYS_VERSION_1_0;
+ } else if (strcmp(temp_version, "1.1") == 0) {
+ *version = LYS_VERSION_1_1;
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_version, "value",
+ "yang-version", "1.0", "1.1");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_version);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_version);
+ ctx->mod_version = *version;
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_YANG_VERSION, NULL, exts);
+}
+
+/**
+ * @brief Parse import element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of import element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] imp_meta Meta information about prefix and imports to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_import(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct import_meta *imp_meta)
+{
+ struct lysp_import *imp;
+ /* allocate new element in sized array for import */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *imp_meta->imports, imp, LY_EMEM);
+
+ struct yin_subelement subelems[5] = {
+ {YANG_DESCRIPTION, &imp->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_PREFIX, &imp->prefix, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &imp->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_REVISION_DATE, imp->rev, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ /* parse import attributes */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &imp->name, Y_IDENTIF_ARG, YANG_IMPORT));
+ LY_CHECK_RET(yin_parse_content(ctx, subelems, 5, data, YANG_IMPORT, NULL, &imp->exts));
+ /* check prefix validity */
+ LY_CHECK_RET(lysp_check_prefix((struct lys_parser_ctx *)ctx, *imp_meta->imports, imp_meta->prefix, &imp->prefix), LY_EVALID);
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse mandatory element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of status element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] flags Flags to add to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_mandatory(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint16_t *flags,
+ struct lysp_ext_instance **exts)
+{
+ const char *temp_val = NULL;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_MANDATORY));
+ if (strcmp(temp_val, "true") == 0) {
+ *flags |= LYS_MAND_TRUE;
+ } else if (strcmp(temp_val, "false") == 0) {
+ *flags |= LYS_MAND_FALSE;
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+ "mandatory", "true", "false");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_MANDATORY, NULL, exts);
+}
+
+/**
+ * @brief Parse status element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of status element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] flags Flags to add to.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_status(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, uint16_t *flags,
+ struct lysp_ext_instance **exts)
+{
+ const char *value = NULL;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &value, Y_STR_ARG, YANG_STATUS));
+ if (strcmp(value, "current") == 0) {
+ *flags |= LYS_STATUS_CURR;
+ } else if (strcmp(value, "deprecated") == 0) {
+ *flags |= LYS_STATUS_DEPRC;
+ } else if (strcmp(value, "obsolete") == 0) {
+ *flags |= LYS_STATUS_OBSLT;
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS3, value, "value",
+ "status", "current", "deprecated", "obsolete");
+ FREE_STRING(ctx->xml_ctx.ctx, value);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, value);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_STATUS, NULL, exts);
+}
+
+/**
+ * @brief Parse when element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of when element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] when_p When pointer to parse to.
+ */
+static LY_ERR
+yin_parse_when(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_when **when_p)
+{
+ struct lysp_when *when;
+ LY_ERR ret = LY_SUCCESS;
+
+ when = calloc(1, sizeof *when);
+ LY_CHECK_ERR_RET(!when, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ ret = yin_parse_attribute(ctx, attrs, YIN_ARG_CONDITION, &when->cond, Y_STR_ARG, YANG_WHEN);
+ LY_CHECK_ERR_RET(ret, free(when), ret);
+
+ *when_p = when;
+ struct yin_subelement subelems[3] = {
+ {YANG_DESCRIPTION, &when->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &when->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ return yin_parse_content(ctx, subelems, 3, data, YANG_WHEN, NULL, &when->exts);
+}
+
+/**
+ * @brief Parse yin-elemenet element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of yin-element element.
+ * @param[in,out] data Data to read from, always moved to currently handled position.
+ * @param[in,out] flags Flags to add to.
+ * @prama[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_yin_element(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ uint16_t *flags, struct lysp_ext_instance **exts)
+{
+ const char *temp_val = NULL;
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_YIN_ELEMENT));
+ if (strcmp(temp_val, "true") == 0) {
+ *flags |= LYS_YINELEM_TRUE;
+ } else if (strcmp(temp_val, "false") == 0) {
+ *flags |= LYS_YINELEM_FALSE;
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS2, temp_val, "value",
+ "yin-element", "true", "false");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+ return yin_parse_content(ctx, subelems, 1, data, YANG_YIN_ELEMENT, NULL, exts);
+}
+
+/**
+ * @brief Parse argument element.
+ *
+ * @param[in,out] xml_ctx Xml context.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of argument element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] arg_meta Meta information about destionation of parsed data.
+ * @param[in,out] exts Extension instances to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_argument(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct yin_argument_meta *arg_meta, struct lysp_ext_instance **exts)
+{
+ struct yin_subelement subelems[2] = {
+ {YANG_YIN_ELEMENT, arg_meta->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, arg_meta->argument, Y_IDENTIF_ARG, YANG_ARGUMENT));
+
+ return yin_parse_content(ctx, subelems, 2, data, YANG_ARGUMENT, NULL, exts);
+}
+
+/**
+ * @brief Parse the extension statement.
+ *
+ * @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 element.
+ * @param[in,out] data Data to read from.
+ * @param[in,out] extensions Extensions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_extension(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_ext **extensions)
+{
+ struct lysp_ext *ex;
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *extensions, ex, LY_EMEM);
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &ex->name, Y_IDENTIF_ARG, YANG_EXTENSION));
+
+ struct yin_argument_meta arg_info = {&ex->flags, &ex->argument};
+ struct yin_subelement subelems[5] = {
+ {YANG_ARGUMENT, &arg_info, YIN_SUBELEM_UNIQUE},
+ {YANG_DESCRIPTION, &ex->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_REFERENCE, &ex->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &ex->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+
+ return yin_parse_content(ctx, subelems, 5, data, YANG_EXTENSION, NULL, &ex->exts);
+}
+
+/**
+ * @brief Parse feature element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] features Features to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_feature(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_feature **features)
+{
+ struct lysp_feature *feat;
+
+ /* allocate new feature */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *features, feat, LY_EMEM);
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &feat->name, Y_IDENTIF_ARG, YANG_FEATURE));
+
+ /* parse content */
+ struct yin_subelement subelems[5] = {
+ {YANG_DESCRIPTION, &feat->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &feat->iffeatures, 0},
+ {YANG_REFERENCE, &feat->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &feat->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 5, data, YANG_FEATURE, NULL, &feat->exts);
+}
+
+/**
+ * @brief Parse identity element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] identities Identities to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_identity(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_ident **identities)
+{
+ struct lysp_ident *ident;
+
+ /* allocate new identity */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *identities, ident, LY_EMEM);
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &ident->name, Y_IDENTIF_ARG, YANG_IDENTITY));
+
+ /* parse content */
+ struct yin_subelement subelems[6] = {
+ {YANG_BASE, &ident->bases, 0},
+ {YANG_DESCRIPTION, &ident->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_IF_FEATURE, &ident->iffeatures, YIN_SUBELEM_VER2},
+ {YANG_REFERENCE, &ident->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_STATUS, &ident->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 6, data, YANG_IDENTITY, NULL, &ident->exts);
+}
+
+/**
+ * @brief Parse list element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_list(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *node_meta)
+{
+ struct lysp_node_list *list;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, list, next);
+ list->nodetype = LYS_LIST;
+ list->parent = node_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &list->name, Y_IDENTIF_ARG, YANG_LIST));
+
+ /* parse list content */
+ LY_CHECK_RET(subelems_allocator(ctx, 25, (struct lysp_node *)list, &subelems,
+ YANG_ACTION, &list->actions, 0,
+ YANG_ANYDATA, &list->child, 0,
+ YANG_ANYXML, &list->child, 0,
+ YANG_CHOICE, &list->child, 0,
+ YANG_CONFIG, &list->flags, YIN_SUBELEM_UNIQUE,
+ YANG_CONTAINER, &list->child, 0,
+ YANG_DESCRIPTION, &list->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_GROUPING, &list->groupings, 0,
+ YANG_IF_FEATURE, &list->iffeatures, 0,
+ YANG_KEY, &list->key, YIN_SUBELEM_UNIQUE,
+ YANG_LEAF, &list->child, 0,
+ YANG_LEAF_LIST, &list->child, 0,
+ YANG_LIST, &list->child, 0,
+ YANG_MAX_ELEMENTS, list, YIN_SUBELEM_UNIQUE,
+ YANG_MIN_ELEMENTS, list, YIN_SUBELEM_UNIQUE,
+ YANG_MUST, &list->musts, 0,
+ YANG_NOTIFICATION, &list->notifs, 0,
+ YANG_ORDERED_BY, &list->flags, YIN_SUBELEM_UNIQUE,
+ YANG_REFERENCE, &list->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, &list->flags, YIN_SUBELEM_UNIQUE,
+ YANG_TYPEDEF, &list->typedefs, 0,
+ YANG_UNIQUE, &list->uniques, 0,
+ YANG_USES, &list->child, 0,
+ YANG_WHEN, &list->when, YIN_SUBELEM_UNIQUE,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = yin_parse_content(ctx, subelems, 25, data, YANG_LIST, NULL, &list->exts);
+ subelems_deallocator(25, subelems);
+ LY_CHECK_RET(ret);
+
+ /* finalize parent pointers to the reallocated items */
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, list->groupings, NULL, list->actions, list->notifs));
+
+ if (list->max && list->min > list->max) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_MINMAX, list->min, list->max);
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse notification element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] notif_meta Meta information about parent node and notifications to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_notification(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *notif_meta)
+{
+ struct lysp_notif *notif;
+ struct lysp_notif **notifs = (struct lysp_notif **)notif_meta->nodes;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ /* allocate new notification */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *notifs, notif, LY_EMEM);
+ notif->nodetype = LYS_NOTIF;
+ notif->parent = notif_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, ¬if->name, Y_IDENTIF_ARG, YANG_NOTIFICATION));
+
+ /* parse notification content */
+ LY_CHECK_RET(subelems_allocator(ctx, 16, (struct lysp_node *)notif, &subelems,
+ YANG_ANYDATA, ¬if->data, 0,
+ YANG_ANYXML, ¬if->data, 0,
+ YANG_CHOICE, ¬if->data, 0,
+ YANG_CONTAINER, ¬if->data, 0,
+ YANG_DESCRIPTION, ¬if->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_GROUPING, ¬if->groupings, 0,
+ YANG_IF_FEATURE, ¬if->iffeatures, 0,
+ YANG_LEAF, ¬if->data, 0,
+ YANG_LEAF_LIST, ¬if->data, 0,
+ YANG_LIST, ¬if->data, 0,
+ YANG_MUST, ¬if->musts, YIN_SUBELEM_VER2,
+ YANG_REFERENCE, ¬if->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, ¬if->flags, YIN_SUBELEM_UNIQUE,
+ YANG_TYPEDEF, ¬if->typedefs, 0,
+ YANG_USES, ¬if->data, 0,
+ YANG_CUSTOM, NULL, 0
+ ));
+
+ ret = yin_parse_content(ctx, subelems, 16, data, YANG_NOTIFICATION, NULL, ¬if->exts);
+ subelems_deallocator(16, subelems);
+ LY_CHECK_RET(ret);
+
+ /* finalize parent pointers to the reallocated items */
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, notif->groupings, NULL, NULL, NULL));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse grouping element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in,out] gr_meta Meta information about parent node and groupings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_grouping(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *gr_meta)
+{
+ struct lysp_grp *grp;
+ struct lysp_grp **grps = (struct lysp_grp **)gr_meta->nodes;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ /* create new grouping */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *grps, grp, LY_EMEM);
+ grp->nodetype = LYS_GROUPING;
+ grp->parent = gr_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &grp->name, Y_IDENTIF_ARG, YANG_GROUPING));
+
+ /* parse grouping content */
+ LY_CHECK_RET(subelems_allocator(ctx, 16, (struct lysp_node *)grp, &subelems,
+ YANG_ACTION, &grp->actions, 0,
+ YANG_ANYDATA, &grp->data, 0,
+ YANG_ANYXML, &grp->data, 0,
+ YANG_CHOICE, &grp->data, 0,
+ YANG_CONTAINER, &grp->data, 0,
+ YANG_DESCRIPTION, &grp->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_GROUPING, &grp->groupings, 0,
+ YANG_LEAF, &grp->data, 0,
+ YANG_LEAF_LIST, &grp->data, 0,
+ YANG_LIST, &grp->data, 0,
+ YANG_NOTIFICATION, &grp->notifs, 0,
+ YANG_REFERENCE, &grp->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, &grp->flags, YIN_SUBELEM_UNIQUE,
+ YANG_TYPEDEF, &grp->typedefs, 0,
+ YANG_USES, &grp->data, 0,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = yin_parse_content(ctx, subelems, 16, data, YANG_GROUPING, NULL, &grp->exts);
+ subelems_deallocator(16, subelems);
+ LY_CHECK_RET(ret);
+
+ /* finalize parent pointers to the reallocated items */
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, grp->groupings, NULL, grp->actions, grp->notifs));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse container element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_container(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *node_meta)
+{
+ struct lysp_node_container *cont;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ /* create new container */
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, cont, next);
+ cont->nodetype = LYS_CONTAINER;
+ cont->parent = node_meta->parent;
+
+ /* parse aegument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &cont->name, Y_IDENTIF_ARG, YANG_CONTAINER));
+
+ /* parse container content */
+ LY_CHECK_RET(subelems_allocator(ctx, 21, (struct lysp_node *)cont, &subelems,
+ YANG_ACTION, &cont->actions, YIN_SUBELEM_VER2,
+ YANG_ANYDATA, &cont->child, YIN_SUBELEM_VER2,
+ YANG_ANYXML, &cont->child, 0,
+ YANG_CHOICE, &cont->child, 0,
+ YANG_CONFIG, &cont->flags, YIN_SUBELEM_UNIQUE,
+ YANG_CONTAINER, &cont->child, 0,
+ YANG_DESCRIPTION, &cont->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_GROUPING, &cont->groupings, 0,
+ YANG_IF_FEATURE, &cont->iffeatures, 0,
+ YANG_LEAF, &cont->child, 0,
+ YANG_LEAF_LIST, &cont->child, 0,
+ YANG_LIST, &cont->child, 0,
+ YANG_MUST, &cont->musts, 0,
+ YANG_NOTIFICATION, &cont->notifs, YIN_SUBELEM_VER2,
+ YANG_PRESENCE, &cont->presence, YIN_SUBELEM_UNIQUE,
+ YANG_REFERENCE, &cont->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, &cont->flags, YIN_SUBELEM_UNIQUE,
+ YANG_TYPEDEF, &cont->typedefs, 0,
+ YANG_USES, &cont->child, 0,
+ YANG_WHEN, &cont->when, YIN_SUBELEM_UNIQUE,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = yin_parse_content(ctx, subelems, 21, data, YANG_CONTAINER, NULL, &cont->exts);
+ subelems_deallocator(21, subelems);
+ LY_CHECK_RET(ret);
+
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, cont->groupings, NULL, cont->actions, cont->notifs));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse case element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_case(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *node_meta)
+{
+ struct lysp_node_case *cas;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;;
+
+ /* create new case */
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, cas, next);
+ cas->nodetype = LYS_CASE;
+ cas->parent = node_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &cas->name, Y_IDENTIF_ARG, YANG_CASE));
+
+ /* parse case content */
+ LY_CHECK_RET(subelems_allocator(ctx, 14, (struct lysp_node *)cas, &subelems,
+ YANG_ANYDATA, &cas->child, YIN_SUBELEM_VER2,
+ YANG_ANYXML, &cas->child, 0,
+ YANG_CHOICE, &cas->child, 0,
+ YANG_CONTAINER, &cas->child, 0,
+ YANG_DESCRIPTION, &cas->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_IF_FEATURE, &cas->iffeatures, 0,
+ YANG_LEAF, &cas->child, 0,
+ YANG_LEAF_LIST, &cas->child, 0,
+ YANG_LIST, &cas->child, 0,
+ YANG_REFERENCE, &cas->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, &cas->flags, YIN_SUBELEM_UNIQUE,
+ YANG_USES, &cas->child, 0,
+ YANG_WHEN, &cas->when, YIN_SUBELEM_UNIQUE,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = yin_parse_content(ctx, subelems, 14, data, YANG_CASE, NULL, &cas->exts);
+ subelems_deallocator(14, subelems);
+
+ return ret;
+}
+
+/**
+ * @brief Parse choice element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] node_meta Meta information about parent node and siblings to add to.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR
+yin_parse_choice(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *node_meta)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+ struct lysp_node_choice *choice;
+
+ /* create new choice */
+ LY_LIST_NEW_RET(ctx->xml_ctx.ctx, node_meta->nodes, choice, next);
+
+ choice->nodetype = LYS_CHOICE;
+ choice->parent = node_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &choice->name, Y_IDENTIF_ARG, YANG_CHOICE));
+
+ /* parse choice content */
+ LY_CHECK_RET(subelems_allocator(ctx, 17, (struct lysp_node *)choice, &subelems,
+ YANG_ANYDATA, &choice->child, YIN_SUBELEM_VER2,
+ YANG_ANYXML, &choice->child, 0,
+ YANG_CASE, &choice->child, 0,
+ YANG_CHOICE, &choice->child, YIN_SUBELEM_VER2,
+ YANG_CONFIG, &choice->flags, YIN_SUBELEM_UNIQUE,
+ YANG_CONTAINER, &choice->child, 0,
+ YANG_DEFAULT, &choice->dflt, YIN_SUBELEM_UNIQUE,
+ YANG_DESCRIPTION, &choice->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_IF_FEATURE, &choice->iffeatures, 0,
+ YANG_LEAF, &choice->child, 0,
+ YANG_LEAF_LIST, &choice->child, 0,
+ YANG_LIST, &choice->child, 0,
+ YANG_MANDATORY, &choice->flags, YIN_SUBELEM_UNIQUE,
+ YANG_REFERENCE, &choice->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, &choice->flags, YIN_SUBELEM_UNIQUE,
+ YANG_WHEN, &choice->when, YIN_SUBELEM_UNIQUE,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = yin_parse_content(ctx, subelems, 17, data, YANG_CHOICE, NULL, &choice->exts);
+ subelems_deallocator(17, subelems);
+ return ret;
+}
+
+/**
+ * @brief Parse input or output element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] inout_kw Identification of input/output element.
+ * @param[in] inout_meta Meta information about parent node and siblings and input/output pointer to write to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_inout(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, enum yang_keyword inout_kw,
+ struct inout_meta *inout_meta)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ /* initiate structure */
+ inout_meta->inout_p->nodetype = (inout_kw == YANG_INPUT) ? LYS_INPUT : LYS_OUTPUT;
+ inout_meta->inout_p->parent = inout_meta->parent;
+
+ /* check attributes */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, inout_kw));
+
+ /* parser input/output content */
+ LY_CHECK_RET(subelems_allocator(ctx, 12, (struct lysp_node *)inout_meta->inout_p, &subelems,
+ YANG_ANYDATA, &inout_meta->inout_p->data, YIN_SUBELEM_VER2,
+ YANG_ANYXML, &inout_meta->inout_p->data, 0,
+ YANG_CHOICE, &inout_meta->inout_p->data, 0,
+ YANG_CONTAINER, &inout_meta->inout_p->data, 0,
+ YANG_GROUPING, &inout_meta->inout_p->groupings, 0,
+ YANG_LEAF, &inout_meta->inout_p->data, 0,
+ YANG_LEAF_LIST, &inout_meta->inout_p->data, 0,
+ YANG_LIST, &inout_meta->inout_p->data, 0,
+ YANG_MUST, &inout_meta->inout_p->musts, YIN_SUBELEM_VER2,
+ YANG_TYPEDEF, &inout_meta->inout_p->typedefs, 0,
+ YANG_USES, &inout_meta->inout_p->data, 0,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = yin_parse_content(ctx, subelems, 12, data, inout_kw, NULL, &inout_meta->inout_p->exts);
+ subelems_deallocator(12, subelems);
+ LY_CHECK_RET(ret);
+
+ /* finalize parent pointers to the reallocated items */
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, inout_meta->inout_p->groupings, NULL, NULL, NULL));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse action element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] act_meta Meta information about parent node and actions to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_action(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *act_meta)
+{
+ struct lysp_action *act, **acts = (struct lysp_action **)act_meta->nodes;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ /* create new action */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *acts, act, LY_EMEM);
+ act->nodetype = LYS_ACTION;
+ act->parent = act_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &act->name, Y_IDENTIF_ARG, YANG_ACTION));
+
+ /* parse content */
+ LY_CHECK_RET(subelems_allocator(ctx, 9, (struct lysp_node *)act, &subelems,
+ YANG_DESCRIPTION, &act->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_GROUPING, &act->groupings, 0,
+ YANG_IF_FEATURE, &act->iffeatures, 0,
+ YANG_INPUT, &act->input, YIN_SUBELEM_UNIQUE,
+ YANG_OUTPUT, &act->output, YIN_SUBELEM_UNIQUE,
+ YANG_REFERENCE, &act->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, &act->flags, YIN_SUBELEM_UNIQUE,
+ YANG_TYPEDEF, &act->typedefs, 0,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = (yin_parse_content(ctx, subelems, 9, data, YANG_ACTION, NULL, &act->exts));
+ subelems_deallocator(9, subelems);
+ LY_CHECK_RET(ret);
+
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, act->groupings, NULL, NULL, NULL));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse augment element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] aug_meta Meta information about parent node and augments to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_augment(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct tree_node_meta *aug_meta)
+{
+ struct lysp_augment *aug;
+ struct lysp_augment **augs = (struct lysp_augment **)aug_meta->nodes;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ /* create new augment */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *augs, aug, LY_EMEM);
+ aug->nodetype = LYS_AUGMENT;
+ aug->parent = aug_meta->parent;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &aug->nodeid, Y_STR_ARG, YANG_AUGMENT));
+ YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(aug->nodeid), "augment");
+
+ /* parser augment content */
+ LY_CHECK_RET(subelems_allocator(ctx, 17, (struct lysp_node *)aug, &subelems,
+ YANG_ACTION, &aug->actions, YIN_SUBELEM_VER2,
+ YANG_ANYDATA, &aug->child, YIN_SUBELEM_VER2,
+ YANG_ANYXML, &aug->child, 0,
+ YANG_CASE, &aug->child, 0,
+ YANG_CHOICE, &aug->child, 0,
+ YANG_CONTAINER, &aug->child, 0,
+ YANG_DESCRIPTION, &aug->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_IF_FEATURE, &aug->iffeatures, 0,
+ YANG_LEAF, &aug->child, 0,
+ YANG_LEAF_LIST, &aug->child, 0,
+ YANG_LIST, &aug->child, 0,
+ YANG_NOTIFICATION, &aug->notifs, YIN_SUBELEM_VER2,
+ YANG_REFERENCE, &aug->ref, YIN_SUBELEM_UNIQUE,
+ YANG_STATUS, &aug->flags, YIN_SUBELEM_UNIQUE,
+ YANG_USES, &aug->child, 0,
+ YANG_WHEN, &aug->when, YIN_SUBELEM_UNIQUE,
+ YANG_CUSTOM, NULL, 0
+ ));
+ ret = yin_parse_content(ctx, subelems, 17, data, YANG_AUGMENT, NULL, &aug->exts);
+ subelems_deallocator(17, subelems);
+ LY_CHECK_RET(ret);
+
+ LY_CHECK_RET(lysp_parse_finalize_reallocated((struct lys_parser_ctx *)ctx, NULL, NULL, aug->actions, aug->notifs));
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse deviate element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] deviates Deviates to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_deviate(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_deviate **deviates)
+{
+ LY_ERR ret = LY_SUCCESS;
+ uint8_t dev_mod;
+ const char *temp_val;
+ struct lysp_deviate *d;
+ struct lysp_deviate_add *d_add = NULL;
+ struct lysp_deviate_rpl *d_rpl = NULL;
+ struct lysp_deviate_del *d_del = NULL;
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, YANG_DEVIATE));
+
+ if (strcmp(temp_val, "not-supported") == 0) {
+ dev_mod = LYS_DEV_NOT_SUPPORTED;
+ } else if (strcmp(temp_val, "add") == 0) {
+ dev_mod = LYS_DEV_ADD;
+ } else if (strcmp(temp_val, "replace") == 0) {
+ dev_mod = LYS_DEV_REPLACE;
+ } else if (strcmp(temp_val, "delete") == 0) {
+ dev_mod = LYS_DEV_DELETE;
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN VALID_VALS4, temp_val, "value", "deviate",
+ "not-supported", "add", "replace", "delete");
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+ return LY_EVALID;
+ }
+ FREE_STRING(ctx->xml_ctx.ctx, temp_val);
+
+ if (dev_mod == LYS_DEV_NOT_SUPPORTED) {
+ d = calloc(1, sizeof *d);
+ LY_CHECK_ERR_RET(!d, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ struct yin_subelement subelems[1] = {
+ {YANG_CUSTOM, NULL, 0}
+ };
+ ret = yin_parse_content(ctx, subelems, 1, data, YANG_DEVIATE, NULL, &d->exts);
+
+ } else if (dev_mod == LYS_DEV_ADD) {
+ d_add = calloc(1, sizeof *d_add);
+ LY_CHECK_ERR_RET(!d_add, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ d = (struct lysp_deviate *)d_add;
+ struct minmax_dev_meta min = {&d_add->min, &d_add->flags, &d_add->exts};
+ struct minmax_dev_meta max = {&d_add->max, &d_add->flags, &d_add->exts};
+ struct yin_subelement subelems[9] = {
+ {YANG_CONFIG, &d_add->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_DEFAULT, &d_add->dflts, 0},
+ {YANG_MANDATORY, &d_add->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_MAX_ELEMENTS, &max, YIN_SUBELEM_UNIQUE},
+ {YANG_MIN_ELEMENTS, &min, YIN_SUBELEM_UNIQUE},
+ {YANG_MUST, &d_add->musts, 0},
+ {YANG_UNIQUE, &d_add->uniques, 0},
+ {YANG_UNITS, &d_add->units, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ ret = yin_parse_content(ctx, subelems, 9, data, YANG_DEVIATE, NULL, &d_add->exts);
+
+ } else if (dev_mod == LYS_DEV_REPLACE) {
+ d_rpl = calloc(1, sizeof *d_rpl);
+ LY_CHECK_ERR_RET(!d_rpl, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ d = (struct lysp_deviate *)d_rpl;
+ struct minmax_dev_meta min = {&d_rpl->min, &d_rpl->flags, &d_rpl->exts};
+ struct minmax_dev_meta max = {&d_rpl->max, &d_rpl->flags, &d_rpl->exts};
+ struct yin_subelement subelems[8] = {
+ {YANG_CONFIG, &d_rpl->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_DEFAULT, &d_rpl->dflt, YIN_SUBELEM_UNIQUE},
+ {YANG_MANDATORY, &d_rpl->flags, YIN_SUBELEM_UNIQUE},
+ {YANG_MAX_ELEMENTS, &max, YIN_SUBELEM_UNIQUE},
+ {YANG_MIN_ELEMENTS, &min, YIN_SUBELEM_UNIQUE},
+ {YANG_TYPE, &d_rpl->type, YIN_SUBELEM_UNIQUE},
+ {YANG_UNITS, &d_rpl->units, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ ret = yin_parse_content(ctx, subelems, 8, data, YANG_DEVIATE, NULL, &d_rpl->exts);
+
+ } else {
+ d_del = calloc(1, sizeof *d_del);
+ LY_CHECK_ERR_RET(!d_del, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ d = (struct lysp_deviate *)d_del;
+ struct yin_subelement subelems[5] = {
+ {YANG_DEFAULT, &d_del->dflts, 0},
+ {YANG_MUST, &d_del->musts, 0},
+ {YANG_UNIQUE, &d_del->uniques, 0},
+ {YANG_UNITS, &d_del->units, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ ret = yin_parse_content(ctx, subelems, 5, data, YANG_DEVIATE, NULL, &d_del->exts);
+ }
+ LY_CHECK_GOTO(ret, cleanup);
+
+ d->mod = dev_mod;
+ /* insert into siblings */
+ LY_LIST_INSERT(deviates, d, next);
+
+ return ret;
+
+cleanup:
+ free(d);
+ return ret;
+}
+
+/**
+ * @brief Parse deviation element.
+ *
+ * @param[in,out] ctx YIN parser context for logging and to store current state.
+ * @param[in] attrs [Sized array](@ref sizedarrays) of attributes of current element.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] deviations Deviations to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_deviation(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_deviation **deviations)
+{
+ struct lysp_deviation *dev;
+
+ /* create new deviation */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *deviations, dev, LY_EMEM);
+
+ /* parse argument */
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_TARGET_NODE, &dev->nodeid, Y_STR_ARG, YANG_DEVIATION));
+ YANG_CHECK_NONEMPTY((struct lys_parser_ctx *)ctx, strlen(dev->nodeid), "deviation");
+ struct yin_subelement subelems[4] = {
+ {YANG_DESCRIPTION, &dev->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_DEVIATE, &dev->deviates, YIN_SUBELEM_MANDATORY},
+ {YANG_REFERENCE, &dev->ref, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0},
+ };
+ return yin_parse_content(ctx, subelems, 4, data, YANG_DEVIATION, NULL, &dev->exts);
+}
+
+/**
+ * @brief Map keyword type to substatement info.
+ *
+ * @param[in] kw Keyword type.
+ *
+ * @return correct LYEXT_SUBSTMT information.
+ */
+static LYEXT_SUBSTMT
+kw2lyext_substmt(enum yang_keyword kw)
+{
+ switch (kw) {
+ case YANG_ARGUMENT:
+ return LYEXT_SUBSTMT_ARGUMENT;
+ case YANG_BASE:
+ return LYEXT_SUBSTMT_BASE;
+ case YANG_BELONGS_TO:
+ return LYEXT_SUBSTMT_BELONGSTO;
+ case YANG_CONTACT:
+ return LYEXT_SUBSTMT_CONTACT;
+ case YANG_DEFAULT:
+ return LYEXT_SUBSTMT_DEFAULT;
+ case YANG_DESCRIPTION:
+ return LYEXT_SUBSTMT_DESCRIPTION;
+ case YANG_ERROR_APP_TAG:
+ return LYEXT_SUBSTMT_ERRTAG;
+ case YANG_ERROR_MESSAGE:
+ return LYEXT_SUBSTMT_ERRMSG;
+ case YANG_KEY:
+ return LYEXT_SUBSTMT_KEY;
+ case YANG_NAMESPACE:
+ return LYEXT_SUBSTMT_NAMESPACE;
+ case YANG_ORGANIZATION:
+ return LYEXT_SUBSTMT_ORGANIZATION;
+ case YANG_PATH:
+ return LYEXT_SUBSTMT_PATH;
+ case YANG_PREFIX:
+ return LYEXT_SUBSTMT_PREFIX;
+ case YANG_PRESENCE:
+ return LYEXT_SUBSTMT_PRESENCE;
+ case YANG_REFERENCE:
+ return LYEXT_SUBSTMT_REFERENCE;
+ case YANG_REVISION_DATE:
+ return LYEXT_SUBSTMT_REVISIONDATE;
+ case YANG_UNITS:
+ return LYEXT_SUBSTMT_UNITS;
+ case YANG_VALUE:
+ return LYEXT_SUBSTMT_VALUE;
+ case YANG_YANG_VERSION:
+ return LYEXT_SUBSTMT_VERSION;
+ case YANG_MODIFIER:
+ return LYEXT_SUBSTMT_MODIFIER;
+ case YANG_REQUIRE_INSTANCE:
+ return LYEXT_SUBSTMT_REQINSTANCE;
+ case YANG_YIN_ELEMENT:
+ return LYEXT_SUBSTMT_YINELEM;
+ case YANG_CONFIG:
+ return LYEXT_SUBSTMT_CONFIG;
+ case YANG_MANDATORY:
+ return LYEXT_SUBSTMT_MANDATORY;
+ case YANG_ORDERED_BY:
+ return LYEXT_SUBSTMT_ORDEREDBY;
+ case YANG_STATUS:
+ return LYEXT_SUBSTMT_STATUS;
+ case YANG_FRACTION_DIGITS:
+ return LYEXT_SUBSTMT_FRACDIGITS;
+ case YANG_MAX_ELEMENTS:
+ return LYEXT_SUBSTMT_MAX;
+ case YANG_MIN_ELEMENTS:
+ return LYEXT_SUBSTMT_MIN;
+ case YANG_POSITION:
+ return LYEXT_SUBSTMT_POSITION;
+ case YANG_UNIQUE:
+ return LYEXT_SUBSTMT_UNIQUE;
+ case YANG_IF_FEATURE:
+ return LYEXT_SUBSTMT_IFFEATURE;
+ default:
+ return LYEXT_SUBSTMT_SELF;
+ }
+}
+
+/**
+ * @brief map keyword to keyword-group.
+ *
+ * @param[in] ctx YIN parser context used for logging.
+ * @param[in] kw Keyword that is child of module or submodule.
+ * @param[out] group Group of keyword.
+ *
+ * @return LY_SUCCESS on success LY_EINT if kw can't be mapped to kw_group, should not happen if called correctly.
+ */
+static LY_ERR
+kw2kw_group(struct yin_parser_ctx *ctx, enum yang_keyword kw, enum yang_module_stmt *group)
+{
+ switch (kw) {
+ /* module header */
+ case YANG_NONE:
+ case YANG_NAMESPACE:
+ case YANG_PREFIX:
+ case YANG_BELONGS_TO:
+ case YANG_YANG_VERSION:
+ *group = Y_MOD_MODULE_HEADER;
+ break;
+ /* linkage */
+ case YANG_INCLUDE:
+ case YANG_IMPORT:
+ *group = Y_MOD_LINKAGE;
+ break;
+ /* meta */
+ case YANG_ORGANIZATION:
+ case YANG_CONTACT:
+ case YANG_DESCRIPTION:
+ case YANG_REFERENCE:
+ *group = Y_MOD_META;
+ break;
+ /* revision */
+ case YANG_REVISION:
+ *group = Y_MOD_REVISION;
+ break;
+ /* body */
+ case YANG_ANYDATA:
+ case YANG_ANYXML:
+ case YANG_AUGMENT:
+ case YANG_CHOICE:
+ case YANG_CONTAINER:
+ case YANG_DEVIATION:
+ case YANG_EXTENSION:
+ case YANG_FEATURE:
+ case YANG_GROUPING:
+ case YANG_IDENTITY:
+ case YANG_LEAF:
+ case YANG_LEAF_LIST:
+ case YANG_LIST:
+ case YANG_NOTIFICATION:
+ case YANG_RPC:
+ case YANG_TYPEDEF:
+ case YANG_USES:
+ case YANG_CUSTOM:
+ *group = Y_MOD_BODY;
+ break;
+ default:
+ LOGINT(ctx->xml_ctx.ctx);
+ return LY_EINT;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Check if relative order of two keywords is valid.
+ *
+ * @param[in] ctx YIN parser context used for logging.
+ * @param[in] kw Current keyword.
+ * @param[in] next_kw Next keyword.
+ * @param[in] parrent Identification of parrent element, can be se to to YANG_MODULE of YANG_SUBMODULE,
+ * because relative order is required only in module and submodule sub-elements, used for logging.
+ *
+ * @return LY_SUCCESS on success and LY_EVALID if relative order is invalid.
+ */
+static LY_ERR
+yin_check_relative_order(struct yin_parser_ctx *ctx, enum yang_keyword kw, enum yang_keyword next_kw, enum yang_keyword parrent)
+{
+ assert(parrent == YANG_MODULE || parrent == YANG_SUBMODULE);
+ enum yang_module_stmt gr, next_gr;
+
+ LY_CHECK_RET(kw2kw_group(ctx, kw, &gr));
+ LY_CHECK_RET(kw2kw_group(ctx, next_kw, &next_gr));
+
+ if (gr > next_gr) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INORDER_YIN, ly_stmt2str(parrent), ly_stmt2str(next_kw), ly_stmt2str(kw));
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+yin_parse_content(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info, signed char subelem_info_size,
+ const char **data, enum yang_keyword current_element, const char **text_content, struct lysp_ext_instance **exts)
+{
+ LY_ERR ret = LY_SUCCESS;
+ char *out = NULL;
+ const char *prefix, *name;
+ size_t out_len = 0, prefix_len, name_len;
+ int dynamic = 0;
+ struct yin_arg_record *attrs = NULL;
+ enum yang_keyword kw = YANG_NONE, last_kw = YANG_NONE;
+ struct yin_subelement *subelem = NULL;
+
+ assert(is_ordered(subelem_info, subelem_info_size));
+
+ if (ctx->xml_ctx.status == LYXML_ELEM_CONTENT) {
+ ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
+ /* current element has subelements as content */
+ if (ret == LY_EINVAL) {
+ while (ctx->xml_ctx.status == LYXML_ELEMENT) {
+ ret = lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len);
+ LY_CHECK_GOTO(ret, cleanup);
+ if (!name) {
+ /* end of current element reached */
+ break;
+ }
+ ret = yin_load_attributes(ctx, data, &attrs);
+ LY_CHECK_GOTO(ret, cleanup);
+ last_kw = kw;
+ kw = yin_match_keyword(ctx, name, name_len, prefix, prefix_len, current_element);
+
+ /* check if this element can be child of current element */
+ subelem = get_record(kw, subelem_info_size, subelem_info);
+ if (!subelem) {
+ if (current_element == YANG_DEVIATE && isdevsub(kw)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INDEV_YIN, ly_stmt2str(kw));
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name_len, name, ly_stmt2str(current_element));
+ }
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* relative order is required only in module and submodule sub-elements */
+ if (current_element == YANG_MODULE || current_element == YANG_SUBMODULE) {
+ ret = yin_check_relative_order(ctx, last_kw, kw, current_element);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+
+ /* flag check */
+ if ((subelem->flags & YIN_SUBELEM_UNIQUE) && (subelem->flags & YIN_SUBELEM_PARSED)) {
+ /* subelement uniquenes */
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_SUBELEM_REDEF, ly_stmt2str(kw), ly_stmt2str(current_element));
+ return LY_EVALID;
+ }
+ if (subelem->flags & YIN_SUBELEM_FIRST) {
+ /* subelement is supposed to be defined as first subelement */
+ ret = yin_check_subelem_first_constraint(ctx, subelem_info, subelem_info_size, current_element, subelem);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ if (subelem->flags & YIN_SUBELEM_VER2) {
+ /* subelement is supported only in version 1.1 or higher */
+ if (ctx->mod_version < 2) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INSUBELEM2, ly_stmt2str(kw), ly_stmt2str(current_element));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ }
+ /* note that element was parsed for easy uniqueness check in next iterations */
+ subelem->flags |= YIN_SUBELEM_PARSED;
+
+ switch (kw) {
+ /* call responsible function */
+ case YANG_CUSTOM:
+ ret = yin_parse_extension_instance(ctx, attrs, data, name2fname(name, prefix_len),
+ len2flen(name_len, prefix_len),
+ kw2lyext_substmt(current_element),
+ (subelem->dest) ? *((uint32_t*)subelem->dest) : 0, exts);
+ break;
+ case YANG_ACTION:
+ case YANG_RPC:
+ ret = yin_parse_action(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_ANYDATA:
+ case YANG_ANYXML:
+ ret = yin_parse_any(ctx, attrs, data, kw, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_ARGUMENT:
+ ret = yin_parse_argument(ctx, attrs, data, (struct yin_argument_meta *)subelem->dest, exts);
+ break;
+ case YANG_AUGMENT:
+ ret = yin_parse_augment(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_BASE:
+ ret = yin_parse_base(ctx, attrs, data, current_element, subelem->dest, exts);
+ break;
+ case YANG_BELONGS_TO:
+ ret = yin_parse_belongs_to(ctx, attrs, data, (struct lysp_submodule *)subelem->dest, exts);
+ break;
+ case YANG_BIT:
+ ret = yin_parse_bit(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_CASE:
+ ret = yin_parse_case(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_CHOICE:
+ ret = yin_parse_choice(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_CONFIG:
+ ret = yin_parse_config(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+ break;
+ case YANG_CONTACT:
+ case YANG_DESCRIPTION:
+ case YANG_ORGANIZATION:
+ case YANG_REFERENCE:
+ ret = yin_parse_meta(ctx, attrs, data, kw, (const char **)subelem->dest, exts);
+ break;
+ case YANG_CONTAINER:
+ ret = yin_parse_container(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_DEFAULT:
+ case YANG_ERROR_APP_TAG:
+ case YANG_KEY:
+ case YANG_PRESENCE:
+ ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_VALUE, Y_STR_ARG, exts);
+ break;
+ case YANG_DEVIATE:
+ ret = yin_parse_deviate(ctx, attrs, data, (struct lysp_deviate **)subelem->dest);
+ break;
+ case YANG_DEVIATION:
+ ret = yin_parse_deviation(ctx, attrs, data, (struct lysp_deviation **)subelem->dest);
+ break;
+ case YANG_ENUM:
+ ret = yin_parse_enum(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_ERROR_MESSAGE:
+ ret = yin_parse_err_msg(ctx, attrs, data, (const char **)subelem->dest, exts);
+ break;
+ case YANG_EXTENSION:
+ ret = yin_parse_extension(ctx, attrs, data, (struct lysp_ext **)subelem->dest);
+ break;
+ case YANG_FEATURE:
+ ret = yin_parse_feature(ctx, attrs, data, (struct lysp_feature **)subelem->dest);
+ break;
+ case YANG_FRACTION_DIGITS:
+ ret = yin_parse_fracdigits(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_GROUPING:
+ ret = yin_parse_grouping(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_IDENTITY:
+ ret = yin_parse_identity(ctx, attrs, data, (struct lysp_ident **)subelem->dest);
+ break;
+ case YANG_IF_FEATURE:
+ case YANG_UNITS:
+ ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_NAME, Y_STR_ARG, exts);
+ break;
+ case YANG_IMPORT:
+ ret = yin_parse_import(ctx, attrs, data, (struct import_meta *)subelem->dest);
+ break;
+ case YANG_INCLUDE:
+ ret = yin_parse_include(ctx, attrs, data, (struct include_meta *)subelem->dest);
+ break;
+ case YANG_INPUT:
+ case YANG_OUTPUT:
+ ret = yin_parse_inout(ctx, attrs, data, kw, (struct inout_meta *)subelem->dest);
+ break;
+ case YANG_LEAF:
+ ret = yin_parse_leaf(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_LEAF_LIST:
+ ret = yin_parse_leaflist(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_LENGTH:
+ ret = yin_parse_length(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_LIST:
+ ret = yin_parse_list(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_MANDATORY:
+ ret = yin_parse_mandatory(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+ break;
+ case YANG_MAX_ELEMENTS:
+ case YANG_MIN_ELEMENTS:
+ ret = yin_parse_minmax(ctx, attrs, data, current_element, kw, subelem->dest);
+ break;
+ case YANG_MODIFIER:
+ ret = yin_parse_modifier(ctx, attrs, data, (const char **)subelem->dest, exts);
+ break;
+ case YANG_MUST:
+ ret = yin_parse_must(ctx, attrs, data, (struct lysp_restr **)subelem->dest);
+ break;
+ case YANG_NAMESPACE:
+ ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_URI, Y_STR_ARG, exts);
+ break;
+ case YANG_NOTIFICATION:
+ ret = yin_parse_notification(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_ORDERED_BY:
+ ret = yin_parse_orderedby(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+ break;
+ case YANG_PATH:
+ ret = yin_parse_path(ctx, attrs, data, kw, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_PATTERN:
+ ret = yin_parse_pattern(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_VALUE:
+ case YANG_POSITION:
+ ret = yin_parse_value_pos(ctx, attrs, data, kw, (struct lysp_type_enum *)subelem->dest);
+ break;
+ case YANG_PREFIX:
+ ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_VALUE, Y_IDENTIF_ARG, exts);
+ break;
+ case YANG_RANGE:
+ ret = yin_parse_range(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_REFINE:
+ ret = yin_parse_refine(ctx, attrs, data, (struct lysp_refine **)subelem->dest);
+ break;
+ case YANG_REQUIRE_INSTANCE:
+ ret = yin_pasrse_reqinstance(ctx, attrs, data, (struct lysp_type *)subelem->dest);
+ break;
+ case YANG_REVISION:
+ ret = yin_parse_revision(ctx, attrs, data, (struct lysp_revision **)subelem->dest);
+ break;
+ case YANG_REVISION_DATE:
+ ret = yin_parse_revision_date(ctx, attrs, data, (char *)subelem->dest, exts);
+ break;
+ case YANG_STATUS:
+ ret = yin_parse_status(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+ break;
+ case YANG_TYPE:
+ ret = yin_parse_type(ctx, attrs, data, current_element, subelem);
+ break;
+ case YANG_TYPEDEF:
+ ret = yin_parse_typedef(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_UNIQUE:
+ ret = yin_parse_simple_elem(ctx, attrs, data, kw, subelem, YIN_ARG_TAG, Y_STR_ARG, exts);
+ break;
+ case YANG_USES:
+ ret = yin_parse_uses(ctx, attrs, data, (struct tree_node_meta *)subelem->dest);
+ break;
+ case YANG_WHEN:
+ ret = yin_parse_when(ctx, attrs, data, (struct lysp_when **)subelem->dest);
+ break;
+ case YANG_YANG_VERSION:
+ ret = yin_parse_yangversion(ctx, attrs, data, (uint8_t *)subelem->dest, exts);
+ break;
+ case YANG_YIN_ELEMENT:
+ ret = yin_parse_yin_element(ctx, attrs, data, (uint16_t *)subelem->dest, exts);
+ break;
+ case YIN_TEXT:
+ case YIN_VALUE:
+ ret = yin_parse_content(ctx, NULL, 0, data, kw, (const char **)subelem->dest, NULL);
+ break;
+ default:
+ LOGINT(ctx->xml_ctx.ctx);
+ ret = LY_EINT;
+ }
+ LY_CHECK_GOTO(ret, cleanup);
+ FREE_ARRAY(ctx, attrs, free_arg_rec);
+ attrs = NULL;
+ subelem = NULL;
+ }
+ } else {
+ LY_CHECK_RET(ret);
+ /* elements with text or none content */
+ /* save text content, if text_content isn't set, it's just ignored */
+ /* no resources are allocated in this branch, no need to use cleanup label */
+ LY_CHECK_RET(yin_validate_value(ctx, Y_STR_ARG, out, out_len));
+ if (text_content) {
+ INSERT_STRING(ctx->xml_ctx.ctx, *text_content, dynamic, out, out_len);
+ LY_CHECK_RET(!*text_content, LY_EMEM);
+ }
+ /* load closing element */
+ LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+ }
+ }
+ /* mandatory subelemnts are checked only after whole element was succesfully parsed */
+ LY_CHECK_RET(yin_check_subelem_mandatory_constraint(ctx, subelem_info, subelem_info_size, current_element));
+
+cleanup:
+ FREE_ARRAY(ctx, attrs, free_arg_rec);
+ return ret;
+}
+
+LY_ERR
+yin_parse_extension_instance(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, const char *ext_name,
+ int ext_name_len, LYEXT_SUBSTMT subelem, uint32_t subelem_index, struct lysp_ext_instance **exts)
+{
+ LY_ERR ret = LY_SUCCESS;
+ char *out;
+ const char *name, *prefix;
+ size_t out_len, prefix_len, name_len;
+ int dynamic;
+ struct lysp_ext_instance *e;
+ struct lysp_stmt *last_subelem = NULL, *new_subelem = NULL;
+ struct yin_arg_record *iter;
+
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *exts, e, LY_EMEM);
+
+ e->yin = 0;
+ /* store name and insubstmt info */
+ e->name = lydict_insert(ctx->xml_ctx.ctx, ext_name, ext_name_len);
+ e->insubstmt = subelem;
+ e->insubstmt_index = subelem_index;
+ e->yin |= LYS_YIN;
+
+ /* store attributes as subelements */
+ LY_ARRAY_FOR_ITER(attrs, struct yin_arg_record, iter) {
+ if (!iter->prefix) {
+ new_subelem = calloc(1, sizeof(*new_subelem));
+ if (!e->child) {
+ e->child = new_subelem;
+ } else {
+ last_subelem->next = new_subelem;
+ }
+ last_subelem = new_subelem;
+
+ last_subelem->flags |= LYS_YIN_ATTR;
+ last_subelem->stmt = lydict_insert(ctx->xml_ctx.ctx, iter->name, iter->name_len);
+ LY_CHECK_RET(!last_subelem->stmt, LY_EMEM);
+
+ INSERT_STRING(ctx->xml_ctx.ctx, last_subelem->arg, iter->dynamic_content, iter->content, iter->content_len);
+ LY_CHECK_RET(!last_subelem->arg, LY_EMEM);
+ }
+ }
+
+ /* parse subelements */
+ if (ctx->xml_ctx.status == LYXML_ELEM_CONTENT) {
+ ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
+ if (ret == LY_EINVAL) {
+ while (ctx->xml_ctx.status == LYXML_ELEMENT) {
+ LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+ if (!name) {
+ /* end of extension instance reached */
+ break;
+ }
+ LY_CHECK_RET(yin_parse_element_generic(ctx, name2fname(name, prefix_len),
+ len2flen(name_len, prefix_len), data, &new_subelem));
+ if (!e->child) {
+ e->child = new_subelem;
+ } else {
+ last_subelem->next = new_subelem;
+ }
+ last_subelem = new_subelem;
+ }
+ } else {
+ if (out_len != 0) {
+ /* save text content */
+ LY_CHECK_RET(ret);
+
+ INSERT_STRING(ctx->xml_ctx.ctx, e->argument, dynamic, out, out_len);
+ LY_CHECK_RET(!e->argument, LY_EMEM);
+
+ /* load closing element */
+ LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+ LY_CHECK_RET(name, LY_EINT);
+ }
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char **data,
+ struct lysp_stmt **element)
+{
+ LY_ERR ret = LY_SUCCESS;
+ const char *temp_prefix, *temp_name;
+ char *out = NULL;
+ size_t out_len, temp_name_len, temp_prefix_len, prefix_len;
+ int dynamic;
+ struct lysp_stmt *last = NULL, *new = NULL;
+
+ /* allocate new structure for element */
+ *element = calloc(1, sizeof(**element));
+ LY_CHECK_ERR_RET(!(*element), LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ (*element)->stmt = lydict_insert(ctx->xml_ctx.ctx, name, name_len);
+ LY_CHECK_RET(!(*element)->stmt, LY_EMEM);
+
+ last = (*element)->child;
+ /* load attributes */
+ while(ctx->xml_ctx.status == LYXML_ATTRIBUTE) {
+ /* add new element to linked-list */
+ new = calloc(1, sizeof(*last));
+ LY_CHECK_ERR_RET(!new, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ if (!(*element)->child) {
+ /* save first */
+ (*element)->child = new;
+ } else {
+ last->next = new;
+ }
+ last = new;
+
+ last->flags |= LYS_YIN_ATTR;
+ LY_CHECK_RET(lyxml_get_attribute(&ctx->xml_ctx, data, &temp_prefix, &prefix_len, &temp_name, &temp_name_len));
+ last->stmt = lydict_insert(ctx->xml_ctx.ctx, temp_name, temp_name_len);
+ LY_CHECK_RET(!last->stmt, LY_EMEM);
+
+ LY_CHECK_RET(lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic));
+ /* attributes with prefix are ignored */
+ if (!temp_prefix) {
+ INSERT_STRING(ctx->xml_ctx.ctx, last->arg, dynamic, out, out_len);
+ LY_CHECK_RET(!last->arg, LY_EMEM);
+ } else {
+ if (dynamic) {
+ free(out);
+ }
+ }
+ }
+
+ /* parse content of element if any */
+ if (ctx->xml_ctx.status == LYXML_ELEM_CONTENT) {
+ ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
+ 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));
+ if (!temp_name) {
+ /* end of element reached */
+ break;
+ }
+ LY_CHECK_RET(yin_parse_element_generic(ctx, name2fname(temp_name, temp_prefix_len),
+ len2flen(temp_name_len, temp_prefix_len), data, &new));
+ if (!(*element)->child) {
+ /* save first */
+ (*element)->child = new;
+ } else {
+ last->next = new;
+ }
+ last = new;
+ }
+ } else {
+ LY_CHECK_RET(ret);
+ /* 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);
+ }
+
+ /* read closing tag */
+ LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &prefix_len, &temp_name, &temp_name_len));
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+yin_parse_mod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs, const char **data, struct lysp_module *mod)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, mod_attrs, YIN_ARG_NAME, &mod->mod->name, Y_IDENTIF_ARG, YANG_MODULE));
+ LY_CHECK_RET(subelems_allocator(ctx, 28, NULL, &subelems,
+ YANG_ANYDATA, &mod->data, YIN_SUBELEM_VER2,
+ YANG_ANYXML, &mod->data, 0,
+ YANG_AUGMENT, &mod->augments, 0,
+ YANG_CHOICE, &mod->data, 0,
+ YANG_CONTACT, &mod->mod->contact, YIN_SUBELEM_UNIQUE,
+ YANG_CONTAINER, &mod->data, 0,
+ YANG_DESCRIPTION, &mod->mod->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_DEVIATION, &mod->deviations, 0,
+ YANG_EXTENSION, &mod->extensions, 0,
+ YANG_FEATURE, &mod->features, 0,
+ YANG_GROUPING, &mod->groupings, 0,
+ YANG_IDENTITY, &mod->identities, 0,
+ YANG_IMPORT, mod->mod->prefix, &mod->imports, 0,
+ YANG_INCLUDE, mod->mod->name, &mod->includes, 0,
+ YANG_LEAF, &mod->data, 0,
+ YANG_LEAF_LIST, &mod->data, 0,
+ YANG_LIST, &mod->data, 0,
+ YANG_NAMESPACE, &mod->mod->ns, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+ YANG_NOTIFICATION, &mod->notifs, 0,
+ YANG_ORGANIZATION, &mod->mod->org, YIN_SUBELEM_UNIQUE,
+ YANG_PREFIX, &mod->mod->prefix, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+ YANG_REFERENCE, &mod->mod->ref, YIN_SUBELEM_UNIQUE,
+ YANG_REVISION, &mod->revs, 0,
+ YANG_RPC, &mod->rpcs, 0,
+ YANG_TYPEDEF, &mod->typedefs, 0,
+ YANG_USES, &mod->data, 0,
+ YANG_YANG_VERSION, &mod->mod->version, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+ YANG_CUSTOM, NULL, 0
+ ));
+
+ ret = yin_parse_content(ctx, subelems, 28, data, YANG_MODULE, NULL, &mod->exts);
+ subelems_deallocator(28, subelems);
+
+ return ret;
+}
+
+LY_ERR
+yin_parse_submod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs, const char **data, struct lysp_submodule *submod)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement *subelems = NULL;
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, mod_attrs, YIN_ARG_NAME, &submod->name, Y_IDENTIF_ARG, YANG_SUBMODULE));
+ LY_CHECK_RET(subelems_allocator(ctx, 27, NULL, &subelems,
+ YANG_ANYDATA, &submod->data, YIN_SUBELEM_VER2,
+ YANG_ANYXML, &submod->data, 0,
+ YANG_AUGMENT, &submod->augments, 0,
+ YANG_BELONGS_TO, submod, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+ YANG_CHOICE, &submod->data, 0,
+ YANG_CONTACT, &submod->contact, YIN_SUBELEM_UNIQUE,
+ YANG_CONTAINER, &submod->data, 0,
+ YANG_DESCRIPTION, &submod->dsc, YIN_SUBELEM_UNIQUE,
+ YANG_DEVIATION, &submod->deviations, 0,
+ YANG_EXTENSION, &submod->extensions, 0,
+ YANG_FEATURE, &submod->features, 0,
+ YANG_GROUPING, &submod->groupings, 0,
+ YANG_IDENTITY, &submod->identities, 0,
+ YANG_IMPORT, submod->prefix, &submod->imports, 0,
+ YANG_INCLUDE, submod->name, &submod->includes, 0,
+ YANG_LEAF, &submod->data, 0,
+ YANG_LEAF_LIST, &submod->data, 0,
+ YANG_LIST, &submod->data, 0,
+ YANG_NOTIFICATION, &submod->notifs, 0,
+ YANG_ORGANIZATION, &submod->org, YIN_SUBELEM_UNIQUE,
+ YANG_REFERENCE, &submod->ref, YIN_SUBELEM_UNIQUE,
+ YANG_REVISION, &submod->revs, 0,
+ YANG_RPC, &submod->rpcs, 0,
+ YANG_TYPEDEF, &submod->typedefs, 0,
+ YANG_USES, &submod->data, 0,
+ YANG_YANG_VERSION, &submod->version, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE,
+ YANG_CUSTOM, NULL, 0
+ ));
+
+ ret = yin_parse_content(ctx, subelems, 27, data, YANG_SUBMODULE, NULL, &submod->exts);
+ subelems_deallocator(27, subelems);
+
+ return ret;
+}
+
+LY_ERR
+yin_parse_submodule(struct yin_parser_ctx **yin_ctx, struct ly_ctx *ctx, struct lys_parser_ctx *main_ctx, const char *data, struct lysp_submodule **submod)
+{
+ enum yang_keyword kw = YANG_NONE;
+ LY_ERR ret = LY_SUCCESS;
+ const char *prefix, *name;
+ size_t prefix_len, name_len;
+ struct yin_arg_record *attrs = NULL;
+ struct lysp_submodule *mod_p = NULL;
+
+ /* create context */
+ *yin_ctx = calloc(1, sizeof **yin_ctx);
+ LY_CHECK_ERR_RET(!(*yin_ctx), LOGMEM(ctx), LY_EMEM);
+ (*yin_ctx)->xml_ctx.ctx = ctx;
+ (*yin_ctx)->xml_ctx.line = 1;
+
+ /* map the typedefs and groupings list from main context to the submodule's context */
+ memcpy(&(*yin_ctx)->tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+ memcpy(&(*yin_ctx)->grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
+
+ /* check submodule */
+ ret = lyxml_get_element(&(*yin_ctx)->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ LY_CHECK_GOTO(ret, cleanup);
+ ret = yin_load_attributes(*yin_ctx, &data, &attrs);
+ LY_CHECK_GOTO(ret, cleanup);
+ kw = yin_match_keyword(*yin_ctx, name, name_len, prefix, prefix_len, YANG_NONE);
+
+ if (kw == YANG_MODULE) {
+ LOGERR(ctx, LY_EDENIED, "Input data contains module in situation when a submodule is expected.");
+ ret = LY_EINVAL;
+ goto cleanup;
+ } else if (kw != YANG_SUBMODULE) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ mod_p = calloc(1, sizeof *mod_p);
+ LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx), cleanup);
+ mod_p->parsing = 1;
+
+ ret = yin_parse_submod(*yin_ctx, attrs, &data, mod_p);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ name = NULL;
+ /* skip possible trailing whitespaces at end of the input */
+ while(*data && isspace(*data)) {
+ data++;
+ }
+ if (*data) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_TRAILING_SUBMOD, 15, data, strlen(data) > 15 ? "..." : "");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ mod_p->parsing = 0;
+ *submod = mod_p;
+
+cleanup:
+ if (ret) {
+ lysp_submodule_free(ctx, mod_p);
+ yin_parser_ctx_free(*yin_ctx);
+ *yin_ctx = NULL;
+ }
+
+ FREE_ARRAY(*yin_ctx, attrs, free_arg_rec);
+ return ret;
+}
+
+LY_ERR
+yin_parse_module(struct yin_parser_ctx **yin_ctx, const char *data, struct lys_module *mod)
+{
+ LY_ERR ret = LY_SUCCESS;
+ enum yang_keyword kw = YANG_NONE;
+ struct lysp_module *mod_p = NULL;
+ const char *prefix, *name;
+ size_t prefix_len, name_len;
+ struct yin_arg_record *attrs = NULL;
+
+ /* create context */
+ *yin_ctx = calloc(1, sizeof **yin_ctx);
+ LY_CHECK_ERR_RET(!(*yin_ctx), LOGMEM(mod->ctx), LY_EMEM);
+ (*yin_ctx)->xml_ctx.ctx = mod->ctx;
+ (*yin_ctx)->xml_ctx.line = 1;
+
+ /* check module */
+ ret = lyxml_get_element(&(*yin_ctx)->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ LY_CHECK_GOTO(ret, cleanup);
+ ret = yin_load_attributes(*yin_ctx, &data, &attrs);
+ LY_CHECK_GOTO(ret, cleanup);
+ kw = yin_match_keyword(*yin_ctx, name, name_len, prefix, prefix_len, YANG_NONE);
+ if (kw == YANG_SUBMODULE) {
+ LOGERR(mod->ctx, LY_EDENIED, "Input data contains submodule which cannot be parsed directly without its main module.");
+ ret = LY_EINVAL;
+ goto cleanup;
+ } else if (kw != YANG_MODULE) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_MOD_SUBOMD, ly_stmt2str(kw));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* allocate module */
+ mod_p = calloc(1, sizeof *mod_p);
+ LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(mod->ctx), cleanup);
+ mod_p->mod = mod;
+ mod_p->parsing = 1;
+
+ /* parse module substatements */
+ ret = yin_parse_mod(*yin_ctx, attrs, &data, mod_p);
+ LY_CHECK_GOTO(ret, cleanup);
+
+ name = NULL;
+ /* skip possible trailing whitespaces at end of the input */
+ while(*data && isspace(*data)) {
+ data++;
+ }
+ if (*data) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)*yin_ctx, LY_VCODE_TRAILING_MOD, 15, data, strlen(data) > 15 ? "..." : "");
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ mod_p->parsing = 0;
+ mod->parsed = mod_p;
+
+cleanup:
+ if (ret != LY_SUCCESS) {
+ lysp_module_free(mod_p);
+ yin_parser_ctx_free(*yin_ctx);
+ *yin_ctx = NULL;
+ }
+ FREE_ARRAY(*yin_ctx, attrs, free_arg_rec);
+ return ret;
+}
diff --git a/src/parser_yin.h b/src/parser_yin.h
new file mode 100644
index 0000000..7bf278a
--- /dev/null
+++ b/src/parser_yin.h
@@ -0,0 +1,300 @@
+/**
+ * @file parser_yin.h
+ * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
+ * @brief YIN parser header file.
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef LY_PARSER_YIN_H_
+#define LY_PARSER_YIN_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "log.h"
+#include "xml.h"
+
+/* list of yin attribute strings */
+extern const char *const yin_attr_list[];
+#define yin_attr2str(STMT) yin_attr_list[STMT]
+
+#define YIN_NS_URI "urn:ietf:params:xml:ns:yang:yin:1"
+
+/**
+ * @brief Get start of full name including possible prefix.
+ *
+ * @param[in] name Start of name in input data.
+ * @param[in] prefix_len Lenght of prefix.
+ *
+ * @return Pointer to begining of full element name including prefix.
+ */
+#define name2fname(name, prefix_len) (prefix_len != 0 ? name - (prefix_len + 1) : name)
+
+/**
+ * @brief Get length of full name including possible prefix.
+ *
+ * @param[in] name_len Lenght of name without prefix.
+ * @param[in] prefix_len Lenght of prefix.
+ *
+ * @return Lenght of full name including possible prefix and ':' delimiter.
+ */
+#define len2flen(name_len, prefix_len) (prefix_len != 0 ? name_len + prefix_len + 1 : name_len)
+
+#define VALID_VALS1 " Only valid value is \"%s\"."
+#define VALID_VALS2 " Valid values are \"%s\" and \"%s\"."
+#define VALID_VALS3 " Valid values are \"%s\", \"%s\" and \"%s\"."
+#define VALID_VALS4 " Valid values are \"%s\", \"%s\", \"%s\" and \"%s\"."
+
+/* shortcut to determin if keyword can in general be subelement of deviation regardles of it's type */
+#define isdevsub(kw) (kw == YANG_CONFIG || kw == YANG_DEFAULT || kw == YANG_MANDATORY || \
+ kw == YANG_MAX_ELEMENTS || kw == YANG_MIN_ELEMENTS || \
+ kw == YANG_MUST || kw == YANG_TYPE || kw == YANG_UNIQUE || \
+ kw == YANG_UNITS || kw == YANG_CUSTOM)
+
+/**
+ * @brief insert string into dictionary and store as target.
+ *
+ * @param[in] CTX libyang context.
+ * @param[out] TARGET variable where to store the pointer to the inserted value.
+ * @param[in] DYNAMIC Set to 1 if STR is dynamically allocated, 0 otherwise. If set to 1, zerocopy version of lydict_insert is used.
+ * @param[in] STR string to store.
+ * @param[in] LEN length of the string in WORD to store.
+ */
+#define INSERT_STRING(CTX, TARGET, DYNAMIC, STR, LEN) \
+ if (DYNAMIC) {(TARGET) = lydict_insert_zc(CTX, STR);} \
+ else {(TARGET) = lydict_insert(CTX, LEN ? STR : "", LEN);}
+
+enum yin_argument {
+ YIN_ARG_UNKNOWN = 0, /**< parsed argument can not be matched with any supported yin argument keyword */
+ YIN_ARG_NAME, /**< argument name */
+ YIN_ARG_TARGET_NODE, /**< argument target-node */
+ YIN_ARG_MODULE, /**< argument module */
+ YIN_ARG_VALUE, /**< argument value */
+ YIN_ARG_TEXT, /**< argument text */
+ YIN_ARG_CONDITION, /**< argument condition */
+ YIN_ARG_URI, /**< argument uri */
+ YIN_ARG_DATE, /**< argument data */
+ YIN_ARG_TAG, /**< argument tag */
+ YIN_ARG_NONE, /**< empty (special value) */
+};
+
+/**
+ * @brief structure to store instance of xml attribute
+ */
+struct yin_arg_record {
+ const char *prefix; /**< start of prefix */
+ size_t prefix_len; /**< length of prefix */
+ const char *name; /**< start of name */
+ size_t name_len; /**< length of name */
+ char *content; /**< start of content */
+ size_t content_len; /**< length of content */
+ int dynamic_content; /**< is set to 1 iff content is dynamically allocated 0 otherwise */
+};
+
+/* flags to set constraints of subelements */
+#define YIN_SUBELEM_MANDATORY 0x01 /**< is set when subelement is mandatory */
+#define YIN_SUBELEM_UNIQUE 0x02 /**< is set when subelement is unique */
+#define YIN_SUBELEM_FIRST 0x04 /**< is set when subelement is actually yang argument mapped to yin element */
+#define YIN_SUBELEM_VER2 0x08 /**< subelemnt is allowed only in modules with version at least 2 (YANG 1.1) */
+
+#define YIN_SUBELEM_PARSED 0x80 /**< is set during parsing when given subelement is encountered for the first
+ time to simply check validity of given constraints */
+
+struct yin_subelement {
+ enum yang_keyword type; /**< type of keyword */
+ void *dest; /**< meta infromation passed to responsible function (mostly information about where parsed subelement should be stored) */
+ uint8_t flags; /**< describes constraints of subelement can be set to YIN_SUBELEM_MANDATORY, YIN_SUBELEM_UNIQUE, YIN_SUBELEM_FIRST and YIN_SUBELEM_VER2 */
+};
+
+/* Meta information passed to yin_parse_argument function,
+ holds information about where content of argument element will be stored. */
+struct yin_argument_meta {
+ uint16_t *flags; /**< Argument flags */
+ const char **argument; /**< Argument value */
+};
+
+/**
+ * @brief Meta information passed to functions working with tree_schema,
+ * that require additional information about parent node.
+ */
+struct tree_node_meta {
+ struct lysp_node *parent; /**< parent node */
+ struct lysp_node **nodes; /**< linked list of siblings */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_import function.
+ */
+struct import_meta {
+ const char *prefix; /**< module prefix. */
+ struct lysp_import **imports; /**< imports to add to. */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_include function.
+ */
+struct include_meta {
+ const char *name; /**< Module/submodule name. */
+ struct lysp_include **includes; /**< [Sized array](@ref sizedarrays) of parsed includes to add to. */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_inout function.
+ */
+struct inout_meta {
+ struct lysp_node *parent; /**< Parent node. */
+ struct lysp_action_inout *inout_p; /**< inout_p Input/output pointer to write to. */
+};
+
+/**
+ * @brief Meta information passed to yin_parse_minmax function.
+ */
+struct minmax_dev_meta {
+ uint32_t *lim; /**< min/max value to write to. */
+ uint16_t *flags; /**< min/max flags to write to. */
+ struct lysp_ext_instance **exts; /**< extension instances to add to. */
+};
+
+/**
+ * @brief Match argument name.
+ *
+ * @param[in] name String representing name.
+ * @param[in] len Lenght of the name.
+ *
+ * @return yin_argument values.
+ */
+enum yin_argument yin_match_argument_name(const char *name, size_t len);
+
+/**
+ * @brief Generic function for content parsing
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] subelem_info array of valid subelement types and meta information,
+ * array must be ordered by subelem_info->type in ascending order.
+ * @param[in] subelem_info_size Size of subelem_info array.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[in] current_element Type of current element.
+ * @param[out] text_content Where the text content of element should be stored if any. Text content is ignored if set to NULL.
+ * @param[in,out] exts Extension instance to add to. Can be set to null if element cannot have extension as subelements.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_content(struct yin_parser_ctx *ctx, struct yin_subelement *subelem_info, signed char subelem_info_size,
+ const char **data, enum yang_keyword current_element, const char **text_content,
+ struct lysp_ext_instance **exts);
+
+/**
+ * @brief Check that val is valid UTF8 character sequence of val_type.
+ * Doesn't check empty string, only character validity.
+ *
+ * @param[in] ctx Yin parser context for logging.
+ * @param[in] val_type Type of the input string to select method of checking character validity.
+ * @param[in] val Input to validate.
+ * @param[in] len Length of input.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_validate_value(struct yin_parser_ctx *ctx, enum yang_arg val_type, char *val, size_t len);
+
+/**
+ * @brief Match yang keyword from yin data.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] name Start of keyword name
+ * @param[in] name_len Lenght of keyword name.
+ * @param[in] prefix Start of keyword prefix.
+ * @param[in] prefix_len Lenght of prefix.
+ * @param[in] parrent Identification of parrent element, use YANG_NONE for elements without parrent.
+ *
+ * @return yang_keyword values.
+ */
+enum yang_keyword yin_match_keyword(struct yin_parser_ctx *ctx, const char *name, size_t name_len,
+ const char *prefix, size_t prefix_len, enum yang_keyword parrent);
+
+/**
+ * @brief Load all attributes of element into ([sized array](@ref sizedarrays)). Caller is suposed to free the array.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] attrs ([Sized array](@ref sizedarrays)) of attributes.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_load_attributes(struct yin_parser_ctx *ctx, const char **data, struct yin_arg_record **attrs);
+
+/**
+ * @brief Parse 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] ext_name Name of the extension element.
+ * @param[in] ext_name_len Length of extension name.
+ * @param[in] subelem Type of the keyword this extension instance is a subelement of.
+ * @param[in] subelem_index Index of the keyword instance this extension instance is a subelement of
+ * @param[in,out] exts Extension instance to add to.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_extension_instance(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ const char *ext_name, int ext_name_len, LYEXT_SUBSTMT subelem,
+ uint32_t subelem_index, struct lysp_ext_instance **exts);
+
+/**
+ * @brief Parse yin element into generic structure.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] name Name of element.
+ * @param[in] name_len Length of elements Name.
+ * @param[in,out] data Data to read from, always moved to currently handled character.
+ * @param[out] element Where the element structure should be stored.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_element_generic(struct yin_parser_ctx *ctx, const char *name, size_t name_len, const char **data,
+ struct lysp_stmt **element);
+
+/**
+ * @brief Parse module element.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] mod_attrs Attributes of module element.
+ * @param[in,out] data Data to read from.
+ * @param[out] mod Parsed module structure.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_mod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs,
+ const char **data, struct lysp_module *mod);
+
+
+/**
+ * @brief Parse submodule element.
+ *
+ * @param[in,out] ctx Yin parser context for logging and to store current state.
+ * @param[in] mod_attrs Attributes of submodule element.
+ * @param[in,out] data Data to read from.
+ * @param[out] submod Parsed submodule structure.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_submod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs,
+ const char **data, struct lysp_submodule *submod);
+
+/**
+ * @brief free argument record, content loaded from lyxml_get_string() can be
+ * dynamically allocated in some cases so it must be also freed.
+ *
+ * @param ctx unused just to fulfill signature of callback for FREE_ARRAY.
+ * @param[in] record Record to free.
+ */
+void free_arg_rec(struct yin_parser_ctx *ctx, struct yin_arg_record *record);
+
+#endif /* LY_PARSER_YIN_H_*/
diff --git a/src/printer_yang.c b/src/printer_yang.c
index a3242a6..65ce5b5 100755
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -229,7 +229,9 @@
if (!count) {
break;
}
- if (ext->insubstmt == substmt && ext->insubstmt_index == substmt_index) {
+ if (ext->yin) {
+ ly_print(ctx->out, "%*s%s Model comes from different input format, extensions must be resolved first.", INDENT, ext[u].name);
+ } else if (ext->insubstmt == substmt && ext->insubstmt_index == substmt_index) {
ypr_open(ctx->out, flag);
if (ext[u].argument) {
ly_print(ctx->out, "%*s%s %s%s", INDENT, ext[u].name, ext[u].argument, ext[u].child ? " {\n" : ";\n");
diff --git a/src/tree_schema.c b/src/tree_schema.c
index ad8e695..3fc8b08 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -595,28 +595,21 @@
{
LY_ERR ret = LY_EINVAL;
struct lysp_submodule *submod = NULL, *latest_sp;
- struct lys_parser_ctx context = {0};
+ struct lys_parser_ctx *context = NULL;
+ struct yin_parser_ctx *yin_context = NULL;
LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
- context.ctx = ctx;
- context.line = 1;
-
- /* map the typedefs and groupings list from main context to the submodule's context */
- memcpy(&context.tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
- memcpy(&context.grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
-
switch (format) {
- /* TODO not yet supported
case LYS_IN_YIN:
- mod = yin_read_module();
+ ret = yin_parse_submodule(&yin_context, ctx, main_ctx, data, &submod);
+ context = (struct lys_parser_ctx *)yin_context;
break;
- */
case LYS_IN_YANG:
- ret = yang_parse_submodule(&context, data, &submod);
+ ret = yang_parse_submodule(&context, ctx, main_ctx, data, &submod);
break;
default:
- LOGERR(context.ctx, LY_EINVAL, "Invalid schema input format.");
+ LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
break;
}
LY_CHECK_RET(ret, NULL);
@@ -625,11 +618,11 @@
lysp_sort_revisions(submod->revs);
if (custom_check) {
- LY_CHECK_GOTO(custom_check(context.ctx, NULL, submod, check_data), error);
+ LY_CHECK_GOTO(custom_check((*context).ctx, NULL, submod, check_data), error);
}
/* decide the latest revision */
- latest_sp = ly_ctx_get_submodule(context.ctx, submod->belongsto, submod->name, NULL);
+ latest_sp = ly_ctx_get_submodule((*context).ctx, submod->belongsto, submod->name, NULL);
if (latest_sp) {
if (submod->revs) {
if (!latest_sp->revs) {
@@ -648,12 +641,23 @@
}
/* remap possibly changed and reallocated typedefs and groupings list back to the main context */
- memcpy(&main_ctx->tpdfs_nodes, &context.tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
- memcpy(&main_ctx->grps_nodes, &context.grps_nodes, sizeof main_ctx->grps_nodes);
+ memcpy(&main_ctx->tpdfs_nodes, &(*context).tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+ memcpy(&main_ctx->grps_nodes, &(*context).grps_nodes, sizeof main_ctx->grps_nodes);
+ if (format == LYS_IN_YANG) {
+ lys_parser_ctx_free(context);
+ } else {
+ yin_parser_ctx_free(yin_context);
+ }
return submod;
+
error:
lysp_submodule_free(ctx, submod);
+ if (format == LYS_IN_YANG) {
+ lys_parser_ctx_free(context);
+ } else {
+ yin_parser_ctx_free(yin_context);
+ }
return NULL;
}
@@ -667,23 +671,20 @@
struct lysp_include *inc;
LY_ERR ret = LY_EINVAL;
unsigned int u, i;
- struct lys_parser_ctx context = {0};
+ struct lys_parser_ctx *context = NULL;
+ struct yin_parser_ctx *yin_context = NULL;
LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
- context.ctx = ctx;
- context.line = 1;
-
mod = calloc(1, sizeof *mod);
LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
mod->ctx = ctx;
switch (format) {
- /* TODO not yet supported
case LYS_IN_YIN:
- mod = yin_read_module();
+ ret = yin_parse_module(&yin_context, data, mod);
+ context = (struct lys_parser_ctx *)yin_context;
break;
- */
case LYS_IN_YANG:
ret = yang_parse_module(&context, data, mod);
break;
@@ -794,7 +795,7 @@
}
LY_ARRAY_FOR(mod->parsed->includes, u) {
inc = &mod->parsed->includes[u];
- if (!inc->submodule && lysp_load_submodule(&context, mod->parsed, inc)) {
+ if (!inc->submodule && lysp_load_submodule(context, mod->parsed, inc)) {
goto error_ctx;
}
if (!mod->implemented) {
@@ -806,15 +807,26 @@
mod->parsed->parsing = 0;
/* check name collisions - typedefs and TODO groupings */
- LY_CHECK_GOTO(lysp_check_typedefs(&context, mod->parsed), error_ctx);
+ LY_CHECK_GOTO(lysp_check_typedefs(context, mod->parsed), error_ctx);
+ if (format == LYS_IN_YANG) {
+ lys_parser_ctx_free(context);
+ } else {
+ yin_parser_ctx_free(yin_context);
+ }
return mod;
error_ctx:
ly_set_rm(&ctx->list, mod, NULL);
error:
lys_module_free(mod, NULL);
- ly_set_erase(&context.tpdfs_nodes, NULL);
+ ly_set_erase(&context->tpdfs_nodes, NULL);
+ if (format == LYS_IN_YANG) {
+ lys_parser_ctx_free(context);
+ } else {
+ yin_parser_ctx_free(yin_context);
+ }
+
return NULL;
}
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 050c7be..4a3dbec 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -294,19 +294,22 @@
const char *arg; /**< statement's argument */
struct lysp_stmt *next; /**< link to the next statement */
struct lysp_stmt *child; /**< list of the statement's substatements (linked list) */
- uint16_t flags;
+ uint16_t flags; /**< statement flags, can be set to LYS_YIN_ATTR */
};
+#define LYS_YIN 0x1 /**< used to specify input format of extension instance */
+
/**
* @brief YANG extension instance
*/
struct lysp_ext_instance {
- const char *name; /**< extension identifier, including possible prefix */
- const char *argument; /**< optional value of the extension's argument */
- struct lysp_stmt *child; /**< list of the extension's substatements (linked list) */
- LYEXT_SUBSTMT insubstmt; /**< value identifying placement of the extension instance */
- uint32_t insubstmt_index; /**< in case the instance is in a substatement, this identifies
- the index of that substatement */
+ const char *name; /**< extension identifier, including possible prefix */
+ const char *argument; /**< optional value of the extension's argument */
+ struct lysp_stmt *child; /**< list of the extension's substatements (linked list) */
+ LYEXT_SUBSTMT insubstmt; /**< value identifying placement of the extension instance */
+ uint32_t insubstmt_index; /**< in case the instance is in a substatement, this identifies
+ the index of that substatement */
+ uint8_t yin; /** flag for YIN source format, can be set to LYS_YIN */
};
/**
@@ -513,7 +516,6 @@
struct lysp_restr *musts; /**< list of must restrictions ([sized array](@ref sizedarrays)) */
const char **uniques; /**< list of uniques specifications ([sized array](@ref sizedarrays)) */
const char **dflts; /**< list of default values ([sized array](@ref sizedarrays)) */
- uint16_t flags; /**< [schema node flags](@ref snodeflags) */
};
struct lysp_deviate_rpl {
@@ -588,6 +590,7 @@
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 11 LYS_SET_MAX | | | |x|x| | | | | | | | | | | | |x| |x| | | |
* LYS_USED_GRP | | | | | | | | | | | | | | | |x| | | | | | | |
+ * LYS_YIN_ATTR | | | | | | | | | | | | | | | | | | | | | | |x|
* ---------------------+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
@@ -701,6 +704,8 @@
#define LYS_SINGLEQUOTED 0x100 /**< flag for single-quoted argument of an extension instance's substatement */
#define LYS_DOUBLEQUOTED 0x200 /**< flag for double-quoted argument of an extension instance's substatement */
+#define LYS_YIN_ATTR 0x400 /**< flag to identify YIN attribute */
+
#define LYS_ISENUM 0x200 /**< flag to simply distinguish type in struct lysc_type_bitenum_item */
#define LYS_FLAGS_COMPILED_MASK 0xff /**< mask for flags that maps to the compiled structures */
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 64728f2..68c8252 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -54,7 +54,7 @@
}
}
-static void
+void
lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import)
{
/* imported module is freed directly from the context's list */
@@ -65,7 +65,7 @@
FREE_ARRAY(ctx, import->exts, lysp_ext_instance_free);
}
-static void
+void
lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include)
{
if (include->submodule) {
@@ -77,7 +77,7 @@
FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
}
-static void
+void
lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev)
{
FREE_STRING(ctx, rev->dsc);
@@ -85,7 +85,7 @@
FREE_ARRAY(ctx, rev->exts, lysp_ext_instance_free);
}
-static void
+void
lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext)
{
FREE_STRING(ctx, ext->name);
@@ -138,7 +138,7 @@
}
void lysc_type_free(struct ly_ctx *ctx, struct lysc_type *type);
-static void
+void
lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type)
{
FREE_STRING(ctx, type->name);
@@ -156,7 +156,7 @@
}
}
-static void
+void
lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf)
{
FREE_STRING(ctx, tpdf->name);
@@ -306,7 +306,7 @@
FREE_ARRAY(ctx, dev->exts, lysp_ext_instance_free);
}
-static void
+void
lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref)
{
FREE_STRING(ctx, ref->nodeid);
@@ -871,3 +871,20 @@
free(module);
}
+
+void
+lys_parser_ctx_free(struct lys_parser_ctx *ctx)
+{
+ if (ctx) {
+ free(ctx);
+ }
+}
+
+void
+yin_parser_ctx_free(struct yin_parser_ctx *ctx)
+{
+ if (ctx) {
+ lyxml_context_clear(&ctx->xml_ctx);
+ free(ctx);
+ }
+}
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 2f8a2b8..46d7801 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -424,6 +424,29 @@
return LY_ENOTFOUND;
}
+LY_ERR
+lysp_check_enum_name(struct lys_parser_ctx *ctx, const char *name, size_t name_len)
+{
+ if (!name_len) {
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not be zero-length.");
+ return LY_EVALID;
+ } else if (isspace(name[0]) || isspace(name[name_len - 1])) {
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Enum name must not have any leading or trailing whitespaces (\"%.*s\").",
+ name_len, name);
+ return LY_EVALID;
+ } else {
+ for (size_t u = 0; u < name_len; ++u) {
+ if (iscntrl(name[u])) {
+ LOGWRN(ctx->ctx, "Control characters in enum name should be avoided (\"%.*s\", character number %d).",
+ name_len, name, u + 1);
+ break;
+ }
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
/*
* @brief Check name of a new type to avoid name collisions.
*
@@ -512,6 +535,97 @@
}
LY_ERR
+lysp_parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
+ struct lysp_action *actions, struct lysp_notif *notifs)
+{
+ unsigned int u, v;
+ struct lysp_node *child;
+
+ /* finalize parent pointers to the reallocated items */
+
+ /* gropings */
+ LY_ARRAY_FOR(groupings, u) {
+ LY_LIST_FOR(groupings[u].data, child) {
+ child->parent = (struct lysp_node*)&groupings[u];
+ }
+ LY_ARRAY_FOR(groupings[u].actions, v) {
+ groupings[u].actions[v].parent = (struct lysp_node*)&groupings[u];
+ }
+ LY_ARRAY_FOR(groupings[u].notifs, v) {
+ groupings[u].notifs[v].parent = (struct lysp_node*)&groupings[u];
+ }
+ LY_ARRAY_FOR(groupings[u].groupings, v) {
+ groupings[u].groupings[v].parent = (struct lysp_node*)&groupings[u];
+ }
+ if (groupings[u].typedefs) {
+ ly_set_add(&ctx->tpdfs_nodes, &groupings[u], 0);
+ }
+ }
+
+ /* augments */
+ LY_ARRAY_FOR(augments, u) {
+ LY_LIST_FOR(augments[u].child, child) {
+ child->parent = (struct lysp_node*)&augments[u];
+ }
+ LY_ARRAY_FOR(augments[u].actions, v) {
+ augments[u].actions[v].parent = (struct lysp_node*)&augments[u];
+ }
+ LY_ARRAY_FOR(augments[u].notifs, v) {
+ augments[u].notifs[v].parent = (struct lysp_node*)&augments[u];
+ }
+ }
+
+ /* actions */
+ LY_ARRAY_FOR(actions, u) {
+ if (actions[u].input.parent) {
+ actions[u].input.parent = (struct lysp_node*)&actions[u];
+ LY_LIST_FOR(actions[u].input.data, child) {
+ child->parent = (struct lysp_node*)&actions[u].input;
+ }
+ LY_ARRAY_FOR(actions[u].input.groupings, v) {
+ actions[u].input.groupings[v].parent = (struct lysp_node*)&actions[u].input;
+ }
+ if (actions[u].input.typedefs) {
+ ly_set_add(&ctx->tpdfs_nodes, &actions[u].input, 0);
+ }
+ }
+ if (actions[u].output.parent) {
+ actions[u].output.parent = (struct lysp_node*)&actions[u];
+ LY_LIST_FOR(actions[u].output.data, child) {
+ child->parent = (struct lysp_node*)&actions[u].output;
+ }
+ LY_ARRAY_FOR(actions[u].output.groupings, v) {
+ actions[u].output.groupings[v].parent = (struct lysp_node*)&actions[u].output;
+ }
+ if (actions[u].output.typedefs) {
+ ly_set_add(&ctx->tpdfs_nodes, &actions[u].output, 0);
+ }
+ }
+ LY_ARRAY_FOR(actions[u].groupings, v) {
+ actions[u].groupings[v].parent = (struct lysp_node*)&actions[u];
+ }
+ if (actions[u].typedefs) {
+ ly_set_add(&ctx->tpdfs_nodes, &actions[u], 0);
+ }
+ }
+
+ /* notifications */
+ LY_ARRAY_FOR(notifs, u) {
+ LY_LIST_FOR(notifs[u].data, child) {
+ child->parent = (struct lysp_node*)¬ifs[u];
+ }
+ LY_ARRAY_FOR(notifs[u].groupings, v) {
+ notifs[u].groupings[v].parent = (struct lysp_node*)¬ifs[u];
+ }
+ if (notifs[u].typedefs) {
+ ly_set_add(&ctx->tpdfs_nodes, ¬ifs[u], 0);
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod)
{
struct hash_table *ids_global;
@@ -796,6 +910,41 @@
}
LY_ERR
+lysp_check_stringchar(struct lys_parser_ctx *ctx, unsigned int c)
+{
+ if (!is_yangutf8char(c)) {
+ LOGVAL_PARSER(ctx, LY_VCODE_INCHAR, c);
+ return LY_EVALID;
+ }
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lysp_check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix)
+{
+ if (first || (prefix && (*prefix) == 1)) {
+ if (!is_yangidentstartchar(c)) {
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid identifier first character '%c'.", c);
+ return LY_EVALID;
+ }
+ if (prefix) {
+ if (first) {
+ (*prefix) = 0;
+ } else {
+ (*prefix) = 2;
+ }
+ }
+ } else if (c == ':' && prefix && (*prefix) == 0) {
+ (*prefix) = 1;
+ } else if (!is_yangidentchar(c)) {
+ LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Invalid identifier character '%c'.", c);
+ return LY_EVALID;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
{
struct lysp_submodule *submod = NULL;
@@ -1261,6 +1410,210 @@
return NULL;
}
+enum yang_keyword
+lysp_match_kw(struct lys_parser_ctx *ctx, const char **data)
+{
+/**
+ * @brief Move the DATA pointer by COUNT items. Also updates the indent value in yang parser context
+ * @param[in] CTX yang parser context to update its indent value.
+ * @param[in,out] DATA pointer to move
+ * @param[in] COUNT number of items for which the DATA pointer is supposed to move on.
+ */
+#define MOVE_IN(CTX, DATA, COUNT) (*(DATA))+=COUNT;if(CTX){(CTX)->indent+=COUNT;}
+#define IF_KW(STR, LEN, STMT) if (!strncmp(*(data), STR, LEN)) {MOVE_IN(ctx, data, LEN);*kw=STMT;}
+#define IF_KW_PREFIX(STR, LEN) if (!strncmp(*(data), STR, LEN)) {MOVE_IN(ctx, data, LEN);
+#define IF_KW_PREFIX_END }
+
+ enum yang_keyword result = YANG_NONE;
+ enum yang_keyword *kw = &result;
+ /* read the keyword itself */
+ switch (**data) {
+ case 'a':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("rgument", 7, YANG_ARGUMENT)
+ else IF_KW("ugment", 6, YANG_AUGMENT)
+ else IF_KW("ction", 5, YANG_ACTION)
+ else IF_KW_PREFIX("ny", 2)
+ IF_KW("data", 4, YANG_ANYDATA)
+ else IF_KW("xml", 3, YANG_ANYXML)
+ IF_KW_PREFIX_END
+ break;
+ case 'b':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("ase", 3, YANG_BASE)
+ else IF_KW("elongs-to", 9, YANG_BELONGS_TO)
+ else IF_KW("it", 2, YANG_BIT)
+ break;
+ case 'c':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("ase", 3, YANG_CASE)
+ else IF_KW("hoice", 5, YANG_CHOICE)
+ else IF_KW_PREFIX("on", 2)
+ IF_KW("fig", 3, YANG_CONFIG)
+ else IF_KW_PREFIX("ta", 2)
+ IF_KW("ct", 2, YANG_CONTACT)
+ else IF_KW("iner", 4, YANG_CONTAINER)
+ IF_KW_PREFIX_END
+ IF_KW_PREFIX_END
+ break;
+ case 'd':
+ MOVE_IN(ctx, data, 1);
+ IF_KW_PREFIX("e", 1)
+ IF_KW("fault", 5, YANG_DEFAULT)
+ else IF_KW("scription", 9, YANG_DESCRIPTION)
+ else IF_KW_PREFIX("viat", 4)
+ IF_KW("e", 1, YANG_DEVIATE)
+ else IF_KW("ion", 3, YANG_DEVIATION)
+ IF_KW_PREFIX_END
+ IF_KW_PREFIX_END
+ break;
+ case 'e':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("num", 3, YANG_ENUM)
+ else IF_KW_PREFIX("rror-", 5)
+ IF_KW("app-tag", 7, YANG_ERROR_APP_TAG)
+ else IF_KW("message", 7, YANG_ERROR_MESSAGE)
+ IF_KW_PREFIX_END
+ else IF_KW("xtension", 8, YANG_EXTENSION)
+ break;
+ case 'f':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("eature", 6, YANG_FEATURE)
+ else IF_KW("raction-digits", 14, YANG_FRACTION_DIGITS)
+ break;
+ case 'g':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("rouping", 7, YANG_GROUPING)
+ break;
+ case 'i':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("dentity", 7, YANG_IDENTITY)
+ else IF_KW("f-feature", 9, YANG_IF_FEATURE)
+ else IF_KW("mport", 5, YANG_IMPORT)
+ else IF_KW_PREFIX("n", 1)
+ IF_KW("clude", 5, YANG_INCLUDE)
+ else IF_KW("put", 3, YANG_INPUT)
+ IF_KW_PREFIX_END
+ break;
+ case 'k':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("ey", 2, YANG_KEY)
+ break;
+ case 'l':
+ MOVE_IN(ctx, data, 1);
+ IF_KW_PREFIX("e", 1)
+ IF_KW("af-list", 7, YANG_LEAF_LIST)
+ else IF_KW("af", 2, YANG_LEAF)
+ else IF_KW("ngth", 4, YANG_LENGTH)
+ IF_KW_PREFIX_END
+ else IF_KW("ist", 3, YANG_LIST)
+ break;
+ case 'm':
+ MOVE_IN(ctx, data, 1);
+ IF_KW_PREFIX("a", 1)
+ IF_KW("ndatory", 7, YANG_MANDATORY)
+ else IF_KW("x-elements", 10, YANG_MAX_ELEMENTS)
+ IF_KW_PREFIX_END
+ else IF_KW("in-elements", 11, YANG_MIN_ELEMENTS)
+ else IF_KW("ust", 3, YANG_MUST)
+ else IF_KW_PREFIX("od", 2)
+ IF_KW("ule", 3, YANG_MODULE)
+ else IF_KW("ifier", 5, YANG_MODIFIER)
+ IF_KW_PREFIX_END
+ break;
+ case 'n':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("amespace", 8, YANG_NAMESPACE)
+ else IF_KW("otification", 11, YANG_NOTIFICATION)
+ break;
+ case 'o':
+ MOVE_IN(ctx, data, 1);
+ IF_KW_PREFIX("r", 1)
+ IF_KW("dered-by", 8, YANG_ORDERED_BY)
+ else IF_KW("ganization", 10, YANG_ORGANIZATION)
+ IF_KW_PREFIX_END
+ else IF_KW("utput", 5, YANG_OUTPUT)
+ break;
+ case 'p':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("ath", 3, YANG_PATH)
+ else IF_KW("attern", 6, YANG_PATTERN)
+ else IF_KW("osition", 7, YANG_POSITION)
+ else IF_KW_PREFIX("re", 2)
+ IF_KW("fix", 3, YANG_PREFIX)
+ else IF_KW("sence", 5, YANG_PRESENCE)
+ IF_KW_PREFIX_END
+ break;
+ case 'r':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("ange", 4, YANG_RANGE)
+ else IF_KW_PREFIX("e", 1)
+ IF_KW_PREFIX("f", 1)
+ IF_KW("erence", 6, YANG_REFERENCE)
+ else IF_KW("ine", 3, YANG_REFINE)
+ IF_KW_PREFIX_END
+ else IF_KW("quire-instance", 14, YANG_REQUIRE_INSTANCE)
+ else IF_KW("vision-date", 11, YANG_REVISION_DATE)
+ else IF_KW("vision", 6, YANG_REVISION)
+ IF_KW_PREFIX_END
+ else IF_KW("pc", 2, YANG_RPC)
+ break;
+ case 's':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("tatus", 5, YANG_STATUS)
+ else IF_KW("ubmodule", 8, YANG_SUBMODULE)
+ break;
+ case 't':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("ypedef", 6, YANG_TYPEDEF)
+ else IF_KW("ype", 3, YANG_TYPE)
+ break;
+ case 'u':
+ MOVE_IN(ctx, data, 1);
+ IF_KW_PREFIX("ni", 2)
+ IF_KW("que", 3, YANG_UNIQUE)
+ else IF_KW("ts", 2, YANG_UNITS)
+ IF_KW_PREFIX_END
+ else IF_KW("ses", 3, YANG_USES)
+ break;
+ case 'v':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("alue", 4, YANG_VALUE)
+ break;
+ case 'w':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("hen", 3, YANG_WHEN)
+ break;
+ case 'y':
+ MOVE_IN(ctx, data, 1);
+ IF_KW("ang-version", 11, YANG_YANG_VERSION)
+ else IF_KW("in-element", 10, YANG_YIN_ELEMENT)
+ break;
+ default:
+ /* if context is not NULL we are matching keyword from YANG data*/
+ if (ctx) {
+ if (**data == ';') {
+ MOVE_IN(ctx, data, 1);
+ *kw = YANG_SEMICOLON;
+ } else if (**data == '{') {
+ MOVE_IN(ctx, data, 1);
+ *kw = YANG_LEFT_BRACE;
+ } else if (**data == '}') {
+ MOVE_IN(ctx, data, 1);
+ *kw = YANG_RIGHT_BRACE;
+ }
+ }
+ break;
+ }
+
+#undef IF_KW
+#undef IF_KW_PREFIX
+#undef IF_KW_PREFIX_END
+#undef MOVE_IN
+
+ return result;
+}
+
unsigned int
lysp_ext_instance_iter(struct lysp_ext_instance *ext, unsigned int index, LYEXT_SUBSTMT substmt)
{
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 8e9e029..1ff883d 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -20,13 +20,51 @@
#include "plugins_exts.h"
#include "set.h"
#include "tree_schema.h"
+#include "xml.h"
-#define LOGVAL_YANG(CTX, ...) LOGVAL((CTX)->ctx, LY_VLOG_LINE, &(CTX)->line, __VA_ARGS__)
+#define LOGVAL_PARSER(CTX, ...) LOGVAL((CTX)->ctx, LY_VLOG_LINE, &(CTX)->line, __VA_ARGS__)
/* These 2 macros checks YANG's identifier grammar rule */
#define is_yangidentstartchar(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')
#define is_yangidentchar(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || \
- c == '_' || c == '-' || c == '.')
+ c == '_' || c == '-' || c == '.')
+
+/* Macro to check YANG's yang-char grammar rule */
+#define is_yangutf8char(c) ((c >= 0x20 && c <= 0xd7ff) || c == 0x09 || c == 0x0a || c == 0x0d || \
+ (c >= 0xe000 && c <= 0xfdcf) || (c >= 0xfdf0 && c <= 0xfffd) || \
+ (c >= 0x10000 && c <= 0x1fffd) || (c >= 0x20000 && c <= 0x2fffd) || \
+ (c >= 0x30000 && c <= 0x3fffd) || (c >= 0x40000 && c <= 0x2fffd) || \
+ (c >= 0x50000 && c <= 0x5fffd) || (c >= 0x60000 && c <= 0x6fffd) || \
+ (c >= 0x70000 && c <= 0x7fffd) || (c >= 0x80000 && c <= 0x8fffd) || \
+ (c >= 0x90000 && c <= 0x9fffd) || (c >= 0xa0000 && c <= 0xafffd) || \
+ (c >= 0xb0000 && c <= 0xbfffd) || (c >= 0xc0000 && c <= 0xcfffd) || \
+ (c >= 0xd0000 && c <= 0xdfffd) || (c >= 0xe0000 && c <= 0xefffd) || \
+ (c >= 0xf0000 && c <= 0xffffd) || (c >= 0x100000 && c <= 0x10fffd))
+
+/**
+ * @brief Try to find object with MEMBER string matching the IDENT in the given ARRAY.
+ * Macro logs an error message and returns LY_EVALID in case of existence of a matching object.
+ *
+ * @param[in] CTX yang parser context for logging.
+ * @param[in] ARRAY [sized array](@ref sizedarrays) of a generic objects with member named MEMBER to search.
+ * @param[in] MEMBER Name of the member of the objects in the ARRAY to compare.
+ * @param[in] STMT Name of the compared YANG statements for logging.
+ * @param[in] IDENT String trying to find in the ARRAY's objects inside the MEMBER member.
+ */
+#define CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, STMT, IDENT) \
+ if (ARRAY) { \
+ for (unsigned int u = 0; u < LY_ARRAY_SIZE(ARRAY) - 1; ++u) { \
+ if (!strcmp((ARRAY)[u].MEMBER, IDENT)) { \
+ LOGVAL_PARSER(CTX, LY_VCODE_DUPIDENT, IDENT, STMT); \
+ return LY_EVALID; \
+ } \
+ } \
+ }
+
+#define YANG_CHECK_NONEMPTY(CTX, VALUE_LEN, STMT) \
+ if (!VALUE_LEN) { \
+ LOGWRN((CTX)->ctx, "Empty argument of %s statement does not make sense.", STMT); \
+ }
/**
* @brief List of YANG statement groups - the (sub)module's substatements
@@ -50,17 +88,39 @@
};
/**
- * @brief internal context for schema parsers
+ * @brief Internal context for yang schema parser.
*/
struct lys_parser_ctx {
- struct ly_ctx *ctx;
- struct ly_set tpdfs_nodes;
- struct ly_set grps_nodes;
- uint64_t line; /**< line number */
- uint64_t indent; /**< current position on the line for YANG indentation */
- uint8_t mod_version; /**< module's version */
+ struct ly_set tpdfs_nodes; /**< set of typedef nodes */
+ struct ly_set grps_nodes; /**< set of grouping nodes */
+ uint8_t mod_version; /**< module's version */
+ struct ly_ctx *ctx; /**< context of then yang schemas */
+ uint64_t line; /**< line number */
+ uint64_t indent; /**< current position on the line for YANG indentation */
};
+/**
+ * @brief free lys parser context.
+ */
+void lys_parser_ctx_free(struct lys_parser_ctx *ctx);
+
+/**
+ * @brief Internal context for yin schema parser.
+ */
+struct yin_parser_ctx {
+ struct ly_set tpdfs_nodes; /**< set of typedef nodes */
+ struct ly_set grps_nodes; /**< set of grouping nodes */
+ uint8_t mod_version; /**< module's version */
+ struct lyxml_context xml_ctx; /**< context for xml parser */
+};
+
+/**
+ * @brief free yin parser context
+ *
+ * @param[in] ctx Context to free.
+ */
+void yin_parser_ctx_free(struct yin_parser_ctx *ctx);
+
struct lysc_incomplete_dflt {
struct lyd_value *dflt;
struct lys_module *dflt_mod;
@@ -68,6 +128,31 @@
};
/**
+ * @brief Check that \p c is valid UTF8 code point for YANG string.
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in] c UTF8 code point of a character to check.
+ * @return LY_ERR values.
+ */
+LY_ERR lysp_check_stringchar(struct lys_parser_ctx *ctx, unsigned int c);
+
+/**
+ * @brief Check that \p c is valid UTF8 code point for YANG identifier.
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in] c UTF8 code point of a character to check.
+ * @param[in] first Flag to check the first character of an identifier, which is more restricted.
+ * @param[in,out] prefix Storage for internally used flag in case of possible prefixed identifiers:
+ * 0 - colon not yet found (no prefix)
+ * 1 - \p c is the colon character
+ * 2 - prefix already processed, now processing the identifier
+ *
+ * If the identifier cannot be prefixed, NULL is expected.
+ * @return LY_ERR values.
+ */
+LY_ERR lysp_check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix);
+
+/**
* @brief Internal structure for lys_get_prefix().
*/
struct lys_get_prefix_data {
@@ -126,13 +211,26 @@
LY_ERR lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod);
/**
+ * @brief Finalize some of the structures in case they are stored in sized array,
+ * which can be possibly reallocated and some other data may point to them.
+ *
+ * Update parent pointers in the nodes inside grouping/augment/RPC/Notification, which could be reallocated.
+ *
+ * @param[in] mod Parsed module to be updated.
+ * @return LY_ERR value (currently only LY_SUCCESS, but it can change in future).
+ */
+LY_ERR
+lysp_parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
+ struct lysp_action *actions, struct lysp_notif *notifs);
+
+/**
* @brief Just move the newest revision into the first position, does not sort the rest
* @param[in] revs Sized-array of the revisions in a printable schema tree.
*/
void lysp_sort_revisions(struct lysp_revision *revs);
/**
- * @brief Find type specified type definition
+ * @brief Find type specified type definition.
*
* @param[in] id Name of the type including possible prefix. Module where the prefix is being searched is start_module.
* @param[in] start_node Context node where the type is being instantiated to be able to search typedefs in parents.
@@ -146,6 +244,17 @@
LY_DATA_TYPE *type, const struct lysp_tpdf **tpdf, struct lysp_node **node, struct lysp_module **module);
/**
+ * @brief Validate enum name.
+ *
+ * @param[in] ctx yang parser context for logging.
+ * @param[in] name String to check.
+ * @param[in] name_len Length of name.
+ *
+ * @return LY_ERR values
+ */
+LY_ERR lysp_check_enum_name(struct lys_parser_ctx *ctx, const char *name, size_t name_len);
+
+/**
* @brief Find and parse module of the given name.
*
* @param[in] ctx libyang context.
@@ -668,12 +777,15 @@
/**
* @brief Parse submodule from YANG data.
- * @param[in] ctx Parser context.
+ * @param[in,out] ctx Parser context.
+ * @param[in] ly_ctx Context of YANG schemas.
+ * @param[in] main_ctx Parser context of main module.
* @param[in] data Input data to be parsed.
* @param[out] submod Pointer to the parsed submodule structure.
* @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
*/
-LY_ERR yang_parse_submodule(struct lys_parser_ctx *ctx, const char *data, struct lysp_submodule **submod);
+LY_ERR yang_parse_submodule(struct lys_parser_ctx **context, struct ly_ctx *ly_ctx, struct lys_parser_ctx *main_ctx,
+ const char *data, struct lysp_submodule **submod);
/**
* @brief Parse module from YANG data.
@@ -683,7 +795,34 @@
* module structure, will be filled in.
* @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
*/
-LY_ERR yang_parse_module(struct lys_parser_ctx *ctx, const char *data, struct lys_module *mod);
+LY_ERR yang_parse_module(struct lys_parser_ctx **context, const char *data, struct lys_module *mod);
+
+/**
+ * @brief Parse module from YIN data.
+ *
+ * @param[in,out] yin_ctx Context created during parsing, is used to finalize lysp_model after it's completly parsed.
+ * @param[in] data Input data to be parsed.
+ * @param[in,out] mod Prepared module structure where the parsed information, including the parsed
+ * module structure, will be filled in.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_module(struct yin_parser_ctx **yin_ctx, const char *data, struct lys_module *mod);
+
+/**
+ * @brief Parse submodule from YIN data.
+ *
+ * @param[in,out] yin_ctx Context created during parsing, is used to finalize lysp_model after it's completly parsed.
+ * @param[in] ctx Libyang context.
+ * @param[in] main_ctx Parser context of main module.
+ * @param[in,out] data Input data to be parsed.
+ * @param[in,out] submod Submodule structure where the parsed information, will be filled in.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_submodule(struct yin_parser_ctx **yin_ctx, struct ly_ctx *ctx, struct lys_parser_ctx *main_ctx,
+ const char *data, struct lysp_submodule **submod);
+
/**
* @brief Make the specific module implemented, use the provided value as flag.
@@ -697,4 +836,14 @@
*/
LY_ERR ly_ctx_module_implement_internal(struct ly_ctx *ctx, struct lys_module *mod, uint8_t implemented);
+/**
+ * @brief match yang keyword
+ *
+ * param[in] ctx yang parser context for logging, can be NULL if keyword is from YIN data.
+ * param[in,out] data Data to read from, always moved to currently handled character.
+ *
+ * return yang_keyword values.
+ */
+enum yang_keyword lysp_match_kw(struct lys_parser_ctx *ctx, const char **data);
+
#endif /* LY_TREE_SCHEMA_INTERNAL_H_ */
diff --git a/src/xml.c b/src/xml.c
index dd556bd..a08417c 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -720,7 +720,7 @@
e = (struct lyxml_elem*)context->elements.objs[context->elements.count - 1];
LY_CHECK_ERR_GOTO(e->prefix_len != prefix_len || e->name_len != name_len
|| (prefix_len && strncmp(prefix, e->prefix, e->prefix_len)) || strncmp(name, e->name, e->name_len),
- free(e); LOGVAL(ctx, LY_VLOG_LINE, &fakecontext.line, LYVE_SYNTAX,
+ free(e); --context->elements.count; LOGVAL(ctx, LY_VLOG_LINE, &fakecontext.line, LYVE_SYNTAX,
"Opening and closing elements tag missmatch (\"%.*s\").", name_len, name),
error);
/* opening and closing element tags matches */
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
new file mode 100644
index 0000000..8ed9c90
--- /dev/null
+++ b/tests/fuzz/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+set(fuzz_targets yangfuzz)
+
+foreach(target_name IN LISTS fuzz_targets)
+ add_executable(${target_name} ${target_name}.c)
+ target_link_libraries(${target_name} yang)
+endforeach(target_name)
diff --git a/tests/fuzz/README.md b/tests/fuzz/README.md
new file mode 100644
index 0000000..e07193f
--- /dev/null
+++ b/tests/fuzz/README.md
@@ -0,0 +1,40 @@
+# FUZZING
+yangfuzz, a simple YANG fuzz harness is available in this directory and
+is designed to be used with the [AFL](http://lcamtuf.coredump.cx/afl/) fuzzer.
+
+To build the fuzz target, the ENABLE_FUZZ_TARGETS option has to be enabled.
+
+To add AFL instrumentation when compiling libyang, the AFL clang-fast compiler
+should be used with the following cmake option:
+
+It is reccomended to set the build type to Release, since otherwise the fuzzer will detect failed asserts as crashes.
+
+```
+$ cmake -DENABLE_FUZZ_TARGETS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=path_to_afl/afl-clang-fast ..
+```
+
+After that the programs can be built by running make:
+```
+$ make
+```
+
+The yangfuzz executable will then be available in the root of the build directory that was used.
+
+The libyang yang test files available in the `tests/data/files` subdirectory can be used as initial
+test cases for fuzzing the programs with AFL.
+
+The files that will be used as starting test cases should be copied into a single directory. Those files should then be minimized by using afl-cmin and afl-tmin.
+Also, AFL will issue a warning about a decrease of performance when working with large files, so only smaller test cases should be used.
+
+To increase the speed of fuzzing, the test cases and AFL output files should be stored on a temporary RAM disk.
+If a new fuzz target is used, AFL persistent mode should be used. More about persistent mode can be read in the official AFL documentation.
+
+When all of the above is done the fuzzing process can begin. AFL supports running multiple instances of the fuzzer, which can speed up the
+process on multi core CPUs. The first fuzz instance should be started in master mode, and the other instances in slave mode.
+The total number of instances should usually be equal to the number of cores.
+
+Below is an example of running 2 instances. The -i flag specifies the testcase input directory, and the -o file specifies the directory the fuzzer will use for output.
+```
+afl-fuzz -i minimised_testcases/ -o syncdir/ -M fuzzer1 -- libyang/build/fuzz/yangfuzz @@
+afl-fuzz -i minimised_testcases/ -o syncdir/ -S fuzzer2 -- libyang/build/fuzz/yangfuzz @@
+```
diff --git a/tests/fuzz/yangfuzz.c b/tests/fuzz/yangfuzz.c
new file mode 100644
index 0000000..06d6076
--- /dev/null
+++ b/tests/fuzz/yangfuzz.c
@@ -0,0 +1,27 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libyang.h"
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "invalid usage\n");
+ exit(EXIT_FAILURE);
+ }
+
+
+ struct ly_ctx *ctx = NULL;
+ LY_ERR err;
+ while (__AFL_LOOP(100)) {
+ err = ly_ctx_new(NULL, 0, &ctx);
+ if (err != LY_SUCCESS) {
+ fprintf(stderr, "Failed to create context\n");
+ exit(EXIT_FAILURE);
+ }
+
+ lys_parse_path(ctx, argv[1], LYS_IN_YANG);
+ ly_ctx_destroy(ctx, NULL);
+ }
+
+ return 0;
+}
diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt
index c5ded11..fa021c9 100644
--- a/tests/src/CMakeLists.txt
+++ b/tests/src/CMakeLists.txt
@@ -5,6 +5,7 @@
src_hash_table
src_xml
src_parser_yang
+ src_parser_yin
src_tree_schema
src_tree_schema_compile
src_tree_schema_helpers
@@ -25,6 +26,7 @@
" "
" "
" "
+ " "
" ")
set(tests ${tests} ${local_tests} PARENT_SCOPE)
set(tests_wraps ${tests_wraps} ${local_tests_wraps} PARENT_SCOPE)
diff --git a/tests/src/test_context.c b/tests/src/test_context.c
index 78deffe..58f52d4 100644
--- a/tests/src/test_context.c
+++ b/tests/src/test_context.c
@@ -283,7 +283,7 @@
assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
assert_int_equal(ctx->module_set_id, ly_ctx_get_module_set_id(ctx));
- assert_null(lys_parse_mem_module(ctx, "module x {namespace urn:x;prefix x;}", 3, 1, NULL, NULL));
+ assert_null(lys_parse_mem_module(ctx, "module x {namespace urn:x;prefix x;}", 4, 1, NULL, NULL));
logbuf_assert("Invalid schema input format.");
/* import callback */
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index 0d6263d..e4adfd7 100644
--- a/tests/src/test_parser_yang.c
+++ b/tests/src/test_parser_yang.c
@@ -38,13 +38,12 @@
void lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when);
LY_ERR buf_add_char(struct ly_ctx *ctx, const char **input, size_t len, char **buf, size_t *buf_len, size_t *buf_used);
-LY_ERR buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg,
- char **word_p, size_t *word_len, char **word_b, size_t *buf_len, int need_buf);
+LY_ERR buf_store_char(struct lys_parser_ctx *ctx, const char **input, enum yang_arg arg, char **word_p,
+ size_t *word_len, char **word_b, size_t *buf_len, int need_buf, int *prefix);
LY_ERR get_keyword(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, size_t *word_len);
LY_ERR get_argument(struct lys_parser_ctx *ctx, const char **data, enum yang_arg arg,
uint16_t *flags, char **word_p, char **word_b, size_t *word_len);
LY_ERR skip_comment(struct lys_parser_ctx *ctx, const char **data, int comment);
-LY_ERR check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix);
LY_ERR parse_action(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions);
LY_ERR parse_any(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node *parent, struct lysp_node **siblings);
@@ -67,6 +66,7 @@
LY_ERR parse_submodule(struct lys_parser_ctx *ctx, const char **data, struct lysp_submodule *submod);
LY_ERR parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
LY_ERR parse_when(struct lys_parser_ctx *ctx, const char **data, struct lysp_when **when_p);
+LY_ERR parse_type_enum_value_pos(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags, struct lysp_ext_instance **exts);
#define BUFSIZE 1024
char logbuf[BUFSIZE] = {0};
@@ -141,10 +141,10 @@
const char *str;
char *buf, *p;
size_t len, size;
- int prefix;
struct lys_parser_ctx ctx;
ctx.ctx = NULL;
ctx.line = 1;
+ int prefix = 0;
/* storing into buffer */
str = "abcd";
@@ -161,48 +161,50 @@
/* invalid first characters */
len = 0;
str = "2invalid";
- assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+ assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
str = ".invalid";
- assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+ assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
str = "-invalid";
- assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+ assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
/* invalid following characters */
len = 3; /* number of characters read before the str content */
str = "!";
- assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+ assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
str = ":";
- assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+ assert_int_equal(LY_EVALID, buf_store_char(&ctx, &str, Y_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
/* valid colon for prefixed identifiers */
len = size = 0;
p = NULL;
+ prefix = 0;
str = "x:id";
- assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 0));
+ assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 0, &prefix));
assert_int_equal(1, len);
assert_null(buf);
assert_string_equal(":id", str);
assert_int_equal('x', p[len - 1]);
- assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 1));
+ assert_int_equal(LY_SUCCESS, buf_store_char(&ctx, &str, Y_PREF_IDENTIF_ARG, &p, &len, &buf, &size, 1, &prefix));
assert_int_equal(2, len);
assert_string_equal("id", str);
assert_int_equal(':', p[len - 1]);
free(buf);
+ prefix = 0;
/* checking identifiers */
- assert_int_equal(LY_EVALID, check_identifierchar(&ctx, ':', 0, NULL));
+ assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, ':', 0, NULL));
logbuf_assert("Invalid identifier character ':'. Line number 1.");
- assert_int_equal(LY_EVALID, check_identifierchar(&ctx, '#', 1, NULL));
+ assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, '#', 1, NULL));
logbuf_assert("Invalid identifier first character '#'. Line number 1.");
- assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, 'a', 1, &prefix));
+ assert_int_equal(LY_SUCCESS, lysp_check_identifierchar(&ctx, 'a', 1, &prefix));
assert_int_equal(0, prefix);
- assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, ':', 0, &prefix));
+ assert_int_equal(LY_SUCCESS, lysp_check_identifierchar(&ctx, ':', 0, &prefix));
assert_int_equal(1, prefix);
- assert_int_equal(LY_EVALID, check_identifierchar(&ctx, ':', 0, &prefix));
+ assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, ':', 0, &prefix));
assert_int_equal(1, prefix);
- assert_int_equal(LY_SUCCESS, check_identifierchar(&ctx, 'b', 0, &prefix));
+ assert_int_equal(LY_SUCCESS, lysp_check_identifierchar(&ctx, 'b', 0, &prefix));
assert_int_equal(2, prefix);
/* second colon is invalid */
- assert_int_equal(LY_EVALID, check_identifierchar(&ctx, ':', 0, &prefix));
+ assert_int_equal(LY_EVALID, lysp_check_identifierchar(&ctx, ':', 0, &prefix));
logbuf_assert("Invalid identifier character ':'. Line number 1.");
}
@@ -282,6 +284,10 @@
assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_STR_ARG, NULL, &word, &buf, &len));
logbuf_assert("Invalid character sequence \"}\", expected unquoted string character, optsep, semicolon or opening brace. Line number 1.");
+ /* invalid identifier-ref-arg-str */
+ str = "pre:pre:value";
+ assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_PREF_IDENTIF_ARG, NULL, &word, &buf, &len));
+
str = "\"\";"; /* empty identifier is not allowed */
assert_int_equal(LY_EVALID, get_argument(&ctx, &str, Y_IDENTIF_ARG, NULL, &word, &buf, &len));
logbuf_assert("Statement argument is required. Line number 1.");
@@ -1041,20 +1047,33 @@
assert_int_equal(2, mod->mod->version);
mod = mod_renew(&ctx);
+ struct lys_parser_ctx *ctx_p = NULL;
str = "module " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
m = mod->mod;
free(mod);
m->parsed = NULL;
- assert_int_equal(LY_EVALID, yang_parse_module(&ctx, str, m));
- logbuf_assert("Trailing garbage \"module q {names...\" after module, expected end-of-input. Line number 3.");
+ assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, str, m));
+ logbuf_assert("Trailing garbage \"module q {names...\" after module, expected end-of-input. Line number 1.");
+ lys_parser_ctx_free(ctx_p);
mod = mod_renew(&ctx);
str = "prefix " SCHEMA_BEGINNING "}";
m = mod->mod;
free(mod);
m->parsed = NULL;
- assert_int_equal(LY_EVALID, yang_parse_module(&ctx, str, m));
- logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 3.");
+ assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, str, m));
+ lys_parser_ctx_free(ctx_p);
+ logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 1.");
+ mod = mod_renew(&ctx);
+
+ str = "module " SCHEMA_BEGINNING "}";
+ str = "module " SCHEMA_BEGINNING "leaf enum {type enumeration {enum seven { position 7;}}}}";
+ m = mod->mod;
+ free(mod);
+ m->parsed = NULL;
+ assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, str, m));
+ lys_parser_ctx_free(ctx_p);
+ logbuf_assert("Invalid keyword \"position\" as a child of \"enum\". Line number 1.");
mod = mod_renew(&ctx);
/* extensions */
@@ -1108,12 +1127,14 @@
str = "submodule " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
lysp_submodule_free(ctx.ctx, submod);
submod = NULL;
- assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx, str, &submod));
- logbuf_assert("Trailing garbage \"module q {names...\" after submodule, expected end-of-input. Line number 3.");
+ assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, ctx.ctx, &ctx, str, &submod));
+ lys_parser_ctx_free(ctx_p);
+ logbuf_assert("Trailing garbage \"module q {names...\" after submodule, expected end-of-input. Line number 1.");
str = "prefix " SCHEMA_BEGINNING "}";
- assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx, str, &submod));
- logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 3.");
+ assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, ctx.ctx, &ctx, str, &submod));
+ lys_parser_ctx_free(ctx_p);
+ logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 1.");
submod = submod_renew(&ctx, submod);
#undef TEST_GENERIC
@@ -2193,6 +2214,32 @@
ly_ctx_destroy(ctx.ctx, NULL);
}
+static void
+test_value(void **state)
+{
+ *state = test_value;
+ struct lys_parser_ctx ctx;
+
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
+ assert_non_null(ctx.ctx);
+ ctx.line = 1;
+ ctx.indent = 0;
+ int64_t val = 0;
+ uint16_t flags = 0;
+
+ const char *data = "-0;";
+ assert_int_equal(parse_type_enum_value_pos(&ctx, &data, YANG_VALUE, &val, &flags, NULL), LY_SUCCESS);
+ assert_int_equal(val, 0);
+
+ data = "-0;";
+ flags = 0;
+ assert_int_equal(parse_type_enum_value_pos(&ctx, &data, YANG_POSITION, &val, &flags, NULL), LY_EVALID);
+ logbuf_assert("Invalid value \"-0\" of \"position\". Line number 1.");
+
+ *state = NULL;
+ ly_ctx_destroy(ctx.ctx, NULL);
+}
+
int main(void)
{
const struct CMUnitTest tests[] = {
@@ -2220,6 +2267,7 @@
cmocka_unit_test_setup_teardown(test_uses, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_augment, logger_setup, logger_teardown),
cmocka_unit_test_setup_teardown(test_when, logger_setup, logger_teardown),
+ cmocka_unit_test_setup_teardown(test_value, logger_setup, logger_teardown),
};
return cmocka_run_group_tests(tests, NULL, NULL);
diff --git a/tests/src/test_parser_yin.c b/tests/src/test_parser_yin.c
new file mode 100644
index 0000000..5ddba08
--- /dev/null
+++ b/tests/src/test_parser_yin.c
@@ -0,0 +1,4437 @@
+/**
+ * @file test_parser_yin.c
+ * @author David Sedlák <xsedla1d@stud.fit.vutbr.cz>
+ * @brief unit tests for functions from parser_yin.c
+ *
+ * Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "../../src/common.h"
+#include "../../src/tree_schema.h"
+#include "../../src/tree_schema_internal.h"
+#include "../../src/parser_yin.h"
+#include "../../src/xml.h"
+
+/* prototypes of static functions */
+void lysp_ext_instance_free(struct ly_ctx *ctx, struct lysp_ext_instance *ext);
+void lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext);
+void lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when);
+void lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type);
+void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node);
+void lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf);
+void lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref);
+void lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev);
+void lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include);
+void lysp_feature_free(struct ly_ctx *ctx, struct lysp_feature *feat);
+void lysp_ident_free(struct ly_ctx *ctx, struct lysp_ident *ident);
+void lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif);
+void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp);
+void lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout);
+void lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action);
+void lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment);
+void lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d);
+void lysp_deviation_free(struct ly_ctx *ctx, struct lysp_deviation *dev);
+void lysp_submodule_free(struct ly_ctx *ctx, struct lysp_submodule *submod);
+void lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import);
+
+/* wrapping element used for mocking has nothing to do with real module structure */
+#define ELEMENT_WRAPPER_START "<status xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+#define ELEMENT_WRAPPER_END "</status>"
+
+struct state {
+ struct ly_ctx *ctx;
+ struct lys_module *mod;
+ struct lysp_module *lysp_mod;
+ struct yin_parser_ctx *yin_ctx;
+ bool finished_correctly;
+};
+
+#define BUFSIZE 1024
+char logbuf[BUFSIZE] = {0};
+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
+
+#if ENABLE_LOGGER_CHECKING
+static void
+logger(LY_LOG_LEVEL level, const char *msg, const char *path)
+{
+ (void) level; /* unused */
+ if (store) {
+ if (path && path[0]) {
+ snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
+ } else {
+ strncpy(logbuf, msg, BUFSIZE - 1);
+ }
+ if (store > 0) {
+ --store;
+ }
+ }
+}
+#endif
+
+#if ENABLE_LOGGER_CHECKING
+# define logbuf_assert(str) assert_string_equal(logbuf, str)
+#else
+# define logbuf_assert(str)
+#endif
+
+#define TEST_DUP_GENERIC(PREFIX, MEMBER, VALUE1, VALUE2, FUNC, RESULT, LINE, CLEANUP) \
+ str = PREFIX MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
+ assert_int_equal(LY_EVALID, FUNC(&ctx, &str, RESULT)); \
+ logbuf_assert("Duplicate keyword \""MEMBER"\". Line number "LINE"."); \
+ CLEANUP
+
+int
+setup_ly_ctx(void **state)
+{
+ struct state *st = NULL;
+
+ /* allocate state variable */
+ (*state) = st = calloc(1, sizeof(*st));
+ if (!st) {
+ fprintf(stderr, "Memmory allocation failed");
+ return EXIT_FAILURE;
+ }
+
+ /* create new libyang context */
+ ly_ctx_new(NULL, 0, &st->ctx);
+
+ return EXIT_SUCCESS;
+}
+
+int
+destroy_ly_ctx(void **state)
+{
+ struct state *st = *state;
+ ly_ctx_destroy(st->ctx, NULL);
+ free(st);
+
+ return EXIT_SUCCESS;
+}
+
+static int
+setup_f(void **state)
+{
+ struct state *st = *state;
+
+#if ENABLE_LOGGER_CHECKING
+ /* setup logger */
+ ly_set_log_clb(logger, 1);
+#endif
+
+ /* allocate new module */
+ st->mod = calloc(1, sizeof(*st->mod));
+ st->mod->ctx = st->ctx;
+
+ /* allocate new parsed module */
+ st->lysp_mod = calloc(1, sizeof(*st->lysp_mod));
+ st->lysp_mod->mod = calloc(1, sizeof(*st->lysp_mod->mod));
+ st->lysp_mod->mod->ctx = st->ctx;
+
+ /* allocate parser context */
+ st->yin_ctx = calloc(1, sizeof(*st->yin_ctx));
+ st->yin_ctx->xml_ctx.ctx = st->ctx;
+ st->yin_ctx->xml_ctx.line = 1;
+
+ return EXIT_SUCCESS;
+}
+
+static int
+teardown_f(void **state)
+{
+ struct state *st = *(struct state **)state;
+ struct lys_module *temp;
+
+#if ENABLE_LOGGER_CHECKING
+ /* teardown logger */
+ if (!st->finished_correctly && logbuf[0] != '\0') {
+ fprintf(stderr, "%s\n", logbuf);
+ }
+#endif
+
+ temp = st->lysp_mod->mod;
+
+ lyxml_context_clear(&st->yin_ctx->xml_ctx);
+ lys_module_free(st->mod, NULL);
+ lysp_module_free(st->lysp_mod);
+ lys_module_free(temp, NULL);
+ free(st->yin_ctx);
+
+ return EXIT_SUCCESS;
+}
+
+static struct state*
+reset_state(void **state)
+{
+ ((struct state *)*state)->finished_correctly = true;
+ logbuf[0] = '\0';
+ teardown_f(state);
+ setup_f(state);
+
+ return *state;
+}
+
+void
+logbuf_clean(void)
+{
+ logbuf[0] = '\0';
+}
+
+static int
+setup_logger(void **state)
+{
+ (void)state; /* unused */
+#if ENABLE_LOGGER_CHECKING
+ /* setup logger */
+ ly_set_log_clb(logger, 1);
+#endif
+
+ logbuf[0] = '\0';
+
+ return EXIT_SUCCESS;
+}
+
+static int
+teardown_logger(void **state)
+{
+ struct state *st = *state;
+
+#if ENABLE_LOGGER_CHECKING
+ /* teardown logger */
+ if (!st->finished_correctly && logbuf[0] != '\0') {
+ fprintf(stderr, "%s\n", logbuf);
+ }
+#endif
+
+ return EXIT_SUCCESS;
+}
+
+static int
+setup_element_test(void **state)
+{
+ setup_logger(state);
+ struct state *st = *state;
+
+ st->yin_ctx = calloc(1, sizeof(*st->yin_ctx));
+
+ /* allocate parser context */
+ st->yin_ctx->xml_ctx.ctx = st->ctx;
+ st->yin_ctx->xml_ctx.line = 1;
+
+ return EXIT_SUCCESS;
+}
+
+static int
+teardown_element_test(void **state)
+{
+ struct state *st = *(struct state **)state;
+
+ lyxml_context_clear(&st->yin_ctx->xml_ctx);
+ free(st->yin_ctx);
+
+ teardown_logger(state);
+
+ return EXIT_SUCCESS;
+}
+
+static void
+test_yin_match_keyword(void **state)
+{
+ struct state *st = *state;
+
+ const char *prefix, *name;
+ struct yin_arg_record *args = NULL;
+ size_t prefix_len, name_len;
+ /* create mock yin namespace in xml context */
+ const char *data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" />";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &args);
+ LY_ARRAY_FREE(args);
+
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "anydatax", strlen("anydatax"), prefix, prefix_len, YANG_NONE), YANG_NONE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "asdasd", strlen("asdasd"), prefix, prefix_len, YANG_NONE), YANG_NONE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "", 0, prefix, prefix_len, YANG_NONE), YANG_NONE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "anydata", strlen("anydata"), prefix, prefix_len, YANG_NONE), YANG_ANYDATA);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "anyxml", strlen("anyxml"), prefix, prefix_len, YANG_NONE), YANG_ANYXML);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "argument", strlen("argument"), prefix, prefix_len, YANG_NONE), YANG_ARGUMENT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "augment", strlen("augment"), prefix, prefix_len, YANG_NONE), YANG_AUGMENT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "base", strlen("base"), prefix, prefix_len, YANG_NONE), YANG_BASE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "belongs-to", strlen("belongs-to"), prefix, prefix_len, YANG_NONE), YANG_BELONGS_TO);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "bit", strlen("bit"), prefix, prefix_len, YANG_NONE), YANG_BIT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "case", strlen("case"), prefix, prefix_len, YANG_NONE), YANG_CASE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "choice", strlen("choice"), prefix, prefix_len, YANG_NONE), YANG_CHOICE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "config", strlen("config"), prefix, prefix_len, YANG_NONE), YANG_CONFIG);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "contact", strlen("contact"), prefix, prefix_len, YANG_NONE), YANG_CONTACT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "container", strlen("container"), prefix, prefix_len, YANG_NONE), YANG_CONTAINER);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "default", strlen("default"), prefix, prefix_len, YANG_NONE), YANG_DEFAULT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "description", strlen("description"), prefix, prefix_len, YANG_NONE), YANG_DESCRIPTION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "deviate", strlen("deviate"), prefix, prefix_len, YANG_NONE), YANG_DEVIATE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "deviation", strlen("deviation"), prefix, prefix_len, YANG_NONE), YANG_DEVIATION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "enum", strlen("enum"), prefix, prefix_len, YANG_NONE), YANG_ENUM);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "error-app-tag", strlen("error-app-tag"), prefix, prefix_len, YANG_NONE), YANG_ERROR_APP_TAG);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "error-message", strlen("error-message"), prefix, prefix_len, YANG_NONE), YANG_ERROR_MESSAGE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "extension", strlen("extension"), prefix, prefix_len, YANG_NONE), YANG_EXTENSION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "feature", strlen("feature"), prefix, prefix_len, YANG_NONE), YANG_FEATURE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "fraction-digits", strlen("fraction-digits"), prefix, prefix_len, YANG_NONE), YANG_FRACTION_DIGITS);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "grouping", strlen("grouping"), prefix, prefix_len, YANG_NONE), YANG_GROUPING);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "identity", strlen("identity"), prefix, prefix_len, YANG_NONE), YANG_IDENTITY);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "if-feature", strlen("if-feature"), prefix, prefix_len, YANG_NONE), YANG_IF_FEATURE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "import", strlen("import"), prefix, prefix_len, YANG_NONE), YANG_IMPORT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "include", strlen("include"), prefix, prefix_len, YANG_NONE), YANG_INCLUDE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "input", strlen("input"), prefix, prefix_len, YANG_NONE), YANG_INPUT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "key", strlen("key"), prefix, prefix_len, YANG_NONE), YANG_KEY);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "leaf", strlen("leaf"), prefix, prefix_len, YANG_NONE), YANG_LEAF);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "leaf-list", strlen("leaf-list"), prefix, prefix_len, YANG_NONE), YANG_LEAF_LIST);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "length", strlen("length"), prefix, prefix_len, YANG_NONE), YANG_LENGTH);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "list", strlen("list"), prefix, prefix_len, YANG_NONE), YANG_LIST);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "mandatory", strlen("mandatory"), prefix, prefix_len, YANG_NONE), YANG_MANDATORY);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "max-elements", strlen("max-elements"), prefix, prefix_len, YANG_NONE), YANG_MAX_ELEMENTS);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "min-elements", strlen("min-elements"), prefix, prefix_len, YANG_NONE), YANG_MIN_ELEMENTS);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "modifier", strlen("modifier"), prefix, prefix_len, YANG_NONE), YANG_MODIFIER);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "module", strlen("module"), prefix, prefix_len, YANG_NONE), YANG_MODULE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "must", strlen("must"), prefix, prefix_len, YANG_NONE), YANG_MUST);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "namespace", strlen("namespace"), prefix, prefix_len, YANG_NONE), YANG_NAMESPACE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "notification", strlen("notification"), prefix, prefix_len, YANG_NONE), YANG_NOTIFICATION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "ordered-by", strlen("ordered-by"), prefix, prefix_len, YANG_NONE), YANG_ORDERED_BY);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "organization", strlen("organization"), prefix, prefix_len, YANG_NONE), YANG_ORGANIZATION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "output", strlen("output"), prefix, prefix_len, YANG_NONE), YANG_OUTPUT);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "path", strlen("path"), prefix, prefix_len, YANG_NONE), YANG_PATH);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "pattern", strlen("pattern"), prefix, prefix_len, YANG_NONE), YANG_PATTERN);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "position", strlen("position"), prefix, prefix_len, YANG_NONE), YANG_POSITION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "prefix", strlen("prefix"), prefix, prefix_len, YANG_NONE), YANG_PREFIX);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "presence", strlen("presence"), prefix, prefix_len, YANG_NONE), YANG_PRESENCE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "range", strlen("range"), prefix, prefix_len, YANG_NONE), YANG_RANGE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "reference", strlen("reference"), prefix, prefix_len, YANG_NONE), YANG_REFERENCE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "refine", strlen("refine"), prefix, prefix_len, YANG_NONE), YANG_REFINE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "require-instance", strlen("require-instance"), prefix, prefix_len, YANG_NONE), YANG_REQUIRE_INSTANCE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "revision", strlen("revision"), prefix, prefix_len, YANG_NONE), YANG_REVISION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "revision-date", strlen("revision-date"), prefix, prefix_len, YANG_NONE), YANG_REVISION_DATE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "rpc", strlen("rpc"), prefix, prefix_len, YANG_NONE), YANG_RPC);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "status", strlen("status"), prefix, prefix_len, YANG_NONE), YANG_STATUS);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "submodule", strlen("submodule"), prefix, prefix_len, YANG_NONE), YANG_SUBMODULE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "type", strlen("type"), prefix, prefix_len, YANG_NONE), YANG_TYPE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "typedef", strlen("typedef"), prefix, prefix_len, YANG_NONE), YANG_TYPEDEF);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "unique", strlen("unique"), prefix, prefix_len, YANG_NONE), YANG_UNIQUE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "units", strlen("units"), prefix, prefix_len, YANG_NONE), YANG_UNITS);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "uses", strlen("uses"), prefix, prefix_len, YANG_NONE), YANG_USES);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "value", strlen("value"), prefix, prefix_len, YANG_NONE), YANG_VALUE);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "when", strlen("when"), prefix, prefix_len, YANG_NONE), YANG_WHEN);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "yang-version", strlen("yang-version"), prefix, prefix_len, YANG_NONE), YANG_YANG_VERSION);
+ assert_int_equal(yin_match_keyword(st->yin_ctx, "yin-element", strlen("yin-element"), prefix, prefix_len, YANG_NONE), YANG_YIN_ELEMENT);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_match_argument_name(void **state)
+{
+ (void)state; /* unused */
+
+ assert_int_equal(yin_match_argument_name("", 5), YIN_ARG_UNKNOWN);
+ assert_int_equal(yin_match_argument_name("qwertyasd", 5), YIN_ARG_UNKNOWN);
+ assert_int_equal(yin_match_argument_name("conditionasd", 8), YIN_ARG_UNKNOWN);
+ assert_int_equal(yin_match_argument_name("condition", 9), YIN_ARG_CONDITION);
+ assert_int_equal(yin_match_argument_name("date", 4), YIN_ARG_DATE);
+ assert_int_equal(yin_match_argument_name("module", 6), YIN_ARG_MODULE);
+ assert_int_equal(yin_match_argument_name("name", 4), YIN_ARG_NAME);
+ assert_int_equal(yin_match_argument_name("tag", 3), YIN_ARG_TAG);
+ assert_int_equal(yin_match_argument_name("target-node", 11), YIN_ARG_TARGET_NODE);
+ assert_int_equal(yin_match_argument_name("text", 4), YIN_ARG_TEXT);
+ assert_int_equal(yin_match_argument_name("uri", 3), YIN_ARG_URI);
+ assert_int_equal(yin_match_argument_name("value", 5), YIN_ARG_VALUE);
+}
+
+static void
+test_yin_parse_element_generic(void **state)
+{
+ const char *prefix, *name;
+ struct state *st = *state;
+ struct lysp_ext_instance exts;
+ size_t prefix_len, name_len;
+ LY_ERR ret;
+
+ memset(&exts, 0, sizeof(exts));
+
+ const char *data = "<elem attr=\"value\">text_value</elem>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ ret = yin_parse_element_generic(st->yin_ctx, name, name_len, &data, &exts.child);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_string_equal(exts.child->stmt, "elem");
+ assert_string_equal(exts.child->arg, "text_value");
+ assert_string_equal(exts.child->child->stmt, "attr");
+ assert_string_equal(exts.child->child->arg, "value");
+ assert_true(exts.child->child->flags & LYS_YIN_ATTR);
+ lysp_ext_instance_free(st->ctx, &exts);
+ st = reset_state(state);
+
+ data = "<elem></elem>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ ret = yin_parse_element_generic(st->yin_ctx, name, name_len, &data, &exts.child);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(exts.child->stmt, "elem");
+ assert_null(exts.child->child);
+ assert_null(exts.child->arg);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ lysp_ext_instance_free(st->ctx, &exts);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_extension_instance(void **state)
+{
+ LY_ERR ret;
+ struct state *st = *state;
+ const char *prefix, *name;
+ size_t prefix_len, name_len;
+ struct yin_arg_record *args = NULL;
+ struct lysp_ext_instance *exts = NULL;
+ const char *data = "<ext value1=\"test\" value=\"test2\"><subelem>text</subelem></ext>";
+ 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, name2fname(name, prefix_len),
+ len2flen(name_len, prefix_len), LYEXT_SUBSTMT_CONTACT, 0, &exts);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(exts->name, "ext");
+ assert_int_equal(exts->insubstmt_index, 0);
+ assert_true(exts->insubstmt == LYEXT_SUBSTMT_CONTACT);
+ assert_true(exts->yin & LYS_YIN);
+ assert_string_equal(exts->child->stmt, "value1");
+ assert_string_equal(exts->child->arg, "test");
+ assert_null(exts->child->child);
+ assert_true(exts->child->flags & LYS_YIN_ATTR);
+ assert_string_equal(exts->child->next->stmt, "value");
+ assert_string_equal(exts->child->next->arg, "test2");
+ assert_null(exts->child->next->child);
+ assert_true(exts->child->next->flags & LYS_YIN_ATTR);
+
+ assert_string_equal(exts->child->next->next->stmt, "subelem");
+ assert_string_equal(exts->child->next->next->arg, "text");
+ assert_null(exts->child->next->next->child);
+ assert_null(exts->child->next->next->next);
+ assert_false(exts->child->next->next->flags & LYS_YIN_ATTR);
+ 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);
+
+ data = "<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->name, "extension-elem");
+ assert_null(exts->argument);
+ assert_null(exts->child);
+ assert_int_equal(exts->insubstmt, LYEXT_SUBSTMT_CONTACT);
+ assert_int_equal(exts->insubstmt_index, 0);
+ assert_true(exts->yin & LYS_YIN);
+ 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);
+
+ data = "<ext attr1=\"text1\" attr2=\"text2\">"
+ "<ext-sub1/>"
+ "<ext-sub2 sattr1=\"stext2\">"
+ "<ext-sub21>"
+ "<ext-sub211 sattr21=\"text21\"/>"
+ "</ext-sub21>"
+ "</ext-sub2>"
+ "<ext-sub3 attr3=\"text3\"></ext-sub3>"
+ "</ext>";
+ 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->name, "ext");
+ assert_null(exts->argument);
+ assert_int_equal(exts->insubstmt, LYEXT_SUBSTMT_CONTACT);
+ assert_int_equal(exts->insubstmt_index, 0);
+ assert_true(exts->yin & LYS_YIN);
+ assert_string_equal(exts->child->stmt, "attr1");
+ assert_string_equal(exts->child->arg, "text1");
+ assert_null(exts->child->child);
+ assert_true(exts->child->flags & LYS_YIN_ATTR);
+
+ assert_string_equal(exts->child->next->stmt, "attr2");
+ assert_string_equal(exts->child->next->arg, "text2");
+ assert_null(exts->child->next->child);
+ assert_true(exts->child->next->flags & LYS_YIN_ATTR);
+
+ assert_string_equal(exts->child->next->next->stmt, "ext-sub1");
+ assert_null(exts->child->next->next->arg);
+ assert_null(exts->child->next->next->child);
+ assert_int_equal(exts->child->next->next->flags, 0);
+
+ assert_string_equal(exts->child->next->next->next->stmt, "ext-sub2");
+ assert_null(exts->child->next->next->next->arg);
+ assert_int_equal(exts->child->next->next->next->flags, 0);
+ assert_string_equal(exts->child->next->next->next->child->stmt, "sattr1");
+ assert_string_equal(exts->child->next->next->next->child->arg, "stext2");
+ assert_null(exts->child->next->next->next->child->child);
+ assert_true(exts->child->next->next->next->child->flags & LYS_YIN_ATTR);
+
+ assert_string_equal(exts->child->next->next->next->child->next->stmt, "ext-sub21");
+ assert_null(exts->child->next->next->next->child->next->arg);
+ assert_null(exts->child->next->next->next->child->next->next);
+ assert_int_equal(exts->child->next->next->next->child->next->flags, 0);
+
+ assert_string_equal(exts->child->next->next->next->child->next->child->stmt, "ext-sub211");
+ assert_null(exts->child->next->next->next->child->next->child->arg);
+ assert_int_equal(exts->child->next->next->next->child->next->child->flags, 0);
+ assert_null(exts->child->next->next->next->child->next->child->next);
+
+ assert_string_equal(exts->child->next->next->next->child->next->child->child->stmt, "sattr21");
+ assert_string_equal(exts->child->next->next->next->child->next->child->child->arg, "text21");
+ assert_null(exts->child->next->next->next->child->next->child->child->next);
+ assert_null(exts->child->next->next->next->child->next->child->child->child);
+ assert_true(exts->child->next->next->next->child->next->child->child->flags & LYS_YIN_ATTR);
+
+ assert_string_equal(exts->child->next->next->next->next->stmt, "ext-sub3");
+ assert_null(exts->child->next->next->next->next->arg);
+ assert_null(exts->child->next->next->next->next->next);
+ assert_int_equal(exts->child->next->next->next->next->flags, 0);
+
+ assert_string_equal(exts->child->next->next->next->next->child->stmt, "attr3");
+ assert_string_equal(exts->child->next->next->next->next->child->arg, "text3");
+ assert_null(exts->child->next->next->next->next->child->next);
+ assert_null(exts->child->next->next->next->next->child->child);
+ assert_true(exts->child->next->next->next->next->child->flags & LYS_YIN_ATTR);
+
+ LY_ARRAY_FREE(args);
+ lysp_ext_instance_free(st->ctx, exts);
+ LY_ARRAY_FREE(exts);
+ exts = NULL;
+ args = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_content(void **state)
+{
+ struct state *st = *state;
+ LY_ERR ret = LY_SUCCESS;
+ const char *name, *prefix;
+ size_t name_len, prefix_len;
+ const char *data = "<prefix value=\"a_mod\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<custom xmlns=\"my-ext\">"
+ "totally amazing extension"
+ "</custom>"
+ "<extension name=\"ext\">"
+ "<argument name=\"argname\"></argument>"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"deprecated\"></status>"
+ "</extension>"
+ "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+ "<if-feature name=\"foo\"></if-feature>"
+ "<when condition=\"condition...\">"
+ "<reference><text>when_ref</text></reference>"
+ "<description><text>when_desc</text></description>"
+ "</when>"
+ "<config value=\"true\"/>"
+ "<error-message>"
+ "<value>error-msg</value>"
+ "</error-message>"
+ "<error-app-tag value=\"err-app-tag\"/>"
+ "<units name=\"radians\"></units>"
+ "<default value=\"default-value\"/>"
+ "<position value=\"25\"></position>"
+ "<value value=\"-5\"/>"
+ "<require-instance value=\"true\"></require-instance>"
+ "<range value=\"5..10\" />"
+ "<length value=\"baf\"/>"
+ "<pattern value='pattern'>"
+ "<modifier value='invert-match'/>"
+ "</pattern>"
+ "<enum name=\"yay\">"
+ "</enum>"
+ "</prefix>";
+ struct lysp_ext_instance *exts = NULL;
+ const char **if_features = NULL;
+ struct yin_arg_record *attrs = NULL;
+ const char *value, *err_msg, *app_tag, *units, *def;
+ struct lysp_ext *ext_def = NULL;
+ struct lysp_when *when_p = NULL;
+ struct lysp_type_enum pos_enum = {}, val_enum = {};
+ struct lysp_type req_type = {}, range_type = {}, len_type = {}, patter_type = {}, enum_type = {};
+ uint8_t config = 0;
+
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+
+ struct yin_subelement subelems[17] = {
+ {YANG_CONFIG, &config, 0},
+ {YANG_DEFAULT, &def, YIN_SUBELEM_UNIQUE},
+ {YANG_ENUM, &enum_type, 0},
+ {YANG_ERROR_APP_TAG, &app_tag, YIN_SUBELEM_UNIQUE},
+ {YANG_ERROR_MESSAGE, &err_msg, 0},
+ {YANG_EXTENSION, &ext_def, 0},
+ {YANG_IF_FEATURE, &if_features, 0},
+ {YANG_LENGTH, &len_type, 0},
+ {YANG_PATTERN, &patter_type, 0},
+ {YANG_POSITION, &pos_enum, 0},
+ {YANG_RANGE, &range_type, 0},
+ {YANG_REQUIRE_INSTANCE, &req_type, 0},
+ {YANG_UNITS, &units, YIN_SUBELEM_UNIQUE},
+ {YANG_VALUE, &val_enum, 0},
+ {YANG_WHEN, &when_p, 0},
+ {YANG_CUSTOM, NULL, 0},
+ {YIN_TEXT, &value, 0}
+ };
+ ret = yin_parse_content(st->yin_ctx, subelems, 17, &data, YANG_PREFIX, NULL, &exts);
+ assert_int_equal(ret, LY_SUCCESS);
+ 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->argument, "totally amazing extension");
+ assert_string_equal(value, "wsefsdf");
+ assert_string_equal(units, "radians");
+ assert_string_equal(when_p->cond, "condition...");
+ assert_string_equal(when_p->dsc, "when_desc");
+ assert_string_equal(when_p->ref, "when_ref");
+ assert_int_equal(config, LYS_CONFIG_W);
+ assert_int_equal(pos_enum.value, 25);
+ assert_true(pos_enum.flags & LYS_SET_VALUE);
+ assert_int_equal(val_enum.value, -5);
+ assert_true(val_enum.flags & LYS_SET_VALUE);
+ assert_int_equal(req_type.require_instance, 1);
+ assert_true(req_type.flags &= LYS_SET_REQINST);
+ assert_string_equal(range_type.range->arg, "5..10");
+ assert_true(range_type.flags & LYS_SET_RANGE);
+ assert_string_equal(err_msg, "error-msg");
+ assert_string_equal(app_tag, "err-app-tag");
+ assert_string_equal(enum_type.enums->name, "yay");
+ assert_string_equal(len_type.length->arg, "baf");
+ assert_true(len_type.flags & LYS_SET_LENGTH);
+ assert_string_equal(patter_type.patterns->arg, "\x015pattern");
+ assert_true(patter_type.flags & LYS_SET_PATTERN);
+ /* cleanup */
+ lysp_ext_instance_free(st->ctx, exts);
+ lysp_when_free(st->ctx, when_p);
+ lysp_ext_free(st->ctx, ext_def);
+ FREE_STRING(st->ctx, *if_features);
+ FREE_STRING(st->ctx, err_msg);
+ FREE_STRING(st->ctx, app_tag);
+ FREE_STRING(st->ctx, units);
+ FREE_STRING(st->ctx, patter_type.patterns->arg);
+ FREE_STRING(st->ctx, def);
+ FREE_STRING(st->ctx, range_type.range->arg);
+ FREE_STRING(st->ctx, len_type.length->arg);
+ FREE_STRING(st->ctx, enum_type.enums->name);
+ FREE_STRING(st->ctx, value);
+ LY_ARRAY_FREE(if_features);
+ LY_ARRAY_FREE(exts);
+ LY_ARRAY_FREE(ext_def);
+ LY_ARRAY_FREE(attrs);
+ LY_ARRAY_FREE(patter_type.patterns);
+ LY_ARRAY_FREE(enum_type.enums);
+ free(when_p);
+ free(range_type.range);
+ free(len_type.length);
+ attrs = NULL;
+ st = reset_state(state);
+
+ /* test unique subelem */
+ const char *prefix_value;
+ struct yin_subelement subelems2[2] = {{YANG_PREFIX, &prefix_value, YIN_SUBELEM_UNIQUE},
+ {YIN_TEXT, &value, YIN_SUBELEM_UNIQUE}};
+ data = ELEMENT_WRAPPER_START
+ "<prefix value=\"inv_mod\" />"
+ "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+ "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+ ELEMENT_WRAPPER_END;
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_content(st->yin_ctx, subelems2, 2, &data, YANG_STATUS, NULL, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Redefinition of \"text\" sub-element in \"status\" element. Line number 1.");
+ lydict_remove(st->ctx, prefix_value);
+ lydict_remove(st->ctx, value);
+ st = reset_state(state);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+
+ /* test first subelem */
+ data = ELEMENT_WRAPPER_START
+ "<prefix value=\"inv_mod\" />"
+ "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+ "<text xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">wsefsdf</text>"
+ ELEMENT_WRAPPER_END;
+ struct yin_subelement subelems3[2] = {{YANG_PREFIX, &prefix_value, YIN_SUBELEM_UNIQUE},
+ {YIN_TEXT, &value, YIN_SUBELEM_FIRST}};
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_content(st->yin_ctx, subelems3, 2, &data, YANG_STATUS, NULL, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Sub-element \"text\" of \"status\" element must be defined as it's first sub-element. Line number 1.");
+ lydict_remove(st->ctx, prefix_value);
+ st = reset_state(state);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+
+ /* test mandatory subelem */
+ data = ELEMENT_WRAPPER_START ELEMENT_WRAPPER_END;
+ struct yin_subelement subelems4[1] = {{YANG_PREFIX, &prefix_value, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE}};
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_content(st->yin_ctx, subelems4, 1, &data, YANG_STATUS, NULL, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Missing mandatory sub-element \"prefix\" of \"status\" element. Line number 1.");
+ LY_ARRAY_FREE(attrs);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_validate_value(void **state)
+{
+ struct state *st = *state;
+ assert_int_equal(yin_validate_value(st->yin_ctx, Y_IDENTIF_ARG, "#invalid", 8), LY_EVALID);
+ logbuf_assert("Invalid identifier character '#'. Line number 1.");
+ assert_int_equal(yin_validate_value(st->yin_ctx, Y_STR_ARG, "", 0), LY_SUCCESS);
+ assert_int_equal(yin_validate_value(st->yin_ctx, Y_IDENTIF_ARG, "pre:b", 5), LY_EVALID);
+ assert_int_equal(yin_validate_value(st->yin_ctx, Y_PREF_IDENTIF_ARG, "pre:b", 5), LY_SUCCESS);
+ assert_int_equal(yin_validate_value(st->yin_ctx, Y_PREF_IDENTIF_ARG, "pre:pre:b", 9), LY_EVALID);
+
+ st->finished_correctly = true;
+}
+
+/* helper function to simplify unit test of each element using parse_content function */
+LY_ERR
+test_element_helper(struct state *st, const char **data, void *dest, const char **text,
+ struct lysp_ext_instance **exts, bool valid)
+{
+ struct yin_arg_record *attrs = NULL;
+ const char *name, *prefix;
+ size_t name_len, prefix_len;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_subelement subelems[71] = {
+ {YANG_ACTION, dest, 0},
+ {YANG_ANYDATA, dest, 0},
+ {YANG_ANYXML, dest, 0},
+ {YANG_ARGUMENT,dest, 0},
+ {YANG_AUGMENT, dest, 0},
+ {YANG_BASE, dest, 0},
+ {YANG_BELONGS_TO, dest, 0},
+ {YANG_BIT, dest, 0},
+ {YANG_CASE, dest, 0},
+ {YANG_CHOICE, dest, 0},
+ {YANG_CONFIG, dest, 0},
+ {YANG_CONTACT, dest, 0},
+ {YANG_CONTAINER, dest, 0},
+ {YANG_DEFAULT, dest, YIN_SUBELEM_UNIQUE},
+ {YANG_DESCRIPTION, dest, 0},
+ {YANG_DEVIATE, dest, 0},
+ {YANG_DEVIATION, dest, 0},
+ {YANG_ENUM, dest, 0},
+ {YANG_ERROR_APP_TAG, dest, YIN_SUBELEM_UNIQUE},
+ {YANG_ERROR_MESSAGE, dest, 0},
+ {YANG_EXTENSION, dest, 0},
+ {YANG_FEATURE, dest, 0},
+ {YANG_FRACTION_DIGITS, dest, 0},
+ {YANG_GROUPING, dest, 0},
+ {YANG_IDENTITY, dest, 0},
+ {YANG_IF_FEATURE, dest, 0},
+ {YANG_IMPORT, dest, 0},
+ {YANG_INCLUDE, dest, 0},
+ {YANG_INPUT, dest, 0},
+ {YANG_KEY, dest, YIN_SUBELEM_UNIQUE},
+ {YANG_LEAF, dest, 0},
+ {YANG_LEAF_LIST, dest, 0},
+ {YANG_LENGTH, dest, 0},
+ {YANG_LIST, dest, 0},
+ {YANG_MANDATORY, dest, 0},
+ {YANG_MAX_ELEMENTS, dest, 0},
+ {YANG_MIN_ELEMENTS, dest, 0},
+ {YANG_MODIFIER, dest, 0},
+ {YANG_MODULE, dest, 0},
+ {YANG_MUST, dest, 0},
+ {YANG_NAMESPACE, dest, YIN_SUBELEM_UNIQUE},
+ {YANG_NOTIFICATION, dest, 0},
+ {YANG_ORDERED_BY, dest, 0},
+ {YANG_ORGANIZATION, dest, 0},
+ {YANG_OUTPUT, dest, 0},
+ {YANG_PATH, dest, 0},
+ {YANG_PATTERN, dest, 0},
+ {YANG_POSITION, dest, 0},
+ {YANG_PREFIX, dest, YIN_SUBELEM_UNIQUE},
+ {YANG_PRESENCE, dest, YIN_SUBELEM_UNIQUE},
+ {YANG_RANGE, dest, 0},
+ {YANG_REFERENCE, dest, 0},
+ {YANG_REFINE, dest, 0},
+ {YANG_REQUIRE_INSTANCE, dest, 0},
+ {YANG_REVISION, dest, 0},
+ {YANG_REVISION_DATE, dest, 0},
+ {YANG_RPC, dest, 0},
+ {YANG_STATUS, dest, 0},
+ {YANG_SUBMODULE, dest, 0},
+ {YANG_TYPE, dest, 0},
+ {YANG_TYPEDEF, dest, 0},
+ {YANG_UNIQUE, dest, 0},
+ {YANG_UNITS, dest, YIN_SUBELEM_UNIQUE},
+ {YANG_USES, dest, 0},
+ {YANG_VALUE, dest, 0},
+ {YANG_WHEN, dest, 0},
+ {YANG_YANG_VERSION, dest, 0},
+ {YANG_YIN_ELEMENT, dest, 0},
+ {YANG_CUSTOM, dest, 0},
+ {YIN_TEXT, dest, 0},
+ {YIN_VALUE, dest, 0}
+ };
+ LY_CHECK_RET(lyxml_get_element(&st->yin_ctx->xml_ctx, data, &prefix, &prefix_len, &name, &name_len));
+ LY_CHECK_RET(yin_load_attributes(st->yin_ctx, data, &attrs));
+ ret = yin_parse_content(st->yin_ctx, subelems, 71, data, yin_match_keyword(st->yin_ctx, name, name_len, prefix, prefix_len, YANG_NONE), text, exts);
+ LY_ARRAY_FREE(attrs);
+ if (valid) {
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ }
+ /* reset status */
+ st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+ return ret;
+}
+
+#define EXT_SUBELEM "<myext:c-define name=\"MY_MTU\" xmlns:myext=\"urn:example:extensions\"/>"
+
+static void
+test_enum_elem(void **state)
+{
+ struct state *st = *state;
+ struct lysp_type type = {};
+ const char *data;
+ data = ELEMENT_WRAPPER_START
+ "<enum name=\"enum-name\">"
+ "<if-feature name=\"feature\" />"
+ "<value value=\"55\" />"
+ "<status value=\"deprecated\" />"
+ "<description><text>desc...</text></description>"
+ "<reference><text>ref...</text></reference>"
+ EXT_SUBELEM
+ "</enum>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.enums->name, "enum-name");
+ assert_string_equal(*type.enums->iffeatures, "feature");
+ assert_int_equal(type.enums->value, 55);
+ assert_true((type.enums->flags & LYS_STATUS_DEPRC) && (type.enums->flags & LYS_SET_VALUE));
+ assert_string_equal(type.enums->dsc, "desc...");
+ assert_string_equal(type.enums->ref, "ref...");
+ assert_string_equal(type.enums->exts->name, "myext:c-define");
+ assert_int_equal(type.enums->exts->insubstmt_index, 0);
+ assert_int_equal(type.enums->exts->insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof type);
+
+ data = ELEMENT_WRAPPER_START
+ "<enum name=\"enum-name\"></enum>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.enums->name, "enum-name");
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof type);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_bit_elem(void **state)
+{
+ struct state *st = *state;
+ struct lysp_type type = {};
+ const char *data;
+ data = ELEMENT_WRAPPER_START
+ "<bit name=\"bit-name\">"
+ "<if-feature name=\"feature\" />"
+ "<position value=\"55\" />"
+ "<status value=\"deprecated\" />"
+ "<description><text>desc...</text></description>"
+ "<reference><text>ref...</text></reference>"
+ EXT_SUBELEM
+ "</bit>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.bits->name, "bit-name");
+ assert_string_equal(*type.bits->iffeatures, "feature");
+ assert_int_equal(type.bits->value, 55);
+ assert_true((type.bits->flags & LYS_STATUS_DEPRC) && (type.bits->flags & LYS_SET_VALUE));
+ assert_string_equal(type.bits->dsc, "desc...");
+ assert_string_equal(type.bits->ref, "ref...");
+ assert_string_equal(type.bits->exts->name, "myext:c-define");
+ assert_int_equal(type.bits->exts->insubstmt_index, 0);
+ assert_int_equal(type.bits->exts->insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof type);
+
+ data = ELEMENT_WRAPPER_START
+ "<bit name=\"bit-name\"> </bit>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.bits->name, "bit-name");
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof type);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_meta_elem(void **state)
+{
+ struct state *st = *state;
+ char *value = NULL;
+ const char *data;
+ struct lysp_ext_instance *exts = NULL;
+
+ /* organization element */
+ data = ELEMENT_WRAPPER_START
+ "<organization><text>organization...</text>" EXT_SUBELEM EXT_SUBELEM "</organization>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ORGANIZATION);
+ assert_string_equal(exts[1].name, "myext:c-define");
+ assert_int_equal(exts[1].insubstmt_index, 0);
+ assert_int_equal(exts[1].insubstmt, LYEXT_SUBSTMT_ORGANIZATION);
+ assert_string_equal(value, "organization...");
+ FREE_STRING(st->ctx, value);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ value = NULL;
+ exts = NULL;
+
+ /* contact element */
+ data = ELEMENT_WRAPPER_START
+ "<contact><text>contact...</text>" EXT_SUBELEM "</contact>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_CONTACT);
+ assert_string_equal(value, "contact...");
+ FREE_STRING(st->ctx, value);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ value = NULL;
+
+ /* description element */
+ data = ELEMENT_WRAPPER_START
+ "<description><text>description...</text>" EXT_SUBELEM "</description>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(value, "description...");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_DESCRIPTION);
+ FREE_STRING(st->ctx, value);
+ value = NULL;
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+
+ /* reference element */
+ data = ELEMENT_WRAPPER_START
+ "<reference><text>reference...</text>" EXT_SUBELEM "</reference>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(value, "reference...");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_REFERENCE);
+ FREE_STRING(st->ctx, value);
+ value = NULL;
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+
+ /* reference element */
+ data = ELEMENT_WRAPPER_START
+ "<reference invalid=\"text\"><text>reference...</text>""</reference>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, false), LY_EVALID);
+ logbuf_assert("Unexpected attribute \"invalid\" of \"reference\" element. Line number 1.");
+ FREE_STRING(st->ctx, value);
+ value = NULL;
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+
+ /* missing text subelement */
+ data = ELEMENT_WRAPPER_START
+ "<reference>reference...</reference>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, false), LY_EVALID);
+ logbuf_assert("Missing mandatory sub-element \"text\" of \"reference\" element. Line number 1.");
+
+ /* reference element */
+ data = ELEMENT_WRAPPER_START
+ "<reference>" EXT_SUBELEM "<text>reference...</text></reference>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, false), LY_EVALID);
+ logbuf_assert("Sub-element \"text\" of \"reference\" element must be defined as it's first sub-element. Line number 1.");
+ FREE_STRING(st->ctx, value);
+ value = NULL;
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_import_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_import *imports = NULL;
+ struct import_meta imp_meta = {"prefix", &imports};
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<import module=\"a\">"
+ EXT_SUBELEM
+ "<prefix value=\"a_mod\"/>"
+ "<revision-date date=\"2015-01-01\"></revision-date>"
+ "<description><text>import description</text></description>"
+ "<reference><text>import reference</text></reference>"
+ "</import>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(imports->name, "a");
+ assert_string_equal(imports->prefix, "a_mod");
+ assert_string_equal(imports->rev, "2015-01-01");
+ assert_string_equal(imports->dsc, "import description");
+ assert_string_equal(imports->ref, "import reference");
+ assert_string_equal(imports->exts->name, "myext:c-define");
+ assert_int_equal(imports->exts->insubstmt, LYEXT_SUBSTMT_SELF);
+ assert_int_equal(imports->exts->insubstmt_index, 0);
+ FREE_ARRAY(st->ctx, imports, lysp_import_free);
+ imports = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START
+ "<import module=\"a\">"
+ "<prefix value=\"a_mod\"/>"
+ "</import>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(imports->prefix, "a_mod");
+ FREE_ARRAY(st->ctx, imports, lysp_import_free);
+ imports = NULL;
+
+ /* invalid (missing prefix) */
+ data = ELEMENT_WRAPPER_START "<import module=\"a\"></import>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory sub-element \"prefix\" of \"import\" element. Line number 1.");
+ FREE_ARRAY(st->ctx, imports, lysp_import_free);
+ imports = NULL;
+
+ /* invalid reused prefix */
+ data = ELEMENT_WRAPPER_START
+ "<import module=\"a\">"
+ "<prefix value=\"prefix\"/>"
+ "</import>"
+ "<import module=\"a\">"
+ "<prefix value=\"prefix\"/>"
+ "</import>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &imp_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Prefix \"prefix\" already used as module prefix. Line number 1.");
+ FREE_ARRAY(st->ctx, imports, lysp_import_free);
+ imports = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_status_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ uint16_t flags = 0;
+ struct lysp_ext_instance *exts = NULL;
+
+ /* test valid values */
+ data = ELEMENT_WRAPPER_START "<status value=\"current\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+ assert_true(flags & LYS_STATUS_CURR);
+
+ data = ELEMENT_WRAPPER_START "<status value=\"deprecated\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+ assert_true(flags & LYS_STATUS_DEPRC);
+
+ data = ELEMENT_WRAPPER_START "<status value=\"obsolete\">"EXT_SUBELEM"</status>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+ assert_true(flags & LYS_STATUS_OBSLT);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_STATUS);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+
+ /* test invalid value */
+ data = ELEMENT_WRAPPER_START "<status value=\"invalid\"></status>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"status\" element. Valid values are \"current\", \"deprecated\" and \"obsolete\". Line number 1.");
+ st->finished_correctly = true;
+}
+
+static void
+test_ext_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_ext *ext = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<extension name=\"ext_name\">"
+ "<argument name=\"arg\"></argument>"
+ "<status value=\"current\"/>"
+ "<description><text>ext_desc</text></description>"
+ "<reference><text>ext_ref</text></reference>"
+ EXT_SUBELEM
+ "</extension>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &ext, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(ext->name, "ext_name");
+ assert_string_equal(ext->argument, "arg");
+ assert_true(ext->flags & LYS_STATUS_CURR);
+ assert_string_equal(ext->dsc, "ext_desc");
+ assert_string_equal(ext->ref, "ext_ref");
+ assert_string_equal(ext->exts[0].name, "myext:c-define");
+ assert_int_equal(ext->exts[0].insubstmt_index, 0);
+ assert_int_equal(ext->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_ext_free(st->ctx, ext);
+ LY_ARRAY_FREE(ext);
+ ext = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<extension name=\"ext_name\"></extension>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &ext, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(ext->name, "ext_name");
+ lysp_ext_free(st->ctx, ext);
+ LY_ARRAY_FREE(ext);
+ ext = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_element_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ uint16_t flags = 0;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<yin-element value=\"true\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+ assert_true(flags & LYS_YINELEM_TRUE);
+
+ data = ELEMENT_WRAPPER_START "<yin-element value=\"false\">" EXT_SUBELEM "</yin-element>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+ assert_true(flags & LYS_YINELEM_TRUE);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_YINELEM);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+ data = ELEMENT_WRAPPER_START "<yin-element value=\"invalid\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+ assert_true(flags & LYS_YINELEM_TRUE);
+ logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"yin-element\" element. Valid values are \"true\" and \"false\". Line number 1.");
+ st->finished_correctly = true;
+}
+
+static void
+test_yangversion_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ uint8_t version = 0;
+ struct lysp_ext_instance *exts = NULL;
+
+ /* valid values */
+ data = ELEMENT_WRAPPER_START "<yang-version value=\"1.0\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &version, NULL, NULL, true), LY_SUCCESS);
+ assert_true(version & LYS_VERSION_1_0);
+ assert_int_equal(st->yin_ctx->mod_version, LYS_VERSION_1_0);
+
+ data = ELEMENT_WRAPPER_START "<yang-version value=\"1.1\">" EXT_SUBELEM "</yang-version>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &version, NULL, &exts, true), LY_SUCCESS);
+ assert_true(version & LYS_VERSION_1_1);
+ assert_int_equal(st->yin_ctx->mod_version, LYS_VERSION_1_1);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_VERSION);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+ /* invalid value */
+ data = ELEMENT_WRAPPER_START "<yang-version value=\"version\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &version, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"version\" of \"value\" attribute in \"yang-version\" element. Valid values are \"1.0\" and \"1.1\". Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_mandatory_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ uint16_t man = 0;
+ struct lysp_ext_instance *exts = NULL;
+
+ /* valid values */
+ data = ELEMENT_WRAPPER_START "<mandatory value=\"true\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &man, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(man, LYS_MAND_TRUE);
+ man = 0;
+
+ data = ELEMENT_WRAPPER_START "<mandatory value=\"false\">" EXT_SUBELEM "</mandatory>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &man, NULL, &exts, true), LY_SUCCESS);
+ assert_int_equal(man, LYS_MAND_FALSE);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_MANDATORY);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+ data = ELEMENT_WRAPPER_START "<mandatory value=\"invalid\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &man, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"mandatory\" element. Valid values are \"true\" and \"false\". Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_argument_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ uint16_t flags = 0;
+ const char *arg;
+ struct yin_argument_meta arg_meta = {&flags, &arg};
+ struct lysp_ext_instance *exts = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<argument name=\"arg-name\">"
+ "<yin-element value=\"true\" />"
+ EXT_SUBELEM
+ "</argument>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &arg_meta, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(arg, "arg-name");
+ assert_true(flags & LYS_YINELEM_TRUE);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ARGUMENT);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ flags = 0;
+ FREE_STRING(st->ctx, arg);
+ arg = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START
+ "<argument name=\"arg\">"
+ "</argument>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &arg_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(arg, "arg");
+ assert_true(flags == 0);
+ FREE_STRING(st->ctx, arg);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_base_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char **bases = NULL;
+ struct lysp_ext_instance *exts = NULL;
+ struct lysp_type type = {};
+
+ /* as identity subelement */
+ data = "<identity xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<base name=\"base-name\">"
+ EXT_SUBELEM
+ "</base>"
+ "</identity>";
+ assert_int_equal(test_element_helper(st, &data, &bases, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(*bases, "base-name");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_BASE);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, *bases);
+ LY_ARRAY_FREE(bases);
+
+ /* as type subelement */
+ data = "<type xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<base name=\"base-name\">"
+ EXT_SUBELEM
+ "</base>"
+ "</type>";
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(*type.bases, "base-name");
+ assert_true(type.flags & LYS_SET_BASE);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_BASE);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, *type.bases);
+ LY_ARRAY_FREE(type.bases);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_belongsto_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_submodule submod;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<belongs-to module=\"module-name\"><prefix value=\"pref\"/>"EXT_SUBELEM"</belongs-to>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &submod, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(submod.belongsto, "module-name");
+ assert_string_equal(submod.prefix, "pref");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_BELONGSTO);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, submod.belongsto);
+ FREE_STRING(st->ctx, submod.prefix);
+
+ data = ELEMENT_WRAPPER_START "<belongs-to module=\"module-name\"></belongs-to>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &submod, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory sub-element \"prefix\" of \"belongs-to\" element. Line number 1.");
+ FREE_STRING(st->ctx, submod.belongsto);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_config_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ uint16_t flags = 0;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<config value=\"true\">" EXT_SUBELEM "</config>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+ assert_true(flags & LYS_CONFIG_W);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_CONFIG);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ flags = 0;
+
+ data = ELEMENT_WRAPPER_START "<config value=\"false\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+ assert_true(flags & LYS_CONFIG_R);
+ flags = 0;
+
+ data = ELEMENT_WRAPPER_START "<config value=\"invalid\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"config\" element. Valid values are \"true\" and \"false\". Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_default_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *val = NULL;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<default value=\"defaul-value\">"EXT_SUBELEM"</default>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(val, "defaul-value");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_DEFAULT);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, val);
+ val = NULL;
+
+ data = ELEMENT_WRAPPER_START "<default/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory attribute value of default element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_err_app_tag_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *val = NULL;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<error-app-tag value=\"val\">"EXT_SUBELEM"</error-app-tag>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(val, "val");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ERRTAG);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, val);
+ val = NULL;
+
+ data = ELEMENT_WRAPPER_START "<error-app-tag/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory attribute value of error-app-tag element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_err_msg_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *val = NULL;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<error-message><value>val</value>"EXT_SUBELEM"</error-message>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(val, "val");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ERRMSG);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, val);
+
+ data = ELEMENT_WRAPPER_START "<error-message></error-message>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory sub-element \"value\" of \"error-message\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<error-message invalid=\"text\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Unexpected attribute \"invalid\" of \"error-message\" element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_fracdigits_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type type = {};
+
+ /* valid value */
+ data = ELEMENT_WRAPPER_START "<fraction-digits value=\"10\">"EXT_SUBELEM"</fraction-digits>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.exts[0].name, "myext:c-define");
+ assert_int_equal(type.exts[0].insubstmt_index, 0);
+ assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_FRACDIGITS);
+ assert_int_equal(type.fraction_digits, 10);
+ assert_true(type.flags & LYS_SET_FRDIGITS);
+ FREE_ARRAY(st->ctx, type.exts, lysp_ext_instance_free);
+
+ /* invalid values */
+ data = ELEMENT_WRAPPER_START "<fraction-digits value=\"-1\"></fraction-digits>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"-1\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<fraction-digits value=\"02\"></fraction-digits>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"02\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<fraction-digits value=\"1p\"></fraction-digits>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"1p\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<fraction-digits value=\"19\"></fraction-digits>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"19\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<fraction-digits value=\"999999999999999999\"></fraction-digits>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"999999999999999999\" of \"value\" attribute in \"fraction-digits\" element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_iffeature_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char **iffeatures = NULL;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<if-feature name=\"local-storage\">"EXT_SUBELEM"</if-feature>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &iffeatures, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(*iffeatures, "local-storage");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_IFFEATURE);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, *iffeatures);
+ LY_ARRAY_FREE(iffeatures);
+ iffeatures = NULL;
+
+ data = ELEMENT_WRAPPER_START "<if-feature/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &iffeatures, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory attribute name of if-feature element. Line number 1.");
+ LY_ARRAY_FREE(iffeatures);
+ iffeatures = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_length_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type type = {};
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<length value=\"length-str\">"
+ "<error-message><value>err-msg</value></error-message>"
+ "<error-app-tag value=\"err-app-tag\"/>"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ EXT_SUBELEM
+ "</length>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.length->arg, "length-str");
+ assert_string_equal(type.length->emsg, "err-msg");
+ assert_string_equal(type.length->eapptag, "err-app-tag");
+ assert_string_equal(type.length->dsc, "desc");
+ assert_string_equal(type.length->ref, "ref");
+ assert_true(type.flags & LYS_SET_LENGTH);
+ assert_string_equal(type.length->exts[0].name, "myext:c-define");
+ assert_int_equal(type.length->exts[0].insubstmt_index, 0);
+ assert_int_equal(type.length->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START
+ "<length value=\"length-str\">"
+ "</length>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.length->arg, "length-str");
+ lysp_type_free(st->ctx, &type);
+ assert_true(type.flags & LYS_SET_LENGTH);
+ memset(&type, 0, sizeof(type));
+
+ data = ELEMENT_WRAPPER_START "<length></length>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory attribute value of length element. Line number 1.");
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ st->finished_correctly = true;
+}
+
+static void
+test_modifier_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *pat = lydict_insert(st->ctx, "\006pattern", 8);
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<modifier value=\"invert-match\">" EXT_SUBELEM "</modifier>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &pat, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(pat, "\x015pattern");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_MODIFIER);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, pat);
+
+ pat = lydict_insert(st->ctx, "\006pattern", 8);
+ data = ELEMENT_WRAPPER_START "<modifier value=\"invert\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &pat, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"invert\" of \"value\" attribute in \"modifier\" element. Only valid value is \"invert-match\". Line number 1.");
+ FREE_STRING(st->ctx, pat);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_namespace_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *ns;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<namespace uri=\"ns\">" EXT_SUBELEM "</namespace>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &ns, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(ns, "ns");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_NAMESPACE);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, ns);
+
+ data = ELEMENT_WRAPPER_START "<namespace/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &ns, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory attribute uri of namespace element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_path_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type type = {};
+
+ data = ELEMENT_WRAPPER_START "<path value=\"p&th-val\">" EXT_SUBELEM "</path>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal("p&th-val", type.path);
+ assert_true(type.flags & LYS_SET_PATH);
+ assert_string_equal(type.exts[0].name, "myext:c-define");
+ assert_int_equal(type.exts[0].insubstmt_index, 0);
+ assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_PATH);
+ lysp_type_free(st->ctx, &type);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_pattern_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type type = {};
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<pattern value=\"super_pattern\">"
+ "<modifier value=\"invert-match\"/>"
+ "<error-message><value>err-msg-value</value></error-message>"
+ "<error-app-tag value=\"err-app-tag-value\"/>"
+ "<description><text>"pattern-desc"</text></description>"
+ "<reference><text>pattern-ref</text></reference>"
+ EXT_SUBELEM
+ "</pattern>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_true(type.flags & LYS_SET_PATTERN);
+ assert_string_equal(type.patterns->arg, "\x015super_pattern");
+ assert_string_equal(type.patterns->dsc, "\"pattern-desc\"");
+ assert_string_equal(type.patterns->eapptag, "err-app-tag-value");
+ assert_string_equal(type.patterns->emsg, "err-msg-value");
+ assert_string_equal(type.patterns->ref, "pattern-ref");
+ assert_string_equal(type.patterns->exts[0].name, "myext:c-define");
+ assert_int_equal(type.patterns->exts[0].insubstmt_index, 0);
+ assert_int_equal(type.patterns->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<pattern value=\"pattern\"> </pattern>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.patterns->arg, "\x006pattern");
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ st->finished_correctly = true;
+}
+
+static void
+test_value_position_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type_enum en = {};
+
+ /* valid values */
+ data = ELEMENT_WRAPPER_START "<value value=\"55\">" EXT_SUBELEM "</value>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(en.value, 55);
+ assert_true(en.flags & LYS_SET_VALUE);
+ assert_string_equal(en.exts[0].name, "myext:c-define");
+ assert_int_equal(en.exts[0].insubstmt_index, 0);
+ assert_int_equal(en.exts[0].insubstmt, LYEXT_SUBSTMT_VALUE);
+ FREE_ARRAY(st->ctx, en.exts, lysp_ext_instance_free);
+ memset(&en, 0, sizeof(en));
+
+ data = ELEMENT_WRAPPER_START "<value value=\"-55\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(en.value, -55);
+ assert_true(en.flags & LYS_SET_VALUE);
+ memset(&en, 0, sizeof(en));
+
+ data = ELEMENT_WRAPPER_START "<value value=\"0\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(en.value, 0);
+ assert_true(en.flags & LYS_SET_VALUE);
+ memset(&en, 0, sizeof(en));
+
+ data = ELEMENT_WRAPPER_START "<value value=\"-0\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(en.value, 0);
+ assert_true(en.flags & LYS_SET_VALUE);
+ memset(&en, 0, sizeof(en));
+
+ /* valid positions */
+ data = ELEMENT_WRAPPER_START "<position value=\"55\">" EXT_SUBELEM "</position>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(en.value, 55);
+ assert_true(en.flags & LYS_SET_VALUE);
+ assert_string_equal(en.exts[0].name, "myext:c-define");
+ assert_int_equal(en.exts[0].insubstmt_index, 0);
+ assert_int_equal(en.exts[0].insubstmt, LYEXT_SUBSTMT_POSITION);
+ FREE_ARRAY(st->ctx, en.exts, lysp_ext_instance_free);
+ memset(&en, 0, sizeof(en));
+
+ data = ELEMENT_WRAPPER_START "<position value=\"0\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(en.value, 0);
+ assert_true(en.flags & LYS_SET_VALUE);
+ memset(&en, 0, sizeof(en));
+
+ /* invalid values */
+ data = ELEMENT_WRAPPER_START "<value value=\"99999999999999999999999\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"99999999999999999999999\" of \"value\" attribute in \"value\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<value value=\"1k\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"1k\" of \"value\" attribute in \"value\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<value value=\"\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"\" of \"value\" attribute in \"value\" element. Line number 1.");
+
+ /*invalid positions */
+ data = ELEMENT_WRAPPER_START "<position value=\"-5\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"-5\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<position value=\"-0\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"-0\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<position value=\"99999999999999999999\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"99999999999999999999\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+ data = ELEMENT_WRAPPER_START "<position value=\"\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &en, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"\" of \"value\" attribute in \"position\" element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_prefix_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *value = NULL;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<prefix value=\"pref\">" EXT_SUBELEM "</prefix>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(value, "pref");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_PREFIX);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ exts = NULL;
+ FREE_STRING(st->ctx, value);
+
+ data = ELEMENT_WRAPPER_START "<prefix value=\"pref\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &value, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(value, "pref");
+ FREE_STRING(st->ctx, value);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_range_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type type = {};
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<range value=\"range-str\">"
+ "<error-message><value>err-msg</value></error-message>"
+ "<error-app-tag value=\"err-app-tag\" />"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ EXT_SUBELEM
+ "</range>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.range->arg, "range-str");
+ assert_string_equal(type.range->dsc, "desc");
+ assert_string_equal(type.range->eapptag, "err-app-tag");
+ assert_string_equal(type.range->emsg, "err-msg");
+ assert_string_equal(type.range->ref, "ref");
+ assert_true(type.flags & LYS_SET_RANGE);
+ assert_string_equal(type.range->exts[0].name, "myext:c-define");
+ assert_int_equal(type.range->exts[0].insubstmt_index, 0);
+ assert_int_equal(type.range->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<range value=\"range-str\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.range->arg, "range-str");
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ st->finished_correctly = true;
+}
+
+static void
+test_reqinstance_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type type = {};
+
+ data = ELEMENT_WRAPPER_START "<require-instance value=\"true\">" EXT_SUBELEM "</require-instance>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(type.require_instance, 1);
+ assert_true(type.flags & LYS_SET_REQINST);
+ assert_string_equal(type.exts[0].name, "myext:c-define");
+ assert_int_equal(type.exts[0].insubstmt_index, 0);
+ assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_REQINSTANCE);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ data = ELEMENT_WRAPPER_START "<require-instance value=\"false\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(type.require_instance, 0);
+ assert_true(type.flags & LYS_SET_REQINST);
+ memset(&type, 0, sizeof(type));
+
+ data = ELEMENT_WRAPPER_START "<require-instance value=\"invalid\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, false), LY_EVALID);
+ memset(&type, 0, sizeof(type));
+ logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"require-instance\" element. Valid values are \"true\" and \"false\". Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_revision_date_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ char rev[LY_REV_SIZE];
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<revision-date date=\"2000-01-01\">"EXT_SUBELEM"</revision-date>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, rev, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(rev, "2000-01-01");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_REVISIONDATE);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+ data = ELEMENT_WRAPPER_START "<revision-date date=\"2000-01-01\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, rev, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(rev, "2000-01-01");
+
+ data = ELEMENT_WRAPPER_START "<revision-date date=\"2000-50-05\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, rev, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"2000-50-05\" of \"revision-date\". Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_unique_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char **values = NULL;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<unique tag=\"tag\">"EXT_SUBELEM"</unique>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &values, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(*values, "tag");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_UNIQUE);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ FREE_STRING(st->ctx, *values);
+ LY_ARRAY_FREE(values);
+ values = NULL;
+
+ data = ELEMENT_WRAPPER_START "<unique tag=\"tag\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &values, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(*values, "tag");
+ FREE_STRING(st->ctx, *values);
+ LY_ARRAY_FREE(values);
+ values = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_units_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *values = NULL;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<units name=\"name\">"EXT_SUBELEM"</units>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &values, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(values, "name");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_UNITS);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ FREE_STRING(st->ctx, values);
+ values = NULL;
+
+ data = ELEMENT_WRAPPER_START "<units name=\"name\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &values, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(values, "name");
+ FREE_STRING(st->ctx, values);
+ values = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_when_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_when *when = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<when condition=\"cond\">"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ EXT_SUBELEM
+ "</when>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &when, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(when->cond, "cond");
+ assert_string_equal(when->dsc, "desc");
+ assert_string_equal(when->ref, "ref");
+ assert_string_equal(when->exts[0].name, "myext:c-define");
+ assert_int_equal(when->exts[0].insubstmt_index, 0);
+ assert_int_equal(when->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_when_free(st->ctx, when);
+ free(when);
+ when = NULL;
+
+ data = ELEMENT_WRAPPER_START "<when condition=\"cond\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &when, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(when->cond, "cond");
+ lysp_when_free(st->ctx, when);
+ free(when);
+ when = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_text_value_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *val;
+
+ data = ELEMENT_WRAPPER_START "<text>text</text>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(val, "text");
+ FREE_STRING(st->ctx, val);
+
+ data = "<error-message xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <value>text</value> </error-message>";
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(val, "text");
+ FREE_STRING(st->ctx, val);
+
+ data = ELEMENT_WRAPPER_START "<text></text>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal("", val);
+ FREE_STRING(st->ctx, val);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_type_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_type type = {};
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<type name=\"type-name\">"
+ "<base name=\"base-name\"/>"
+ "<bit name=\"bit\"/>"
+ "<enum name=\"enum\"/>"
+ "<fraction-digits value=\"2\"/>"
+ "<length value=\"length\"/>"
+ "<path value=\"path\"/>"
+ "<pattern value=\"pattern\"/>"
+ "<range value=\"range\" />"
+ "<require-instance value=\"true\"/>"
+ "<type name=\"sub-type-name\"/>"
+ EXT_SUBELEM
+ "</type>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(type.name, "type-name");
+ assert_string_equal(*type.bases, "base-name");
+ assert_string_equal(type.bits->name, "bit");
+ assert_string_equal(type.enums->name, "enum");
+ assert_int_equal(type.fraction_digits, 2);
+ assert_string_equal(type.length->arg, "length");
+ assert_string_equal(type.path, "path");
+ assert_string_equal(type.patterns->arg, "\006pattern");
+ assert_string_equal(type.range->arg, "range");
+ assert_int_equal(type.require_instance, 1);
+ assert_string_equal(type.types->name, "sub-type-name");
+ assert_string_equal(type.exts[0].name, "myext:c-define");
+ assert_int_equal(type.exts[0].insubstmt_index, 0);
+ assert_int_equal(type.exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ assert_true(type.flags & LYS_SET_BASE);
+ assert_true(type.flags & LYS_SET_BIT);
+ assert_true(type.flags & LYS_SET_ENUM);
+ assert_true(type.flags & LYS_SET_FRDIGITS);
+ assert_true(type.flags & LYS_SET_LENGTH);
+ assert_true(type.flags & LYS_SET_PATH);
+ assert_true(type.flags & LYS_SET_PATTERN);
+ assert_true(type.flags & LYS_SET_RANGE);
+ assert_true(type.flags & LYS_SET_REQINST);
+ assert_true(type.flags & LYS_SET_TYPE);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<type name=\"type-name\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &type, NULL, NULL, true), LY_SUCCESS);
+ lysp_type_free(st->ctx, &type);
+ memset(&type, 0, sizeof(type));
+
+ st->finished_correctly = true;
+}
+
+static void
+test_max_elems_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node_list list = {};
+ struct lysp_node_leaflist llist = {};
+ struct lysp_refine refine = {};
+
+ data = "<refine xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"unbounded\">"EXT_SUBELEM"</max-elements> </refine>";
+ assert_int_equal(test_element_helper(st, &data, &refine, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(refine.max, 0);
+ assert_true(refine.flags & LYS_SET_MAX);
+ assert_string_equal(refine.exts[0].name, "myext:c-define");
+ assert_int_equal(refine.exts[0].insubstmt_index, 0);
+ assert_int_equal(refine.exts[0].insubstmt, LYEXT_SUBSTMT_MAX);
+ FREE_ARRAY(st->ctx, refine.exts, lysp_ext_instance_free);
+
+ data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"5\">"EXT_SUBELEM"</max-elements> </list>";
+ assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(list.max, 5);
+ assert_true(list.flags & LYS_SET_MAX);
+ assert_string_equal(list.exts[0].name, "myext:c-define");
+ assert_int_equal(list.exts[0].insubstmt_index, 0);
+ assert_int_equal(list.exts[0].insubstmt, LYEXT_SUBSTMT_MAX);
+ FREE_ARRAY(st->ctx, list.exts, lysp_ext_instance_free);
+
+ data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"85\">"EXT_SUBELEM"</max-elements> </leaf-list>";
+ assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(llist.max, 85);
+ assert_true(llist.flags & LYS_SET_MAX);
+ assert_string_equal(llist.exts[0].name, "myext:c-define");
+ assert_int_equal(llist.exts[0].insubstmt_index, 0);
+ assert_int_equal(llist.exts[0].insubstmt, LYEXT_SUBSTMT_MAX);
+ FREE_ARRAY(st->ctx, llist.exts, lysp_ext_instance_free);
+
+ data = "<refine xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"10\"/> </refine>";
+ assert_int_equal(test_element_helper(st, &data, &refine, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(refine.max, 10);
+ assert_true(refine.flags & LYS_SET_MAX);
+
+ data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"0\"/> </list>";
+ assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"0\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+ data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"-10\"/> </list>";
+ assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"-10\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+ data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"k\"/> </list>";
+ assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"k\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+ data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <max-elements value=\"u12\"/> </list>";
+ assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"u12\" of \"value\" attribute in \"max-elements\" element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_min_elems_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node_list list = {};
+ struct lysp_node_leaflist llist = {};
+ struct lysp_refine refine = {};
+
+ data = "<refine xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"0\">"EXT_SUBELEM"</min-elements> </refine>";
+ assert_int_equal(test_element_helper(st, &data, &refine, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(refine.min, 0);
+ assert_true(refine.flags & LYS_SET_MIN);
+ assert_string_equal(refine.exts[0].name, "myext:c-define");
+ assert_int_equal(refine.exts[0].insubstmt_index, 0);
+ assert_int_equal(refine.exts[0].insubstmt, LYEXT_SUBSTMT_MIN);
+ FREE_ARRAY(st->ctx, refine.exts, lysp_ext_instance_free);
+
+ data = "<list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"41\">"EXT_SUBELEM"</min-elements> </list>";
+ assert_int_equal(test_element_helper(st, &data, &list, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(list.min, 41);
+ assert_true(list.flags & LYS_SET_MIN);
+ assert_string_equal(list.exts[0].name, "myext:c-define");
+ assert_int_equal(list.exts[0].insubstmt_index, 0);
+ assert_int_equal(list.exts[0].insubstmt, LYEXT_SUBSTMT_MIN);
+ FREE_ARRAY(st->ctx, list.exts, lysp_ext_instance_free);
+
+ data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"50\">"EXT_SUBELEM"</min-elements> </leaf-list>";
+ assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(llist.min, 50);
+ assert_true(llist.flags & LYS_SET_MIN);
+ assert_string_equal(llist.exts[0].name, "myext:c-define");
+ assert_int_equal(llist.exts[0].insubstmt_index, 0);
+ assert_int_equal(llist.exts[0].insubstmt, LYEXT_SUBSTMT_MIN);
+ FREE_ARRAY(st->ctx, llist.exts, lysp_ext_instance_free);
+
+ data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"-5\"/> </leaf-list>";
+ assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Value \"-5\" of \"value\" attribute in \"min-elements\" element is out of bounds. Line number 1.");
+
+ data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"99999999999999999\"/> </leaf-list>";
+ assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Value \"99999999999999999\" of \"value\" attribute in \"min-elements\" element is out of bounds. Line number 1.");
+
+ data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"5k\"/> </leaf-list>";
+ assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"5k\" of \"value\" attribute in \"min-elements\" element. Line number 1.");
+
+ data = "<leaf-list xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"> <min-elements value=\"05\"/> </leaf-list>";
+ assert_int_equal(test_element_helper(st, &data, &llist, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"05\" of \"value\" attribute in \"min-elements\" element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_ordby_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ uint16_t flags = 0;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<ordered-by value=\"system\">"EXT_SUBELEM"</ordered-by>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, &exts, true), LY_SUCCESS);
+ assert_true(flags & LYS_ORDBY_SYSTEM);
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_ORDEREDBY);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+
+ data = ELEMENT_WRAPPER_START "<ordered-by value=\"user\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, true), LY_SUCCESS);
+ assert_true(flags & LYS_ORDBY_USER);
+
+ data = ELEMENT_WRAPPER_START "<ordered-by value=\"inv\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &flags, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"inv\" of \"value\" attribute in \"ordered-by\" element. Valid values are \"system\" and \"user\". Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_any_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+ struct lysp_node_anydata *parsed = NULL;
+
+ /* anyxml max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<anyxml name=\"any-name\">"
+ "<config value=\"true\" />"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"feature\" />"
+ "<mandatory value=\"true\" />"
+ "<must condition=\"must-cond\" />"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"deprecated\"/>"
+ "<when condition=\"when-cond\"/>"
+ EXT_SUBELEM
+ "</anyxml>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_anydata *)siblings;
+ assert_null(parsed->parent);
+ assert_int_equal(parsed->nodetype, LYS_ANYXML);
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_true(parsed->flags & LYS_MAND_TRUE);
+ assert_true(parsed->flags & LYS_STATUS_DEPRC);
+ assert_null(parsed->next);
+ assert_string_equal(parsed->name, "any-name");
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_string_equal(*parsed->iffeatures, "feature");
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ /* anydata max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<anydata name=\"any-name\">"
+ "<config value=\"true\" />"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"feature\" />"
+ "<mandatory value=\"true\" />"
+ "<must condition=\"must-cond\" />"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"deprecated\"/>"
+ "<when condition=\"when-cond\"/>"
+ EXT_SUBELEM
+ "</anydata>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_anydata *)siblings;
+ assert_null(parsed->parent);
+ assert_int_equal(parsed->nodetype, LYS_ANYDATA);
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_true(parsed->flags & LYS_MAND_TRUE);
+ assert_true(parsed->flags & LYS_STATUS_DEPRC);
+ assert_null(parsed->next);
+ assert_string_equal(parsed->name, "any-name");
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_string_equal(*parsed->iffeatures, "feature");
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ /* min subelems */
+ node_meta.parent = (void *)0x10;
+ data = ELEMENT_WRAPPER_START "<anydata name=\"any-name\"> </anydata>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_anydata *)siblings;
+ assert_ptr_equal(parsed->parent, node_meta.parent);
+ assert_int_equal(parsed->nodetype, LYS_ANYDATA);
+ assert_null(parsed->next);
+ assert_null(parsed->exts);
+ lysp_node_free(st->ctx, siblings);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_leaf_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+ struct lysp_node_leaf *parsed = NULL;
+
+ /* max elements */
+ data = ELEMENT_WRAPPER_START
+ "<leaf name=\"leaf\">"
+ "<config value=\"true\" />"
+ "<default value=\"def-val\"/>"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"feature\" />"
+ "<mandatory value=\"true\" />"
+ "<must condition=\"must-cond\" />"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"deprecated\"/>"
+ "<type name=\"type\"/>"
+ "<units name=\"uni\"/>"
+ "<when condition=\"when-cond\"/>"
+ EXT_SUBELEM
+ "</leaf>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_leaf *)siblings;
+ assert_null(parsed->parent);
+ assert_int_equal(parsed->nodetype, LYS_LEAF);
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_true(parsed->flags & LYS_MAND_TRUE);
+ assert_true(parsed->flags & LYS_STATUS_DEPRC);
+ assert_null(parsed->next);
+ assert_string_equal(parsed->name, "leaf");
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_string_equal(*parsed->iffeatures, "feature");
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ assert_string_equal(parsed->musts->arg, "must-cond");
+ assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->units, "uni");
+ assert_string_equal(parsed->dflt, "def-val");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ /* min elements */
+ data = ELEMENT_WRAPPER_START "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_leaf *)siblings;
+ assert_string_equal(parsed->name, "leaf");
+ assert_string_equal(parsed->type.name, "type");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_leaf_list_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {.parent = NULL, .nodes = &siblings};
+ struct lysp_node_leaflist *parsed = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<leaf-list name=\"llist\">"
+ "<config value=\"true\" />"
+ "<default value=\"def-val0\"/>"
+ "<default value=\"def-val1\"/>"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"feature\"/>"
+ "<max-elements value=\"5\"/>"
+ "<must condition=\"must-cond\"/>"
+ "<ordered-by value=\"user\" />"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<type name=\"type\"/>"
+ "<units name=\"uni\"/>"
+ "<when condition=\"when-cond\"/>"
+ EXT_SUBELEM
+ "</leaf-list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_leaflist *)siblings;
+ assert_string_equal(parsed->dflts[0], "def-val0");
+ assert_string_equal(parsed->dflts[1], "def-val1");
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(*parsed->iffeatures, "feature");
+ assert_int_equal(parsed->max, 5);
+ assert_string_equal(parsed->musts->arg, "must-cond");
+ assert_string_equal(parsed->name, "llist");
+ assert_null(parsed->next);
+ assert_int_equal(parsed->nodetype, LYS_LEAFLIST);
+ assert_null(parsed->parent);
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->units, "uni");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_true(parsed->flags & LYS_ORDBY_USER);
+ assert_true(parsed->flags & LYS_STATUS_CURR);
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<leaf-list name=\"llist\">"
+ "<config value=\"true\" />"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"feature\"/>"
+ "<min-elements value=\"5\"/>"
+ "<must condition=\"must-cond\"/>"
+ "<ordered-by value=\"user\" />"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<type name=\"type\"/>"
+ "<units name=\"uni\"/>"
+ "<when condition=\"when-cond\"/>"
+ EXT_SUBELEM
+ "</leaf-list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_leaflist *)siblings;
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(*parsed->iffeatures, "feature");
+ assert_int_equal(parsed->min, 5);
+ assert_string_equal(parsed->musts->arg, "must-cond");
+ assert_string_equal(parsed->name, "llist");
+ assert_null(parsed->next);
+ assert_int_equal(parsed->nodetype, LYS_LEAFLIST);
+ assert_null(parsed->parent);
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->units, "uni");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_true(parsed->flags & LYS_ORDBY_USER);
+ assert_true(parsed->flags & LYS_STATUS_CURR);
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<leaf-list name=\"llist\">"
+ "<config value=\"true\" />"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"feature\"/>"
+ "<max-elements value=\"15\"/>"
+ "<min-elements value=\"5\"/>"
+ "<must condition=\"must-cond\"/>"
+ "<ordered-by value=\"user\" />"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<type name=\"type\"/>"
+ "<units name=\"uni\"/>"
+ "<when condition=\"when-cond\"/>"
+ "</leaf-list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_leaflist *)siblings;
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(*parsed->iffeatures, "feature");
+ assert_int_equal(parsed->min, 5);
+ assert_int_equal(parsed->max, 15);
+ assert_string_equal(parsed->musts->arg, "must-cond");
+ assert_string_equal(parsed->name, "llist");
+ assert_null(parsed->next);
+ assert_int_equal(parsed->nodetype, LYS_LEAFLIST);
+ assert_null(parsed->parent);
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->type.name, "type");
+ assert_string_equal(parsed->units, "uni");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_true(parsed->flags & LYS_ORDBY_USER);
+ assert_true(parsed->flags & LYS_STATUS_CURR);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<leaf-list name=\"llist\">"
+ "<type name=\"type\"/>"
+ "</leaf-list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_leaflist *)siblings;
+ assert_string_equal(parsed->name, "llist");
+ assert_string_equal(parsed->type.name, "type");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ /* invalid combinations */
+ data = ELEMENT_WRAPPER_START
+ "<leaf-list name=\"llist\">"
+ "<max-elements value=\"5\"/>"
+ "<min-elements value=\"15\"/>"
+ "<type name=\"type\"/>"
+ "</leaf-list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid combination of min-elements and max-elements: min value 15 is bigger than the max value 5. Line number 1.");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<leaf-list name=\"llist\">"
+ "<default value=\"def-val1\"/>"
+ "<min-elements value=\"15\"/>"
+ "<type name=\"type\"/>"
+ "</leaf-list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid combination of sub-elemnts \"min-elements\" and \"default\" in \"leaf-list\" element. Line number 1.");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<leaf-list name=\"llist\">"
+ "</leaf-list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory sub-element \"type\" of \"leaf-list\" element. Line number 1.");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_presence_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *val;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<presence value=\"presence-val\">"EXT_SUBELEM"</presence>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(val, "presence-val");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_PRESENCE);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ FREE_STRING(st->ctx, val);
+
+ data = ELEMENT_WRAPPER_START "<presence value=\"presence-val\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(val, "presence-val");
+ FREE_STRING(st->ctx, val);
+
+ data = ELEMENT_WRAPPER_START "<presence/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory attribute value of presence element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_key_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ const char *val;
+ struct lysp_ext_instance *exts = NULL;
+
+ data = ELEMENT_WRAPPER_START "<key value=\"key-value\">"EXT_SUBELEM"</key>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, &exts, true), LY_SUCCESS);
+ assert_string_equal(val, "key-value");
+ assert_string_equal(exts[0].name, "myext:c-define");
+ assert_int_equal(exts[0].insubstmt_index, 0);
+ assert_int_equal(exts[0].insubstmt, LYEXT_SUBSTMT_KEY);
+ FREE_ARRAY(st->ctx, exts, lysp_ext_instance_free);
+ FREE_STRING(st->ctx, val);
+
+ data = ELEMENT_WRAPPER_START "<key value=\"key-value\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(val, "key-value");
+ FREE_STRING(st->ctx, val);
+
+ data = ELEMENT_WRAPPER_START "<key/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &val, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Missing mandatory attribute value of key element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_typedef_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_tpdf *tpdfs = NULL;
+ struct tree_node_meta typdef_meta = {NULL, (struct lysp_node **)&tpdfs};
+
+ data = ELEMENT_WRAPPER_START
+ "<typedef name=\"tpdf-name\">"
+ "<default value=\"def-val\"/>"
+ "<description><text>desc-text</text></description>"
+ "<reference><text>ref-text</text></reference>"
+ "<status value=\"current\"/>"
+ "<type name=\"type\"/>"
+ "<units name=\"uni\"/>"
+ EXT_SUBELEM
+ "</typedef>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &typdef_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(tpdfs[0].dflt, "def-val");
+ assert_string_equal(tpdfs[0].dsc, "desc-text");
+ assert_string_equal(tpdfs[0].name, "tpdf-name");
+ assert_string_equal(tpdfs[0].ref, "ref-text");
+ assert_string_equal(tpdfs[0].type.name, "type");
+ assert_string_equal(tpdfs[0].units, "uni");
+ assert_true(tpdfs[0].flags & LYS_STATUS_CURR);
+ assert_string_equal(tpdfs[0].exts[0].name, "myext:c-define");
+ assert_int_equal(tpdfs[0].exts[0].insubstmt_index, 0);
+ assert_int_equal(tpdfs[0].exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, tpdfs, lysp_tpdf_free);
+ tpdfs = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<typedef name=\"tpdf-name\">"
+ "<type name=\"type\"/>"
+ "</typedef>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &typdef_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(tpdfs[0].name, "tpdf-name");
+ assert_string_equal(tpdfs[0].type.name, "type");
+ FREE_ARRAY(st->ctx, tpdfs, lysp_tpdf_free);
+ tpdfs = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_refine_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_refine *refines = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<refine target-node=\"target\">"
+ "<if-feature name=\"feature\" />"
+ "<must condition=\"cond\" />"
+ "<presence value=\"presence\" />"
+ "<default value=\"def\" />"
+ "<config value=\"true\" />"
+ "<mandatory value=\"true\" />"
+ "<min-elements value=\"10\" />"
+ "<max-elements value=\"20\" />"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ EXT_SUBELEM
+ "</refine>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &refines, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(refines->nodeid, "target");
+ assert_string_equal(*refines->dflts, "def");
+ assert_string_equal(refines->dsc, "desc");
+ assert_true(refines->flags & LYS_CONFIG_W);
+ assert_true(refines->flags & LYS_MAND_TRUE);
+ assert_string_equal(*refines->iffeatures, "feature");
+ assert_int_equal(refines->max, 20);
+ assert_int_equal(refines->min, 10);
+ assert_string_equal(refines->musts->arg, "cond");
+ assert_string_equal(refines->presence, "presence");
+ assert_string_equal(refines->ref, "ref");
+ assert_string_equal(refines->exts[0].name, "myext:c-define");
+ assert_int_equal(refines->exts[0].insubstmt_index, 0);
+ assert_int_equal(refines->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, refines, lysp_refine_free);
+ refines = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<refine target-node=\"target\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &refines, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(refines->nodeid, "target");
+ FREE_ARRAY(st->ctx, refines, lysp_refine_free);
+ refines = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_uses_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {NULL, &siblings};
+ struct lysp_node_uses *parsed = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<uses name=\"uses-name\">"
+ "<when condition=\"cond\" />"
+ "<if-feature name=\"feature\" />"
+ "<status value=\"obsolete\" />"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ "<refine target-node=\"target\"/>"
+ "<augment target-node=\"target\" />"
+ EXT_SUBELEM
+ "</uses>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_uses *)&siblings[0];
+ assert_string_equal(parsed->name, "uses-name");
+ assert_string_equal(parsed->dsc, "desc");
+ assert_true(parsed->flags & LYS_STATUS_OBSLT);
+ assert_string_equal(*parsed->iffeatures, "feature");
+ assert_null(parsed->next);
+ assert_int_equal(parsed->nodetype, LYS_USES);
+ assert_null(parsed->parent);
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->refines->nodeid, "target");
+ assert_string_equal(parsed->when->cond, "cond");
+ assert_string_equal(parsed->augments->nodeid, "target");
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<uses name=\"uses-name\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(siblings[0].name, "uses-name");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_revision_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_revision *revs = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<revision date=\"2018-12-25\">"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ EXT_SUBELEM
+ "</revision>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &revs, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(revs->date, "2018-12-25");
+ assert_string_equal(revs->dsc, "desc");
+ assert_string_equal(revs->ref, "ref");
+ assert_string_equal(revs->exts[0].name, "myext:c-define");
+ assert_int_equal(revs->exts[0].insubstmt_index, 0);
+ assert_int_equal(revs->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, revs, lysp_revision_free);
+ revs = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<revision date=\"2005-05-05\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &revs, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(revs->date, "2005-05-05");
+ FREE_ARRAY(st->ctx, revs, lysp_revision_free);
+ revs = NULL;
+
+ /* invalid value */
+ data = ELEMENT_WRAPPER_START "<revision date=\"05-05-2005\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &revs, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"05-05-2005\" of \"revision\". Line number 1.");
+ FREE_ARRAY(st->ctx, revs, lysp_revision_free);
+ revs = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_include_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_include *includes = NULL;
+ struct include_meta inc_meta = {"module-name", &includes};
+
+ /* max subelems */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<include module=\"mod\">"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ "<revision-date date=\"1999-09-09\"/>"
+ EXT_SUBELEM
+ "</include>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(includes->name, "mod");
+ assert_string_equal(includes->dsc, "desc");
+ assert_string_equal(includes->ref, "ref");
+ assert_string_equal(includes->rev, "1999-09-09");
+ assert_string_equal(includes->exts[0].name, "myext:c-define");
+ assert_int_equal(includes->exts[0].insubstmt_index, 0);
+ assert_int_equal(includes->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, includes, lysp_include_free);
+ includes = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<include module=\"mod\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(includes->name, "mod");
+ FREE_ARRAY(st->ctx, includes, lysp_include_free);
+ includes = NULL;
+
+ /* invalid combinations */
+ st->yin_ctx->mod_version = LYS_VERSION_1_0;
+ data = ELEMENT_WRAPPER_START
+ "<include module=\"mod\">"
+ "<description><text>desc</text></description>"
+ "<revision-date date=\"1999-09-09\"/>"
+ "</include>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid sub-elemnt \"description\" of \"include\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+ FREE_ARRAY(st->ctx, includes, lysp_include_free);
+ includes = NULL;
+
+ st->yin_ctx->mod_version = LYS_VERSION_1_0;
+ data = ELEMENT_WRAPPER_START
+ "<include module=\"mod\">"
+ "<reference><text>ref</text></reference>"
+ "<revision-date date=\"1999-09-09\"/>"
+ "</include>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid sub-elemnt \"reference\" of \"include\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+ FREE_ARRAY(st->ctx, includes, lysp_include_free);
+ includes = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_feature_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_feature *features = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<feature name=\"feature-name\">"
+ "<if-feature name=\"iff\"/>"
+ "<status value=\"deprecated\"/>"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ EXT_SUBELEM
+ "</feature>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &features, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(features->name, "feature-name");
+ assert_string_equal(features->dsc, "desc");
+ assert_true(features->flags & LYS_STATUS_DEPRC);
+ assert_string_equal(*features->iffeatures, "iff");
+ assert_string_equal(features->ref, "ref");
+ assert_string_equal(features->exts[0].name, "myext:c-define");
+ assert_int_equal(features->exts[0].insubstmt_index, 0);
+ assert_int_equal(features->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, features, lysp_feature_free);
+ features = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<feature name=\"feature-name\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &features, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(features->name, "feature-name");
+ FREE_ARRAY(st->ctx, features, lysp_feature_free);
+ features = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_identity_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_ident *identities = NULL;
+
+ /* max subelems */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<identity name=\"ident-name\">"
+ "<if-feature name=\"iff\"/>"
+ "<base name=\"base-name\"/>"
+ "<status value=\"deprecated\"/>"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ EXT_SUBELEM
+ "</identity>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &identities, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(identities->name, "ident-name");
+ assert_string_equal(*identities->bases, "base-name");
+ assert_string_equal(*identities->iffeatures, "iff");
+ assert_string_equal(identities->dsc, "desc");
+ assert_string_equal(identities->ref, "ref");
+ assert_true(identities->flags & LYS_STATUS_DEPRC);
+ assert_string_equal(identities->exts[0].name, "myext:c-define");
+ assert_int_equal(identities->exts[0].insubstmt_index, 0);
+ assert_int_equal(identities->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, identities, lysp_ident_free);
+ identities = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<identity name=\"ident-name\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &identities, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(identities->name, "ident-name");
+ FREE_ARRAY(st->ctx, identities, lysp_ident_free);
+ identities = NULL;
+
+ /* invalid */
+ st->yin_ctx->mod_version = LYS_VERSION_1_0;
+ data = ELEMENT_WRAPPER_START
+ "<identity name=\"ident-name\">"
+ "<if-feature name=\"iff\"/>"
+ "</identity>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &identities, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid sub-elemnt \"if-feature\" of \"identity\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+ FREE_ARRAY(st->ctx, identities, lysp_ident_free);
+ identities = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_list_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {NULL, &siblings};
+ struct lysp_node_list *parsed = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<list name=\"list-name\">"
+ "<when condition=\"when\"/>"
+ "<if-feature name=\"iff\"/>"
+ "<must condition=\"must-cond\"/>"
+ "<key value=\"key\"/>"
+ "<unique tag=\"utag\"/>"
+ "<config value=\"true\"/>"
+ "<min-elements value=\"10\"/>"
+ "<ordered-by value=\"user\"/>"
+ "<status value=\"deprecated\"/>"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<container name=\"cont\"/>"
+ "<choice name=\"choice\"/>"
+ "<action name=\"action\"/>"
+ "<grouping name=\"grp\"/>"
+ "<notification name=\"notf\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"sub-list\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ "<uses name=\"uses-name\"/>"
+ EXT_SUBELEM
+ "</list>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_list *)&siblings[0];
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(parsed->child->name, "anyd");
+ assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+ assert_string_equal(parsed->child->next->name, "anyx");
+ assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+ assert_string_equal(parsed->child->next->next->name, "cont");
+ assert_int_equal(parsed->child->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(parsed->child->next->next->next->name, "choice");
+ assert_int_equal(parsed->child->next->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(parsed->child->next->next->next->next->name, "leaf");
+ assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(parsed->child->next->next->next->next->next->name, "llist");
+ assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->name, "sub-list");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(parsed->child->next->next->next->next->next->next->next->next);
+ assert_string_equal(parsed->groupings->name, "grp");
+ assert_string_equal(parsed->actions->name, "action");
+ assert_int_equal(parsed->groupings->nodetype, LYS_GROUPING);
+ assert_string_equal(parsed->notifs->name, "notf");
+ assert_true(parsed->flags & LYS_ORDBY_USER);
+ assert_true(parsed->flags & LYS_STATUS_DEPRC);
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_string_equal(*parsed->iffeatures, "iff");
+ assert_string_equal(parsed->key, "key");
+ assert_int_equal(parsed->min, 10);
+ assert_string_equal(parsed->musts->arg, "must-cond");
+ assert_string_equal(parsed->name, "list-name");
+ assert_null(parsed->next);
+ assert_int_equal(parsed->nodetype, LYS_LIST);
+ assert_null(parsed->parent);
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->typedefs->name, "tpdf");
+ assert_string_equal(*parsed->uniques, "utag");
+ assert_string_equal(parsed->when->cond, "when");
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ ly_set_erase(&st->yin_ctx->tpdfs_nodes, NULL);
+ siblings = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<list name=\"list-name\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_list *)&siblings[0];
+ assert_string_equal(parsed->name, "list-name");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_notification_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_notif *notifs = NULL;
+ struct tree_node_meta notif_meta = {NULL, (struct lysp_node **)¬ifs};
+
+ /* max subelems */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<notification name=\"notif-name\">"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"iff\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"sub-list\"/>"
+ "<must condition=\"cond\"/>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"deprecated\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ "<uses name=\"uses-name\"/>"
+ "<container name=\"cont\"/>"
+ "<choice name=\"choice\"/>"
+ "<grouping name=\"grp\"/>"
+ EXT_SUBELEM
+ "</notification>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, ¬if_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(notifs->name, "notif-name");
+ assert_string_equal(notifs->data->name, "anyd");
+ assert_int_equal(notifs->data->nodetype, LYS_ANYDATA);
+ assert_string_equal(notifs->data->next->name, "anyx");
+ assert_int_equal(notifs->data->next->nodetype, LYS_ANYXML);
+ assert_string_equal(notifs->data->next->next->name, "leaf");
+ assert_int_equal(notifs->data->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(notifs->data->next->next->next->name, "llist");
+ assert_int_equal(notifs->data->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(notifs->data->next->next->next->next->name, "sub-list");
+ assert_int_equal(notifs->data->next->next->next->next->nodetype, LYS_LIST);
+ assert_true(notifs->flags & LYS_STATUS_DEPRC);
+ assert_string_equal(notifs->groupings->name, "grp");
+ assert_int_equal(notifs->groupings->nodetype, LYS_GROUPING);
+ assert_string_equal(notifs->data->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(notifs->data->next->next->next->next->next->nodetype, LYS_USES);
+ assert_string_equal(notifs->data->next->next->next->next->next->next->name, "cont");
+ assert_int_equal(notifs->data->next->next->next->next->next->next->nodetype, LYS_CONTAINER);
+ assert_int_equal(notifs->data->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(notifs->data->next->next->next->next->next->next->next->name, "choice");
+ assert_null(notifs->data->next->next->next->next->next->next->next->next);
+ assert_string_equal(*notifs->iffeatures, "iff");
+ assert_string_equal(notifs->musts->arg, "cond");
+ assert_int_equal(notifs->nodetype, LYS_NOTIF);
+ assert_null(notifs->parent);
+ assert_string_equal(notifs->ref, "ref");
+ assert_string_equal(notifs->typedefs->name, "tpdf");
+ assert_string_equal(notifs->exts[0].name, "myext:c-define");
+ assert_int_equal(notifs->exts[0].insubstmt_index, 0);
+ assert_int_equal(notifs->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, notifs, lysp_notif_free);
+ notifs = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<notification name=\"notif-name\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, ¬if_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(notifs->name, "notif-name");
+ FREE_ARRAY(st->ctx, notifs, lysp_notif_free);
+ notifs = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_grouping_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_grp *grps = NULL;
+ struct tree_node_meta grp_meta = {NULL, (struct lysp_node **)&grps};
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<grouping name=\"grp-name\">"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<description><text>desc</text></description>"
+ "<grouping name=\"sub-grp\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"list\"/>"
+ "<notification name=\"notf\"/>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ "<uses name=\"uses-name\"/>"
+ "<action name=\"act\"/>"
+ "<container name=\"cont\"/>"
+ "<choice name=\"choice\"/>"
+ EXT_SUBELEM
+ "</grouping>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &grp_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(grps->name, "grp-name");
+ assert_string_equal(grps->data->name, "anyd");
+ assert_string_equal(grps->data->next->name, "anyx");
+ assert_string_equal(grps->data->next->next->name, "leaf");
+ assert_string_equal(grps->data->next->next->next->name, "llist");
+ assert_string_equal(grps->data->next->next->next->next->name, "list");
+ assert_string_equal(grps->dsc, "desc");
+ assert_true(grps->flags & LYS_STATUS_CURR);
+ assert_string_equal(grps->groupings->name, "sub-grp");
+ assert_int_equal(grps->nodetype, LYS_GROUPING);
+ assert_string_equal(grps->notifs->name, "notf");
+ assert_null(grps->parent);
+ assert_string_equal(grps->ref, "ref");
+ assert_string_equal(grps->typedefs->name, "tpdf");
+ assert_string_equal(grps->actions->name, "act");
+ assert_string_equal(grps->data->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(grps->data->next->next->next->next->next->nodetype, LYS_USES);
+ assert_string_equal(grps->data->next->next->next->next->next->next->name, "cont");
+ assert_int_equal(grps->data->next->next->next->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(grps->data->next->next->next->next->next->next->next->name, "choice");
+ assert_int_equal(grps->data->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(grps->exts[0].name, "myext:c-define");
+ assert_int_equal(grps->exts[0].insubstmt_index, 0);
+ assert_int_equal(grps->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, grps, lysp_grp_free);
+ grps = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<grouping name=\"grp-name\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &grp_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(grps->name, "grp-name");
+ FREE_ARRAY(st->ctx, grps, lysp_grp_free);
+ grps = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_container_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {NULL, &siblings};
+ struct lysp_node_container *parsed = NULL;
+
+ /* max subelems */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<container name=\"cont-name\">"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<config value=\"true\"/>"
+ "<container name=\"subcont\"/>"
+ "<description><text>desc</text></description>"
+ "<grouping name=\"sub-grp\"/>"
+ "<if-feature name=\"iff\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"list\"/>"
+ "<must condition=\"cond\"/>"
+ "<notification name=\"notf\"/>"
+ "<presence value=\"presence\"/>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ "<uses name=\"uses-name\"/>"
+ "<when condition=\"when-cond\"/>"
+ "<action name=\"act\"/>"
+ "<choice name=\"choice\"/>"
+ EXT_SUBELEM
+ "</container>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_container *)siblings;
+ assert_string_equal(parsed->name, "cont-name");
+ assert_null(parsed->parent);
+ assert_int_equal(parsed->nodetype, LYS_CONTAINER);
+ assert_true(parsed->flags & LYS_CONFIG_W);
+ assert_true(parsed->flags & LYS_STATUS_CURR);
+ assert_null(parsed->next);
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_string_equal(*parsed->iffeatures, "iff");
+ assert_string_equal(parsed->musts->arg, "cond");
+ assert_string_equal(parsed->presence, "presence");
+ assert_string_equal(parsed->typedefs->name, "tpdf");
+ assert_string_equal(parsed->groupings->name, "sub-grp");
+ assert_string_equal(parsed->child->name, "anyd");
+ assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+ assert_string_equal(parsed->child->next->name, "anyx");
+ assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+ assert_string_equal(parsed->child->next->next->name, "subcont");
+ assert_int_equal(parsed->child->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(parsed->child->next->next->next->name, "leaf");
+ assert_int_equal(parsed->child->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(parsed->child->next->next->next->next->name, "llist");
+ assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(parsed->child->next->next->next->next->next->name, "list");
+ assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "choice");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+ assert_null(parsed->child->next->next->next->next->next->next->next->next);
+ assert_string_equal(parsed->notifs->name, "notf");
+ assert_string_equal(parsed->actions->name, "act");
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ ly_set_erase(&st->yin_ctx->tpdfs_nodes, NULL);
+ siblings = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<container name=\"cont-name\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_container *)siblings;
+ assert_string_equal(parsed->name, "cont-name");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_case_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {NULL, &siblings};
+ struct lysp_node_case *parsed = NULL;
+
+ /* max subelems */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<case name=\"case-name\">"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<container name=\"subcont\"/>"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"iff\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"list\"/>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<uses name=\"uses-name\"/>"
+ "<when condition=\"when-cond\"/>"
+ "<choice name=\"choice\"/>"
+ EXT_SUBELEM
+ "</case>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_case *)siblings;
+ assert_string_equal(parsed->name, "case-name");
+ assert_null(parsed->parent);
+ assert_int_equal(parsed->nodetype, LYS_CASE);
+ assert_true(parsed->flags & LYS_STATUS_CURR);
+ assert_null(parsed->next);
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_string_equal(*parsed->iffeatures, "iff");
+ assert_string_equal(parsed->child->name, "anyd");
+ assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+ assert_string_equal(parsed->child->next->name, "anyx");
+ assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+ assert_string_equal(parsed->child->next->next->name, "subcont");
+ assert_int_equal(parsed->child->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(parsed->child->next->next->next->name, "leaf");
+ assert_int_equal(parsed->child->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(parsed->child->next->next->next->next->name, "llist");
+ assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(parsed->child->next->next->next->next->next->name, "list");
+ assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "choice");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_CHOICE);
+ assert_null(parsed->child->next->next->next->next->next->next->next->next);
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<case name=\"case-name\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_case *)siblings;
+ assert_string_equal(parsed->name, "case-name");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_choice_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_node *siblings = NULL;
+ struct tree_node_meta node_meta = {NULL, &siblings};
+ struct lysp_node_choice *parsed = NULL;
+
+ /* max subelems */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<choice name=\"choice-name\">"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<case name=\"sub-case\"/>"
+ "<choice name=\"choice\"/>"
+ "<config value=\"true\"/>"
+ "<container name=\"subcont\"/>"
+ "<default value=\"def\"/>"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"iff\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"list\"/>"
+ "<mandatory value=\"true\" />"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<when condition=\"when-cond\"/>"
+ EXT_SUBELEM
+ "</choice>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_choice *)siblings;
+ assert_string_equal(parsed->name, "choice-name");
+ assert_null(parsed->parent);
+ assert_int_equal(parsed->nodetype, LYS_CHOICE);
+ assert_true(parsed->flags & LYS_CONFIG_W && parsed->flags & LYS_MAND_TRUE && parsed->flags & LYS_STATUS_CURR);
+ assert_null(parsed->next);
+ assert_string_equal(parsed->dsc, "desc");
+ assert_string_equal(parsed->ref, "ref");
+ assert_string_equal(parsed->when->cond, "when-cond");
+ assert_string_equal(*parsed->iffeatures, "iff");
+ assert_string_equal(parsed->child->name, "anyd");
+ assert_int_equal(parsed->child->nodetype, LYS_ANYDATA);
+ assert_string_equal(parsed->child->next->name, "anyx");
+ assert_int_equal(parsed->child->next->nodetype, LYS_ANYXML);
+ assert_string_equal(parsed->child->next->next->name, "sub-case");
+ assert_int_equal(parsed->child->next->next->nodetype, LYS_CASE);
+ assert_string_equal(parsed->child->next->next->next->name, "choice");
+ assert_int_equal(parsed->child->next->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(parsed->child->next->next->next->next->name, "subcont");
+ assert_int_equal(parsed->child->next->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(parsed->child->next->next->next->next->next->name, "leaf");
+ assert_int_equal(parsed->child->next->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->name, "llist");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(parsed->child->next->next->next->next->next->next->next->name, "list");
+ assert_int_equal(parsed->child->next->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_null(parsed->child->next->next->next->next->next->next->next->next);
+ assert_string_equal(parsed->exts[0].name, "myext:c-define");
+ assert_int_equal(parsed->exts[0].insubstmt_index, 0);
+ assert_int_equal(parsed->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<choice name=\"choice-name\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &node_meta, NULL, NULL, true), LY_SUCCESS);
+ parsed = (struct lysp_node_choice *)siblings;
+ assert_string_equal(parsed->name, "choice-name");
+ lysp_node_free(st->ctx, siblings);
+ siblings = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_inout_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_action_inout inout = {};
+ struct inout_meta inout_meta = {NULL, &inout};
+
+ /* max subelements */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<input>"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<choice name=\"choice\"/>"
+ "<container name=\"subcont\"/>"
+ "<grouping name=\"sub-grp\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"list\"/>"
+ "<must condition=\"cond\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ "<uses name=\"uses-name\"/>"
+ EXT_SUBELEM
+ "</input>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_null(inout.parent);
+ assert_int_equal(inout.nodetype, LYS_INPUT);
+ assert_string_equal(inout.musts->arg, "cond");
+ assert_string_equal(inout.typedefs->name, "tpdf");
+ assert_string_equal(inout.groupings->name, "sub-grp");
+ assert_string_equal(inout.data->name, "anyd");
+ assert_int_equal(inout.data->nodetype, LYS_ANYDATA);
+ assert_string_equal(inout.data->next->name, "anyx");
+ assert_int_equal(inout.data->next->nodetype, LYS_ANYXML);
+ assert_string_equal(inout.data->next->next->name, "choice");
+ assert_int_equal(inout.data->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(inout.data->next->next->next->name, "subcont");
+ assert_int_equal(inout.data->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(inout.data->next->next->next->next->name, "leaf");
+ assert_int_equal(inout.data->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(inout.data->next->next->next->next->next->name, "llist");
+ assert_int_equal(inout.data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(inout.data->next->next->next->next->next->next->name, "list");
+ assert_int_equal(inout.data->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(inout.data->next->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(inout.data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(inout.data->next->next->next->next->next->next->next->next);
+ assert_string_equal(inout.exts[0].name, "myext:c-define");
+ assert_int_equal(inout.exts[0].insubstmt_index, 0);
+ assert_int_equal(inout.exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_action_inout_free(st->ctx, &inout);
+ memset(&inout, 0, sizeof inout);
+
+ /* max subelements */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<output>"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<choice name=\"choice\"/>"
+ "<container name=\"subcont\"/>"
+ "<grouping name=\"sub-grp\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"list\"/>"
+ "<must condition=\"cond\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ "<uses name=\"uses-name\"/>"
+ EXT_SUBELEM
+ "</output>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_null(inout.parent);
+ assert_int_equal(inout.nodetype, LYS_OUTPUT);
+ assert_string_equal(inout.musts->arg, "cond");
+ assert_string_equal(inout.typedefs->name, "tpdf");
+ assert_string_equal(inout.groupings->name, "sub-grp");
+ assert_string_equal(inout.data->name, "anyd");
+ assert_int_equal(inout.data->nodetype, LYS_ANYDATA);
+ assert_string_equal(inout.data->next->name, "anyx");
+ assert_int_equal(inout.data->next->nodetype, LYS_ANYXML);
+ assert_string_equal(inout.data->next->next->name, "choice");
+ assert_int_equal(inout.data->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(inout.data->next->next->next->name, "subcont");
+ assert_int_equal(inout.data->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(inout.data->next->next->next->next->name, "leaf");
+ assert_int_equal(inout.data->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(inout.data->next->next->next->next->next->name, "llist");
+ assert_int_equal(inout.data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(inout.data->next->next->next->next->next->next->name, "list");
+ assert_int_equal(inout.data->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(inout.data->next->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(inout.data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(inout.data->next->next->next->next->next->next->next->next);
+ assert_string_equal(inout.exts[0].name, "myext:c-define");
+ assert_int_equal(inout.exts[0].insubstmt_index, 0);
+ assert_int_equal(inout.exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_action_inout_free(st->ctx, &inout);
+ memset(&inout, 0, sizeof inout);
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<input />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+ memset(&inout, 0, sizeof inout);
+
+ data = ELEMENT_WRAPPER_START "<output />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, true), LY_SUCCESS);
+ memset(&inout, 0, sizeof inout);
+
+ /* invalid combinations */
+ data = ELEMENT_WRAPPER_START "<input name=\"test\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &inout_meta, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Unexpected attribute \"name\" of \"input\" element. Line number 1.");
+ memset(&inout, 0, sizeof inout);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_action_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_action *actions = NULL;
+ struct tree_node_meta act_meta = {NULL, (struct lysp_node **)&actions};
+
+ /* max subelems */
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<action name=\"act\">"
+ "<description><text>desc</text></description>"
+ "<grouping name=\"grouping\"/>"
+ "<if-feature name=\"iff\"/>"
+ "<input><uses name=\"uses-name\"/></input>"
+ "<output><must condition=\"cond\"/></output>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"deprecated\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ EXT_SUBELEM
+ "</action>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &act_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_null(actions->parent);
+ assert_int_equal(actions->nodetype, LYS_ACTION);
+ assert_true(actions->flags & LYS_STATUS_DEPRC);
+ assert_string_equal(actions->name, "act");
+ assert_string_equal(actions->dsc, "desc");
+ assert_string_equal(actions->ref, "ref");
+ assert_string_equal(*actions->iffeatures, "iff");
+ assert_string_equal(actions->typedefs->name, "tpdf");
+ assert_string_equal(actions->groupings->name, "grouping");
+ assert_string_equal(actions->input.data->name, "uses-name");
+ assert_string_equal(actions->output.musts->arg, "cond");
+ assert_string_equal(actions->exts[0].name, "myext:c-define");
+ assert_int_equal(actions->exts[0].insubstmt_index, 0);
+ assert_int_equal(actions->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, actions, lysp_action_free)
+ actions = NULL;
+
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<rpc name=\"act\">"
+ "<description><text>desc</text></description>"
+ "<grouping name=\"grouping\"/>"
+ "<if-feature name=\"iff\"/>"
+ "<input><uses name=\"uses-name\"/></input>"
+ "<output><must condition=\"cond\"/></output>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"deprecated\"/>"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>"
+ EXT_SUBELEM
+ "</rpc>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &act_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_null(actions->parent);
+ assert_int_equal(actions->nodetype, LYS_ACTION);
+ assert_true(actions->flags & LYS_STATUS_DEPRC);
+ assert_string_equal(actions->name, "act");
+ assert_string_equal(actions->dsc, "desc");
+ assert_string_equal(actions->ref, "ref");
+ assert_string_equal(*actions->iffeatures, "iff");
+ assert_string_equal(actions->typedefs->name, "tpdf");
+ assert_string_equal(actions->groupings->name, "grouping");
+ assert_string_equal(actions->input.data->name, "uses-name");
+ assert_string_equal(actions->output.musts->arg, "cond");
+ assert_string_equal(actions->exts[0].name, "myext:c-define");
+ assert_int_equal(actions->exts[0].insubstmt_index, 0);
+ assert_int_equal(actions->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, actions, lysp_action_free)
+ actions = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START "<action name=\"act\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &act_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(actions->name, "act");
+ FREE_ARRAY(st->ctx, actions, lysp_action_free)
+ actions = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_augment_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_augment *augments = NULL;
+ struct tree_node_meta aug_meta = {NULL, (struct lysp_node **)&augments};
+
+ st->yin_ctx->mod_version = LYS_VERSION_1_1;
+ data = ELEMENT_WRAPPER_START
+ "<augment target-node=\"target\">"
+ "<action name=\"action\"/>"
+ "<anydata name=\"anyd\"/>"
+ "<anyxml name=\"anyx\"/>"
+ "<case name=\"case\"/>"
+ "<choice name=\"choice\"/>"
+ "<container name=\"subcont\"/>"
+ "<description><text>desc</text></description>"
+ "<if-feature name=\"iff\"/>"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>"
+ "<list name=\"list\"/>"
+ "<notification name=\"notif\"/>"
+ "<reference><text>ref</text></reference>"
+ "<status value=\"current\"/>"
+ "<uses name=\"uses\"/>"
+ "<when condition=\"when-cond\"/>"
+ EXT_SUBELEM
+ "</augment>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &aug_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(augments->nodeid, "target");
+ assert_null(augments->parent);
+ assert_int_equal(augments->nodetype, LYS_AUGMENT);
+ assert_true(augments->flags & LYS_STATUS_CURR);
+ assert_string_equal(augments->dsc, "desc");
+ assert_string_equal(augments->ref, "ref");
+ assert_string_equal(augments->when->cond, "when-cond");
+ assert_string_equal(*augments->iffeatures, "iff");
+ assert_string_equal(augments->child->name, "anyd");
+ assert_int_equal(augments->child->nodetype, LYS_ANYDATA);
+ assert_string_equal(augments->child->next->name, "anyx");
+ assert_int_equal(augments->child->next->nodetype, LYS_ANYXML);
+ assert_string_equal(augments->child->next->next->name, "case");
+ assert_int_equal(augments->child->next->next->nodetype, LYS_CASE);
+ assert_string_equal(augments->child->next->next->next->name, "choice");
+ assert_int_equal(augments->child->next->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(augments->child->next->next->next->next->name, "subcont");
+ assert_int_equal(augments->child->next->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(augments->child->next->next->next->next->next->name, "leaf");
+ assert_int_equal(augments->child->next->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(augments->child->next->next->next->next->next->next->name, "llist");
+ assert_int_equal(augments->child->next->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(augments->child->next->next->next->next->next->next->next->name, "list");
+ assert_int_equal(augments->child->next->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(augments->child->next->next->next->next->next->next->next->next->name, "uses");
+ assert_int_equal(augments->child->next->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(augments->child->next->next->next->next->next->next->next->next->next);
+ assert_string_equal(augments->actions->name, "action");
+ assert_string_equal(augments->notifs->name, "notif");
+ assert_string_equal(augments->exts[0].name, "myext:c-define");
+ assert_int_equal(augments->exts[0].insubstmt_index, 0);
+ assert_int_equal(augments->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, augments, lysp_augment_free)
+ augments = NULL;
+
+ data = ELEMENT_WRAPPER_START "<augment target-node=\"target\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &aug_meta, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(augments->nodeid, "target");
+ FREE_ARRAY(st->ctx, augments, lysp_augment_free)
+ augments = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_deviate_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_deviate *deviates = NULL;
+ struct lysp_deviate_add *d_add;
+ struct lysp_deviate_rpl *d_rpl;
+ struct lysp_deviate_del *d_del;
+
+ /* all valid arguments with min subelems */
+ data = ELEMENT_WRAPPER_START "<deviate value=\"not-supported\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(deviates->mod, LYS_DEV_NOT_SUPPORTED);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START "<deviate value=\"add\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(deviates->mod, LYS_DEV_ADD);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START "<deviate value=\"replace\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(deviates->mod, LYS_DEV_REPLACE);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START "<deviate value=\"delete\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(deviates->mod, LYS_DEV_DELETE);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ /* max subelems and valid arguments */
+ data = ELEMENT_WRAPPER_START
+ "<deviate value=\"not-supported\">"
+ EXT_SUBELEM
+ "</deviate>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ assert_int_equal(deviates->mod, LYS_DEV_NOT_SUPPORTED);
+ assert_string_equal(deviates->exts[0].name, "myext:c-define");
+ assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+ assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<deviate value=\"add\">"
+ "<units name=\"units\"/>"
+ "<must condition=\"cond\"/>"
+ "<unique tag=\"utag\"/>"
+ "<default value=\"def\"/>"
+ "<config value=\"true\"/>"
+ "<mandatory value=\"true\"/>"
+ "<min-elements value=\"5\"/>"
+ "<max-elements value=\"15\"/>"
+ EXT_SUBELEM
+ "</deviate>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ d_add = (struct lysp_deviate_add *)deviates;
+ assert_int_equal(d_add->mod, LYS_DEV_ADD);
+ assert_null(d_add->next);
+ assert_string_equal(d_add->units, "units");
+ assert_string_equal(d_add->musts->arg, "cond");
+ assert_string_equal(*d_add->uniques, "utag");
+ assert_string_equal(*d_add->dflts, "def");
+ assert_true(d_add->flags & LYS_MAND_TRUE && d_add->flags & LYS_CONFIG_W);
+ assert_int_equal(d_add->min, 5);
+ assert_int_equal(d_add->max, 15);
+ assert_string_equal(deviates->exts[0].name, "myext:c-define");
+ assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+ assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<deviate value=\"replace\">"
+ "<type name=\"newtype\"/>"
+ "<units name=\"uni\"/>"
+ "<default value=\"def\"/>"
+ "<config value=\"true\"/>"
+ "<mandatory value=\"true\"/>"
+ "<min-elements value=\"5\"/>"
+ "<max-elements value=\"15\"/>"
+ EXT_SUBELEM
+ "</deviate>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ d_rpl = (struct lysp_deviate_rpl *)deviates;
+ assert_int_equal(d_rpl->mod, LYS_DEV_REPLACE);
+ assert_null(d_rpl->next);
+ assert_string_equal(d_rpl->type->name, "newtype");
+ assert_string_equal(d_rpl->units, "uni");
+ assert_string_equal(d_rpl->dflt, "def");
+ assert_true(d_rpl->flags & LYS_MAND_TRUE && d_rpl->flags & LYS_CONFIG_W);
+ assert_int_equal(d_rpl->min, 5);
+ assert_int_equal(d_rpl->max, 15);
+ assert_string_equal(deviates->exts[0].name, "myext:c-define");
+ assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+ assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<deviate value=\"delete\">"
+ "<units name=\"u\"/>"
+ "<must condition=\"c\"/>"
+ "<unique tag=\"tag\"/>"
+ "<default value=\"default\"/>"
+ EXT_SUBELEM
+ "</deviate>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, true), LY_SUCCESS);
+ d_del = (struct lysp_deviate_del *)deviates;
+ assert_int_equal(d_del->mod, LYS_DEV_DELETE);
+ assert_null(d_del->next);
+ assert_string_equal(d_del->units, "u");
+ assert_string_equal(d_del->musts->arg, "c");
+ assert_string_equal(*d_del->uniques, "tag");
+ assert_string_equal(*d_del->dflts, "default");
+ assert_string_equal(deviates->exts[0].name, "myext:c-define");
+ assert_int_equal(deviates->exts[0].insubstmt_index, 0);
+ assert_int_equal(deviates->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_deviate_free(st->ctx, deviates);
+ free(deviates);
+ deviates = NULL;
+
+ /* invalid arguments */
+ data = ELEMENT_WRAPPER_START "<deviate value=\"\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START "<deviate value=\"invalid\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"invalid\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START "<deviate value=\"ad\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"ad\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START "<deviate value=\"adds\" />" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Invalid value \"adds\" of \"value\" attribute in \"deviate\" element. Valid values are \"not-supported\", \"add\", \"replace\" and \"delete\". Line number 1.");
+ deviates = NULL;
+
+ data = ELEMENT_WRAPPER_START
+ "<deviate value=\"not-supported\">"
+ "<must condition=\"c\"/>"
+ "</deviate>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviates, NULL, NULL, false), LY_EVALID);
+ logbuf_assert("Deviate of this type doesn't allow \"must\" as it's sub-element. Line number 1.");
+
+ st->finished_correctly = true;
+}
+
+static void
+test_deviation_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lysp_deviation *deviations = NULL;
+
+ /* min subelems */
+ data = ELEMENT_WRAPPER_START
+ "<deviation target-node=\"target\">"
+ "<deviate value=\"not-supported\"/>"
+ "</deviation>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviations, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(deviations->nodeid, "target");
+ assert_int_equal(deviations->deviates->mod, LYS_DEV_NOT_SUPPORTED);
+ FREE_ARRAY(st->ctx, deviations, lysp_deviation_free);
+ deviations = NULL;
+
+ /* max subelems */
+ data = ELEMENT_WRAPPER_START
+ "<deviation target-node=\"target\">"
+ "<reference><text>ref</text></reference>"
+ "<description><text>desc</text></description>"
+ "<deviate value=\"add\"/>"
+ EXT_SUBELEM
+ "</deviation>"
+ ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviations, NULL, NULL, true), LY_SUCCESS);
+ assert_string_equal(deviations->nodeid, "target");
+ assert_int_equal(deviations->deviates->mod, LYS_DEV_ADD);
+ assert_string_equal(deviations->ref, "ref");
+ assert_string_equal(deviations->dsc, "desc");
+ assert_string_equal(deviations->exts[0].name, "myext:c-define");
+ assert_int_equal(deviations->exts[0].insubstmt_index, 0);
+ assert_int_equal(deviations->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ FREE_ARRAY(st->ctx, deviations, lysp_deviation_free);
+ deviations = NULL;
+
+ /* invalid */
+ data = ELEMENT_WRAPPER_START "<deviation target-node=\"target\"/>" ELEMENT_WRAPPER_END;
+ assert_int_equal(test_element_helper(st, &data, &deviations, NULL, NULL, false), LY_EVALID);
+ FREE_ARRAY(st->ctx, deviations, lysp_deviation_free);
+ deviations = NULL;
+ logbuf_assert("Missing mandatory sub-element \"deviate\" of \"deviation\" element. Line number 1.");
+ /* TODO */
+ st->finished_correctly = true;
+}
+
+static void
+test_module_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data, *name, *prefix;
+ size_t name_len, prefix_len;
+ struct yin_arg_record *attrs = NULL;
+ struct lys_module *lys_mod = NULL;
+ struct lysp_module *lysp_mod = NULL;
+
+ /* max subelems */
+ st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+ lys_mod = calloc(1, sizeof *lys_mod);
+ lysp_mod = calloc(1, sizeof *lysp_mod);
+ lys_mod->ctx = st->ctx;
+ lysp_mod->mod = lys_mod;
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">\n"
+ "<yang-version value=\"1.1\"/>\n"
+ "<namespace uri=\"ns\"/>\n"
+ "<prefix value=\"pref\"/>\n"
+ "<include module=\"b-mod\"/>\n"
+ "<import module=\"a-mod\"><prefix value=\"imp-pref\"/></import>\n"
+ "<organization><text>org</text></organization>\n"
+ "<contact><text>contact</text></contact>\n"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>\n"
+ "<revision date=\"2019-02-02\"/>\n"
+ "<anydata name=\"anyd\"/>\n"
+ "<anyxml name=\"anyx\"/>\n"
+ "<choice name=\"choice\"/>\n"
+ "<container name=\"cont\"/>\n"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>\n"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>\n"
+ "<list name=\"sub-list\"/>\n"
+ "<uses name=\"uses-name\"/>\n"
+ "<augment target-node=\"target\"/>\n"
+ "<deviation target-node=\"target\">""<deviate value=\"not-supported\"/>""</deviation>\n"
+ "<extension name=\"ext\"/>\n"
+ "<feature name=\"feature\"/>\n"
+ "<grouping name=\"grp\"/>\n"
+ "<identity name=\"ident-name\"/>\n"
+ "<notification name=\"notf\"/>\n"
+ "<rpc name=\"rpc-name\"/>\n"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>\n"
+ EXT_SUBELEM"\n"
+ "</module>\n";
+ assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+ assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+ assert_int_equal(yin_parse_mod(st->yin_ctx, attrs, &data, lysp_mod), LY_SUCCESS);
+ assert_string_equal(lysp_mod->mod->name, "mod");
+ assert_string_equal(lysp_mod->revs, "2019-02-02");
+ assert_string_equal(lysp_mod->mod->ns, "ns");
+ assert_string_equal(lysp_mod->mod->prefix, "pref");
+ assert_null(lysp_mod->mod->filepath);
+ assert_string_equal(lysp_mod->mod->org, "org");
+ assert_string_equal(lysp_mod->mod->contact, "contact");
+ assert_string_equal(lysp_mod->mod->dsc, "desc");
+ assert_string_equal(lysp_mod->mod->ref, "ref");
+ assert_int_equal(lysp_mod->mod->version, LYS_VERSION_1_1);
+ assert_string_equal(lysp_mod->imports->name, "a-mod");
+ assert_string_equal(lysp_mod->includes->name, "b-mod");
+ assert_string_equal(lysp_mod->extensions->name, "ext");
+ assert_string_equal(lysp_mod->features->name, "feature");
+ assert_string_equal(lysp_mod->identities->name, "ident-name");
+ assert_string_equal(lysp_mod->typedefs->name, "tpdf");
+ assert_string_equal(lysp_mod->groupings->name, "grp");
+ assert_string_equal(lysp_mod->data->name, "anyd");
+ assert_int_equal(lysp_mod->data->nodetype, LYS_ANYDATA);
+ assert_string_equal(lysp_mod->data->next->name, "anyx");
+ assert_int_equal(lysp_mod->data->next->nodetype, LYS_ANYXML);
+ assert_string_equal(lysp_mod->data->next->next->name, "choice");
+ assert_int_equal(lysp_mod->data->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(lysp_mod->data->next->next->next->name, "cont");
+ assert_int_equal(lysp_mod->data->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(lysp_mod->data->next->next->next->next->name, "leaf");
+ assert_int_equal(lysp_mod->data->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(lysp_mod->data->next->next->next->next->next->name, "llist");
+ assert_int_equal(lysp_mod->data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(lysp_mod->data->next->next->next->next->next->next->name, "sub-list");
+ assert_int_equal(lysp_mod->data->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(lysp_mod->data->next->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(lysp_mod->data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(lysp_mod->data->next->next->next->next->next->next->next->next);
+ assert_string_equal(lysp_mod->augments->nodeid, "target");
+ assert_string_equal(lysp_mod->rpcs->name, "rpc-name");
+ assert_string_equal(lysp_mod->notifs->name, "notf");
+ assert_string_equal(lysp_mod->deviations->nodeid, "target");
+ assert_string_equal(lysp_mod->exts[0].name, "myext:c-define");
+ assert_int_equal(lysp_mod->exts[0].insubstmt_index, 0);
+ assert_int_equal(lysp_mod->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+ lysp_module_free(lysp_mod);
+ lys_module_free(lys_mod, NULL);
+ FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+ attrs = NULL;
+
+ /* min subelems */
+ st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+ lys_mod = calloc(1, sizeof *lys_mod);
+ lysp_mod = calloc(1, sizeof *lysp_mod);
+ lys_mod->ctx = st->ctx;
+ lysp_mod->mod = lys_mod;
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">"
+ "<namespace uri=\"ns\"/>"
+ "<prefix value=\"pref\"/>"
+ "<yang-version value=\"1.1\"/>"
+ "</module>";
+ assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+ assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+ assert_int_equal(yin_parse_mod(st->yin_ctx, attrs, &data, lysp_mod), LY_SUCCESS);
+ assert_string_equal(lysp_mod->mod->name, "mod");
+ lysp_module_free(lysp_mod);
+ lys_module_free(lys_mod, NULL);
+ FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+ attrs = NULL;
+
+ /* incorrect subelem order */
+ st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+ lys_mod = calloc(1, sizeof *lys_mod);
+ lysp_mod = calloc(1, sizeof *lysp_mod);
+ lys_mod->ctx = st->ctx;
+ lysp_mod->mod = lys_mod;
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">"
+ "<feature name=\"feature\"/>\n"
+ "<namespace uri=\"ns\"/>"
+ "<prefix value=\"pref\"/>"
+ "<yang-version value=\"1.1\"/>"
+ "</module>";
+ assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+ assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+ assert_int_equal(yin_parse_mod(st->yin_ctx, attrs, &data, lysp_mod), LY_EVALID);
+ logbuf_assert("Invalid order of module\'s sub-elements \"namespace\" can\'t appear after \"feature\". Line number 30.");
+ lysp_module_free(lysp_mod);
+ lys_module_free(lys_mod, NULL);
+ FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+ attrs = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_submodule_elem(void **state)
+{
+ struct state *st = *state;
+ const char *data, *name, *prefix;
+ size_t name_len, prefix_len;
+ struct yin_arg_record *attrs = NULL;
+ struct lysp_submodule *lysp_submod = NULL;
+
+ /* max subelements */
+ st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+ lysp_submod = calloc(1, sizeof *lysp_submod);
+ data = "<submodule xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"mod\">\n"
+ "<yang-version value=\"1.1\"/>\n"
+ "<belongs-to module=\"mod-name\"><prefix value=\"pref\"/></belongs-to>"
+ "<include module=\"b-mod\"/>\n"
+ "<import module=\"a-mod\"><prefix value=\"imp-pref\"/></import>\n"
+ "<organization><text>org</text></organization>\n"
+ "<contact><text>contact</text></contact>\n"
+ "<description><text>desc</text></description>"
+ "<reference><text>ref</text></reference>\n"
+ "<revision date=\"2019-02-02\"/>\n"
+ "<anydata name=\"anyd\"/>\n"
+ "<anyxml name=\"anyx\"/>\n"
+ "<choice name=\"choice\"/>\n"
+ "<container name=\"cont\"/>\n"
+ "<leaf name=\"leaf\"> <type name=\"type\"/> </leaf>\n"
+ "<leaf-list name=\"llist\"> <type name=\"type\"/> </leaf-list>\n"
+ "<list name=\"sub-list\"/>\n"
+ "<uses name=\"uses-name\"/>\n"
+ "<augment target-node=\"target\"/>\n"
+ "<deviation target-node=\"target\">""<deviate value=\"not-supported\"/>""</deviation>\n"
+ "<extension name=\"ext\"/>\n"
+ "<feature name=\"feature\"/>\n"
+ "<grouping name=\"grp\"/>\n"
+ "<identity name=\"ident-name\"/>\n"
+ "<notification name=\"notf\"/>\n"
+ "<rpc name=\"rpc-name\"/>\n"
+ "<typedef name=\"tpdf\"> <type name=\"type\"/> </typedef>\n"
+ EXT_SUBELEM"\n"
+ "</submodule>\n";
+ assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+ assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+ assert_int_equal(yin_parse_submod(st->yin_ctx, attrs, &data, lysp_submod), LY_SUCCESS);
+
+ assert_string_equal(lysp_submod->name, "mod");
+ assert_string_equal(lysp_submod->revs, "2019-02-02");
+ assert_string_equal(lysp_submod->prefix, "pref");
+ assert_null(lysp_submod->filepath);
+ assert_string_equal(lysp_submod->org, "org");
+ assert_string_equal(lysp_submod->contact, "contact");
+ assert_string_equal(lysp_submod->dsc, "desc");
+ assert_string_equal(lysp_submod->ref, "ref");
+ assert_int_equal(lysp_submod->version, LYS_VERSION_1_1);
+ assert_string_equal(lysp_submod->imports->name, "a-mod");
+ assert_string_equal(lysp_submod->includes->name, "b-mod");
+ assert_string_equal(lysp_submod->extensions->name, "ext");
+ assert_string_equal(lysp_submod->features->name, "feature");
+ assert_string_equal(lysp_submod->identities->name, "ident-name");
+ assert_string_equal(lysp_submod->typedefs->name, "tpdf");
+ assert_string_equal(lysp_submod->groupings->name, "grp");
+ assert_string_equal(lysp_submod->data->name, "anyd");
+ assert_int_equal(lysp_submod->data->nodetype, LYS_ANYDATA);
+ assert_string_equal(lysp_submod->data->next->name, "anyx");
+ assert_int_equal(lysp_submod->data->next->nodetype, LYS_ANYXML);
+ assert_string_equal(lysp_submod->data->next->next->name, "choice");
+ assert_int_equal(lysp_submod->data->next->next->nodetype, LYS_CHOICE);
+ assert_string_equal(lysp_submod->data->next->next->next->name, "cont");
+ assert_int_equal(lysp_submod->data->next->next->next->nodetype, LYS_CONTAINER);
+ assert_string_equal(lysp_submod->data->next->next->next->next->name, "leaf");
+ assert_int_equal(lysp_submod->data->next->next->next->next->nodetype, LYS_LEAF);
+ assert_string_equal(lysp_submod->data->next->next->next->next->next->name, "llist");
+ assert_int_equal(lysp_submod->data->next->next->next->next->next->nodetype, LYS_LEAFLIST);
+ assert_string_equal(lysp_submod->data->next->next->next->next->next->next->name, "sub-list");
+ assert_int_equal(lysp_submod->data->next->next->next->next->next->next->nodetype, LYS_LIST);
+ assert_string_equal(lysp_submod->data->next->next->next->next->next->next->next->name, "uses-name");
+ assert_int_equal(lysp_submod->data->next->next->next->next->next->next->next->nodetype, LYS_USES);
+ assert_null(lysp_submod->data->next->next->next->next->next->next->next->next);
+ assert_string_equal(lysp_submod->augments->nodeid, "target");
+ assert_string_equal(lysp_submod->rpcs->name, "rpc-name");
+ assert_string_equal(lysp_submod->notifs->name, "notf");
+ assert_string_equal(lysp_submod->deviations->nodeid, "target");
+ assert_string_equal(lysp_submod->exts[0].name, "myext:c-define");
+ assert_int_equal(lysp_submod->exts[0].insubstmt_index, 0);
+ assert_int_equal(lysp_submod->exts[0].insubstmt, LYEXT_SUBSTMT_SELF);
+
+ lysp_submodule_free(st->ctx, lysp_submod);
+ FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+ attrs = NULL;
+
+ /* min subelemnts */
+ st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+ lysp_submod = calloc(1, sizeof *lysp_submod);
+ data = "<submodule xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"submod\">"
+ "<yang-version value=\"1.0\"/>"
+ "<belongs-to module=\"mod-name\"><prefix value=\"pref\"/></belongs-to>"
+ "</submodule>";
+ assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+ assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+ assert_int_equal(yin_parse_submod(st->yin_ctx, attrs, &data, lysp_submod), LY_SUCCESS);
+ assert_string_equal(lysp_submod->prefix, "pref");
+ assert_string_equal(lysp_submod->belongsto, "mod-name");
+ assert_int_equal(lysp_submod->version, LYS_VERSION_1_0);
+ lysp_submodule_free(st->ctx, lysp_submod);
+ FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+ attrs = NULL;
+
+ /* incorrect subelem order */
+ st->yin_ctx->xml_ctx.status = LYXML_ELEMENT;
+ lysp_submod = calloc(1, sizeof *lysp_submod);
+ data = "<submodule xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" name=\"submod\">"
+ "<yang-version value=\"1.0\"/>"
+ "<reference><text>ref</text></reference>\n"
+ "<belongs-to module=\"mod-name\"><prefix value=\"pref\"/></belongs-to>"
+ "</submodule>";
+ assert_int_equal(lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len), LY_SUCCESS);
+ assert_int_equal(yin_load_attributes(st->yin_ctx, &data, &attrs), LY_SUCCESS);
+ assert_int_equal(yin_parse_submod(st->yin_ctx, attrs, &data, lysp_submod), LY_EVALID);
+ logbuf_assert("Invalid order of submodule's sub-elements \"belongs-to\" can't appear after \"reference\". Line number 28.");
+ lysp_submodule_free(st->ctx, lysp_submod);
+ FREE_ARRAY(st->yin_ctx, attrs, free_arg_rec);
+ attrs = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_module(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct lys_module *mod;
+ struct yin_parser_ctx *yin_ctx = NULL;
+
+ mod = calloc(1, sizeof *mod);
+ mod->ctx = st->ctx;
+ data = "<module name=\"example-foo\""
+ "xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\""
+ "xmlns:foo=\"urn:example:foo\""
+ "xmlns:myext=\"urn:example:extensions\">\n"
+
+ "<yang-version value=\"1.0\"/>\n"
+
+ "<namespace uri=\"urn:example:foo\"/>\n"
+ "<prefix value=\"foo\"/>\n"
+
+ "<import module=\"example-extensions\">\n"
+ "<prefix value=\"myext\"/>\n"
+ "</import>\n"
+
+ "<list name=\"interface\">\n"
+ "<key value=\"name\"/>\n"
+ "<leaf name=\"name\">\n"
+ "<type name=\"string\"/>\n"
+ "</leaf>\n"
+ "<leaf name=\"mtu\">\n"
+ "<type name=\"uint32\"/>\n"
+ "<description>\n"
+ "<text>The MTU of the interface.</text>\n"
+ "</description>\n"
+ "<myext:c-define name=\"MY_MTU\"/>\n"
+ "</leaf>\n"
+ "</list>\n"
+ "</module>\n";
+ assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_SUCCESS);
+ lys_module_free(mod, NULL);
+ yin_parser_ctx_free(yin_ctx);
+ mod = NULL;
+ yin_ctx = NULL;
+
+ mod = calloc(1, sizeof *mod);
+ mod->ctx = st->ctx;
+ data = "<module name=\"example-foo\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\n"
+ "<yang-version value=\"1.0\"/>\n"
+ "<namespace uri=\"urn:example:foo\"/>\n"
+ "<prefix value=\"foo\"/>\n"
+ "</module>\n";
+ assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_SUCCESS);
+ lys_module_free(mod, NULL);
+ yin_parser_ctx_free(yin_ctx);
+ mod = NULL;
+ yin_ctx = NULL;
+
+
+ mod = calloc(1, sizeof *mod);
+ mod->ctx = st->ctx;
+ data = "<submodule name=\"example-foo\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "</submodule>\n";
+ assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_EINVAL);
+ logbuf_assert("Input data contains submodule which cannot be parsed directly without its main module.");
+ lys_module_free(mod, NULL);
+ yin_parser_ctx_free(yin_ctx);
+
+ mod = calloc(1, sizeof *mod);
+ mod->ctx = st->ctx;
+ data = "<module name=\"example-foo\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\n"
+ "<yang-version value=\"1.0\"/>\n"
+ "<namespace uri=\"urn:example:foo\"/>\n"
+ "<prefix value=\"foo\"/>\n"
+ "</module>"
+ "<module>";
+ assert_int_equal(yin_parse_module(&yin_ctx, data, mod), LY_EVALID);
+ logbuf_assert("Trailing garbage \"<module>\" after module, expected end-of-input. Line number 5.");
+ lys_module_free(mod, NULL);
+ yin_parser_ctx_free(yin_ctx);
+ mod = NULL;
+ yin_ctx = NULL;
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_submodule(void **state)
+{
+ struct state *st = *state;
+ const char *data;
+ struct yin_parser_ctx *yin_ctx = NULL;
+ struct lysp_submodule *submod = NULL;
+ struct lys_parser_ctx main_ctx = {};
+
+ data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<submodule name=\"asub\""
+ "xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\""
+ "xmlns:a=\"urn:a\">"
+ "<yang-version value=\"1.0\"/>\n"
+ "<belongs-to module=\"a\">"
+ "<prefix value=\"a_pref\"/>"
+ "</belongs-to>"
+ "<include module=\"atop\"/>"
+ "<feature name=\"fox\"/>"
+ "<notification name=\"bar-notif\">"
+ "<if-feature name=\"bar\"/>"
+ "</notification>"
+ "<notification name=\"fox-notif\">"
+ "<if-feature name=\"fox\"/>"
+ "</notification>"
+ "<augment target-node=\"/a_pref:top\">"
+ "<if-feature name=\"bar\"/>"
+ "<container name=\"bar-sub\"/>"
+ "</augment>"
+ "<augment target-node=\"/top\">"
+ "<container name=\"bar-sub2\"/>"
+ "</augment>"
+ "</submodule>";
+ assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_SUCCESS);
+ lysp_submodule_free(st->ctx, submod);
+ yin_parser_ctx_free(yin_ctx);
+ yin_ctx = NULL;
+ submod = NULL;
+
+ data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<submodule name=\"asub\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<yang-version value=\"1.0\"/>\n"
+ "<belongs-to module=\"a\">"
+ "<prefix value=\"a_pref\"/>"
+ "</belongs-to>"
+ "</submodule>";
+ assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_SUCCESS);
+ lysp_submodule_free(st->ctx, submod);
+ yin_parser_ctx_free(yin_ctx);
+ yin_ctx = NULL;
+ submod = NULL;
+
+ data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<module name=\"inval\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "</module>";
+ assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_EINVAL);
+ logbuf_assert("Input data contains module in situation when a submodule is expected.");
+ lysp_submodule_free(st->ctx, submod);
+ yin_parser_ctx_free(yin_ctx);
+ yin_ctx = NULL;
+ submod = NULL;
+
+ data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<submodule name=\"asub\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<yang-version value=\"1.0\"/>\n"
+ "<belongs-to module=\"a\">"
+ "<prefix value=\"a_pref\"/>"
+ "</belongs-to>"
+ "</submodule>"
+ "<submodule name=\"asub\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<yang-version value=\"1.0\"/>\n"
+ "<belongs-to module=\"a\">"
+ "<prefix value=\"a_pref\"/>"
+ "</belongs-to>"
+ "</submodule>";
+ assert_int_equal(yin_parse_submodule(&yin_ctx, st->ctx, &main_ctx, data, &submod), LY_EVALID);
+ logbuf_assert("Trailing garbage \"<submodule name...\" after submodule, expected end-of-input. Line number 2.");
+ lysp_submodule_free(st->ctx, submod);
+ yin_parser_ctx_free(yin_ctx);
+ yin_ctx = NULL;
+ submod = NULL;
+
+ st->finished_correctly = true;
+}
+
+int
+main(void)
+{
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_yin_match_keyword, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_element_generic, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_extension_instance, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_content, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_validate_value, setup_f, teardown_f),
+
+ cmocka_unit_test(test_yin_match_argument_name),
+ cmocka_unit_test_setup_teardown(test_enum_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_bit_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_meta_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_import_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_status_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_ext_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_yin_element_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_yangversion_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_mandatory_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_argument_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_base_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_belongsto_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_config_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_default_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_err_app_tag_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_err_msg_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_fracdigits_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_iffeature_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_length_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_modifier_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_namespace_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_path_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_pattern_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_value_position_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_prefix_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_range_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_reqinstance_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_revision_date_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_unique_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_units_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_when_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_yin_text_value_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_type_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_max_elems_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_min_elems_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_ordby_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_any_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_leaf_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_leaf_list_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_presence_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_key_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_typedef_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_refine_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_uses_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_revision_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_include_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_feature_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_identity_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_list_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_notification_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_grouping_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_container_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_case_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_choice_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_inout_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_action_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_augment_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_deviate_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_deviation_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_module_elem, setup_element_test, teardown_element_test),
+ cmocka_unit_test_setup_teardown(test_submodule_elem, setup_element_test, teardown_element_test),
+
+ cmocka_unit_test_setup_teardown(test_yin_parse_module, setup_logger, teardown_logger),
+ cmocka_unit_test_setup_teardown(test_yin_parse_submodule, setup_logger, teardown_logger),
+ };
+
+ return cmocka_run_group_tests(tests, setup_ly_ctx, destroy_ly_ctx);
+}
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index 1be0815..6ebe998 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -26,6 +26,7 @@
#include "../../src/plugins_types.h"
void lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat);
+void lys_parser_ctx_free(struct lys_parser_ctx *ctx);
LY_ERR lys_path_token(const char **path, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len,
int *parent_times, int *has_predicate);
@@ -95,20 +96,21 @@
}
static void
-reset_mod(struct ly_ctx *ctx, struct lys_module *module)
+reset_mod(struct lys_module *module)
{
+ struct ly_ctx *ctx = module->ctx;
lysc_module_free(module->compiled, NULL);
lysp_module_free(module->parsed);
- FREE_STRING(module->ctx, module->name);
- FREE_STRING(module->ctx, module->ns);
- FREE_STRING(module->ctx, module->prefix);
- FREE_STRING(module->ctx, module->filepath);
- FREE_STRING(module->ctx, module->org);
- FREE_STRING(module->ctx, module->contact);
- FREE_STRING(module->ctx, module->dsc);
- FREE_STRING(module->ctx, module->ref);
- FREE_ARRAY(module->ctx, module->off_features, lysc_feature_free);
+ FREE_STRING(ctx, module->name);
+ FREE_STRING(ctx, module->ns);
+ FREE_STRING(ctx, module->prefix);
+ FREE_STRING(ctx, module->filepath);
+ FREE_STRING(ctx, module->org);
+ FREE_STRING(ctx, module->contact);
+ FREE_STRING(ctx, module->dsc);
+ FREE_STRING(ctx, module->ref);
+ FREE_ARRAY(ctx, module->off_features, lysc_feature_free);
memset(module, 0, sizeof *module);
module->ctx = ctx;
@@ -121,21 +123,22 @@
*state = test_module;
const char *str;
- struct lys_parser_ctx ctx = {0};
+ struct lys_parser_ctx *ctx = NULL;
struct lys_module mod = {0};
struct lysc_feature *f;
struct lysc_iffeature *iff;
str = "module test {namespace urn:test; prefix t;"
"feature f1;feature f2 {if-feature f1;}}";
- assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
- reset_mod(ctx.ctx, &mod);
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &mod.ctx));
+ reset_mod(&mod);
assert_int_equal(LY_EINVAL, lys_compile(NULL, 0));
logbuf_assert("Invalid argument mod (lys_compile()).");
assert_int_equal(LY_EINVAL, lys_compile(&mod, 0));
logbuf_assert("Invalid argument mod->parsed (lys_compile()).");
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, str, &mod));
+ lys_parser_ctx_free(ctx);
mod.implemented = 0;
assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
assert_null(mod.compiled);
@@ -168,20 +171,22 @@
/* submodules cannot be compiled directly */
str = "submodule test {belongs-to xxx {prefix x;}}";
assert_int_equal(LY_EINVAL, yang_parse_module(&ctx, str, &mod));
+ lys_parser_ctx_free(ctx);
logbuf_assert("Input data contains submodule which cannot be parsed directly without its main module.");
assert_null(mod.parsed);
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
/* data definition name collision in top level */
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module aa {namespace urn:aa;prefix aa;"
"leaf a {type string;} container a{presence x;}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Duplicate identifier \"a\" of data definition/RPC/action/Notification statement. /aa:a");
assert_null(mod.compiled);
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
*state = NULL;
- ly_ctx_destroy(ctx.ctx, NULL);
+ ly_ctx_destroy(mod.ctx, NULL);
}
static void
@@ -189,7 +194,7 @@
{
*state = test_feature;
- struct lys_parser_ctx ctx = {0};
+ struct lys_parser_ctx *ctx = NULL;
struct lys_module mod = {0}, *modp;
const char *str;
struct lysc_feature *f, *f1;
@@ -203,10 +208,11 @@
"feature f8 {if-feature \"f1 or f2 or f3 or orfeature or andfeature\";}\n"
"feature f9 {if-feature \"not not f1\";}}";
- assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &ctx.ctx));
- reset_mod(ctx.ctx, &mod);
+ assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, 0, &mod.ctx));
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, str, &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_SUCCESS, lys_compile(&mod, 0));
assert_non_null(mod.compiled);
assert_non_null(mod.compiled->features);
@@ -283,7 +289,7 @@
assert_int_equal(1, lys_feature_value(&mod, "f1"));
assert_int_equal(0, lys_feature_value(&mod, "f2"));
- assert_non_null(modp = lys_parse_mem(ctx.ctx, "module b {namespace urn:b;prefix b;"
+ assert_non_null(modp = lys_parse_mem(mod.ctx, "module b {namespace urn:b;prefix b;"
"feature f1 {if-feature f2;}feature f2;}", LYS_IN_YANG));
assert_non_null(modp->compiled);
assert_non_null(modp->compiled->features);
@@ -303,83 +309,91 @@
assert_int_equal(LY_EINVAL, lys_feature_enable(&mod, "xxx"));
logbuf_assert("Feature \"xxx\" not found in module \"a\".");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
/* some invalid expressions */
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature f1;}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Invalid value \"f1\" of if-feature - unable to find feature \"f1\". /b:{feature='f'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f and';}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Invalid value \"f and\" of if-feature - unexpected end of expression. /b:{feature='f2'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f{if-feature 'or';}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Invalid value \"or\" of if-feature - unexpected end of expression. /b:{feature='f'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature '(f1';}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Invalid value \"(f1\" of if-feature - non-matching opening and closing parentheses. /b:{feature='f2'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature 'f1)';}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Invalid value \"f1)\" of if-feature - non-matching opening and closing parentheses. /b:{feature='f2'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{yang-version 1.1;namespace urn:b; prefix b; feature f1; feature f2{if-feature ---;}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Invalid value \"---\" of if-feature - unable to find feature \"---\". /b:{feature='f2'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f2{if-feature 'not f1';}}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Invalid value \"not f1\" of if-feature - YANG 1.1 expression in YANG 1.0 module. /b:{feature='f2'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
assert_int_equal(LY_SUCCESS, yang_parse_module(&ctx, "module b{namespace urn:b; prefix b; feature f1; feature f1;}", &mod));
+ lys_parser_ctx_free(ctx);
assert_int_equal(LY_EVALID, lys_compile(&mod, 0));
logbuf_assert("Duplicate identifier \"f1\" of feature statement. /b:{feature='f1'}");
- reset_mod(ctx.ctx, &mod);
+ reset_mod(&mod);
- ly_ctx_set_module_imp_clb(ctx.ctx, test_imp_clb, "submodule sz {belongs-to z {prefix z;} feature f1;}");
- assert_null(lys_parse_mem(ctx.ctx, "module z{namespace urn:z; prefix z; include sz;feature f1;}", LYS_IN_YANG));
+ ly_ctx_set_module_imp_clb(mod.ctx, test_imp_clb, "submodule sz {belongs-to z {prefix z;} feature f1;}");
+ assert_null(lys_parse_mem(mod.ctx, "module z{namespace urn:z; prefix z; include sz;feature f1;}", LYS_IN_YANG));
logbuf_assert("Duplicate identifier \"f1\" of feature statement. /z:{feature='f1'}");
- assert_null(lys_parse_mem(ctx.ctx, "module aa{namespace urn:aa; prefix aa; feature f1 {if-feature f2;} feature f2 {if-feature f1;}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(mod.ctx, "module aa{namespace urn:aa; prefix aa; feature f1 {if-feature f2;} feature f2 {if-feature f1;}}", LYS_IN_YANG));
logbuf_assert("Feature \"f1\" is indirectly referenced from itself. /aa:{feature='f2'}");
- assert_null(lys_parse_mem(ctx.ctx, "module ab{namespace urn:ab; prefix ab; feature f1 {if-feature f1;}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(mod.ctx, "module ab{namespace urn:ab; prefix ab; feature f1 {if-feature f1;}}", LYS_IN_YANG));
logbuf_assert("Feature \"f1\" is referenced from itself. /ab:{feature='f1'}");
- assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f {if-feature ();}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f {if-feature ();}}", LYS_IN_YANG));
logbuf_assert("Invalid value \"()\" of if-feature - number of features in expression does not match the required number "
"of operands for the operations. /bb:{feature='f'}");
- assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1(';}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1(';}}", LYS_IN_YANG));
logbuf_assert("Invalid value \"f1(\" of if-feature - non-matching opening and closing parentheses. /bb:{feature='f'}");
- assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'and f1';}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'and f1';}}", LYS_IN_YANG));
logbuf_assert("Invalid value \"and f1\" of if-feature - missing feature/expression before \"and\" operation. /bb:{feature='f'}");
- assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not ';}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not ';}}", LYS_IN_YANG));
logbuf_assert("Invalid value \"f1 not \" of if-feature - unexpected end of expression. /bb:{feature='f'}");
- assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not not ';}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f {if-feature 'f1 not not ';}}", LYS_IN_YANG));
logbuf_assert("Invalid value \"f1 not not \" of if-feature - unexpected end of expression. /bb:{feature='f'}");
- assert_null(lys_parse_mem(ctx.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f2; "
+ assert_null(lys_parse_mem(mod.ctx, "module bb{yang-version 1.1; namespace urn:bb; prefix bb; feature f1; feature f2; "
"feature f {if-feature 'or f1 f2';}}", LYS_IN_YANG));
logbuf_assert("Invalid value \"or f1 f2\" of if-feature - missing feature/expression before \"or\" operation. /bb:{feature='f'}");
/* import reference */
- assert_non_null(modp = lys_parse_mem(ctx.ctx, str, LYS_IN_YANG));
+ assert_non_null(modp = lys_parse_mem(mod.ctx, str, LYS_IN_YANG));
assert_int_equal(LY_SUCCESS, lys_feature_enable(modp, "f1"));
- assert_non_null(modp = lys_parse_mem(ctx.ctx, "module c{namespace urn:c; prefix c; import a {prefix a;} feature f1; feature f2{if-feature 'a:f1';}}", LYS_IN_YANG));
+ assert_non_null(modp = lys_parse_mem(mod.ctx, "module c{namespace urn:c; prefix c; import a {prefix a;} feature f1; feature f2{if-feature 'a:f1';}}", LYS_IN_YANG));
assert_int_equal(LY_SUCCESS, lys_feature_enable(modp, "f2"));
assert_int_equal(0, lys_feature_value(modp, "f1"));
assert_int_equal(1, lys_feature_value(modp, "f2"));
*state = NULL;
- ly_ctx_destroy(ctx.ctx, NULL);
+ ly_ctx_destroy(mod.ctx, NULL);
}
static void
@@ -1515,7 +1529,7 @@
assert_int_equal(8, ((struct lysc_type_bits*)type)->bits[4].position);
assert_non_null(mod = lys_parse_mem(ctx, "module b {yang-version 1.1;namespace urn:b;prefix b;feature f; typedef mytype {type bits {"
- "bit automin; bit one;bit two; bit seven {value 7;}bit eight;}} leaf l { type mytype {bit eight;bit seven;bit automin;}}}",
+ "bit automin; bit one;bit two; bit seven {position 7;}bit eight;}} leaf l { type mytype {bit eight;bit seven;bit automin;}}}",
LYS_IN_YANG));
type = ((struct lysc_node_leaf*)mod->compiled->data)->type;
assert_non_null(type);
@@ -1538,8 +1552,8 @@
"bit one {position -1;}}}}", LYS_IN_YANG));
logbuf_assert("Invalid value \"-1\" of \"position\". Line number 1.");
assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type bits {"
- "bit one {value 4294967296;}}}}", LYS_IN_YANG));
- logbuf_assert("Invalid value \"4294967296\" of \"value\". Line number 1.");
+ "bit one {position 4294967296;}}}}", LYS_IN_YANG));
+ logbuf_assert("Invalid value \"4294967296\" of \"position\". Line number 1.");
assert_null(lys_parse_mem(ctx, "module aa {namespace urn:aa;prefix aa; leaf l {type bits {"
"bit one; bit one;}}}", LYS_IN_YANG));
logbuf_assert("Duplicate identifier \"one\" of bit statement. Line number 1.");
@@ -1563,7 +1577,7 @@
assert_null(lys_parse_mem(ctx, "module ee {namespace urn:ee;prefix ee;leaf l {type bits {bit x {position 4294967295;}bit y;}}}", LYS_IN_YANG));
logbuf_assert("Invalid bits - it is not possible to auto-assign bit position for \"y\" since the highest value is already 4294967295. /ee:l");
- assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type bits {bit x {value 1;}bit y {value 1;}}}}", LYS_IN_YANG));
+ assert_null(lys_parse_mem(ctx, "module ff {namespace urn:ff;prefix ff;leaf l {type bits {bit x {position 1;}bit y {position 1;}}}}", LYS_IN_YANG));
logbuf_assert("Invalid bits - position 1 collide in items \"y\" and \"x\". /ff:l");
assert_null(lys_parse_mem(ctx, "module gg {namespace urn:gg;prefix gg;typedef mytype {type bits;}"
diff --git a/tests/src/test_xml.c b/tests/src/test_xml.c
index 1622b92..ffa1e2d 100644
--- a/tests/src/test_xml.c
+++ b/tests/src/test_xml.c
@@ -224,6 +224,15 @@
logbuf_assert("Mixed XML content is not allowed (text <b>). Line number 1.");
lyxml_context_clear(&ctx);
+ /* tag missmatch */
+ str = "<a>text</b>";
+ assert_int_equal(LY_SUCCESS, lyxml_get_element(&ctx, &str, &prefix, &prefix_len, &name, &name_len));
+ assert_string_equal("text</b>", str);
+ assert_int_equal(LYXML_ELEM_CONTENT, ctx.status);
+ assert_int_equal(LY_EVALID, lyxml_get_string(&ctx, &str, &buf, &buf_len, &out, &len, &dynamic));
+ logbuf_assert("Opening and closing elements tag missmatch (\"b\"). Line number 1.");
+ lyxml_context_clear(&ctx);
+
}
static void