diff options
Diffstat (limited to '')
-rw-r--r-- | src/path.c | 512 |
1 files changed, 404 insertions, 108 deletions
@@ -3,7 +3,7 @@ * @author Michal Vasko <mvasko@cesnet.cz> * @brief Path functions * - * Copyright (c) 2020 CESNET, z.s.p.o. + * Copyright (c) 2020 - 2023 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. @@ -11,6 +11,9 @@ * * https://opensource.org/licenses/BSD-3-Clause */ + +#define _GNU_SOURCE + #include "path.h" #include <assert.h> @@ -45,7 +48,7 @@ */ static LY_ERR ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lyxp_expr *exp, - uint32_t *tok_idx, uint8_t prefix, uint8_t pred) + uint32_t *tok_idx, uint16_t prefix, uint16_t pred) { LY_ERR ret = LY_SUCCESS; struct ly_set *set = NULL; @@ -106,8 +109,19 @@ ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_no /* '=' */ LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error); - /* Literal or Number */ - LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error); + /* fill repeat */ + exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]); + LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup); + exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY; + + /* Literal, Number, or VariableReference */ + if (lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_LITERAL) && + lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_NUMBER) && + lyxp_next_token(NULL, exp, tok_idx, LYXP_TOKEN_VARREF)) { + /* error */ + lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL); + goto token_error; + } /* ']' */ LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_BRACK2), token_error); @@ -121,6 +135,11 @@ ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_no /* '=' */ LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error); + /* fill repeat */ + exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]); + LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup); + exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY; + /* Literal or Number */ LY_CHECK_GOTO(lyxp_next_token2(ctx, exp, tok_idx, LYXP_TOKEN_LITERAL, LYXP_TOKEN_NUMBER), token_error); @@ -178,6 +197,11 @@ ly_path_check_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_no /* '=' */ LY_CHECK_GOTO(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_OPER_EQUAL), token_error); + /* fill repeat */ + exp->repeat[*tok_idx - 2] = calloc(2, sizeof *exp->repeat[*tok_idx]); + LY_CHECK_ERR_GOTO(!exp->repeat[*tok_idx - 2], LOGMEM(NULL); ret = LY_EMEM, cleanup); + exp->repeat[*tok_idx - 2][0] = LYXP_EXPR_EQUALITY; + /* FuncName */ LY_CHECK_GOTO(lyxp_check_token(ctx, exp, *tok_idx, LYXP_TOKEN_FUNCNAME), token_error); if ((exp->tok_len[*tok_idx] != ly_strlen_const("current")) || @@ -240,45 +264,121 @@ token_error: return LY_EVALID; } +/** + * @brief Parse deref XPath function and perform all additional checks. + * + * @param[in] ctx libyang context. + * @param[in] ctx_node Optional context node, used for logging. + * @param[in] exp Parsed path. + * @param[in,out] tok_idx Index in @p exp, is adjusted. + * @return LY_ERR value. + */ +static LY_ERR +ly_path_parse_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lyxp_expr *exp, + uint32_t *tok_idx) +{ + size_t arg_len; + uint32_t begin_token, end_token; + struct lyxp_expr *arg_expr = NULL; + + /* mandatory FunctionName */ + LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_FUNCNAME), LY_EVALID); + if (!strncmp(&exp->expr[exp->tok_pos[*tok_idx]], "deref", 5)) { + LOGVAL(ctx, LYVE_XPATH, "Unexpected XPath function \"%.*s\" in path, expected \"deref(...)\"", + exp->tok_len[*tok_idx], exp->expr + exp->tok_pos[*tok_idx]); + return LY_EVALID; + } + + /* mandatory '(' */ + LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR1), LY_EVALID); + begin_token = *tok_idx; + + /* count tokens till ')' */ + while (lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_PAR2) && *tok_idx < exp->used) { + /* emebedded functions are not allowed */ + if (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_FUNCNAME)) { + LOGVAL(ctx, LYVE_XPATH, "Embedded function XPath function inside deref function within the path" + "is not allowed"); + return LY_EVALID; + } + + (*tok_idx)++; + } + + /* mandatory ')' */ + LY_CHECK_RET(lyxp_next_token(ctx, exp, tok_idx, LYXP_TOKEN_PAR2), LY_EVALID); + end_token = *tok_idx - 1; + + /* parse the path of deref argument */ + arg_len = exp->tok_pos[end_token] - exp->tok_pos[begin_token]; + LY_CHECK_RET(ly_path_parse(ctx, ctx_node, &exp->expr[exp->tok_pos[begin_token]], arg_len, 1, + LY_PATH_BEGIN_EITHER, LY_PATH_PREFIX_OPTIONAL, LY_PATH_PRED_LEAFREF, &arg_expr), LY_EVALID); + lyxp_expr_free(ctx, arg_expr); + + return LY_SUCCESS; +} + LY_ERR ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *str_path, size_t path_len, - ly_bool lref, uint8_t begin, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr) + ly_bool lref, uint16_t begin, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr) { LY_ERR ret = LY_SUCCESS; struct lyxp_expr *exp = NULL; uint32_t tok_idx, cur_len; const char *cur_node, *prev_prefix = NULL, *ptr; + ly_bool is_abs; assert((begin == LY_PATH_BEGIN_ABSOLUTE) || (begin == LY_PATH_BEGIN_EITHER)); assert((prefix == LY_PATH_PREFIX_OPTIONAL) || (prefix == LY_PATH_PREFIX_MANDATORY) || - (prefix == LY_PATH_PREFIX_STRICT_INHERIT)); + (prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT)); assert((pred == LY_PATH_PRED_KEYS) || (pred == LY_PATH_PRED_SIMPLE) || (pred == LY_PATH_PRED_LEAFREF)); LOG_LOCSET(ctx_node, NULL, NULL, NULL); - /* parse as a generic XPath expression */ - LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 1, &exp), error); + /* parse as a generic XPath expression, reparse is performed manually */ + LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error); tok_idx = 0; + /* alloc empty repeat (only '=', filled manually) */ + exp->repeat = calloc(exp->size, sizeof *exp->repeat); + LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error); + if (begin == LY_PATH_BEGIN_EITHER) { /* is the path relative? */ if (lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_OPER_PATH)) { /* relative path check specific to leafref */ if (lref) { + /* optional function 'deref..' */ + if ((ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_EXTENDED) && + !lyxp_check_token(NULL, exp, tok_idx, LYXP_TOKEN_FUNCNAME)) { + LY_CHECK_ERR_GOTO(ly_path_parse_deref(ctx, ctx_node, exp, &tok_idx), ret = LY_EVALID, error); + + /* '/' */ + LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, + error); + } + /* mandatory '..' */ LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_DDOT), ret = LY_EVALID, error); do { /* '/' */ - LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error); + LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, + error); /* optional '..' */ } while (!lyxp_next_token(NULL, exp, &tok_idx, LYXP_TOKEN_DDOT)); } + + is_abs = 0; + } else { + is_abs = 1; } } else { /* '/' */ LY_CHECK_ERR_GOTO(lyxp_next_token(ctx, exp, &tok_idx, LYXP_TOKEN_OPER_PATH), ret = LY_EVALID, error); + + is_abs = 1; } do { @@ -294,8 +394,8 @@ ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const ret = LY_EVALID; goto error; } - } else if (prefix == LY_PATH_PREFIX_STRICT_INHERIT) { - if (!prev_prefix) { + } else if ((prefix == LY_PATH_PREFIX_FIRST) || (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) { + if (!prev_prefix && is_abs) { /* the first node must have a prefix */ if (!strnstr(cur_node, ":", cur_len)) { LOGVAL(ctx, LYVE_XPATH, "Prefix missing for \"%.*s\" in path.", cur_len, cur_node); @@ -305,7 +405,7 @@ ly_path_parse(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const /* remember the first prefix */ prev_prefix = cur_node; - } else { + } else if (prev_prefix && (prefix == LY_PATH_PREFIX_STRICT_INHERIT)) { /* the prefix must be different, if any */ ptr = strnstr(cur_node, ":", cur_len); if (ptr) { @@ -349,7 +449,7 @@ error: LY_ERR ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const char *str_path, - size_t path_len, uint8_t prefix, uint8_t pred, struct lyxp_expr **expr) + size_t path_len, uint16_t prefix, uint16_t pred, struct lyxp_expr **expr) { LY_ERR ret = LY_SUCCESS; struct lyxp_expr *exp = NULL; @@ -360,10 +460,14 @@ ly_path_parse_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_no LOG_LOCSET(cur_node, NULL, NULL, NULL); - /* parse as a generic XPath expression */ + /* parse as a generic XPath expression, reparse is performed manually */ LY_CHECK_GOTO(ret = lyxp_expr_parse(ctx, str_path, path_len, 0, &exp), error); tok_idx = 0; + /* alloc empty repeat (only '=', filled manually) */ + exp->repeat = calloc(exp->size, sizeof *exp->repeat); + LY_CHECK_ERR_GOTO(!exp->repeat, LOGMEM(ctx); ret = LY_EMEM, error); + LY_CHECK_GOTO(ret = ly_path_check_predicate(ctx, cur_node, exp, &tok_idx, prefix, pred), error); /* trailing token check */ @@ -521,7 +625,7 @@ error: LY_ERR ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_node, const struct lys_module *cur_mod, const struct lysc_node *ctx_node, const struct lyxp_expr *expr, uint32_t *tok_idx, LY_VALUE_FORMAT format, - void *prefix_data, struct ly_path_predicate **predicates, enum ly_path_pred_type *pred_type) + void *prefix_data, struct ly_path_predicate **predicates) { LY_ERR ret = LY_SUCCESS; struct ly_path_predicate *p; @@ -533,7 +637,7 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ LOG_LOCSET(cur_node, NULL, NULL, NULL); - *pred_type = 0; + *predicates = NULL; if (lyxp_next_token(NULL, expr, tok_idx, LYXP_TOKEN_BRACK1)) { /* '[', no predicate */ @@ -565,11 +669,7 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ } ++(*tok_idx); - if (!*pred_type) { - /* new predicate */ - *pred_type = LY_PATH_PREDTYPE_LIST; - } - assert(*pred_type == LY_PATH_PREDTYPE_LIST); + /* new predicate */ LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup); p->key = key; @@ -577,27 +677,38 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL); ++(*tok_idx); - /* Literal or Number */ - assert((expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) || (expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER)); - if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) { - /* skip quotes */ - val = expr->expr + expr->tok_pos[*tok_idx] + 1; - val_len = expr->tok_len[*tok_idx] - 2; + /* Literal, Number, or VariableReference */ + if (expr->tokens[*tok_idx] == LYXP_TOKEN_VARREF) { + /* store the variable name */ + p->variable = strndup(expr->expr + expr->tok_pos[*tok_idx], expr->tok_len[*tok_idx]); + LY_CHECK_ERR_GOTO(!p->variable, LOGMEM(ctx); ret = LY_EMEM, cleanup); + + p->type = LY_PATH_PREDTYPE_LIST_VAR; + ++(*tok_idx); } else { - val = expr->expr + expr->tok_pos[*tok_idx]; - val_len = expr->tok_len[*tok_idx]; - } + if (expr->tokens[*tok_idx] == LYXP_TOKEN_LITERAL) { + /* skip quotes */ + val = expr->expr + expr->tok_pos[*tok_idx] + 1; + val_len = expr->tok_len[*tok_idx] - 2; + } else { + assert(expr->tokens[*tok_idx] == LYXP_TOKEN_NUMBER); + val = expr->expr + expr->tok_pos[*tok_idx]; + val_len = expr->tok_len[*tok_idx]; + } - /* store the value */ - LOG_LOCSET(key, NULL, NULL, NULL); - ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, NULL, format, - prefix_data, LYD_HINT_DATA, key, NULL); - LOG_LOCBACK(key ? 1 : 0, 0, 0, 0); - LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup); - ++(*tok_idx); + /* store the value */ + LOG_LOCSET(key, NULL, NULL, NULL); + ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaf *)key)->type, val, val_len, 0, NULL, + format, prefix_data, LYD_HINT_DATA, key, NULL); + LOG_LOCBACK(key ? 1 : 0, 0, 0, 0); + LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup); + + /* "allocate" the type to avoid problems when freeing the value after the type was freed */ + LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount); - /* "allocate" the type to avoid problems when freeing the value after the type was freed */ - LY_ATOMIC_INC_BARRIER(((struct lysc_type *)p->value.realtype)->refcount); + p->type = LY_PATH_PREDTYPE_LIST; + ++(*tok_idx); + } /* ']' */ assert(expr->tokens[*tok_idx] == LYXP_TOKEN_BRACK2); @@ -615,7 +726,7 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ /* names (keys) are unique - it was checked when parsing */ LOGVAL(ctx, LYVE_XPATH, "Predicate missing for a key of %s \"%s\" in path.", lys_nodetype2str(ctx_node->nodetype), ctx_node->name); - ly_path_predicates_free(ctx, LY_PATH_PREDTYPE_LIST, *predicates); + ly_path_predicates_free(ctx, *predicates); *predicates = NULL; ret = LY_EVALID; goto cleanup; @@ -631,8 +742,8 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ ++(*tok_idx); /* new predicate */ - *pred_type = LY_PATH_PREDTYPE_LEAFLIST; LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup); + p->type = LY_PATH_PREDTYPE_LEAFLIST; /* '=' */ assert(expr->tokens[*tok_idx] == LYXP_TOKEN_OPER_EQUAL); @@ -651,8 +762,8 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ /* store the value */ LOG_LOCSET(ctx_node, NULL, NULL, NULL); - ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, NULL, format, - prefix_data, LYD_HINT_DATA, ctx_node, NULL); + ret = lyd_value_store(ctx, &p->value, ((struct lysc_node_leaflist *)ctx_node)->type, val, val_len, 0, NULL, + format, prefix_data, LYD_HINT_DATA, ctx_node, NULL); LOG_LOCBACK(ctx_node ? 1 : 0, 0, 0, 0); LY_CHECK_ERR_GOTO(ret, p->value.realtype = NULL, cleanup); ++(*tok_idx); @@ -678,8 +789,8 @@ ly_path_compile_predicate(const struct ly_ctx *ctx, const struct lysc_node *cur_ } /* new predicate */ - *pred_type = LY_PATH_PREDTYPE_POSITION; LY_ARRAY_NEW_GOTO(ctx, *predicates, p, ret, cleanup); + p->type = LY_PATH_PREDTYPE_POSITION; /* syntax was already checked */ p->position = strtoull(expr->expr + expr->tok_pos[*tok_idx], (char **)&val, LY_BASE_DEC); @@ -820,6 +931,197 @@ cleanup: } /** + * @brief Duplicate ly_path_predicate structure. + * + * @param[in] ctx libyang context. + * @param[in] pred The array of path predicates. + * @param[out] dup Duplicated predicates. + * @return LY_ERR value. + */ +static LY_ERR +ly_path_dup_predicates(const struct ly_ctx *ctx, const struct ly_path_predicate *pred, struct ly_path_predicate **dup) +{ + LY_ARRAY_COUNT_TYPE u; + + if (!pred) { + return LY_SUCCESS; + } + + LY_ARRAY_CREATE_RET(ctx, *dup, LY_ARRAY_COUNT(pred), LY_EMEM); + LY_ARRAY_FOR(pred, u) { + LY_ARRAY_INCREMENT(*dup); + (*dup)[u].type = pred->type; + + switch (pred[u].type) { + case LY_PATH_PREDTYPE_POSITION: + /* position-predicate */ + (*dup)[u].position = pred[u].position; + break; + case LY_PATH_PREDTYPE_LIST: + case LY_PATH_PREDTYPE_LEAFLIST: + /* key-predicate or leaf-list-predicate */ + (*dup)[u].key = pred[u].key; + pred[u].value.realtype->plugin->duplicate(ctx, &pred[u].value, &(*dup)[u].value); + LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred[u].value.realtype)->refcount); + break; + case LY_PATH_PREDTYPE_LIST_VAR: + /* key-predicate with a variable */ + (*dup)[u].key = pred[u].key; + (*dup)[u].variable = strdup(pred[u].variable); + break; + } + } + + return LY_SUCCESS; +} + +/** + * @brief Appends path elements from source to destination array + * + * @param[in] ctx libyang context. + * @param[in] src The source path + * @param[in,out] dst The destination path + * @return LY_ERR value. + */ +static LY_ERR +ly_path_append(const struct ly_ctx *ctx, const struct ly_path *src, struct ly_path **dst) +{ + LY_ERR ret = LY_SUCCESS; + LY_ARRAY_COUNT_TYPE u; + struct ly_path *p; + + if (!src) { + return LY_SUCCESS; + } + + LY_ARRAY_CREATE_RET(ctx, *dst, LY_ARRAY_COUNT(src), LY_EMEM); + LY_ARRAY_FOR(src, u) { + LY_ARRAY_NEW_GOTO(ctx, *dst, p, ret, cleanup); + p->node = src[u].node; + p->ext = src[u].ext; + LY_CHECK_GOTO(ret = ly_path_dup_predicates(ctx, src[u].predicates, &p->predicates), cleanup); + } + +cleanup: + return ret; +} + +/** + * @brief Compile deref XPath function into ly_path structure. + * + * @param[in] ctx libyang context. + * @param[in] ctx_node Optional context node, mandatory of @p lref. + * @param[in] top_ext Extension instance containing the definition of the data being created. It is used to find + * the top-level node inside the extension instance instead of a module. Note that this is the case not only if + * the @p ctx_node is NULL, but also if the relative path starting in @p ctx_node reaches the document root + * via double dots. + * @param[in] expr Parsed path. + * @param[in] oper Oper option (@ref path_oper_options). + * @param[in] target Target option (@ref path_target_options). + * @param[in] format Format of the path. + * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix). + * @param[in,out] tok_idx Index in @p exp, is adjusted. + * @param[out] path Compiled path. + * @return LY_ERR value. + */ +static LY_ERR +ly_path_compile_deref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, + const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint16_t oper, uint16_t target, + LY_VALUE_FORMAT format, void *prefix_data, uint32_t *tok_idx, struct ly_path **path) +{ + LY_ERR ret = LY_SUCCESS; + struct lyxp_expr expr2; + struct ly_path *path2 = NULL; + const struct lysc_node *node2; + const struct lysc_node_leaf *deref_leaf_node; + const struct lysc_type_leafref *lref; + uint32_t begin_token; + + *path = NULL; + + /* properly parsed path must always starts with 'deref' and '(' */ + assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_FUNCNAME)); + assert(!strncmp(&expr->expr[expr->tok_pos[*tok_idx]], "deref", 5)); + (*tok_idx)++; + assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR1)); + (*tok_idx)++; + begin_token = *tok_idx; + + /* emebedded functions were already identified count tokens till ')' */ + while (lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2) && (*tok_idx < expr->used)) { + (*tok_idx)++; + } + + /* properly parsed path must have ')' within the tokens */ + assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2)); + + /* prepare expr representing just deref arg */ + expr2.tokens = &expr->tokens[begin_token]; + expr2.tok_pos = &expr->tok_pos[begin_token]; + expr2.tok_len = &expr->tok_len[begin_token]; + expr2.repeat = &expr->repeat[begin_token]; + expr2.used = *tok_idx - begin_token; + expr2.size = expr->size - begin_token; + expr2.expr = expr->expr; + + /* compile just deref arg, append it to the path and find dereferenced lref for next operations */ + LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, ctx_node, top_ext, &expr2, oper, target, format, prefix_data, + &path2), cleanup); + node2 = path2[LY_ARRAY_COUNT(path2) - 1].node; + if ((node2->nodetype != LYS_LEAF) && (node2->nodetype != LYS_LEAFLIST)) { + LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leaf nor leaflist", node2->name); + ret = LY_EVALID; + goto cleanup; + } + deref_leaf_node = (const struct lysc_node_leaf *)node2; + if (deref_leaf_node->type->basetype != LY_TYPE_LEAFREF) { + LOGVAL(ctx, LYVE_XPATH, "The deref function target node \"%s\" is not leafref", node2->name); + ret = LY_EVALID; + goto cleanup; + } + lref = (const struct lysc_type_leafref *)deref_leaf_node->type; + LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup); + ly_path_free(ctx, path2); + path2 = NULL; + + /* compile dereferenced leafref expression and append it to the path */ + LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, node2, top_ext, lref->path, oper, target, format, prefix_data, + &path2), cleanup); + node2 = path2[LY_ARRAY_COUNT(path2) - 1].node; + LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup); + ly_path_free(ctx, path2); + path2 = NULL; + + /* properly parsed path must always continue with ')' and '/' */ + assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_PAR2)); + (*tok_idx)++; + assert(!lyxp_check_token(NULL, expr, *tok_idx, LYXP_TOKEN_OPER_PATH)); + (*tok_idx)++; + + /* prepare expr representing rest of the path after deref */ + expr2.tokens = &expr->tokens[*tok_idx]; + expr2.tok_pos = &expr->tok_pos[*tok_idx]; + expr2.tok_len = &expr->tok_len[*tok_idx]; + expr2.repeat = &expr->repeat[*tok_idx]; + expr2.used = expr->used - *tok_idx; + expr2.size = expr->size - *tok_idx; + expr2.expr = expr->expr; + + /* compile rest of the path and append it to the path */ + LY_CHECK_GOTO(ret = ly_path_compile_leafref(ctx, node2, top_ext, &expr2, oper, target, format, prefix_data, &path2), + cleanup); + LY_CHECK_GOTO(ret = ly_path_append(ctx, path2, path), cleanup); + +cleanup: + ly_path_free(ctx, path2); + if (ret) { + ly_path_free(ctx, *path); + *path = NULL; + } + return ret; +} + +/** * @brief Compile path into ly_path structure. Any predicates of a leafref are only checked, not compiled. * * @param[in] ctx libyang context. @@ -843,7 +1145,7 @@ cleanup: */ static LY_ERR _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node, - const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, ly_bool lref, uint8_t oper, uint8_t target, + const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, ly_bool lref, uint16_t oper, uint16_t target, ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path) { LY_ERR ret = LY_SUCCESS; @@ -876,7 +1178,12 @@ _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, con getnext_opts = 0; } - if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) { + if (lref && (ly_ctx_get_options(ctx) & LY_CTX_LEAFREF_EXTENDED) && + (expr->tokens[tok_idx] == LYXP_TOKEN_FUNCNAME)) { + /* deref function */ + ret = ly_path_compile_deref(ctx, ctx_node, top_ext, expr, oper, target, format, prefix_data, &tok_idx, path); + goto cleanup; + } else if (expr->tokens[tok_idx] == LYXP_TOKEN_OPER_PATH) { /* absolute path */ ctx_node = NULL; @@ -940,7 +1247,7 @@ _ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, con ret = ly_path_compile_predicate_leafref(ctx_node, cur_node, expr, &tok_idx, format, prefix_data); } else { ret = ly_path_compile_predicate(ctx, cur_node, cur_mod, ctx_node, expr, &tok_idx, format, prefix_data, - &p->predicates, &p->pred_type); + &p->predicates); } LY_CHECK_GOTO(ret, cleanup); } while (!lyxp_next_token(NULL, expr, &tok_idx, LYXP_TOKEN_OPER_PATH)); @@ -971,7 +1278,7 @@ cleanup: LY_ERR ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, const struct lysc_node *ctx_node, - const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint8_t oper, uint8_t target, + const struct lysc_ext_instance *top_ext, const struct lyxp_expr *expr, uint16_t oper, uint16_t target, ly_bool limit_access_tree, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path) { return _ly_path_compile(ctx, cur_mod, ctx_node, top_ext, expr, 0, oper, target, limit_access_tree, format, @@ -980,15 +1287,15 @@ ly_path_compile(const struct ly_ctx *ctx, const struct lys_module *cur_mod, cons LY_ERR ly_path_compile_leafref(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const struct lysc_ext_instance *top_ext, - const struct lyxp_expr *expr, uint8_t oper, uint8_t target, LY_VALUE_FORMAT format, void *prefix_data, + const struct lyxp_expr *expr, uint16_t oper, uint16_t target, LY_VALUE_FORMAT format, void *prefix_data, struct ly_path **path) { return _ly_path_compile(ctx, ctx_node->module, ctx_node, top_ext, expr, 1, oper, target, 1, format, prefix_data, path); } LY_ERR -ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, LY_ARRAY_COUNT_TYPE *path_idx, - struct lyd_node **match) +ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars, + ly_bool with_opaq, LY_ARRAY_COUNT_TYPE *path_idx, struct lyd_node **match) { LY_ARRAY_COUNT_TYPE u; struct lyd_node *prev_node = NULL, *elem, *node = NULL, *target; @@ -1010,35 +1317,43 @@ ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, L } LY_ARRAY_FOR(path, u) { - switch (path[u].pred_type) { - case LY_PATH_PREDTYPE_POSITION: - /* we cannot use hashes and want an instance on a specific position */ - pos = 1; - node = NULL; - LYD_LIST_FOR_INST(start, path[u].node, elem) { - if (pos == path[u].predicates[0].position) { - node = elem; - break; + if (path[u].predicates) { + switch (path[u].predicates[0].type) { + case LY_PATH_PREDTYPE_POSITION: + /* we cannot use hashes and want an instance on a specific position */ + pos = 1; + node = NULL; + LYD_LIST_FOR_INST(start, path[u].node, elem) { + if (pos == path[u].predicates[0].position) { + node = elem; + break; + } + ++pos; } - ++pos; + break; + case LY_PATH_PREDTYPE_LEAFLIST: + /* we will use hashes to find one leaf-list instance */ + LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target)); + lyd_find_sibling_first(start, target, &node); + lyd_free_tree(target); + break; + case LY_PATH_PREDTYPE_LIST_VAR: + case LY_PATH_PREDTYPE_LIST: + /* we will use hashes to find one list instance */ + LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, vars, &target)); + lyd_find_sibling_first(start, target, &node); + lyd_free_tree(target); + break; } - break; - case LY_PATH_PREDTYPE_LEAFLIST: - /* we will use hashes to find one leaf-list instance */ - LY_CHECK_RET(lyd_create_term2(path[u].node, &path[u].predicates[0].value, &target)); - lyd_find_sibling_first(start, target, &node); - lyd_free_tree(target); - break; - case LY_PATH_PREDTYPE_LIST: - /* we will use hashes to find one list instance */ - LY_CHECK_RET(lyd_create_list(path[u].node, path[u].predicates, &target)); - lyd_find_sibling_first(start, target, &node); - lyd_free_tree(target); - break; - case LY_PATH_PREDTYPE_NONE: + } else { /* we will use hashes to find one any/container/leaf instance */ - lyd_find_sibling_val(start, path[u].node, NULL, 0, &node); - break; + if (lyd_find_sibling_val(start, path[u].node, NULL, 0, &node) && with_opaq) { + if (!lyd_find_sibling_opaq_next(start, path[u].node->name, &node) && + (lyd_node_module(node) != path[u].node->module)) { + /* non-matching opaque node */ + node = NULL; + } + } } if (!node) { @@ -1085,12 +1400,12 @@ ly_path_eval_partial(const struct ly_path *path, const struct lyd_node *start, L } LY_ERR -ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct lyd_node **match) +ly_path_eval(const struct ly_path *path, const struct lyd_node *start, const struct lyxp_var *vars, struct lyd_node **match) { LY_ERR ret; struct lyd_node *m; - ret = ly_path_eval_partial(path, start, NULL, &m); + ret = ly_path_eval_partial(path, start, vars, 0, NULL, &m); if (ret == LY_SUCCESS) { /* last node was found */ @@ -1110,7 +1425,8 @@ ly_path_eval(const struct ly_path *path, const struct lyd_node *start, struct ly LY_ERR ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path **dup) { - LY_ARRAY_COUNT_TYPE u, v; + LY_ERR ret = LY_SUCCESS; + LY_ARRAY_COUNT_TYPE u; if (!path) { return LY_SUCCESS; @@ -1120,37 +1436,15 @@ ly_path_dup(const struct ly_ctx *ctx, const struct ly_path *path, struct ly_path LY_ARRAY_FOR(path, u) { LY_ARRAY_INCREMENT(*dup); (*dup)[u].node = path[u].node; - if (path[u].predicates) { - LY_ARRAY_CREATE_RET(ctx, (*dup)[u].predicates, LY_ARRAY_COUNT(path[u].predicates), LY_EMEM); - (*dup)[u].pred_type = path[u].pred_type; - LY_ARRAY_FOR(path[u].predicates, v) { - struct ly_path_predicate *pred = &path[u].predicates[v]; - - LY_ARRAY_INCREMENT((*dup)[u].predicates); - switch (path[u].pred_type) { - case LY_PATH_PREDTYPE_POSITION: - /* position-predicate */ - (*dup)[u].predicates[v].position = pred->position; - break; - case LY_PATH_PREDTYPE_LIST: - case LY_PATH_PREDTYPE_LEAFLIST: - /* key-predicate or leaf-list-predicate */ - (*dup)[u].predicates[v].key = pred->key; - pred->value.realtype->plugin->duplicate(ctx, &pred->value, &(*dup)[u].predicates[v].value); - LY_ATOMIC_INC_BARRIER(((struct lysc_type *)pred->value.realtype)->refcount); - break; - case LY_PATH_PREDTYPE_NONE: - break; - } - } - } + (*dup)[u].ext = path[u].ext; + LY_CHECK_RET(ret = ly_path_dup_predicates(ctx, path[u].predicates, &(*dup)[u].predicates), ret); } return LY_SUCCESS; } void -ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_type, struct ly_path_predicate *predicates) +ly_path_predicates_free(const struct ly_ctx *ctx, struct ly_path_predicate *predicates) { LY_ARRAY_COUNT_TYPE u; struct lysf_ctx fctx = {.ctx = (struct ly_ctx *)ctx}; @@ -1160,9 +1454,8 @@ ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_ty } LY_ARRAY_FOR(predicates, u) { - switch (pred_type) { + switch (predicates[u].type) { case LY_PATH_PREDTYPE_POSITION: - case LY_PATH_PREDTYPE_NONE: /* nothing to free */ break; case LY_PATH_PREDTYPE_LIST: @@ -1172,6 +1465,9 @@ ly_path_predicates_free(const struct ly_ctx *ctx, enum ly_path_pred_type pred_ty lysc_type_free(&fctx, (struct lysc_type *)predicates[u].value.realtype); } break; + case LY_PATH_PREDTYPE_LIST_VAR: + free(predicates[u].variable); + break; } } LY_ARRAY_FREE(predicates); @@ -1187,7 +1483,7 @@ ly_path_free(const struct ly_ctx *ctx, struct ly_path *path) } LY_ARRAY_FOR(path, u) { - ly_path_predicates_free(ctx, path[u].pred_type, path[u].predicates); + ly_path_predicates_free(ctx, path[u].predicates); } LY_ARRAY_FREE(path); } |