data tree FEATURE initial implementation of YANG data support
diff --git a/src/common.c b/src/common.c
index a35c72c..5e19200 100644
--- a/src/common.c
+++ b/src/common.c
@@ -16,16 +16,14 @@
#include <assert.h>
#include <errno.h>
-#include <limits.h>
#include <stdlib.h>
-#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
+#include "extensions.h"
#include "tree_schema.h"
const char *const ly_stmt_list[] = {
diff --git a/src/common.h b/src/common.h
index 17b24c1..df65edc 100644
--- a/src/common.h
+++ b/src/common.h
@@ -18,18 +18,21 @@
#define _DEFAULT_SOURCE
#define _GNU_SOURCE
-#include <assert.h>
+#include <features.h>
#include <pthread.h>
+#include <stdc-predef.h>
+#include <stddef.h>
#include <stdint.h>
-#include <stdlib.h>
-#include <unistd.h>
#include "config.h"
-#include "log.h"
+
#include "context.h"
-#include "tree_schema.h"
-#include "set.h"
+#include "dict.h"
#include "hash_table.h"
+#include "log.h"
+#include "set.h"
+
+struct ly_ctx;
#if __STDC_VERSION__ >= 201112 && !defined __STDC_NO_THREADS__
# define THREAD_LOCAL _Thread_local
@@ -61,6 +64,19 @@
#endif
/******************************************************************************
+ * Compatibility functions
+ *****************************************************************************/
+
+#ifndef HAVE_STRNSTR
+/**
+ * @brief Find the first occurrence of find in s, where the search is limited to the
+ * first slen characters of s.
+ */
+char *strnstr(const char *s, const char *find, size_t slen);
+#endif
+
+
+/******************************************************************************
* Logger
*****************************************************************************/
@@ -85,8 +101,32 @@
extern volatile uint8_t ly_log_level;
extern volatile uint8_t ly_log_opts;
-void ly_err_free(void *ptr);
+/**
+ * @brief Set error-app-tag to the last error record in the context.
+ * @param[in] ctx libyang context where the error records are present.
+ * @param[in] apptag The error-app-tag value to store.
+ */
+void ly_err_last_set_apptag(const struct ly_ctx *ctx, const char *apptag);
+
+/**
+ * @brief Print a log message and store it into the context (if provided).
+ *
+ * @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
+ * @param[in] level Log message level (error, warning, etc.)
+ * @param[in] no Error type code.
+ * @param[in] format Format string to print.
+ */
void ly_log(const struct ly_ctx *ctx, LY_LOG_LEVEL level, LY_ERR no, const char *format, ...);
+
+/**
+ * @brief Print Validation error and store it into the context (if provided).
+ *
+ * @param[in] ctx libyang context to store the error record. If not provided, the error is just printed.
+ * @param[in] elem_type Type of the data in @p elem variable.
+ * @param[in] elem Object to provide more information about the place where the error appeared.
+ * @param[in] code Validation error code.
+ * @param[in] format Format string to print.
+ */
void ly_vlog(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const void *elem, LY_VECODE code, const char *format, ...);
#define LOGERR(ctx, errno, str, args...) ly_log(ctx, LY_LLERR, errno, str, ##args)
diff --git a/src/compat.c b/src/compat.c
new file mode 100644
index 0000000..7c4d660
--- /dev/null
+++ b/src/compat.c
@@ -0,0 +1,42 @@
+/**
+ * @file compat.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief Compatibility functions - implemented basic functions which are not available on all the platforms.
+ *
+ * Copyright (c) 2018 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 <string.h>
+
+#ifndef HAVE_STRNSTR
+
+char *
+strnstr(const char *s, const char *find, size_t slen)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != '\0') {
+ len = strlen(find);
+ do {
+ do {
+ if (slen-- < 1 || (sc = *s++) == '\0')
+ return (NULL);
+ } while (sc != c);
+ if (len > slen)
+ return (NULL);
+ } while (strncmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
+
+#endif
diff --git a/src/config.h.in b/src/config.h.in
index a65de05..3f107d9 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -19,6 +19,8 @@
#cmakedefine HAVE_VDPRINTF
+#cmakedefine HAVE_STRNSTR
+
/**
* @brief Compiler flag for unused function attributes
*/
diff --git a/src/context.c b/src/context.c
index d3ec7a3..9de0592 100644
--- a/src/context.c
+++ b/src/context.c
@@ -14,17 +14,21 @@
#include "common.h"
+#include <assert.h>
#include <errno.h>
-#include <limits.h>
+#include <pthread.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
#include "context.h"
+#include "hash_table.h"
+#include "set.h"
+#include "tree.h"
#include "tree_schema_internal.h"
-#include "libyang.h"
+#include "plugins_types.h"
#define LY_INTERNAL_MODS_COUNT 6
diff --git a/src/context.h b/src/context.h
index 65aa954..cbe027f 100644
--- a/src/context.h
+++ b/src/context.h
@@ -15,6 +15,8 @@
#ifndef LY_CONTEXT_H_
#define LY_CONTEXT_H_
+#include <stdint.h>
+
#include "log.h"
#include "tree_schema.h"
diff --git a/src/hash_table.c b/src/hash_table.c
index 11ca8f3..5e48332 100644
--- a/src/hash_table.c
+++ b/src/hash_table.c
@@ -12,14 +12,14 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
+#include "common.h"
+
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
-#include "common.h"
-#include "context.h"
#include "hash_table.h"
static int
diff --git a/src/hash_table.h b/src/hash_table.h
index 70ec695..ac42631 100644
--- a/src/hash_table.h
+++ b/src/hash_table.h
@@ -16,11 +16,13 @@
#ifndef LY_HASH_TABLE_H_
#define LY_HASH_TABLE_H_
-#include <stdint.h>
-#include <pthread.h>
-
#include "common.h"
-#include "dict.h"
+
+#include <pthread.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "log.h"
/**
* @brief Compute hash from (several) string(s).
diff --git a/src/libyang.h b/src/libyang.h
index 7b89268..a702e0b 100644
--- a/src/libyang.h
+++ b/src/libyang.h
@@ -25,8 +25,11 @@
#include "set.h"
#include "dict.h"
#include "context.h"
+#include "tree.h"
+#include "tree_data.h"
#include "tree_schema.h"
#include "printer_schema.h"
+#include "printer_data.h"
/**
* @mainpage About
diff --git a/src/log.c b/src/log.c
index b576437..b600b62 100644
--- a/src/log.c
+++ b/src/log.c
@@ -16,11 +16,14 @@
#include <assert.h>
#include <inttypes.h>
+#include <pthread.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-#include "libyang.h"
-#include "context.h"
+#include "log.h"
THREAD_LOCAL enum int_log_opts log_opt;
volatile uint8_t ly_log_level = LY_LLWRN;
@@ -106,6 +109,27 @@
}
API struct ly_err_item *
+ly_err_new(LY_LOG_LEVEL level, LY_ERR no, LY_VECODE vecode, char *msg, char *path, char *apptag)
+{
+ struct ly_err_item *eitem;
+
+ eitem = malloc(sizeof *eitem);
+ LY_CHECK_ERR_RET(!eitem, LOGMEM(NULL), NULL);
+ eitem->prev = eitem;
+ eitem->next = NULL;
+
+ /* fill in the information */
+ eitem->level = level;
+ eitem->no = no;
+ eitem->vecode = vecode;
+ eitem->msg = msg;
+ eitem->path = path;
+ eitem->apptag = apptag;
+
+ return eitem;
+}
+
+API struct ly_err_item *
ly_err_first(const struct ly_ctx *ctx)
{
LY_CHECK_ARG_RET(NULL, ctx, NULL);
@@ -113,7 +137,7 @@
return pthread_getspecific(ctx->errlist_key);
}
-void
+API void
ly_err_free(void *ptr)
{
struct ly_err_item *i, *next;
@@ -454,3 +478,16 @@
}
}
+void
+ly_err_last_set_apptag(const struct ly_ctx *ctx, const char *apptag)
+{
+ struct ly_err_item *i;
+
+ if (log_opt != ILO_IGNORE) {
+ i = ly_err_first(ctx);
+ if (i) {
+ i = i->prev;
+ i->apptag = strdup(apptag);
+ }
+ }
+}
diff --git a/src/log.h b/src/log.h
index 0074d83..920cd9e 100644
--- a/src/log.h
+++ b/src/log.h
@@ -166,7 +166,9 @@
LYVE_SYNTAX_YANG, /**< YANG-related syntax error */
LYVE_REFERENCE, /**< invalid referencing or using an item */
LYVE_XPATH, /**< invalid XPath expression */
- LYVE_SEMANTICS /**< generic semantic error */
+ LYVE_SEMANTICS, /**< generic semantic error */
+ LYVE_SYNTAX_XML, /**< XML-related syntax error */
+ LYVE_RESTRICTION /**< YANG data does not reflect some of the module restrictions */
} LY_VECODE;
/**
diff --git a/src/parser_xml.c b/src/parser_xml.c
new file mode 100644
index 0000000..cdc8111
--- /dev/null
+++ b/src/parser_xml.c
@@ -0,0 +1,273 @@
+/**
+ * @file parser_xml.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief XML data parser for libyang
+ *
+ * Copyright (c) 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "context.h"
+#include "dict.h"
+#include "log.h"
+#include "plugins_types.h"
+#include "set.h"
+#include "tree_data.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+#include "xml.h"
+
+/**
+ * @brief internal context for XML YANG data parser.
+ *
+ * The leading part is compatible with the struct lyxml_context
+ */
+struct lyd_xml_ctx {
+ struct ly_ctx *ctx; /**< libyang context */
+ uint64_t line; /**< number of the line being currently processed */
+ enum LYXML_PARSER_STATUS status; /**< status providing information about the next expected object in input data */
+ struct ly_set elements; /**< list of not-yet-closed elements */
+ struct ly_set ns; /**< handled with LY_SET_OPT_USEASLIST */
+
+ uint16_t options; /**< various @ref dataparseroptions. */
+ uint16_t path_len; /**< used bytes in the path buffer */
+#define LYD_PARSER_BUFSIZE 4078
+ char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
+};
+
+/**
+ * @brief Parse XML attributes of the XML element of YANG data.
+ *
+ * @param[in] ctx XML YANG data parser context.
+ * @param[in] element_name Element identifier to distinguish namespaces defined in different elements.
+ * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
+ * @param[out] attributes Resulting list of the parsed attributes. XML namespace definitions are not parsed
+ * as attributes, they are stored internally in the parser context.
+ * @reutn LY_ERR value.
+ */
+static LY_ERR
+lydxml_attributes(struct lyd_xml_ctx *ctx, const char *element_name, const char **data, struct lyd_attr **attributes)
+{
+ LY_ERR ret = LY_SUCCESS;
+ unsigned int u;
+ const char *prefix, *name;
+ size_t prefix_len, name_len;
+ struct lyd_attr *attr = NULL, *last = NULL;
+ const struct lyxml_ns *ns;
+ struct ly_set attr_prefixes = {0};
+ struct attr_prefix_s {
+ const char *prefix;
+ size_t prefix_len;
+ } *attr_prefix;
+ struct lys_module *mod;
+
+ while(ctx->status == LYXML_ATTRIBUTE &&
+ lyxml_get_attribute((struct lyxml_context*)ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
+ int dynamic = 0;
+ char *buffer = NULL, *value;
+ size_t buffer_size = 0, value_len;
+
+ lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+
+ if (prefix_len == 5 && !strncmp(prefix, "xmlns", 5)) {
+ /* named namespace */
+ lyxml_ns_add((struct lyxml_context *)ctx, element_name, name, name_len,
+ dynamic ? value : strndup(value, value_len));
+ } else if (!prefix && name_len == 5 && !strncmp(name, "xmlns", 5)) {
+ /* default namespace */
+ lyxml_ns_add((struct lyxml_context *)ctx, element_name, NULL, 0,
+ dynamic ? value : strndup(value, value_len));
+ } else {
+ /* attribute */
+ attr = calloc(1, sizeof *attr);
+ LY_CHECK_ERR_GOTO(!attr, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
+
+ attr->name = lydict_insert(ctx->ctx, name, name_len);
+ /* auxiliary store the prefix information and wait with resolving prefix to the time when all the namespaces,
+ * defined in this element, are parsed, so we will get the correct namespace for this prefix */
+ attr_prefix = malloc(sizeof *attr_prefix);
+ attr_prefix->prefix = prefix;
+ attr_prefix->prefix_len = prefix_len;
+ ly_set_add(&attr_prefixes, attr_prefix, LY_SET_OPT_USEASLIST);
+
+ /* TODO process value */
+
+ if (last) {
+ last->next = attr;
+ } else {
+ (*attributes) = attr;
+ }
+ last = attr;
+ }
+ }
+
+ /* resolve annotation pointers in all the attributes */
+ for (last = *attributes, u = 0; u < attr_prefixes.count && last; u++, last = last->next) {
+ attr_prefix = (struct attr_prefix_s*)attr_prefixes.objs[u];
+ ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_prefix->prefix, attr_prefix->prefix_len);
+ mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
+
+ /* TODO get annotation */
+ }
+
+cleanup:
+
+ ly_set_erase(&attr_prefixes, free);
+ return ret;
+}
+
+/**
+ * @brief Parse XML elements as children YANG data node of the specified parent node.
+ *
+ * @param[in] ctx XML YANG data parser context.
+ * @param[in] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
+ * @param[in,out] data Pointer to the XML string representation of the YANG data to parse.
+ * @param[out] node Resulting list of the parsed nodes.
+ * @reutn LY_ERR value.
+ */
+static LY_ERR
+lydxml_nodes(struct lyd_xml_ctx *ctx, struct lyd_node_inner *parent, const char **data, struct lyd_node **node)
+{
+ LY_ERR ret = LY_SUCCESS;
+ const char *prefix, *name;
+ char *element_name = NULL;
+ size_t prefix_len, name_len;
+ struct lyd_attr *attributes = NULL;
+ const struct lyxml_ns *ns;
+ const struct lysc_node *snode;
+ struct lys_module *mod;
+ unsigned int parents_count = ctx->elements.count;
+ struct lyd_node *cur = NULL, *prev = NULL;
+
+ (*node) = NULL;
+
+ while(ctx->status == LYXML_ELEMENT) {
+ ret = lyxml_get_element((struct lyxml_context *)ctx, data, &prefix, &prefix_len, &name, &name_len);
+ LY_CHECK_GOTO(ret, cleanup);
+ if (!name) {
+ /* closing previous element */
+ lyxml_ns_rm((struct lyxml_context *)ctx, element_name);
+ free(element_name);
+ element_name = NULL;
+ if (ctx->elements.count < parents_count) {
+ /* all siblings parsed */
+ break;
+ } else {
+ continue;
+ }
+ }
+ attributes = NULL;
+ element_name = strndup(name, name_len);
+ LY_CHECK_GOTO(lydxml_attributes(ctx, element_name, data, &attributes), cleanup);
+ ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
+ if (!ns) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%*.s\".", prefix_len, prefix);
+ goto cleanup;
+ }
+ mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
+ if (!mod) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
+ goto cleanup;
+ }
+ snode = lys_child(parent ? parent->schema : NULL, mod, name, name_len, 0, (ctx->options & LYD_OPT_RPCREPLY) ? LYS_GETNEXT_OUTPUT : 0);
+ if (!snode) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Element \"%.*s\" not found in the \"%s\" module.", name_len, name, mod->name);
+ goto cleanup;
+ }
+
+ /* allocate new node */
+ switch (snode->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ cur = calloc(1, sizeof(struct lyd_node_inner));
+ break;
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ cur = calloc(1, sizeof(struct lyd_node_term));
+ break;
+ case LYS_ANYDATA:
+ case LYS_ANYXML:
+ cur = calloc(1, sizeof(struct lyd_node_any));
+ break;
+ /* TODO LYS_ACTION, LYS_NOTIF */
+ default:
+ LOGINT(ctx->ctx);
+ goto cleanup;
+ }
+ if (!(*node)) {
+ (*node) = cur;
+ }
+ cur->schema = snode;
+ cur->parent = parent;
+ if (prev) {
+ cur->prev = prev;
+ prev->next = cur;
+ } else {
+ cur->prev = cur;
+ }
+ prev = cur;
+ cur->attr = attributes;
+ attributes = NULL;
+
+ if (snode->nodetype & LYD_NODE_TERM) {
+ int dynamic = 0;
+ char *buffer = NULL, *value;
+ size_t buffer_size = 0, value_len;
+
+ if (ctx->status == LYXML_ELEM_CONTENT) {
+ /* get the value */
+ lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+ lyd_value_validate((struct lyd_node_term*)cur, value, value_len,
+ LY_TYPE_VALIDATE_CANONIZE | (dynamic ? LY_TYPE_VALIDATE_DYNAMIC : 0));
+ }
+ } else if (snode->nodetype & LYD_NODE_INNER) {
+ int dynamic = 0;
+ char *buffer = NULL, *value;
+ size_t buffer_size = 0, value_len;
+
+ if (ctx->status == LYXML_ELEM_CONTENT) {
+ LY_ERR r = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &value, &value_len, &dynamic);
+ if (r != LY_EINVAL) {
+ LOGINT(ctx->ctx);
+ goto cleanup;
+ }
+ }
+ if (ctx->status == LYXML_ELEMENT) {
+ ret = lydxml_nodes(ctx, (struct lyd_node_inner*)cur, data, lyd_node_children_p(cur));
+ }
+ }
+ /* TODO anyxml/anydata */
+ }
+
+cleanup:
+ lyxml_ns_rm((struct lyxml_context *)ctx, element_name);
+ lyd_free_attr(ctx->ctx, attributes, 1);
+ free(element_name);
+ return ret;
+}
+
+LY_ERR
+lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **result)
+{
+ LY_ERR ret;
+ struct lyd_xml_ctx xmlctx = {0};
+
+ xmlctx.options = options;
+ xmlctx.ctx = ctx;
+ xmlctx.line = 1;
+
+ ret = lydxml_nodes(&xmlctx, NULL, &data, result);
+ lyxml_context_clear((struct lyxml_context*)&xmlctx);
+ return ret;
+}
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 83ad888..7ef4968 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -11,22 +11,24 @@
*
* https://opensource.org/licenses/BSD-3-Clause
*/
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <errno.h>
-#include <ctype.h>
-#include <string.h>
-#include <dirent.h>
-#include <assert.h>
#include "common.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "context.h"
-#include "libyang.h"
+#include "dict.h"
+#include "extensions.h"
+#include "log.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_schema.h"
#include "tree_schema_internal.h"
/* Macro to check YANG's yang-char grammar rule */
@@ -117,12 +119,12 @@
#define YANG_CHECK_STMTVER2_RET(CTX, KW, PARENT) \
if ((CTX)->mod_version < 2) {LOGVAL_YANG((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
-static LY_ERR parse_container(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_uses(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_choice(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_case(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_list(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
-static LY_ERR parse_grouping(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
+static LY_ERR parse_container(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_choice(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_case(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
+static LY_ERR parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
/**
* @brief Add another character to dynamic buffer, a low-level function.
@@ -166,7 +168,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-check_stringchar(struct ly_parser_ctx *ctx, unsigned int c)
+check_stringchar(struct lys_parser_ctx *ctx, unsigned int c)
{
if (!is_yangutf8char(c)) {
LOGVAL_YANG(ctx, LY_VCODE_INCHAR, c);
@@ -190,7 +192,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-check_identifierchar(struct ly_parser_ctx *ctx, unsigned int c, int first, int *prefix)
+check_identifierchar(struct lys_parser_ctx *ctx, unsigned int c, int first, int *prefix)
{
if (first || (prefix && (*prefix) == 1)) {
if (!is_yangidentstartchar(c)) {
@@ -231,7 +233,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-buf_store_char(struct ly_parser_ctx *ctx, const char **input, enum yang_arg arg,
+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 = 0;
@@ -315,7 +317,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-skip_comment(struct ly_parser_ctx *ctx, const char **data, int comment)
+skip_comment(struct lys_parser_ctx *ctx, const char **data, int comment)
{
/* internal statuses: 0 - comment ended,
* 1 - in line comment,
@@ -384,7 +386,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-read_qstring(struct ly_parser_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len,
+read_qstring(struct lys_parser_ctx *ctx, const char **data, enum yang_arg arg, char **word_p, char **word_b, size_t *word_len,
size_t *buf_len)
{
/* string: 0 - string ended, 1 - string with ', 2 - string with ", 3 - string with " with last character \,
@@ -580,7 +582,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-get_argument(struct ly_parser_ctx *ctx, const char **data, enum yang_arg arg,
+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)
{
size_t buf_len = 0;
@@ -695,7 +697,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-get_keyword(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, size_t *word_len)
+get_keyword(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword *kw, char **word_p, size_t *word_len)
{
int prefix;
const char *word_start;
@@ -1011,7 +1013,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_ext_substmt(struct ly_parser_ctx *ctx, const char **data, char *word, size_t word_len,
+parse_ext_substmt(struct lys_parser_ctx *ctx, const char **data, char *word, size_t word_len,
struct lysp_stmt **child)
{
char *buf;
@@ -1063,7 +1065,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_ext(struct ly_parser_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
+parse_ext(struct lys_parser_ctx *ctx, const char **data, const char *ext_name, int ext_name_len, LYEXT_SUBSTMT insubstmt,
uint32_t insubstmt_index, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
@@ -1107,7 +1109,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_text_field(struct ly_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
+parse_text_field(struct lys_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, uint32_t substmt_index,
const char **value, enum yang_arg arg, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
@@ -1150,7 +1152,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_yangversion(struct ly_parser_ctx *ctx, const char **data, uint8_t *version, struct lysp_ext_instance **exts)
+parse_yangversion(struct lys_parser_ctx *ctx, const char **data, uint8_t *version, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1201,7 +1203,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_belongsto(struct ly_parser_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
+parse_belongsto(struct lys_parser_ctx *ctx, const char **data, const char **belongsto, const char **prefix, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1251,7 +1253,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_revisiondate(struct ly_parser_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
+parse_revisiondate(struct lys_parser_ctx *ctx, const char **data, char *rev, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1300,7 +1302,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_include(struct ly_parser_ctx *ctx, const char *module_name, const char **data, struct lysp_include **includes)
+parse_include(struct lys_parser_ctx *ctx, const char *module_name, const char **data, struct lysp_include **includes)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1357,7 +1359,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_import(struct ly_parser_ctx *ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
+parse_import(struct lys_parser_ctx *ctx, const char *module_prefix, const char **data, struct lysp_import **imports)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1414,7 +1416,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_revision(struct ly_parser_ctx *ctx, const char **data, struct lysp_revision **revs)
+parse_revision(struct lys_parser_ctx *ctx, const char **data, struct lysp_revision **revs)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1467,7 +1469,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_text_fields(struct ly_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
+parse_text_fields(struct lys_parser_ctx *ctx, const char **data, LYEXT_SUBSTMT substmt, const char ***texts, enum yang_arg arg,
struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
@@ -1507,7 +1509,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_config(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_config(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1557,7 +1559,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_mandatory(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_mandatory(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1607,7 +1609,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_restr(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr *restr)
+parse_restr(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr *restr)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1654,7 +1656,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_restrs(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr **restrs)
+parse_restrs(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword restr_kw, struct lysp_restr **restrs)
{
struct lysp_restr *restr;
@@ -1673,7 +1675,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_status(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_status(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1724,7 +1726,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_when(struct ly_parser_ctx *ctx, const char **data, struct lysp_when **when_p)
+parse_when(struct lys_parser_ctx *ctx, const char **data, struct lysp_when **when_p)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1775,7 +1777,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_any(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node *parent, struct lysp_node **siblings)
+parse_any(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword kw, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -1853,7 +1855,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_type_enum_value_pos(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
+parse_type_enum_value_pos(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword val_kw, int64_t *value, uint16_t *flags,
struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
@@ -1935,7 +1937,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_type_enum(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword enum_kw, struct lysp_type_enum **enums)
+parse_type_enum(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword enum_kw, struct lysp_type_enum **enums)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2013,7 +2015,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_type_fracdigits(struct ly_parser_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
+parse_type_fracdigits(struct lys_parser_ctx *ctx, const char **data, uint8_t *fracdig, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word, *ptr;
@@ -2076,7 +2078,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_type_reqinstance(struct ly_parser_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
+parse_type_reqinstance(struct lys_parser_ctx *ctx, const char **data, uint8_t *reqinst, uint16_t *flags,
struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
@@ -2126,7 +2128,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_type_pattern_modifier(struct ly_parser_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
+parse_type_pattern_modifier(struct lys_parser_ctx *ctx, const char **data, const char **pat, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2181,7 +2183,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_type_pattern(struct ly_parser_ctx *ctx, const char **data, struct lysp_restr **patterns)
+parse_type_pattern(struct lys_parser_ctx *ctx, const char **data, struct lysp_restr **patterns)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2246,7 +2248,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_type(struct ly_parser_ctx *ctx, const char **data, struct lysp_type *type)
+parse_type(struct lys_parser_ctx *ctx, const char **data, struct lysp_type *type)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2341,7 +2343,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_leaf(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_leaf(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2439,7 +2441,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_maxelements(struct ly_parser_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_maxelements(struct lys_parser_ctx *ctx, const char **data, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word, *ptr;
@@ -2506,7 +2508,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_minelements(struct ly_parser_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_minelements(struct lys_parser_ctx *ctx, const char **data, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word, *ptr;
@@ -2569,7 +2571,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_orderedby(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_orderedby(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2618,7 +2620,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_leaflist(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_leaflist(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2727,7 +2729,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_refine(struct ly_parser_ctx *ctx, const char **data, struct lysp_refine **refines)
+parse_refine(struct lys_parser_ctx *ctx, const char **data, struct lysp_refine **refines)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2795,7 +2797,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_typedef(struct ly_parser_ctx *ctx, struct lysp_node *parent, const char **data, struct lysp_tpdf **typedefs)
+parse_typedef(struct lys_parser_ctx *ctx, struct lysp_node *parent, const char **data, struct lysp_tpdf **typedefs)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -2865,7 +2867,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_inout(struct ly_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
+parse_inout(struct lys_parser_ctx *ctx, const char **data, enum yang_keyword inout_kw, struct lysp_node *parent, struct lysp_action_inout *inout_p)
{
LY_ERR ret = LY_SUCCESS;
char *word;
@@ -2947,7 +2949,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_action(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions)
+parse_action(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_action **actions)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3020,7 +3022,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_notif(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_notif **notifs)
+parse_notif(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_notif **notifs)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3115,7 +3117,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_grouping(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings)
+parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3211,7 +3213,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_augment(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_augment **augments)
+parse_augment(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_augment **augments)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3302,7 +3304,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_uses(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_uses(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3375,7 +3377,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_case(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_case(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3466,7 +3468,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_choice(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_choice(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3573,7 +3575,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_container(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_container(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = 0;
char *buf, *word;
@@ -3695,7 +3697,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_list(struct ly_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
+parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3839,7 +3841,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_yinelement(struct ly_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_yinelement(struct lys_parser_ctx *ctx, const char **data, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3890,7 +3892,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_argument(struct ly_parser_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
+parse_argument(struct lys_parser_ctx *ctx, const char **data, const char **argument, uint16_t *flags, struct lysp_ext_instance **exts)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3932,7 +3934,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_extension(struct ly_parser_ctx *ctx, const char **data, struct lysp_ext **extensions)
+parse_extension(struct lys_parser_ctx *ctx, const char **data, struct lysp_ext **extensions)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -3981,7 +3983,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_deviate(struct ly_parser_ctx *ctx, const char **data, struct lysp_deviate **deviates)
+parse_deviate(struct lys_parser_ctx *ctx, const char **data, struct lysp_deviate **deviates)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -4195,7 +4197,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_deviation(struct ly_parser_ctx *ctx, const char **data, struct lysp_deviation **deviations)
+parse_deviation(struct lys_parser_ctx *ctx, const char **data, struct lysp_deviation **deviations)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -4249,7 +4251,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_feature(struct ly_parser_ctx *ctx, const char **data, struct lysp_feature **features)
+parse_feature(struct lys_parser_ctx *ctx, const char **data, struct lysp_feature **features)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -4298,7 +4300,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_identity(struct ly_parser_ctx *ctx, const char **data, struct lysp_ident **identities)
+parse_identity(struct lys_parser_ctx *ctx, const char **data, struct lysp_ident **identities)
{
LY_ERR ret = LY_SUCCESS;
char *buf, *word;
@@ -4381,7 +4383,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_module(struct ly_parser_ctx *ctx, const char **data, struct lysp_module *mod)
+parse_module(struct lys_parser_ctx *ctx, const char **data, struct lysp_module *mod)
{
LY_ERR ret = 0;
char *buf, *word;
@@ -4591,7 +4593,7 @@
* @return LY_ERR values.
*/
static LY_ERR
-parse_submodule(struct ly_parser_ctx *ctx, const char **data, struct lysp_submodule *submod)
+parse_submodule(struct lys_parser_ctx *ctx, const char **data, struct lysp_submodule *submod)
{
LY_ERR ret = 0;
char *buf, *word;
@@ -4785,7 +4787,7 @@
}
LY_ERR
-yang_parse_submodule(struct ly_parser_ctx *context, const char *data, struct lysp_submodule **submod)
+yang_parse_submodule(struct lys_parser_ctx *context, const char *data, struct lysp_submodule **submod)
{
LY_ERR ret = LY_SUCCESS;
char *word, *buf;
@@ -4841,7 +4843,7 @@
}
LY_ERR
-yang_parse_module(struct ly_parser_ctx *context, const char *data, struct lys_module *mod)
+yang_parse_module(struct lys_parser_ctx *context, const char *data, struct lys_module *mod)
{
LY_ERR ret = LY_SUCCESS;
char *word, *buf;
diff --git a/src/plugins_types.c b/src/plugins_types.c
new file mode 100644
index 0000000..cc5d740
--- /dev/null
+++ b/src/plugins_types.c
@@ -0,0 +1,204 @@
+/**
+ * @file plugin_types.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Built-in types plugins and interface for user types plugins.
+ *
+ * Copyright (c) 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 <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "plugins_types.h"
+#include "dict.h"
+#include "tree_schema.h"
+
+API LY_ERR
+ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, struct ly_err_item **err)
+{
+ unsigned int u;
+ char *errmsg = NULL;
+
+ LY_ARRAY_FOR(range->parts, u) {
+ if (basetype < LY_TYPE_DEC64) {
+ /* unsigned */
+ if ((uint64_t)value < range->parts[u].min_u64) {
+ if (range->emsg) {
+ errmsg = strdup(range->emsg);
+ } else {
+ asprintf(&errmsg, "%s \"%"PRIu64"\" does not satisfy the %s constraint.",
+ (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "Length" : "Value", (uint64_t)value,
+ (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "length" : "range");
+ }
+ goto error;
+ } else if ((uint64_t)value < range->parts[u].max_u64) {
+ /* inside the range */
+ return LY_SUCCESS;
+ } else if (u == LY_ARRAY_SIZE(range->parts) - 1) {
+ /* we have the last range part, so the value is out of bounds */
+ if (range->emsg) {
+ errmsg = strdup(range->emsg);
+ } else {
+ asprintf(&errmsg, "%s \"%"PRIu64"\" does not satisfy the %s constraint.",
+ (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "Length" : "Value", (uint64_t)value,
+ (basetype & (LY_TYPE_BINARY | LY_TYPE_STRING)) ? "length" : "range");
+ }
+ goto error;
+ }
+ } else {
+ /* signed */
+ if (value < range->parts[u].min_64) {
+ if (range->emsg) {
+ errmsg = strdup(range->emsg);
+ } else {
+ asprintf(&errmsg, "Value \"%"PRId64"\" does not satisfy the range constraint.", value);
+ }
+ goto error;
+ } else if (value < range->parts[u].max_64) {
+ /* inside the range */
+ return LY_SUCCESS;
+ } else if (u == LY_ARRAY_SIZE(range->parts) - 1) {
+ /* we have the last range part, so the value is out of bounds */
+ if (range->emsg) {
+ errmsg = strdup(range->emsg);
+ } else {
+ asprintf(&errmsg, "Value \"%"PRId64"\" does not satisfy the range constraint.", value);
+ }
+ goto error;
+ }
+ }
+ }
+
+ return LY_SUCCESS;
+
+error:
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, range->eapptag ? strdup(range->eapptag) : NULL);
+ return LY_EVALID;
+}
+
+/**
+ * @brief Validate and canonize value of the YANG built-in binary type.
+ *
+ * Implementation of the ly_type_validate_clb.
+ */
+static LY_ERR
+ly_type_validate_binary(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ const char **canonized, struct ly_err_item **err)
+{
+ size_t start, stop, count = 0, u, termination = 0;
+ struct lysc_type_bin *type_bin = (struct lysc_type_bin *)type;
+ char *errmsg;
+
+ /* initiate */
+ *err = NULL;
+
+ /* validate characters and remember the number of octets for length validation */
+ if (value) {
+ /* silently skip leading/trailing whitespaces */
+ for (start = 0; (start < value_len) && isspace(value[start]); start++);
+ for (stop = value_len - 1; stop > start && isspace(value[stop]); stop--);
+ if (start == stop) {
+ /* empty string */
+ goto finish;
+ }
+
+ for (count = 0, u = start; u < stop; u++) {
+ if (value[u] == '\n') {
+ /* newline formatting */
+ continue;
+ }
+ count++;
+
+ if ((value[u] < '/' && value[u] != '+') ||
+ (value[u] > '9' && value[u] < 'A') ||
+ (value[u] > 'Z' && value[u] < 'a') || value[u] > 'z') {
+ /* non-encoding characters */
+ if (value[u] == '=') {
+ /* padding */
+ if (u == stop - 1 && value[u + 1] == '=') {
+ termination = 2;
+ stop = u + 1;
+ } else if (u == stop){
+ termination = 1;
+ stop = u;
+ }
+ }
+ if (!termination) {
+ /* error */
+ asprintf(&errmsg, "Invalid Base64 character (%c).", value[u]);
+ goto error;
+ }
+ }
+ }
+ }
+
+finish:
+ if (count & 3) {
+ /* base64 length must be multiple of 4 chars */
+ errmsg = strdup("Base64 encoded value length must be divisible by 4.");
+ goto error;
+ }
+
+ /* length of the encoded string */
+ if (type_bin->length) {
+ uint64_t len = ((count / 4) * 3) - termination;
+ LY_CHECK_RET(ly_type_validate_range(LY_TYPE_BINARY, type_bin->length, len, err));
+ }
+
+ if (options & LY_TYPE_VALIDATE_CANONIZE) {
+ if (start != 0 || stop != value_len - 1) {
+ *canonized = lydict_insert_zc(ctx, strndup(&value[start], stop - start));
+ } else if (options & LY_TYPE_VALIDATE_DYNAMIC) {
+ *canonized = lydict_insert_zc(ctx, (char*)value);
+ value = NULL;
+ } else {
+ *canonized = lydict_insert(ctx, value, value_len);
+ }
+ }
+ if (options & LY_TYPE_VALIDATE_DYNAMIC) {
+ free((char*)value);
+ }
+
+ return LY_SUCCESS;
+
+error:
+ if (!*err) {
+ *err = ly_err_new(LY_LLERR, LY_EVALID, LYVE_RESTRICTION, errmsg, NULL, NULL);
+ }
+ return (*err)->no;
+}
+
+
+struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT] = {
+ {0}, /* LY_TYPE_UNKNOWN */
+ {.type = LY_TYPE_BINARY, .validate = ly_type_validate_binary, .store = NULL},
+ {0}, /* TODO LY_TYPE_UINT8 */
+ {0}, /* TODO LY_TYPE_UINT16 */
+ {0}, /* TODO LY_TYPE_UINT32 */
+ {0}, /* TODO LY_TYPE_UINT64 */
+ {0}, /* TODO LY_TYPE_STRING */
+ {0}, /* TODO LY_TYPE_BITS */
+ {0}, /* TODO LY_TYPE_BOOL */
+ {0}, /* TODO LY_TYPE_DEC64 */
+ {0}, /* TODO LY_TYPE_EMPTY */
+ {0}, /* TODO LY_TYPE_ENUM */
+ {0}, /* TODO LY_TYPE_IDENT */
+ {0}, /* TODO LY_TYPE_INST */
+ {0}, /* TODO LY_TYPE_LEAFREF */
+ {0}, /* TODO LY_TYPE_UNION */
+ {0}, /* TODO LY_TYPE_INT8 */
+ {0}, /* TODO LY_TYPE_INT16 */
+ {0}, /* TODO LY_TYPE_INT32 */
+ {0} /* TODO LY_TYPE_INT64 */
+};
+
diff --git a/src/plugins_types.h b/src/plugins_types.h
new file mode 100644
index 0000000..0a84f3c
--- /dev/null
+++ b/src/plugins_types.h
@@ -0,0 +1,144 @@
+/**
+ * @file plugins_types.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief API for (user) types plugins
+ *
+ * Copyright (c) 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_PLUGINS_TYPES_H_
+#define LY_PLUGINS_TYPES_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "tree.h"
+#include "tree_schema.h"
+#include "tree_data.h"
+
+/**
+ * @brief Helper function for various plugin functions to generate error information structure.
+ *
+ * @param[in] level Error level of the error.
+ * @param[in] code Code of the error.
+ * @param[in] vecode Validity error code in case of LY_EVALID error code.
+ * @param[in] msg Error message.
+ * @param[in] path Path to the node causing the error.
+ * @param[in] apptag Error-app-tag value.
+ * @return NULL in case of memory allocation failure.
+ * @return Created error information structure that can be freed using ly_err_free().
+ */
+struct ly_err_item *ly_err_new(LY_LOG_LEVEL level, LY_ERR code, LY_VECODE vecode, char *msg, char *path, char *apptag);
+
+/**
+ * @brief Destructor for the error records created with ly_err_new().
+ *
+ * Compatible with the free(), so usable as a generic callback.
+ *
+ * @param[in] ptr Error record to free. With the record, also all the records connected after this one are freed.
+ */
+void ly_err_free(void *ptr);
+
+/**
+ * @defgroup plugintypevalidateopts Options for type plugin validation callback.
+ * Options applicable to ly_type_validate_clb().
+ * @{
+ */
+#define LY_TYPE_VALIDATE_CANONIZE 0x01 /**< Canonize the given value and store it (insert into the context's dictionary)
+ as the value's canonized string */
+#define LY_TYPE_VALIDATE_DYNAMIC 0x02 /**< Flag for the dynamically allocated string value, in this case the value is supposed to be freed
+ or directly used to insert into the node's value structure in case of canonization.
+ In any case, the caller of the callback does not free the provided string value after calling
+ the ly_type_validate_clb() with this option */
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup plugintypeflags Various flags for type plugins usage.
+ * Options applicable to ly_type_validate_clb().
+ * @{
+ */
+#define LY_TYPE_FLAG_PREFIXES 0x01 /**< The value contains prefixes, so when printing XML,
+ get the namespaces connected with the prefixes and print them. */
+/**
+ * @}
+ */
+
+/**
+ * @brief Callback to validate the given @p value according to the given @p type. Optionaly, it can be requested to canonize the value.
+ *
+ * Note that the \p value string is not necessarily zero-terminated. The provided \p value_len is always correct.
+ *
+ * @param[in] ctx libyang Context
+ * @param[in] type Type of the value being canonized.
+ * @param[in] value Lexical representation of the value to be validated (and canonized).
+ * @param[in] value_len Length of the given \p value.
+ * @param[in] options [Type validation options ](@ref plugintypevalidateopts).
+ * @param[out] canonized If LY_TYPE_VALIDATE_CANONIZE option set, the canonized string stored in the @p ctx dictionary is returned via this parameter.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
+ * The error structure can be created by ly_err_new().
+ * @return LY_SUCCESS on success
+ * @return LY_ERR value if an error occurred and the value could not be canonized following the type's rules.
+ */
+typedef LY_ERR (*ly_type_validate_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value, size_t value_len, int options,
+ const char **canonized, struct ly_err_item **err);
+
+/**
+ * @brief Callback for storing user type values.
+ *
+ * This callback should overwrite the value stored in \p value using some custom encoding. Be careful,
+ * if the type is #LY_TYPE_BITS, the bits must be freed before overwritting the union value.
+ *
+ * @param[in] ctx libyang ctx to enable correct manipulation with values that are in the dictionary.
+ * @param[in] type Type of the value being stored.
+ * @param[in] value_str Canonized string value to be stored.
+ * @param[in,out] value Value structure to store the data in the type plugin specific way.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
+ * The error structure can be created by ly_err_new().
+ * @return LY_SUCCESS on success
+ * @return LY_ERR value if an error occurred and the value could not be stored for any reason.
+ */
+typedef LY_ERR (*ly_type_store_clb)(struct ly_ctx *ctx, struct lysc_type *type, const char *value_str, struct lyd_value *value, struct ly_err_item **err);
+
+/**
+ * @brief Hold type-specific functions for various operations with the data values.
+ *
+ * libyang includes set of plugins for all the built-in types. They are, by default, inherited to the derived types.
+ * However, if the user type plugin for the specific type is loaded, the plugin can provide it's own functions.
+ * The built-in types plugins and are public, so even the user type plugins can use them to do part of their own functionality.
+ */
+struct lysc_type_plugin {
+ LY_DATA_TYPE type; /**< implemented type, use LY_TYPE_UNKNOWN for derived data types */
+ ly_type_validate_clb validate; /**< function to validate and canonize given value */
+ ly_type_store_clb store; /**< function to store the value in the type-specific way */
+ uint32_t flags; /**< [type flags ](@ref plugintypeflags). */
+};
+
+/**
+ * @brief List of type plugins for built-in types.
+ */
+extern struct lysc_type_plugin ly_builtin_type_plugins[LY_DATA_TYPE_COUNT];
+
+/**
+ * @brief Data type validator for a range/length-restricted values.
+ *
+ * @param[in] ctx libyang context
+ * @param[in] range Range (length) restriction information.
+ * @param[in] value Value to check. In case of basetypes using unsigned integer values, the value is actually cast to uint64_t.
+ * @param[out] err Optionally provided error information in case of failure. If not provided to the caller, a generic error message is prepared instead.
+ * The error structure can be created by ly_err_new().
+ * @return LY_ERR value according to the result of the validation.
+ */
+LY_ERR ly_type_validate_range(LY_DATA_TYPE basetype, struct lysc_range *range, int64_t value, struct ly_err_item **err);
+
+
+#endif /* LY_PLUGINS_TYPES_H_ */
diff --git a/src/printer.c b/src/printer.c
index e681104..72872b1 100644
--- a/src/printer.c
+++ b/src/printer.c
@@ -1,7 +1,7 @@
/**
* @file printer.c
* @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Wrapper for all libyang printers.
+ * @brief Generic libyang printers functions.
*
* Copyright (c) 2015 - 2019 CESNET, z.s.p.o.
*
@@ -16,8 +16,12 @@
#include <errno.h>
#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include "log.h"
#include "printer_internal.h"
/**
@@ -159,15 +163,20 @@
fflush(out->method.f);
break;
case LYOUT_FD:
+ fsync(out->method.fd);
+ break;
case LYOUT_MEMORY:
case LYOUT_CALLBACK:
/* nothing to do */
break;
}
+
+ free(out->buffered);
+ out->buf_size = out->buf_len = 0;
}
LY_ERR
-ly_write(struct lyout *out, const char *buf, size_t count)
+ly_write(struct lyout *out, const char *buf, size_t len)
{
int written = 0;
@@ -175,48 +184,48 @@
if (out->hole_count) {
/* we are buffering data after a hole */
- if (out->buf_len + count > out->buf_size) {
- out->buffered = ly_realloc(out->buffered, out->buf_len + count);
+ if (out->buf_len + len > out->buf_size) {
+ out->buffered = ly_realloc(out->buffered, out->buf_len + len);
if (!out->buffered) {
out->buf_len = 0;
out->buf_size = 0;
LOGMEM_RET(NULL);
}
- out->buf_size = out->buf_len + count;
+ out->buf_size = out->buf_len + len;
}
- memcpy(&out->buffered[out->buf_len], buf, count);
- out->buf_len += count;
+ memcpy(&out->buffered[out->buf_len], buf, len);
+ out->buf_len += len;
return LY_SUCCESS;
}
repeat:
switch (out->type) {
case LYOUT_MEMORY:
- if (out->method.mem.len + count + 1 > out->method.mem.size) {
- out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + count + 1);
+ if (out->method.mem.len + len + 1 > out->method.mem.size) {
+ out->method.mem.buf = ly_realloc(out->method.mem.buf, out->method.mem.len + len + 1);
if (!out->method.mem.buf) {
out->method.mem.len = 0;
out->method.mem.size = 0;
LOGMEM_RET(NULL);
}
- out->method.mem.size = out->method.mem.len + count + 1;
+ out->method.mem.size = out->method.mem.len + len + 1;
}
- memcpy(&out->method.mem.buf[out->method.mem.len], buf, count);
- out->method.mem.len += count;
+ memcpy(&out->method.mem.buf[out->method.mem.len], buf, len);
+ out->method.mem.len += len;
out->method.mem.buf[out->method.mem.len] = '\0';
- out->printed += count;
+ out->printed += len;
return LY_SUCCESS;
case LYOUT_FD:
- written = write(out->method.fd, buf, count);
+ written = write(out->method.fd, buf, len);
break;
case LYOUT_FDSTREAM:
case LYOUT_STREAM:
- written = fwrite(buf, sizeof *buf, count, out->method.f);
+ written = fwrite(buf, sizeof *buf, len, out->method.f);
break;
case LYOUT_CALLBACK:
- written = out->method.clb.f(out->method.clb.arg, buf, count);
+ written = out->method.clb.f(out->method.clb.arg, buf, len);
break;
}
@@ -227,8 +236,8 @@
LOGERR(out->ctx, LY_ESYS, "%s: writing data failed (%s).", __func__, strerror(errno));
out->status = LY_ESYS;
return LY_ESYS;
- } else if ((size_t)written != count) {
- LOGERR(out->ctx, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__, count - (size_t)written, count);
+ } else if ((size_t)written != len) {
+ LOGERR(out->ctx, LY_ESYS, "%s: writing data failed (unable to write %u from %u data).", __func__, len - (size_t)written, len);
out->status = LY_ESYS;
return LY_ESYS;
} else {
@@ -331,162 +340,3 @@
return ret;
}
-
-static LY_ERR
-lys_print_(struct lyout *out, const struct lys_module *module, LYS_OUTFORMAT format, int UNUSED(line_length), int UNUSED(options))
-{
- LY_ERR ret;
-
- switch (format) {
- case LYS_OUT_YANG:
- ret = yang_print_parsed(out, module);
- break;
- case LYS_OUT_YANG_COMPILED:
- ret = yang_print_compiled(out, module);
- break;
- /* TODO not yet implemented
- case LYS_OUT_YIN:
- lys_disable_deviations((struct lys_module *)module);
- ret = yin_print_model(out, module);
- lys_enable_deviations((struct lys_module *)module);
- break;
- case LYS_OUT_TREE:
- ret = tree_print_model(out, module, target_node, line_length, options);
- break;
- case LYS_OUT_INFO:
- ret = info_print_model(out, module, target_node);
- break;
- case LYS_OUT_JSON:
- ret = jsons_print_model(out, module, target_node);
- break;
- */
- default:
- LOGERR(module->ctx, LY_EINVAL, "Unknown output format.");
- ret = LY_EINVAL;
- break;
- }
-
- return ret;
-}
-
-API ssize_t
-lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
- struct lyout out;
- LY_ERR ret;
-
- LY_CHECK_ARG_RET(NULL, f, module, LY_EINVAL);
-
- memset(&out, 0, sizeof out);
- out.ctx = module->ctx;
- out.type = LYOUT_STREAM;
- out.method.f = f;
-
- ret = lys_print_(&out, module, format, line_length, options);
- if (ret) {
- /* error */
- return (-1) * ret;
- } else {
- /* success */
- return (ssize_t)out.printed;
- }
-}
-
-API ssize_t
-lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
- FILE *f;
- ssize_t ret;
-
- LY_CHECK_ARG_RET(NULL, path, module, LY_EINVAL);
-
- f = fopen(path, "w");
- if (!f) {
- LOGERR(module->ctx, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
- return LY_ESYS;
- }
-
- ret = lys_print_file(f, module, format, line_length, options);
- fclose(f);
- return ret;
-}
-
-API ssize_t
-lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
- LY_ERR ret;
- struct lyout out;
-
- LY_CHECK_ARG_RET(NULL, fd >= 0, module, LY_EINVAL);
-
- memset(&out, 0, sizeof out);
- out.ctx = module->ctx;
- out.type = LYOUT_FD;
- out.method.fd = fd;
-
- ret = lys_print_(&out, module, format, line_length, options);
-
- if (out.type == LYOUT_FDSTREAM) {
- /* close temporary stream based on the given file descriptor */
- fclose(out.method.f);
- /* move the original file descriptor to the end of the output file */
- lseek(fd, 0, SEEK_END);
- }
-
- if (ret) {
- /* error */
- return (-1) * ret;
- } else {
- /* success */
- return (ssize_t)out.printed;
- }
-}
-
-API ssize_t
-lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
-{
- struct lyout out;
- LY_ERR ret;
-
- LY_CHECK_ARG_RET(NULL, strp, module, LY_EINVAL);
-
- memset(&out, 0, sizeof out);
- out.ctx = module->ctx;
- out.type = LYOUT_MEMORY;
-
- ret = lys_print_(&out, module, format, line_length, options);
- if (ret) {
- /* error */
- *strp = NULL;
- return (-1) * ret;
- } else {
- /* success */
- *strp = out.method.mem.buf;
- return (ssize_t)out.printed;
- }
-}
-
-API ssize_t
-lys_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lys_module *module,
- LYS_OUTFORMAT format, int line_length, int options)
-{
- LY_ERR ret;
- struct lyout out;
-
- LY_CHECK_ARG_RET(NULL, writeclb, module, LY_EINVAL);
-
- memset(&out, 0, sizeof out);
- out.ctx = module->ctx;
- out.type = LYOUT_CALLBACK;
- out.method.clb.f = writeclb;
- out.method.clb.arg = arg;
-
- ret = lys_print_(&out, module, format, line_length, options);
- if (ret) {
- /* error */
- return (-1) * ret;
- } else {
- /* success */
- return (ssize_t)out.printed;
- }
-}
diff --git a/src/printer_data.c b/src/printer_data.c
new file mode 100644
index 0000000..7853099
--- /dev/null
+++ b/src/printer_data.c
@@ -0,0 +1,194 @@
+/**
+ * @file printer_data.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Generic data printers functions.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "printer_internal.h"
+#include "tree_schema.h"
+#include "tree_data.h"
+
+/**
+ * @brief Common YANG data printer.
+ *
+ * @param[in] out Prepared structure defining the type and details of the printer output.
+ * @param[in] root The root element of the (sub)tree to print.
+ * @param[in] format Output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyd_print_(struct lyout *out, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+ LY_ERR ret;
+
+ switch (format) {
+ case LYD_XML:
+ ret = xml_print_data(out, root, options);
+ break;
+#if 0
+ case LYD_JSON:
+ ret = json_print_data(out, root, options);
+ break;
+ case LYD_LYB:
+ ret = lyb_print_data(out, root, options);
+ break;
+#endif
+ default:
+ LOGERR(root->schema->module->ctx, LY_EINVAL, "Unknown output format.");
+ ret = LY_EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+API ssize_t
+lyd_print_file(FILE *f, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+ struct lyout out;
+ LY_ERR ret;
+
+ LY_CHECK_ARG_RET(NULL, f, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.type = LYOUT_STREAM;
+ out.method.f = f;
+
+ if (root) {
+ out.ctx = root->schema->module->ctx;
+ }
+
+ ret = lyd_print_(&out, root, format, options);
+ if (ret) {
+ /* error */
+ return (-1) * ret;
+ } else {
+ /* success */
+ return (ssize_t)out.printed;
+ }
+}
+
+API ssize_t
+lyd_print_path(const char *path, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+ FILE *f;
+ ssize_t ret;
+
+ LY_CHECK_ARG_RET(NULL, path, LY_EINVAL);
+
+ f = fopen(path, "w");
+ if (!f) {
+ LOGERR(root ? root->schema->module->ctx : NULL, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
+ return LY_ESYS;
+ }
+
+ ret = lyd_print_file(f, root, format, options);
+ fclose(f);
+ return ret;
+}
+
+API ssize_t
+lyd_print_fd(int fd, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+ LY_ERR ret;
+ struct lyout out;
+
+ LY_CHECK_ARG_RET(NULL, fd >= 0, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.type = LYOUT_FD;
+ out.method.fd = fd;
+
+ if (root) {
+ out.ctx = root->schema->module->ctx;
+ }
+
+ ret = lyd_print_(&out, root, format, options);
+
+ if (out.type == LYOUT_FDSTREAM) {
+ /* close temporary stream based on the given file descriptor */
+ fclose(out.method.f);
+ /* move the original file descriptor to the end of the output file */
+ lseek(fd, 0, SEEK_END);
+ }
+
+ if (ret) {
+ /* error */
+ return (-1) * ret;
+ } else {
+ /* success */
+ return (ssize_t)out.printed;
+ }
+}
+
+API ssize_t
+lyd_print_mem(char **strp, const struct lyd_node *root, LYD_FORMAT format, int options)
+{
+ struct lyout out;
+ LY_ERR ret;
+
+ LY_CHECK_ARG_RET(NULL, strp, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.type = LYOUT_MEMORY;
+
+ if (root) {
+ out.ctx = root->schema->module->ctx;
+ }
+
+ ret = lyd_print_(&out, root, format, options);
+ if (ret) {
+ /* error */
+ *strp = NULL;
+ return (-1) * ret;
+ } else {
+ /* success */
+ *strp = out.method.mem.buf;
+ return (ssize_t)out.printed;
+ }
+}
+
+API ssize_t
+lyd_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lyd_node *root,
+ LYD_FORMAT format, int options)
+{
+ LY_ERR ret;
+ struct lyout out;
+
+ LY_CHECK_ARG_RET(NULL, writeclb, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.type = LYOUT_CALLBACK;
+ out.method.clb.f = writeclb;
+ out.method.clb.arg = arg;
+
+ if (root) {
+ out.ctx = root->schema->module->ctx;
+ }
+
+ ret = lyd_print_(&out, root, format, options);
+ if (ret) {
+ /* error */
+ return (-1) * ret;
+ } else {
+ /* success */
+ return (ssize_t)out.printed;
+ }
+}
diff --git a/src/printer_data.h b/src/printer_data.h
new file mode 100644
index 0000000..197463c
--- /dev/null
+++ b/src/printer_data.h
@@ -0,0 +1,125 @@
+/**
+ * @file printer_schema.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Schema printers for libyang
+ *
+ * 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_PRINTER_DATA_H_
+#define LY_PRINTER_DATA_H_
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tree_data.h"
+
+/**
+ * @defgroup dataprinterflags Data printer flags
+ * @ingroup datatree
+ *
+ * Validity flags for data nodes.
+ *
+ * @{
+ */
+#define LYDP_WITHSIBLINGS 0x01 /**< Flag for printing also the (following) sibling nodes of the data node. */
+#define LYDP_FORMAT 0x02 /**< Flag for formatted output. */
+#define LYDP_KEEPEMPTYCONT 0x04 /**< Preserve empty non-presence containers */
+#define LYDP_WD_MASK 0xF0 /**< Mask for with-defaults modes */
+#define LYDP_WD_EXPLICIT 0x00 /**< Explicit mode - print only data explicitly being present in the data tree.
+ Note that this is the default value when no WD option is specified. */
+#define LYDP_WD_TRIM 0x10 /**< Do not print the nodes with the value equal to their default value */
+#define LYDP_WD_ALL 0x20 /**< Include implicit default nodes */
+#define LYDP_WD_ALL_TAG 0x40 /**< Same as #LYP_WD_ALL but also adds attribute 'default' with value 'true' to
+ all nodes that has its default value. The 'default' attribute has namespace:
+ urn:ietf:params:xml:ns:netconf:default:1.0 and thus the attributes are
+ printed only when the ietf-netconf-with-defaults module is present in libyang
+ context (but in that case this namespace is always printed). */
+#define LYDP_WD_IMPL_TAG 0x80 /**< Same as LYP_WD_ALL_TAG but the attributes are added only to the nodes that
+ are not explicitly present in the original data tree despite their
+ value is equal to their default value. There is the same limitation regarding
+ the presence of ietf-netconf-with-defaults module in libyang context. */
+#define LYDP_NETCONF 0x100 /**< Print the data tree for use in NETCONF meaning:
+ - for RPC output - skip the top-level RPC node,
+ - for action output - skip all the parents of and the action node itself,
+ - for action input - enclose the data in an action element in the base YANG namespace,
+ - for all other data - print the whole data tree normally. */
+/**
+ * @}
+ */
+
+/**
+ * @brief Print data tree in the specified format into a memory block.
+ * It is up to caller to free the returned string by free().
+ *
+ * @param[out] strp Pointer to store the resulting dump.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_mem(char **strp, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format into a file descriptor.
+ *
+ * @param[in] fd File descriptor where to print the data.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_fd(int fd, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format into a file stream.
+ *
+ * @param[in] f File stream where to print the schema.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_file(FILE *f, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format into a file.
+ *
+ * @param[in] path File where to print the schema.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_path(const char *path, const struct lyd_node *root, LYD_FORMAT format, int options);
+
+/**
+ * @brief Print data tree in the specified format using the provided callback.
+ *
+ * @param[in] writeclb Callback function to write the data (see write(2)).
+ * @param[in] arg Optional caller-specific argument to be passed to the \p writeclb callback.
+ * @param[in] root Root node of the data tree to print. It can be actually any (not only real root)
+ * node of the data tree to print the specific subtree.
+ * @param[in] format Data output format.
+ * @param[in] options [Data printer flags](@ref dataprinterflags). With \p format LYD_LYB, only #LYP_WITHSIBLINGS option is accepted.
+ * @return Number of printed bytes in case of success.
+ * @return Negative value failure (absolute value corresponds to LY_ERR values).
+ */
+ssize_t lyd_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lyd_node *root,
+ LYD_FORMAT format, int options);
+
+#endif /* LY_PRINTER_DATA_H_ */
diff --git a/src/printer_internal.h b/src/printer_internal.h
index 2fb582e..7d0e312 100644
--- a/src/printer_internal.h
+++ b/src/printer_internal.h
@@ -16,7 +16,11 @@
#define LY_PRINTER_INTERNAL_H_
#include "printer_schema.h"
+#include "printer_data.h"
+/**
+ * @brief Types of the printer's output
+ */
typedef enum LYOUT_TYPE {
LYOUT_FD, /**< file descriptor */
LYOUT_STREAM, /**< FILE stream */
@@ -25,44 +29,43 @@
LYOUT_CALLBACK /**< print via provided callback */
} LYOUT_TYPE;
+/**
+ * @brief Printer output structure specifying where the data are printed.
+ */
struct lyout {
- LYOUT_TYPE type;
+ LYOUT_TYPE type; /**< type of the output to select the output method */
union {
- int fd;
- FILE *f;
+ int fd; /**< file descriptor for LYOUT_FD type */
+ FILE *f; /**< file structure for LYOUT_STREAM and LYOUT_FDSTREAM types */
struct {
- char *buf;
- size_t len;
- size_t size;
- } mem;
+ char *buf; /**< pointer to the memory buffer to store the output */
+ size_t len; /**< number of used bytes in the buffer */
+ size_t size; /**< allocated size of the buffer */
+ } mem; /**< memory buffer information for LYOUT_MEMORY type */
struct {
- ssize_t (*f)(void *arg, const void *buf, size_t count);
- void *arg;
- } clb;
- } method;
+ ssize_t (*f)(void *arg, const void *buf, size_t count); /**< callback function */
+ void *arg; /**< optional argument for the callback function */
+ } clb; /**< printer callback for LYOUT_CALLBACK type */
+ } method; /**< type-specific information about the output */
- /* buffer for holes */
- char *buffered;
- size_t buf_len;
- size_t buf_size;
+ char *buffered; /**< additional buffer for holes, used only for LYB data format */
+ size_t buf_len; /**< number of used bytes in the additional buffer for holes, used only for LYB data format */
+ size_t buf_size; /**< allocated size of the buffer for holes, used only for LYB data format */
+ size_t hole_count; /**< hole counter, used only for LYB data format */
- /* hole counter */
- size_t hole_count;
+ size_t printed; /**< Number of printed bytes */
- /* counter for printed bytes */
- size_t printed;
-
- /* libyang context for error logging */
- struct ly_ctx *ctx;
- LY_ERR status;
+ struct ly_ctx *ctx; /**< libyang context for error logging */
+ LY_ERR status; /**< current status of the printer */
};
-#define LYOUT_CHECK(LYOUT, ...) if (LYOUT->status) {return __VA_ARGS__;}
-
+/**
+ * @brief Informational structure for YANG statements
+ */
struct ext_substmt_info_s {
- const char *name;
- const char *arg;
- int flags;
+ const char *name; /**< name of the statement */
+ const char *arg; /**< name of YIN's attribute to present the statement */
+ int flags; /**< various flags to clarify printing of the statement */
#define SUBST_FLAG_YIN 0x1 /**< has YIN element */
#define SUBST_FLAG_ID 0x2 /**< the value is identifier -> no quotes */
};
@@ -70,21 +73,97 @@
/* filled in printer.c */
extern struct ext_substmt_info_s ext_substmt_info[];
+/**
+ * @brief macro to check current status of the printer.
+ */
+#define LYOUT_CHECK(LYOUT, ...) if (LYOUT->status) {return __VA_ARGS__;}
/**
- * @brief
+ * @brief YANG printer of the parsed schemas. Full YANG printer.
+ *
+ * @param[in] out Output specification.
+ * @param[in] module Schema to be printed (the parsed member is used).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
*/
LY_ERR yang_print_parsed(struct lyout *out, const struct lys_module *module);
/**
- * @brief
+ * @brief YANG printer of the compiled schemas.
+ *
+ * This printer provides information about modules how they are understood by libyang.
+ * Despite the format is inspired by YANG, it is not fully compatible and should not be
+ * used as a standard YANG format.
+ *
+ * @param[in] out Output specification.
+ * @param[in] module Schema to be printed (the compiled member is used).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
*/
LY_ERR yang_print_compiled(struct lyout *out, const struct lys_module *module);
+/**
+ * @brief XML printer of the YANG data.
+ *
+ * @param[in] out Output specification.
+ * @param[in] root The root element of the (sub)tree to print.
+ * @param[in] options [Data printer flags](@ref dataprinterflags).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
+LY_ERR xml_print_data(struct lyout *out, const struct lyd_node *root, int options);
+
+/**
+ * @brief Generic printer of the given format string into the specified output.
+ *
+ * Alternatively, ly_write() can be used.
+ *
+ * @param[in] out Output specification.
+ * @param[in] format format string to be printed.
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
LY_ERR ly_print(struct lyout *out, const char *format, ...);
+/**
+ * @brief Flush the output from any internal buffers and clean any auxiliary data.
+ * @param[in] out Output specification.
+ */
void ly_print_flush(struct lyout *out);
-LY_ERR ly_write(struct lyout *out, const char *buf, size_t count);
+/**
+ * @brief Generic printer of the given string buffer into the specified output.
+ *
+ * Alternatively, ly_print() can be used.
+ *
+ * As an extension for printing holes (skipping some data until they are known),
+ * ly_write_skip() and ly_write_skipped() can be used.
+ *
+ * @param[in] out Output specification.
+ * @param[in] buf Memory buffer with the data to print.
+ * @param[in] len Length of the data to print in the @p buf.
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
+LY_ERR ly_write(struct lyout *out, const char *buf, size_t len);
+
+/**
+ * @brief Create a hole in the output data that will be filled later.
+ *
+ * @param[in] out Output specification.
+ * @param[in] len Length of the created hole.
+ * @param[out] position Position of the hole, value must be later provided to the ly_write_skipped() call.
+ * @return LY_ERR value. The number of the printed bytes is updated in lyout::printed
+ * only in case the data are really written into the output.
+ */
+LY_ERR ly_write_skip(struct lyout *out, size_t len, size_t *position);
+
+/**
+ * @brief Write data into the hole at given position.
+ *
+ * @param[in] out Output specification.
+ * @param[in] position Position of the hole to fill, the value was provided by ly_write_skip().
+ * @param[in] buf Memory buffer with the data to print.
+ * @param[in] len Length of the data to print in the @p buf. Not that the length must correspond
+ * to the len value specified in the corresponding ly_write_skip() call.
+ * @return LY_ERR value. The number of the printed bytes is updated in lyout::printed
+ * only in case the data are really written into the output.
+ */
+LY_ERR ly_write_skipped(struct lyout *out, size_t position, const char *buf, size_t len);
#endif /* LY_PRINTER_INTERNAL_H_ */
diff --git a/src/printer_schema.c b/src/printer_schema.c
new file mode 100644
index 0000000..c07ea79
--- /dev/null
+++ b/src/printer_schema.c
@@ -0,0 +1,193 @@
+/**
+ * @file printer_schema.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Generic schema printers functions.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "printer_internal.h"
+#include "tree_schema.h"
+
+/**
+ * @brief Common schema printer.
+ *
+ * @param[in] out Prepared structure defining the type and details of the printer output.
+ * @param[in] module Schema to print.
+ * @param[in] format Output format.
+ * @param[in] line_length Maximum characters to be printed on a line, 0 for unlimited. Only for #LYS_OUT_TREE printer.
+ * @param[in] options Schema output options (see @ref schemaprinterflags).
+ * @return LY_ERR value, number of the printed bytes is updated in lyout::printed.
+ */
+static LY_ERR
+lys_print_(struct lyout *out, const struct lys_module *module, LYS_OUTFORMAT format, int UNUSED(line_length), int UNUSED(options))
+{
+ LY_ERR ret;
+
+ switch (format) {
+ case LYS_OUT_YANG:
+ ret = yang_print_parsed(out, module);
+ break;
+ case LYS_OUT_YANG_COMPILED:
+ ret = yang_print_compiled(out, module);
+ break;
+ /* TODO not yet implemented
+ case LYS_OUT_YIN:
+ lys_disable_deviations((struct lys_module *)module);
+ ret = yin_print_model(out, module);
+ lys_enable_deviations((struct lys_module *)module);
+ break;
+ case LYS_OUT_TREE:
+ ret = tree_print_model(out, module, target_node, line_length, options);
+ break;
+ case LYS_OUT_INFO:
+ ret = info_print_model(out, module, target_node);
+ break;
+ case LYS_OUT_JSON:
+ ret = jsons_print_model(out, module, target_node);
+ break;
+ */
+ default:
+ LOGERR(module->ctx, LY_EINVAL, "Unknown output format.");
+ ret = LY_EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+API ssize_t
+lys_print_file(FILE *f, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ struct lyout out;
+ LY_ERR ret;
+
+ LY_CHECK_ARG_RET(NULL, f, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.ctx = module->ctx;
+ out.type = LYOUT_STREAM;
+ out.method.f = f;
+
+ ret = lys_print_(&out, module, format, line_length, options);
+ if (ret) {
+ /* error */
+ return (-1) * ret;
+ } else {
+ /* success */
+ return (ssize_t)out.printed;
+ }
+}
+
+API ssize_t
+lys_print_path(const char *path, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ FILE *f;
+ ssize_t ret;
+
+ LY_CHECK_ARG_RET(NULL, path, module, LY_EINVAL);
+
+ f = fopen(path, "w");
+ if (!f) {
+ LOGERR(module->ctx, LY_ESYS, "Failed to open file \"%s\" (%s).", path, strerror(errno));
+ return LY_ESYS;
+ }
+
+ ret = lys_print_file(f, module, format, line_length, options);
+ fclose(f);
+ return ret;
+}
+
+API ssize_t
+lys_print_fd(int fd, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ LY_ERR ret;
+ struct lyout out;
+
+ LY_CHECK_ARG_RET(NULL, fd >= 0, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.ctx = module->ctx;
+ out.type = LYOUT_FD;
+ out.method.fd = fd;
+
+ ret = lys_print_(&out, module, format, line_length, options);
+
+ if (out.type == LYOUT_FDSTREAM) {
+ /* close temporary stream based on the given file descriptor */
+ fclose(out.method.f);
+ /* move the original file descriptor to the end of the output file */
+ lseek(fd, 0, SEEK_END);
+ }
+
+ if (ret) {
+ /* error */
+ return (-1) * ret;
+ } else {
+ /* success */
+ return (ssize_t)out.printed;
+ }
+}
+
+API ssize_t
+lys_print_mem(char **strp, const struct lys_module *module, LYS_OUTFORMAT format, int line_length, int options)
+{
+ struct lyout out;
+ LY_ERR ret;
+
+ LY_CHECK_ARG_RET(NULL, strp, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.ctx = module->ctx;
+ out.type = LYOUT_MEMORY;
+
+ ret = lys_print_(&out, module, format, line_length, options);
+ if (ret) {
+ /* error */
+ *strp = NULL;
+ return (-1) * ret;
+ } else {
+ /* success */
+ *strp = out.method.mem.buf;
+ return (ssize_t)out.printed;
+ }
+}
+
+API ssize_t
+lys_print_clb(ssize_t (*writeclb)(void *arg, const void *buf, size_t count), void *arg, const struct lys_module *module,
+ LYS_OUTFORMAT format, int line_length, int options)
+{
+ LY_ERR ret;
+ struct lyout out;
+
+ LY_CHECK_ARG_RET(NULL, writeclb, module, LY_EINVAL);
+
+ memset(&out, 0, sizeof out);
+ out.ctx = module->ctx;
+ out.type = LYOUT_CALLBACK;
+ out.method.clb.f = writeclb;
+ out.method.clb.arg = arg;
+
+ ret = lys_print_(&out, module, format, line_length, options);
+ if (ret) {
+ /* error */
+ return (-1) * ret;
+ } else {
+ /* success */
+ return (ssize_t)out.printed;
+ }
+}
diff --git a/src/printer_schema.h b/src/printer_schema.h
index 7ad6154..613e768 100644
--- a/src/printer_schema.h
+++ b/src/printer_schema.h
@@ -15,8 +15,11 @@
#ifndef LY_PRINTER_SCHEMA_H_
#define LY_PRINTER_SCHEMA_H_
+#include <stdio.h>
#include <unistd.h>
+#include "tree_schema.h"
+
/**
* @brief Print schema tree in the specified format into a memory block.
* It is up to caller to free the returned string by free().
diff --git a/src/printer_xml.c b/src/printer_xml.c
new file mode 100644
index 0000000..37ebc0d
--- /dev/null
+++ b/src/printer_xml.c
@@ -0,0 +1,560 @@
+/**
+ * @file printer_xml.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief XML printer for libyang data structure
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "plugins_types.h"
+#include "printer_data.h"
+#include "printer_internal.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+#include "xml.h"
+
+/**
+ * @brief XML printer context.
+ */
+struct xmlpr_ctx {
+ struct lyout *out; /**< output specification */
+ unsigned int level; /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
+ int options; /**< [Data printer flags](@ref dataprinterflags) */
+ int toplevel; /**< top-level flag */
+};
+
+#define LEVEL ctx->level /**< current level */
+#define INDENT ((LEVEL) ? (LEVEL)*2 : 0),"" /**< indentation parameters for printer functions */
+#define LEVEL_INC if (LEVEL) {LEVEL++;} /**< increase indentation level */
+#define LEVEL_DEC if (LEVEL) {LEVEL--;} /**< decrease indentation level */
+
+/**
+ * TODO
+ */
+struct mlist {
+ struct mlist *next;
+ struct lys_module *module;
+} *mlist = NULL, *mlist_new;
+
+#if 0
+static LY_ERR
+modlist_add(struct mlist **mlist, const struct lys_module *mod)
+{
+ struct mlist *iter;
+
+ for (iter = *mlist; iter; iter = iter->next) {
+ if (mod == iter->module) {
+ break;
+ }
+ }
+
+ if (!iter) {
+ iter = malloc(sizeof *iter);
+ LY_CHECK_ERR_RET(!iter, LOGMEM(mod->ctx), LY_EMEM);
+ iter->next = *mlist;
+ iter->module = (struct lys_module *)mod;
+ *mlist = iter;
+ }
+
+ return LY_SUCCESS;
+}
+#endif
+
+/**
+ * TODO
+ */
+static void
+xml_print_ns(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+ struct lyd_node *next, *cur, *child;
+ struct lyd_attr *attr;
+ struct mlist *mlist = NULL, *miter;
+ int r = 0;
+
+#if 0
+ const struct lys_module *wdmod = NULL;
+
+ /* add node attribute modules */
+ for (attr = node->attr; attr; attr = attr->next) {
+ if (!strcmp(node->schema->name, "filter") &&
+ (!strcmp(node->schema->module->name, "ietf-netconf") ||
+ !strcmp(node->schema->module->name, "notifications"))) {
+ /* exception for NETCONF's filter attributes */
+ continue;
+ } else {
+ r = modlist_add(&mlist, lys_main_module(attr->annotation->module));
+ }
+ if (r) {
+ goto print;
+ }
+ }
+#endif
+
+ /* add node children nodes and attribute modules */
+ switch (node->schema->nodetype) {
+ case LYS_LEAFLIST:
+ case LYS_LEAF:
+ /* TODO ietf-netconf-with-defaults namespace */
+#if 0
+ if (node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) {
+ /* get with-defaults module and print its namespace */
+ wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+ if (wdmod && modlist_add(&mlist, wdmod)) {
+ goto print;
+ }
+ }
+#endif
+ break;
+ case LYS_CONTAINER:
+ case LYS_LIST:
+#if 0
+ case LYS_RPC:
+ case LYS_ACTION:
+ case LYS_NOTIF:
+ if (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG)) {
+ /* get with-defaults module and print its namespace */
+ wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+ if (wdmod && modlist_add(&mlist, wdmod)) {
+ goto print;
+ }
+ }
+#endif
+ LY_LIST_FOR(((struct lyd_node_inner*)node)->child, child) {
+ LYD_TREE_DFS_BEGIN(child, next, cur) {
+ for (attr = cur->attr; attr; attr = attr->next) {
+ if (!strcmp(cur->schema->name, "filter") &&
+ (!strcmp(cur->schema->module->name, "ietf-netconf") ||
+ !strcmp(cur->schema->module->name, "notifications"))) {
+ /* exception for NETCONF's filter attributes */
+ continue;
+ } else {
+ /* TODO annotations r = modlist_add(&mlist, lys_main_module(attr->annotation->module)); */
+ }
+ if (r) {
+ goto print;
+ }
+ }
+ LYD_TREE_DFS_END(child, next, cur)}
+ }
+ break;
+ default:
+ break;
+ }
+
+print:
+ /* print used namespaces */
+ while (mlist) {
+ miter = mlist;
+ mlist = mlist->next;
+
+ ly_print(ctx->out, " xmlns:%s=\"%s\"", miter->module->prefix, miter->module->ns);
+ free(miter);
+ }
+}
+
+/**
+ * TODO
+ */
+static LY_ERR
+xml_print_attrs(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+ (void) ctx;
+ (void) node;
+
+#if 0
+ struct lyd_attr *attr;
+ const char **prefs, **nss;
+ const char *xml_expr = NULL, *mod_name;
+ uint32_t ns_count, i;
+ int rpc_filter = 0;
+ const struct lys_module *wdmod = NULL;
+ char *p;
+ size_t len;
+
+ LY_PRINT_SET;
+
+ /* with-defaults */
+ if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+ if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
+ (!node->dflt && (options & LYP_WD_ALL_TAG) && lyd_wd_default((struct lyd_node_leaf_list *)node))) {
+ /* we have implicit OR explicit default node */
+ /* get with-defaults module */
+ wdmod = ly_ctx_get_module(node->schema->module->ctx, "ietf-netconf-with-defaults", NULL, 1);
+ if (wdmod) {
+ /* print attribute only if context include with-defaults schema */
+ ly_print(out, " %s:default=\"true\"", wdmod->prefix);
+ }
+ }
+ }
+ /* technically, check for the extension get-filter-element-attributes from ietf-netconf */
+ if (!strcmp(node->schema->name, "filter")
+ && (!strcmp(node->schema->module->name, "ietf-netconf") || !strcmp(node->schema->module->name, "notifications"))) {
+ rpc_filter = 1;
+ }
+
+ for (attr = node->attr; attr; attr = attr->next) {
+ if (rpc_filter) {
+ /* exception for NETCONF's filter's attributes */
+ if (!strcmp(attr->name, "select")) {
+ /* xpath content, we have to convert the JSON format into XML first */
+ xml_expr = transform_json2xml(node->schema->module, attr->value_str, 0, &prefs, &nss, &ns_count);
+ if (!xml_expr) {
+ /* error */
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < ns_count; ++i) {
+ ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
+ }
+ free(prefs);
+ free(nss);
+ }
+ ly_print(out, " %s=\"", attr->name);
+ } else {
+ ly_print(out, " %s:%s=\"", attr->annotation->module->prefix, attr->name);
+ }
+
+ switch (attr->value_type) {
+ case LY_TYPE_BINARY:
+ case LY_TYPE_STRING:
+ case LY_TYPE_BITS:
+ case LY_TYPE_ENUM:
+ case LY_TYPE_BOOL:
+ case LY_TYPE_DEC64:
+ case LY_TYPE_INT8:
+ case LY_TYPE_INT16:
+ case LY_TYPE_INT32:
+ case LY_TYPE_INT64:
+ case LY_TYPE_UINT8:
+ case LY_TYPE_UINT16:
+ case LY_TYPE_UINT32:
+ case LY_TYPE_UINT64:
+ if (attr->value_str) {
+ /* xml_expr can contain transformed xpath */
+ lyxml_dump_text(out, xml_expr ? xml_expr : attr->value_str, LYXML_DATA_ATTR);
+ }
+ break;
+
+ case LY_TYPE_IDENT:
+ if (!attr->value_str) {
+ break;
+ }
+ p = strchr(attr->value_str, ':');
+ assert(p);
+ len = p - attr->value_str;
+ mod_name = attr->annotation->module->name;
+ if (!strncmp(attr->value_str, mod_name, len) && !mod_name[len]) {
+ lyxml_dump_text(out, ++p, LYXML_DATA_ATTR);
+ } else {
+ /* avoid code duplication - use instance-identifier printer which gets necessary namespaces to print */
+ goto printinst;
+ }
+ break;
+ case LY_TYPE_INST:
+printinst:
+ xml_expr = transform_json2xml(node->schema->module, ((struct lyd_node_leaf_list *)node)->value_str, 1,
+ &prefs, &nss, &ns_count);
+ if (!xml_expr) {
+ /* error */
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < ns_count; ++i) {
+ ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
+ }
+ free(prefs);
+ free(nss);
+
+ lyxml_dump_text(out, xml_expr, LYXML_DATA_ATTR);
+ lydict_remove(node->schema->module->ctx, xml_expr);
+ break;
+
+ /* LY_TYPE_LEAFREF not allowed */
+ case LY_TYPE_EMPTY:
+ break;
+
+ default:
+ /* error */
+ LOGINT(node->schema->module->ctx);
+ return EXIT_FAILURE;
+ }
+
+ ly_print(out, "\"");
+
+ if (xml_expr) {
+ lydict_remove(node->schema->module->ctx, xml_expr);
+ }
+ }
+#endif
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print generic XML element despite of the data node type.
+ *
+ * Prints the element name, attributes and necessary namespaces.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_node_open(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+ if (ctx->toplevel || !node->parent || node->schema->module != node->parent->schema->module) {
+ /* print "namespace" */
+ ly_print(ctx->out, "%*s<%s xmlns=\"%s\"", INDENT, node->schema->name, node->schema->module->ns);
+ } else {
+ ly_print(ctx->out, "%*s<%s", INDENT, node->schema->name);
+ }
+
+ if (ctx->toplevel) {
+ xml_print_ns(ctx, node);
+ ctx->toplevel = 0;
+ }
+
+ LY_CHECK_RET(xml_print_attrs(ctx, node));
+
+ return LY_SUCCESS;
+}
+
+static LY_ERR xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node);
+
+/**
+ * @brief Print XML element representing lyd_node_term.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_term(struct xmlpr_ctx *ctx, const struct lyd_node_term *node)
+{
+ LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+
+ if (((struct lysc_node_leaf*)node->schema)->type->plugin->flags & LY_TYPE_FLAG_PREFIXES) {
+ /* TODO get prefixes from the value and print namespaces */
+ }
+
+ if (!node->value.canonized || !node->value.canonized[0]) {
+ ly_print(ctx->out, "/>%s", LEVEL ? "\n" : "");
+ } else {
+ ly_print(ctx->out, ">");
+ lyxml_dump_text(ctx->out, node->value.canonized, 0);
+ ly_print(ctx->out, "</%s>%s", node->schema->name, LEVEL ? "\n" : "");
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Print XML element representing lyd_node_inner.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_inner(struct xmlpr_ctx *ctx, const struct lyd_node_inner *node)
+{
+ LY_ERR ret;
+ struct lyd_node *child;
+
+ LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+
+ if (!node->child) {
+ ly_print(ctx->out, "/>%s", ctx->level ? "\n" : "");
+ return LY_SUCCESS;
+ }
+
+ /* children */
+ ly_print(ctx->out, ">%s", ctx->level ? "\n" : "");
+
+ LEVEL_INC;
+ LY_LIST_FOR(node->child, child) {
+ ret = xml_print_node(ctx, child);
+ LY_CHECK_ERR_RET(ret, LEVEL_DEC, ret);
+ }
+ LEVEL_DEC;
+
+ ly_print(ctx->out, "%*s</%s>%s", INDENT, node->schema->name, LEVEL ? "\n" : "");
+
+ return LY_SUCCESS;
+}
+
+#if 0
+static int
+xml_print_anydata(struct lyout *out, int level, const struct lyd_node *node, int toplevel, int options)
+{
+ char *buf;
+ struct lyd_node_anydata *any = (struct lyd_node_anydata *)node;
+ struct lyd_node *iter;
+ const char *ns;
+
+ LY_PRINT_SET;
+
+ if (toplevel || !node->parent || nscmp(node, node->parent)) {
+ /* print "namespace" */
+ ns = lyd_node_module(node)->ns;
+ ly_print(out, "%*s<%s xmlns=\"%s\"", INDENT, node->schema->name, ns);
+ } else {
+ ly_print(out, "%*s<%s", INDENT, node->schema->name);
+ }
+
+ if (toplevel) {
+ xml_print_ns(out, node, options);
+ }
+ if (xml_print_attrs(out, node, options)) {
+ return EXIT_FAILURE;
+ }
+ if (!(void*)any->value.tree || (any->value_type == LYD_ANYDATA_CONSTSTRING && !any->value.str[0])) {
+ /* no content */
+ ly_print(out, "/>%s", level ? "\n" : "");
+ } else {
+ if (any->value_type == LYD_ANYDATA_DATATREE) {
+ /* print namespaces in the anydata data tree */
+ LY_TREE_FOR(any->value.tree, iter) {
+ xml_print_ns(out, iter, options);
+ }
+ }
+ /* close opening tag ... */
+ ly_print(out, ">");
+ /* ... and print anydata content */
+ switch (any->value_type) {
+ case LYD_ANYDATA_CONSTSTRING:
+ lyxml_dump_text(out, any->value.str, LYXML_DATA_ELEM);
+ break;
+ case LYD_ANYDATA_DATATREE:
+ if (any->value.tree) {
+ if (level) {
+ ly_print(out, "\n");
+ }
+ LY_TREE_FOR(any->value.tree, iter) {
+ if (xml_print_node(out, level ? level + 1 : 0, iter, 0, (options & ~(LYP_WITHSIBLINGS | LYP_NETCONF)))) {
+ return EXIT_FAILURE;
+ }
+ }
+ }
+ break;
+ case LYD_ANYDATA_XML:
+ lyxml_print_mem(&buf, any->value.xml, (level ? LYXML_PRINT_FORMAT | LYXML_PRINT_NO_LAST_NEWLINE : 0)
+ | LYXML_PRINT_SIBLINGS);
+ ly_print(out, "%s%s", level ? "\n" : "", buf);
+ free(buf);
+ break;
+ case LYD_ANYDATA_SXML:
+ /* print without escaping special characters */
+ ly_print(out, "%s", any->value.str);
+ break;
+ case LYD_ANYDATA_JSON:
+ case LYD_ANYDATA_LYB:
+ /* JSON and LYB format is not supported */
+ LOGWRN(node->schema->module->ctx, "Unable to print anydata content (type %d) as XML.", any->value_type);
+ break;
+ case LYD_ANYDATA_STRING:
+ case LYD_ANYDATA_SXMLD:
+ case LYD_ANYDATA_JSOND:
+ case LYD_ANYDATA_LYBD:
+ /* dynamic strings are used only as input parameters */
+ assert(0);
+ break;
+ }
+
+ /* closing tag */
+ ly_print(out, "</%s>%s", node->schema->name, level ? "\n" : "");
+ }
+
+ LY_PRINT_RET(node->schema->module->ctx);
+}
+#endif
+
+/**
+ * @brief Print XML element representing lyd_node.
+ *
+ * @param[in] ctx XML printer context.
+ * @param[in] node Data node to be printed.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node)
+{
+ LY_ERR ret = LY_SUCCESS;
+
+#if 0
+ if (!lyd_wd_toprint(node, ctx->options)) {
+ /* wd says do not print */
+ return EXIT_SUCCESS;
+ }
+#endif
+
+ switch (node->schema->nodetype) {
+#if 0
+ case LYS_NOTIF:
+ case LYS_ACTION:
+#endif
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ ret = xml_print_inner(ctx, (const struct lyd_node_inner*)node);
+ break;
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ ret = xml_print_term(ctx, (const struct lyd_node_term*)node);
+ break;
+#if 0
+ case LYS_ANYXML:
+ case LYS_ANYDATA:
+ ret = xml_print_anydata(ctx, node);
+ break;
+#endif
+ default:
+ LOGINT(node->schema->module->ctx);
+ ret = LY_EINT;
+ break;
+ }
+
+ return ret;
+}
+
+LY_ERR
+xml_print_data(struct lyout *out, const struct lyd_node *root, int options)
+{
+ const struct lyd_node *node;
+ struct xmlpr_ctx ctx_ = {.out = out, .level = (options & LYDP_FORMAT ? 1 : 0), .options = options, .toplevel = 1}, *ctx = &ctx_;
+
+ if (!root) {
+ if (out->type == LYOUT_MEMORY || out->type == LYOUT_CALLBACK) {
+ ly_print(out, "");
+ }
+ goto finish;
+ }
+
+ /* content */
+ LY_LIST_FOR(root, node) {
+ if (xml_print_node(ctx, node)) {
+ return EXIT_FAILURE;
+ }
+ if (!(options & LYDP_WITHSIBLINGS)) {
+ break;
+ }
+ }
+
+finish:
+ ly_print_flush(out);
+ return LY_SUCCESS;
+}
+
diff --git a/src/printer_yang.c b/src/printer_yang.c
index 2dfd5e6..c429094 100755
--- a/src/printer_yang.c
+++ b/src/printer_yang.c
@@ -15,27 +15,52 @@
#include "common.h"
#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "extensions.h"
+#include "log.h"
#include "printer_internal.h"
+#include "tree.h"
#include "tree_schema.h"
#include "tree_schema_internal.h"
#include "xpath.h"
-#define LEVEL ctx->level
-#define INDENT (LEVEL)*2,""
-
+/**
+ * @brief Types of the YANG printers
+ */
enum schema_type {
- YPR_PARSED,
- YPR_COMPILED
+ YPR_PARSED, /**< YANG printer of the parsed schema */
+ YPR_COMPILED /**< YANG printer of the compiled schema */
};
+/**
+ * @brief YANG printer context.
+ */
struct ypr_ctx {
- struct lyout *out;
- unsigned int level;
- const struct lys_module *module;
- enum schema_type schema;
+ struct lyout *out; /**< output specification */
+ unsigned int level; /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
+ const struct lys_module *module; /**< schema to print */
+ enum schema_type schema; /**< type of the schema to print */
};
+#define LEVEL ctx->level /**< current level */
+#define INDENT (LEVEL)*2,"" /**< indentation parameters for printer functions */
+
+/**
+ * @brief Print the given text as content of a double quoted YANG string,
+ * including encoding characters that have special meanings. The quotation marks
+ * are not printed.
+ *
+ * Follows RFC 7950, section 6.1.3.
+ *
+ * @param[in] out Output specification.
+ * @param[in] text String to be printed.
+ * @param[in] len Length of the string from @p text to be printed. In case of 0,
+ * the @p text is printed completely as a NULL-terminated string.
+ */
static void
ypr_encode(struct lyout *out, const char *text, int len)
{
diff --git a/src/set.c b/src/set.c
index 9769145..b858491 100644
--- a/src/set.c
+++ b/src/set.c
@@ -12,9 +12,14 @@
* https://opensource.org/licenses/BSD-3-Clause
*/
-#include "libyang.h"
#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "set.h"
+
API struct ly_set *
ly_set_new(void)
{
diff --git a/src/set.h b/src/set.h
index f16feae..9f73064 100644
--- a/src/set.h
+++ b/src/set.h
@@ -15,6 +15,8 @@
#ifndef LY_SET_H_
#define LY_SET_H_
+#include "log.h"
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/tree.h b/src/tree.h
new file mode 100644
index 0000000..d700a5b
--- /dev/null
+++ b/src/tree.h
@@ -0,0 +1,158 @@
+/**
+ * @file tree.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang geenric macros and functions to work with YANG schema or data trees.
+ *
+ * Copyright (c) 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_TREE_H_
+#define LY_TREE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Macro selector for other LY_ARRAY_* macros, do not use directly!
+ */
+#define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME
+
+/**
+ * @brief Helper macro to go through sized-arrays with a pointer iterator.
+ *
+ * Use with opening curly bracket (`{`).
+ *
+ * @param[in] ARRAY Array to go through
+ * @param[in] TYPE Type of the records in the ARRAY
+ * @param[out] ITER Iterating pointer to the item being processed in each loop
+ */
+#define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \
+ for (ITER = ARRAY; \
+ (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((uint32_t*)(ARRAY) - 1)); \
+ ITER = (void*)((TYPE*)ITER + 1))
+
+/**
+ * @brief Helper macro to go through sized-arrays with a numeric iterator.
+ *
+ * Use with opening curly bracket (`{`).
+ *
+ * To access an item with the INDEX value, use always LY_ARRAY_INDEX macro!
+ *
+ * @param[in] ARRAY Array to go through
+ * @param[out] INDEX Iterating index of the item being processed in each loop
+ */
+#define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \
+ for (INDEX = 0; \
+ ARRAY && INDEX < (*((uint32_t*)(ARRAY) - 1)); \
+ ++INDEX)
+
+/**
+ * @defgroup schematree Schema Tree
+ * @{
+ *
+ * Data structures and functions to manipulate and access schema tree.
+ */
+
+/**
+ * @brief Get a number of records in the ARRAY.
+ *
+ * Does not check if array exists!
+ */
+#define LY_ARRAY_SIZE(ARRAY) (*((uint32_t*)(ARRAY) - 1))
+
+/**
+ * @brief Sized-array iterator (for-loop).
+ *
+ * Use with opening curly bracket (`{`).
+ *
+ * There are 2 variants:
+ *
+ * LY_ARRAY_FOR(ARRAY, TYPE, ITER)
+ *
+ * Where ARRAY is a sized-array to go through, TYPE is the type of the items in the ARRAY and ITER is a pointer variable
+ * providing the items of the ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_ITER macro
+ *
+ * LY_ARRAY_FOR(ARRAY, INDEX)
+ *
+ * The ARRAY is again a sized-array to go through, the INDEX is a variable (unsigned integer) for storing iterating ARRAY's index
+ * to access the items of ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_INDEX macro.
+ */
+#define LY_ARRAY_FOR(ARRAY, ...) LY_ARRAY_SELECT(__VA_ARGS__, LY_ARRAY_FOR_ITER, LY_ARRAY_FOR_INDEX)(ARRAY, __VA_ARGS__)
+
+/**
+ * @brief Macro to iterate via all sibling elements without affecting the list itself
+ *
+ * Works for all types of nodes despite it is data or schema tree, but all the
+ * parameters must be pointers to the same type.
+ *
+ * Use with opening curly bracket (`{`). All parameters must be of the same type.
+ *
+ * @param START Pointer to the starting element.
+ * @param ELEM Iterator.
+ */
+#define LY_LIST_FOR(START, ELEM) \
+ for ((ELEM) = (START); \
+ (ELEM); \
+ (ELEM) = (ELEM)->next)
+
+/**
+ * @brief Macro to iterate via all sibling elements allowing to modify the list itself (e.g. removing elements)
+ *
+ * Use with opening curly bracket (`{`). All parameters must be of the same type.
+ *
+ * @param START Pointer to the starting element.
+ * @param NEXT Temporary storage to allow removing of the current iterator content.
+ * @param ELEM Iterator.
+ */
+#define LY_LIST_FOR_SAFE(START, NEXT, ELEM) \
+ for ((ELEM) = (START); \
+ (ELEM) ? (NEXT = (ELEM)->next, 1) : 0; \
+ (ELEM) = (NEXT))
+
+/**
+ * @brief YANG built-in types
+ */
+typedef enum
+{
+ LY_TYPE_UNKNOWN = 0, /**< Unknown type */
+ LY_TYPE_BINARY, /**< Any binary data ([RFC 6020 sec 9.8](http://tools.ietf.org/html/rfc6020#section-9.8)) */
+ LY_TYPE_UINT8, /**< 8-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+ LY_TYPE_UINT16, /**< 16-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+ LY_TYPE_UINT32, /**< 32-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+ LY_TYPE_UINT64, /**< 64-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+ LY_TYPE_STRING, /**< Human-readable string ([RFC 6020 sec 9.4](http://tools.ietf.org/html/rfc6020#section-9.4)) */
+ LY_TYPE_BITS, /**< A set of bits or flags ([RFC 6020 sec 9.7](http://tools.ietf.org/html/rfc6020#section-9.7)) */
+ LY_TYPE_BOOL, /**< "true" or "false" ([RFC 6020 sec 9.5](http://tools.ietf.org/html/rfc6020#section-9.5)) */
+ LY_TYPE_DEC64, /**< 64-bit signed decimal number ([RFC 6020 sec 9.3](http://tools.ietf.org/html/rfc6020#section-9.3))*/
+ LY_TYPE_EMPTY, /**< A leaf that does not have any value ([RFC 6020 sec 9.11](http://tools.ietf.org/html/rfc6020#section-9.11)) */
+ LY_TYPE_ENUM, /**< Enumerated strings ([RFC 6020 sec 9.6](http://tools.ietf.org/html/rfc6020#section-9.6)) */
+ LY_TYPE_IDENT, /**< A reference to an abstract identity ([RFC 6020 sec 9.10](http://tools.ietf.org/html/rfc6020#section-9.10)) */
+ LY_TYPE_INST, /**< References a data tree node ([RFC 6020 sec 9.13](http://tools.ietf.org/html/rfc6020#section-9.13)) */
+ LY_TYPE_LEAFREF, /**< A reference to a leaf instance ([RFC 6020 sec 9.9](http://tools.ietf.org/html/rfc6020#section-9.9))*/
+ LY_TYPE_UNION, /**< Choice of member types ([RFC 6020 sec 9.12](http://tools.ietf.org/html/rfc6020#section-9.12)) */
+ LY_TYPE_INT8, /**< 8-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+ LY_TYPE_INT16, /**< 16-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+ LY_TYPE_INT32, /**< 32-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+ LY_TYPE_INT64, /**< 64-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
+} LY_DATA_TYPE;
+#define LY_DATA_TYPE_COUNT 20 /**< Number of different types */
+
+/**
+ * @brief Stringified YANG built-in data types
+ */
+extern const char* ly_data_type2str[LY_DATA_TYPE_COUNT];
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LY_TREE_H_ */
diff --git a/src/tree_data.c b/src/tree_data.c
new file mode 100644
index 0000000..7ecb5e9
--- /dev/null
+++ b/src/tree_data.c
@@ -0,0 +1,257 @@
+/**
+ * @file tree_schema.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Schema tree implementation
+ *
+ * Copyright (c) 2015 - 2018 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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_data_internal.h"
+#include "tree_schema.h"
+
+static int
+cmp_str(const char *refstr, const char *str, size_t strlen)
+{
+
+ if (strlen) {
+ int r = strncmp(refstr, str, strlen);
+ if (!r && !refstr[strlen]) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ return strcmp(refstr, str);
+ }
+}
+
+API const struct lyd_node *
+lyd_search(const struct lyd_node *first, const struct lys_module *module,
+ const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len)
+{
+ const struct lyd_node *node = NULL;
+ const struct lysc_node *snode;
+
+ LY_CHECK_ARG_RET(NULL, module, name, NULL);
+ if (!nodetype) {
+ nodetype = 0xffff;
+ }
+
+ LY_LIST_FOR(first, node) {
+ snode = node->schema;
+ if (!(snode->nodetype & nodetype)) {
+ continue;
+ }
+ if (snode->module != module) {
+ continue;
+ }
+
+ if (cmp_str(snode->name, name, name_len)) {
+ continue;
+ }
+
+ if (value) {
+ if (snode->nodetype == LYS_LIST) {
+ /* TODO handle value as keys of the list instance */
+ } else if (snode->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
+ if (cmp_str(((struct lyd_node_term*)node)->value.canonized, value, value_len)) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+ }
+
+ /* all criteria passed */
+ return node;
+ }
+ return NULL;
+}
+
+static struct lyd_node *
+lyd_parse_mem_(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, va_list ap)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct lyd_node *result = NULL;
+ const struct lyd_node *rpc_act = NULL, *data_tree = NULL, *iter;
+ const char *yang_data_name = NULL;
+
+ if (lyd_parse_check_options(ctx, options, __func__)) {
+ return NULL;
+ }
+
+ if (options & LYD_OPT_RPCREPLY) {
+ rpc_act = va_arg(ap, const struct lyd_node *);
+ if (!rpc_act || rpc_act->parent || !(rpc_act->schema->nodetype & (LYS_ACTION | LYS_LIST | LYS_CONTAINER))) {
+ LOGERR(ctx, LY_EINVAL, "Data parser invalid variable parameter (const struct lyd_node *rpc_act).");
+ return NULL;
+ }
+ }
+ if (options & (LYD_OPT_RPC | LYD_OPT_NOTIF | LYD_OPT_RPCREPLY)) {
+ data_tree = va_arg(ap, const struct lyd_node *);
+ if (data_tree) {
+ if (options & LYD_OPT_NOEXTDEPS) {
+ LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree and LYD_OPT_NOEXTDEPS set).",
+ __func__);
+ return NULL;
+ }
+
+ LY_LIST_FOR(data_tree, iter) {
+ if (iter->parent) {
+ /* a sibling is not top-level */
+ LOGERR(ctx, LY_EINVAL, "%s: invalid variable parameter (const struct lyd_node *data_tree).", __func__);
+ return NULL;
+ }
+ }
+
+ /* move it to the beginning */
+ for (; data_tree->prev->next; data_tree = data_tree->prev);
+
+ /* LYD_OPT_NOSIBLINGS cannot be set in this case */
+ if (options & LYD_OPT_NOSIBLINGS) {
+ LOGERR(ctx, LY_EINVAL, "%s: invalid parameter (variable arg const struct lyd_node *data_tree with LYD_OPT_NOSIBLINGS).", __func__);
+ return NULL;
+ }
+ }
+ }
+ if (options & LYD_OPT_DATA_TEMPLATE) {
+ yang_data_name = va_arg(ap, const char *);
+ }
+
+ if (!format) {
+ /* TODO try to detect format from the content */
+ }
+
+ switch (format) {
+ case LYD_XML:
+ ret = lyd_parse_xml(ctx, data, options, &result);
+ break;
+#if 0
+ case LYD_JSON:
+ ret = lyd_parse_json(ctx, data, options, rpc_act, data_tree, yang_data_name);
+ break;
+ case LYD_LYB:
+ ret = lyd_parse_lyb(ctx, data, options, data_tree, yang_data_name, NULL);
+ break;
+#endif
+ case LYD_UNKNOWN:
+ LOGINT(ctx);
+ break;
+ }
+
+ if (ret) {
+ lyd_free_all(result);
+ result = NULL;
+ }
+
+ return result;
+}
+
+API struct lyd_node *
+lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...)
+{
+ va_list ap;
+ struct lyd_node *result;
+
+ va_start(ap, options);
+ result = lyd_parse_mem_(ctx, data, format, options, ap);
+ va_end(ap);
+
+ return result;
+}
+
+static struct lyd_node *
+lyd_parse_fd_(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, va_list ap)
+{
+ struct lyd_node *result;
+ size_t length;
+ char *addr;
+
+ LY_CHECK_ARG_RET(ctx, ctx, NULL);
+ if (fd < 0) {
+ LOGARG(ctx, fd);
+ return NULL;
+ }
+
+ LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
+ result = lyd_parse_mem_(ctx, addr ? addr : "", format, options, ap);
+ ly_munmap(addr, length);
+
+ return result;
+}
+
+API struct lyd_node *
+lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...)
+{
+ struct lyd_node *ret;
+ va_list ap;
+
+ va_start(ap, options);
+ ret = lyd_parse_fd_(ctx, fd, format, options, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+API struct lyd_node *
+lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...)
+{
+ int fd;
+ struct lyd_node *result;
+ size_t len;
+ va_list ap;
+
+ LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
+
+ fd = open(path, O_RDONLY);
+ LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
+
+ if (!format) {
+ /* unknown format - try to detect it from filename's suffix */
+ len = strlen(path);
+
+ /* ignore trailing whitespaces */
+ for (; len > 0 && isspace(path[len - 1]); len--);
+
+ if (len >= 5 && !strncmp(&path[len - 4], ".xml", 4)) {
+ format = LYD_XML;
+#if 0
+ } else if (len >= 6 && !strncmp(&path[len - 5], ".json", 5)) {
+ format = LYD_JSON;
+ } else if (len >= 5 && !strncmp(&path[len - 4], ".lyb", 4)) {
+ format = LYD_LYB;
+#endif
+ } /* else still unknown, try later to detect it from the content */
+ }
+
+ va_start(ap, options);
+ result = lyd_parse_fd_(ctx, fd, format, options, ap);
+
+ va_end(ap);
+ close(fd);
+
+ return result;
+}
+
+
+
+
diff --git a/src/tree_data.h b/src/tree_data.h
new file mode 100644
index 0000000..9fe0af6
--- /dev/null
+++ b/src/tree_data.h
@@ -0,0 +1,571 @@
+/**
+ * @file tree_data.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief libyang representation of YANG data trees.
+ *
+ * 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_TREE_DATA_H_
+#define LY_TREE_DATA_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "log.h"
+#include "tree.h"
+#include "tree_schema.h"
+
+struct ly_ctx;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup datatree Data Tree
+ * @{
+ *
+ * Data structures and functions to manipulate and access instance data tree.
+ */
+
+/**
+ * @brief Macro to iterate via all elements in a data tree. This is the opening part
+ * to the #LYD_TREE_DFS_END - they always have to be used together.
+ *
+ * The function follows deep-first search algorithm:
+ * <pre>
+ * 1
+ * / \
+ * 2 4
+ * / / \
+ * 3 5 6
+ * </pre>
+ *
+ * Use the same parameters for #LY_TREE_DFS_BEGIN and #LY_TREE_DFS_END. While
+ * START can be any of the lyd_node* types, NEXT and ELEM variables are expected
+ * to be pointers to a generic struct lyd_node.
+ *
+ * Since the next node is selected as part of #LYD_TREE_DFS_END, do not use
+ * continue statement between the #LYD_TREE_DFS_BEGIN and #LYD_TREE_DFS_END.
+ *
+ * Use with opening curly bracket '{' after the macro.
+ *
+ * @param START Pointer to the starting element processed first.
+ * @param NEXT Temporary storage, do not use.
+ * @param ELEM Iterator intended for use in the block.
+ */
+#define LYD_TREE_DFS_BEGIN(START, NEXT, ELEM) \
+ for ((ELEM) = (NEXT) = (START); \
+ (ELEM); \
+ (ELEM) = (NEXT))
+
+/**
+ * @brief Macro to iterate via all elements in a tree. This is the closing part
+ * to the #LYD_TREE_DFS_BEGIN - they always have to be used together.
+ *
+ * Use the same parameters for #LYD_TREE_DFS_BEGIN and #LYD_TREE_DFS_END. While
+ * START can be any of the lyd_node* types, NEXT and ELEM variables are expected
+ * to be pointers to a generic struct lyd_node.
+ *
+ * Use with closing curly bracket '}' after the macro.
+ *
+ * @param START Pointer to the starting element processed first.
+ * @param NEXT Temporary storage, do not use.
+ * @param ELEM Iterator intended for use in the block.
+ */
+
+#define LYD_TREE_DFS_END(START, NEXT, ELEM) \
+ /* select element for the next run - children first */ \
+ (NEXT) = (struct lyd_node*)lyd_node_children((struct lyd_node*)ELEM); \
+ if (!(NEXT)) { \
+ /* no children */ \
+ if ((ELEM) == (struct lyd_node*)(START)) { \
+ /* we are done, (START) has no children */ \
+ break; \
+ } \
+ /* try siblings */ \
+ (NEXT) = (ELEM)->next; \
+ } \
+ while (!(NEXT)) { \
+ /* parent is already processed, go to its sibling */ \
+ (ELEM) = (struct lyd_node*)(ELEM)->parent; \
+ /* no siblings, go back through parents */ \
+ if ((ELEM)->parent == (START)->parent) { \
+ /* we are done, no next element to process */ \
+ break; \
+ } \
+ (NEXT) = (ELEM)->next; \
+ }
+
+/**
+ * @brief Data input/output formats supported by libyang [parser](@ref howtodataparsers) and
+ * [printer](@ref howtodataprinters) functions.
+ */
+typedef enum {
+ LYD_UNKNOWN = 0, /**< unknown format, used as return value in case of error */
+ LYD_XML, /**< XML format of the instance data */
+#if 0
+ LYD_JSON, /**< JSON format of the instance data */
+ LYD_LYB, /**< LYB format of the instance data */
+#endif
+} LYD_FORMAT;
+
+/**
+ * @brief List of possible value types stored in ::lyd_node_anydata.
+ */
+typedef enum {
+ LYD_ANYDATA_CONSTSTRING = 0x00, /**< value is constant string (const char *) which is internally duplicated for
+ storing in the anydata structure; XML sensitive characters (such as & or \>)
+ are automatically escaped when the anydata is printed in XML format. */
+ LYD_ANYDATA_STRING = 0x01, /**< value is dynamically allocated string (char*), so the data are used directly
+ without duplication and caller is supposed to not manipulate with the data
+ after a successful call (including calling free() on the provided data); XML
+ sensitive characters (such as & or \>) are automatically escaped when the
+ anydata is printed in XML format */
+ LYD_ANYDATA_JSON = 0x02, /**< value is string containing the data modeled by YANG and encoded as I-JSON. The
+ string is handled as constant string. In case of using the value as input
+ parameter, the #LYD_ANYDATA_JSOND can be used for dynamically allocated
+ string. */
+ LYD_ANYDATA_JSOND = 0x03, /**< In case of using value as input parameter, this enumeration is supposed to be
+ used for dynamically allocated strings (it is actually combination of
+ #LYD_ANYDATA_JSON and #LYD_ANYDATA_STRING (and it can be also specified as
+ ORed value of the mentioned values. */
+ LYD_ANYDATA_SXML = 0x04, /**< value is string containing the serialized XML data. The string is handled as
+ constant string. In case of using the value as input parameter, the
+ #LYD_ANYDATA_SXMLD can be used for dynamically allocated string. */
+ LYD_ANYDATA_SXMLD = 0x05, /**< In case of using serialized XML value as input parameter, this enumeration is
+ supposed to be used for dynamically allocated strings (it is actually
+ combination of #LYD_ANYDATA_SXML and #LYD_ANYDATA_STRING (and it can be also
+ specified as ORed value of the mentioned values). */
+ LYD_ANYDATA_XML = 0x08, /**< value is struct lyxml_elem*, the structure is directly connected into the
+ anydata node without duplication, caller is supposed to not manipulate with the
+ data after a successful call (including calling lyxml_free() on the provided
+ data) */
+ LYD_ANYDATA_DATATREE = 0x10, /**< value is struct lyd_node* (first sibling), the structure is directly connected
+ into the anydata node without duplication, caller is supposed to not manipulate
+ with the data after a successful call (including calling lyd_free() on the
+ provided data) */
+ LYD_ANYDATA_LYB = 0x20, /**< value is a memory with serialized data tree in LYB format. The data are handled
+ as a constant string. In case of using the value as input parameter,
+ the #LYD_ANYDATA_LYBD can be used for dynamically allocated string. */
+ LYD_ANYDATA_LYBD = 0x21, /**< In case of using LYB value as input parameter, this enumeration is
+ supposed to be used for dynamically allocated strings (it is actually
+ combination of #LYD_ANYDATA_LYB and #LYD_ANYDATA_STRING (and it can be also
+ specified as ORed value of the mentioned values). */
+} LYD_ANYDATA_VALUETYPE;
+
+/** @} */
+
+/**
+ * @brief YANG data representation
+ */
+struct lyd_value {
+ const char *canonized; /**< string representation of value (for comparison, printing,...), canonized according to the
+ rules implemented in the type's canonization callback (if any). */
+ union {
+ const char *string; /**< original, non-canonized string value. Useful for example for unions where the type (and therefore
+ the cannonization rules) can change by changing value (e.g. leafref target) somewhere else. */
+ int8_t boolean; /**< 0 as false, 1 as true */
+ int64_t dec64; /**< decimal64: value = dec64 / 10^fraction-digits */
+ struct lysc_type_bitenum_item *enum_item; /**< pointer to the definition of the enumeration value */
+ struct lysc_ident *ident; /**< pointer to the schema definition of the identityref value */
+ int8_t int8; /**< 8-bit signed integer */
+ int16_t int16; /**< 16-bit signed integer */
+ int32_t int32; /**< 32-bit signed integer */
+ int64_t int64; /**< 64-bit signed integer */
+ uint8_t uint8; /**< 8-bit unsigned integer */
+ uint16_t uint16; /**< 16-bit signed integer */
+ uint32_t uint32; /**< 32-bit signed integer */
+ uint64_t uint64; /**< 64-bit signed integer */
+ void *ptr; /**< generic data type structure used to store the data */
+ }; /**< The union is just a list of shorthands to possible values stored by a type's plugin. libyang works only with the canonized string,
+ this specific data type storage is just to simplify use of the values by the libyang users. */
+ LY_DATA_TYPE type; /**< type of the value in the node, mainly for union to avoid repeating of type detection */
+};
+
+/**
+ * @brief Attribute structure.
+ *
+ * The structure provides information about attributes of a data element. Such attributes must map to
+ * annotations as specified in RFC 7952. The only exception is the filter type (in NETCONF get operations)
+ * and edit-config's operation attributes. In XML, they are represented as standard XML attributes. In JSON,
+ * they are represented as JSON elements starting with the '@' character (for more information, see the
+ * YANG metadata RFC.
+ *
+ */
+struct lyd_attr {
+ struct lyd_node *parent; /**< data node where the attribute is placed */
+ struct lyd_attr *next; /**< pointer to the next attribute of the same element */
+ void *annotation; /**< TODO pointer to the attribute/annotation's definition */
+ const char *name; /**< attribute name */
+ struct lyd_value value; /**< attribute's value representation */
+};
+
+
+#define LYD_NODE_INNER (LYS_CONTAINER|LYS_LIST) /**< Schema nodetype mask for lyd_node_inner */
+#define LYD_NODE_TERM (LYS_LEAF|LYS_LEAFLIST) /**< Schema nodetype mask for lyd_node_term */
+#define LYD_NODE_ANY (LYS_ANYDATA) /**< Schema nodetype mask for lyd_node_any */
+
+/**
+ * @brief Generic structure for a data node.
+ */
+struct lyd_node {
+ uint32_t hash; /**< hash of this particular node (module name + schema name + key string values if list) */
+ const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+ struct lyd_node_inner *parent; /**< pointer to the parent node, NULL in case of root node */
+ struct lyd_node *next; /**< pointer to the next sibling node (NULL if there is no one) */
+ struct lyd_node *prev; /**< pointer to the previous sibling node \note Note that this pointer is
+ never NULL. If there is no sibling node, pointer points to the node
+ itself. In case of the first node, this pointer points to the last
+ node in the list. */
+ struct lyd_attr *attr; /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+ void *priv; /**< private user data, not used by libyang */
+#endif
+};
+
+/**
+ * @brief Data node structure for the inner data tree nodes - containers and lists.
+ */
+struct lyd_node_inner {
+ uint32_t hash; /**< hash of this particular node (module name + schema name + key string values if list) */
+ const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+ struct lyd_node_inner *parent; /**< pointer to the parent node, NULL in case of root node */
+ struct lyd_node *next; /**< pointer to the next sibling node (NULL if there is no one) */
+ struct lyd_node *prev; /**< pointer to the previous sibling node \note Note that this pointer is
+ never NULL. If there is no sibling node, pointer points to the node
+ itself. In case of the first node, this pointer points to the last
+ node in the list. */
+ struct lyd_attr *attr; /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+ void *priv; /**< private user data, not used by libyang */
+#endif
+
+ struct lyd_node *child; /**< pointer to the first child node. */
+ struct hash_table *children_ht; /**< hash table with all the direct children (except keys for a list, lists without keys) */
+};
+
+/**
+ * @brief Data node structure for the terminal data tree nodes - leafs and leaf-lists.
+ */
+struct lyd_node_term {
+ uint32_t hash; /**< hash of this particular node (module name + schema name + key string values if list) */
+ const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+ struct lyd_node_inner *parent; /**< pointer to the parent node, NULL in case of root node */
+ struct lyd_node *next; /**< pointer to the next sibling node (NULL if there is no one) */
+ struct lyd_node *prev; /**< pointer to the previous sibling node \note Note that this pointer is
+ never NULL. If there is no sibling node, pointer points to the node
+ itself. In case of the first node, this pointer points to the last
+ node in the list. */
+ struct lyd_attr *attr; /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+ void *priv; /**< private user data, not used by libyang */
+#endif
+
+ struct lyd_value value; /**< node's value representation */
+};
+
+/**
+ * @brief Data node structure for the anydata data tree nodes - anydatas and anyxmls.
+ */
+struct lyd_node_any {
+ uint32_t hash; /**< hash of this particular node (module name + schema name + key string values if list) */
+ const struct lysc_node *schema; /**< pointer to the schema definition of this node */
+ struct lyd_node_inner *parent; /**< pointer to the parent node, NULL in case of root node */
+ struct lyd_node *next; /**< pointer to the next sibling node (NULL if there is no one) */
+ struct lyd_node *prev; /**< pointer to the previous sibling node \note Note that this pointer is
+ never NULL. If there is no sibling node, pointer points to the node
+ itself. In case of the first node, this pointer points to the last
+ node in the list. */
+ struct lyd_attr *attr; /**< pointer to the list of attributes of this node */
+
+#ifdef LY_ENABLED_LYD_PRIV
+ void *priv; /**< private user data, not used by libyang */
+#endif
+
+ /* TODO - anydata representation */
+};
+
+/**
+ * @defgroup dataparseroptions Data parser options
+ * @ingroup datatree
+ *
+ * Various options to change the data tree parsers behavior.
+ *
+ * Default behavior:
+ * - in case of XML, parser reads all data from its input (file, memory, XML tree) including the case of not well-formed
+ * XML document (multiple top-level elements) and if there is an unknown element, it is skipped including its subtree
+ * (see the next point). This can be changed by the #LYD_OPT_NOSIBLINGS option which make parser to read only a single
+ * tree (with a single root element) from its input.
+ * - parser silently ignores the data without a matching node in schema trees. If the caller want to stop
+ * parsing in case of presence of unknown data, the #LYD_OPT_STRICT can be used. The strict mode is useful for
+ * NETCONF servers, since NETCONF clients should always send data according to the capabilities announced by the server.
+ * On the other hand, the default non-strict mode is useful for clients receiving data from NETCONF server since
+ * clients are not required to understand everything the server does. Of course, the optimal strategy for clients is
+ * to use filtering to get only the required data. Having an unknown element of the known namespace is always an error.
+ * The behavior can be changed by #LYD_OPT_STRICT option.
+ * - using obsolete statements (status set to obsolete) just generates a warning, but the processing continues. The
+ * behavior can be changed by #LYD_OPT_OBSOLETE option.
+ * - parser expects that the provided data provides complete datastore content (both the configuration and state data)
+ * and performs data validation according to all YANG rules. This can be a problem in case of representing NETCONF's
+ * subtree filter data, edit-config's data or other type of data set - such data do not represent a complete data set
+ * and some of the validation rules can fail. Therefore there are other options (within lower 8 bits) to make parser
+ * to accept such a data.
+ * - when parser evaluates when-stmt condition to false, a validation error is raised. If the
+ * #LYD_OPT_WHENAUTODEL is used, the invalid node is silently removed instead of an error. The option (and also this default
+ * behavior) takes effect only in case of #LYD_OPT_DATA or #LYD_OPT_CONFIG type of data.
+ * @{
+ */
+
+#define LYD_OPT_DATA 0x00 /**< Default type of data - complete datastore content with configuration as well as
+ state data. To handle possibly missing (but by default required) ietf-yang-library
+ data, use #LYD_OPT_DATA_NO_YANGLIB or #LYD_OPT_DATA_ADD_YANGLIB options. */
+#define LYD_OPT_CONFIG 0x01 /**< A configuration datastore - complete datastore without state data.
+ Validation modifications:
+ - status data are not allowed */
+#define LYD_OPT_GET 0x02 /**< Data content from a NETCONF reply message to the NETCONF \<get\> operation.
+ Validation modifications:
+ - mandatory nodes can be omitted
+ - leafrefs and instance-identifier resolution is allowed to fail
+ - list's keys/unique nodes are not required (so duplication is not checked)
+ - must and when evaluation skipped */
+#define LYD_OPT_GETCONFIG 0x04 /**< Data content from a NETCONF reply message to the NETCONF \<get-config\> operation
+ Validation modifications:
+ - mandatory nodes can be omitted
+ - leafrefs and instance-identifier resolution is allowed to fail
+ - list's keys/unique nodes are not required (so duplication is not checked)
+ - must and when evaluation skipped
+ - status data are not allowed */
+#define LYD_OPT_EDIT 0x08 /**< Content of the NETCONF \<edit-config\>'s config element.
+ Validation modifications:
+ - mandatory nodes can be omitted
+ - leafrefs and instance-identifier resolution is allowed to fail
+ - must and when evaluation skipped
+ - status data are not allowed */
+#define LYD_OPT_RPC 0x10 /**< Data represents RPC or action input parameters. */
+#define LYD_OPT_RPCREPLY 0x20 /**< Data represents RPC or action output parameters (maps to NETCONF <rpc-reply> data). */
+#define LYD_OPT_NOTIF 0x40 /**< Data represents an event notification data. */
+#define LYD_OPT_NOTIF_FILTER 0x80 /**< Data represents a filtered event notification data.
+ Validation modification:
+ - the only requirement is that the data tree matches the schema tree */
+#define LYD_OPT_TYPEMASK 0x10000ff /**< Mask to filter data type options. Always only a single data type option (only
+ single bit from the lower 8 bits) can be set. */
+
+/* 0x100 reserved, used internally */
+#define LYD_OPT_STRICT 0x0200 /**< Instead of silent ignoring data without schema definition, raise an error. */
+#define LYD_OPT_DESTRUCT 0x0400 /**< Free the provided XML tree during parsing the data. With this option, the
+ provided XML tree is affected and all successfully parsed data are freed.
+ This option is applicable only to lyd_parse_xml() function. */
+#define LYD_OPT_OBSOLETE 0x0800 /**< Raise an error when an obsolete statement (status set to obsolete) is used. */
+#define LYD_OPT_NOSIBLINGS 0x1000 /**< Parse only a single XML tree from the input. This option applies only to
+ XML input data. */
+#define LYD_OPT_TRUSTED 0x2000 /**< Data comes from a trusted source and it is not needed to validate them. Data
+ are connected with the schema, but the most validation checks (mandatory nodes,
+ list instance uniqueness, etc.) are not performed. This option does not make
+ sense for lyd_validate() so it is ignored by this function. */
+#define LYD_OPT_WHENAUTODEL 0x4000 /**< Automatically delete subtrees with false when-stmt condition. The flag is
+ applicable only in combination with #LYD_OPT_DATA and #LYD_OPT_CONFIG flags.
+ If used, libyang will not generate a validation error. */
+#define LYD_OPT_NOEXTDEPS 0x8000 /**< Allow external dependencies (external leafrefs, instance-identifiers, must,
+ and when) to not be resolved/satisfied during validation. */
+#define LYD_OPT_DATA_NO_YANGLIB 0x10000 /**< Ignore (possibly) missing ietf-yang-library data. Applicable only with #LYD_OPT_DATA. */
+#define LYD_OPT_DATA_ADD_YANGLIB 0x20000 /**< Add missing ietf-yang-library data into the validated data tree. Applicable
+ only with #LYD_OPT_DATA. If some ietf-yang-library data are present, they are
+ preserved and option is ignored. */
+#define LYD_OPT_VAL_DIFF 0x40000 /**< Flag only for validation, store all the data node changes performed by the validation
+ in a diff structure. */
+#define LYD_OPT_DATA_TEMPLATE 0x1000000 /**< Data represents YANG data template. */
+
+/**@} dataparseroptions */
+
+/**
+ * @brief Get the node's children list if any.
+ *
+ * Decides the node's type and in case it has a children list, returns it.
+ * @param[in] node Node to check.
+ * @return Pointer to the first child node (if any) of the \p node.
+ */
+const struct lyd_node *lyd_node_children(const struct lyd_node *node);
+
+/**
+ * @brief Find the node, in the list, satisfying the given restrictions.
+ *
+ * @param[in] first Starting child node for search.
+ * @param[in] module Module of the node to find (mandatory argument).
+ * @param[in] name Name of the node to find (mandatory argument).
+ * @param[in] name_len Optional length of the @p name argument in case it is not NULL-terminated string.
+ * @param[in] nodetype Optional mask for the nodetype of the node to find, 0 is understood as all nodetypes.
+ * @param[in] value Optional restriction for lyd_node_term nodes to select node with the specific value.
+ * @param[in] value_len Optional length of the @p value argument in case it is not NULL-terminated string.
+ * @return The sibling node of the @p first (or itself), satisfying the given restrictions.
+ * @return NULL in case there is no node satisfying the restrictions.
+ */
+const struct lyd_node *lyd_search(const struct lyd_node *first, const struct lys_module *module,
+ const char *name, size_t name_len, uint16_t nodetype, const char *value, size_t value_len);
+
+/**
+ * @brief Parse (and validate) data from memory.
+ *
+ * In case of LY_XML format, the data string is parsed completely. It means that when it contains
+ * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
+ * returned data node is a root of the first tree with other trees connected via the next pointer.
+ * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
+ *
+ * @param[in] ctx Context to connect with the data tree being built here.
+ * @param[in] data Serialized data in the specified format.
+ * @param[in] format Format of the input data to be parsed.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
+ * @param[in] ... Variable arguments depend on \p options. If they include:
+ * - #LYD_OPT_DATA:
+ * - #LYD_OPT_CONFIG:
+ * - #LYD_OPT_GET:
+ * - #LYD_OPT_GETCONFIG:
+ * - #LYD_OPT_EDIT:
+ * - no variable arguments expected.
+ * - #LYD_OPT_RPC:
+ * - #LYD_OPT_NOTIF:
+ * - struct lyd_node *data_tree - additional data tree that will be used
+ * when checking any "when" or "must" conditions in the parsed tree that require
+ * some nodes outside their subtree. It must be a list of top-level elements!
+ * - #LYD_OPT_RPCREPLY:
+ * - const struct ::lyd_node *rpc_act - pointer to the whole RPC or (top-level) action operation
+ * data tree (the request) of the reply.
+ * - const struct ::lyd_node *data_tree - additional data tree that will be used
+ * when checking any "when" or "must" conditions in the parsed tree that require
+ * some nodes outside their subtree. It must be a list of top-level elements!
+ * @return Pointer to the built data tree or NULL in case of empty \p data. To free the returned structure,
+ * use lyd_free(). In these cases, the function sets #ly_errno to LY_SUCCESS. In case of error,
+ * #ly_errno contains appropriate error code (see #LY_ERR).
+ */
+struct lyd_node *lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, ...);
+
+/**
+ * @brief Read (and validate) data from the given file descriptor.
+ *
+ * \note Current implementation supports only reading data from standard (disk) file, not from sockets, pipes, etc.
+ *
+ * In case of LY_XML format, the file content is parsed completely. It means that when it contains
+ * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
+ * returned data node is a root of the first tree with other trees connected via the next pointer.
+ * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
+ *
+ * @param[in] ctx Context to connect with the data tree being built here.
+ * @param[in] fd The standard file descriptor of the file containing the data tree in the specified format.
+ * @param[in] format Format of the input data to be parsed.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
+ * @param[in] ... Variable arguments depend on \p options. If they include:
+ * - #LYD_OPT_DATA:
+ * - #LYD_OPT_CONFIG:
+ * - #LYD_OPT_GET:
+ * - #LYD_OPT_GETCONFIG:
+ * - #LYD_OPT_EDIT:
+ * - no variable arguments expected.
+ * - #LYD_OPT_RPC:
+ * - #LYD_OPT_NOTIF:
+ * - struct lyd_node *data_tree - additional data tree that will be used
+ * when checking any "when" or "must" conditions in the parsed tree that require
+ * some nodes outside their subtree. It must be a list of top-level elements!
+ * - #LYD_OPT_RPCREPLY:
+ * - const struct ::lyd_node *rpc_act - pointer to the whole RPC or action operation data
+ * tree (the request) of the reply.
+ * - const struct ::lyd_node *data_tree - additional data tree that will be used
+ * when checking any "when" or "must" conditions in the parsed tree that require
+ * some nodes outside their subtree. It must be a list of top-level elements!
+ * @return Pointer to the built data tree or NULL in case of empty file. To free the returned structure,
+ * use lyd_free(). In these cases, the function sets #ly_errno to LY_SUCCESS. In case of error,
+ * #ly_errno contains appropriate error code (see #LY_ERR).
+ */
+struct lyd_node *lyd_parse_fd(struct ly_ctx *ctx, int fd, LYD_FORMAT format, int options, ...);
+
+/**
+ * @brief Read (and validate) data from the given file path.
+ *
+ * In case of LY_XML format, the file content is parsed completely. It means that when it contains
+ * a non well-formed XML with multiple root elements, all those sibling XML trees are parsed. The
+ * returned data node is a root of the first tree with other trees connected via the next pointer.
+ * This behavior can be changed by #LYD_OPT_NOSIBLINGS option.
+ *
+ * @param[in] ctx Context to connect with the data tree being built here.
+ * @param[in] path Path to the file containing the data tree in the specified format.
+ * @param[in] format Format of the input data to be parsed.
+ * @param[in] options Parser options, see @ref parseroptions. \p format LYD_LYB uses #LYD_OPT_TRUSTED implicitly.
+ * @param[in] ... Variable arguments depend on \p options. If they include:
+ * - #LYD_OPT_DATA:
+ * - #LYD_OPT_CONFIG:
+ * - #LYD_OPT_GET:
+ * - #LYD_OPT_GETCONFIG:
+ * - #LYD_OPT_EDIT:
+ * - no variable arguments expected.
+ * - #LYD_OPT_RPC:
+ * - #LYD_OPT_NOTIF:
+ * - struct lyd_node *data_tree - additional data tree that will be used
+ * when checking any "when" or "must" conditions in the parsed tree that require
+ * some nodes outside their subtree. It must be a list of top-level elements!
+ * - #LYD_OPT_RPCREPLY:
+ * - const struct ::lyd_node *rpc_act - pointer to the whole RPC or action operation data
+ * tree (the request) of the reply.
+ * - const struct ::lyd_node *data_tree - additional data tree that will be used
+ * when checking any "when" or "must" conditions in the parsed tree that require
+ * some nodes outside their subtree. It must be a list of top-level elements!
+ * @return Pointer to the built data tree or NULL in case of empty file. To free the returned structure,
+ * use lyd_free(). In these cases, the function sets #ly_errno to LY_SUCCESS. In case of error,
+ * #ly_errno contains appropriate error code (see #LY_ERR).
+ */
+struct lyd_node *lyd_parse_path(struct ly_ctx *ctx, const char *path, LYD_FORMAT format, int options, ...);
+
+/**
+ * @brief Free all the nodes in the data tree.
+ *
+ * @param[in] node Any of the nodes inside the tree.
+ */
+void lyd_free_all(struct lyd_node *node);
+
+/**
+ * @brief Free (and unlink) the specified data (sub)tree.
+ *
+ * __PARTIAL CHANGE__ - validate after the final change on the data tree (see @ref howtodatamanipulators).
+ *
+ * @param[in] node Root of the (sub)tree to be freed.
+ */
+void lyd_free_tree(struct lyd_node *node);
+
+/**
+ * @brief Unlink the specified data subtree. All referenced namespaces are copied.
+ *
+ * Note, that the node's connection with the schema tree is kept. Therefore, in case of
+ * reconnecting the node to a data tree using lyd_paste() it is necessary to paste it
+ * to the appropriate place in the data tree following the schema.
+ *
+ * __PARTIAL CHANGE__ - validate after the final change on the data tree (see @ref howtodatamanipulators).
+ *
+ * @param[in] node Data tree node to be unlinked (together with all children).
+ * @return LY_SUCCESS for success
+ * @return LY_E* values in case of error
+ */
+LY_ERR lyd_unlink_tree(struct lyd_node *node);
+
+/**
+ * @brief Destroy data attribute.
+ *
+ * @param[in] ctx Context where the attribute was created.
+ * @param[in] attr Attribute to destroy
+ * @param[in] recursive Zero to destroy only the attribute (the attribute list is corrected),
+ * non-zero to destroy also all the subsequent attributes in the list.
+ */
+void lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LY_TREE_DATA_H_ */
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
new file mode 100644
index 0000000..1337abf
--- /dev/null
+++ b/src/tree_data_free.c
@@ -0,0 +1,224 @@
+/**
+ * @file tree_data_free.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Freeing functions for data tree structures
+ *
+ * Copyright (c) 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 <stdlib.h>
+
+#include "hash_table.h"
+#include "log.h"
+#include "tree.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+#include "tree_data_internal.h"
+
+API LY_ERR
+lyd_unlink_tree(struct lyd_node *node)
+{
+ struct lyd_node *iter;
+ struct lyd_node **first_sibling;
+
+ LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+
+ if (node->parent) {
+ first_sibling = lyd_node_children_p((struct lyd_node*)node->parent);
+ }
+
+ /* unlink from siblings */
+ if (node->prev->next) {
+ node->prev->next = node->next;
+ }
+ if (node->next) {
+ node->next->prev = node->prev;
+ } else {
+ /* unlinking the last node */
+ if (node->parent) {
+ iter = *first_sibling;
+ } else {
+ iter = node->prev;
+ while (iter->prev != node) {
+ iter = iter->prev;
+ }
+ }
+ /* update the "last" pointer from the first node */
+ iter->prev = node->prev;
+ }
+
+ /* unlink from parent */
+ if (node->parent) {
+ if (*first_sibling == node) {
+ /* the node is the first child */
+ *first_sibling = node->next;
+ }
+ lyd_unlink_hash(node);
+ node->parent = NULL;
+ }
+
+ node->next = NULL;
+ node->prev = node;
+
+ return EXIT_SUCCESS;
+}
+
+/**
+ * @brief Free the YANG data value content.
+ * @param[in] ctx libyang context
+ * @param[in] value Data value structure to clean - since it is mostly part of other structure, only content is freed.
+ */
+static void
+lyd_free_value(struct ly_ctx *ctx, struct lyd_value *value)
+{
+ FREE_STRING(ctx, value->canonized);
+}
+
+API void
+lyd_free_attr(struct ly_ctx *ctx, struct lyd_attr *attr, int recursive)
+{
+ struct lyd_attr *iter;
+
+ LY_CHECK_ARG_RET(NULL, ctx, );
+ if (!attr) {
+ return;
+ }
+
+ if (attr->parent) {
+ if (attr->parent->attr == attr) {
+ if (recursive) {
+ attr->parent->attr = NULL;
+ } else {
+ attr->parent->attr = attr->next;
+ }
+ } else {
+ for (iter = attr->parent->attr; iter->next != attr; iter = iter->next);
+ if (iter->next) {
+ if (recursive) {
+ iter->next = NULL;
+ } else {
+ iter->next = attr->next;
+ }
+ }
+ }
+ }
+
+ if (!recursive) {
+ attr->next = NULL;
+ }
+
+ for(iter = attr; iter; ) {
+ attr = iter;
+ iter = iter->next;
+
+ FREE_STRING(ctx, attr->name);
+ lyd_free_value(ctx, &attr->value);
+ free(attr);
+ }
+}
+
+/**
+ * @brief Free Data (sub)tree.
+ * @param[in] ctx libyang context.
+ * @param[in] node Data node to be freed.
+ * @param[in] top Recursion flag to unlink the root of the subtree being freed.
+ */
+static void
+lyd_free_subtree(struct ly_ctx *ctx, struct lyd_node *node, int top)
+{
+ struct lyd_node *iter, *next;
+ struct lyd_node *children;
+
+ assert(node);
+
+ /* remove children hash table in case of inner data node */
+ if (node->schema->nodetype & LYD_NODE_INNER) {
+ lyht_free(((struct lyd_node_inner*)node)->children_ht);
+ ((struct lyd_node_inner*)node)->children_ht = NULL;
+
+ /* free the children */
+ children = (struct lyd_node*)lyd_node_children(node);
+ LY_LIST_FOR_SAFE(children, next, iter) {
+ lyd_free_subtree(ctx, iter, 0);
+ }
+ } else if (node->schema->nodetype & LYD_NODE_ANY) {
+ /* TODO anydata */
+#if 0
+ switch (((struct lyd_node_anydata *)node)->value_type) {
+ case LYD_ANYDATA_CONSTSTRING:
+ case LYD_ANYDATA_SXML:
+ case LYD_ANYDATA_JSON:
+ FREE_STRING(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.str);
+ break;
+ case LYD_ANYDATA_DATATREE:
+ lyd_free_withsiblings(((struct lyd_node_anydata *)node)->value.tree);
+ break;
+ case LYD_ANYDATA_XML:
+ lyxml_free_withsiblings(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.xml);
+ break;
+ case LYD_ANYDATA_LYB:
+ free(((struct lyd_node_anydata *)node)->value.mem);
+ break;
+ case LYD_ANYDATA_STRING:
+ case LYD_ANYDATA_SXMLD:
+ case LYD_ANYDATA_JSOND:
+ case LYD_ANYDATA_LYBD:
+ /* dynamic strings are used only as input parameters */
+ assert(0);
+ break;
+ }
+#endif
+ } else if (node->schema->nodetype & LYD_NODE_TERM) {
+ lyd_free_value(ctx, &((struct lyd_node_term*)node)->value);
+ }
+
+ /* free the node's attributes */
+ lyd_free_attr(ctx, node->attr, 1);
+
+ /* unlink only the nodes from the first level, nodes in subtree are freed all, so no unlink is needed */
+ if (top) {
+ lyd_unlink_tree(node);
+ }
+
+ free(node);
+}
+
+API void
+lyd_free_tree(struct lyd_node *node)
+{
+ if (!node) {
+ return;
+ }
+
+ lyd_free_subtree(node->schema->module->ctx, node, 1);
+}
+
+API void
+lyd_free_all(struct lyd_node *node)
+{
+ struct lyd_node *iter, *next;
+
+ if (!node) {
+ return;
+ }
+
+ /* get the first top-level sibling */
+ for (; node->parent; node = (struct lyd_node*)node->parent);
+ while (node->prev->next) {
+ node = node->prev;
+ }
+
+ LY_LIST_FOR_SAFE(node, next, iter) {
+ /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
+ lyd_free_subtree(node->schema->module->ctx, node, node->parent ? 1 : 0);
+ }
+}
diff --git a/src/tree_data_hash.c b/src/tree_data_hash.c
new file mode 100644
index 0000000..546b2fd
--- /dev/null
+++ b/src/tree_data_hash.c
@@ -0,0 +1,25 @@
+/**
+ * @file tree_data_hash.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Functions to manipulate with the data node's hashes.
+ *
+ * Copyright (c) 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 "hash_table.h"
+#include "tree_data.h"
+
+void
+lyd_unlink_hash(struct lyd_node *node)
+{
+ if (node->parent && node->parent->children_ht) {
+ lyht_remove(node->parent->children_ht, &node, node->hash);
+ }
+}
diff --git a/src/tree_data_helpers.c b/src/tree_data_helpers.c
new file mode 100644
index 0000000..fc4bf1c
--- /dev/null
+++ b/src/tree_data_helpers.c
@@ -0,0 +1,111 @@
+/**
+ * @file tree_data_helpers.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Parsing and validation helper functions for data trees
+ *
+ * Copyright (c) 2015 - 2018 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 <stdlib.h>
+
+#include "log.h"
+#include "dict.h"
+#include "plugins_types.h"
+#include "tree_data.h"
+#include "tree_schema.h"
+
+struct lyd_node **
+lyd_node_children_p(struct lyd_node *node)
+{
+ assert(node);
+ switch (node->schema->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LIST:
+ return &((struct lyd_node_inner*)node)->child;
+ default:
+ return NULL;
+ }
+}
+
+API const struct lyd_node *
+lyd_node_children(const struct lyd_node *node)
+{
+ struct lyd_node **children;
+
+ if (!node) {
+ return NULL;
+ }
+
+ children = lyd_node_children_p((struct lyd_node*)node);
+ if (children) {
+ return *children;
+ } else {
+ return NULL;
+ }
+}
+
+LY_ERR
+lyd_parse_check_options(struct ly_ctx *ctx, int options, const char *func)
+{
+ int x = options & LYD_OPT_TYPEMASK;
+
+ /* LYD_OPT_WHENAUTODEL can be used only with LYD_OPT_DATA or LYD_OPT_CONFIG */
+ if (options & LYD_OPT_WHENAUTODEL) {
+ if ((x == LYD_OPT_EDIT) || (x == LYD_OPT_NOTIF_FILTER)) {
+ LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (LYD_OPT_DATA_WHENAUTODEL can be used only with LYD_OPT_DATA or LYD_OPT_CONFIG)",
+ func, options);
+ return LY_EINVAL;
+ }
+ }
+
+ if (options & (LYD_OPT_DATA_ADD_YANGLIB | LYD_OPT_DATA_NO_YANGLIB)) {
+ if (x != LYD_OPT_DATA) {
+ LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (LYD_OPT_DATA_*_YANGLIB can be used only with LYD_OPT_DATA)",
+ func, options);
+ return LY_EINVAL;
+ }
+ }
+
+ /* "is power of 2" algorithm, with 0 exception */
+ if (x && !(x && !(x & (x - 1)))) {
+ LOGERR(ctx, LY_EINVAL, "%s: Invalid options 0x%x (multiple data type flags set).", func, options);
+ return LY_EINVAL;
+ }
+
+ return LY_SUCCESS;
+}
+
+LY_ERR
+lyd_value_validate(struct lyd_node_term *node, const char *value, size_t value_len, int options)
+{
+ LY_ERR ret = LY_SUCCESS;
+ struct ly_err_item *err = NULL;
+ struct ly_ctx *ctx;
+ struct lysc_type *type;
+
+ assert(node);
+
+ ctx = node->schema->module->ctx;
+ type = ((struct lysc_node_leaf*)node->schema)->type;
+ if (type->plugin->validate) {
+ ret = type->plugin->validate(ctx, type, value, value_len, options, &node->value.canonized, &err);
+ if (ret) {
+ ly_err_print(err);
+ LOGVAL(ctx, LY_VLOG_STR, err->path, err->vecode, err->msg);
+ ly_err_free(err);
+ }
+ } else if (options & LY_TYPE_VALIDATE_CANONIZE) {
+ node->value.canonized = lydict_insert(ctx, value, value_len);
+ }
+
+ return ret;
+}
+
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
new file mode 100644
index 0000000..ba0729e
--- /dev/null
+++ b/src/tree_data_internal.h
@@ -0,0 +1,76 @@
+/**
+ * @file tree_data_internal.h
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief internal functions for YANG schema trees.
+ *
+ * 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_TREE_DATA_INTERNAL_H_
+#define LY_TREE_DATA_INTERNAL_H_
+
+#include "tree_data.h"
+
+/**
+ * @brief Get address of a node's child pointer if any.
+ *
+ * Decides the node's type and in case it has a children list, returns its address.
+ * @param[in] node Node to check.
+ * @return Address of the node's child member if any, NULL otherwise.
+ */
+struct lyd_node **lyd_node_children_p(struct lyd_node *node);
+
+/**
+ * @brief Check validity of data parser options.
+ *
+ * @param ctx libyang context
+ * @param options Data parser options to check
+ * @param func name of the function where called
+ * @return LY_SUCCESS when options are ok
+ * @return LY_EINVAL when multiple data types bits are set, or incompatible options are used together.
+ */
+LY_ERR lyd_parse_check_options(struct ly_ctx *ctx, int options, const char *func);
+
+/**
+ * @brief Validate the given value according to the type's rules.
+ *
+ * According to the given options, the value can be also canonized or stored into the node's value structure.
+ *
+ * @param[in] options [Type validation options ](@ref plugintypevalidateopts).
+ */
+LY_ERR lyd_value_validate(struct lyd_node_term *node, const char *value, size_t value_len, int options);
+
+/**
+ * @brief Parse XML string as YANG data tree.
+ *
+ * @param[in] ctx libyang context
+ * @param[in] data Pointer to the XML string representation of the YANG data to parse.
+ * @param[in] options @ref dataparseroptions
+ * @param[out] result Resulting list of the parsed data trees. Note that NULL can be a valid result.
+ * @reutn LY_ERR value.
+ */
+LY_ERR lyd_parse_xml(struct ly_ctx *ctx, const char *data, int options, struct lyd_node **result);
+
+/**
+ * @defgroup datahash Data nodes hash manipulation
+ * @ingroup datatree
+ */
+
+/**
+ * @brief Maintain node's parent's children hash table when unlinking the node.
+ *
+ * When completely freeing data tree, it is expected to free the parent's children hash table first, at once.
+ *
+ * @param[in] node The data node being unlinked from its parent.
+ */
+void lyd_unlink_hash(struct lyd_node *node);
+
+/** @} datahash */
+
+#endif /* LY_TREE_DATA_INTERNAL_H_ */
diff --git a/src/tree_schema.c b/src/tree_schema.c
index ca093fc..4e5ffb3 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -14,19 +14,25 @@
#include "common.h"
+#include <assert.h>
#include <dirent.h>
#include <errno.h>
-#include <limits.h>
#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
-#include "libyang.h"
#include "context.h"
+#include "dict.h"
+#include "log.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_schema.h"
#include "tree_schema_internal.h"
-#include "xpath.h"
API const struct lysc_node *
lys_getnext(const struct lysc_node *last, const struct lysc_node *parent, const struct lysc_module *module, int options)
@@ -505,12 +511,12 @@
}
struct lysp_submodule *
-lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx*, struct lysp_module*, struct lysp_submodule*, void*), void *check_data)
{
LY_ERR ret = LY_EINVAL;
struct lysp_submodule *submod = NULL, *latest_sp;
- struct ly_parser_ctx context = {0};
+ struct lys_parser_ctx context = {0};
LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
@@ -582,7 +588,7 @@
struct lysp_include *inc;
LY_ERR ret = LY_EINVAL;
unsigned int u, i;
- struct ly_parser_ctx context = {0};
+ struct lys_parser_ctx context = {0};
LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
@@ -769,7 +775,7 @@
}
void *
-lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
+lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct lys_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
void *check_data)
{
@@ -821,7 +827,7 @@
}
struct lysp_submodule *
-lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
void *check_data)
{
diff --git a/src/tree_schema.h b/src/tree_schema.h
index b2d619d..20d1c17 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -21,115 +21,17 @@
#include <stdint.h>
#include <stdio.h>
+#include "log.h"
+#include "tree.h"
#include "extensions.h"
+struct ly_ctx;
+
#ifdef __cplusplus
extern "C" {
#endif
/**
- * @brief XPath representation.
- */
-struct lyxp_expr;
-
-/**
- * @brief Macro selector for other LY_ARRAY_* macros, do not use directly!
- */
-#define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME
-
-/**
- * @brief Helper macro to go through sized-arrays with a pointer iterator.
- *
- * Use with opening curly bracket (`{`).
- *
- * @param[in] ARRAY Array to go through
- * @param[in] TYPE Type of the records in the ARRAY
- * @param[out] ITER Iterating pointer to the item being processed in each loop
- */
-#define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \
- for (ITER = ARRAY; \
- (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((uint32_t*)(ARRAY) - 1)); \
- ITER = (void*)((TYPE*)ITER + 1))
-
-/**
- * @brief Helper macro to go through sized-arrays with a numeric iterator.
- *
- * Use with opening curly bracket (`{`).
- *
- * To access an item with the INDEX value, use always LY_ARRAY_INDEX macro!
- *
- * @param[in] ARRAY Array to go through
- * @param[out] INDEX Iterating index of the item being processed in each loop
- */
-#define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \
- for (INDEX = 0; \
- ARRAY && INDEX < (*((uint32_t*)(ARRAY) - 1)); \
- ++INDEX)
-
-/**
- * @defgroup schematree Schema Tree
- * @{
- *
- * Data structures and functions to manipulate and access schema tree.
- */
-
-/**
- * @brief Get a number of records in the ARRAY.
- *
- * Does not check if array exists!
- */
-#define LY_ARRAY_SIZE(ARRAY) (*((uint32_t*)(ARRAY) - 1))
-
-/**
- * @brief Sized-array iterator (for-loop).
- *
- * Use with opening curly bracket (`{`).
- *
- * There are 2 variants:
- *
- * LY_ARRAY_FOR(ARRAY, TYPE, ITER)
- *
- * Where ARRAY is a sized-array to go through, TYPE is the type of the items in the ARRAY and ITER is a pointer variable
- * providing the items of the ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_ITER macro
- *
- * LY_ARRAY_FOR(ARRAY, INDEX)
- *
- * The ARRAY is again a sized-array to go through, the INDEX is a variable (unsigned integer) for storing iterating ARRAY's index
- * to access the items of ARRAY in the loops. This functionality is provided by LY_ARRAY_FOR_INDEX macro.
- */
-#define LY_ARRAY_FOR(ARRAY, ...) LY_ARRAY_SELECT(__VA_ARGS__, LY_ARRAY_FOR_ITER, LY_ARRAY_FOR_INDEX)(ARRAY, __VA_ARGS__)
-
-/**
- * @brief Macro to iterate via all sibling elements without affecting the list itself
- *
- * Works for all types of nodes despite it is data or schema tree, but all the
- * parameters must be pointers to the same type.
- *
- * Use with opening curly bracket (`{`). All parameters must be of the same type.
- *
- * @param START Pointer to the starting element.
- * @param ELEM Iterator.
- */
-#define LY_LIST_FOR(START, ELEM) \
- for ((ELEM) = (START); \
- (ELEM); \
- (ELEM) = (ELEM)->next)
-
-/**
- * @brief Macro to iterate via all sibling elements allowing to modify the list itself (e.g. removing elements)
- *
- * Use with opening curly bracket (`{`). All parameters must be of the same type.
- *
- * @param START Pointer to the starting element.
- * @param NEXT Temporary storage to allow removing of the current iterator content.
- * @param ELEM Iterator.
- */
-#define LY_LIST_FOR_SAFE(START, NEXT, ELEM) \
- for ((ELEM) = (START); \
- (ELEM) ? (NEXT = (ELEM)->next, 1) : 0; \
- (ELEM) = (NEXT))
-
-/**
* @brief Schema input formats accepted by libyang [parser functions](@ref howtoschemasparsers).
*/
typedef enum {
@@ -163,49 +65,18 @@
#define LYS_ANYXML 0x0020 /**< anyxml statement node */
#define LYS_ANYDATA 0x0120 /**< anydata statement node, in tests it can be used for both #LYS_ANYXML and #LYS_ANYDATA */
+#define LYS_ACTION 0x400 /**< RPC or action */
+#define LYS_NOTIF 0x800
+
#define LYS_CASE 0x0040 /**< case statement node */
#define LYS_USES 0x0080 /**< uses statement node */
#define LYS_INPUT 0x100
#define LYS_OUTPUT 0x200
#define LYS_INOUT 0x300
-#define LYS_ACTION 0x400 /**< RPC or action */
-#define LYS_NOTIF 0x800
#define LYS_GROUPING 0x1000
#define LYS_AUGMENT 0x2000
/**
- * @brief YANG built-in types
- */
-typedef enum {
- LY_TYPE_UNKNOWN = 0, /**< Unknown type */
- LY_TYPE_BINARY, /**< Any binary data ([RFC 6020 sec 9.8](http://tools.ietf.org/html/rfc6020#section-9.8)) */
- LY_TYPE_UINT8, /**< 8-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
- LY_TYPE_UINT16, /**< 16-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
- LY_TYPE_UINT32, /**< 32-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
- LY_TYPE_UINT64, /**< 64-bit unsigned integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
- LY_TYPE_STRING, /**< Human-readable string ([RFC 6020 sec 9.4](http://tools.ietf.org/html/rfc6020#section-9.4)) */
- LY_TYPE_BITS, /**< A set of bits or flags ([RFC 6020 sec 9.7](http://tools.ietf.org/html/rfc6020#section-9.7)) */
- LY_TYPE_BOOL, /**< "true" or "false" ([RFC 6020 sec 9.5](http://tools.ietf.org/html/rfc6020#section-9.5)) */
- LY_TYPE_DEC64, /**< 64-bit signed decimal number ([RFC 6020 sec 9.3](http://tools.ietf.org/html/rfc6020#section-9.3))*/
- LY_TYPE_EMPTY, /**< A leaf that does not have any value ([RFC 6020 sec 9.11](http://tools.ietf.org/html/rfc6020#section-9.11)) */
- LY_TYPE_ENUM, /**< Enumerated strings ([RFC 6020 sec 9.6](http://tools.ietf.org/html/rfc6020#section-9.6)) */
- LY_TYPE_IDENT, /**< A reference to an abstract identity ([RFC 6020 sec 9.10](http://tools.ietf.org/html/rfc6020#section-9.10)) */
- LY_TYPE_INST, /**< References a data tree node ([RFC 6020 sec 9.13](http://tools.ietf.org/html/rfc6020#section-9.13)) */
- LY_TYPE_LEAFREF, /**< A reference to a leaf instance ([RFC 6020 sec 9.9](http://tools.ietf.org/html/rfc6020#section-9.9))*/
- LY_TYPE_UNION, /**< Choice of member types ([RFC 6020 sec 9.12](http://tools.ietf.org/html/rfc6020#section-9.12)) */
- LY_TYPE_INT8, /**< 8-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
- LY_TYPE_INT16, /**< 16-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
- LY_TYPE_INT32, /**< 32-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
- LY_TYPE_INT64, /**< 64-bit signed integer ([RFC 6020 sec 9.2](http://tools.ietf.org/html/rfc6020#section-9.2)) */
-} LY_DATA_TYPE;
-#define LY_DATA_TYPE_COUNT 20 /**< Number of different types */
-
-/**
- * @brief Stringified YANG built-in data types
- */
-extern const char* ly_data_type2str[LY_DATA_TYPE_COUNT];
-
-/**
* @brief YANG import-stmt
*/
struct lysp_import {
@@ -1066,12 +937,12 @@
struct lysc_range {
struct lysc_range_part {
union { /**< min boundary */
- int64_t min_64; /**< for int8, int16, int32, int64 and decimal64 */
- uint64_t min_u64; /**< for uint8, uint16, uint32, uint64, string and binary */
+ int64_t min_64; /**< for int8, int16, int32, int64 and decimal64 ( >= LY_TYPE_DEC64) */
+ uint64_t min_u64; /**< for uint8, uint16, uint32, uint64, string and binary ( < LY_TYPE_DEC64) */
};
union { /**< max boundary */
- int64_t max_64; /**< for int8, int16, int32, int64 and decimal64 */
- uint64_t max_u64; /**< for uint8, uint16, uint32, uint64, string and binary */
+ int64_t max_64; /**< for int8, int16, int32, int64 and decimal64 ( >= LY_TYPE_DEC64) */
+ uint64_t max_u64; /**< for uint8, uint16, uint32, uint64, string and binary ( < LY_TYPE_DEC64) */
};
} *parts; /**< compiled range expression ([sized array](@ref sizedarrays)) */
const char *dsc; /**< description */
@@ -1106,6 +977,7 @@
struct lysc_type {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
};
@@ -1113,6 +985,7 @@
struct lysc_type_num {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
struct lysc_range *range; /**< Optional range limitation */
@@ -1121,6 +994,7 @@
struct lysc_type_dec {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
uint8_t fraction_digits; /**< fraction digits specification */
@@ -1130,6 +1004,7 @@
struct lysc_type_str {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
struct lysc_range *length; /**< Optional length limitation */
@@ -1153,6 +1028,7 @@
struct lysc_type_enum {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
struct lysc_type_bitenum_item *enums; /**< enumerations list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
@@ -1161,6 +1037,7 @@
struct lysc_type_bits {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
struct lysc_type_bitenum_item *bits; /**< bits list ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
@@ -1169,6 +1046,7 @@
struct lysc_type_leafref {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
const char* path; /**< target path */
@@ -1180,6 +1058,7 @@
struct lysc_type_identityref {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
struct lysc_ident **bases; /**< list of pointers to the base identities ([sized array](@ref sizedarrays)),
@@ -1189,6 +1068,7 @@
struct lysc_type_instanceid {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
uint8_t require_instance; /**< require-instance flag */
@@ -1197,6 +1077,7 @@
struct lysc_type_union {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
struct lysc_type **types; /**< list of types in the union ([sized array](@ref sizedarrays)), mandatory (at least 1 item) */
@@ -1205,6 +1086,7 @@
struct lysc_type_bin {
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
const char *dflt; /**< type's default value if any */
+ struct lysc_type_plugin *plugin; /**< type's plugin with built-in as well as user functions to canonize or validate the value of the type */
LY_DATA_TYPE basetype; /**< Base type of the type */
uint32_t refcount; /**< reference counter for type sharing */
struct lysc_range *length; /**< Optional length limitation */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 1f57db9..2f9246c 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -14,11 +14,20 @@
#include "common.h"
+#include <assert.h>
#include <ctype.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-#include "libyang.h"
-#include "context.h"
+#include "dict.h"
+#include "log.h"
+#include "set.h"
+#include "plugins_types.h"
+#include "tree.h"
+#include "tree_schema.h"
#include "tree_schema_internal.h"
#include "xpath.h"
@@ -93,7 +102,7 @@
static struct lysc_ext_instance *
lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
{
- /* TODO */
+ /* TODO - extensions */
(void) ctx;
(void) orig;
return NULL;
@@ -2999,6 +3008,8 @@
}
(*type)->basetype = basetype;
+ /* TODO user type plugins */
+ (*type)->plugin = &ly_builtin_type_plugins[basetype];
prev_type = *type;
ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->mod, tctx->tpdf->name, &((struct lysp_tpdf*)tctx->tpdf)->type,
basetype & (LY_TYPE_LEAFREF | LY_TYPE_UNION) ? lysp_find_module(ctx->ctx, tctx->mod) : NULL,
@@ -3013,6 +3024,8 @@
if (type_p->flags || !base || basetype == LY_TYPE_LEAFREF) {
/* get restrictions from the node itself */
(*type)->basetype = basetype;
+ /* TODO user type plugins */
+ (*type)->plugin = &ly_builtin_type_plugins[basetype];
++(*type)->refcount;
ret = lys_compile_type_(ctx, context_node_p, context_flags, context_mod, context_name, type_p, ctx->mod_def, basetype, NULL, base, type);
LY_CHECK_GOTO(ret, cleanup);
@@ -3766,7 +3779,6 @@
struct lysp_node_choice *ch_p = (struct lysp_node_choice*)node_p;
struct lysc_node_choice *ch = (struct lysc_node_choice*)node;
struct lysp_node *child_p, *case_child_p;
- struct lys_module;
LY_ERR ret = LY_SUCCESS;
LY_LIST_FOR(ch_p->child, child_p) {
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index c3948a0..283ba29 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -1,9 +1,9 @@
/**
- * @file tree_schema.c
+ * @file tree_schema_free.c
* @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Schema tree implementation
+ * @brief Freeing functions for schema tree structures.
*
- * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
+ * Copyright (c) 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.
@@ -14,8 +14,11 @@
#include "common.h"
-#include "libyang.h"
-#include "context.h"
+#include <stdlib.h>
+
+#include "dict.h"
+#include "tree.h"
+#include "tree_schema.h"
#include "tree_schema_internal.h"
#include "xpath.h"
@@ -621,7 +624,6 @@
}
FREE_ARRAY(ctx, type->exts, lysc_ext_instance_free);
FREE_STRING(ctx, type->dflt);
-
free(type);
}
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index a4a93ee..9ba34e9 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -1,7 +1,7 @@
/**
* @file tree_schema_helpers.c
* @author Radek Krejci <rkrejci@cesnet.cz>
- * @brief Parsing and validation helper functions
+ * @brief Parsing and validation helper functions for schema trees
*
* Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
*
@@ -13,18 +13,26 @@
*/
#include "common.h"
+#include <assert.h>
+#include <bits/types/struct_tm.h>
#include <ctype.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <stdint.h>
#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <string.h>
#include <unistd.h>
#include <time.h>
-#include "libyang.h"
+#include "context.h"
+#include "dict.h"
+#include "extensions.h"
+#include "hash_table.h"
+#include "log.h"
+#include "set.h"
+#include "tree.h"
+#include "tree_schema.h"
#include "tree_schema_internal.h"
/**
@@ -201,7 +209,7 @@
}
LY_ERR
-lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
+lysp_check_prefix(struct lys_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value)
{
struct lysp_import *i;
@@ -244,7 +252,7 @@
}
LY_ERR
-lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
+lysp_check_date(struct lys_parser_ctx *ctx, const char *date, int date_len, const char *stmt)
{
int i;
struct tm tm, tm_;
@@ -487,7 +495,7 @@
* @return LY_EEXIST in case of collision, LY_SUCCESS otherwise.
*/
static LY_ERR
-lysp_check_typedef(struct ly_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
+lysp_check_typedef(struct lys_parser_ctx *ctx, struct lysp_node *node, const struct lysp_tpdf *tpdf,
struct hash_table *tpdfs_global, struct hash_table *tpdfs_scoped)
{
struct lysp_node *parent;
@@ -562,7 +570,7 @@
}
LY_ERR
-lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod)
+lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod)
{
struct hash_table *ids_global;
struct hash_table *ids_scoped;
@@ -679,7 +687,7 @@
}
LY_ERR
-lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
+lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_parser_ctx *main_ctx,
void **result)
{
int fd;
@@ -846,7 +854,7 @@
}
LY_ERR
-lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
+lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
{
struct lysp_submodule *submod = NULL;
const char *submodule_data = NULL;
@@ -1182,6 +1190,11 @@
lysp_node_children(const struct lysp_node *node)
{
struct lysp_node **children;
+
+ if (!node) {
+ return NULL;
+ }
+
children = lysp_node_children_p((struct lysp_node*)node);
if (children) {
return *children;
@@ -1277,6 +1290,11 @@
lysc_node_children(const struct lysc_node *node, uint16_t flags)
{
struct lysc_node **children;
+
+ if (!node) {
+ return NULL;
+ }
+
children = lysc_node_children_p((struct lysc_node*)node, flags);
if (children) {
return *children;
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 6194649..2f5c063 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -46,7 +46,7 @@
/**
* @brief internal context for schema parsers
*/
-struct ly_parser_ctx {
+struct lys_parser_ctx {
struct ly_ctx *ctx;
struct ly_set tpdfs_nodes;
struct ly_set grps_nodes;
@@ -83,7 +83,7 @@
* @param[in] value Newly added prefix value (including its location to distinguish collision with itself).
* @return LY_EEXIST when prefix is already used in the module, LY_SUCCESS otherwise
*/
-LY_ERR lysp_check_prefix(struct ly_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value);
+LY_ERR lysp_check_prefix(struct lys_parser_ctx *ctx, struct lysp_import *imports, const char *module_prefix, const char **value);
/**
* @brief Check date string (4DIGIT "-" 2DIGIT "-" 2DIGIT)
@@ -94,7 +94,7 @@
* @param[in] stmt Statement name for error message.
* @return LY_ERR value.
*/
-LY_ERR lysp_check_date(struct ly_parser_ctx *ctx, const char *date, int date_len, const char *stmt);
+LY_ERR lysp_check_date(struct lys_parser_ctx *ctx, const char *date, int date_len, const char *stmt);
/**
* @brief Check names of typedefs in the parsed module to detect collisions.
@@ -103,7 +103,7 @@
* @param[in] mod Module where the type is being defined.
* @return LY_ERR value.
*/
-LY_ERR lysp_check_typedefs(struct ly_parser_ctx *ctx, struct lysp_module *mod);
+LY_ERR lysp_check_typedefs(struct lys_parser_ctx *ctx, struct lysp_module *mod);
/**
* @brief Just move the newest revision into the first position, does not sort the rest
@@ -150,7 +150,7 @@
* submodule is stored into this structure.
* @return LY_ERR value.
*/
-LY_ERR lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
+LY_ERR lysp_load_submodule(struct lys_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
/**
* @defgroup scflags Schema compile flags
@@ -405,7 +405,7 @@
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @return Pointer to the data model structure or NULL on error.
*/
-struct lysp_submodule *lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+struct lysp_submodule *lys_parse_mem_submodule(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
void *check_data);
@@ -427,7 +427,7 @@
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @return Pointer to the data model structure or NULL on error.
*/
-void *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
+void *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct lys_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *data),
void *check_data);
@@ -467,7 +467,7 @@
* @param[in] check_data Caller's data to pass to the custom_check callback.
* @return Pointer to the data model structure or NULL on error.
*/
-struct lysp_submodule *lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct ly_parser_ctx *main_ctx,
+struct lysp_submodule *lys_parse_fd_submodule(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_submodule *submod, void *check_data),
void *check_data);
@@ -506,7 +506,7 @@
* If it is a module, it is already in the context!
* @return LY_ERR value, in case of LY_SUCCESS, the \arg result is always provided.
*/
-LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
+LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_parser_ctx *main_ctx,
void **result);
/**
@@ -657,7 +657,7 @@
* @param[out] submod Pointer to the parsed submodule structure.
* @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
*/
-LY_ERR yang_parse_submodule(struct ly_parser_ctx *ctx, const char *data, struct lysp_submodule **submod);
+LY_ERR yang_parse_submodule(struct lys_parser_ctx *ctx, const char *data, struct lysp_submodule **submod);
/**
* @brief Parse module from YANG data.
@@ -667,7 +667,7 @@
* module structure, will be filled in.
* @return LY_ERR value - LY_SUCCESS, LY_EINVAL or LY_EVALID.
*/
-LY_ERR yang_parse_module(struct ly_parser_ctx *ctx, const char *data, struct lys_module *mod);
+LY_ERR yang_parse_module(struct lys_parser_ctx *ctx, const char *data, struct lys_module *mod);
/**
* @brief Make the specific module implemented, use the provided value as flag.
diff --git a/src/xml.c b/src/xml.c
index a7e40f7..195ce56 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -18,10 +18,11 @@
#include <ctype.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
-#include "libyang.h"
#include "xml.h"
+#include "printer_internal.h"
/* Move input p by s characters, if EOF log with lyxml_context c */
#define move_input(c,p,s) p += s; LY_CHECK_ERR_RET(!p[0], LOGVAL(c->ctx, LY_VLOG_LINE, &c->line, LY_VCODE_EOF), LY_EVALID)
@@ -218,6 +219,7 @@
context->line += newlines;
if (in[offset] == '<') {
(*input) = in + offset;
+ context->status -= 1; /* LYXML_ELEMENT */;
return LY_EINVAL;
}
}
@@ -739,3 +741,40 @@
}
ly_set_erase(&context->ns, NULL);
}
+
+LY_ERR
+lyxml_dump_text(struct lyout *out, const char *text, int attribute)
+{
+ LY_ERR ret = LY_SUCCESS;
+ unsigned int u;
+
+ if (!text) {
+ return 0;
+ }
+
+ for (u = 0; text[u]; u++) {
+ switch (text[u]) {
+ case '&':
+ ret = ly_print(out, "&");
+ break;
+ case '<':
+ ret = ly_print(out, "<");
+ break;
+ case '>':
+ /* not needed, just for readability */
+ ret = ly_print(out, ">");
+ break;
+ case '"':
+ if (attribute) {
+ ret = ly_print(out, """);
+ break;
+ }
+ /* falls through */
+ default:
+ ly_write(out, &text[u], 1);
+ }
+ }
+
+ return ret;
+}
+
diff --git a/src/xml.h b/src/xml.h
index 70431ea..3224e8d 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -15,11 +15,14 @@
#ifndef LY_XML_H_
#define LY_XML_H_
+#include <stddef.h>
#include <stdint.h>
-#include "context.h"
+#include "log.h"
#include "set.h"
+struct lyout;
+
/* Macro to test if character is whitespace */
#define is_xmlws(c) (c == 0x20 || c == 0x9 || c == 0xa || c == 0xd)
@@ -81,7 +84,7 @@
/**
* @brief Parse input expecting an XML element.
*
- * Able to silently skip comments, PIs and CData. DOCTYPE is not parsable, so it is reported as LY_EVALID error.
+ * Able to silently skip comments, PIs and CData. DOCTYPE is not parseable, so it is reported as LY_EVALID error.
* If '<' is not found in input, LY_EINVAL is returned (but no error is logged), so it is possible to continue
* with parsing input as text content.
*
@@ -200,6 +203,16 @@
LY_ERR lyxml_ns_rm(struct lyxml_context *context, const char *element_name);
/**
+ * @brief Print the given @p text as XML string which replaces some of the characters which cannot appear in XML data.
+ *
+ * @param[in] out Output structure for printing.
+ * @param[in] text String to print.
+ * @param[in] attribute Flag for attribute's value where a double quotes must be replaced.
+ * @return LY_ERR values.
+ */
+LY_ERR lyxml_dump_text(struct lyout *out, const char *text, int attribute);
+
+/**
* @brief Remove the allocated working memory of the context.
*
* @param[in] context XML context to clear.
diff --git a/src/xpath.c b/src/xpath.c
index a73c2e0..ba818ca 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -15,16 +15,13 @@
#include "common.h"
#include <ctype.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdint.h>
#include <string.h>
-#include <assert.h>
-#include <limits.h>
-#include <errno.h>
-#include <math.h>
#include "xpath.h"
+#include "dict.h"
#include "xml.h"
/**
diff --git a/src/xpath.h b/src/xpath.h
index df3a4f9..5abd427 100644
--- a/src/xpath.h
+++ b/src/xpath.h
@@ -17,11 +17,11 @@
#include <stdint.h>
-#include "libyang.h"
-#include "tree_schema.h"
-#if 0
-#include "tree_data.h"
-#endif
+#include "log.h"
+
+struct ly_ctx;
+struct lysc_node;
+
/*
* XPath evaluator fully compliant with http://www.w3.org/TR/1999/REC-xpath-19991116/
* except the following restrictions in the grammar.