logger CHANGE support for validation errors - work in progress
diff --git a/src/log.c b/src/log.c
index d61895e..d1a6dd3 100644
--- a/src/log.c
+++ b/src/log.c
@@ -30,6 +30,9 @@
volatile int ly_log_dbg_groups = 0;
#endif
+/* how many bytes add when enlarging buffers */
+#define LY_BUF_STEP 128
+
API LY_VECODE
ly_vecode(const struct ly_ctx *ctx)
{
@@ -369,6 +372,259 @@
va_end(ap);
}
+static LY_ERR
+ly_vlog_build_path_print(const struct ly_ctx *ctx, char **path, uint16_t *index, const char *str, uint16_t str_len, uint16_t *length)
+{
+ void *mem;
+ uint16_t step;
+
+ if ((*index) < str_len) {
+ /* enlarge buffer */
+ step = (str_len < LY_BUF_STEP) ? LY_BUF_STEP : str_len;
+ mem = realloc(*path, *length + *index + step + 1);
+ LY_CHECK_ERR_RET(!mem, LOGMEM(ctx), LY_EMEM);
+ *path = mem;
+
+ /* move data, lengths */
+ memmove(&(*path)[*index + step], &(*path)[*index], *length);
+ (*index) += step;
+ }
+
+ (*index) -= str_len;
+ memcpy(&(*path)[*index], str, str_len);
+ *length += str_len;
+
+ return 0;
+}
+
+LY_ERR
+ly_vlog_build_path(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const void *elem, char **path, int UNUSED(schema_all_prefixes))
+{
+ uint16_t length, index;
+ size_t len;
+ LY_ERR rc = LY_SUCCESS;
+
+ length = 0;
+ *path = malloc(1);
+ LY_CHECK_ERR_RET(!(*path), LOGMEM(ctx), LY_EMEM);
+ index = 0;
+
+ while (elem) {
+ switch (elem_type) {
+ case LY_VLOG_LYS:
+ /* TODO */
+ break;
+ case LY_VLOG_LYD:
+#if 0 /* TODO when data tree present */
+ name = ((struct lyd_node *)elem)->schema->name;
+ if (!((struct lyd_node *)elem)->parent ||
+ lyd_node_module((struct lyd_node *)elem) != lyd_node_module(((struct lyd_node *)elem)->parent)) {
+ prefix = lyd_node_module((struct lyd_node *)elem)->name;
+ } else {
+ prefix = NULL;
+ }
+
+ /* handle predicates (keys) in case of lists */
+ if (((struct lyd_node *)elem)->schema->nodetype == LYS_LIST) {
+ dlist = (struct lyd_node *)elem;
+ slist = (struct lys_node_list *)((struct lyd_node *)elem)->schema;
+ if (slist->keys_size) {
+ /* schema list with keys - use key values in predicates */
+ for (i = slist->keys_size - 1; i > -1; i--) {
+ LY_TREE_FOR(dlist->child, diter) {
+ if (diter->schema == (struct lys_node *)slist->keys[i]) {
+ break;
+ }
+ }
+ if (diter && ((struct lyd_node_leaf_list *)diter)->value_str) {
+ if (strchr(((struct lyd_node_leaf_list *)diter)->value_str, '\'')) {
+ val_start = "=\"";
+ val_end = "\"]";
+ } else {
+ val_start = "='";
+ val_end = "']";
+ }
+
+ /* print value */
+ if (ly_vlog_build_path_print(path, &index, val_end, 2, &length)) {
+ return -1;
+ }
+ len = strlen(((struct lyd_node_leaf_list *)diter)->value_str);
+ if (ly_vlog_build_path_print(path, &index,
+ ((struct lyd_node_leaf_list *)diter)->value_str, len, &length)) {
+ return -1;
+ }
+
+ /* print schema name */
+ if (ly_vlog_build_path_print(path, &index, val_start, 2, &length)) {
+ return -1;
+ }
+ len = strlen(diter->schema->name);
+ if (ly_vlog_build_path_print(path, &index, diter->schema->name, len, &length)) {
+ return -1;
+ }
+
+ if (lyd_node_module(dlist) != lyd_node_module(diter)) {
+ if (ly_vlog_build_path_print(path, &index, ":", 1, &length)) {
+ return -1;
+ }
+ len = strlen(lyd_node_module(diter)->name);
+ if (ly_vlog_build_path_print(path, &index, lyd_node_module(diter)->name, len, &length)) {
+ return -1;
+ }
+ }
+
+ if (ly_vlog_build_path_print(path, &index, "[", 1, &length)) {
+ return -1;
+ }
+ }
+ }
+ } else {
+ /* schema list without keys - use instance position */
+ i = j = lyd_list_pos(dlist);
+ len = 1;
+ while (j > 9) {
+ ++len;
+ j /= 10;
+ }
+
+ if (ly_vlog_build_path_print(path, &index, "]", 1, &length)) {
+ return -1;
+ }
+
+ str = malloc(len + 1);
+ LY_CHECK_ERR_RETURN(!str, LOGMEM(NULL), -1);
+ sprintf(str, "%d", i);
+
+ if (ly_vlog_build_path_print(path, &index, str, len, &length)) {
+ free(str);
+ return -1;
+ }
+ free(str);
+
+ if (ly_vlog_build_path_print(path, &index, "[", 1, &length)) {
+ return -1;
+ }
+ }
+ } else if (((struct lyd_node *)elem)->schema->nodetype == LYS_LEAFLIST &&
+ ((struct lyd_node_leaf_list *)elem)->value_str) {
+ if (strchr(((struct lyd_node_leaf_list *)elem)->value_str, '\'')) {
+ val_start = "[.=\"";
+ val_end = "\"]";
+ } else {
+ val_start = "[.='";
+ val_end = "']";
+ }
+
+ if (ly_vlog_build_path_print(path, &index, val_end, 2, &length)) {
+ return -1;
+ }
+ len = strlen(((struct lyd_node_leaf_list *)elem)->value_str);
+ if (ly_vlog_build_path_print(path, &index, ((struct lyd_node_leaf_list *)elem)->value_str, len, &length)) {
+ return -1;
+ }
+ if (ly_vlog_build_path_print(path, &index, val_start, 4, &length)) {
+ return -1;
+ }
+ }
+
+ /* check if it is yang-data top element */
+ if (!((struct lyd_node *)elem)->parent) {
+ ext_name = lyp_get_yang_data_template_name(elem);
+ if (ext_name) {
+ if (ly_vlog_build_path_print(path, &index, name, strlen(name), &length)) {
+ return -1;
+ }
+ if (ly_vlog_build_path_print(path, &index, "/", 1, &length)) {
+ return -1;
+ }
+ yang_data_extension = 1;
+ name = ext_name;
+ }
+ }
+
+ elem = ((struct lyd_node *)elem)->parent;
+ break;
+#endif
+ case LY_VLOG_STR:
+ len = strlen((const char *)elem);
+ rc = ly_vlog_build_path_print(ctx, path, &index, (const char *)elem, len, &length);
+ LY_CHECK_RET(rc != LY_SUCCESS, rc);
+ goto success;
+ case LY_VLOG_LINE:
+
+ goto success;
+ default:
+ /* shouldn't be here */
+ LOGINT_RET(ctx);
+ }
+
+#if 0 /* TODO when data/schema tree present */
+ if (name) {
+ if (ly_vlog_build_path_print(ctx, path, &index, name, strlen(name), &length)) {
+ return -1;
+ }
+ if (prefix) {
+ if (yang_data_extension && ly_vlog_build_path_print(path, &index, "#", 1, &length)) {
+ return -1;
+ }
+ if (ly_vlog_build_path_print(ctx, path, &index, ":", 1, &length)) {
+ return -1;
+ }
+ if (ly_vlog_build_path_print(ctx, path, &index, prefix, strlen(prefix), &length)) {
+ return -1;
+ }
+ }
+ }
+ if (ly_vlog_build_path_print(ctx, path, &index, "/", 1, &length)) {
+ return -1;
+ }
+ if ((elem_type == LY_VLOG_LYS) && !elem && sparent && (sparent->nodetype == LYS_AUGMENT)) {
+ len = strlen(((struct lys_node_augment *)sparent)->target_name);
+ if (ly_vlog_build_path_print(ctx, path, &index, ((struct lys_node_augment *)sparent)->target_name, len, &length)) {
+ return -1;
+ }
+ }
+#endif
+ }
+
+success:
+ memmove(*path, (*path) + index, length);
+ (*path)[length] = '\0';
+ return LY_SUCCESS;
+}
+
+void
+ly_vlog(const struct ly_ctx *ctx, enum LY_VLOG_ELEM elem_type, const void *elem, LY_VECODE code, const char *format, ...)
+{
+ va_list ap;
+ char* path = NULL;
+ const struct ly_err_item *first;
+
+ if (path_flag && (elem_type != LY_VLOG_NONE)) {
+ if (elem_type == LY_VLOG_PREV) {
+ /* use previous path */
+ first = ly_err_first(ctx);
+ if (first && first->prev->path) {
+ path = strdup(first->prev->path);
+ }
+ } else {
+ /* print path */
+ if (!elem) {
+ /* top-level */
+ path = strdup("/");
+ } else {
+ ly_vlog_build_path(ctx, elem_type, elem, &path, 0);
+ }
+ }
+ }
+
+ va_start(ap, format);
+ log_vprintf(ctx, LY_LLERR, LY_EVALID, code, path, format, ap);
+ /* path is spent and should not be freed! */
+ va_end(ap);
+}
+
API void
ly_err_print(struct ly_err_item *eitem)
{