data tree NEW getting string value and data path
diff --git a/src/tree_data.c b/src/tree_data.c
index 6c98e7d..e3f2b29 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -345,6 +345,22 @@
return ret;
}
+API const char *
+lyd_value2str(const struct lyd_node_term *node, int *dynamic)
+{
+ LY_CHECK_ARG_RET(node ? node->schema->module->ctx : NULL, node, dynamic, NULL);
+
+ return node->value.realtype->plugin->print(&node->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
+}
+
+API const char *
+lyd_attr2str(const struct lyd_attr *attr, int *dynamic)
+{
+ LY_CHECK_ARG_RET(attr ? attr->parent->schema->module->ctx : NULL, attr, dynamic, NULL);
+
+ return attr->value.realtype->plugin->print(&attr->value, LYD_JSON, json_print_get_prefix, NULL, dynamic);
+}
+
API struct lyd_node *
lyd_parse_mem(struct ly_ctx *ctx, const char *data, LYD_FORMAT format, int options, const struct lyd_node **trees)
{
@@ -903,3 +919,233 @@
}
return NULL;
}
+
+static LY_ERR
+lyd_path_str_enlarge(char **buffer, size_t *buflen, size_t reqlen, int is_static)
+{
+ if (reqlen > *buflen) {
+ if (is_static) {
+ return LY_EINCOMPLETE;
+ }
+
+ *buffer = ly_realloc(*buffer, reqlen * sizeof **buffer);
+ if (!*buffer) {
+ return LY_EMEM;
+ }
+
+ *buflen = reqlen;
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Append all list key predicates to path.
+ *
+ * @param[in] node Node with keys to print.
+ * @param[in,out] buffer Buffer to print to.
+ * @param[in,out] buflen Current buffer length.
+ * @param[in,out] bufused Current number of characters used in @p buffer.
+ * @param[in] is_static Whether buffer is static or can be reallocated.
+ * @return LY_ERR
+ */
+static LY_ERR
+lyd_path_list_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
+{
+ const struct lyd_node *key;
+ int dynamic = 0;
+ size_t len;
+ const char *val;
+ char quot;
+ LY_ERR rc;
+
+ for (key = lyd_node_children(node); key && (key->flags & LYS_KEY); key = key->next) {
+ val = lyd_value2str((struct lyd_node_term *)key, &dynamic);
+ len = 1 + strlen(key->schema->name) + 2 + strlen(val) + 2;
+ rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
+ if (rc != LY_SUCCESS) {
+ if (dynamic) {
+ free((char *)val);
+ }
+ return rc;
+ }
+
+ quot = '\'';
+ if (strchr(val, '\'')) {
+ quot = '"';
+ }
+ *bufused += sprintf(*buffer + *bufused, "[%s=%c%s%c]", key->schema->name, quot, val, quot);
+
+ if (dynamic) {
+ free((char *)val);
+ }
+ }
+
+ return LY_SUCCESS;
+}
+
+/**
+ * @brief Append leaf-list value predicate to path.
+ *
+ * @param[in] node Node to print.
+ * @param[in,out] buffer Buffer to print to.
+ * @param[in,out] buflen Current buffer length.
+ * @param[in,out] bufused Current number of characters used in @p buffer.
+ * @param[in] is_static Whether buffer is static or can be reallocated.
+ * @return LY_ERR
+ */
+static LY_ERR
+lyd_path_leaflist_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
+{
+ int dynamic = 0;
+ size_t len;
+ const char *val;
+ char quot;
+ LY_ERR rc;
+
+ val = lyd_value2str((struct lyd_node_term *)node, &dynamic);
+ len = 4 + strlen(val) + 2;
+ rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
+ if (rc != LY_SUCCESS) {
+ goto cleanup;
+ }
+
+ quot = '\'';
+ if (strchr(val, '\'')) {
+ quot = '"';
+ }
+ *bufused += sprintf(*buffer + *bufused, "[.=%c%s%c]", quot, val, quot);
+
+cleanup:
+ if (dynamic) {
+ free((char *)val);
+ }
+ return rc;
+}
+
+/**
+ * @brief Append node position (relative to its other instances) predicate to path.
+ *
+ * @param[in] node Node to print.
+ * @param[in,out] buffer Buffer to print to.
+ * @param[in,out] buflen Current buffer length.
+ * @param[in,out] bufused Current number of characters used in @p buffer.
+ * @param[in] is_static Whether buffer is static or can be reallocated.
+ * @return LY_ERR
+ */
+static LY_ERR
+lyd_path_position_predicate(const struct lyd_node *node, char **buffer, size_t *buflen, size_t *bufused, int is_static)
+{
+ const struct lyd_node *first, *iter;
+ size_t len;
+ int pos;
+ char *val = NULL;
+ LY_ERR rc;
+
+ if (node->parent) {
+ first = node->parent->child;
+ } else {
+ for (first = node; node->prev->next; node = node->prev);
+ }
+ pos = 1;
+ for (iter = first; iter != node; iter = iter->next) {
+ if (iter->schema == node->schema) {
+ ++pos;
+ }
+ }
+ if (asprintf(&val, "%d", pos) == -1) {
+ return LY_EMEM;
+ }
+
+ len = 1 + strlen(val) + 1;
+ rc = lyd_path_str_enlarge(buffer, buflen, *bufused + len, is_static);
+ if (rc != LY_SUCCESS) {
+ goto cleanup;
+ }
+
+ *bufused += sprintf(*buffer + *bufused, "[%s]", val);
+
+cleanup:
+ free(val);
+ return rc;
+}
+
+API char *
+lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen)
+{
+ int is_static = 0, i, j, depth;
+ size_t bufused = 1 /* ending zero */, len;
+ const struct lyd_node *iter;
+ const struct lys_module *mod;
+ LY_ERR rc;
+
+ LY_CHECK_ARG_RET(NULL, node, NULL);
+ if (buffer) {
+ LY_CHECK_ARG_RET(node->schema->module->ctx, buflen > 1, NULL);
+ is_static = 1;
+ }
+
+ switch (pathtype) {
+ case LYSC_PATH_LOG:
+ depth = 0;
+ for (iter = node; iter->parent; iter = (const struct lyd_node *)iter->parent) {
+ ++depth;
+ }
+
+ i = depth + 1;
+ goto iter_print;
+ while (i) {
+ /* find the right node */
+ for (iter = node, j = 0; j < i; iter = (const struct lyd_node *)iter->parent, ++j);
+iter_print:
+ /* print prefix and name */
+ mod = NULL;
+ if (!iter->parent || (iter->schema->module != iter->parent->schema->module)) {
+ mod = iter->schema->module;
+ }
+
+ /* realloc string */
+ len = 1 + (mod ? strlen(mod->name) + 1 : 0) + strlen(iter->schema->name);
+ rc = lyd_path_str_enlarge(&buffer, &buflen, bufused + len, is_static);
+ if (rc != LY_SUCCESS) {
+ break;
+ }
+
+ /* print next node */
+ bufused += sprintf(buffer + bufused, "/%s%s%s", mod ? mod->name : "", mod ? ":" : "", iter->schema->name);
+
+ switch (iter->schema->nodetype) {
+ case LYS_LIST:
+ if (iter->schema->flags & LYS_KEYLESS) {
+ /* print its position */
+ rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
+ } else {
+ /* print all list keys in predicates */
+ rc = lyd_path_list_predicate(iter, &buffer, &buflen, &bufused, is_static);
+ }
+ break;
+ case LYS_LEAFLIST:
+ if (iter->schema->flags & LYS_CONFIG_W) {
+ /* print leaf-list value */
+ rc = lyd_path_leaflist_predicate(iter, &buffer, &buflen, &bufused, is_static);
+ } else {
+ /* print its position */
+ rc = lyd_path_position_predicate(iter, &buffer, &buflen, &bufused, is_static);
+ }
+ break;
+ default:
+ /* nothing to print more */
+ rc = LY_SUCCESS;
+ break;
+ }
+ if (rc != LY_SUCCESS) {
+ break;
+ }
+
+ --i;
+ }
+ break;
+ }
+
+ return buffer;
+}
diff --git a/src/tree_data.h b/src/tree_data.h
index c0dc1f0..41f8d01 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -743,6 +743,44 @@
*/
const struct lyd_node_term *lyd_target(struct lyd_value_path *path, const struct lyd_node **trees);
+/**
+ * @brief Get string value of a term data \p node.
+ *
+ * @param[in] node Data tree node with the value.
+ * @param[out] dynamic Whether the string value was dynmically allocated.
+ * @return String value of @p node, if @p dynamic, needs to be freed.
+ */
+const char *lyd_value2str(const struct lyd_node_term *node, int *dynamic);
+
+/**
+ * @brief Get string value of an attribute \p attr.
+ *
+ * @param[in] attr Attribute with the value.
+ * @param[out] dynamic Whether the string value was dynmically allocated.
+ * @return String value of @p attr, if @p dynamic, needs to be freed.
+ */
+const char *lyd_attr2str(const struct lyd_attr *attr, int *dynamic);
+
+/**
+ * @brief Types of the different data paths.
+ */
+typedef enum {
+ LYD_PATH_LOG /**< Descriptive path format used in log messages */
+} LYD_PATH_TYPE;
+
+/**
+ * @brief Generate path of the given node in the requested format.
+ *
+ * @param[in] node Schema path of this node will be generated.
+ * @param[in] pathtype Format of the path to generate.
+ * @param[in,out] buffer Prepared buffer of the @p buflen length to store the generated path.
+ * If NULL, memory for the complete path is allocated.
+ * @param[in] buflen Size of the provided @p buffer.
+ * @return NULL in case of memory allocation error, path of the node otherwise.
+ * In case the @p buffer is NULL, the returned string is dynamically allocated and caller is responsible to free it.
+ */
+char *lyd_path(const struct lyd_node *node, LYD_PATH_TYPE pathtype, char *buffer, size_t buflen);
+
#ifdef __cplusplus
}
#endif