Merge remote-tracking branch 'upstream/libyang2' into libyang2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c592d44..346527b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -216,6 +216,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
diff --git a/src/common.c b/src/common.c
index 3c36baa..8e1c53c 100644
--- a/src/common.c
+++ b/src/common.c
@@ -100,6 +100,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 1c18a13..3ca8856 100644
--- a/src/common.h
+++ b/src/common.h
@@ -191,6 +191,11 @@
#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_INVAL_YIN LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\"."
+#define LY_VCODE_DUPELEM LYVE_SYNTAX_YIN, "Duplicate element \"%s\"."
+#define LY_VCODE_INCHILDSTMT_YIN LYVE_SYNTAX_YIN, "Invalid element \"%.*s\" as a child of \"%.*s\"."
+#define LY_VCODE_MISSATTR LYVE_SYNTAX_YIN, "Missing mandatory child element \"%s\" of %s element ."
+#define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected child element \"%.*s\" of %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."
@@ -305,7 +310,10 @@
YANG_SEMICOLON,
YANG_LEFT_BRACE,
YANG_RIGHT_BRACE,
- YANG_CUSTOM
+ YANG_CUSTOM,
+
+ YIN_TEXT,
+ YIN_VALUE
};
/* list of the YANG statements strings */
diff --git a/src/log.h b/src/log.h
index 26376c0..8bff336 100644
--- a/src/log.h
+++ b/src/log.h
@@ -166,6 +166,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 dabe200..6452b10 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 <= 0xd77) || 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);
@@ -169,62 +132,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 +144,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 +163,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 +175,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 +280,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 +312,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 +334,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 +356,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 +367,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 +392,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 +405,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 +425,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 +472,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 +485,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 +510,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 +524,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 +544,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 +584,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 +651,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 +676,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 +707,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 +717,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 +861,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 +877,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 +903,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 +915,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 +927,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 +954,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 +972,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 +980,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 +1005,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 +1028,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 +1064,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 +1085,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 +1138,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;
}
@@ -1465,7 +1193,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 +1235,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 +1261,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 +1273,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 +1285,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 +1311,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 +1323,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 +1335,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 +1363,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 +1383,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 +1428,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 +1442,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 +1454,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 +1480,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 +1489,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 +1506,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;
}
}
@@ -1853,7 +1581,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;
}
@@ -1885,7 +1613,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;
@@ -1894,7 +1622,7 @@
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));
+ LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
goto error;
}
@@ -1902,23 +1630,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 +1662,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 +1688,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 +1697,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 +1724,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 +1764,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 +1772,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 +1781,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 +1799,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 +1827,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 +1838,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 +1850,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 +1876,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 +1884,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 +1906,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 +1971,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 +1997,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 +2025,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 +2044,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 +2066,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;
}
}
@@ -2432,7 +2150,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 +2158,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 +2190,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 +2199,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 +2209,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 +2229,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 +2257,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 +2266,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 +2275,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 +2293,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 +2319,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 +2331,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 +2343,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;
}
}
@@ -2716,7 +2434,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 +2442,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 +2481,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 +2521,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 +2577,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,7 +2585,7 @@
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;
}
@@ -2898,7 +2616,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,7 +2665,7 @@
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;
}
}
@@ -3017,7 +2735,7 @@
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;
}
}
@@ -3109,7 +2827,7 @@
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;
}
}
@@ -3202,7 +2920,7 @@
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;
}
}
@@ -3236,7 +2954,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,7 +3017,7 @@
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;
}
}
@@ -3477,7 +3195,7 @@
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;
}
}
@@ -3572,7 +3290,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;
}
}
@@ -3673,14 +3391,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;
@@ -3794,7 +3512,7 @@
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;
}
}
@@ -3924,7 +3642,7 @@
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;
}
}
@@ -3934,7 +3652,7 @@
LY_CHECK_RET(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 +3680,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 +3692,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 +3704,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 +3712,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 +3731,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 +3748,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 +3797,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;
}
}
@@ -4123,7 +3841,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;
}
@@ -4186,7 +3904,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 +3914,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 +3928,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 +3939,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 +3950,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 +3961,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 +3973,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 +3990,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 +4000,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 +4011,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 +4040,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 +4058,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 +4066,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 +4115,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 +4163,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 +4172,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 +4205,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 +4359,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;
}
}
@@ -4653,10 +4371,10 @@
/* 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 +4382,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 +4415,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 +4565,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;
}
}
@@ -4859,7 +4577,7 @@
/* 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 +4585,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;
}
@@ -4892,7 +4610,7 @@
ret = LY_EINVAL;
goto cleanup;
} else if (kw != YANG_SUBMODULE) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
+ LOGVAL_PARSER(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
ly_stmt2str(kw));
ret = LY_EVALID;
goto cleanup;
@@ -4911,7 +4629,7 @@
data++;
}
if (*data) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input.",
+ LOGVAL_PARSER(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after submodule, expected end-of-input.",
15, data, strlen(data) > 15 ? "..." : "");
ret = LY_EVALID;
goto cleanup;
@@ -4946,7 +4664,7 @@
ret = LY_EINVAL;
goto cleanup;
} else if (kw != YANG_MODULE) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
+ LOGVAL_PARSER(context, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
ly_stmt2str(kw));
ret = LY_EVALID;
goto cleanup;
@@ -4966,7 +4684,7 @@
data++;
}
if (*data) {
- LOGVAL_YANG(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input.",
+ LOGVAL_PARSER(context, LYVE_SYNTAX, "Trailing garbage \"%.*s%s\" after module, expected end-of-input.",
15, data, strlen(data) > 15 ? "..." : "");
ret = LY_EVALID;
goto cleanup;
diff --git a/src/parser_yin.c b/src/parser_yin.c
new file mode 100644
index 0000000..31983dd
--- /dev/null
+++ b/src/parser_yin.c
@@ -0,0 +1,1677 @@
+/**
+ * @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 "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)
+
+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 *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 if (strncmp(start, "value", name_len) == 0) {
+ return YIN_VALUE;
+ } 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;
+}
+
+/**
+ * @brief free argument record, content loaded from lyxml_get_string() can be
+ * dynamically allocated in some cases so it must be also freed.
+ */
+static void free_arg_rec(struct yin_parser_ctx *ctx, struct yin_arg_record *record) {
+ (void)ctx; /* unused */
+ if (record->dynamic_content) {
+ free(record->content);
+ }
+}
+
+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;
+ struct sized_string prefix, name;
+
+ /* load all attributes */
+ while (ctx->xml_ctx.status == LYXML_ATTRIBUTE) {
+ ret = lyxml_get_attribute(&ctx->xml_ctx, data, &prefix.value, &prefix.len, &name.value, &name.len);
+ LY_CHECK_GOTO(ret != LY_SUCCESS, 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.value;
+ argument_record->name_len = name.len;
+ argument_record->prefix = prefix.value;
+ 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 != LY_SUCCESS, 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 argument.
+ *
+ * @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,out] data Data to read from.
+ * @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 if 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, LYVE_SYNTAX_YIN, "Duplicit definition of %s attribute in %s element",
+ 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));
+ if (iter->dynamic_content) {
+ *arg_val = lydict_insert_zc(ctx->xml_ctx.ctx, iter->content);
+ LY_CHECK_RET(!(*arg_val), LY_EMEM);
+ /* string is no longer supposed to be freed when the sized array is freed */
+ iter->dynamic_content = 0;
+ } else {
+ *arg_val = lydict_insert(ctx->xml_ctx.ctx, iter->content, iter->content_len);
+ LY_CHECK_RET(!(*arg_val), LY_EMEM);
+ }
+ } else {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YIN, "Unexpected attribute \"%.*s\" of %s element.", 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, LYVE_SYNTAX_YIN, "Missing mandatory subelement %s of %s element.",
+ 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.
+ *
+ * @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, LYVE_SYNTAX_YIN, "Subelement %s of %s element must be defined as first subelement.",
+ 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 instance 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 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] patterns Restrictions to add to.
+ *
+ * @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 enum or 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] enum_kw Identification of actual keyword, can be set to YANG_BIT or YANG_ENUM.
+ * @param[in,out] enums Enums or bits to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_enum_bit(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ enum yang_keyword enum_kw, struct lysp_type *type)
+{
+ assert(enum_kw == YANG_BIT || enum_kw == YANG_ENUM);
+ struct lysp_type_enum *en;
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, type->enums, en, LY_EMEM);
+ LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_NAME, &en->name, Y_IDENTIF_ARG, enum_kw));
+ type->flags |= (enum_kw == YANG_ENUM) ? LYS_SET_ENUM : LYS_SET_BIT;
+ if (enum_kw == 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, ly_stmt2str(enum_kw), 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},
+ {(enum_kw == YANG_ENUM) ? YANG_VALUE : YANG_POSITION, &en->value, YIN_SUBELEM_UNIQUE},
+ {YANG_CUSTOM, NULL, 0}
+ };
+ return yin_parse_content(ctx, subelems, 6, data, enum_kw, 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 instance 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 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, temp_val, "require-instance");
+ 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, temp_val, "modifier");
+ 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]
+ */
+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 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 extensions.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_value_pos_element(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] == '+') || ((temp_val[0] == '0') && (temp_val[0] != '\0')) || ((kw == YANG_VALUE) && !strcmp(temp_val, "-0"))) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL, strlen(temp_val), temp_val, 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, strlen(temp_val), temp_val, 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, strlen(temp_val), temp_val, 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, strlen(temp_val), temp_val, ly_stmt2str(kw));
+ }
+ if (errno == ERANGE) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB, strlen(temp_val), temp_val, 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 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,out] data Data to read from, always moved to currently handled character.
+ * @param[in] 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 instance to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_meta_element(struct yin_parser_ctx *ctx, 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}
+ };
+
+ 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,out] data Data to read from.
+ * @param[out] value Where the content of error-message element should be stored.
+ * @param[in,out] exts Extension instance to add to.
+ *
+ * @return LY_ERR values.
+ */
+static LY_ERR
+yin_parse_err_msg_element(struct yin_parser_ctx *ctx, 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}
+ };
+
+ return yin_parse_content(ctx, subelems, 2, data, YANG_ERROR_MESSAGE, NULL, 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 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);
+}
+
+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;
+ struct sized_string prefix, name;
+ char *out;
+ size_t out_len;
+ int dynamic;
+ struct yin_arg_record *subelem_attrs = NULL;
+ enum yang_keyword kw = YANG_NONE;
+ struct yin_subelement *subelem_info_rec = NULL;
+ uint32_t index = 0;
+ struct lysp_type *type;
+ 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.value, &prefix.len, &name.value, &name.len);
+ LY_CHECK_GOTO(ret, cleanup);
+ if (!name.value) {
+ /* end of current element reached */
+ break;
+ }
+ ret = yin_load_attributes(ctx, data, &subelem_attrs);
+ LY_CHECK_GOTO(ret, cleanup);
+ kw = yin_match_keyword(ctx, name.value, name.len, prefix.value, prefix.len, current_element);
+
+ /* check if this element can be child of current element */
+ subelem_info_rec = get_record(kw, subelem_info_size, subelem_info);
+ if (!subelem_info_rec) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_UNEXP_SUBELEM, name.len, name.value, ly_stmt2str(current_element));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* TODO check relative order */
+
+ /* if element is unique and already defined log error */
+ if ((subelem_info_rec->flags & YIN_SUBELEM_UNIQUE) && (subelem_info_rec->flags & YIN_SUBELEM_PARSED)) {
+ LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YIN, "Redefinition of %s element in %s element.", ly_stmt2str(kw), ly_stmt2str(current_element));
+ return LY_EVALID;
+ }
+ if (subelem_info_rec->flags & YIN_SUBELEM_FIRST) {
+ ret = yin_check_subelem_first_constraint(ctx, subelem_info, subelem_info_size, current_element, subelem_info_rec);
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ subelem_info_rec->flags |= YIN_SUBELEM_PARSED;
+
+ switch (kw) {
+ case YANG_CUSTOM:
+ index = (subelem_info_rec->dest) ? *((uint32_t*)subelem_info_rec->dest) : 0;
+ ret = yin_parse_extension_instance(ctx, subelem_attrs, data, name2fullname(name.value, prefix.len),
+ namelen2fulllen(name.len, prefix.len),
+ kw2lyext_substmt(current_element), index, exts);
+ break;
+ case YANG_ACTION:
+ break;
+ case YANG_ANYDATA:
+ break;
+ case YANG_ANYXML:
+ break;
+ case YANG_ARGUMENT:
+ ret = yin_parse_argument_element(ctx, subelem_attrs, data, (struct yin_argument_meta *)subelem_info_rec->dest, exts);
+ break;
+ case YANG_AUGMENT:
+ break;
+ case YANG_BASE:
+ if (current_element == YANG_IDENTITY) {
+ type = (struct lysp_type *)subelem_info_rec->dest;
+ ret = yin_parse_simple_elements(ctx, subelem_attrs, data, kw, &type->bases, YIN_ARG_NAME,
+ Y_PREF_IDENTIF_ARG, exts);
+ type->flags |= LYS_SET_BASE;
+ } else if (current_element == YANG_TYPE) {
+ ret = yin_parse_simple_elements(ctx, subelem_attrs, data, kw, (const char ***)subelem_info_rec->dest,
+ YIN_ARG_NAME, Y_PREF_IDENTIF_ARG, exts);
+ } else {
+ LOGINT(ctx->xml_ctx.ctx);
+ ret = LY_EINT;
+ }
+ break;
+ case YANG_BELONGS_TO:
+ ret = yin_parse_belongs_to(ctx, subelem_attrs, data, (struct lysp_submodule *)subelem_info_rec->dest, exts);
+ break;
+ case YANG_BIT:
+ case YANG_ENUM:
+ ret = yin_parse_enum_bit(ctx, subelem_attrs, data, kw, (struct lysp_type *)subelem_info_rec->dest);
+ break;
+ case YANG_CASE:
+ break;
+ case YANG_CHOICE:
+ break;
+ case YANG_CONFIG:
+ ret = yin_parse_config(ctx, subelem_attrs, data, (uint16_t *)subelem_info_rec->dest, exts);
+ break;
+ case YANG_CONTACT:
+ case YANG_DESCRIPTION:
+ case YANG_ORGANIZATION:
+ case YANG_REFERENCE:
+ ret = yin_parse_meta_element(ctx, data, kw, (const char **)subelem_info_rec->dest, exts);
+ break;
+ case YANG_CONTAINER:
+ break;
+ case YANG_DEFAULT:
+ ret = yin_parse_simple_element(ctx, subelem_attrs, data, kw, (const char **)subelem_info_rec->dest,
+ YIN_ARG_VALUE, Y_STR_ARG, exts);
+ break;
+ case YANG_DEVIATE:
+ break;
+ case YANG_DEVIATION:
+ break;
+ case YANG_ERROR_APP_TAG:
+ ret = yin_parse_simple_element(ctx, subelem_attrs, data, kw, (const char **)subelem_info_rec->dest,
+ YIN_ARG_VALUE, Y_STR_ARG, exts);
+ break;
+ case YANG_ERROR_MESSAGE:
+ ret = yin_parse_err_msg_element(ctx, data, (const char **)subelem_info_rec->dest, exts);
+ break;
+ case YANG_EXTENSION:
+ ret = yin_parse_extension(ctx, subelem_attrs, data, (struct lysp_ext **)subelem_info_rec->dest);
+ break;
+ case YANG_FEATURE:
+ break;
+ case YANG_FRACTION_DIGITS:
+ break;
+ case YANG_GROUPING:
+ break;
+ case YANG_IDENTITY:
+ break;
+ case YANG_IF_FEATURE:
+ ret = yin_parse_simple_elements(ctx, subelem_attrs, data, kw,
+ (const char ***)subelem_info_rec->dest, YIN_ARG_VALUE, Y_STR_ARG, exts);
+ break;
+ case YANG_IMPORT:
+ ret = yin_parse_import(ctx, subelem_attrs, data, (struct lysp_module *)subelem_info_rec->dest);
+ break;
+ case YANG_INCLUDE:
+ break;
+ case YANG_INPUT:
+ break;
+ case YANG_KEY:
+ break;
+ case YANG_LEAF:
+ break;
+ case YANG_LEAF_LIST:
+ break;
+ case YANG_LENGTH:
+ type = (struct lysp_type *)subelem_info_rec->dest;
+ type->length = calloc(1, sizeof *type->length);
+ LY_CHECK_ERR_GOTO(!type->length, LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, cleanup);
+ ret = yin_parse_restriction(ctx, subelem_attrs, data, kw, type->length);
+ type->flags |= LYS_SET_LENGTH;
+ break;
+ case YANG_LIST:
+ break;
+ case YANG_MANDATORY:
+ ret = yin_parse_mandatory(ctx, subelem_attrs, data, (uint16_t *)subelem_info_rec->dest, exts);
+ break;
+ case YANG_MAX_ELEMENTS:
+ break;
+ case YANG_MIN_ELEMENTS:
+ break;
+ case YANG_MODIFIER:
+ ret = yin_parse_modifier(ctx, subelem_attrs, data, (const char **)subelem_info_rec->dest, exts);
+ break;
+ case YANG_MODULE:
+ break;
+ case YANG_MUST:
+ ret = yin_parse_must(ctx, subelem_attrs, data, (struct lysp_restr **)subelem_info_rec->dest);
+ break;
+ case YANG_NAMESPACE:
+ ret = yin_parse_simple_element(ctx, subelem_attrs, data, kw, (const char **)subelem_info_rec->dest,
+ YIN_ARG_URI, Y_STR_ARG, exts);
+ break;
+ case YANG_NOTIFICATION:
+ break;
+ case YANG_ORDERED_BY:
+ break;
+ case YANG_OUTPUT:
+ break;
+ case YANG_PATH:
+ type = (struct lysp_type *)subelem_info_rec->dest;
+ ret = yin_parse_simple_element(ctx, subelem_attrs, data, kw, &type->path,
+ YIN_ARG_VALUE, Y_STR_ARG, exts);
+ type->flags |= LYS_SET_PATH;
+ break;
+ case YANG_PATTERN:
+ ret = yin_parse_pattern(ctx, subelem_attrs, data, (struct lysp_type *)subelem_info_rec->dest);
+ break;
+ case YANG_VALUE:
+ case YANG_POSITION:
+ ret = yin_parse_value_pos_element(ctx, subelem_attrs, data, kw,
+ (struct lysp_type_enum *)subelem_info_rec->dest);
+ break;
+ case YANG_PREFIX:
+ ret = yin_parse_simple_element(ctx, subelem_attrs, data, kw,
+ (const char **)subelem_info_rec->dest, YIN_ARG_VALUE, Y_IDENTIF_ARG, exts);
+ break;
+ case YANG_PRESENCE:
+ break;
+ case YANG_RANGE:
+ type = (struct lysp_type *)subelem_info_rec->dest;
+ type->range = calloc(1, sizeof *type->range);
+ LY_CHECK_ERR_GOTO(!type->range, LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, cleanup);
+ ret = yin_parse_restriction(ctx, subelem_attrs, data, kw, type->range);
+ type->flags |= LYS_SET_RANGE;
+ break;
+ case YANG_REFINE:
+ break;
+ case YANG_REQUIRE_INSTANCE:
+ ret = yin_pasrse_reqinstance(ctx, subelem_attrs, data, (struct lysp_type *)subelem_info_rec->dest);
+ break;
+ case YANG_REVISION:
+ break;
+ case YANG_REVISION_DATE:
+ ret = yin_parse_revision_date(ctx, subelem_attrs, data, (char *)subelem_info_rec->dest, exts);
+ break;
+ case YANG_RPC:
+ break;
+ case YANG_STATUS:
+ ret = yin_parse_status(ctx, subelem_attrs, data, (uint16_t *)subelem_info_rec->dest, exts);
+ break;
+ case YANG_SUBMODULE:
+ break;
+ case YANG_TYPE:
+ break;
+ case YANG_TYPEDEF:
+ break;
+ case YANG_UNIQUE:
+ ret = yin_parse_simple_elements(ctx, subelem_attrs, data, kw, (const char ***)subelem_info_rec->dest,
+ YIN_ARG_TAG, Y_STR_ARG, exts);
+ break;
+ case YANG_UNITS:
+ ret = yin_parse_simple_element(ctx, subelem_attrs, data, kw, (const char **)subelem_info_rec->dest,
+ YIN_ARG_NAME, Y_STR_ARG, exts);
+ break;
+ case YANG_USES:
+ break;
+ case YANG_WHEN:
+ ret = yin_parse_when(ctx, subelem_attrs, data, (struct lysp_when **)subelem_info_rec->dest);
+ break;
+ case YANG_YANG_VERSION:
+ ret = yin_parse_yangversion(ctx, subelem_attrs, data, (uint8_t *)subelem_info_rec->dest, exts);
+ break;
+ case YANG_YIN_ELEMENT:
+ ret = yin_parse_yin_element_element(ctx, subelem_attrs, data, (uint16_t *)subelem_info_rec->dest, exts);
+ break;
+ case YIN_TEXT:
+ case YIN_VALUE:
+ ret = yin_parse_content(ctx, NULL, 0, data, kw, (const char **)subelem_info_rec->dest, NULL);
+ break;
+ default:
+ LOGINT(ctx->xml_ctx.ctx);
+ return LY_EINT;
+ }
+ LY_CHECK_GOTO(ret, cleanup);
+ FREE_ARRAY(ctx, subelem_attrs, free_arg_rec);
+ subelem_attrs = NULL;
+ subelem_info_rec = NULL;
+ }
+ } else {
+ /* elements with text or none content */
+ /* save text content, if text_content isn't set, it's just ignored */
+ if (text_content) {
+ if (dynamic) {
+ *text_content = lydict_insert_zc(ctx->xml_ctx.ctx, out);
+ if (!*text_content) {
+ free(out);
+ return LY_EMEM;
+ }
+ } else {
+ if (out_len == 0) {
+ *text_content = NULL;
+ } else {
+ *text_content = lydict_insert(ctx->xml_ctx.ctx, out, out_len);
+ }
+ }
+ }
+ /* load closing element */
+ LY_CHECK_RET(lyxml_get_element(&ctx->xml_ctx, data, &prefix.value, &prefix.len, &name.value, &name.len));
+ }
+
+ LY_CHECK_RET(yin_check_subelem_mandatory_constraint(ctx, subelem_info, subelem_info_size, current_element));
+ }
+
+cleanup:
+ FREE_ARRAY(ctx, subelem_attrs, free_arg_rec);
+ return ret;
+}
+
+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_RET(lysp_check_date((struct lys_parser_ctx *)ctx, temp_rev, strlen(temp_rev), "revision-date") != LY_SUCCESS, 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] 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, temp_val, "config");
+ 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);
+}
+
+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, temp_version, "yang-version");
+ 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);
+}
+
+LY_ERR
+yin_parse_import(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data, struct lysp_module *mod)
+{
+ struct lysp_import *imp;
+ /* allocate new element in sized array for import */
+ LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, mod->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, mod->imports, mod->mod->prefix, &imp->prefix), LY_EVALID);
+
+ return yin_parse_content(ctx, subelems, 5, data, YANG_IMPORT, NULL, &imp->exts);
+}
+
+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, temp_val, "mandatory");
+ 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);
+}
+
+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, value, "status");
+ 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);
+}
+
+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;
+ when = calloc(1, sizeof *when);
+ LY_CHECK_ERR_RET(!when, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ yin_parse_attribute(ctx, attrs, YIN_ARG_CONDITION, &when->cond, Y_STR_ARG, YANG_WHEN);
+ *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);
+}
+
+LY_ERR
+yin_parse_yin_element_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, temp_val, "yin-element");
+ 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);
+}
+
+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_ERR_RET(!last_subelem->stmt, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ if (iter->dynamic_content) {
+ last_subelem->arg = lydict_insert_zc(ctx->xml_ctx.ctx, iter->content);
+ LY_CHECK_ERR_RET(!last_subelem->arg, LOGMEM(ctx->xml_ctx.ctx), LY_EMEM);
+ } else {
+ last_subelem->arg = lydict_insert(ctx->xml_ctx.ctx, iter->content, iter->content_len);
+ LY_CHECK_ERR_RET(!last_subelem->arg, LOGMEM(ctx->xml_ctx.ctx), 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, name, name_len, prefix, prefix_len, data, &new_subelem));
+ if (!e->child) {
+ e->child = new_subelem;
+ } else {
+ last_subelem->next = new_subelem;
+ }
+ last_subelem = new_subelem;
+ }
+ } else {
+ /* save text content */
+ if (dynamic) {
+ e->argument = lydict_insert_zc(ctx->xml_ctx.ctx, out);
+ if (!e->argument) {
+ free(out);
+ return LY_EMEM;
+ }
+ } else {
+ e->argument = lydict_insert(ctx->xml_ctx.ctx, out, out_len);
+ LY_CHECK_RET(!e->argument, LY_EMEM);
+ }
+ 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 *prefix,
+ size_t prefix_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;
+ int dynamic;
+ struct yin_arg_record *subelem_args = NULL;
+ struct lysp_stmt *last = NULL, *new = NULL;
+
+ /* allocate new structure for element */
+ *element = calloc(1, sizeof(**element));
+ (*element)->stmt = lydict_insert(ctx->xml_ctx.ctx, name, name_len);
+ LY_CHECK_ERR_RET(!(*element)->stmt, LOGMEM(ctx->xml_ctx.ctx), 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_GOTO(ret, LOGMEM(ctx->xml_ctx.ctx), err);
+ if (!(*element)->child) {
+ /* save first */
+ (*element)->child = new;
+ } else {
+ last->next = new;
+ }
+ last = new;
+
+ last->flags |= LYS_YIN_ATTR;
+ ret = lyxml_get_attribute(&ctx->xml_ctx, data, &temp_prefix, &prefix_len, &temp_name, &temp_name_len);
+ LY_CHECK_GOTO(ret, err);
+ ret = lyxml_get_string(&ctx->xml_ctx, data, &out, &out_len, &out, &out_len, &dynamic);
+ LY_CHECK_GOTO(ret, err);
+ last->stmt = lydict_insert(ctx->xml_ctx.ctx, temp_name, temp_name_len);
+ LY_CHECK_ERR_GOTO(!last->stmt, LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, err);
+ /* attributes with prefix are ignored */
+ if (!temp_prefix) {
+ if (dynamic) {
+ last->arg = lydict_insert_zc(ctx->xml_ctx.ctx, out);
+ if (!last->arg) {
+ free(out);
+ LOGMEM(ctx->xml_ctx.ctx);
+ ret = LY_EMEM;
+ goto err;
+ }
+ } else {
+ last->arg = lydict_insert(ctx->xml_ctx.ctx, out, out_len);
+ LY_CHECK_ERR_GOTO(!last->arg, LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, err);
+ }
+ }
+ }
+
+ /* parse content of element */
+ 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 */
+ ret = lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &temp_prefix_len, &temp_name, &temp_name_len);
+ LY_CHECK_GOTO(ret, err);
+ if (!name) {
+ /* end of element reached */
+ break;
+ }
+ ret = yin_parse_element_generic(ctx, temp_name, temp_name_len, temp_prefix, temp_prefix_len, data, &last->next);
+ LY_CHECK_GOTO(ret, err);
+ last = last->next;
+ }
+ } else {
+ /* save element content */
+ if (out_len != 0) {
+ if (dynamic) {
+ (*element)->arg = lydict_insert_zc(ctx->xml_ctx.ctx, out);
+ if (!(*element)->arg) {
+ free(out);
+ LOGMEM(ctx->xml_ctx.ctx);
+ ret = LY_EMEM;
+ goto err;
+ }
+ } else {
+ (*element)->arg = lydict_insert(ctx->xml_ctx.ctx, out, out_len);
+ LY_CHECK_ERR_GOTO(!(*element)->arg, LOGMEM(ctx->xml_ctx.ctx); ret = LY_EMEM, err);
+ }
+ }
+ /* read closing tag */
+ ret = lyxml_get_element(&ctx->xml_ctx, data, &temp_prefix, &prefix_len, &temp_name, &temp_name_len);
+ LY_CHECK_GOTO(ret, err);
+ }
+
+ FREE_ARRAY(ctx, subelem_args, free_arg_rec);
+ return LY_SUCCESS;
+
+err:
+ FREE_ARRAY(ctx, subelem_args, free_arg_rec);
+ return ret;
+}
+
+LY_ERR
+yin_parse_argument_element(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);
+}
+
+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 module substatements.
+ *
+ * @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.
+ */
+static LY_ERR
+yin_parse_mod(struct yin_parser_ctx *ctx, struct yin_arg_record *mod_attrs, const char **data, struct lysp_module **mod)
+{
+ struct yin_subelement subelems[9] = {
+ {YANG_CONTACT, &(*mod)->mod->contact, YIN_SUBELEM_UNIQUE},
+ {YANG_DESCRIPTION, &(*mod)->mod->dsc, YIN_SUBELEM_UNIQUE},
+ {YANG_EXTENSION, &(*mod)->exts, 0},
+ {YANG_IMPORT, *mod, 0},
+ {YANG_NAMESPACE, &(*mod)->mod->ns, YIN_SUBELEM_MANDATORY | YIN_SUBELEM_UNIQUE},
+ {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_CUSTOM, NULL, 0}
+ };
+
+ LY_CHECK_RET(yin_parse_attribute(ctx, mod_attrs, YIN_ARG_NAME, &(*mod)->mod->name, Y_IDENTIF_ARG, YANG_MODULE));
+
+ return yin_parse_content(ctx, subelems, 9, data, YANG_MODULE, NULL, &(*mod)->exts);
+}
+
+LY_ERR
+yin_parse_module(struct ly_ctx *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;
+
+ struct yin_parser_ctx yin_ctx;
+
+ /* initialize context */
+ memset(&yin_ctx, 0, sizeof yin_ctx);
+ yin_ctx.xml_ctx.ctx = ctx;
+ yin_ctx.xml_ctx.line = 1;
+
+
+ /* 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_SUBMODULE) {
+ LOGERR(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, LYVE_SYNTAX, "Invalid keyword \"%s\", expected \"module\" or \"submodule\".",
+ ly_stmt2str(kw));
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+
+ /* allocate module */
+ mod_p = calloc(1, sizeof *mod_p);
+ LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(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);
+
+ mod_p->parsing = 0;
+ mod->parsed = mod_p;
+
+cleanup:
+ if (ret != LY_SUCCESS) {
+ lysp_module_free(mod_p);
+ }
+ FREE_ARRAY(&yin_ctx, attrs, free_arg_rec);
+ lyxml_context_clear(&yin_ctx.xml_ctx);
+ return ret;
+}
diff --git a/src/parser_yin.h b/src/parser_yin.h
new file mode 100644
index 0000000..8ae07d8
--- /dev/null
+++ b/src/parser_yin.h
@@ -0,0 +1,313 @@
+/**
+ * @file parser_yin.h
+ * @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
+ */
+
+#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"
+#define name2fullname(name, prefix_len) (prefix_len != 0 ? name - (prefix_len + 1) : name)
+#define namelen2fulllen(name_len, prefix_len) (prefix_len != 0 ? name_len + prefix_len + 1 : name_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 */
+};
+
+struct yin_parser_ctx {
+ struct lyxml_context xml_ctx; /**< context for xml parser */
+ uint8_t mod_version; /**< module's version */
+};
+
+/* flags to encode cardinality of subelement */
+#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_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 cardianlity of subelement can be set to YIN_SUBELEM_MANDATORY and YIN_SUBELEM_UNIQUE and YIN_SUBELEM_FIRST */
+};
+
+/* helper structure just to make code look simpler */
+struct sized_string {
+ const char *value;
+ size_t len;
+};
+
+/* 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 Match argument name.
+ *
+ * @param[in] name String representing name.
+ * @param[in] len Lenght of the name.
+ *
+ * @return YIN_ARGUMENT value.
+ */
+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 se 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 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 instance to add to.
+ *
+ * @return LY_ERR values.
+ */
+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);
+
+/**
+ * @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 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] mod Structure of module that is being parsed.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_import(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs,
+ const char **data, struct lysp_module *mod);
+
+/**
+ * @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 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.
+ */
+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);
+
+/**
+ * @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.
+ */
+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);
+
+/**
+ * @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.
+ */
+LY_ERR yin_parse_when(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct lysp_when **when_p);
+
+/**
+ * @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.
+ */
+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);
+
+/**
+ * @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 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 instance to add to.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_yin_element_element(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ uint16_t *flags, struct lysp_ext_instance **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 af prased data.
+ * @param[in,out] exts Extension instance to add to.
+ *
+ * @return LY_ERR values.
+ */
+LY_ERR yin_parse_argument_element(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+ struct yin_argument_meta *arg_meta, struct lysp_ext_instance **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.
+ */
+LY_ERR yin_parse_extension(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs,
+ const char **data, struct lysp_ext **extensions);
+
+/**
+ * @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] prefix Element prefix.
+ * @param[in] prefix_len Length of element prefix.
+ * @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 *prefix,
+ size_t prefix_len, const char **data, struct lysp_stmt **element);
+
+#endif /* LY_PARSER_YIN_H_*/
diff --git a/src/printer_yang.c b/src/printer_yang.c
index 445afc2..42fcb14 100755
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -228,7 +228,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.h b/src/tree_schema.h
index 8ed59a4..a8b2d5f 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -124,19 +124,20 @@
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; /**< */
};
-
+#define LYS_YIN 0x1
/**
* @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 */
};
/**
@@ -529,6 +530,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 0x1000 /**< 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 b7fe1a8..60a392b 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -84,7 +84,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);
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 644b79a..75fd1ba 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.
*
@@ -796,6 +819,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 +1319,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)
{
@@ -1275,4 +1537,3 @@
return LY_ARRAY_SIZE(ext);
}
-
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 4da52a7..76e5413 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -20,13 +20,50 @@
#include "set.h"
#include "tree_schema.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 == '.')
+/* Macro to check YANG's yang-char grammar rule */
+#define is_yangutf8char(c) ((c >= 0x20 && c <= 0xd77) || 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
*/
@@ -53,9 +90,9 @@
*/
struct lys_parser_ctx {
struct ly_ctx *ctx;
+ uint64_t line; /**< line number */
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 */
};
@@ -80,6 +117,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 Check the currently present prefixes in the module for collision with the new one.
*
* @param[in] ctx Context for logging.
@@ -117,7 +179,7 @@
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.
@@ -131,6 +193,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.
@@ -662,6 +735,16 @@
LY_ERR yang_parse_module(struct lys_parser_ctx *ctx, const char *data, struct lys_module *mod);
/**
+ * @brief Parse module from YIN data.
+ * @param[in] ctx Libyang context.
+ * @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 ly_ctx *ctx, const char *data, struct lys_module *mod);
+
+/**
* @brief Make the specific module implemented, use the provided value as flag.
*
* @param[in] ctx libyang context to change.
@@ -673,4 +756,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/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt
index a1aa577..ed17333 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
@@ -21,6 +22,7 @@
" "
" "
" "
+ " "
" ")
set(tests ${tests} ${local_tests} PARENT_SCOPE)
set(tests_wraps ${tests_wraps} ${local_tests_wraps} PARENT_SCOPE)
diff --git a/tests/src/test_parser_yang.c b/tests/src/test_parser_yang.c
index 0d6263d..cfe8cd2 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);
@@ -141,10 +140,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 +160,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 +283,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.");
@@ -1057,6 +1062,15 @@
logbuf_assert("Invalid keyword \"prefix\", expected \"module\" or \"submodule\". Line number 3.");
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, str, m));
+ logbuf_assert("Invalid keyword \"position\" as a child of \"enum\". Line number 3.");
+ mod = mod_renew(&ctx);
+
/* extensions */
TEST_GENERIC("prefix:test;}", mod->exts,
assert_string_equal("prefix:test", mod->exts[0].name);
diff --git a/tests/src/test_parser_yin.c b/tests/src/test_parser_yin.c
new file mode 100644
index 0000000..7d31ffb
--- /dev/null
+++ b/tests/src/test_parser_yin.c
@@ -0,0 +1,977 @@
+/**
+ * @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);
+
+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
+
+
+static int
+setup_f(void **state)
+{
+ struct state *st = NULL;
+
+#if ENABLE_LOGGER_CHECKING
+ /* setup logger */
+ ly_set_log_clb(logger, 1);
+#endif
+
+ /* 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);
+
+ /* 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);
+ ly_ctx_destroy(st->ctx, NULL);
+ free(st->yin_ctx);
+ free(st);
+
+ 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 void
+test_yin_parse_module(void **state)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct state *st = *state;
+
+ ret = yin_parse_module(st->ctx,
+ "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\
+ name=\"example-foo\"\
+ xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\
+ xmlns:foo=\"urn:example:foo\"\
+ xmlns:myext=\"urn:example:extensions\">\
+ <namespace uri=\"urn:example:foo\" xmlns:myext=\"urn:example:extensions\"/>\
+ <prefix xmlns:myxt=\"urn:emple:extensions\" value=\"foo\" xmlns:myext=\"urn:example:extensions\"/>\
+ </module>",
+ st->mod);
+
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(st->mod->parsed->mod->name, "example-foo");
+ assert_string_equal(st->mod->parsed->mod->prefix, "foo");
+ assert_string_equal(st->mod->parsed->mod->ns, "urn:example:foo");
+
+ st = reset_state(state);
+ ret = yin_parse_module(st->ctx,
+ "<module name=\"example-foo\">\
+ <invalid-tag uri=\"urn:example:foo\"\"/>\
+ </module>",
+ st->mod);
+ assert_int_equal(ret, LY_EVALID);
+
+ st = reset_state(state);
+ ret = yin_parse_module(st->ctx,
+ "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\
+ </module>",
+ st->mod);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Missing mandatory attribute name of module element. Line number 1.");
+
+ st = reset_state(state);
+ ret = yin_parse_module(st->ctx,
+ "",
+ st->mod);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Invalid keyword \"(null)\", expected \"module\" or \"submodule\". Line number 1.");
+ st->finished_correctly = true;
+}
+
+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_meta(void **state)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct state *st = *state;
+
+ ret = yin_parse_module(st->ctx,"<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"\
+ name=\"example-foo\">\
+ <prefix value=\"foo\">ignored</prefix>\
+ <namespace uri=\"urn:example:foo\" xmlns:myext=\"urn:example:extensions\"/>\
+ <organization xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\"><text>organization...</text></organization>\
+ <contact><text>contact...</text></contact>\
+ <description><text>description...</text></description>\
+ <reference><text>reference...</text></reference>\
+ </module>", st->mod);
+
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(st->mod->parsed->mod->org, "organization...");
+ assert_string_equal(st->mod->parsed->mod->contact, "contact...");
+ assert_string_equal(st->mod->parsed->mod->dsc, "description...");
+ assert_string_equal(st->mod->parsed->mod->ref, "reference...");
+
+ st = reset_state(state);
+ ret = yin_parse_module(st->ctx,"<module name=\"example-foo\">\
+ <organization test=\"invalid-argument\">organization...</organization>\
+ </module>", st->mod);
+ assert_int_equal(ret, LY_EVALID);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_import(void **state)
+{
+ struct state *st = *state;
+ const char *prefix = NULL, *name = NULL;
+ size_t prefix_len = 0, name_len = 0;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_arg_record *args = NULL;
+
+ const char *data = "<import xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" module=\"a\">\
+ <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>\
+ \
+ <import xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" module=\"a\">\
+ <prefix value=\"a_mod\"/>\
+ <revision-date date=\"2015-01-01\" />\
+ </import>";
+ /* first import */
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &args);
+ st->lysp_mod->mod->prefix = "b-mod";
+ ret = yin_parse_import(st->yin_ctx, args, &data, st->lysp_mod);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_string_equal(st->lysp_mod->imports->name, "a");
+ assert_string_equal(st->lysp_mod->imports->prefix, "a_mod");
+ assert_string_equal(st->lysp_mod->imports->rev, "2015-01-01");
+ assert_string_equal(st->lysp_mod->imports->dsc, "import description");
+ assert_string_equal(st->lysp_mod->imports->ref, "import reference");
+ LY_ARRAY_FREE(args);
+ args = NULL;
+ st = reset_state(state);
+
+ /* second invalid import */
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &args);
+ st->lysp_mod->mod->prefix = "a_mod";
+ ret = yin_parse_import(st->yin_ctx, args, &data, st->lysp_mod);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Prefix \"a_mod\" already used as module prefix. Line number 1.");
+ LY_ARRAY_FREE(args);
+ args = NULL;
+
+ st = reset_state(state);
+ /* import with unknown child element */
+ data = "<import xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" module=\"a\">\
+ <what value=\"a_mod\"/>\
+ </import>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix, &prefix_len, &name, &name_len);
+ yin_load_attributes(st->yin_ctx, &data, &args);
+ st->lysp_mod->mod->prefix = "invalid_mod";
+ ret = yin_parse_import(st->yin_ctx, args, &data, st->lysp_mod);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Unexpected child element \"what\" of import element. Line number 1.");
+ LY_ARRAY_FREE(args);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_status(void **state)
+{
+ struct state *st = *state;
+ const char *prefix = NULL, *name = NULL;
+ size_t prefix_len = 0, name_len = 0;
+ LY_ERR ret = LY_SUCCESS;
+ uint16_t flags = 0;
+ struct lysp_ext_instance *exts;
+ struct yin_arg_record *args = NULL;
+
+ /* try all valid values */
+ const char *data = "<status value=\"current\" 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);
+ ret = yin_parse_status(st->yin_ctx, args, &data, &flags, &exts);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_true(flags & LYS_STATUS_CURR);
+ LY_ARRAY_FREE(args);
+ args = NULL;
+
+ st = reset_state(state);
+ flags = 0;
+ data = "<status value=\"deprecated\" 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);
+ ret = yin_parse_status(st->yin_ctx, args, &data, &flags, &exts);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_true(flags & LYS_STATUS_DEPRC);
+ LY_ARRAY_FREE(args);
+ args = NULL;
+
+ st = reset_state(state);
+ flags = 0;
+ data = "<status value=\"obsolete\" 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);
+ ret = yin_parse_status(st->yin_ctx, args, &data, &flags, &exts);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_true(flags & LYS_STATUS_OBSLT);
+ LY_ARRAY_FREE(args);
+ args = NULL;
+
+ /* invalid status value */
+ st = reset_state(state);
+ flags = 0;
+ data = "<status value=\"dunno\" 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);
+ ret = yin_parse_status(st->yin_ctx, args, &data, &flags, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Invalid value \"dunno\" of \"status\". Line number 1.");
+ LY_ARRAY_FREE(args);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_extension(void **state)
+{
+ struct state *st = *state;
+ const char *prefix = NULL, *name = NULL;
+ size_t prefix_len = 0, name_len = 0;
+ LY_ERR ret = LY_SUCCESS;
+ struct yin_arg_record *args = NULL;
+ struct lysp_ext *exts = NULL, *iter = NULL;
+
+ const char *data = "<extension name=\"b\" xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\
+ <argument name=\"argname\"></argument>\
+ <description><text>desc</text></description>\
+ <reference><text>ref</text></reference>\
+ <status value=\"deprecated\"></status>\
+ </extension>";
+ 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(st->yin_ctx, args, &data, &exts);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_int_equal(ret, LY_SUCCESS);
+ LY_ARRAY_FOR_ITER(exts, struct lysp_ext, iter) {
+ assert_string_equal(iter->name, "b");
+ assert_string_equal(iter->dsc, "desc");
+ assert_string_equal(iter->ref, "ref");
+ assert_string_equal(iter->argument, "argname");
+ assert_true(iter->flags & LYS_STATUS_DEPRC);
+ }
+ lydict_remove(st->ctx, "b");
+ lydict_remove(st->ctx, "desc");
+ lydict_remove(st->ctx, "ref");
+ lydict_remove(st->ctx, "argname");
+ LY_ARRAY_FREE(args);
+ LY_ARRAY_FREE(exts);
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_yin_element_element(void **state)
+{
+ struct state *st = *state;
+ const char *prefix = NULL, *name = NULL;
+ size_t prefix_len = 0, name_len = 0;
+ LY_ERR ret = LY_SUCCESS;
+ uint16_t flags = 0;
+ struct lysp_ext_instance *exts;
+ struct yin_arg_record *args = NULL;
+
+ /* try all valid values */
+ const char *data = "<yin-element value=\"true\" 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);
+ ret = yin_parse_yin_element_element(st->yin_ctx, args, &data, &flags, &exts);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_true(flags & LYS_YINELEM_TRUE);
+ LY_ARRAY_FREE(args);
+ args = NULL;
+
+ st = reset_state(state);
+ flags = 0;
+ data = "<yin-element value=\"false\" 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);
+ ret = yin_parse_yin_element_element(st->yin_ctx, args, &data, &flags, &exts);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_int_equal(ret, LY_SUCCESS);
+ assert_true(flags & LYS_YINELEM_FALSE);
+ LY_ARRAY_FREE(args);
+ args = NULL;
+
+ /* invalid value */
+ st = reset_state(state);
+ flags = 0;
+ data = "<yin-element value=\"invalid\" 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);
+ ret = yin_parse_yin_element_element(st->yin_ctx, args, &data, &flags, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ LY_ARRAY_FREE(args);
+ args = NULL;
+
+ st->finished_correctly = true;
+}
+
+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, prefix, prefix_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, prefix, prefix_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, name2fullname(name, prefix_len),
+ namelen2fulllen(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);
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_content(void **state)
+{
+ struct state *st = *state;
+ LY_ERR ret = LY_SUCCESS;
+ struct sized_string name, prefix;
+ 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 value=\"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.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+
+ struct yin_subelement subelems[17] = {
+ {YANG_CONFIG, &config, 0},
+ {YANG_DEFAULT, &def, 0},
+ {YANG_ENUM, &enum_type, 0},
+ {YANG_ERROR_APP_TAG, &app_tag, 0},
+ {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, 0},
+ {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, 0},
+ {YIN_TEXT, &value, YIN_SUBELEM_UNIQUE}};
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<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>"
+ "</module>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_content(st->yin_ctx, subelems2, 2, &data, YANG_MODULE, NULL, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Redefinition of text element in module 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 = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "<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>"
+ "</module>";
+ struct yin_subelement subelems3[2] = {{YANG_PREFIX, &prefix_value, 0},
+ {YIN_TEXT, &value, YIN_SUBELEM_FIRST}};
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_content(st->yin_ctx, subelems3, 2, &data, YANG_MODULE, NULL, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Subelement text of module element must be defined as first subelement. Line number 1.");
+ lydict_remove(st->ctx, prefix_value);
+ st = reset_state(state);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+
+ /* test mandatory subelem */
+ data = "<module xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">"
+ "</module>";
+ struct yin_subelement subelems4[1] = {{YANG_PREFIX, &prefix_value, YIN_SUBELEM_MANDATORY}};
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_content(st->yin_ctx, subelems4, 1, &data, YANG_MODULE, NULL, &exts);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Missing mandatory subelement prefix of module element. Line number 1.");
+ LY_ARRAY_FREE(attrs);
+
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_yangversion(void **state)
+{
+ struct state *st = *state;
+ LY_ERR ret = LY_SUCCESS;
+ struct sized_string name, prefix;
+ struct yin_arg_record *attrs = NULL;
+ uint8_t version;
+
+ const char *data = "<yang-version xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" value=\"1.0\">\n"
+ "</yang-version>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_yangversion(st->yin_ctx, attrs, &data, &version, NULL);
+ assert_int_equal(LY_SUCCESS, ret);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_true(version == LYS_VERSION_1_0);
+ assert_true(st->yin_ctx->mod_version == LYS_VERSION_1_0);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+ st = reset_state(state);
+
+ data = "<yang-version xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" value=\"1.1\">\n"
+ "</yang-version>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_yangversion(st->yin_ctx, attrs, &data, &version, NULL);
+ assert_int_equal(LY_SUCCESS, ret);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_true(version == LYS_VERSION_1_1);
+ assert_true(st->yin_ctx->mod_version == LYS_VERSION_1_1);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+ st = reset_state(state);
+
+ data = "<yang-version xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" value=\"randomvalue\">\n"
+ "</yang-version>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_yangversion(st->yin_ctx, attrs, &data, &version, NULL);
+ assert_int_equal(ret, LY_EVALID);
+ logbuf_assert("Invalid value \"randomvalue\" of \"yang-version\". Line number 1.");
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+ st = reset_state(state);
+
+ data = "<yang-version xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\n"
+ "</yang-version>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_yangversion(st->yin_ctx, attrs, &data, &version, NULL);
+ assert_int_equal(ret, LY_EVALID);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+ logbuf_assert("Missing mandatory attribute value of yang-version element. Line number 1.");
+ st->finished_correctly = true;
+}
+
+static void
+test_yin_parse_mandatory(void **state)
+{
+ struct state *st = *state;
+ LY_ERR ret = LY_SUCCESS;
+ struct sized_string name, prefix;
+ struct yin_arg_record *attrs = NULL;
+ uint16_t man = 0;
+
+ const char *data = "<mandatory xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" value=\"true\">\n"
+ "</mandatory>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_mandatory(st->yin_ctx, attrs, &data, &man, NULL);
+ assert_int_equal(LY_SUCCESS, ret);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_true(man == LYS_MAND_TRUE);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+ man = 0;
+ st = reset_state(state);
+
+ data = "<mandatory xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" value=\"false\" />";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_mandatory(st->yin_ctx, attrs, &data, &man, NULL);
+ assert_int_equal(LY_SUCCESS, ret);
+ assert_int_equal(st->yin_ctx->xml_ctx.status, LYXML_END);
+ assert_true(man == LYS_MAND_FALSE);
+ LY_ARRAY_FREE(attrs);
+ attrs = NULL;
+ man = 0;
+ st = reset_state(state);
+
+ data = "<mandatory xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\" value=\"randomvalue\">\n"
+ "</mandatory>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_mandatory(st->yin_ctx, attrs, &data, &man, NULL);
+ assert_int_equal(ret, LY_EVALID);
+ LY_ARRAY_FREE(attrs);
+ logbuf_assert("Invalid value \"randomvalue\" of \"mandatory\". Line number 1.");
+ attrs = NULL;
+ man = 0;
+ st = reset_state(state);
+
+ data = "<mandatory xmlns=\"urn:ietf:params:xml:ns:yang:yin:1\">\n"
+ "</mandatory>";
+ lyxml_get_element(&st->yin_ctx->xml_ctx, &data, &prefix.value, &prefix.len, &name.value, &name.len);
+ yin_load_attributes(st->yin_ctx, &data, &attrs);
+ ret = yin_parse_mandatory(st->yin_ctx, attrs, &data, &man, NULL);
+ assert_int_equal(ret, LY_EVALID);
+ LY_ARRAY_FREE(attrs);
+ logbuf_assert("Missing mandatory attribute value of mandatory element. Line number 1.");
+ 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;
+}
+
+int
+main(void)
+{
+
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_yin_parse_module, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_meta, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_import, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_status, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_match_keyword, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_extension, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_yin_element_element, 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_yin_parse_yangversion, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_yin_parse_mandatory, setup_f, teardown_f),
+ cmocka_unit_test_setup_teardown(test_validate_value, setup_f, teardown_f),
+ cmocka_unit_test(test_yin_match_argument_name),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/src/test_tree_schema_compile.c b/tests/src/test_tree_schema_compile.c
index bd00a7e..e5e28ff 100644
--- a/tests/src/test_tree_schema_compile.c
+++ b/tests/src/test_tree_schema_compile.c
@@ -1478,7 +1478,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);
@@ -1501,8 +1501,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.");
@@ -1526,7 +1526,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..ebca0da 100644
--- a/tests/src/test_xml.c
+++ b/tests/src/test_xml.c
@@ -561,6 +561,7 @@
cmocka_unit_test_setup(test_attribute, logger_setup),
cmocka_unit_test_setup(test_text, logger_setup),
cmocka_unit_test_setup(test_ns, logger_setup),
+ cmocka_unit_test(test_simple_xml),
cmocka_unit_test_setup(test_ns2, logger_setup),
cmocka_unit_test_setup(test_simple_xml, logger_setup),
};