blob: f86575e0fdebdeca42a81333e9c5725199bd1154 [file] [log] [blame]
Radek Krejci19a96102018-11-15 13:38:09 +01001/**
2 * @file tree_schema.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Schema tree implementation
5 *
6 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
Radek Krejci535ea9f2020-05-29 16:01:05 +020015#define _GNU_SOURCE
Radek Krejci19a96102018-11-15 13:38:09 +010016
Radek Krejcie7b95092019-05-15 11:03:07 +020017#include <assert.h>
Radek Krejci19a96102018-11-15 13:38:09 +010018#include <ctype.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include <stddef.h>
20#include <stdint.h>
Radek Krejci19a96102018-11-15 13:38:09 +010021#include <stdio.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include <stdlib.h>
23#include <string.h>
Radek Krejci19a96102018-11-15 13:38:09 +010024
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include "common.h"
Michal Vasko5aa44c02020-06-29 11:47:02 +020026#include "compat.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "context.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "dict.h"
29#include "log.h"
Radek Krejcif0e1ba52020-05-22 15:14:35 +020030#include "parser.h"
Radek Krejcica376bd2020-06-11 16:04:06 +020031#include "parser_schema.h"
Michal Vasko69730152020-10-09 16:30:07 +020032#include "path.h"
Radek Krejci0935f412019-08-20 16:15:18 +020033#include "plugins_exts.h"
Radek Krejci0935f412019-08-20 16:15:18 +020034#include "plugins_exts_internal.h"
Michal Vasko69730152020-10-09 16:30:07 +020035#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020036#include "set.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020037#include "tree.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020038#include "tree_data.h"
Michal Vasko7c8439f2020-08-05 13:25:19 +020039#include "tree_data_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020040#include "tree_schema.h"
Radek Krejci19a96102018-11-15 13:38:09 +010041#include "tree_schema_internal.h"
42#include "xpath.h"
43
Michal Vasko5fe75f12020-03-02 13:52:37 +010044static LY_ERR lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext,
Radek Krejci0f969882020-08-21 16:56:47 +020045 void *parent, LYEXT_PARENT parent_type, const struct lys_module *ext_mod);
Michal Vasko5fe75f12020-03-02 13:52:37 +010046
Michal Vasko7f45cf22020-10-01 12:49:44 +020047static LY_ERR lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname);
48
Radek Krejci19a96102018-11-15 13:38:09 +010049/**
Radek Krejci90d4e922020-10-12 15:55:33 +020050 * @defgroup scflags Schema compile flags
51 *
52 * Flags are currently used only internally - the compilation process does not have a public interface and it is
53 * integrated in the schema parsers. The current options set does not make sense for public used, but it can be a way
54 * to modify behavior of the compilation process in future.
55 *
56 * @{
57 */
58#define LYS_COMPILE_RPC_INPUT LYS_CONFIG_W /**< Internal option when compiling schema tree of RPC/action input */
59#define LYS_COMPILE_RPC_OUTPUT LYS_CONFIG_R /**< Internal option when compiling schema tree of RPC/action output */
60#define LYS_COMPILE_RPC_MASK LYS_CONFIG_MASK /**< mask for the internal RPC options */
61#define LYS_COMPILE_NOTIFICATION 0x08 /**< Internal option when compiling schema tree of Notification */
62
63#define LYS_COMPILE_GROUPING 0x10 /** Compiling (validation) of a non-instantiated grouping.
64 In this case not all the restrictions are checked since they can be valid only
65 in the real placement of the grouping. TODO - what specifically is not done */
66/** @} scflags */
67
68/**
Radek Krejci19a96102018-11-15 13:38:09 +010069 * @brief Duplicate string into dictionary
70 * @param[in] CTX libyang context of the dictionary.
71 * @param[in] ORIG String to duplicate.
72 * @param[out] DUP Where to store the result.
73 */
Radek Krejci011e4aa2020-09-04 15:22:31 +020074#define DUP_STRING(CTX, ORIG, DUP, RET) if (ORIG) {RET = lydict_insert(CTX, ORIG, 0, &DUP);}
75
76#define DUP_STRING_GOTO(CTX, ORIG, DUP, RET, GOTO) if (ORIG) {LY_CHECK_GOTO(RET = lydict_insert(CTX, ORIG, 0, &DUP), GOTO);}
Radek Krejci19a96102018-11-15 13:38:09 +010077
Michal Vasko7f45cf22020-10-01 12:49:44 +020078#define DUP_ARRAY(CTX, ORIG_ARRAY, NEW_ARRAY, DUP_FUNC) \
79 if (ORIG_ARRAY) { \
80 LY_ARRAY_COUNT_TYPE u; \
81 LY_ARRAY_CREATE_RET(CTX, NEW_ARRAY, LY_ARRAY_COUNT(ORIG_ARRAY), LY_EMEM); \
82 LY_ARRAY_FOR(ORIG_ARRAY, u) { \
83 LY_ARRAY_INCREMENT(NEW_ARRAY); \
84 LY_CHECK_RET(DUP_FUNC(CTX, &(NEW_ARRAY)[u], &(ORIG_ARRAY)[u])); \
85 } \
86 }
87
Radek Krejciec4da802019-05-02 13:02:41 +020088#define COMPILE_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, ITER, FUNC, RET, GOTO) \
Radek Krejci19a96102018-11-15 13:38:09 +010089 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +020090 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
91 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
92 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejci19a96102018-11-15 13:38:09 +010093 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +020094 RET = FUNC(CTX, &(ARRAY_P)[ITER], &(ARRAY_C)[ITER + __array_offset]); \
Radek Krejcid05cbd92018-12-05 14:26:40 +010095 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
96 } \
97 }
98
Michal Vasko7f45cf22020-10-01 12:49:44 +020099#define COMPILE_OP_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, PARENT, ITER, FUNC, USES_STATUS, RET, GOTO) \
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100100 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200101 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
102 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
103 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100104 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200105 RET = FUNC(CTX, &(ARRAY_P)[ITER], PARENT, &(ARRAY_C)[ITER + __array_offset], USES_STATUS); \
Michal Vasko7f45cf22020-10-01 12:49:44 +0200106 if (RET == LY_EDENIED) { \
107 LY_ARRAY_DECREMENT(ARRAY_C); \
108 } else if (RET != LY_SUCCESS) { \
109 goto GOTO; \
110 } \
Radek Krejci6eeb58f2019-02-22 16:29:37 +0100111 } \
112 }
113
Radek Krejci0935f412019-08-20 16:15:18 +0200114#define COMPILE_EXTS_GOTO(CTX, EXTS_P, EXT_C, PARENT, PARENT_TYPE, RET, GOTO) \
115 if (EXTS_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200116 LY_ARRAY_CREATE_GOTO((CTX)->ctx, EXT_C, LY_ARRAY_COUNT(EXTS_P), RET, GOTO); \
117 for (LY_ARRAY_COUNT_TYPE __exts_iter = 0, __array_offset = LY_ARRAY_COUNT(EXT_C); __exts_iter < LY_ARRAY_COUNT(EXTS_P); ++__exts_iter) { \
Radek Krejci0935f412019-08-20 16:15:18 +0200118 LY_ARRAY_INCREMENT(EXT_C); \
Michal Vasko8d544252020-03-02 10:19:52 +0100119 RET = lys_compile_ext(CTX, &(EXTS_P)[__exts_iter], &(EXT_C)[__exts_iter + __array_offset], PARENT, PARENT_TYPE, NULL); \
Radek Krejci0935f412019-08-20 16:15:18 +0200120 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
121 } \
122 }
123
Radek Krejciec4da802019-05-02 13:02:41 +0200124#define COMPILE_ARRAY_UNIQUE_GOTO(CTX, ARRAY_P, ARRAY_C, ITER, FUNC, RET, GOTO) \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100125 if (ARRAY_P) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200126 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_COUNT(ARRAY_P), RET, GOTO); \
127 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
128 for (ITER = 0; ITER < LY_ARRAY_COUNT(ARRAY_P); ++ITER) { \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100129 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200130 RET = FUNC(CTX, &(ARRAY_P)[ITER], ARRAY_C, &(ARRAY_C)[ITER + __array_offset]); \
Radek Krejci19a96102018-11-15 13:38:09 +0100131 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
132 } \
133 }
134
Radek Krejciec4da802019-05-02 13:02:41 +0200135#define COMPILE_MEMBER_GOTO(CTX, MEMBER_P, MEMBER_C, FUNC, RET, GOTO) \
Radek Krejci19a96102018-11-15 13:38:09 +0100136 if (MEMBER_P) { \
137 MEMBER_C = calloc(1, sizeof *(MEMBER_C)); \
138 LY_CHECK_ERR_GOTO(!(MEMBER_C), LOGMEM((CTX)->ctx); RET = LY_EMEM, GOTO); \
Radek Krejciec4da802019-05-02 13:02:41 +0200139 RET = FUNC(CTX, MEMBER_P, MEMBER_C); \
Radek Krejci19a96102018-11-15 13:38:09 +0100140 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
141 }
142
Radek Krejciec4da802019-05-02 13:02:41 +0200143#define COMPILE_MEMBER_ARRAY_GOTO(CTX, MEMBER_P, ARRAY_C, FUNC, RET, GOTO) \
Radek Krejci00b874b2019-02-12 10:54:50 +0100144 if (MEMBER_P) { \
145 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, 1, RET, GOTO); \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200146 LY_ARRAY_COUNT_TYPE __array_offset = LY_ARRAY_COUNT(ARRAY_C); \
Radek Krejci00b874b2019-02-12 10:54:50 +0100147 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejciec4da802019-05-02 13:02:41 +0200148 RET = FUNC(CTX, MEMBER_P, &(ARRAY_C)[__array_offset]); \
Radek Krejci00b874b2019-02-12 10:54:50 +0100149 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
150 }
151
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100152#define COMPILE_CHECK_UNIQUENESS_ARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100153 if (ARRAY) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200154 for (LY_ARRAY_COUNT_TYPE u__ = 0; u__ < LY_ARRAY_COUNT(ARRAY); ++u__) { \
Radek Krejci0af46292019-01-11 16:02:31 +0100155 if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__].MEMBER) == (void*)(IDENT)) { \
Radek Krejcid05cbd92018-12-05 14:26:40 +0100156 LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
157 return LY_EVALID; \
158 } \
159 } \
160 }
161
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100162#define COMPILE_CHECK_UNIQUENESS_PARRAY(CTX, ARRAY, MEMBER, EXCL, STMT, IDENT) \
163 if (ARRAY) { \
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200164 for (LY_ARRAY_COUNT_TYPE u__ = 0; u__ < LY_ARRAY_COUNT(ARRAY); ++u__) { \
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100165 if (&(ARRAY)[u__] != EXCL && (void*)((ARRAY)[u__]->MEMBER) == (void*)(IDENT)) { \
166 LOGVAL((CTX)->ctx, LY_VLOG_STR, (CTX)->path, LY_VCODE_DUPIDENT, IDENT, STMT); \
167 return LY_EVALID; \
168 } \
169 } \
170 }
171
172struct lysc_ext *
173lysc_ext_dup(struct lysc_ext *orig)
174{
175 ++orig->refcount;
176 return orig;
177}
178
Radek Krejci19a96102018-11-15 13:38:09 +0100179static struct lysc_ext_instance *
180lysc_ext_instance_dup(struct ly_ctx *ctx, struct lysc_ext_instance *orig)
181{
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100182 /* TODO - extensions, increase refcount */
Radek Krejci19a96102018-11-15 13:38:09 +0100183 (void) ctx;
184 (void) orig;
185 return NULL;
186}
187
Michal Vasko7f45cf22020-10-01 12:49:44 +0200188/**
189 * @brief Add/replace a leaf default value in unres.
190 * Can also be used for a single leaf-list default value.
191 *
192 * @param[in] ctx Compile context.
193 * @param[in] leaf Leaf with the default value.
194 * @param[in] dflt Default value to use.
195 * @return LY_ERR value.
196 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200197static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200198lysc_unres_leaf_dflt_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200199{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200200 struct lysc_unres_dflt *r = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200201 uint32_t i;
202
203 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +0200204 if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->leaf == leaf) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200205 /* just replace the default */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200206 r = ctx->dflts.objs[i];
207 lysp_qname_free(ctx->ctx, r->dflt);
208 free(r->dflt);
209 break;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200210 }
211 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200212 if (!r) {
213 /* add new unres item */
214 r = calloc(1, sizeof *r);
215 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
216 r->leaf = leaf;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200217
Radek Krejci3d92e442020-10-12 12:48:13 +0200218 LY_CHECK_RET(ly_set_add(&ctx->dflts, r, 1, NULL));
Michal Vasko7f45cf22020-10-01 12:49:44 +0200219 }
220
221 r->dflt = malloc(sizeof *r->dflt);
Michal Vaskoaf702452020-10-02 09:02:55 +0200222 LY_CHECK_GOTO(!r->dflt, error);
223 LY_CHECK_GOTO(lysp_qname_dup(ctx->ctx, r->dflt, dflt), error);
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200224
225 return LY_SUCCESS;
Michal Vaskoaf702452020-10-02 09:02:55 +0200226
227error:
228 free(r->dflt);
229 LOGMEM(ctx->ctx);
230 return LY_EMEM;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200231}
232
Radek Krejcib56c7502019-02-13 14:19:54 +0100233/**
Michal Vasko7f45cf22020-10-01 12:49:44 +0200234 * @brief Add/replace a leaf-list default value(s) in unres.
235 *
236 * @param[in] ctx Compile context.
237 * @param[in] llist Leaf-list with the default value.
238 * @param[in] dflts Sized array of the default values.
239 * @return LY_ERR value.
Radek Krejci474f9b82019-07-24 11:36:37 +0200240 */
241static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200242lysc_unres_llist_dflts_add(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflts)
Radek Krejci474f9b82019-07-24 11:36:37 +0200243{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200244 struct lysc_unres_dflt *r = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200245 uint32_t i;
246
247 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +0200248 if (((struct lysc_unres_dflt *)ctx->dflts.objs[i])->llist == llist) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200249 /* just replace the defaults */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200250 r = ctx->dflts.objs[i];
251 lysp_qname_free(ctx->ctx, r->dflt);
252 free(r->dflt);
253 r->dflt = NULL;
254 FREE_ARRAY(ctx->ctx, r->dflts, lysp_qname_free);
255 r->dflts = NULL;
256 break;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200257 }
258 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200259 if (!r) {
260 r = calloc(1, sizeof *r);
261 LY_CHECK_ERR_RET(!r, LOGMEM(ctx->ctx), LY_EMEM);
262 r->llist = llist;
Michal Vaskoba99a3e2020-08-18 15:50:05 +0200263
Radek Krejci3d92e442020-10-12 12:48:13 +0200264 LY_CHECK_RET(ly_set_add(&ctx->dflts, r, 1, NULL));
Michal Vasko7f45cf22020-10-01 12:49:44 +0200265 }
266
267 DUP_ARRAY(ctx->ctx, dflts, r->dflts, lysp_qname_dup);
Radek Krejci474f9b82019-07-24 11:36:37 +0200268
269 return LY_SUCCESS;
270}
271
Radek Krejci474f9b82019-07-24 11:36:37 +0200272static void
Michal Vasko7f45cf22020-10-01 12:49:44 +0200273lysc_unres_dflt_free(const struct ly_ctx *ctx, struct lysc_unres_dflt *r)
Radek Krejci474f9b82019-07-24 11:36:37 +0200274{
Michal Vasko7f45cf22020-10-01 12:49:44 +0200275 assert(!r->dflt || !r->dflts);
276 if (r->dflt) {
277 lysp_qname_free((struct ly_ctx *)ctx, r->dflt);
278 free(r->dflt);
279 } else {
280 FREE_ARRAY((struct ly_ctx *)ctx, r->dflts, lysp_qname_free);
Radek Krejci474f9b82019-07-24 11:36:37 +0200281 }
Michal Vasko7f45cf22020-10-01 12:49:44 +0200282 free(r);
Radek Krejci474f9b82019-07-24 11:36:37 +0200283}
284
Radek Krejci0e59c312019-08-15 15:34:15 +0200285void
Radek Krejci327de162019-06-14 12:52:07 +0200286lysc_update_path(struct lysc_ctx *ctx, struct lysc_node *parent, const char *name)
287{
288 int len;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200289 uint8_t nextlevel = 0; /* 0 - no starttag, 1 - '/' starttag, 2 - '=' starttag + '}' endtag */
Radek Krejci327de162019-06-14 12:52:07 +0200290
291 if (!name) {
292 /* removing last path segment */
293 if (ctx->path[ctx->path_len - 1] == '}') {
Michal Vaskod989ba02020-08-24 10:59:24 +0200294 for ( ; ctx->path[ctx->path_len] != '=' && ctx->path[ctx->path_len] != '{'; --ctx->path_len) {}
Radek Krejci327de162019-06-14 12:52:07 +0200295 if (ctx->path[ctx->path_len] == '=') {
296 ctx->path[ctx->path_len++] = '}';
297 } else {
298 /* not a top-level special tag, remove also preceiding '/' */
299 goto remove_nodelevel;
300 }
301 } else {
302remove_nodelevel:
Michal Vaskod989ba02020-08-24 10:59:24 +0200303 for ( ; ctx->path[ctx->path_len] != '/'; --ctx->path_len) {}
Radek Krejci327de162019-06-14 12:52:07 +0200304 if (ctx->path_len == 0) {
305 /* top-level (last segment) */
Radek Krejciacc79042019-07-25 14:14:57 +0200306 ctx->path_len = 1;
Radek Krejci327de162019-06-14 12:52:07 +0200307 }
308 }
309 /* set new terminating NULL-byte */
310 ctx->path[ctx->path_len] = '\0';
311 } else {
312 if (ctx->path_len > 1) {
Michal Vasko69730152020-10-09 16:30:07 +0200313 if (!parent && (ctx->path[ctx->path_len - 1] == '}') && (ctx->path[ctx->path_len - 2] != '\'')) {
Radek Krejci327de162019-06-14 12:52:07 +0200314 /* extension of the special tag */
315 nextlevel = 2;
316 --ctx->path_len;
317 } else {
318 /* there is already some path, so add next level */
319 nextlevel = 1;
320 }
321 } /* else the path is just initiated with '/', so do not add additional slash in case of top-level nodes */
322
323 if (nextlevel != 2) {
Michal Vasko69730152020-10-09 16:30:07 +0200324 if ((parent && (parent->module == ctx->mod)) || (!parent && (ctx->path_len > 1) && (name[0] == '{'))) {
Radek Krejci327de162019-06-14 12:52:07 +0200325 /* module not changed, print the name unprefixed */
Radek Krejci70ee9152019-07-25 11:27:27 +0200326 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s", nextlevel ? "/" : "", name);
Radek Krejci327de162019-06-14 12:52:07 +0200327 } else {
Radek Krejci70ee9152019-07-25 11:27:27 +0200328 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "%s%s:%s", nextlevel ? "/" : "", ctx->mod->name, name);
Radek Krejci327de162019-06-14 12:52:07 +0200329 }
330 } else {
Radek Krejci70ee9152019-07-25 11:27:27 +0200331 len = snprintf(&ctx->path[ctx->path_len], LYSC_CTX_BUFSIZE - ctx->path_len, "='%s'}", name);
Radek Krejci327de162019-06-14 12:52:07 +0200332 }
Radek Krejci1deb5be2020-08-26 16:43:36 +0200333 if (len >= LYSC_CTX_BUFSIZE - (int)ctx->path_len) {
Radek Krejciacc79042019-07-25 14:14:57 +0200334 /* output truncated */
335 ctx->path_len = LYSC_CTX_BUFSIZE - 1;
336 } else {
337 ctx->path_len += len;
338 }
Radek Krejci327de162019-06-14 12:52:07 +0200339 }
340}
341
342/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100343 * @brief Duplicate the compiled pattern structure.
344 *
345 * Instead of duplicating memory, the reference counter in the @p orig is increased.
346 *
347 * @param[in] orig The pattern structure to duplicate.
348 * @return The duplicated structure to use.
349 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200350static struct lysc_pattern *
Radek Krejci19a96102018-11-15 13:38:09 +0100351lysc_pattern_dup(struct lysc_pattern *orig)
352{
353 ++orig->refcount;
354 return orig;
355}
356
Radek Krejcib56c7502019-02-13 14:19:54 +0100357/**
358 * @brief Duplicate the array of compiled patterns.
359 *
360 * The sized array itself is duplicated, but the pattern structures are just shadowed by increasing their reference counter.
361 *
362 * @param[in] ctx Libyang context for logging.
363 * @param[in] orig The patterns sized array to duplicate.
364 * @return New sized array as a copy of @p orig.
365 * @return NULL in case of memory allocation error.
366 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200367static struct lysc_pattern **
Radek Krejci19a96102018-11-15 13:38:09 +0100368lysc_patterns_dup(struct ly_ctx *ctx, struct lysc_pattern **orig)
369{
Radek Krejcid05cbd92018-12-05 14:26:40 +0100370 struct lysc_pattern **dup = NULL;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200371 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +0100372
Radek Krejcib56c7502019-02-13 14:19:54 +0100373 assert(orig);
374
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200375 LY_ARRAY_CREATE_RET(ctx, dup, LY_ARRAY_COUNT(orig), NULL);
Radek Krejci19a96102018-11-15 13:38:09 +0100376 LY_ARRAY_FOR(orig, u) {
377 dup[u] = lysc_pattern_dup(orig[u]);
378 LY_ARRAY_INCREMENT(dup);
379 }
380 return dup;
381}
382
Radek Krejcib56c7502019-02-13 14:19:54 +0100383/**
384 * @brief Duplicate compiled range structure.
385 *
386 * @param[in] ctx Libyang context for logging.
387 * @param[in] orig The range structure to be duplicated.
388 * @return New compiled range structure as a copy of @p orig.
389 * @return NULL in case of memory allocation error.
390 */
Michal Vasko22df3f02020-08-24 13:29:22 +0200391struct lysc_range *
Radek Krejci19a96102018-11-15 13:38:09 +0100392lysc_range_dup(struct ly_ctx *ctx, const struct lysc_range *orig)
393{
394 struct lysc_range *dup;
395 LY_ERR ret;
396
Radek Krejcib56c7502019-02-13 14:19:54 +0100397 assert(orig);
398
Radek Krejci19a96102018-11-15 13:38:09 +0100399 dup = calloc(1, sizeof *dup);
400 LY_CHECK_ERR_RET(!dup, LOGMEM(ctx), NULL);
401 if (orig->parts) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200402 LY_ARRAY_CREATE_GOTO(ctx, dup->parts, LY_ARRAY_COUNT(orig->parts), ret, cleanup);
403 LY_ARRAY_COUNT(dup->parts) = LY_ARRAY_COUNT(orig->parts);
404 memcpy(dup->parts, orig->parts, LY_ARRAY_COUNT(dup->parts) * sizeof *dup->parts);
Radek Krejci19a96102018-11-15 13:38:09 +0100405 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200406 DUP_STRING_GOTO(ctx, orig->eapptag, dup->eapptag, ret, cleanup);
407 DUP_STRING_GOTO(ctx, orig->emsg, dup->emsg, ret, cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +0100408 dup->exts = lysc_ext_instance_dup(ctx, orig->exts);
409
410 return dup;
411cleanup:
412 free(dup);
413 (void) ret; /* set but not used due to the return type */
414 return NULL;
415}
416
Radek Krejcib56c7502019-02-13 14:19:54 +0100417/**
418 * @brief Stack for processing if-feature expressions.
419 */
Radek Krejci19a96102018-11-15 13:38:09 +0100420struct iff_stack {
Radek Krejci1deb5be2020-08-26 16:43:36 +0200421 size_t size; /**< number of items in the stack */
422 size_t index; /**< first empty item */
423 uint8_t *stack; /**< stack - array of @ref ifftokens to create the if-feature expression in prefix format */
Radek Krejci19a96102018-11-15 13:38:09 +0100424};
425
Radek Krejcib56c7502019-02-13 14:19:54 +0100426/**
427 * @brief Add @ref ifftokens into the stack.
428 * @param[in] stack The if-feature stack to use.
429 * @param[in] value One of the @ref ifftokens to store in the stack.
430 * @return LY_EMEM in case of memory allocation error
431 * @return LY_ESUCCESS if the value successfully stored.
432 */
Radek Krejci19a96102018-11-15 13:38:09 +0100433static LY_ERR
434iff_stack_push(struct iff_stack *stack, uint8_t value)
435{
436 if (stack->index == stack->size) {
437 stack->size += 4;
438 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
439 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
440 }
441 stack->stack[stack->index++] = value;
442 return LY_SUCCESS;
443}
444
Radek Krejcib56c7502019-02-13 14:19:54 +0100445/**
446 * @brief Get (and remove) the last item form the stack.
447 * @param[in] stack The if-feature stack to use.
448 * @return The value from the top of the stack.
449 */
Radek Krejci19a96102018-11-15 13:38:09 +0100450static uint8_t
451iff_stack_pop(struct iff_stack *stack)
452{
Radek Krejcib56c7502019-02-13 14:19:54 +0100453 assert(stack && stack->index);
454
Radek Krejci19a96102018-11-15 13:38:09 +0100455 stack->index--;
456 return stack->stack[stack->index];
457}
458
Radek Krejcib56c7502019-02-13 14:19:54 +0100459/**
460 * @brief Clean up the stack.
461 * @param[in] stack The if-feature stack to use.
462 */
Radek Krejci19a96102018-11-15 13:38:09 +0100463static void
464iff_stack_clean(struct iff_stack *stack)
465{
466 stack->size = 0;
467 free(stack->stack);
468}
469
Radek Krejcib56c7502019-02-13 14:19:54 +0100470/**
471 * @brief Store the @ref ifftokens (@p op) on the given position in the 2bits array
472 * (libyang format of the if-feature expression).
473 * @param[in,out] list The 2bits array to modify.
474 * @param[in] op The operand (@ref ifftokens) to store.
475 * @param[in] pos Position (0-based) where to store the given @p op.
476 */
Radek Krejci19a96102018-11-15 13:38:09 +0100477static void
Radek Krejci1deb5be2020-08-26 16:43:36 +0200478iff_setop(uint8_t *list, uint8_t op, size_t pos)
Radek Krejci19a96102018-11-15 13:38:09 +0100479{
480 uint8_t *item;
481 uint8_t mask = 3;
482
Radek Krejci19a96102018-11-15 13:38:09 +0100483 assert(op <= 3); /* max 2 bits */
484
485 item = &list[pos / 4];
486 mask = mask << 2 * (pos % 4);
487 *item = (*item) & ~mask;
488 *item = (*item) | (op << 2 * (pos % 4));
489}
490
Radek Krejcib56c7502019-02-13 14:19:54 +0100491#define LYS_IFF_LP 0x04 /**< Additional, temporary, value of @ref ifftokens: ( */
492#define LYS_IFF_RP 0x08 /**< Additional, temporary, value of @ref ifftokens: ) */
Radek Krejci19a96102018-11-15 13:38:09 +0100493
Radek Krejci0af46292019-01-11 16:02:31 +0100494/**
495 * @brief Find a feature of the given name and referenced in the given module.
496 *
497 * If the compiled schema is available (the schema is implemented), the feature from the compiled schema is
498 * returned. Otherwise, the special array of pre-compiled features is used to search for the feature. Such
499 * features are always disabled (feature from not implemented schema cannot be enabled), but in case the schema
500 * will be made implemented in future (no matter if implicitly via augmenting/deviating it or explicitly via
501 * ly_ctx_module_implement()), the compilation of these feature structure is finished, but the pointers
502 * assigned till that time will be still valid.
503 *
504 * @param[in] mod Module where the feature was referenced (used to resolve prefix of the feature).
505 * @param[in] name Name of the feature including possible prefix.
506 * @param[in] len Length of the string representing the feature identifier in the name variable (mandatory!).
507 * @return Pointer to the feature structure if found, NULL otherwise.
508 */
Radek Krejci19a96102018-11-15 13:38:09 +0100509static struct lysc_feature *
Michal Vasko7f45cf22020-10-01 12:49:44 +0200510lys_feature_find(const struct lys_module *mod, const char *name, size_t len)
Radek Krejci19a96102018-11-15 13:38:09 +0100511{
512 size_t i;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200513 LY_ARRAY_COUNT_TYPE u;
Radek Krejci14915cc2020-09-14 17:28:13 +0200514 struct lysc_feature *f;
Radek Krejci19a96102018-11-15 13:38:09 +0100515
Radek Krejci120d8542020-08-12 09:29:16 +0200516 assert(mod);
517
Radek Krejci19a96102018-11-15 13:38:09 +0100518 for (i = 0; i < len; ++i) {
519 if (name[i] == ':') {
520 /* we have a prefixed feature */
Radek Krejci0af46292019-01-11 16:02:31 +0100521 mod = lys_module_find_prefix(mod, name, i);
Radek Krejci19a96102018-11-15 13:38:09 +0100522 LY_CHECK_RET(!mod, NULL);
523
524 name = &name[i + 1];
525 len = len - i - 1;
526 }
527 }
528
529 /* we have the correct module, get the feature */
Radek Krejci14915cc2020-09-14 17:28:13 +0200530 LY_ARRAY_FOR(mod->features, u) {
531 f = &mod->features[u];
Radek Krejci7f9b6512019-09-18 13:11:09 +0200532 if (!ly_strncmp(f->name, name, len)) {
Radek Krejci19a96102018-11-15 13:38:09 +0100533 return f;
534 }
535 }
536
537 return NULL;
538}
539
Michal Vasko8d544252020-03-02 10:19:52 +0100540/**
Michal Vasko5fe75f12020-03-02 13:52:37 +0100541 * @brief Fill in the prepared compiled extensions definition structure according to the parsed extension definition.
542 */
543static LY_ERR
544lys_compile_extension(struct lysc_ctx *ctx, const struct lys_module *ext_mod, struct lysp_ext *ext_p, struct lysc_ext **ext)
545{
546 LY_ERR ret = LY_SUCCESS;
547
548 if (!ext_p->compiled) {
549 lysc_update_path(ctx, NULL, "{extension}");
550 lysc_update_path(ctx, NULL, ext_p->name);
551
552 /* compile the extension definition */
553 ext_p->compiled = calloc(1, sizeof **ext);
554 ext_p->compiled->refcount = 1;
Radek Krejci011e4aa2020-09-04 15:22:31 +0200555 DUP_STRING_GOTO(ctx->ctx, ext_p->name, ext_p->compiled->name, ret, done);
556 DUP_STRING_GOTO(ctx->ctx, ext_p->argument, ext_p->compiled->argument, ret, done);
Michal Vasko5fe75f12020-03-02 13:52:37 +0100557 ext_p->compiled->module = (struct lys_module *)ext_mod;
558 COMPILE_EXTS_GOTO(ctx, ext_p->exts, ext_p->compiled->exts, *ext, LYEXT_PAR_EXT, ret, done);
559
560 lysc_update_path(ctx, NULL, NULL);
561 lysc_update_path(ctx, NULL, NULL);
562
563 /* find extension definition plugin */
564 ext_p->compiled->plugin = lyext_get_plugin(ext_p->compiled);
565 }
566
567 *ext = lysc_ext_dup(ext_p->compiled);
568
569done:
570 return ret;
571}
572
573/**
Michal Vasko8d544252020-03-02 10:19:52 +0100574 * @brief Fill in the prepared compiled extension instance structure according to the parsed extension instance.
575 *
576 * @param[in] ctx Compilation context.
577 * @param[in] ext_p Parsed extension instance.
578 * @param[in,out] ext Prepared compiled extension instance.
579 * @param[in] parent Extension instance parent.
580 * @param[in] parent_type Extension instance parent type.
581 * @param[in] ext_mod Optional module with the extension instance extension definition, set only for internal annotations.
582 */
Radek Krejci19a96102018-11-15 13:38:09 +0100583static LY_ERR
Michal Vasko8d544252020-03-02 10:19:52 +0100584lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, struct lysc_ext_instance *ext, void *parent,
Radek Krejci0f969882020-08-21 16:56:47 +0200585 LYEXT_PARENT parent_type, const struct lys_module *ext_mod)
Radek Krejci19a96102018-11-15 13:38:09 +0100586{
Radek Krejci011e4aa2020-09-04 15:22:31 +0200587 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +0100588 const char *name;
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200589 size_t u;
Michal Vaskofd69e1d2020-07-03 11:57:17 +0200590 LY_ARRAY_COUNT_TYPE v;
Radek Krejci7c960162019-09-18 14:16:12 +0200591 const char *prefixed_name = NULL;
Radek Krejci19a96102018-11-15 13:38:09 +0100592
Radek Krejci011e4aa2020-09-04 15:22:31 +0200593 DUP_STRING(ctx->ctx, ext_p->argument, ext->argument, ret);
594 LY_CHECK_RET(ret);
595
Radek Krejci19a96102018-11-15 13:38:09 +0100596 ext->insubstmt = ext_p->insubstmt;
597 ext->insubstmt_index = ext_p->insubstmt_index;
Michal Vasko8ce51352020-10-06 14:07:24 +0200598 ext->module = ctx->mod;
Radek Krejci0935f412019-08-20 16:15:18 +0200599 ext->parent = parent;
600 ext->parent_type = parent_type;
Radek Krejci19a96102018-11-15 13:38:09 +0100601
Michal Vasko22df3f02020-08-24 13:29:22 +0200602 lysc_update_path(ctx, ext->parent_type == LYEXT_PAR_NODE ? (struct lysc_node *)ext->parent : NULL, "{extension}");
Radek Krejcif56e2a42019-09-09 14:15:25 +0200603
Radek Krejci19a96102018-11-15 13:38:09 +0100604 /* get module where the extension definition should be placed */
Radek Krejci1e008d22020-08-17 11:37:37 +0200605 for (u = strlen(ext_p->name); u && ext_p->name[u - 1] != ':'; --u) {}
Radek Krejci7c960162019-09-18 14:16:12 +0200606 if (ext_p->yin) {
607 /* YIN parser has to replace prefixes by the namespace - XML namespace/prefix pairs may differs form the YANG schema's
608 * namespace/prefix pair. YIN parser does not have the imports available, so mapping from XML namespace to the
609 * YANG (import) prefix must be done here. */
610 if (!ly_strncmp(ctx->mod_def->ns, ext_p->name, u - 1)) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200611 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, &ext_p->name[u], 0, &prefixed_name), cleanup);
Radek Krejci7c960162019-09-18 14:16:12 +0200612 u = 0;
Michal Vasko7c8439f2020-08-05 13:25:19 +0200613 } else {
614 assert(ctx->mod_def->parsed);
615 LY_ARRAY_FOR(ctx->mod_def->parsed->imports, v) {
616 if (!ly_strncmp(ctx->mod_def->parsed->imports[v].module->ns, ext_p->name, u - 1)) {
Radek Krejci7c960162019-09-18 14:16:12 +0200617 char *s;
Michal Vasko7c8439f2020-08-05 13:25:19 +0200618 LY_CHECK_ERR_GOTO(asprintf(&s, "%s:%s", ctx->mod_def->parsed->imports[v].prefix, &ext_p->name[u]) == -1,
Michal Vasko69730152020-10-09 16:30:07 +0200619 ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200620 LY_CHECK_GOTO(ret = lydict_insert_zc(ctx->ctx, s, &prefixed_name), cleanup);
Michal Vasko7c8439f2020-08-05 13:25:19 +0200621 u = strlen(ctx->mod_def->parsed->imports[v].prefix) + 1; /* add semicolon */
Radek Krejci7c960162019-09-18 14:16:12 +0200622 break;
623 }
624 }
625 }
626 if (!prefixed_name) {
627 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200628 "Invalid XML prefix of \"%.*s\" namespace used for extension instance identifier.", u, ext_p->name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200629 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200630 goto cleanup;
631 }
632 } else {
633 prefixed_name = ext_p->name;
634 }
635 lysc_update_path(ctx, NULL, prefixed_name);
636
Michal Vasko8d544252020-03-02 10:19:52 +0100637 if (!ext_mod) {
Radek Krejci63f55512020-05-20 14:37:18 +0200638 ext_mod = u ? lys_module_find_prefix(ctx->mod_def, prefixed_name, u - 1) : ctx->mod_def;
Michal Vasko8d544252020-03-02 10:19:52 +0100639 if (!ext_mod) {
640 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200641 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, prefixed_name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200642 ret = LY_EVALID;
Michal Vasko8d544252020-03-02 10:19:52 +0100643 goto cleanup;
644 } else if (!ext_mod->parsed->extensions) {
645 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
646 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
647 prefixed_name, ext_mod->name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200648 ret = LY_EVALID;
Michal Vasko8d544252020-03-02 10:19:52 +0100649 goto cleanup;
650 }
Radek Krejci7c960162019-09-18 14:16:12 +0200651 }
652 name = &prefixed_name[u];
Radek Krejci0935f412019-08-20 16:15:18 +0200653
Michal Vasko5fe75f12020-03-02 13:52:37 +0100654 /* find the parsed extension definition there */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200655 LY_ARRAY_FOR(ext_mod->parsed->extensions, v) {
656 if (!strcmp(name, ext_mod->parsed->extensions[v].name)) {
Michal Vasko5fe75f12020-03-02 13:52:37 +0100657 /* compile extension definition and assign it */
Radek Krejci011e4aa2020-09-04 15:22:31 +0200658 LY_CHECK_GOTO(ret = lys_compile_extension(ctx, ext_mod, &ext_mod->parsed->extensions[v], &ext->def), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +0100659 break;
660 }
661 }
Radek Krejci7c960162019-09-18 14:16:12 +0200662 if (!ext->def) {
663 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200664 "Extension definition of extension instance \"%s\" not found.", prefixed_name);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200665 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200666 goto cleanup;
667 }
Radek Krejci0935f412019-08-20 16:15:18 +0200668
Radek Krejcif56e2a42019-09-09 14:15:25 +0200669 /* unify the parsed extension from YIN and YANG sources. Without extension definition, it is not possible
670 * to get extension's argument from YIN source, so it is stored as one of the substatements. Here we have
671 * to find it, mark it with LYS_YIN_ARGUMENT and store it in the compiled structure. */
Radek Krejci7c960162019-09-18 14:16:12 +0200672 if (ext_p->yin && ext->def->argument && !ext->argument) {
Radek Krejcif56e2a42019-09-09 14:15:25 +0200673 /* Schema was parsed from YIN and an argument is expected, ... */
674 struct lysp_stmt *stmt = NULL;
675
676 if (ext->def->flags & LYS_YINELEM_TRUE) {
677 /* ... argument was the first XML child element */
678 if (ext_p->child && !(ext_p->child->flags & LYS_YIN_ATTR)) {
679 /* TODO check namespace of the statement */
680 if (!strcmp(ext_p->child->stmt, ext->def->argument)) {
681 stmt = ext_p->child;
682 }
683 }
684 } else {
685 /* ... argument was one of the XML attributes which are represented as child stmt
686 * with LYS_YIN_ATTR flag */
687 for (stmt = ext_p->child; stmt && (stmt->flags & LYS_YIN_ATTR); stmt = stmt->next) {
688 if (!strcmp(stmt->stmt, ext->def->argument)) {
689 /* this is the extension's argument */
Radek Krejcif56e2a42019-09-09 14:15:25 +0200690 break;
691 }
692 }
693 }
694 if (!stmt) {
695 /* missing extension's argument */
696 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200697 "Extension instance \"%s\" misses argument \"%s\".", prefixed_name, ext->def->argument);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200698 ret = LY_EVALID;
Radek Krejci7c960162019-09-18 14:16:12 +0200699 goto cleanup;
Radek Krejcif56e2a42019-09-09 14:15:25 +0200700
701 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200702 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, stmt->arg, 0, &ext->argument), cleanup);
Radek Krejcif56e2a42019-09-09 14:15:25 +0200703 stmt->flags |= LYS_YIN_ARGUMENT;
704 }
Radek Krejci7c960162019-09-18 14:16:12 +0200705 if (prefixed_name != ext_p->name) {
706 lydict_remove(ctx->ctx, ext_p->name);
707 ext_p->name = prefixed_name;
708 if (!ext_p->argument && ext->argument) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200709 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, ext->argument, 0, &ext_p->argument), cleanup);
Radek Krejci7c960162019-09-18 14:16:12 +0200710 }
711 }
Radek Krejcif56e2a42019-09-09 14:15:25 +0200712
Radek Krejci0935f412019-08-20 16:15:18 +0200713 if (ext->def->plugin && ext->def->plugin->compile) {
Radek Krejciad5963b2019-09-06 16:03:05 +0200714 if (ext->argument) {
Michal Vasko22df3f02020-08-24 13:29:22 +0200715 lysc_update_path(ctx, (struct lysc_node *)ext, ext->argument);
Radek Krejciad5963b2019-09-06 16:03:05 +0200716 }
Radek Krejci011e4aa2020-09-04 15:22:31 +0200717 LY_CHECK_GOTO(ret = ext->def->plugin->compile(ctx, ext_p, ext), cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +0200718 if (ext->argument) {
719 lysc_update_path(ctx, NULL, NULL);
720 }
Radek Krejci0935f412019-08-20 16:15:18 +0200721 }
Radek Krejcif56e2a42019-09-09 14:15:25 +0200722 ext_p->compiled = ext;
723
Radek Krejci7c960162019-09-18 14:16:12 +0200724cleanup:
Michal Vasko69730152020-10-09 16:30:07 +0200725 if (prefixed_name && (prefixed_name != ext_p->name)) {
Radek Krejci7c960162019-09-18 14:16:12 +0200726 lydict_remove(ctx->ctx, prefixed_name);
727 }
728
Radek Krejcif56e2a42019-09-09 14:15:25 +0200729 lysc_update_path(ctx, NULL, NULL);
730 lysc_update_path(ctx, NULL, NULL);
Radek Krejci0935f412019-08-20 16:15:18 +0200731
Radek Krejci7c960162019-09-18 14:16:12 +0200732 return ret;
Radek Krejci0935f412019-08-20 16:15:18 +0200733}
734
735/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100736 * @brief Compile information from the if-feature statement
737 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +0200738 * @param[in] qname The if-feature argument to process. It is pointer-to-qname just to unify the compile functions.
Radek Krejcib56c7502019-02-13 14:19:54 +0100739 * @param[in,out] iff Prepared (empty) compiled if-feature structure to fill.
740 * @return LY_ERR value.
741 */
Radek Krejci19a96102018-11-15 13:38:09 +0100742static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +0200743lys_compile_iffeature(struct lysc_ctx *ctx, struct lysp_qname *qname, struct lysc_iffeature *iff)
Radek Krejci19a96102018-11-15 13:38:09 +0100744{
Radek Krejci1deb5be2020-08-26 16:43:36 +0200745 LY_ERR rc = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +0200746 const char *c = qname->str;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200747 int64_t i, j;
748 int8_t op_len, last_not = 0, checkversion = 0;
749 LY_ARRAY_COUNT_TYPE f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci19a96102018-11-15 13:38:09 +0100750 uint8_t op;
751 struct iff_stack stack = {0, 0, NULL};
752 struct lysc_feature *f;
753
754 assert(c);
755
756 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
Radek Krejci1deb5be2020-08-26 16:43:36 +0200757 for (i = j = 0; c[i]; i++) {
Radek Krejci19a96102018-11-15 13:38:09 +0100758 if (c[i] == '(') {
759 j++;
760 checkversion = 1;
761 continue;
762 } else if (c[i] == ')') {
763 j--;
764 continue;
765 } else if (isspace(c[i])) {
766 checkversion = 1;
767 continue;
768 }
769
Radek Krejci1deb5be2020-08-26 16:43:36 +0200770 if (!strncmp(&c[i], "not", op_len = 3) || !strncmp(&c[i], "and", op_len = 3) || !strncmp(&c[i], "or", op_len = 2)) {
771 uint64_t spaces;
Michal Vasko2b7e5582020-10-07 12:31:23 +0200772 for (spaces = 0; c[i + op_len + spaces] && isspace(c[i + op_len + spaces]); spaces++) {}
Radek Krejci1deb5be2020-08-26 16:43:36 +0200773 if (c[i + op_len + spaces] == '\0') {
Radek Krejci19a96102018-11-15 13:38:09 +0100774 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200775 "Invalid value \"%s\" of if-feature - unexpected end of expression.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100776 return LY_EVALID;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200777 } else if (!isspace(c[i + op_len])) {
Radek Krejci19a96102018-11-15 13:38:09 +0100778 /* feature name starting with the not/and/or */
779 last_not = 0;
780 f_size++;
781 } else if (c[i] == 'n') { /* not operation */
782 if (last_not) {
783 /* double not */
784 expr_size = expr_size - 2;
785 last_not = 0;
786 } else {
787 last_not = 1;
788 }
789 } else { /* and, or */
Radek Krejci6788abc2019-06-14 13:56:49 +0200790 if (f_exp != f_size) {
791 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200792 "Invalid value \"%s\" of if-feature - missing feature/expression before \"%.*s\" operation.",
793 qname->str, op_len, &c[i]);
Radek Krejci6788abc2019-06-14 13:56:49 +0200794 return LY_EVALID;
795 }
Radek Krejci19a96102018-11-15 13:38:09 +0100796 f_exp++;
Radek Krejci6788abc2019-06-14 13:56:49 +0200797
Radek Krejci19a96102018-11-15 13:38:09 +0100798 /* not a not operation */
799 last_not = 0;
800 }
Radek Krejci1deb5be2020-08-26 16:43:36 +0200801 i += op_len;
Radek Krejci19a96102018-11-15 13:38:09 +0100802 } else {
803 f_size++;
804 last_not = 0;
805 }
806 expr_size++;
807
808 while (!isspace(c[i])) {
Michal Vasko69730152020-10-09 16:30:07 +0200809 if (!c[i] || (c[i] == ')') || (c[i] == '(')) {
Radek Krejci19a96102018-11-15 13:38:09 +0100810 i--;
811 break;
812 }
813 i++;
814 }
815 }
Radek Krejci6788abc2019-06-14 13:56:49 +0200816 if (j) {
Radek Krejci19a96102018-11-15 13:38:09 +0100817 /* not matching count of ( and ) */
818 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200819 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100820 return LY_EVALID;
821 }
Radek Krejci6788abc2019-06-14 13:56:49 +0200822 if (f_exp != f_size) {
823 /* features do not match the needed arguments for the logical operations */
824 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200825 "Invalid value \"%s\" of if-feature - number of features in expression does not match "
826 "the required number of operands for the operations.", qname->str);
Radek Krejci6788abc2019-06-14 13:56:49 +0200827 return LY_EVALID;
828 }
Radek Krejci19a96102018-11-15 13:38:09 +0100829
Michal Vasko69730152020-10-09 16:30:07 +0200830 if (checkversion || (expr_size > 1)) {
Radek Krejci19a96102018-11-15 13:38:09 +0100831 /* check that we have 1.1 module */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200832 if (qname->mod->version != LYS_VERSION_1_1) {
Radek Krejci19a96102018-11-15 13:38:09 +0100833 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +0200834 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100835 return LY_EVALID;
836 }
837 }
838
839 /* allocate the memory */
840 LY_ARRAY_CREATE_RET(ctx->ctx, iff->features, f_size, LY_EMEM);
841 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
842 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci1deb5be2020-08-26 16:43:36 +0200843 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->ctx); rc = LY_EMEM, error);
Radek Krejci19a96102018-11-15 13:38:09 +0100844
845 stack.size = expr_size;
846 f_size--; expr_size--; /* used as indexes from now */
847
848 for (i--; i >= 0; i--) {
849 if (c[i] == ')') {
850 /* push it on stack */
851 iff_stack_push(&stack, LYS_IFF_RP);
852 continue;
853 } else if (c[i] == '(') {
854 /* pop from the stack into result all operators until ) */
Michal Vaskod989ba02020-08-24 10:59:24 +0200855 while ((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
Radek Krejci19a96102018-11-15 13:38:09 +0100856 iff_setop(iff->expr, op, expr_size--);
857 }
858 continue;
859 } else if (isspace(c[i])) {
860 continue;
861 }
862
863 /* end of operator or operand -> find beginning and get what is it */
864 j = i + 1;
865 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
866 i--;
867 }
868 i++; /* go back by one step */
869
870 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
Michal Vasko69730152020-10-09 16:30:07 +0200871 if (stack.index && (stack.stack[stack.index - 1] == LYS_IFF_NOT)) {
Radek Krejci19a96102018-11-15 13:38:09 +0100872 /* double not */
873 iff_stack_pop(&stack);
874 } else {
875 /* not has the highest priority, so do not pop from the stack
876 * as in case of AND and OR */
877 iff_stack_push(&stack, LYS_IFF_NOT);
878 }
879 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
880 /* as for OR - pop from the stack all operators with the same or higher
881 * priority and store them to the result, then push the AND to the stack */
882 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
883 op = iff_stack_pop(&stack);
884 iff_setop(iff->expr, op, expr_size--);
885 }
886 iff_stack_push(&stack, LYS_IFF_AND);
887 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
888 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
889 op = iff_stack_pop(&stack);
890 iff_setop(iff->expr, op, expr_size--);
891 }
892 iff_stack_push(&stack, LYS_IFF_OR);
893 } else {
894 /* feature name, length is j - i */
895
896 /* add it to the expression */
897 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
898
899 /* now get the link to the feature definition */
Michal Vasko7f45cf22020-10-01 12:49:44 +0200900 f = lys_feature_find(qname->mod, &c[i], j - i);
Radek Krejci0af46292019-01-11 16:02:31 +0100901 LY_CHECK_ERR_GOTO(!f, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200902 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", qname->str, j - i, &c[i]);
903 rc = LY_EVALID, error)
Radek Krejci19a96102018-11-15 13:38:09 +0100904 iff->features[f_size] = f;
905 LY_ARRAY_INCREMENT(iff->features);
906 f_size--;
907 }
908 }
909 while (stack.index) {
910 op = iff_stack_pop(&stack);
911 iff_setop(iff->expr, op, expr_size--);
912 }
913
914 if (++expr_size || ++f_size) {
915 /* not all expected operators and operands found */
916 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko7f45cf22020-10-01 12:49:44 +0200917 "Invalid value \"%s\" of if-feature - processing error.", qname->str);
Radek Krejci19a96102018-11-15 13:38:09 +0100918 rc = LY_EINT;
919 } else {
920 rc = LY_SUCCESS;
921 }
922
923error:
924 /* cleanup */
925 iff_stack_clean(&stack);
926
927 return rc;
928}
929
Radek Krejcib56c7502019-02-13 14:19:54 +0100930/**
Michal Vasko175012e2019-11-06 15:49:14 +0100931 * @brief Get the XPath context node for the given schema node.
932 * @param[in] start The schema node where the XPath expression appears.
933 * @return The context node to evaluate XPath expression in given schema node.
934 * @return NULL in case the context node is the root node.
935 */
936static struct lysc_node *
937lysc_xpath_context(struct lysc_node *start)
938{
Michal Vasko1bf09392020-03-27 12:38:10 +0100939 for (; start && !(start->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_RPC | LYS_ACTION | LYS_NOTIF));
Radek Krejci1e008d22020-08-17 11:37:37 +0200940 start = start->parent) {}
Michal Vasko175012e2019-11-06 15:49:14 +0100941 return start;
942}
943
944/**
Radek Krejcib56c7502019-02-13 14:19:54 +0100945 * @brief Compile information from the when statement
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200946 *
Radek Krejcib56c7502019-02-13 14:19:54 +0100947 * @param[in] ctx Compile context.
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200948 * @param[in] when_p Parsed when structure.
949 * @param[in] flags Flags of the parsed node with the when statement.
950 * @param[in] ctx_node Context node for the when statement.
Radek Krejcib56c7502019-02-13 14:19:54 +0100951 * @param[out] when Pointer where to store pointer to the created compiled when structure.
952 * @return LY_ERR value.
953 */
Radek Krejci19a96102018-11-15 13:38:09 +0100954static LY_ERR
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200955lys_compile_when_(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t flags, const struct lysc_node *ctx_node,
956 struct lysc_when **when)
Radek Krejci19a96102018-11-15 13:38:09 +0100957{
Radek Krejci19a96102018-11-15 13:38:09 +0100958 LY_ERR ret = LY_SUCCESS;
959
Radek Krejci00b874b2019-02-12 10:54:50 +0100960 *when = calloc(1, sizeof **when);
Radek Krejcif03a9e22020-09-18 20:09:31 +0200961 LY_CHECK_ERR_RET(!(*when), LOGMEM(ctx->ctx), LY_EMEM);
Radek Krejci00b874b2019-02-12 10:54:50 +0100962 (*when)->refcount = 1;
Radek Krejcif03a9e22020-09-18 20:09:31 +0200963 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, when_p->cond, 0, 1, &(*when)->cond));
Radek Krejcia0f704a2019-09-09 16:12:23 +0200964 (*when)->module = ctx->mod_def;
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200965 (*when)->context = (struct lysc_node *)ctx_node;
Radek Krejci011e4aa2020-09-04 15:22:31 +0200966 DUP_STRING_GOTO(ctx->ctx, when_p->dsc, (*when)->dsc, ret, done);
967 DUP_STRING_GOTO(ctx->ctx, when_p->ref, (*when)->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +0200968 COMPILE_EXTS_GOTO(ctx, when_p->exts, (*when)->exts, (*when), LYEXT_PAR_WHEN, ret, done);
Michal Vasko175012e2019-11-06 15:49:14 +0100969 (*when)->flags = flags & LYS_STATUS_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +0100970
971done:
972 return ret;
973}
974
Radek Krejcib56c7502019-02-13 14:19:54 +0100975/**
Michal Vaskoceab6dd2020-10-09 16:53:36 +0200976 * @brief Compile information from the when statement by either standard compilation or by reusing
977 * another compiled when structure.
978 *
979 * @param[in] ctx Compile context.
980 * @param[in] when_p Parsed when structure.
981 * @param[in] flags Flags of the parsed node with the when statement.
982 * @param[in] ctx_node Context node for the when statement.
983 * @param[in] node Compiled node to which add the compiled when.
984 * @param[in,out] when_c Optional, pointer to the previously compiled @p when_p to be reused. Set to NULL
985 * for the first call.
986 * @return LY_ERR value.
987 */
988static LY_ERR
989lys_compile_when(struct lysc_ctx *ctx, struct lysp_when *when_p, uint16_t flags, const struct lysc_node *ctx_node,
990 struct lysc_node *node, struct lysc_when **when_c)
991{
992 struct lysc_when **new_when, ***node_when;
993
994 assert(when_p);
995
996 /* get the when array */
997 if (node->nodetype & LYS_ACTION) {
998 node_when = &((struct lysc_action *)node)->when;
999 } else if (node->nodetype == LYS_NOTIF) {
1000 node_when = &((struct lysc_notif *)node)->when;
1001 } else {
1002 node_when = &node->when;
1003 }
1004
1005 /* create new when pointer */
1006 LY_ARRAY_NEW_RET(ctx->ctx, *node_when, new_when, LY_EMEM);
1007 if (!when_c || !(*when_c)) {
1008 /* compile when */
1009 LY_CHECK_RET(lys_compile_when_(ctx, when_p, flags, ctx_node, new_when));
1010
Radek Krejci90d4e922020-10-12 15:55:33 +02001011 if (!(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02001012 /* do not check "when" semantics in a grouping */
1013 LY_CHECK_RET(ly_set_add(&ctx->xpath, node, 0, NULL));
1014 }
1015
1016 /* remember the compiled when for sharing */
1017 if (when_c) {
1018 *when_c = *new_when;
1019 }
1020 } else {
1021 /* use the previously compiled when */
1022 ++(*when_c)->refcount;
1023 *new_when = *when_c;
1024
Radek Krejci90d4e922020-10-12 15:55:33 +02001025 if (!(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02001026 /* in this case check "when" again for all children because of dummy node check */
1027 LY_CHECK_RET(ly_set_add(&ctx->xpath, node, 0, NULL));
1028 }
1029 }
1030
1031 return LY_SUCCESS;
1032}
1033
1034/**
Radek Krejcib56c7502019-02-13 14:19:54 +01001035 * @brief Compile information from the must statement
1036 * @param[in] ctx Compile context.
1037 * @param[in] must_p The parsed must statement structure.
Radek Krejcib56c7502019-02-13 14:19:54 +01001038 * @param[in,out] must Prepared (empty) compiled must structure to fill.
1039 * @return LY_ERR value.
1040 */
Radek Krejci19a96102018-11-15 13:38:09 +01001041static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02001042lys_compile_must(struct lysc_ctx *ctx, struct lysp_restr *must_p, struct lysc_must *must)
Radek Krejci19a96102018-11-15 13:38:09 +01001043{
Radek Krejci19a96102018-11-15 13:38:09 +01001044 LY_ERR ret = LY_SUCCESS;
1045
Michal Vasko7f45cf22020-10-01 12:49:44 +02001046 LY_CHECK_RET(lyxp_expr_parse(ctx->ctx, must_p->arg.str, 0, 1, &must->cond));
1047 must->module = (struct lys_module *)must_p->arg.mod;
Radek Krejci011e4aa2020-09-04 15:22:31 +02001048 DUP_STRING_GOTO(ctx->ctx, must_p->eapptag, must->eapptag, ret, done);
1049 DUP_STRING_GOTO(ctx->ctx, must_p->emsg, must->emsg, ret, done);
1050 DUP_STRING_GOTO(ctx->ctx, must_p->dsc, must->dsc, ret, done);
1051 DUP_STRING_GOTO(ctx->ctx, must_p->ref, must->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02001052 COMPILE_EXTS_GOTO(ctx, must_p->exts, must->exts, must, LYEXT_PAR_MUST, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01001053
1054done:
1055 return ret;
1056}
1057
Radek Krejcib56c7502019-02-13 14:19:54 +01001058/**
Michal Vasko7c8439f2020-08-05 13:25:19 +02001059 * @brief Compile information in the import statement - make sure there is the target module
Radek Krejcib56c7502019-02-13 14:19:54 +01001060 * @param[in] ctx Compile context.
Michal Vasko7c8439f2020-08-05 13:25:19 +02001061 * @param[in] imp_p The parsed import statement structure to fill the module to.
Radek Krejcib56c7502019-02-13 14:19:54 +01001062 * @return LY_ERR value.
1063 */
Radek Krejci19a96102018-11-15 13:38:09 +01001064static LY_ERR
Michal Vasko7c8439f2020-08-05 13:25:19 +02001065lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p)
Radek Krejci19a96102018-11-15 13:38:09 +01001066{
Michal Vasko3a41dff2020-07-15 14:30:28 +02001067 const struct lys_module *mod = NULL;
Radek Krejci19a96102018-11-15 13:38:09 +01001068 LY_ERR ret = LY_SUCCESS;
1069
Radek Krejci7f2a5362018-11-28 13:05:37 +01001070 /* make sure that we have the parsed version (lysp_) of the imported module to import groupings or typedefs.
1071 * The compiled version is needed only for augments, deviates and leafrefs, so they are checked (and added,
Radek Krejci0e5d8382018-11-28 16:37:53 +01001072 * if needed) when these nodes are finally being instantiated and validated at the end of schema compilation. */
Michal Vasko7c8439f2020-08-05 13:25:19 +02001073 if (!imp_p->module->parsed) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +01001074 /* try to use filepath if present */
Michal Vasko7c8439f2020-08-05 13:25:19 +02001075 if (imp_p->module->filepath) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001076 struct ly_in *in;
Michal Vasko7c8439f2020-08-05 13:25:19 +02001077 if (ly_in_new_filepath(imp_p->module->filepath, 0, &in)) {
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001078 LOGINT(ctx->ctx);
1079 } else {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001080 LY_CHECK_RET(lys_parse(ctx->ctx, in, !strcmp(&imp_p->module->filepath[strlen(imp_p->module->filepath - 4)],
Michal Vasko69730152020-10-09 16:30:07 +02001081 ".yin") ? LYS_IN_YIN : LYS_IN_YANG, &mod));
Michal Vasko7c8439f2020-08-05 13:25:19 +02001082 if (mod != imp_p->module) {
Michal Vasko3a41dff2020-07-15 14:30:28 +02001083 LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
Michal Vasko69730152020-10-09 16:30:07 +02001084 imp_p->module->filepath, imp_p->module->name);
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001085 mod = NULL;
1086 }
Radek Krejci19a96102018-11-15 13:38:09 +01001087 }
Radek Krejcif0e1ba52020-05-22 15:14:35 +02001088 ly_in_free(in, 1);
Radek Krejci19a96102018-11-15 13:38:09 +01001089 }
1090 if (!mod) {
Michal Vasko7c8439f2020-08-05 13:25:19 +02001091 if (lysp_load_module(ctx->ctx, imp_p->module->name, imp_p->module->revision, 0, 1, (struct lys_module **)&mod)) {
Radek Krejci19a96102018-11-15 13:38:09 +01001092 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
Michal Vasko69730152020-10-09 16:30:07 +02001093 imp_p->module->name, ctx->mod->name);
Radek Krejci19a96102018-11-15 13:38:09 +01001094 return LY_ENOTFOUND;
1095 }
1096 }
Radek Krejci19a96102018-11-15 13:38:09 +01001097 }
1098
Radek Krejci19a96102018-11-15 13:38:09 +01001099 return ret;
1100}
1101
Michal Vasko33ff9422020-07-03 09:50:39 +02001102LY_ERR
1103lys_identity_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
Radek Krejci0f969882020-08-21 16:56:47 +02001104 struct lysp_ident *identities_p, struct lysc_ident **identities)
Radek Krejci19a96102018-11-15 13:38:09 +01001105{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001106 LY_ARRAY_COUNT_TYPE offset = 0, u, v;
Michal Vasko33ff9422020-07-03 09:50:39 +02001107 struct lysc_ctx context = {0};
Radek Krejci19a96102018-11-15 13:38:09 +01001108 LY_ERR ret = LY_SUCCESS;
1109
Michal Vasko33ff9422020-07-03 09:50:39 +02001110 assert(ctx_sc || ctx);
Radek Krejci327de162019-06-14 12:52:07 +02001111
Michal Vasko33ff9422020-07-03 09:50:39 +02001112 if (!ctx_sc) {
1113 context.ctx = ctx;
1114 context.mod = module;
Radek Krejci120d8542020-08-12 09:29:16 +02001115 context.mod_def = module;
Michal Vasko33ff9422020-07-03 09:50:39 +02001116 context.path_len = 1;
1117 context.path[0] = '/';
1118 ctx_sc = &context;
1119 }
Radek Krejci19a96102018-11-15 13:38:09 +01001120
Michal Vasko33ff9422020-07-03 09:50:39 +02001121 if (!identities_p) {
1122 return LY_SUCCESS;
1123 }
1124 if (*identities) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001125 offset = LY_ARRAY_COUNT(*identities);
Michal Vasko33ff9422020-07-03 09:50:39 +02001126 }
1127
1128 lysc_update_path(ctx_sc, NULL, "{identity}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001129 LY_ARRAY_CREATE_RET(ctx_sc->ctx, *identities, LY_ARRAY_COUNT(identities_p), LY_EMEM);
Michal Vasko33ff9422020-07-03 09:50:39 +02001130 LY_ARRAY_FOR(identities_p, u) {
1131 lysc_update_path(ctx_sc, NULL, identities_p[u].name);
1132
1133 LY_ARRAY_INCREMENT(*identities);
1134 COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *identities, name, &(*identities)[offset + u], "identity", identities_p[u].name);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001135 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].name, (*identities)[offset + u].name, ret, done);
1136 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].dsc, (*identities)[offset + u].dsc, ret, done);
1137 DUP_STRING_GOTO(ctx_sc->ctx, identities_p[u].ref, (*identities)[offset + u].ref, ret, done);
Michal Vasko33ff9422020-07-03 09:50:39 +02001138 (*identities)[offset + u].module = ctx_sc->mod;
1139 COMPILE_ARRAY_GOTO(ctx_sc, identities_p[u].iffeatures, (*identities)[offset + u].iffeatures, v,
Michal Vasko69730152020-10-09 16:30:07 +02001140 lys_compile_iffeature, ret, done);
Michal Vasko33ff9422020-07-03 09:50:39 +02001141 /* backlinks (derived) can be added no sooner than when all the identities in the current module are present */
1142 COMPILE_EXTS_GOTO(ctx_sc, identities_p[u].exts, (*identities)[offset + u].exts, &(*identities)[offset + u],
Michal Vasko69730152020-10-09 16:30:07 +02001143 LYEXT_PAR_IDENT, ret, done);
Michal Vasko33ff9422020-07-03 09:50:39 +02001144 (*identities)[offset + u].flags = identities_p[u].flags;
1145
1146 lysc_update_path(ctx_sc, NULL, NULL);
1147 }
1148 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001149done:
1150 return ret;
1151}
1152
Radek Krejcib56c7502019-02-13 14:19:54 +01001153/**
1154 * @brief Check circular dependency of identities - identity MUST NOT reference itself (via their base statement).
1155 *
1156 * The function works in the same way as lys_compile_feature_circular_check() with different structures and error messages.
1157 *
1158 * @param[in] ctx Compile context for logging.
1159 * @param[in] ident The base identity (its derived list is being extended by the identity being currently processed).
1160 * @param[in] derived The list of derived identities of the identity being currently processed (not the one provided as @p ident)
1161 * @return LY_SUCCESS if everything is ok.
1162 * @return LY_EVALID if the identity is derived from itself.
1163 */
Radek Krejci38222632019-02-12 16:55:05 +01001164static LY_ERR
1165lys_compile_identity_circular_check(struct lysc_ctx *ctx, struct lysc_ident *ident, struct lysc_ident **derived)
1166{
Radek Krejciba03a5a2020-08-27 14:40:41 +02001167 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001168 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci38222632019-02-12 16:55:05 +01001169 struct ly_set recursion = {0};
1170 struct lysc_ident *drv;
1171
1172 if (!derived) {
1173 return LY_SUCCESS;
1174 }
1175
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001176 for (u = 0; u < LY_ARRAY_COUNT(derived); ++u) {
Radek Krejci38222632019-02-12 16:55:05 +01001177 if (ident == derived[u]) {
1178 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001179 "Identity \"%s\" is indirectly derived from itself.", ident->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001180 ret = LY_EVALID;
Radek Krejci38222632019-02-12 16:55:05 +01001181 goto cleanup;
1182 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001183 ret = ly_set_add(&recursion, derived[u], 0, NULL);
1184 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci38222632019-02-12 16:55:05 +01001185 }
1186
1187 for (v = 0; v < recursion.count; ++v) {
1188 drv = recursion.objs[v];
1189 if (!drv->derived) {
1190 continue;
1191 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001192 for (u = 0; u < LY_ARRAY_COUNT(drv->derived); ++u) {
Radek Krejci38222632019-02-12 16:55:05 +01001193 if (ident == drv->derived[u]) {
1194 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001195 "Identity \"%s\" is indirectly derived from itself.", ident->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001196 ret = LY_EVALID;
Radek Krejci38222632019-02-12 16:55:05 +01001197 goto cleanup;
1198 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001199 ret = ly_set_add(&recursion, drv->derived[u], 0, NULL);
1200 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci38222632019-02-12 16:55:05 +01001201 }
1202 }
Radek Krejci38222632019-02-12 16:55:05 +01001203
1204cleanup:
1205 ly_set_erase(&recursion, NULL);
1206 return ret;
1207}
1208
Radek Krejcia3045382018-11-22 14:30:31 +01001209/**
1210 * @brief Find and process the referenced base identities from another identity or identityref
1211 *
Radek Krejciaca74032019-06-04 08:53:06 +02001212 * For bases in identity set backlinks to them from the base identities. For identityref, store
Radek Krejcia3045382018-11-22 14:30:31 +01001213 * the array of pointers to the base identities. So one of the ident or bases parameter must be set
1214 * to distinguish these two use cases.
1215 *
1216 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
1217 * @param[in] bases_p Array of names (including prefix if necessary) of base identities.
Michal Vasko33ff9422020-07-03 09:50:39 +02001218 * @param[in] ident Referencing identity to work with, NULL for identityref.
Radek Krejcia3045382018-11-22 14:30:31 +01001219 * @param[in] bases Array of bases of identityref to fill in.
1220 * @return LY_ERR value.
1221 */
Radek Krejci19a96102018-11-15 13:38:09 +01001222static LY_ERR
Michal Vasko72619ce2020-10-06 14:05:32 +02001223lys_compile_identity_bases(struct lysc_ctx *ctx, const struct lys_module *context_module, const char **bases_p,
Radek Krejci0f969882020-08-21 16:56:47 +02001224 struct lysc_ident *ident, struct lysc_ident ***bases)
Radek Krejci19a96102018-11-15 13:38:09 +01001225{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001226 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci19a96102018-11-15 13:38:09 +01001227 const char *s, *name;
Michal Vasko72619ce2020-10-06 14:05:32 +02001228 const struct lys_module *mod;
Radek Krejci80d281e2020-09-14 17:42:54 +02001229 struct lysc_ident **idref;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001230
1231 assert(ident || bases);
1232
Michal Vasko69730152020-10-09 16:30:07 +02001233 if ((LY_ARRAY_COUNT(bases_p) > 1) && (ctx->mod_def->version < 2)) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01001234 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001235 "Multiple bases in %s are allowed only in YANG 1.1 modules.", ident ? "identity" : "identityref type");
Radek Krejci555cb5b2018-11-16 14:54:33 +01001236 return LY_EVALID;
1237 }
1238
Michal Vasko33ff9422020-07-03 09:50:39 +02001239 LY_ARRAY_FOR(bases_p, u) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01001240 s = strchr(bases_p[u], ':');
1241 if (s) {
1242 /* prefixed identity */
1243 name = &s[1];
Radek Krejci0a33b042020-05-27 10:05:06 +02001244 mod = lys_module_find_prefix(context_module, bases_p[u], s - bases_p[u]);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001245 } else {
1246 name = bases_p[u];
Radek Krejci0a33b042020-05-27 10:05:06 +02001247 mod = context_module;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001248 }
1249 if (!mod) {
1250 if (ident) {
1251 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001252 "Invalid prefix used for base (%s) of identity \"%s\".", bases_p[u], ident->name);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001253 } else {
1254 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001255 "Invalid prefix used for base (%s) of identityref.", bases_p[u]);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001256 }
1257 return LY_EVALID;
1258 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001259
Radek Krejci555cb5b2018-11-16 14:54:33 +01001260 idref = NULL;
Radek Krejci80d281e2020-09-14 17:42:54 +02001261 LY_ARRAY_FOR(mod->identities, v) {
1262 if (!strcmp(name, mod->identities[v].name)) {
Michal Vasko33ff9422020-07-03 09:50:39 +02001263 if (ident) {
Radek Krejci80d281e2020-09-14 17:42:54 +02001264 if (ident == &mod->identities[v]) {
Michal Vasko33ff9422020-07-03 09:50:39 +02001265 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001266 "Identity \"%s\" is derived from itself.", ident->name);
Michal Vasko33ff9422020-07-03 09:50:39 +02001267 return LY_EVALID;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001268 }
Radek Krejci80d281e2020-09-14 17:42:54 +02001269 LY_CHECK_RET(lys_compile_identity_circular_check(ctx, &mod->identities[v], ident->derived));
Michal Vasko33ff9422020-07-03 09:50:39 +02001270 /* we have match! store the backlink */
Radek Krejci80d281e2020-09-14 17:42:54 +02001271 LY_ARRAY_NEW_RET(ctx->ctx, mod->identities[v].derived, idref, LY_EMEM);
Michal Vasko33ff9422020-07-03 09:50:39 +02001272 *idref = ident;
1273 } else {
1274 /* we have match! store the found identity */
1275 LY_ARRAY_NEW_RET(ctx->ctx, *bases, idref, LY_EMEM);
Radek Krejci80d281e2020-09-14 17:42:54 +02001276 *idref = &mod->identities[v];
Radek Krejci555cb5b2018-11-16 14:54:33 +01001277 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001278 break;
Radek Krejci555cb5b2018-11-16 14:54:33 +01001279 }
1280 }
1281 if (!idref || !(*idref)) {
1282 if (ident) {
1283 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001284 "Unable to find base (%s) of identity \"%s\".", bases_p[u], ident->name);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001285 } else {
1286 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001287 "Unable to find base (%s) of identityref.", bases_p[u]);
Radek Krejci555cb5b2018-11-16 14:54:33 +01001288 }
1289 return LY_EVALID;
1290 }
1291 }
1292 return LY_SUCCESS;
1293}
1294
Radek Krejcia3045382018-11-22 14:30:31 +01001295/**
1296 * @brief For the given array of identities, set the backlinks from all their base identities.
1297 * @param[in] ctx Compile context, not only for logging but also to get the current module to resolve prefixes.
1298 * @param[in] idents_p Array of identities definitions from the parsed schema structure.
1299 * @param[in] idents Array of referencing identities to which the backlinks are supposed to be set.
1300 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
1301 */
Radek Krejci555cb5b2018-11-16 14:54:33 +01001302static LY_ERR
1303lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1304{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001305 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01001306
Michal Vasko33ff9422020-07-03 09:50:39 +02001307 lysc_update_path(ctx, NULL, "{identity}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001308 for (u = 0; u < LY_ARRAY_COUNT(idents_p); ++u) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001309 if (!idents_p[u].bases) {
Radek Krejci19a96102018-11-15 13:38:09 +01001310 continue;
1311 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001312 lysc_update_path(ctx, NULL, idents[u].name);
Radek Krejci0a33b042020-05-27 10:05:06 +02001313 LY_CHECK_RET(lys_compile_identity_bases(ctx, idents[u].module, idents_p[u].bases, &idents[u], NULL));
Radek Krejci327de162019-06-14 12:52:07 +02001314 lysc_update_path(ctx, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001315 }
Michal Vasko33ff9422020-07-03 09:50:39 +02001316 lysc_update_path(ctx, NULL, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01001317 return LY_SUCCESS;
1318}
1319
Radek Krejci0af46292019-01-11 16:02:31 +01001320LY_ERR
Michal Vasko33ff9422020-07-03 09:50:39 +02001321lys_feature_precompile(struct lysc_ctx *ctx_sc, struct ly_ctx *ctx, struct lys_module *module,
Radek Krejci0f969882020-08-21 16:56:47 +02001322 struct lysp_feature *features_p, struct lysc_feature **features)
Radek Krejci0af46292019-01-11 16:02:31 +01001323{
Radek Krejci011e4aa2020-09-04 15:22:31 +02001324 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001325 LY_ARRAY_COUNT_TYPE offset = 0, u;
Radek Krejci0af46292019-01-11 16:02:31 +01001326 struct lysc_ctx context = {0};
1327
Radek Krejci327de162019-06-14 12:52:07 +02001328 assert(ctx_sc || ctx);
1329
1330 if (!ctx_sc) {
1331 context.ctx = ctx;
1332 context.mod = module;
1333 context.path_len = 1;
1334 context.path[0] = '/';
1335 ctx_sc = &context;
1336 }
Radek Krejci0af46292019-01-11 16:02:31 +01001337
1338 if (!features_p) {
1339 return LY_SUCCESS;
1340 }
1341 if (*features) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001342 offset = LY_ARRAY_COUNT(*features);
Radek Krejci0af46292019-01-11 16:02:31 +01001343 }
1344
Radek Krejci327de162019-06-14 12:52:07 +02001345 lysc_update_path(ctx_sc, NULL, "{feature}");
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001346 LY_ARRAY_CREATE_RET(ctx_sc->ctx, *features, LY_ARRAY_COUNT(features_p), LY_EMEM);
Radek Krejci0af46292019-01-11 16:02:31 +01001347 LY_ARRAY_FOR(features_p, u) {
Radek Krejci327de162019-06-14 12:52:07 +02001348 lysc_update_path(ctx_sc, NULL, features_p[u].name);
1349
Radek Krejci0af46292019-01-11 16:02:31 +01001350 LY_ARRAY_INCREMENT(*features);
Michal Vasko6f4cbb62020-02-28 11:15:47 +01001351 COMPILE_CHECK_UNIQUENESS_ARRAY(ctx_sc, *features, name, &(*features)[offset + u], "feature", features_p[u].name);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001352 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].name, (*features)[offset + u].name, ret, done);
1353 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].dsc, (*features)[offset + u].dsc, ret, done);
1354 DUP_STRING_GOTO(ctx_sc->ctx, features_p[u].ref, (*features)[offset + u].ref, ret, done);
Radek Krejci0af46292019-01-11 16:02:31 +01001355 (*features)[offset + u].flags = features_p[u].flags;
Radek Krejci327de162019-06-14 12:52:07 +02001356 (*features)[offset + u].module = ctx_sc->mod;
1357
1358 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci0af46292019-01-11 16:02:31 +01001359 }
Radek Krejci327de162019-06-14 12:52:07 +02001360 lysc_update_path(ctx_sc, NULL, NULL);
Radek Krejci0af46292019-01-11 16:02:31 +01001361
Radek Krejci011e4aa2020-09-04 15:22:31 +02001362done:
1363 return ret;
Radek Krejci0af46292019-01-11 16:02:31 +01001364}
1365
Radek Krejcia3045382018-11-22 14:30:31 +01001366/**
Radek Krejci09a1fc52019-02-13 10:55:17 +01001367 * @brief Check circular dependency of features - feature MUST NOT reference itself (via their if-feature statement).
Radek Krejcib56c7502019-02-13 14:19:54 +01001368 *
1369 * The function works in the same way as lys_compile_identity_circular_check() with different structures and error messages.
1370 *
Radek Krejci09a1fc52019-02-13 10:55:17 +01001371 * @param[in] ctx Compile context for logging.
Radek Krejcib56c7502019-02-13 14:19:54 +01001372 * @param[in] feature The feature referenced in if-feature statement (its depfeatures list is being extended by the feature
1373 * being currently processed).
1374 * @param[in] depfeatures The list of depending features of the feature being currently processed (not the one provided as @p feature)
Radek Krejci09a1fc52019-02-13 10:55:17 +01001375 * @return LY_SUCCESS if everything is ok.
1376 * @return LY_EVALID if the feature references indirectly itself.
1377 */
1378static LY_ERR
1379lys_compile_feature_circular_check(struct lysc_ctx *ctx, struct lysc_feature *feature, struct lysc_feature **depfeatures)
1380{
Radek Krejciba03a5a2020-08-27 14:40:41 +02001381 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001382 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001383 struct ly_set recursion = {0};
1384 struct lysc_feature *drv;
1385
1386 if (!depfeatures) {
1387 return LY_SUCCESS;
1388 }
1389
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001390 for (u = 0; u < LY_ARRAY_COUNT(depfeatures); ++u) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001391 if (feature == depfeatures[u]) {
1392 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001393 "Feature \"%s\" is indirectly referenced from itself.", feature->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001394 ret = LY_EVALID;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001395 goto cleanup;
1396 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001397 ret = ly_set_add(&recursion, depfeatures[u], 0, NULL);
1398 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001399 }
1400
1401 for (v = 0; v < recursion.count; ++v) {
1402 drv = recursion.objs[v];
1403 if (!drv->depfeatures) {
1404 continue;
1405 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001406 for (u = 0; u < LY_ARRAY_COUNT(drv->depfeatures); ++u) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001407 if (feature == drv->depfeatures[u]) {
1408 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001409 "Feature \"%s\" is indirectly referenced from itself.", feature->name);
Radek Krejciba03a5a2020-08-27 14:40:41 +02001410 ret = LY_EVALID;
Radek Krejci09a1fc52019-02-13 10:55:17 +01001411 goto cleanup;
1412 }
Radek Krejciba03a5a2020-08-27 14:40:41 +02001413 ly_set_add(&recursion, drv->depfeatures[u], 0, NULL);
1414 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001415 }
1416 }
Radek Krejci09a1fc52019-02-13 10:55:17 +01001417
1418cleanup:
1419 ly_set_erase(&recursion, NULL);
1420 return ret;
1421}
1422
1423/**
Radek Krejci0af46292019-01-11 16:02:31 +01001424 * @brief Create pre-compiled features array.
1425 *
1426 * See lys_feature_precompile() for more details.
1427 *
Radek Krejcia3045382018-11-22 14:30:31 +01001428 * @param[in] ctx Compile context.
1429 * @param[in] feature_p Parsed feature definition to compile.
Radek Krejci0af46292019-01-11 16:02:31 +01001430 * @param[in,out] features List of already (pre)compiled features to find the corresponding precompiled feature structure.
Radek Krejcia3045382018-11-22 14:30:31 +01001431 * @return LY_ERR value.
1432 */
Radek Krejci19a96102018-11-15 13:38:09 +01001433static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02001434lys_feature_precompile_finish(struct lysc_ctx *ctx, struct lysp_feature *feature_p, struct lysc_feature *features)
Radek Krejci19a96102018-11-15 13:38:09 +01001435{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001436 LY_ARRAY_COUNT_TYPE u, v, x;
Radek Krejci0af46292019-01-11 16:02:31 +01001437 struct lysc_feature *feature, **df;
Radek Krejci19a96102018-11-15 13:38:09 +01001438 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +01001439
Radek Krejci0af46292019-01-11 16:02:31 +01001440 /* find the preprecompiled feature */
1441 LY_ARRAY_FOR(features, x) {
1442 if (strcmp(features[x].name, feature_p->name)) {
1443 continue;
1444 }
1445 feature = &features[x];
Radek Krejci327de162019-06-14 12:52:07 +02001446 lysc_update_path(ctx, NULL, "{feature}");
1447 lysc_update_path(ctx, NULL, feature_p->name);
Radek Krejci19a96102018-11-15 13:38:09 +01001448
Radek Krejci0af46292019-01-11 16:02:31 +01001449 /* finish compilation started in lys_feature_precompile() */
Radek Krejci0935f412019-08-20 16:15:18 +02001450 COMPILE_EXTS_GOTO(ctx, feature_p->exts, feature->exts, feature, LYEXT_PAR_FEATURE, ret, done);
Radek Krejciec4da802019-05-02 13:02:41 +02001451 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, u, lys_compile_iffeature, ret, done);
Radek Krejci0af46292019-01-11 16:02:31 +01001452 if (feature->iffeatures) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001453 for (u = 0; u < LY_ARRAY_COUNT(feature->iffeatures); ++u) {
Radek Krejci0af46292019-01-11 16:02:31 +01001454 if (feature->iffeatures[u].features) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001455 for (v = 0; v < LY_ARRAY_COUNT(feature->iffeatures[u].features); ++v) {
Radek Krejci09a1fc52019-02-13 10:55:17 +01001456 /* check for circular dependency - direct reference first,... */
1457 if (feature == feature->iffeatures[u].features[v]) {
1458 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02001459 "Feature \"%s\" is referenced from itself.", feature->name);
Radek Krejci09a1fc52019-02-13 10:55:17 +01001460 return LY_EVALID;
1461 }
1462 /* ... and indirect circular reference */
1463 LY_CHECK_RET(lys_compile_feature_circular_check(ctx, feature->iffeatures[u].features[v], feature->depfeatures));
1464
Radek Krejci0af46292019-01-11 16:02:31 +01001465 /* add itself into the dependants list */
1466 LY_ARRAY_NEW_RET(ctx->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
1467 *df = feature;
1468 }
Radek Krejci19a96102018-11-15 13:38:09 +01001469 }
Radek Krejci19a96102018-11-15 13:38:09 +01001470 }
1471 }
Radek Krejci327de162019-06-14 12:52:07 +02001472 lysc_update_path(ctx, NULL, NULL);
1473 lysc_update_path(ctx, NULL, NULL);
Michal Vasko69730152020-10-09 16:30:07 +02001474done:
Radek Krejci0af46292019-01-11 16:02:31 +01001475 return ret;
Radek Krejci19a96102018-11-15 13:38:09 +01001476 }
Radek Krejci0af46292019-01-11 16:02:31 +01001477
1478 LOGINT(ctx->ctx);
1479 return LY_EINT;
Radek Krejci19a96102018-11-15 13:38:09 +01001480}
1481
Radek Krejcib56c7502019-02-13 14:19:54 +01001482/**
1483 * @brief Revert compiled list of features back to the precompiled state.
1484 *
1485 * Function is needed in case the compilation failed and the schema is expected to revert back to the non-compiled status.
Radek Krejcib56c7502019-02-13 14:19:54 +01001486 *
1487 * @param[in] ctx Compilation context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02001488 * @param[in] mod The module structure with the features to decompile.
Radek Krejcib56c7502019-02-13 14:19:54 +01001489 */
Radek Krejci95710c92019-02-11 15:49:55 +01001490static void
1491lys_feature_precompile_revert(struct lysc_ctx *ctx, struct lys_module *mod)
1492{
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001493 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci95710c92019-02-11 15:49:55 +01001494
Michal Vasko33ff9422020-07-03 09:50:39 +02001495 /* in the dis_features list, remove all the parts (from finished compiling process)
Radek Krejci95710c92019-02-11 15:49:55 +01001496 * which may points into the data being freed here */
Radek Krejci14915cc2020-09-14 17:28:13 +02001497 LY_ARRAY_FOR(mod->features, u) {
1498 LY_ARRAY_FOR(mod->features[u].iffeatures, v) {
1499 lysc_iffeature_free(ctx->ctx, &mod->features[u].iffeatures[v]);
Radek Krejci95710c92019-02-11 15:49:55 +01001500 }
Radek Krejci14915cc2020-09-14 17:28:13 +02001501 LY_ARRAY_FREE(mod->features[u].iffeatures);
1502 mod->features[u].iffeatures = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01001503
Radek Krejci14915cc2020-09-14 17:28:13 +02001504 LY_ARRAY_FOR(mod->features[u].exts, v) {
1505 lysc_ext_instance_free(ctx->ctx, &(mod->features[u].exts)[v]);
Radek Krejci95710c92019-02-11 15:49:55 +01001506 }
Radek Krejci14915cc2020-09-14 17:28:13 +02001507 LY_ARRAY_FREE(mod->features[u].exts);
1508 mod->features[u].exts = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01001509 }
1510}
1511
Radek Krejcia3045382018-11-22 14:30:31 +01001512/**
1513 * @brief Validate and normalize numeric value from a range definition.
1514 * @param[in] ctx Compile context.
1515 * @param[in] basetype Base YANG built-in type of the node connected with the range restriction. Actually only LY_TYPE_DEC64 is important to
1516 * allow processing of the fractions. The fraction point is extracted from the value which is then normalize according to given frdigits into
1517 * valcopy to allow easy parsing and storing of the value. libyang stores decimal number without the decimal point which is always recovered from
1518 * the known fraction-digits value. So, with fraction-digits 2, number 3.14 is stored as 314 and number 1 is stored as 100.
1519 * @param[in] frdigits The fraction-digits of the type in case of LY_TYPE_DEC64.
1520 * @param[in] value String value of the range boundary.
1521 * @param[out] len Number of the processed bytes from the value. Processing stops on the first character which is not part of the number boundary.
1522 * @param[out] valcopy NULL-terminated string with the numeric value to parse and store.
1523 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID (no number) or LY_EINVAL (decimal64 not matching fraction-digits value).
1524 */
Radek Krejcie88beef2019-05-30 15:47:19 +02001525LY_ERR
Radek Krejci6cba4292018-11-15 17:33:29 +01001526range_part_check_value_syntax(struct lysc_ctx *ctx, LY_DATA_TYPE basetype, uint8_t frdigits, const char *value, size_t *len, char **valcopy)
Radek Krejci19a96102018-11-15 13:38:09 +01001527{
Radek Krejci6cba4292018-11-15 17:33:29 +01001528 size_t fraction = 0, size;
1529
Radek Krejci19a96102018-11-15 13:38:09 +01001530 *len = 0;
1531
1532 assert(value);
1533 /* parse value */
1534 if (!isdigit(value[*len]) && (value[*len] != '-') && (value[*len] != '+')) {
1535 return LY_EVALID;
1536 }
1537
1538 if ((value[*len] == '-') || (value[*len] == '+')) {
1539 ++(*len);
1540 }
1541
1542 while (isdigit(value[*len])) {
1543 ++(*len);
1544 }
1545
1546 if ((basetype != LY_TYPE_DEC64) || (value[*len] != '.') || !isdigit(value[*len + 1])) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001547 if (basetype == LY_TYPE_DEC64) {
1548 goto decimal;
1549 } else {
1550 *valcopy = strndup(value, *len);
1551 return LY_SUCCESS;
1552 }
Radek Krejci19a96102018-11-15 13:38:09 +01001553 }
1554 fraction = *len;
1555
1556 ++(*len);
1557 while (isdigit(value[*len])) {
1558 ++(*len);
1559 }
1560
Radek Krejci6cba4292018-11-15 17:33:29 +01001561 if (basetype == LY_TYPE_DEC64) {
1562decimal:
1563 assert(frdigits);
Radek Krejci943177f2019-06-14 16:32:43 +02001564 if (fraction && (*len - 1 - fraction > frdigits)) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001565 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001566 "Range boundary \"%.*s\" of decimal64 type exceeds defined number (%u) of fraction digits.",
1567 *len, value, frdigits);
Radek Krejci6cba4292018-11-15 17:33:29 +01001568 return LY_EINVAL;
1569 }
1570 if (fraction) {
1571 size = (*len) + (frdigits - ((*len) - 1 - fraction));
1572 } else {
1573 size = (*len) + frdigits + 1;
1574 }
1575 *valcopy = malloc(size * sizeof **valcopy);
Radek Krejci19a96102018-11-15 13:38:09 +01001576 LY_CHECK_ERR_RET(!(*valcopy), LOGMEM(ctx->ctx), LY_EMEM);
1577
Radek Krejci6cba4292018-11-15 17:33:29 +01001578 (*valcopy)[size - 1] = '\0';
1579 if (fraction) {
1580 memcpy(&(*valcopy)[0], &value[0], fraction);
1581 memcpy(&(*valcopy)[fraction], &value[fraction + 1], (*len) - 1 - (fraction));
1582 memset(&(*valcopy)[(*len) - 1], '0', frdigits - ((*len) - 1 - fraction));
1583 } else {
1584 memcpy(&(*valcopy)[0], &value[0], *len);
1585 memset(&(*valcopy)[*len], '0', frdigits);
1586 }
Radek Krejci19a96102018-11-15 13:38:09 +01001587 }
1588 return LY_SUCCESS;
1589}
1590
Radek Krejcia3045382018-11-22 14:30:31 +01001591/**
1592 * @brief Check that values in range are in ascendant order.
1593 * @param[in] unsigned_value Flag to note that we are working with unsigned values.
Radek Krejci5969f272018-11-23 10:03:58 +01001594 * @param[in] max Flag to distinguish if checking min or max value. min value must be strictly higher than previous,
1595 * max can be also equal.
Radek Krejcia3045382018-11-22 14:30:31 +01001596 * @param[in] value Current value to check.
1597 * @param[in] prev_value The last seen value.
1598 * @return LY_SUCCESS or LY_EEXIST for invalid order.
1599 */
Radek Krejci19a96102018-11-15 13:38:09 +01001600static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001601range_part_check_ascendancy(ly_bool unsigned_value, ly_bool max, int64_t value, int64_t prev_value)
Radek Krejci19a96102018-11-15 13:38:09 +01001602{
1603 if (unsigned_value) {
Michal Vasko69730152020-10-09 16:30:07 +02001604 if ((max && ((uint64_t)prev_value > (uint64_t)value)) || (!max && ((uint64_t)prev_value >= (uint64_t)value))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001605 return LY_EEXIST;
1606 }
1607 } else {
Michal Vasko69730152020-10-09 16:30:07 +02001608 if ((max && (prev_value > value)) || (!max && (prev_value >= value))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001609 return LY_EEXIST;
1610 }
1611 }
1612 return LY_SUCCESS;
1613}
1614
Radek Krejcia3045382018-11-22 14:30:31 +01001615/**
1616 * @brief Set min/max value of the range part.
1617 * @param[in] ctx Compile context.
1618 * @param[in] part Range part structure to fill.
1619 * @param[in] max Flag to distinguish if storing min or max value.
1620 * @param[in] prev The last seen value to check that all values in range are specified in ascendant order.
1621 * @param[in] basetype Type of the value to get know implicit min/max values and other checking rules.
1622 * @param[in] first Flag for the first value of the range to avoid ascendancy order.
1623 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
1624 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
Radek Krejci5969f272018-11-23 10:03:58 +01001625 * @param[in] base_range Range from the type from which the current type is derived (if not built-in) to get type's min and max values.
Radek Krejcia3045382018-11-22 14:30:31 +01001626 * @param[in,out] value Numeric range value to be stored, if not provided the type's min/max value is set.
1627 * @return LY_ERR value - LY_SUCCESS, LY_EDENIED (value brokes type's boundaries), LY_EVALID (not a number),
1628 * LY_EEXIST (value is smaller than the previous one), LY_EINVAL (decimal64 value does not corresponds with the
1629 * frdigits value), LY_EMEM.
1630 */
Radek Krejci19a96102018-11-15 13:38:09 +01001631static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001632range_part_minmax(struct lysc_ctx *ctx, struct lysc_range_part *part, ly_bool max, int64_t prev, LY_DATA_TYPE basetype,
1633 ly_bool first, ly_bool length_restr, uint8_t frdigits, struct lysc_range *base_range, const char **value)
Radek Krejci19a96102018-11-15 13:38:09 +01001634{
1635 LY_ERR ret = LY_SUCCESS;
1636 char *valcopy = NULL;
1637 size_t len;
1638
1639 if (value) {
Radek Krejci6cba4292018-11-15 17:33:29 +01001640 ret = range_part_check_value_syntax(ctx, basetype, frdigits, *value, &len, &valcopy);
Radek Krejci5969f272018-11-23 10:03:58 +01001641 LY_CHECK_GOTO(ret, finalize);
1642 }
1643 if (!valcopy && base_range) {
1644 if (max) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001645 part->max_64 = base_range->parts[LY_ARRAY_COUNT(base_range->parts) - 1].max_64;
Radek Krejci5969f272018-11-23 10:03:58 +01001646 } else {
1647 part->min_64 = base_range->parts[0].min_64;
1648 }
1649 if (!first) {
1650 ret = range_part_check_ascendancy(basetype <= LY_TYPE_STRING ? 1 : 0, max, max ? part->max_64 : part->min_64, prev);
1651 }
1652 goto finalize;
Radek Krejci19a96102018-11-15 13:38:09 +01001653 }
1654
1655 switch (basetype) {
Radek Krejci19a96102018-11-15 13:38:09 +01001656 case LY_TYPE_INT8: /* range */
1657 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001658 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-128), INT64_C(127), 10, max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001659 } else if (max) {
1660 part->max_64 = INT64_C(127);
1661 } else {
1662 part->min_64 = INT64_C(-128);
1663 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001664 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001665 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001666 }
1667 break;
1668 case LY_TYPE_INT16: /* range */
1669 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001670 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-32768), INT64_C(32767), 10, max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001671 } else if (max) {
1672 part->max_64 = INT64_C(32767);
1673 } else {
1674 part->min_64 = INT64_C(-32768);
1675 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001676 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001677 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001678 }
1679 break;
1680 case LY_TYPE_INT32: /* range */
1681 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001682 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-2147483648), INT64_C(2147483647), 10, max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001683 } else if (max) {
1684 part->max_64 = INT64_C(2147483647);
1685 } else {
1686 part->min_64 = INT64_C(-2147483648);
1687 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001688 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001689 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001690 }
1691 break;
1692 case LY_TYPE_INT64: /* range */
Radek Krejci25cfef72018-11-23 14:15:52 +01001693 case LY_TYPE_DEC64: /* range */
Radek Krejci19a96102018-11-15 13:38:09 +01001694 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001695 ret = ly_parse_int(valcopy, strlen(valcopy), INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(9223372036854775807), 10,
Michal Vasko69730152020-10-09 16:30:07 +02001696 max ? &part->max_64 : &part->min_64);
Radek Krejci19a96102018-11-15 13:38:09 +01001697 } else if (max) {
1698 part->max_64 = INT64_C(9223372036854775807);
1699 } else {
1700 part->min_64 = INT64_C(-9223372036854775807) - INT64_C(1);
1701 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001702 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001703 ret = range_part_check_ascendancy(0, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001704 }
1705 break;
1706 case LY_TYPE_UINT8: /* range */
1707 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001708 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(255), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001709 } else if (max) {
1710 part->max_u64 = UINT64_C(255);
1711 } else {
1712 part->min_u64 = UINT64_C(0);
1713 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001714 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001715 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001716 }
1717 break;
1718 case LY_TYPE_UINT16: /* range */
1719 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001720 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(65535), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001721 } else if (max) {
1722 part->max_u64 = UINT64_C(65535);
1723 } else {
1724 part->min_u64 = UINT64_C(0);
1725 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001726 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001727 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001728 }
1729 break;
1730 case LY_TYPE_UINT32: /* range */
1731 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001732 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(4294967295), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001733 } else if (max) {
1734 part->max_u64 = UINT64_C(4294967295);
1735 } else {
1736 part->min_u64 = UINT64_C(0);
1737 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001738 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001739 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001740 }
1741 break;
1742 case LY_TYPE_UINT64: /* range */
Radek Krejci19a96102018-11-15 13:38:09 +01001743 case LY_TYPE_STRING: /* length */
Radek Krejci25cfef72018-11-23 14:15:52 +01001744 case LY_TYPE_BINARY: /* length */
Radek Krejci19a96102018-11-15 13:38:09 +01001745 if (valcopy) {
Radek Krejci249973a2019-06-10 10:50:54 +02001746 ret = ly_parse_uint(valcopy, strlen(valcopy), UINT64_C(18446744073709551615), 10, max ? &part->max_u64 : &part->min_u64);
Radek Krejci19a96102018-11-15 13:38:09 +01001747 } else if (max) {
1748 part->max_u64 = UINT64_C(18446744073709551615);
1749 } else {
1750 part->min_u64 = UINT64_C(0);
1751 }
Radek Krejci6cba4292018-11-15 17:33:29 +01001752 if (!ret && !first) {
Radek Krejci5969f272018-11-23 10:03:58 +01001753 ret = range_part_check_ascendancy(1, max, max ? part->max_64 : part->min_64, prev);
Radek Krejci19a96102018-11-15 13:38:09 +01001754 }
1755 break;
1756 default:
1757 LOGINT(ctx->ctx);
1758 ret = LY_EINT;
1759 }
1760
Radek Krejci5969f272018-11-23 10:03:58 +01001761finalize:
Radek Krejci19a96102018-11-15 13:38:09 +01001762 if (ret == LY_EDENIED) {
1763 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001764 "Invalid %s restriction - value \"%s\" does not fit the type limitations.",
1765 length_restr ? "length" : "range", valcopy ? valcopy : *value);
Radek Krejci19a96102018-11-15 13:38:09 +01001766 } else if (ret == LY_EVALID) {
1767 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001768 "Invalid %s restriction - invalid value \"%s\".",
1769 length_restr ? "length" : "range", valcopy ? valcopy : *value);
Radek Krejci19a96102018-11-15 13:38:09 +01001770 } else if (ret == LY_EEXIST) {
1771 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001772 "Invalid %s restriction - values are not in ascending order (%s).",
1773 length_restr ? "length" : "range",
Radek Krejci0f969882020-08-21 16:56:47 +02001774 (valcopy && basetype != LY_TYPE_DEC64) ? valcopy : value ? *value : max ? "max" : "min");
Radek Krejci19a96102018-11-15 13:38:09 +01001775 } else if (!ret && value) {
1776 *value = *value + len;
1777 }
1778 free(valcopy);
1779 return ret;
1780}
1781
Radek Krejcia3045382018-11-22 14:30:31 +01001782/**
1783 * @brief Compile the parsed range restriction.
1784 * @param[in] ctx Compile context.
1785 * @param[in] range_p Parsed range structure to compile.
1786 * @param[in] basetype Base YANG built-in type of the node with the range restriction.
1787 * @param[in] length_restr Flag to distinguish between range and length restrictions. Only for logging.
1788 * @param[in] frdigits The fraction-digits value in case of LY_TYPE_DEC64 basetype.
1789 * @param[in] base_range Range restriction of the type from which the current type is derived. The current
1790 * range restriction must be more restrictive than the base_range.
1791 * @param[in,out] range Pointer to the created current range structure.
1792 * @return LY_ERR value.
1793 */
Radek Krejci19a96102018-11-15 13:38:09 +01001794static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +02001795lys_compile_type_range(struct lysc_ctx *ctx, struct lysp_restr *range_p, LY_DATA_TYPE basetype, ly_bool length_restr,
Radek Krejci0f969882020-08-21 16:56:47 +02001796 uint8_t frdigits, struct lysc_range *base_range, struct lysc_range **range)
Radek Krejci19a96102018-11-15 13:38:09 +01001797{
1798 LY_ERR ret = LY_EVALID;
1799 const char *expr;
1800 struct lysc_range_part *parts = NULL, *part;
Radek Krejci857189e2020-09-01 13:26:36 +02001801 ly_bool range_expected = 0, uns;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001802 LY_ARRAY_COUNT_TYPE parts_done = 0, u, v;
Radek Krejci19a96102018-11-15 13:38:09 +01001803
1804 assert(range);
1805 assert(range_p);
1806
Michal Vasko7f45cf22020-10-01 12:49:44 +02001807 expr = range_p->arg.str;
Michal Vaskod989ba02020-08-24 10:59:24 +02001808 while (1) {
Radek Krejci19a96102018-11-15 13:38:09 +01001809 if (isspace(*expr)) {
1810 ++expr;
1811 } else if (*expr == '\0') {
1812 if (range_expected) {
1813 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001814 "Invalid %s restriction - unexpected end of the expression after \"..\" (%s).",
1815 length_restr ? "length" : "range", range_p->arg);
Radek Krejci19a96102018-11-15 13:38:09 +01001816 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02001817 } else if (!parts || (parts_done == LY_ARRAY_COUNT(parts))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001818 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001819 "Invalid %s restriction - unexpected end of the expression (%s).",
1820 length_restr ? "length" : "range", range_p->arg);
Radek Krejci19a96102018-11-15 13:38:09 +01001821 goto cleanup;
1822 }
1823 parts_done++;
1824 break;
1825 } else if (!strncmp(expr, "min", 3)) {
1826 if (parts) {
1827 /* min cannot be used elsewhere than in the first part */
1828 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001829 "Invalid %s restriction - unexpected data before min keyword (%.*s).", length_restr ? "length" : "range",
1830 expr - range_p->arg.str, range_p->arg.str);
Radek Krejci19a96102018-11-15 13:38:09 +01001831 goto cleanup;
1832 }
1833 expr += 3;
1834
1835 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Radek Krejci5969f272018-11-23 10:03:58 +01001836 LY_CHECK_GOTO(range_part_minmax(ctx, part, 0, 0, basetype, 1, length_restr, frdigits, base_range, NULL), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001837 part->max_64 = part->min_64;
1838 } else if (*expr == '|') {
1839 if (!parts || range_expected) {
1840 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001841 "Invalid %s restriction - unexpected beginning of the expression (%s).", length_restr ? "length" : "range", expr);
Radek Krejci19a96102018-11-15 13:38:09 +01001842 goto cleanup;
1843 }
1844 expr++;
1845 parts_done++;
1846 /* process next part of the expression */
1847 } else if (!strncmp(expr, "..", 2)) {
1848 expr += 2;
1849 while (isspace(*expr)) {
1850 expr++;
1851 }
Michal Vasko69730152020-10-09 16:30:07 +02001852 if (!parts || (LY_ARRAY_COUNT(parts) == parts_done)) {
Radek Krejci19a96102018-11-15 13:38:09 +01001853 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001854 "Invalid %s restriction - unexpected \"..\" without a lower bound.", length_restr ? "length" : "range");
Radek Krejci19a96102018-11-15 13:38:09 +01001855 goto cleanup;
1856 }
1857 /* continue expecting the upper boundary */
1858 range_expected = 1;
1859 } else if (isdigit(*expr) || (*expr == '-') || (*expr == '+')) {
1860 /* number */
1861 if (range_expected) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001862 part = &parts[LY_ARRAY_COUNT(parts) - 1];
Radek Krejci5969f272018-11-23 10:03:58 +01001863 LY_CHECK_GOTO(range_part_minmax(ctx, part, 1, part->min_64, basetype, 0, length_restr, frdigits, NULL, &expr), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001864 range_expected = 0;
1865 } else {
1866 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001867 LY_CHECK_GOTO(range_part_minmax(ctx, part, 0, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Michal Vasko69730152020-10-09 16:30:07 +02001868 basetype, parts_done ? 0 : 1, length_restr, frdigits, NULL, &expr), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001869 part->max_64 = part->min_64;
1870 }
1871
1872 /* continue with possible another expression part */
1873 } else if (!strncmp(expr, "max", 3)) {
1874 expr += 3;
1875 while (isspace(*expr)) {
1876 expr++;
1877 }
1878 if (*expr != '\0') {
1879 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data after max keyword (%s).",
Michal Vasko69730152020-10-09 16:30:07 +02001880 length_restr ? "length" : "range", expr);
Radek Krejci19a96102018-11-15 13:38:09 +01001881 goto cleanup;
1882 }
1883 if (range_expected) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001884 part = &parts[LY_ARRAY_COUNT(parts) - 1];
Radek Krejci5969f272018-11-23 10:03:58 +01001885 LY_CHECK_GOTO(range_part_minmax(ctx, part, 1, part->min_64, basetype, 0, length_restr, frdigits, base_range, NULL), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001886 range_expected = 0;
1887 } else {
1888 LY_ARRAY_NEW_GOTO(ctx->ctx, parts, part, ret, cleanup);
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001889 LY_CHECK_GOTO(range_part_minmax(ctx, part, 1, parts_done ? parts[LY_ARRAY_COUNT(parts) - 2].max_64 : 0,
Michal Vasko69730152020-10-09 16:30:07 +02001890 basetype, parts_done ? 0 : 1, length_restr, frdigits, base_range, NULL), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001891 part->min_64 = part->max_64;
1892 }
1893 } else {
1894 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s restriction - unexpected data (%s).",
Michal Vasko69730152020-10-09 16:30:07 +02001895 length_restr ? "length" : "range", expr);
Radek Krejci19a96102018-11-15 13:38:09 +01001896 goto cleanup;
1897 }
1898 }
1899
1900 /* check with the previous range/length restriction */
1901 if (base_range) {
1902 switch (basetype) {
1903 case LY_TYPE_BINARY:
1904 case LY_TYPE_UINT8:
1905 case LY_TYPE_UINT16:
1906 case LY_TYPE_UINT32:
1907 case LY_TYPE_UINT64:
1908 case LY_TYPE_STRING:
1909 uns = 1;
1910 break;
1911 case LY_TYPE_DEC64:
1912 case LY_TYPE_INT8:
1913 case LY_TYPE_INT16:
1914 case LY_TYPE_INT32:
1915 case LY_TYPE_INT64:
1916 uns = 0;
1917 break;
1918 default:
1919 LOGINT(ctx->ctx);
1920 ret = LY_EINT;
1921 goto cleanup;
1922 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001923 for (u = v = 0; u < parts_done && v < LY_ARRAY_COUNT(base_range->parts); ++u) {
Michal Vasko69730152020-10-09 16:30:07 +02001924 if ((uns && (parts[u].min_u64 < base_range->parts[v].min_u64)) || (!uns && (parts[u].min_64 < base_range->parts[v].min_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001925 goto baseerror;
1926 }
1927 /* current lower bound is not lower than the base */
1928 if (base_range->parts[v].min_64 == base_range->parts[v].max_64) {
1929 /* base has single value */
1930 if (base_range->parts[v].min_64 == parts[u].min_64) {
1931 /* both lower bounds are the same */
1932 if (parts[u].min_64 != parts[u].max_64) {
1933 /* current continues with a range */
1934 goto baseerror;
1935 } else {
1936 /* equal single values, move both forward */
1937 ++v;
1938 continue;
1939 }
1940 } else {
1941 /* base is single value lower than current range, so the
1942 * value from base range is removed in the current,
1943 * move only base and repeat checking */
1944 ++v;
1945 --u;
1946 continue;
1947 }
1948 } else {
1949 /* base is the range */
1950 if (parts[u].min_64 == parts[u].max_64) {
1951 /* current is a single value */
Michal Vasko69730152020-10-09 16:30:07 +02001952 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001953 /* current is behind the base range, so base range is omitted,
1954 * move the base and keep the current for further check */
1955 ++v;
1956 --u;
1957 } /* else it is within the base range, so move the current, but keep the base */
1958 continue;
1959 } else {
1960 /* both are ranges - check the higher bound, the lower was already checked */
Michal Vasko69730152020-10-09 16:30:07 +02001961 if ((uns && (parts[u].max_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].max_64 > base_range->parts[v].max_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001962 /* higher bound is higher than the current higher bound */
Michal Vasko69730152020-10-09 16:30:07 +02001963 if ((uns && (parts[u].min_u64 > base_range->parts[v].max_u64)) || (!uns && (parts[u].min_64 > base_range->parts[v].max_64))) {
Radek Krejci19a96102018-11-15 13:38:09 +01001964 /* but the current lower bound is also higher, so the base range is omitted,
1965 * continue with the same current, but move the base */
1966 --u;
1967 ++v;
1968 continue;
1969 }
1970 /* current range starts within the base range but end behind it */
1971 goto baseerror;
1972 } else {
1973 /* current range is smaller than the base,
1974 * move current, but stay with the base */
1975 continue;
1976 }
1977 }
1978 }
1979 }
1980 if (u != parts_done) {
1981baseerror:
1982 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02001983 "Invalid %s restriction - the derived restriction (%s) is not equally or more limiting.",
1984 length_restr ? "length" : "range", range_p->arg);
Radek Krejci19a96102018-11-15 13:38:09 +01001985 goto cleanup;
1986 }
1987 }
1988
1989 if (!(*range)) {
1990 *range = calloc(1, sizeof **range);
1991 LY_CHECK_ERR_RET(!(*range), LOGMEM(ctx->ctx), LY_EMEM);
1992 }
1993
Radek Krejcic8b31002019-01-08 10:24:45 +01001994 /* we rewrite the following values as the types chain is being processed */
Radek Krejci19a96102018-11-15 13:38:09 +01001995 if (range_p->eapptag) {
1996 lydict_remove(ctx->ctx, (*range)->eapptag);
Radek Krejci011e4aa2020-09-04 15:22:31 +02001997 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->eapptag, 0, &(*range)->eapptag), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01001998 }
1999 if (range_p->emsg) {
2000 lydict_remove(ctx->ctx, (*range)->emsg);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002001 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->emsg, 0, &(*range)->emsg), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01002002 }
Radek Krejcic8b31002019-01-08 10:24:45 +01002003 if (range_p->dsc) {
2004 lydict_remove(ctx->ctx, (*range)->dsc);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002005 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->dsc, 0, &(*range)->dsc), cleanup);
Radek Krejcic8b31002019-01-08 10:24:45 +01002006 }
2007 if (range_p->ref) {
2008 lydict_remove(ctx->ctx, (*range)->ref);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002009 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, range_p->ref, 0, &(*range)->ref), cleanup);
Radek Krejcic8b31002019-01-08 10:24:45 +01002010 }
Radek Krejci19a96102018-11-15 13:38:09 +01002011 /* extensions are taken only from the last range by the caller */
2012
2013 (*range)->parts = parts;
2014 parts = NULL;
2015 ret = LY_SUCCESS;
2016cleanup:
Radek Krejci19a96102018-11-15 13:38:09 +01002017 LY_ARRAY_FREE(parts);
2018
2019 return ret;
2020}
2021
2022/**
2023 * @brief Checks pattern syntax.
2024 *
Michal Vasko03ff5a72019-09-11 13:49:33 +02002025 * @param[in] ctx Context.
2026 * @param[in] log_path Path for logging errors.
Radek Krejci19a96102018-11-15 13:38:09 +01002027 * @param[in] pattern Pattern to check.
Radek Krejci54579462019-04-30 12:47:06 +02002028 * @param[in,out] pcre2_code Compiled PCRE2 pattern. If NULL, the compiled information used to validate pattern are freed.
Radek Krejcia3045382018-11-22 14:30:31 +01002029 * @return LY_ERR value - LY_SUCCESS, LY_EMEM, LY_EVALID.
Radek Krejci19a96102018-11-15 13:38:09 +01002030 */
Michal Vasko03ff5a72019-09-11 13:49:33 +02002031LY_ERR
2032lys_compile_type_pattern_check(struct ly_ctx *ctx, const char *log_path, const char *pattern, pcre2_code **code)
Radek Krejci19a96102018-11-15 13:38:09 +01002033{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002034 size_t idx, idx2, start, end, size, brack;
Radek Krejci19a96102018-11-15 13:38:09 +01002035 char *perl_regex, *ptr;
Radek Krejci54579462019-04-30 12:47:06 +02002036 int err_code;
2037 const char *orig_ptr;
2038 PCRE2_SIZE err_offset;
2039 pcre2_code *code_local;
Michal Vasko69730152020-10-09 16:30:07 +02002040
Radek Krejci19a96102018-11-15 13:38:09 +01002041#define URANGE_LEN 19
2042 char *ublock2urange[][2] = {
2043 {"BasicLatin", "[\\x{0000}-\\x{007F}]"},
2044 {"Latin-1Supplement", "[\\x{0080}-\\x{00FF}]"},
2045 {"LatinExtended-A", "[\\x{0100}-\\x{017F}]"},
2046 {"LatinExtended-B", "[\\x{0180}-\\x{024F}]"},
2047 {"IPAExtensions", "[\\x{0250}-\\x{02AF}]"},
2048 {"SpacingModifierLetters", "[\\x{02B0}-\\x{02FF}]"},
2049 {"CombiningDiacriticalMarks", "[\\x{0300}-\\x{036F}]"},
2050 {"Greek", "[\\x{0370}-\\x{03FF}]"},
2051 {"Cyrillic", "[\\x{0400}-\\x{04FF}]"},
2052 {"Armenian", "[\\x{0530}-\\x{058F}]"},
2053 {"Hebrew", "[\\x{0590}-\\x{05FF}]"},
2054 {"Arabic", "[\\x{0600}-\\x{06FF}]"},
2055 {"Syriac", "[\\x{0700}-\\x{074F}]"},
2056 {"Thaana", "[\\x{0780}-\\x{07BF}]"},
2057 {"Devanagari", "[\\x{0900}-\\x{097F}]"},
2058 {"Bengali", "[\\x{0980}-\\x{09FF}]"},
2059 {"Gurmukhi", "[\\x{0A00}-\\x{0A7F}]"},
2060 {"Gujarati", "[\\x{0A80}-\\x{0AFF}]"},
2061 {"Oriya", "[\\x{0B00}-\\x{0B7F}]"},
2062 {"Tamil", "[\\x{0B80}-\\x{0BFF}]"},
2063 {"Telugu", "[\\x{0C00}-\\x{0C7F}]"},
2064 {"Kannada", "[\\x{0C80}-\\x{0CFF}]"},
2065 {"Malayalam", "[\\x{0D00}-\\x{0D7F}]"},
2066 {"Sinhala", "[\\x{0D80}-\\x{0DFF}]"},
2067 {"Thai", "[\\x{0E00}-\\x{0E7F}]"},
2068 {"Lao", "[\\x{0E80}-\\x{0EFF}]"},
2069 {"Tibetan", "[\\x{0F00}-\\x{0FFF}]"},
2070 {"Myanmar", "[\\x{1000}-\\x{109F}]"},
2071 {"Georgian", "[\\x{10A0}-\\x{10FF}]"},
2072 {"HangulJamo", "[\\x{1100}-\\x{11FF}]"},
2073 {"Ethiopic", "[\\x{1200}-\\x{137F}]"},
2074 {"Cherokee", "[\\x{13A0}-\\x{13FF}]"},
2075 {"UnifiedCanadianAboriginalSyllabics", "[\\x{1400}-\\x{167F}]"},
2076 {"Ogham", "[\\x{1680}-\\x{169F}]"},
2077 {"Runic", "[\\x{16A0}-\\x{16FF}]"},
2078 {"Khmer", "[\\x{1780}-\\x{17FF}]"},
2079 {"Mongolian", "[\\x{1800}-\\x{18AF}]"},
2080 {"LatinExtendedAdditional", "[\\x{1E00}-\\x{1EFF}]"},
2081 {"GreekExtended", "[\\x{1F00}-\\x{1FFF}]"},
2082 {"GeneralPunctuation", "[\\x{2000}-\\x{206F}]"},
2083 {"SuperscriptsandSubscripts", "[\\x{2070}-\\x{209F}]"},
2084 {"CurrencySymbols", "[\\x{20A0}-\\x{20CF}]"},
2085 {"CombiningMarksforSymbols", "[\\x{20D0}-\\x{20FF}]"},
2086 {"LetterlikeSymbols", "[\\x{2100}-\\x{214F}]"},
2087 {"NumberForms", "[\\x{2150}-\\x{218F}]"},
2088 {"Arrows", "[\\x{2190}-\\x{21FF}]"},
2089 {"MathematicalOperators", "[\\x{2200}-\\x{22FF}]"},
2090 {"MiscellaneousTechnical", "[\\x{2300}-\\x{23FF}]"},
2091 {"ControlPictures", "[\\x{2400}-\\x{243F}]"},
2092 {"OpticalCharacterRecognition", "[\\x{2440}-\\x{245F}]"},
2093 {"EnclosedAlphanumerics", "[\\x{2460}-\\x{24FF}]"},
2094 {"BoxDrawing", "[\\x{2500}-\\x{257F}]"},
2095 {"BlockElements", "[\\x{2580}-\\x{259F}]"},
2096 {"GeometricShapes", "[\\x{25A0}-\\x{25FF}]"},
2097 {"MiscellaneousSymbols", "[\\x{2600}-\\x{26FF}]"},
2098 {"Dingbats", "[\\x{2700}-\\x{27BF}]"},
2099 {"BraillePatterns", "[\\x{2800}-\\x{28FF}]"},
2100 {"CJKRadicalsSupplement", "[\\x{2E80}-\\x{2EFF}]"},
2101 {"KangxiRadicals", "[\\x{2F00}-\\x{2FDF}]"},
2102 {"IdeographicDescriptionCharacters", "[\\x{2FF0}-\\x{2FFF}]"},
2103 {"CJKSymbolsandPunctuation", "[\\x{3000}-\\x{303F}]"},
2104 {"Hiragana", "[\\x{3040}-\\x{309F}]"},
2105 {"Katakana", "[\\x{30A0}-\\x{30FF}]"},
2106 {"Bopomofo", "[\\x{3100}-\\x{312F}]"},
2107 {"HangulCompatibilityJamo", "[\\x{3130}-\\x{318F}]"},
2108 {"Kanbun", "[\\x{3190}-\\x{319F}]"},
2109 {"BopomofoExtended", "[\\x{31A0}-\\x{31BF}]"},
2110 {"EnclosedCJKLettersandMonths", "[\\x{3200}-\\x{32FF}]"},
2111 {"CJKCompatibility", "[\\x{3300}-\\x{33FF}]"},
2112 {"CJKUnifiedIdeographsExtensionA", "[\\x{3400}-\\x{4DB5}]"},
2113 {"CJKUnifiedIdeographs", "[\\x{4E00}-\\x{9FFF}]"},
2114 {"YiSyllables", "[\\x{A000}-\\x{A48F}]"},
2115 {"YiRadicals", "[\\x{A490}-\\x{A4CF}]"},
2116 {"HangulSyllables", "[\\x{AC00}-\\x{D7A3}]"},
2117 {"PrivateUse", "[\\x{E000}-\\x{F8FF}]"},
2118 {"CJKCompatibilityIdeographs", "[\\x{F900}-\\x{FAFF}]"},
2119 {"AlphabeticPresentationForms", "[\\x{FB00}-\\x{FB4F}]"},
2120 {"ArabicPresentationForms-A", "[\\x{FB50}-\\x{FDFF}]"},
2121 {"CombiningHalfMarks", "[\\x{FE20}-\\x{FE2F}]"},
2122 {"CJKCompatibilityForms", "[\\x{FE30}-\\x{FE4F}]"},
2123 {"SmallFormVariants", "[\\x{FE50}-\\x{FE6F}]"},
2124 {"ArabicPresentationForms-B", "[\\x{FE70}-\\x{FEFE}]"},
2125 {"HalfwidthandFullwidthForms", "[\\x{FF00}-\\x{FFEF}]"},
2126 {NULL, NULL}
2127 };
2128
2129 /* adjust the expression to a Perl equivalent
2130 * http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#regexs */
2131
Michal Vasko40a00082020-05-27 15:20:01 +02002132 /* allocate space for the transformed pattern */
2133 size = strlen(pattern) + 1;
2134 perl_regex = malloc(size);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002135 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002136 perl_regex[0] = '\0';
2137
Michal Vasko40a00082020-05-27 15:20:01 +02002138 /* we need to replace all "$" and "^" (that are not in "[]") with "\$" and "\^" */
2139 brack = 0;
2140 idx = 0;
2141 orig_ptr = pattern;
2142 while (orig_ptr[0]) {
2143 switch (orig_ptr[0]) {
2144 case '$':
2145 case '^':
2146 if (!brack) {
2147 /* make space for the extra character */
2148 ++size;
2149 perl_regex = ly_realloc(perl_regex, size);
2150 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002151
Michal Vasko40a00082020-05-27 15:20:01 +02002152 /* print escape slash */
2153 perl_regex[idx] = '\\';
2154 ++idx;
2155 }
2156 break;
2157 case '[':
2158 /* must not be escaped */
2159 if ((orig_ptr == pattern) || (orig_ptr[-1] != '\\')) {
2160 ++brack;
2161 }
2162 break;
2163 case ']':
2164 if ((orig_ptr == pattern) || (orig_ptr[-1] != '\\')) {
2165 /* pattern was checked and compiled already */
2166 assert(brack);
2167 --brack;
2168 }
2169 break;
2170 default:
2171 break;
Radek Krejci19a96102018-11-15 13:38:09 +01002172 }
Michal Vasko40a00082020-05-27 15:20:01 +02002173
2174 /* copy char */
2175 perl_regex[idx] = orig_ptr[0];
2176
2177 ++idx;
2178 ++orig_ptr;
Radek Krejci19a96102018-11-15 13:38:09 +01002179 }
Michal Vasko40a00082020-05-27 15:20:01 +02002180 perl_regex[idx] = '\0';
Radek Krejci19a96102018-11-15 13:38:09 +01002181
2182 /* substitute Unicode Character Blocks with exact Character Ranges */
2183 while ((ptr = strstr(perl_regex, "\\p{Is"))) {
2184 start = ptr - perl_regex;
2185
2186 ptr = strchr(ptr, '}');
2187 if (!ptr) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002188 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
Michal Vasko69730152020-10-09 16:30:07 +02002189 pattern, perl_regex + start + 2, "unterminated character property");
Radek Krejci19a96102018-11-15 13:38:09 +01002190 free(perl_regex);
2191 return LY_EVALID;
2192 }
2193 end = (ptr - perl_regex) + 1;
2194
2195 /* need more space */
2196 if (end - start < URANGE_LEN) {
2197 perl_regex = ly_realloc(perl_regex, strlen(perl_regex) + (URANGE_LEN - (end - start)) + 1);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002198 LY_CHECK_ERR_RET(!perl_regex, LOGMEM(ctx); free(perl_regex), LY_EMEM);
Radek Krejci19a96102018-11-15 13:38:09 +01002199 }
2200
2201 /* find our range */
2202 for (idx = 0; ublock2urange[idx][0]; ++idx) {
2203 if (!strncmp(perl_regex + start + 5, ublock2urange[idx][0], strlen(ublock2urange[idx][0]))) {
2204 break;
2205 }
2206 }
2207 if (!ublock2urange[idx][0]) {
Michal Vasko03ff5a72019-09-11 13:49:33 +02002208 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP,
Michal Vasko69730152020-10-09 16:30:07 +02002209 pattern, perl_regex + start + 5, "unknown block name");
Radek Krejci19a96102018-11-15 13:38:09 +01002210 free(perl_regex);
2211 return LY_EVALID;
2212 }
2213
2214 /* make the space in the string and replace the block (but we cannot include brackets if it was already enclosed in them) */
Michal Vasko40a00082020-05-27 15:20:01 +02002215 for (idx2 = 0, idx = 0; idx2 < start; ++idx2) {
Radek Krejci19a96102018-11-15 13:38:09 +01002216 if ((perl_regex[idx2] == '[') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
Michal Vasko40a00082020-05-27 15:20:01 +02002217 ++idx;
Radek Krejci19a96102018-11-15 13:38:09 +01002218 }
2219 if ((perl_regex[idx2] == ']') && (!idx2 || (perl_regex[idx2 - 1] != '\\'))) {
Michal Vasko40a00082020-05-27 15:20:01 +02002220 --idx;
Radek Krejci19a96102018-11-15 13:38:09 +01002221 }
2222 }
Michal Vasko40a00082020-05-27 15:20:01 +02002223 if (idx) {
Radek Krejci19a96102018-11-15 13:38:09 +01002224 /* skip brackets */
2225 memmove(perl_regex + start + (URANGE_LEN - 2), perl_regex + end, strlen(perl_regex + end) + 1);
2226 memcpy(perl_regex + start, ublock2urange[idx][1] + 1, URANGE_LEN - 2);
2227 } else {
2228 memmove(perl_regex + start + URANGE_LEN, perl_regex + end, strlen(perl_regex + end) + 1);
2229 memcpy(perl_regex + start, ublock2urange[idx][1], URANGE_LEN);
2230 }
2231 }
2232
2233 /* must return 0, already checked during parsing */
Radek Krejci5819f7c2019-05-31 14:53:29 +02002234 code_local = pcre2_compile((PCRE2_SPTR)perl_regex, PCRE2_ZERO_TERMINATED,
Michal Vasko69730152020-10-09 16:30:07 +02002235 PCRE2_UTF | PCRE2_ANCHORED | PCRE2_ENDANCHORED | PCRE2_DOLLAR_ENDONLY | PCRE2_NO_AUTO_CAPTURE,
2236 &err_code, &err_offset, NULL);
Radek Krejci54579462019-04-30 12:47:06 +02002237 if (!code_local) {
2238 PCRE2_UCHAR err_msg[256] = {0};
2239 pcre2_get_error_message(err_code, err_msg, 256);
Michal Vasko03ff5a72019-09-11 13:49:33 +02002240 LOGVAL(ctx, LY_VLOG_STR, log_path, LY_VCODE_INREGEXP, pattern, perl_regex + err_offset, err_msg);
Radek Krejci19a96102018-11-15 13:38:09 +01002241 free(perl_regex);
2242 return LY_EVALID;
2243 }
2244 free(perl_regex);
2245
Radek Krejci54579462019-04-30 12:47:06 +02002246 if (code) {
2247 *code = code_local;
Radek Krejci19a96102018-11-15 13:38:09 +01002248 } else {
Radek Krejci54579462019-04-30 12:47:06 +02002249 free(code_local);
Radek Krejci19a96102018-11-15 13:38:09 +01002250 }
2251
2252 return LY_SUCCESS;
2253
2254#undef URANGE_LEN
2255}
2256
Radek Krejcia3045382018-11-22 14:30:31 +01002257/**
2258 * @brief Compile parsed pattern restriction in conjunction with the patterns from base type.
2259 * @param[in] ctx Compile context.
2260 * @param[in] patterns_p Array of parsed patterns from the current type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002261 * @param[in] base_patterns Compiled patterns from the type from which the current type is derived.
2262 * Patterns from the base type are inherited to have all the patterns that have to match at one place.
2263 * @param[out] patterns Pointer to the storage for the patterns of the current type.
2264 * @return LY_ERR LY_SUCCESS, LY_EMEM, LY_EVALID.
2265 */
Radek Krejci19a96102018-11-15 13:38:09 +01002266static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02002267lys_compile_type_patterns(struct lysc_ctx *ctx, struct lysp_restr *patterns_p,
Radek Krejci0f969882020-08-21 16:56:47 +02002268 struct lysc_pattern **base_patterns, struct lysc_pattern ***patterns)
Radek Krejci19a96102018-11-15 13:38:09 +01002269{
2270 struct lysc_pattern **pattern;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002271 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01002272 LY_ERR ret = LY_SUCCESS;
2273
2274 /* first, copy the patterns from the base type */
2275 if (base_patterns) {
2276 *patterns = lysc_patterns_dup(ctx->ctx, base_patterns);
2277 LY_CHECK_ERR_RET(!(*patterns), LOGMEM(ctx->ctx), LY_EMEM);
2278 }
2279
2280 LY_ARRAY_FOR(patterns_p, u) {
2281 LY_ARRAY_NEW_RET(ctx->ctx, (*patterns), pattern, LY_EMEM);
2282 *pattern = calloc(1, sizeof **pattern);
2283 ++(*pattern)->refcount;
2284
Michal Vasko7f45cf22020-10-01 12:49:44 +02002285 ret = lys_compile_type_pattern_check(ctx->ctx, ctx->path, &patterns_p[u].arg.str[1], &(*pattern)->code);
Radek Krejci19a96102018-11-15 13:38:09 +01002286 LY_CHECK_RET(ret);
Radek Krejci19a96102018-11-15 13:38:09 +01002287
Michal Vasko7f45cf22020-10-01 12:49:44 +02002288 if (patterns_p[u].arg.str[0] == 0x15) {
Radek Krejci19a96102018-11-15 13:38:09 +01002289 (*pattern)->inverted = 1;
2290 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02002291 DUP_STRING_GOTO(ctx->ctx, &patterns_p[u].arg.str[1], (*pattern)->expr, ret, done);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002292 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].eapptag, (*pattern)->eapptag, ret, done);
2293 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].emsg, (*pattern)->emsg, ret, done);
2294 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].dsc, (*pattern)->dsc, ret, done);
2295 DUP_STRING_GOTO(ctx->ctx, patterns_p[u].ref, (*pattern)->ref, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02002296 COMPILE_EXTS_GOTO(ctx, patterns_p[u].exts, (*pattern)->exts, (*pattern), LYEXT_PAR_PATTERN, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01002297 }
2298done:
2299 return ret;
2300}
2301
Radek Krejcia3045382018-11-22 14:30:31 +01002302/**
2303 * @brief map of the possible restrictions combination for the specific built-in type.
2304 */
Radek Krejci19a96102018-11-15 13:38:09 +01002305static uint16_t type_substmt_map[LY_DATA_TYPE_COUNT] = {
2306 0 /* LY_TYPE_UNKNOWN */,
2307 LYS_SET_LENGTH /* LY_TYPE_BINARY */,
Radek Krejci5969f272018-11-23 10:03:58 +01002308 LYS_SET_RANGE /* LY_TYPE_UINT8 */,
2309 LYS_SET_RANGE /* LY_TYPE_UINT16 */,
2310 LYS_SET_RANGE /* LY_TYPE_UINT32 */,
2311 LYS_SET_RANGE /* LY_TYPE_UINT64 */,
2312 LYS_SET_LENGTH | LYS_SET_PATTERN /* LY_TYPE_STRING */,
Radek Krejci19a96102018-11-15 13:38:09 +01002313 LYS_SET_BIT /* LY_TYPE_BITS */,
2314 0 /* LY_TYPE_BOOL */,
2315 LYS_SET_FRDIGITS | LYS_SET_RANGE /* LY_TYPE_DEC64 */,
2316 0 /* LY_TYPE_EMPTY */,
2317 LYS_SET_ENUM /* LY_TYPE_ENUM */,
2318 LYS_SET_BASE /* LY_TYPE_IDENT */,
2319 LYS_SET_REQINST /* LY_TYPE_INST */,
2320 LYS_SET_REQINST | LYS_SET_PATH /* LY_TYPE_LEAFREF */,
Radek Krejci19a96102018-11-15 13:38:09 +01002321 LYS_SET_TYPE /* LY_TYPE_UNION */,
2322 LYS_SET_RANGE /* LY_TYPE_INT8 */,
Radek Krejci19a96102018-11-15 13:38:09 +01002323 LYS_SET_RANGE /* LY_TYPE_INT16 */,
Radek Krejci19a96102018-11-15 13:38:09 +01002324 LYS_SET_RANGE /* LY_TYPE_INT32 */,
Radek Krejci5969f272018-11-23 10:03:58 +01002325 LYS_SET_RANGE /* LY_TYPE_INT64 */
2326};
2327
2328/**
2329 * @brief stringification of the YANG built-in data types
2330 */
Michal Vasko69730152020-10-09 16:30:07 +02002331const char *ly_data_type2str[LY_DATA_TYPE_COUNT] = {
2332 "unknown", "binary", "8bit unsigned integer", "16bit unsigned integer",
Radek Krejci5969f272018-11-23 10:03:58 +01002333 "32bit unsigned integer", "64bit unsigned integer", "string", "bits", "boolean", "decimal64", "empty", "enumeration",
Michal Vasko69730152020-10-09 16:30:07 +02002334 "identityref", "instance-identifier", "leafref", "union", "8bit integer", "16bit integer", "32bit integer", "64bit integer"
2335};
Radek Krejci19a96102018-11-15 13:38:09 +01002336
Radek Krejcia3045382018-11-22 14:30:31 +01002337/**
2338 * @brief Compile parsed type's enum structures (for enumeration and bits types).
2339 * @param[in] ctx Compile context.
2340 * @param[in] enums_p Array of the parsed enum structures to compile.
2341 * @param[in] basetype Base YANG built-in type from which the current type is derived. Only LY_TYPE_ENUM and LY_TYPE_BITS are expected.
Radek Krejcia3045382018-11-22 14:30:31 +01002342 * @param[in] base_enums Array of the compiled enums information from the (latest) base type to check if the current enums are compatible.
2343 * @param[out] enums Newly created array of the compiled enums information for the current type.
2344 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
2345 */
Radek Krejci19a96102018-11-15 13:38:09 +01002346static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02002347lys_compile_type_enums(struct lysc_ctx *ctx, struct lysp_type_enum *enums_p, LY_DATA_TYPE basetype,
Radek Krejci0f969882020-08-21 16:56:47 +02002348 struct lysc_type_bitenum_item *base_enums, struct lysc_type_bitenum_item **enums)
Radek Krejci19a96102018-11-15 13:38:09 +01002349{
2350 LY_ERR ret = LY_SUCCESS;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002351 LY_ARRAY_COUNT_TYPE u, v, match = 0;
Radek Krejci19a96102018-11-15 13:38:09 +01002352 int32_t value = 0;
2353 uint32_t position = 0;
Radek Krejci693262f2019-04-29 15:23:20 +02002354 struct lysc_type_bitenum_item *e, storage;
Radek Krejci19a96102018-11-15 13:38:09 +01002355
Michal Vasko69730152020-10-09 16:30:07 +02002356 if (base_enums && (ctx->mod_def->version < 2)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002357 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "%s type can be subtyped only in YANG 1.1 modules.",
Michal Vasko69730152020-10-09 16:30:07 +02002358 basetype == LY_TYPE_ENUM ? "Enumeration" : "Bits");
Radek Krejci19a96102018-11-15 13:38:09 +01002359 return LY_EVALID;
2360 }
2361
2362 LY_ARRAY_FOR(enums_p, u) {
2363 LY_ARRAY_NEW_RET(ctx->ctx, *enums, e, LY_EMEM);
Radek Krejci011e4aa2020-09-04 15:22:31 +02002364 DUP_STRING_GOTO(ctx->ctx, enums_p[u].name, e->name, ret, done);
2365 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->dsc, ret, done);
2366 DUP_STRING_GOTO(ctx->ctx, enums_p[u].ref, e->ref, ret, done);
Radek Krejci693262f2019-04-29 15:23:20 +02002367 e->flags = enums_p[u].flags & LYS_FLAGS_COMPILED_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +01002368 if (base_enums) {
2369 /* check the enum/bit presence in the base type - the set of enums/bits in the derived type must be a subset */
2370 LY_ARRAY_FOR(base_enums, v) {
2371 if (!strcmp(e->name, base_enums[v].name)) {
2372 break;
2373 }
2374 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002375 if (v == LY_ARRAY_COUNT(base_enums)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002376 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002377 "Invalid %s - derived type adds new item \"%s\".",
2378 basetype == LY_TYPE_ENUM ? "enumeration" : "bits", e->name);
Radek Krejci19a96102018-11-15 13:38:09 +01002379 return LY_EVALID;
2380 }
2381 match = v;
2382 }
2383
2384 if (basetype == LY_TYPE_ENUM) {
Radek Krejci693262f2019-04-29 15:23:20 +02002385 e->flags |= LYS_ISENUM;
Radek Krejci19a96102018-11-15 13:38:09 +01002386 if (enums_p[u].flags & LYS_SET_VALUE) {
2387 e->value = (int32_t)enums_p[u].value;
Michal Vasko69730152020-10-09 16:30:07 +02002388 if (!u || (e->value >= value)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002389 value = e->value + 1;
2390 }
2391 /* check collision with other values */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002392 for (v = 0; v < LY_ARRAY_COUNT(*enums) - 1; ++v) {
Radek Krejci19a96102018-11-15 13:38:09 +01002393 if (e->value == (*enums)[v].value) {
2394 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002395 "Invalid enumeration - value %d collide in items \"%s\" and \"%s\".",
2396 e->value, e->name, (*enums)[v].name);
Radek Krejci19a96102018-11-15 13:38:09 +01002397 return LY_EVALID;
2398 }
2399 }
2400 } else if (base_enums) {
2401 /* inherit the assigned value */
2402 e->value = base_enums[match].value;
Michal Vasko69730152020-10-09 16:30:07 +02002403 if (!u || (e->value >= value)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002404 value = e->value + 1;
2405 }
2406 } else {
2407 /* assign value automatically */
Michal Vasko69730152020-10-09 16:30:07 +02002408 if (u && (value == INT32_MIN)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002409 /* counter overflow */
2410 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002411 "Invalid enumeration - it is not possible to auto-assign enum value for "
2412 "\"%s\" since the highest value is already 2147483647.", e->name);
Radek Krejci19a96102018-11-15 13:38:09 +01002413 return LY_EVALID;
2414 }
2415 e->value = value++;
2416 }
2417 } else { /* LY_TYPE_BITS */
2418 if (enums_p[u].flags & LYS_SET_VALUE) {
2419 e->value = (int32_t)enums_p[u].value;
Michal Vasko69730152020-10-09 16:30:07 +02002420 if (!u || ((uint32_t)e->value >= position)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002421 position = (uint32_t)e->value + 1;
2422 }
2423 /* check collision with other values */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002424 for (v = 0; v < LY_ARRAY_COUNT(*enums) - 1; ++v) {
Radek Krejci19a96102018-11-15 13:38:09 +01002425 if (e->value == (*enums)[v].value) {
2426 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002427 "Invalid bits - position %u collide in items \"%s\" and \"%s\".",
Radek Krejci0f969882020-08-21 16:56:47 +02002428 (uint32_t)e->value, e->name, (*enums)[v].name);
Radek Krejci19a96102018-11-15 13:38:09 +01002429 return LY_EVALID;
2430 }
2431 }
2432 } else if (base_enums) {
2433 /* inherit the assigned value */
2434 e->value = base_enums[match].value;
Michal Vasko69730152020-10-09 16:30:07 +02002435 if (!u || ((uint32_t)e->value >= position)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002436 position = (uint32_t)e->value + 1;
2437 }
2438 } else {
2439 /* assign value automatically */
Michal Vasko69730152020-10-09 16:30:07 +02002440 if (u && (position == 0)) {
Radek Krejci19a96102018-11-15 13:38:09 +01002441 /* counter overflow */
2442 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002443 "Invalid bits - it is not possible to auto-assign bit position for "
2444 "\"%s\" since the highest value is already 4294967295.", e->name);
Radek Krejci19a96102018-11-15 13:38:09 +01002445 return LY_EVALID;
2446 }
2447 e->value = position++;
2448 }
2449 }
2450
2451 if (base_enums) {
2452 /* the assigned values must not change from the derived type */
2453 if (e->value != base_enums[match].value) {
2454 if (basetype == LY_TYPE_ENUM) {
2455 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002456 "Invalid enumeration - value of the item \"%s\" has changed from %d to %d in the derived type.",
2457 e->name, base_enums[match].value, e->value);
Radek Krejci19a96102018-11-15 13:38:09 +01002458 } else {
2459 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002460 "Invalid bits - position of the item \"%s\" has changed from %u to %u in the derived type.",
2461 e->name, (uint32_t)base_enums[match].value, (uint32_t)e->value);
Radek Krejci19a96102018-11-15 13:38:09 +01002462 }
2463 return LY_EVALID;
2464 }
2465 }
2466
Radek Krejciec4da802019-05-02 13:02:41 +02002467 COMPILE_ARRAY_GOTO(ctx, enums_p[u].iffeatures, e->iffeatures, v, lys_compile_iffeature, ret, done);
Radek Krejci0935f412019-08-20 16:15:18 +02002468 COMPILE_EXTS_GOTO(ctx, enums_p[u].exts, e->exts, e, basetype == LY_TYPE_ENUM ? LYEXT_PAR_TYPE_ENUM : LYEXT_PAR_TYPE_BIT, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01002469
2470 if (basetype == LY_TYPE_BITS) {
2471 /* keep bits ordered by position */
Radek Krejci1e008d22020-08-17 11:37:37 +02002472 for (v = u; v && (*enums)[v - 1].value > e->value; --v) {}
Radek Krejci19a96102018-11-15 13:38:09 +01002473 if (v != u) {
2474 memcpy(&storage, e, sizeof *e);
2475 memmove(&(*enums)[v + 1], &(*enums)[v], (u - v) * sizeof **enums);
2476 memcpy(&(*enums)[v], &storage, sizeof storage);
2477 }
2478 }
2479 }
2480
2481done:
2482 return ret;
2483}
2484
Radek Krejcia3045382018-11-22 14:30:31 +01002485/**
2486 * @brief Parse path-arg (leafref). Get tokens of the path by repetitive calls of the function.
2487 *
2488 * path-arg = absolute-path / relative-path
2489 * absolute-path = 1*("/" (node-identifier *path-predicate))
2490 * relative-path = 1*(".." "/") descendant-path
2491 *
2492 * @param[in,out] path Path to parse.
2493 * @param[out] prefix Prefix of the token, NULL if there is not any.
2494 * @param[out] pref_len Length of the prefix, 0 if there is not any.
2495 * @param[out] name Name of the token.
2496 * @param[out] nam_len Length of the name.
2497 * @param[out] parent_times Number of leading ".." in the path. Must be 0 on the first call,
2498 * must not be changed between consecutive calls. -1 if the
2499 * path is absolute.
2500 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
2501 * @return LY_ERR value: LY_SUCCESS or LY_EINVAL in case of invalid character in the path.
2502 */
Radek Krejci2d7a47b2019-05-16 13:34:10 +02002503LY_ERR
Radek Krejcia3045382018-11-22 14:30:31 +01002504lys_path_token(const char **path, const char **prefix, size_t *prefix_len, const char **name, size_t *name_len,
Radek Krejci857189e2020-09-01 13:26:36 +02002505 int32_t *parent_times, ly_bool *has_predicate)
Radek Krejcia3045382018-11-22 14:30:31 +01002506{
Radek Krejci1deb5be2020-08-26 16:43:36 +02002507 int32_t par_times = 0;
Radek Krejcia3045382018-11-22 14:30:31 +01002508
2509 assert(path && *path);
2510 assert(parent_times);
2511 assert(prefix);
2512 assert(prefix_len);
2513 assert(name);
2514 assert(name_len);
2515 assert(has_predicate);
2516
2517 *prefix = NULL;
2518 *prefix_len = 0;
2519 *name = NULL;
2520 *name_len = 0;
2521 *has_predicate = 0;
2522
2523 if (!*parent_times) {
2524 if (!strncmp(*path, "..", 2)) {
2525 *path += 2;
2526 ++par_times;
2527 while (!strncmp(*path, "/..", 3)) {
2528 *path += 3;
2529 ++par_times;
2530 }
2531 }
2532 if (par_times) {
2533 *parent_times = par_times;
2534 } else {
2535 *parent_times = -1;
2536 }
2537 }
2538
2539 if (**path != '/') {
2540 return LY_EINVAL;
2541 }
2542 /* skip '/' */
2543 ++(*path);
2544
2545 /* node-identifier ([prefix:]name) */
Radek Krejcib4a4a272019-06-10 12:44:52 +02002546 LY_CHECK_RET(ly_parse_nodeid(path, prefix, prefix_len, name, name_len));
Radek Krejcia3045382018-11-22 14:30:31 +01002547
Michal Vasko69730152020-10-09 16:30:07 +02002548 if (((**path == '/') && (*path)[1]) || !**path) {
Radek Krejcia3045382018-11-22 14:30:31 +01002549 /* path continues by another token or this is the last token */
2550 return LY_SUCCESS;
2551 } else if ((*path)[0] != '[') {
2552 /* unexpected character */
2553 return LY_EINVAL;
2554 } else {
2555 /* predicate starting with [ */
2556 *has_predicate = 1;
2557 return LY_SUCCESS;
2558 }
2559}
2560
2561/**
Radek Krejci58d171e2018-11-23 13:50:55 +01002562 * @brief Check the features used in if-feature statements applicable to the leafref and its target.
2563 *
2564 * The set of features used for target must be a subset of features used for the leafref.
2565 * This is not a perfect, we should compare the truth tables but it could require too much resources
2566 * and RFC 7950 does not require it explicitely, so we simplify that.
2567 *
2568 * @param[in] refnode The leafref node.
2569 * @param[in] target Tha target node of the leafref.
2570 * @return LY_SUCCESS or LY_EVALID;
2571 */
2572static LY_ERR
2573lys_compile_leafref_features_validate(const struct lysc_node *refnode, const struct lysc_node *target)
2574{
2575 LY_ERR ret = LY_EVALID;
2576 const struct lysc_node *iter;
Radek Krejci1deb5be2020-08-26 16:43:36 +02002577 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci58d171e2018-11-23 13:50:55 +01002578 struct ly_set features = {0};
2579
2580 for (iter = refnode; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002581 if (iter->iffeatures) {
2582 LY_ARRAY_FOR(iter->iffeatures, u) {
2583 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002584 LY_CHECK_GOTO(ly_set_add(&features, iter->iffeatures[u].features[v], 0, NULL), cleanup);
Radek Krejci58d171e2018-11-23 13:50:55 +01002585 }
2586 }
2587 }
2588 }
2589
2590 /* we should have, in features set, a superset of features applicable to the target node.
Radek Krejciba03a5a2020-08-27 14:40:41 +02002591 * If the feature is not present, we don;t have a subset of features applicable
Radek Krejci58d171e2018-11-23 13:50:55 +01002592 * to the leafref itself. */
Radek Krejci58d171e2018-11-23 13:50:55 +01002593 for (iter = target; iter; iter = iter->parent) {
Radek Krejci056d0a82018-12-06 16:57:25 +01002594 if (iter->iffeatures) {
2595 LY_ARRAY_FOR(iter->iffeatures, u) {
2596 LY_ARRAY_FOR(iter->iffeatures[u].features, v) {
Radek Krejciba03a5a2020-08-27 14:40:41 +02002597 if (!ly_set_contains(&features, iter->iffeatures[u].features[v], NULL)) {
2598 /* feature not present */
Radek Krejci58d171e2018-11-23 13:50:55 +01002599 goto cleanup;
2600 }
2601 }
2602 }
2603 }
2604 }
2605 ret = LY_SUCCESS;
2606
2607cleanup:
2608 ly_set_erase(&features, NULL);
2609 return ret;
2610}
2611
Michal Vasko7f45cf22020-10-01 12:49:44 +02002612static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Radek Krejci0f969882020-08-21 16:56:47 +02002613 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02002614 struct lysc_type **type, const char **units, struct lysp_qname **dflt);
Radek Krejcia3045382018-11-22 14:30:31 +01002615
Radek Krejcia3045382018-11-22 14:30:31 +01002616/**
2617 * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
2618 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002619 * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
Radek Krejcicdfecd92018-11-26 11:27:32 +01002620 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2621 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2622 * @param[in] context_name Name of the context node or referencing typedef for logging.
Radek Krejcia3045382018-11-22 14:30:31 +01002623 * @param[in] type_p Parsed type to compile.
2624 * @param[in] basetype Base YANG built-in type of the type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002625 * @param[in] tpdfname Name of the type's typedef, serves as a flag - if it is leaf/leaf-list's type, it is NULL.
2626 * @param[in] base The latest base (compiled) type from which the current type is being derived.
2627 * @param[out] type Newly created type structure with the filled information about the type.
2628 * @return LY_ERR value.
2629 */
Radek Krejci19a96102018-11-15 13:38:09 +01002630static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02002631lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Michal Vaskoe9c050f2020-10-06 14:01:23 +02002632 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p, LY_DATA_TYPE basetype,
2633 const char *tpdfname, struct lysc_type *base, struct lysc_type **type)
Radek Krejcic5c27e52018-11-15 14:38:11 +01002634{
2635 LY_ERR ret = LY_SUCCESS;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002636 struct lysc_type_bin *bin;
2637 struct lysc_type_num *num;
2638 struct lysc_type_str *str;
2639 struct lysc_type_bits *bits;
2640 struct lysc_type_enum *enumeration;
Radek Krejci6cba4292018-11-15 17:33:29 +01002641 struct lysc_type_dec *dec;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002642 struct lysc_type_identityref *idref;
Michal Vasko004d3152020-06-11 19:59:22 +02002643 struct lysc_type_leafref *lref;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002644 struct lysc_type_union *un, *un_aux;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002645
2646 switch (basetype) {
2647 case LY_TYPE_BINARY:
Michal Vasko22df3f02020-08-24 13:29:22 +02002648 bin = (struct lysc_type_bin *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002649
2650 /* RFC 7950 9.8.1, 9.4.4 - length, number of octets it contains */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002651 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002652 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002653 base ? ((struct lysc_type_bin *)base)->length : NULL, &bin->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002654 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002655 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, bin->length->exts, bin->length, LYEXT_PAR_LENGTH, ret, cleanup);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002656 }
2657 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002658 break;
2659 case LY_TYPE_BITS:
2660 /* RFC 7950 9.7 - bits */
Michal Vasko22df3f02020-08-24 13:29:22 +02002661 bits = (struct lysc_type_bits *)(*type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002662 if (type_p->bits) {
Radek Krejciec4da802019-05-02 13:02:41 +02002663 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->bits, basetype,
Michal Vasko69730152020-10-09 16:30:07 +02002664 base ? (struct lysc_type_bitenum_item *)((struct lysc_type_bits *)base)->bits : NULL,
Michal Vasko22df3f02020-08-24 13:29:22 +02002665 (struct lysc_type_bitenum_item **)&bits->bits));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002666 }
2667
Radek Krejci555cb5b2018-11-16 14:54:33 +01002668 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002669 /* type derived from bits built-in type must contain at least one bit */
Radek Krejci6cba4292018-11-15 17:33:29 +01002670 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002671 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002672 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002673 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "bit", "bits type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002674 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002675 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002676 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002677 break;
Radek Krejci6cba4292018-11-15 17:33:29 +01002678 case LY_TYPE_DEC64:
Radek Krejci115a74d2020-08-14 22:18:12 +02002679 dec = (struct lysc_type_dec *)(*type);
Radek Krejci6cba4292018-11-15 17:33:29 +01002680
2681 /* RFC 7950 9.3.4 - fraction-digits */
Radek Krejci555cb5b2018-11-16 14:54:33 +01002682 if (!base) {
Radek Krejci643c8242018-11-15 17:51:11 +01002683 if (!type_p->fraction_digits) {
2684 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002685 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type ", tpdfname);
Radek Krejci643c8242018-11-15 17:51:11 +01002686 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002687 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "fraction-digits", "decimal64 type", "");
Radek Krejci643c8242018-11-15 17:51:11 +01002688 }
2689 return LY_EVALID;
2690 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002691 dec->fraction_digits = type_p->fraction_digits;
2692 } else {
2693 if (type_p->fraction_digits) {
2694 /* fraction digits is prohibited in types not directly derived from built-in decimal64 */
2695 if (tpdfname) {
2696 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002697 "Invalid fraction-digits substatement for type \"%s\" not directly derived from decimal64 built-in type.",
2698 tpdfname);
Radek Krejci115a74d2020-08-14 22:18:12 +02002699 } else {
2700 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002701 "Invalid fraction-digits substatement for type not directly derived from decimal64 built-in type.");
Radek Krejci115a74d2020-08-14 22:18:12 +02002702 }
2703 return LY_EVALID;
Radek Krejci6cba4292018-11-15 17:33:29 +01002704 }
Radek Krejci115a74d2020-08-14 22:18:12 +02002705 dec->fraction_digits = ((struct lysc_type_dec *)base)->fraction_digits;
Radek Krejci6cba4292018-11-15 17:33:29 +01002706 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002707
2708 /* RFC 7950 9.2.4 - range */
2709 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002710 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, dec->fraction_digits,
Michal Vasko69730152020-10-09 16:30:07 +02002711 base ? ((struct lysc_type_dec *)base)->range : NULL, &dec->range));
Radek Krejci6cba4292018-11-15 17:33:29 +01002712 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002713 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, dec->range->exts, dec->range, LYEXT_PAR_RANGE, ret, cleanup);
Radek Krejci6cba4292018-11-15 17:33:29 +01002714 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002715 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002716 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002717 case LY_TYPE_STRING:
Michal Vasko22df3f02020-08-24 13:29:22 +02002718 str = (struct lysc_type_str *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002719
2720 /* RFC 7950 9.4.4 - length */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002721 if (type_p->length) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002722 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->length, basetype, 1, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002723 base ? ((struct lysc_type_str *)base)->length : NULL, &str->length));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002724 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002725 COMPILE_EXTS_GOTO(ctx, type_p->length->exts, str->length->exts, str->length, LYEXT_PAR_LENGTH, ret, cleanup);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002726 }
Michal Vasko22df3f02020-08-24 13:29:22 +02002727 } else if (base && ((struct lysc_type_str *)base)->length) {
2728 str->length = lysc_range_dup(ctx->ctx, ((struct lysc_type_str *)base)->length);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002729 }
2730
2731 /* RFC 7950 9.4.5 - pattern */
2732 if (type_p->patterns) {
Radek Krejciec4da802019-05-02 13:02:41 +02002733 LY_CHECK_RET(lys_compile_type_patterns(ctx, type_p->patterns,
Michal Vasko69730152020-10-09 16:30:07 +02002734 base ? ((struct lysc_type_str *)base)->patterns : NULL, &str->patterns));
Michal Vasko22df3f02020-08-24 13:29:22 +02002735 } else if (base && ((struct lysc_type_str *)base)->patterns) {
2736 str->patterns = lysc_patterns_dup(ctx->ctx, ((struct lysc_type_str *)base)->patterns);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002737 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002738 break;
2739 case LY_TYPE_ENUM:
Michal Vasko22df3f02020-08-24 13:29:22 +02002740 enumeration = (struct lysc_type_enum *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002741
2742 /* RFC 7950 9.6 - enum */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002743 if (type_p->enums) {
Radek Krejciec4da802019-05-02 13:02:41 +02002744 LY_CHECK_RET(lys_compile_type_enums(ctx, type_p->enums, basetype,
Michal Vasko69730152020-10-09 16:30:07 +02002745 base ? ((struct lysc_type_enum *)base)->enums : NULL, &enumeration->enums));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002746 }
2747
Radek Krejci555cb5b2018-11-16 14:54:33 +01002748 if (!base && !type_p->flags) {
Radek Krejcic5c27e52018-11-15 14:38:11 +01002749 /* type derived from enumerations built-in type must contain at least one enum */
Radek Krejci6cba4292018-11-15 17:33:29 +01002750 if (tpdfname) {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002751 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type ", tpdfname);
Radek Krejci6cba4292018-11-15 17:33:29 +01002752 } else {
Radek Krejci555cb5b2018-11-16 14:54:33 +01002753 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "enum", "enumeration type", "");
Radek Krejcic5c27e52018-11-15 14:38:11 +01002754 }
Radek Krejci6cba4292018-11-15 17:33:29 +01002755 return LY_EVALID;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002756 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002757 break;
2758 case LY_TYPE_INT8:
2759 case LY_TYPE_UINT8:
2760 case LY_TYPE_INT16:
2761 case LY_TYPE_UINT16:
2762 case LY_TYPE_INT32:
2763 case LY_TYPE_UINT32:
2764 case LY_TYPE_INT64:
2765 case LY_TYPE_UINT64:
Michal Vasko22df3f02020-08-24 13:29:22 +02002766 num = (struct lysc_type_num *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002767
2768 /* RFC 6020 9.2.4 - range */
Radek Krejcic5c27e52018-11-15 14:38:11 +01002769 if (type_p->range) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02002770 LY_CHECK_RET(lys_compile_type_range(ctx, type_p->range, basetype, 0, 0,
Michal Vasko69730152020-10-09 16:30:07 +02002771 base ? ((struct lysc_type_num *)base)->range : NULL, &num->range));
Radek Krejcic5c27e52018-11-15 14:38:11 +01002772 if (!tpdfname) {
Michal Vasko1734be92020-09-22 08:55:10 +02002773 COMPILE_EXTS_GOTO(ctx, type_p->range->exts, num->range->exts, num->range, LYEXT_PAR_RANGE, ret, cleanup);
Radek Krejcic5c27e52018-11-15 14:38:11 +01002774 }
2775 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002776 break;
Radek Krejci555cb5b2018-11-16 14:54:33 +01002777 case LY_TYPE_IDENT:
Michal Vasko22df3f02020-08-24 13:29:22 +02002778 idref = (struct lysc_type_identityref *)(*type);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002779
2780 /* RFC 7950 9.10.2 - base */
2781 if (type_p->bases) {
2782 if (base) {
2783 /* only the directly derived identityrefs can contain base specification */
2784 if (tpdfname) {
2785 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002786 "Invalid base substatement for the type \"%s\" not directly derived from identityref built-in type.",
2787 tpdfname);
Radek Krejci555cb5b2018-11-16 14:54:33 +01002788 } else {
2789 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002790 "Invalid base substatement for the type not directly derived from identityref built-in type.");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002791 }
2792 return LY_EVALID;
2793 }
Michal Vaskoe9c050f2020-10-06 14:01:23 +02002794 LY_CHECK_RET(lys_compile_identity_bases(ctx, type_p->mod, type_p->bases, NULL, &idref->bases));
Radek Krejci555cb5b2018-11-16 14:54:33 +01002795 }
2796
2797 if (!base && !type_p->flags) {
2798 /* type derived from identityref built-in type must contain at least one base */
2799 if (tpdfname) {
2800 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type ", tpdfname);
2801 } else {
2802 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "base", "identityref type", "");
Radek Krejci555cb5b2018-11-16 14:54:33 +01002803 }
2804 return LY_EVALID;
2805 }
Radek Krejci555cb5b2018-11-16 14:54:33 +01002806 break;
Radek Krejcia3045382018-11-22 14:30:31 +01002807 case LY_TYPE_LEAFREF:
Michal Vasko22df3f02020-08-24 13:29:22 +02002808 lref = (struct lysc_type_leafref *)*type;
Michal Vasko004d3152020-06-11 19:59:22 +02002809
Radek Krejcia3045382018-11-22 14:30:31 +01002810 /* RFC 7950 9.9.3 - require-instance */
2811 if (type_p->flags & LYS_SET_REQINST) {
Radek Krejci0bcdaed2019-01-10 10:21:34 +01002812 if (context_mod->mod->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002813 if (tpdfname) {
2814 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02002815 "Leafref type \"%s\" can be restricted by require-instance statement only in YANG 1.1 modules.", tpdfname);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002816 } else {
2817 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02002818 "Leafref type can be restricted by require-instance statement only in YANG 1.1 modules.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01002819 }
2820 return LY_EVALID;
2821 }
Michal Vasko004d3152020-06-11 19:59:22 +02002822 lref->require_instance = type_p->require_instance;
Radek Krejci412ddfa2018-11-23 11:44:11 +01002823 } else if (base) {
2824 /* inherit */
Michal Vasko004d3152020-06-11 19:59:22 +02002825 lref->require_instance = ((struct lysc_type_leafref *)base)->require_instance;
Radek Krejcia3045382018-11-22 14:30:31 +01002826 } else {
2827 /* default is true */
Michal Vasko004d3152020-06-11 19:59:22 +02002828 lref->require_instance = 1;
Radek Krejcia3045382018-11-22 14:30:31 +01002829 }
2830 if (type_p->path) {
Michal Vasko1734be92020-09-22 08:55:10 +02002831 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, type_p->path, &lref->path));
Michal Vaskoe9c050f2020-10-06 14:01:23 +02002832 lref->path_mod = type_p->mod;
Radek Krejcia3045382018-11-22 14:30:31 +01002833 } else if (base) {
Michal Vasko1734be92020-09-22 08:55:10 +02002834 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)base)->path, &lref->path));
Michal Vasko72619ce2020-10-06 14:05:32 +02002835 lref->path_mod = ((struct lysc_type_leafref *)base)->path_mod;
Radek Krejcia3045382018-11-22 14:30:31 +01002836 } else if (tpdfname) {
2837 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type ", tpdfname);
2838 return LY_EVALID;
2839 } else {
2840 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type", "");
Radek Krejcia3045382018-11-22 14:30:31 +01002841 return LY_EVALID;
2842 }
Radek Krejcia3045382018-11-22 14:30:31 +01002843 break;
Radek Krejci16c0f822018-11-16 10:46:10 +01002844 case LY_TYPE_INST:
2845 /* RFC 7950 9.9.3 - require-instance */
2846 if (type_p->flags & LYS_SET_REQINST) {
Michal Vasko22df3f02020-08-24 13:29:22 +02002847 ((struct lysc_type_instanceid *)(*type))->require_instance = type_p->require_instance;
Radek Krejci16c0f822018-11-16 10:46:10 +01002848 } else {
2849 /* default is true */
Michal Vasko22df3f02020-08-24 13:29:22 +02002850 ((struct lysc_type_instanceid *)(*type))->require_instance = 1;
Radek Krejci16c0f822018-11-16 10:46:10 +01002851 }
Radek Krejci16c0f822018-11-16 10:46:10 +01002852 break;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002853 case LY_TYPE_UNION:
Michal Vasko22df3f02020-08-24 13:29:22 +02002854 un = (struct lysc_type_union *)(*type);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002855
2856 /* RFC 7950 7.4 - type */
2857 if (type_p->types) {
2858 if (base) {
2859 /* only the directly derived union can contain types specification */
2860 if (tpdfname) {
2861 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002862 "Invalid type substatement for the type \"%s\" not directly derived from union built-in type.",
2863 tpdfname);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002864 } else {
2865 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Michal Vasko69730152020-10-09 16:30:07 +02002866 "Invalid type substatement for the type not directly derived from union built-in type.");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002867 }
2868 return LY_EVALID;
2869 }
2870 /* compile the type */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002871 LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_COUNT(type_p->types), LY_EVALID);
2872 for (LY_ARRAY_COUNT_TYPE u = 0, additional = 0; u < LY_ARRAY_COUNT(type_p->types); ++u) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02002873 LY_CHECK_RET(lys_compile_type(ctx, context_pnode, context_flags, context_mod, context_name,
Michal Vasko69730152020-10-09 16:30:07 +02002874 &type_p->types[u], &un->types[u + additional], NULL, NULL));
Radek Krejcicdfecd92018-11-26 11:27:32 +01002875 if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
2876 /* add space for additional types from the union subtype */
2877 un_aux = (struct lysc_type_union *)un->types[u + additional];
Michal Vasko22df3f02020-08-24 13:29:22 +02002878 LY_ARRAY_RESIZE_ERR_RET(ctx->ctx, un->types, (*((uint64_t *)(type_p->types) - 1)) + additional + LY_ARRAY_COUNT(un_aux->types) - 1,
Michal Vasko69730152020-10-09 16:30:07 +02002879 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux), LY_EMEM);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002880
2881 /* copy subtypes of the subtype union */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02002882 for (LY_ARRAY_COUNT_TYPE v = 0; v < LY_ARRAY_COUNT(un_aux->types); ++v) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01002883 if (un_aux->types[v]->basetype == LY_TYPE_LEAFREF) {
2884 /* duplicate the whole structure because of the instance-specific path resolving for realtype */
2885 un->types[u + additional] = calloc(1, sizeof(struct lysc_type_leafref));
Michal Vasko22df3f02020-08-24 13:29:22 +02002886 LY_CHECK_ERR_RET(!un->types[u + additional], LOGMEM(ctx->ctx); lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux), LY_EMEM);
Michal Vasko004d3152020-06-11 19:59:22 +02002887 lref = (struct lysc_type_leafref *)un->types[u + additional];
2888
2889 lref->basetype = LY_TYPE_LEAFREF;
Michal Vasko1734be92020-09-22 08:55:10 +02002890 LY_CHECK_RET(lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref *)un_aux->types[v])->path, &lref->path));
Michal Vasko004d3152020-06-11 19:59:22 +02002891 lref->refcount = 1;
Michal Vasko22df3f02020-08-24 13:29:22 +02002892 lref->require_instance = ((struct lysc_type_leafref *)un_aux->types[v])->require_instance;
Michal Vasko72619ce2020-10-06 14:05:32 +02002893 lref->path_mod = ((struct lysc_type_leafref *)un_aux->types[v])->path_mod;
Radek Krejcicdfecd92018-11-26 11:27:32 +01002894 /* TODO extensions */
2895
2896 } else {
2897 un->types[u + additional] = un_aux->types[v];
2898 ++un_aux->types[v]->refcount;
2899 }
2900 ++additional;
2901 LY_ARRAY_INCREMENT(un->types);
2902 }
2903 /* compensate u increment in main loop */
2904 --additional;
2905
2906 /* free the replaced union subtype */
Michal Vasko22df3f02020-08-24 13:29:22 +02002907 lysc_type_free(ctx->ctx, (struct lysc_type *)un_aux);
Radek Krejcicdfecd92018-11-26 11:27:32 +01002908 } else {
2909 LY_ARRAY_INCREMENT(un->types);
2910 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002911 }
2912 }
2913
2914 if (!base && !type_p->flags) {
2915 /* type derived from union built-in type must contain at least one type */
2916 if (tpdfname) {
2917 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type ", tpdfname);
2918 } else {
2919 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "type", "union type", "");
Radek Krejcicdfecd92018-11-26 11:27:32 +01002920 }
2921 return LY_EVALID;
2922 }
Radek Krejcicdfecd92018-11-26 11:27:32 +01002923 break;
Radek Krejcic5c27e52018-11-15 14:38:11 +01002924 case LY_TYPE_BOOL:
2925 case LY_TYPE_EMPTY:
2926 case LY_TYPE_UNKNOWN: /* just to complete switch */
2927 break;
2928 }
Michal Vasko1734be92020-09-22 08:55:10 +02002929
2930 if (tpdfname) {
2931 switch (basetype) {
2932 case LY_TYPE_BINARY:
2933 type_p->compiled = *type;
2934 *type = calloc(1, sizeof(struct lysc_type_bin));
2935 break;
2936 case LY_TYPE_BITS:
2937 type_p->compiled = *type;
2938 *type = calloc(1, sizeof(struct lysc_type_bits));
2939 break;
2940 case LY_TYPE_DEC64:
2941 type_p->compiled = *type;
2942 *type = calloc(1, sizeof(struct lysc_type_dec));
2943 break;
2944 case LY_TYPE_STRING:
2945 type_p->compiled = *type;
2946 *type = calloc(1, sizeof(struct lysc_type_str));
2947 break;
2948 case LY_TYPE_ENUM:
2949 type_p->compiled = *type;
2950 *type = calloc(1, sizeof(struct lysc_type_enum));
2951 break;
2952 case LY_TYPE_INT8:
2953 case LY_TYPE_UINT8:
2954 case LY_TYPE_INT16:
2955 case LY_TYPE_UINT16:
2956 case LY_TYPE_INT32:
2957 case LY_TYPE_UINT32:
2958 case LY_TYPE_INT64:
2959 case LY_TYPE_UINT64:
2960 type_p->compiled = *type;
2961 *type = calloc(1, sizeof(struct lysc_type_num));
2962 break;
2963 case LY_TYPE_IDENT:
2964 type_p->compiled = *type;
2965 *type = calloc(1, sizeof(struct lysc_type_identityref));
2966 break;
2967 case LY_TYPE_LEAFREF:
2968 type_p->compiled = *type;
2969 *type = calloc(1, sizeof(struct lysc_type_leafref));
2970 break;
2971 case LY_TYPE_INST:
2972 type_p->compiled = *type;
2973 *type = calloc(1, sizeof(struct lysc_type_instanceid));
2974 break;
2975 case LY_TYPE_UNION:
2976 type_p->compiled = *type;
2977 *type = calloc(1, sizeof(struct lysc_type_union));
2978 break;
2979 case LY_TYPE_BOOL:
2980 case LY_TYPE_EMPTY:
2981 case LY_TYPE_UNKNOWN: /* just to complete switch */
2982 break;
2983 }
2984 }
Radek Krejcic5c27e52018-11-15 14:38:11 +01002985 LY_CHECK_ERR_RET(!(*type), LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko1734be92020-09-22 08:55:10 +02002986
2987cleanup:
Radek Krejcic5c27e52018-11-15 14:38:11 +01002988 return ret;
2989}
2990
Radek Krejcia3045382018-11-22 14:30:31 +01002991/**
2992 * @brief Compile information about the leaf/leaf-list's type.
2993 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02002994 * @param[in] context_pnode Schema node where the type/typedef is placed to correctly find the base types.
Radek Krejcicdfecd92018-11-26 11:27:32 +01002995 * @param[in] context_flags Flags of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2996 * @param[in] context_mod Module of the context node or the referencing typedef to correctly check status of referencing and referenced objects.
2997 * @param[in] context_name Name of the context node or referencing typedef for logging.
2998 * @param[in] type_p Parsed type to compile.
Radek Krejcia3045382018-11-22 14:30:31 +01002999 * @param[out] type Newly created (or reused with increased refcount) type structure with the filled information about the type.
Radek Krejcicdfecd92018-11-26 11:27:32 +01003000 * @param[out] units Storage for inheriting units value from the typedefs the current type derives from.
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003001 * @param[out] dflt Default value for the type.
Radek Krejcia3045382018-11-22 14:30:31 +01003002 * @return LY_ERR value.
3003 */
Radek Krejcic5c27e52018-11-15 14:38:11 +01003004static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003005lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_pnode, uint16_t context_flags,
Radek Krejci0f969882020-08-21 16:56:47 +02003006 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
Michal Vasko7f45cf22020-10-01 12:49:44 +02003007 struct lysc_type **type, const char **units, struct lysp_qname **dflt)
Radek Krejci19a96102018-11-15 13:38:09 +01003008{
3009 LY_ERR ret = LY_SUCCESS;
Radek Krejci857189e2020-09-01 13:26:36 +02003010 ly_bool dummyloops = 0;
Radek Krejci19a96102018-11-15 13:38:09 +01003011 struct type_context {
3012 const struct lysp_tpdf *tpdf;
3013 struct lysp_node *node;
3014 struct lysp_module *mod;
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003015 } *tctx, *tctx_prev = NULL, *tctx_iter;
Radek Krejci19a96102018-11-15 13:38:09 +01003016 LY_DATA_TYPE basetype = LY_TYPE_UNKNOWN;
Radek Krejcic5c27e52018-11-15 14:38:11 +01003017 struct lysc_type *base = NULL, *prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01003018 struct ly_set tpdf_chain = {0};
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003019
Radek Krejci19a96102018-11-15 13:38:09 +01003020 (*type) = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003021 if (dflt) {
3022 *dflt = NULL;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003023 }
Radek Krejci19a96102018-11-15 13:38:09 +01003024
3025 tctx = calloc(1, sizeof *tctx);
3026 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003027 for (ret = lysp_type_find(type_p->name, context_pnode, ctx->mod_def->parsed,
Michal Vasko69730152020-10-09 16:30:07 +02003028 &basetype, &tctx->tpdf, &tctx->node, &tctx->mod);
Radek Krejci19a96102018-11-15 13:38:09 +01003029 ret == LY_SUCCESS;
3030 ret = lysp_type_find(tctx_prev->tpdf->type.name, tctx_prev->node, tctx_prev->mod,
Michal Vasko69730152020-10-09 16:30:07 +02003031 &basetype, &tctx->tpdf, &tctx->node, &tctx->mod)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003032 if (basetype) {
3033 break;
3034 }
3035
3036 /* check status */
Radek Krejcicdfecd92018-11-26 11:27:32 +01003037 ret = lysc_check_status(ctx, context_flags, context_mod, context_name,
Michal Vasko69730152020-10-09 16:30:07 +02003038 tctx->tpdf->flags, tctx->mod, tctx->node ? tctx->node->name : tctx->tpdf->name);
Radek Krejci87e25252020-09-15 13:28:31 +02003039 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003040
Radek Krejcicdfecd92018-11-26 11:27:32 +01003041 if (units && !*units) {
3042 /* inherit units */
Radek Krejci87e25252020-09-15 13:28:31 +02003043 DUP_STRING(ctx->ctx, tctx->tpdf->units, *units, ret);
3044 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01003045 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003046 if (dflt && !*dflt && tctx->tpdf->dflt.str) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01003047 /* inherit default */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003048 *dflt = (struct lysp_qname *)&tctx->tpdf->dflt;
Michal Vaskoe9c050f2020-10-06 14:01:23 +02003049 assert((*dflt)->mod);
Radek Krejcicdfecd92018-11-26 11:27:32 +01003050 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003051 if (dummyloops && (!units || *units) && dflt && *dflt) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003052 basetype = ((struct type_context *)tpdf_chain.objs[tpdf_chain.count - 1])->tpdf->type.compiled->basetype;
Radek Krejcicdfecd92018-11-26 11:27:32 +01003053 break;
3054 }
3055
Radek Krejci19a96102018-11-15 13:38:09 +01003056 if (tctx->tpdf->type.compiled) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01003057 /* it is not necessary to continue, the rest of the chain was already compiled,
3058 * but we still may need to inherit default and units values, so start dummy loops */
Radek Krejci19a96102018-11-15 13:38:09 +01003059 basetype = tctx->tpdf->type.compiled->basetype;
Radek Krejci3d92e442020-10-12 12:48:13 +02003060 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02003061 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003062
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003063 if ((units && !*units) || (dflt && !*dflt)) {
Radek Krejcicdfecd92018-11-26 11:27:32 +01003064 dummyloops = 1;
3065 goto preparenext;
3066 } else {
3067 tctx = NULL;
3068 break;
3069 }
Radek Krejci19a96102018-11-15 13:38:09 +01003070 }
3071
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003072 /* circular typedef reference detection */
Radek Krejci1deb5be2020-08-26 16:43:36 +02003073 for (uint32_t u = 0; u < tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003074 /* local part */
Michal Vasko22df3f02020-08-24 13:29:22 +02003075 tctx_iter = (struct type_context *)tpdf_chain.objs[u];
Michal Vasko69730152020-10-09 16:30:07 +02003076 if ((tctx_iter->mod == tctx->mod) && (tctx_iter->node == tctx->node) && (tctx_iter->tpdf == tctx->tpdf)) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003077 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003078 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003079 free(tctx);
3080 ret = LY_EVALID;
3081 goto cleanup;
3082 }
3083 }
Radek Krejci1deb5be2020-08-26 16:43:36 +02003084 for (uint32_t u = 0; u < ctx->tpdf_chain.count; u++) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003085 /* global part for unions corner case */
Michal Vasko22df3f02020-08-24 13:29:22 +02003086 tctx_iter = (struct type_context *)ctx->tpdf_chain.objs[u];
Michal Vasko69730152020-10-09 16:30:07 +02003087 if ((tctx_iter->mod == tctx->mod) && (tctx_iter->node == tctx->node) && (tctx_iter->tpdf == tctx->tpdf)) {
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003088 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003089 "Invalid \"%s\" type reference - circular chain of types detected.", tctx->tpdf->name);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003090 free(tctx);
3091 ret = LY_EVALID;
3092 goto cleanup;
3093 }
3094 }
3095
Radek Krejci19a96102018-11-15 13:38:09 +01003096 /* store information for the following processing */
Radek Krejci3d92e442020-10-12 12:48:13 +02003097 ret = ly_set_add(&tpdf_chain, tctx, 1, NULL);
Radek Krejci87e25252020-09-15 13:28:31 +02003098 LY_CHECK_ERR_GOTO(ret, free(tctx), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003099
Radek Krejcicdfecd92018-11-26 11:27:32 +01003100preparenext:
Radek Krejci19a96102018-11-15 13:38:09 +01003101 /* prepare next loop */
3102 tctx_prev = tctx;
3103 tctx = calloc(1, sizeof *tctx);
3104 LY_CHECK_ERR_RET(!tctx, LOGMEM(ctx->ctx), LY_EMEM);
3105 }
3106 free(tctx);
3107
3108 /* allocate type according to the basetype */
3109 switch (basetype) {
3110 case LY_TYPE_BINARY:
3111 *type = calloc(1, sizeof(struct lysc_type_bin));
Radek Krejci19a96102018-11-15 13:38:09 +01003112 break;
3113 case LY_TYPE_BITS:
3114 *type = calloc(1, sizeof(struct lysc_type_bits));
Radek Krejci19a96102018-11-15 13:38:09 +01003115 break;
3116 case LY_TYPE_BOOL:
3117 case LY_TYPE_EMPTY:
3118 *type = calloc(1, sizeof(struct lysc_type));
3119 break;
3120 case LY_TYPE_DEC64:
3121 *type = calloc(1, sizeof(struct lysc_type_dec));
3122 break;
3123 case LY_TYPE_ENUM:
3124 *type = calloc(1, sizeof(struct lysc_type_enum));
Radek Krejci19a96102018-11-15 13:38:09 +01003125 break;
3126 case LY_TYPE_IDENT:
3127 *type = calloc(1, sizeof(struct lysc_type_identityref));
3128 break;
3129 case LY_TYPE_INST:
3130 *type = calloc(1, sizeof(struct lysc_type_instanceid));
3131 break;
3132 case LY_TYPE_LEAFREF:
3133 *type = calloc(1, sizeof(struct lysc_type_leafref));
3134 break;
3135 case LY_TYPE_STRING:
3136 *type = calloc(1, sizeof(struct lysc_type_str));
Radek Krejci19a96102018-11-15 13:38:09 +01003137 break;
3138 case LY_TYPE_UNION:
3139 *type = calloc(1, sizeof(struct lysc_type_union));
3140 break;
3141 case LY_TYPE_INT8:
3142 case LY_TYPE_UINT8:
3143 case LY_TYPE_INT16:
3144 case LY_TYPE_UINT16:
3145 case LY_TYPE_INT32:
3146 case LY_TYPE_UINT32:
3147 case LY_TYPE_INT64:
3148 case LY_TYPE_UINT64:
3149 *type = calloc(1, sizeof(struct lysc_type_num));
Radek Krejci19a96102018-11-15 13:38:09 +01003150 break;
3151 case LY_TYPE_UNKNOWN:
3152 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02003153 "Referenced type \"%s\" not found.", tctx_prev ? tctx_prev->tpdf->type.name : type_p->name);
Radek Krejci19a96102018-11-15 13:38:09 +01003154 ret = LY_EVALID;
3155 goto cleanup;
3156 }
3157 LY_CHECK_ERR_GOTO(!(*type), LOGMEM(ctx->ctx), cleanup);
Radek Krejcicdfecd92018-11-26 11:27:32 +01003158 if (~type_substmt_map[basetype] & type_p->flags) {
Radek Krejci19a96102018-11-15 13:38:09 +01003159 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid type restrictions for %s type.",
Michal Vasko69730152020-10-09 16:30:07 +02003160 ly_data_type2str[basetype]);
Radek Krejci19a96102018-11-15 13:38:09 +01003161 free(*type);
3162 (*type) = NULL;
3163 ret = LY_EVALID;
3164 goto cleanup;
3165 }
3166
3167 /* get restrictions from the referred typedefs */
Radek Krejci1deb5be2020-08-26 16:43:36 +02003168 for (uint32_t u = tpdf_chain.count - 1; u + 1 > 0; --u) {
Michal Vasko22df3f02020-08-24 13:29:22 +02003169 tctx = (struct type_context *)tpdf_chain.objs[u];
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003170
3171 /* remember the typedef context for circular check */
Radek Krejci3d92e442020-10-12 12:48:13 +02003172 ret = ly_set_add(&ctx->tpdf_chain, tctx, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003173 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003174
Radek Krejci43699232018-11-23 14:59:46 +01003175 if (tctx->tpdf->type.compiled) {
Radek Krejci19a96102018-11-15 13:38:09 +01003176 base = tctx->tpdf->type.compiled;
3177 continue;
Michal Vasko69730152020-10-09 16:30:07 +02003178 } else if ((basetype != LY_TYPE_LEAFREF) && (u != tpdf_chain.count - 1) && !(tctx->tpdf->type.flags)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003179 /* no change, just use the type information from the base */
Michal Vasko22df3f02020-08-24 13:29:22 +02003180 base = ((struct lysp_tpdf *)tctx->tpdf)->type.compiled = ((struct type_context *)tpdf_chain.objs[u + 1])->tpdf->type.compiled;
Radek Krejci19a96102018-11-15 13:38:09 +01003181 ++base->refcount;
3182 continue;
3183 }
3184
3185 ++(*type)->refcount;
Radek Krejci43699232018-11-23 14:59:46 +01003186 if (~type_substmt_map[basetype] & tctx->tpdf->type.flags) {
3187 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid type \"%s\" restriction(s) for %s type.",
Michal Vasko69730152020-10-09 16:30:07 +02003188 tctx->tpdf->name, ly_data_type2str[basetype]);
Radek Krejci43699232018-11-23 14:59:46 +01003189 ret = LY_EVALID;
3190 goto cleanup;
Michal Vasko69730152020-10-09 16:30:07 +02003191 } else if ((basetype == LY_TYPE_EMPTY) && tctx->tpdf->dflt.str) {
Radek Krejci43699232018-11-23 14:59:46 +01003192 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003193 "Invalid type \"%s\" - \"empty\" type must not have a default value (%s).",
3194 tctx->tpdf->name, tctx->tpdf->dflt.str);
Radek Krejci43699232018-11-23 14:59:46 +01003195 ret = LY_EVALID;
3196 goto cleanup;
3197 }
3198
Radek Krejci19a96102018-11-15 13:38:09 +01003199 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003200 /* TODO user type plugins */
3201 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejcic5c27e52018-11-15 14:38:11 +01003202 prev_type = *type;
Michal Vaskoe9c050f2020-10-06 14:01:23 +02003203 ret = lys_compile_type_(ctx, tctx->node, tctx->tpdf->flags, tctx->mod, tctx->tpdf->name,
3204 &((struct lysp_tpdf *)tctx->tpdf)->type, basetype, tctx->tpdf->name, base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003205 LY_CHECK_GOTO(ret, cleanup);
3206 base = prev_type;
Radek Krejci19a96102018-11-15 13:38:09 +01003207 }
Radek Krejci99b5b2a2019-04-30 16:57:04 +02003208 /* remove the processed typedef contexts from the stack for circular check */
3209 ctx->tpdf_chain.count = ctx->tpdf_chain.count - tpdf_chain.count;
Radek Krejci19a96102018-11-15 13:38:09 +01003210
Radek Krejcic5c27e52018-11-15 14:38:11 +01003211 /* process the type definition in leaf */
Michal Vasko69730152020-10-09 16:30:07 +02003212 if (type_p->flags || !base || (basetype == LY_TYPE_LEAFREF)) {
Radek Krejcia3045382018-11-22 14:30:31 +01003213 /* get restrictions from the node itself */
Radek Krejci19a96102018-11-15 13:38:09 +01003214 (*type)->basetype = basetype;
Radek Krejcie7b95092019-05-15 11:03:07 +02003215 /* TODO user type plugins */
3216 (*type)->plugin = &ly_builtin_type_plugins[basetype];
Radek Krejci19a96102018-11-15 13:38:09 +01003217 ++(*type)->refcount;
Michal Vaskoe9c050f2020-10-06 14:01:23 +02003218 ret = lys_compile_type_(ctx, context_pnode, context_flags, context_mod, context_name, type_p, basetype, NULL,
3219 base, type);
Radek Krejcic5c27e52018-11-15 14:38:11 +01003220 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko69730152020-10-09 16:30:07 +02003221 } else if ((basetype != LY_TYPE_BOOL) && (basetype != LY_TYPE_EMPTY)) {
Radek Krejci19a96102018-11-15 13:38:09 +01003222 /* no specific restriction in leaf's type definition, copy from the base */
3223 free(*type);
3224 (*type) = base;
3225 ++(*type)->refcount;
Radek Krejci19a96102018-11-15 13:38:09 +01003226 }
3227
Radek Krejci0935f412019-08-20 16:15:18 +02003228 COMPILE_EXTS_GOTO(ctx, type_p->exts, (*type)->exts, (*type), LYEXT_PAR_TYPE, ret, cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01003229
3230cleanup:
3231 ly_set_erase(&tpdf_chain, free);
3232 return ret;
3233}
3234
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003235/**
3236 * @brief Compile status information of the given node.
3237 *
3238 * To simplify getting status of the node, the flags are set following inheritance rules, so all the nodes
3239 * has the status correctly set during the compilation.
3240 *
3241 * @param[in] ctx Compile context
3242 * @param[in,out] node_flags Flags of the compiled node which status is supposed to be resolved.
3243 * If the status was set explicitly on the node, it is already set in the flags value and we just check
3244 * the compatibility with the parent's status value.
3245 * @param[in] parent_flags Flags of the parent node to check/inherit the status value.
3246 * @return LY_ERR value.
3247 */
3248static LY_ERR
3249lys_compile_status(struct lysc_ctx *ctx, uint16_t *node_flags, uint16_t parent_flags)
3250{
3251 /* status - it is not inherited by specification, but it does not make sense to have
3252 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
3253 if (!((*node_flags) & LYS_STATUS_MASK)) {
3254 if (parent_flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT)) {
3255 if ((parent_flags & 0x3) != 0x3) {
3256 /* do not print the warning when inheriting status from uses - the uses_status value has a special
3257 * combination of bits (0x3) which marks the uses_status value */
3258 LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
Radek Krejci0f969882020-08-21 16:56:47 +02003259 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003260 }
3261 (*node_flags) |= parent_flags & LYS_STATUS_MASK;
3262 } else {
3263 (*node_flags) |= LYS_STATUS_CURR;
3264 }
3265 } else if (parent_flags & LYS_STATUS_MASK) {
3266 /* check status compatibility with the parent */
3267 if ((parent_flags & LYS_STATUS_MASK) > ((*node_flags) & LYS_STATUS_MASK)) {
3268 if ((*node_flags) & LYS_STATUS_CURR) {
3269 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003270 "A \"current\" status is in conflict with the parent's \"%s\" status.",
Radek Krejci0f969882020-08-21 16:56:47 +02003271 (parent_flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003272 } else { /* LYS_STATUS_DEPRC */
3273 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003274 "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003275 }
3276 return LY_EVALID;
3277 }
3278 }
3279 return LY_SUCCESS;
3280}
3281
Radek Krejci8cce8532019-03-05 11:27:45 +01003282/**
3283 * @brief Check uniqness of the node/action/notification name.
3284 *
3285 * Data nodes, actions/RPCs and Notifications are stored separately (in distinguish lists) in the schema
3286 * structures, but they share the namespace so we need to check their name collisions.
3287 *
3288 * @param[in] ctx Compile context.
Michal Vasko20424b42020-08-31 12:29:38 +02003289 * @param[in] parent Parent of the nodes to check, can be NULL.
Radek Krejci8cce8532019-03-05 11:27:45 +01003290 * @param[in] name Name of the item to find in the given lists.
Michal Vasko20424b42020-08-31 12:29:38 +02003291 * @param[in] exclude Node that was just added that should be excluded from the name checking.
Radek Krejci8cce8532019-03-05 11:27:45 +01003292 * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
3293 */
3294static LY_ERR
Michal Vasko20424b42020-08-31 12:29:38 +02003295lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *parent, const char *name,
3296 const struct lysc_node *exclude)
Radek Krejci8cce8532019-03-05 11:27:45 +01003297{
Michal Vasko20424b42020-08-31 12:29:38 +02003298 const struct lysc_node *iter, *iter2;
3299 const struct lysc_action *actions;
3300 const struct lysc_notif *notifs;
3301 uint32_t getnext_flags;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003302 LY_ARRAY_COUNT_TYPE u;
Radek Krejci8cce8532019-03-05 11:27:45 +01003303
Michal Vasko20424b42020-08-31 12:29:38 +02003304#define CHECK_NODE(iter, exclude, name) (iter != (void *)exclude && (iter)->module == exclude->module && !strcmp(name, (iter)->name))
3305
3306 if (exclude->nodetype == LYS_CASE) {
3307 /* check restricted only to all the cases */
3308 assert(parent->nodetype == LYS_CHOICE);
3309 LY_LIST_FOR(lysc_node_children(parent, 0), iter) {
3310 if (CHECK_NODE(iter, exclude, name)) {
3311 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "case");
3312 return LY_EEXIST;
3313 }
3314 }
3315
3316 return LY_SUCCESS;
3317 }
3318
3319 /* no reason for our parent to be choice anymore */
3320 assert(!parent || (parent->nodetype != LYS_CHOICE));
3321
3322 if (parent && (parent->nodetype == LYS_CASE)) {
3323 /* move to the first data definition parent */
3324 parent = lysc_data_parent(parent);
3325 }
3326
3327 getnext_flags = LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE;
3328 if (parent && (parent->nodetype & (LYS_RPC | LYS_ACTION)) && (exclude->flags & LYS_CONFIG_R)) {
3329 getnext_flags |= LYS_GETNEXT_OUTPUT;
3330 }
3331
3332 iter = NULL;
3333 while ((iter = lys_getnext(iter, parent, ctx->mod->compiled, getnext_flags))) {
3334 if (CHECK_NODE(iter, exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003335 goto error;
3336 }
Michal Vasko20424b42020-08-31 12:29:38 +02003337
3338 /* we must compare with both the choice and all its nested data-definiition nodes (but not recursively) */
3339 if (iter->nodetype == LYS_CHOICE) {
3340 iter2 = NULL;
3341 while ((iter2 = lys_getnext(iter2, iter, NULL, LYS_GETNEXT_NOSTATECHECK))) {
3342 if (CHECK_NODE(iter2, exclude, name)) {
3343 goto error;
3344 }
3345 }
3346 }
Radek Krejci8cce8532019-03-05 11:27:45 +01003347 }
Michal Vasko20424b42020-08-31 12:29:38 +02003348
3349 actions = parent ? lysc_node_actions(parent) : ctx->mod->compiled->rpcs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003350 LY_ARRAY_FOR(actions, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003351 if (CHECK_NODE(&actions[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003352 goto error;
3353 }
3354 }
Michal Vasko20424b42020-08-31 12:29:38 +02003355
3356 notifs = parent ? lysc_node_notifs(parent) : ctx->mod->compiled->notifs;
Radek Krejci8cce8532019-03-05 11:27:45 +01003357 LY_ARRAY_FOR(notifs, u) {
Michal Vasko20424b42020-08-31 12:29:38 +02003358 if (CHECK_NODE(&notifs[u], exclude, name)) {
Radek Krejci8cce8532019-03-05 11:27:45 +01003359 goto error;
3360 }
3361 }
3362 return LY_SUCCESS;
Michal Vasko20424b42020-08-31 12:29:38 +02003363
Radek Krejci8cce8532019-03-05 11:27:45 +01003364error:
Michal Vaskoa3881362020-01-21 15:57:35 +01003365 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPIDENT, name, "data definition/RPC/action/notification");
Radek Krejci8cce8532019-03-05 11:27:45 +01003366 return LY_EEXIST;
Michal Vasko20424b42020-08-31 12:29:38 +02003367
3368#undef CHECK_NODE
Radek Krejci8cce8532019-03-05 11:27:45 +01003369}
3370
Michal Vasko7f45cf22020-10-01 12:49:44 +02003371static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent,
3372 uint16_t uses_status, struct ly_set *child_set);
3373
3374static LY_ERR lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode,
3375 const struct lysc_node *parent, struct lysp_node **dev_pnode, ly_bool *not_supported);
3376
3377static LY_ERR lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node);
3378
3379static void lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01003380
Radek Krejcia3045382018-11-22 14:30:31 +01003381/**
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003382 * @brief Compile parsed RPC/action schema node information.
3383 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003384 * @param[in] action_p Parsed RPC/action schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003385 * @param[in] parent Parent node of the action, NULL in case of RPC (top-level action)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003386 * @param[in,out] action Prepared (empty) compiled action structure to fill.
3387 * @param[in] uses_status If the RPC/action is being placed instead of uses, here we have the uses's status value (as node's flags).
3388 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003389 * @return LY_SUCCESS on success,
3390 * @return LY_EVALID on validation error,
3391 * @return LY_EDENIED on not-supported deviation.
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003392 */
3393static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003394lys_compile_action(struct lysc_ctx *ctx, struct lysp_action *action_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003395 struct lysc_node *parent, struct lysc_action *action, uint16_t uses_status)
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003396{
3397 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003398 struct lysp_node *child_p, *dev_pnode = NULL, *dev_input_p = NULL, *dev_output_p = NULL;
3399 struct lysp_action *orig_action_p = action_p;
3400 struct lysp_action_inout *inout_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003401 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003402 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003403 uint32_t opt_prev = ctx->options;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003404
Radek Krejci327de162019-06-14 12:52:07 +02003405 lysc_update_path(ctx, parent, action_p->name);
3406
Michal Vasko7f45cf22020-10-01 12:49:44 +02003407 /* apply deviation on the action/RPC */
3408 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)action_p, parent, &dev_pnode, &not_supported));
3409 if (not_supported) {
3410 lysc_update_path(ctx, NULL, NULL);
3411 return LY_EDENIED;
3412 } else if (dev_pnode) {
3413 action_p = (struct lysp_action *)dev_pnode;
3414 }
3415
Michal Vasko20424b42020-08-31 12:29:38 +02003416 /* member needed for uniqueness check lys_getnext() */
3417 action->nodetype = parent ? LYS_ACTION : LYS_RPC;
3418 action->module = ctx->mod;
3419 action->parent = parent;
3420
3421 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, action_p->name, (struct lysc_node *)action));
Radek Krejci8cce8532019-03-05 11:27:45 +01003422
Radek Krejci90d4e922020-10-12 15:55:33 +02003423 if (ctx->options & (LYS_COMPILE_RPC_MASK | LYS_COMPILE_NOTIFICATION)) {
Radek Krejci05b774b2019-02-25 13:26:18 +01003424 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003425 "Action \"%s\" is placed inside %s.", action_p->name,
Radek Krejci90d4e922020-10-12 15:55:33 +02003426 ctx->options & LYS_COMPILE_RPC_MASK ? "another RPC/action" : "notification");
Radek Krejci05b774b2019-02-25 13:26:18 +01003427 return LY_EVALID;
3428 }
3429
Radek Krejci90d4e922020-10-12 15:55:33 +02003430 action->sp = orig_action_p;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003431 action->flags = action_p->flags & LYS_FLAGS_COMPILED_MASK;
3432
3433 /* status - it is not inherited by specification, but it does not make sense to have
3434 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vaskocc048b22020-03-27 15:52:38 +01003435 LY_CHECK_RET(lys_compile_status(ctx, &action->flags, uses_status ? uses_status : (parent ? parent->flags : 0)));
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003436
Radek Krejci011e4aa2020-09-04 15:22:31 +02003437 DUP_STRING_GOTO(ctx->ctx, action_p->name, action->name, ret, cleanup);
3438 DUP_STRING_GOTO(ctx->ctx, action_p->dsc, action->dsc, ret, cleanup);
3439 DUP_STRING_GOTO(ctx->ctx, action_p->ref, action->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003440 COMPILE_ARRAY_GOTO(ctx, action_p->iffeatures, action->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejci0935f412019-08-20 16:15:18 +02003441 COMPILE_EXTS_GOTO(ctx, action_p->exts, action->exts, action, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003442
Michal Vasko7f45cf22020-10-01 12:49:44 +02003443 /* connect any action augments */
3444 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)action));
3445
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003446 /* input */
Michal Vasko22df3f02020-08-24 13:29:22 +02003447 lysc_update_path(ctx, (struct lysc_node *)action, "input");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003448
3449 /* apply deviations on input */
3450 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->input, (struct lysc_node *)action,
3451 &dev_input_p, &not_supported));
3452 if (not_supported) {
3453 inout_p = NULL;
3454 } else if (dev_input_p) {
3455 inout_p = (struct lysp_action_inout *)dev_input_p;
3456 } else {
3457 inout_p = &action_p->input;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003458 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003459
3460 if (inout_p) {
3461 action->input.nodetype = LYS_INPUT;
3462 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->input.musts, u, lys_compile_must, ret, cleanup);
3463 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->input_exts, &action->input, LYEXT_PAR_INPUT, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003464 ctx->options |= LYS_COMPILE_RPC_INPUT;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003465
3466 /* connect any input augments */
3467 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->input));
3468
3469 LY_LIST_FOR(inout_p->data, child_p) {
3470 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3471 }
3472 ctx->options = opt_prev;
3473 }
3474
Radek Krejci327de162019-06-14 12:52:07 +02003475 lysc_update_path(ctx, NULL, NULL);
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003476
3477 /* output */
Michal Vasko22df3f02020-08-24 13:29:22 +02003478 lysc_update_path(ctx, (struct lysc_node *)action, "output");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003479
3480 /* apply deviations on output */
3481 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)&action_p->output, (struct lysc_node *)action,
3482 &dev_output_p, &not_supported));
3483 if (not_supported) {
3484 inout_p = NULL;
3485 } else if (dev_output_p) {
3486 inout_p = (struct lysp_action_inout *)dev_output_p;
3487 } else {
3488 inout_p = &action_p->output;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003489 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003490
3491 if (inout_p) {
3492 action->output.nodetype = LYS_OUTPUT;
3493 COMPILE_ARRAY_GOTO(ctx, inout_p->musts, action->output.musts, u, lys_compile_must, ret, cleanup);
3494 COMPILE_EXTS_GOTO(ctx, inout_p->exts, action->output_exts, &action->output, LYEXT_PAR_OUTPUT, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003495 ctx->options |= LYS_COMPILE_RPC_OUTPUT;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003496
3497 /* connect any output augments */
3498 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)&action->output));
3499
3500 LY_LIST_FOR(inout_p->data, child_p) {
3501 LY_CHECK_RET(lys_compile_node(ctx, child_p, (struct lysc_node *)action, uses_status, NULL));
3502 }
3503 ctx->options = opt_prev;
3504 }
3505
Radek Krejci327de162019-06-14 12:52:07 +02003506 lysc_update_path(ctx, NULL, NULL);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003507
Radek Krejci90d4e922020-10-12 15:55:33 +02003508 if ((action->input.musts || action->output.musts) && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003509 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003510 ret = ly_set_add(&ctx->xpath, action, 0, NULL);
3511 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003512 }
3513
Michal Vasko7f45cf22020-10-01 12:49:44 +02003514 lysc_update_path(ctx, NULL, NULL);
3515
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003516cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003517 lysp_dev_node_free(ctx->ctx, dev_pnode);
3518 lysp_dev_node_free(ctx->ctx, dev_input_p);
3519 lysp_dev_node_free(ctx->ctx, dev_output_p);
Radek Krejciec4da802019-05-02 13:02:41 +02003520 ctx->options = opt_prev;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003521 return ret;
3522}
3523
3524/**
Radek Krejci43981a32019-04-12 09:44:11 +02003525 * @brief Compile parsed Notification schema node information.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003526 * @param[in] ctx Compile context
Radek Krejci43981a32019-04-12 09:44:11 +02003527 * @param[in] notif_p Parsed Notification schema node.
Radek Krejci43981a32019-04-12 09:44:11 +02003528 * @param[in] parent Parent node of the Notification, NULL in case of top-level Notification
3529 * @param[in,out] notif Prepared (empty) compiled notification structure to fill.
3530 * @param[in] uses_status If the Notification is being placed instead of uses, here we have the uses's status value (as node's flags).
Radek Krejcifc11bd72019-04-11 16:00:05 +02003531 * Zero means no uses, non-zero value with no status bit set mean the default status.
Michal Vasko7f45cf22020-10-01 12:49:44 +02003532 * @return LY_SUCCESS on success,
3533 * @return LY_EVALID on validation error,
3534 * @return LY_EDENIED on not-supported deviation.
Radek Krejcifc11bd72019-04-11 16:00:05 +02003535 */
3536static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02003537lys_compile_notif(struct lysc_ctx *ctx, struct lysp_notif *notif_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003538 struct lysc_node *parent, struct lysc_notif *notif, uint16_t uses_status)
Radek Krejcifc11bd72019-04-11 16:00:05 +02003539{
3540 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003541 struct lysp_node *child_p, *dev_pnode = NULL;
3542 struct lysp_notif *orig_notif_p = notif_p;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003543 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003544 ly_bool not_supported;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003545 uint32_t opt_prev = ctx->options;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003546
Radek Krejci327de162019-06-14 12:52:07 +02003547 lysc_update_path(ctx, parent, notif_p->name);
3548
Michal Vasko7f45cf22020-10-01 12:49:44 +02003549 LY_CHECK_RET(lys_compile_node_deviations_refines(ctx, (struct lysp_node *)notif_p, parent, &dev_pnode, &not_supported));
3550 if (not_supported) {
3551 lysc_update_path(ctx, NULL, NULL);
3552 return LY_EDENIED;
3553 } else if (dev_pnode) {
3554 notif_p = (struct lysp_notif *)dev_pnode;
3555 }
3556
Michal Vasko20424b42020-08-31 12:29:38 +02003557 /* member needed for uniqueness check lys_getnext() */
3558 notif->nodetype = LYS_NOTIF;
3559 notif->module = ctx->mod;
3560 notif->parent = parent;
3561
3562 LY_CHECK_RET(lys_compile_node_uniqness(ctx, parent, notif_p->name, (struct lysc_node *)notif));
Radek Krejcifc11bd72019-04-11 16:00:05 +02003563
Radek Krejci90d4e922020-10-12 15:55:33 +02003564 if (ctx->options & (LYS_COMPILE_RPC_MASK | LYS_COMPILE_NOTIFICATION)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02003565 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003566 "Notification \"%s\" is placed inside %s.", notif_p->name,
Radek Krejci90d4e922020-10-12 15:55:33 +02003567 ctx->options & LYS_COMPILE_RPC_MASK ? "RPC/action" : "another notification");
Radek Krejcifc11bd72019-04-11 16:00:05 +02003568 return LY_EVALID;
3569 }
3570
Radek Krejci90d4e922020-10-12 15:55:33 +02003571 notif->sp = orig_notif_p;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003572 notif->flags = notif_p->flags & LYS_FLAGS_COMPILED_MASK;
3573
3574 /* status - it is not inherited by specification, but it does not make sense to have
3575 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003576 ret = lys_compile_status(ctx, &notif->flags, uses_status ? uses_status : (parent ? parent->flags : 0));
3577 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003578
Radek Krejci011e4aa2020-09-04 15:22:31 +02003579 DUP_STRING_GOTO(ctx->ctx, notif_p->name, notif->name, ret, cleanup);
3580 DUP_STRING_GOTO(ctx->ctx, notif_p->dsc, notif->dsc, ret, cleanup);
3581 DUP_STRING_GOTO(ctx->ctx, notif_p->ref, notif->ref, ret, cleanup);
Radek Krejciec4da802019-05-02 13:02:41 +02003582 COMPILE_ARRAY_GOTO(ctx, notif_p->iffeatures, notif->iffeatures, u, lys_compile_iffeature, ret, cleanup);
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003583 COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, u, lys_compile_must, ret, cleanup);
Radek Krejci90d4e922020-10-12 15:55:33 +02003584 if (notif_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003585 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003586 ret = ly_set_add(&ctx->xpath, notif, 0, NULL);
3587 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003588 }
Radek Krejci0935f412019-08-20 16:15:18 +02003589 COMPILE_EXTS_GOTO(ctx, notif_p->exts, notif->exts, notif, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003590
Radek Krejci90d4e922020-10-12 15:55:33 +02003591 ctx->options |= LYS_COMPILE_NOTIFICATION;
Michal Vasko7f45cf22020-10-01 12:49:44 +02003592
3593 /* connect any notification augments */
3594 LY_CHECK_RET(lys_compile_node_augments(ctx, (struct lysc_node *)notif));
3595
Radek Krejcifc11bd72019-04-11 16:00:05 +02003596 LY_LIST_FOR(notif_p->data, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003597 ret = lys_compile_node(ctx, child_p, (struct lysc_node *)notif, uses_status, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003598 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02003599 }
3600
Radek Krejci327de162019-06-14 12:52:07 +02003601 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003602
Radek Krejcifc11bd72019-04-11 16:00:05 +02003603cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02003604 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejciec4da802019-05-02 13:02:41 +02003605 ctx->options = opt_prev;
Radek Krejcifc11bd72019-04-11 16:00:05 +02003606 return ret;
3607}
3608
3609/**
Radek Krejcia3045382018-11-22 14:30:31 +01003610 * @brief Compile parsed container node information.
3611 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003612 * @param[in] pnode Parsed container node.
Radek Krejcia3045382018-11-22 14:30:31 +01003613 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3614 * is enriched with the container-specific information.
3615 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3616 */
Radek Krejci19a96102018-11-15 13:38:09 +01003617static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003618lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003619{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003620 struct lysp_node_container *cont_p = (struct lysp_node_container *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003621 struct lysc_node_container *cont = (struct lysc_node_container *)node;
Radek Krejci19a96102018-11-15 13:38:09 +01003622 struct lysp_node *child_p;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003623 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003624 LY_ERR ret = LY_SUCCESS;
3625
Radek Krejcife909632019-02-12 15:34:42 +01003626 if (cont_p->presence) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003627 /* explicit presence */
Radek Krejcife909632019-02-12 15:34:42 +01003628 cont->flags |= LYS_PRESENCE;
Michal Vaskoba417ac2020-08-06 14:48:20 +02003629 } else if (cont_p->musts) {
3630 /* container with a must condition */
Radek Krejci175f25b2020-08-13 12:02:36 +02003631 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning from its \"must\" condition.", cont_p->name);
3632 cont->flags |= LYS_PRESENCE;
3633 } else if (cont_p->when) {
3634 /* container with a when condition */
3635 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning from its \"when\" condition.", cont_p->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003636 cont->flags |= LYS_PRESENCE;
3637 } else if (cont_p->parent) {
3638 if (cont_p->parent->nodetype == LYS_CHOICE) {
3639 /* container is an implicit case, so its existence decides the existence of the whole case */
Radek Krejci175f25b2020-08-13 12:02:36 +02003640 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning as a case of choice \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02003641 cont_p->name, cont_p->parent->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003642 cont->flags |= LYS_PRESENCE;
Michal Vasko69730152020-10-09 16:30:07 +02003643 } else if ((cont_p->parent->nodetype == LYS_CASE) &&
3644 (((struct lysp_node_case *)cont_p->parent)->child == pnode) && !cont_p->next) {
Michal Vaskoba417ac2020-08-06 14:48:20 +02003645 /* container is the only node in a case, so its existence decides the existence of the whole case */
Radek Krejci175f25b2020-08-13 12:02:36 +02003646 LOGWRN(ctx->ctx, "Container \"%s\" changed to presence because it has a meaning as a case of choice \"%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02003647 cont_p->name, cont_p->parent->name);
Michal Vaskoba417ac2020-08-06 14:48:20 +02003648 cont->flags |= LYS_PRESENCE;
3649 }
Radek Krejcife909632019-02-12 15:34:42 +01003650 }
3651
Michal Vaskoba417ac2020-08-06 14:48:20 +02003652 /* more cases when the container has meaning but is kept NP for convenience:
3653 * - when condition
3654 * - direct child action/notification
3655 */
3656
Radek Krejci19a96102018-11-15 13:38:09 +01003657 LY_LIST_FOR(cont_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003658 ret = lys_compile_node(ctx, child_p, node, 0, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003659 LY_CHECK_GOTO(ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01003660 }
3661
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003662 COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003663 if (cont_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003664 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003665 ret = ly_set_add(&ctx->xpath, cont, 0, NULL);
3666 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003667 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02003668 COMPILE_OP_ARRAY_GOTO(ctx, cont_p->actions, cont->actions, node, u, lys_compile_action, 0, ret, done);
3669 COMPILE_OP_ARRAY_GOTO(ctx, cont_p->notifs, cont->notifs, node, u, lys_compile_notif, 0, ret, done);
Radek Krejci19a96102018-11-15 13:38:09 +01003670
3671done:
3672 return ret;
3673}
3674
Radek Krejci33f72892019-02-21 10:36:58 +01003675/*
3676 * @brief Compile type in leaf/leaf-list node and do all the necessary checks.
3677 * @param[in] ctx Compile context.
3678 * @param[in] context_node Schema node where the type/typedef is placed to correctly find the base types.
3679 * @param[in] type_p Parsed type to compile.
Radek Krejci33f72892019-02-21 10:36:58 +01003680 * @param[in,out] leaf Compiled leaf structure (possibly cast leaf-list) to provide node information and to store the compiled type information.
3681 * @return LY_ERR value.
3682 */
3683static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003684lys_compile_node_type(struct lysc_ctx *ctx, struct lysp_node *context_node, struct lysp_type *type_p,
Radek Krejci0f969882020-08-21 16:56:47 +02003685 struct lysc_node_leaf *leaf)
Radek Krejci33f72892019-02-21 10:36:58 +01003686{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003687 struct lysp_qname *dflt;
Radek Krejci33f72892019-02-21 10:36:58 +01003688
Radek Krejciec4da802019-05-02 13:02:41 +02003689 LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, ctx->mod_def->parsed, leaf->name, type_p, &leaf->type,
Michal Vasko69730152020-10-09 16:30:07 +02003690 leaf->units ? NULL : &leaf->units, &dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003691
3692 /* store default value, if any */
3693 if (dflt && !(leaf->flags & LYS_SET_DFLT)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003694 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
Radek Krejci33f72892019-02-21 10:36:58 +01003695 }
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003696
Radek Krejci33f72892019-02-21 10:36:58 +01003697 if (leaf->type->basetype == LY_TYPE_LEAFREF) {
3698 /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003699 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003700 } else if (leaf->type->basetype == LY_TYPE_UNION) {
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003701 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003702 LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
3703 if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
Radek Krejci33f72892019-02-21 10:36:58 +01003704 /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003705 LY_CHECK_RET(ly_set_add(&ctx->leafrefs, leaf, 0, NULL));
Radek Krejci33f72892019-02-21 10:36:58 +01003706 }
3707 }
3708 } else if (leaf->type->basetype == LY_TYPE_EMPTY) {
Michal Vasko69730152020-10-09 16:30:07 +02003709 if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->mod_def->version < LYS_VERSION_1_1)) {
Radek Krejci33f72892019-02-21 10:36:58 +01003710 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003711 "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
Radek Krejci33f72892019-02-21 10:36:58 +01003712 return LY_EVALID;
3713 }
3714 }
3715
Radek Krejci33f72892019-02-21 10:36:58 +01003716 return LY_SUCCESS;
3717}
3718
Radek Krejcia3045382018-11-22 14:30:31 +01003719/**
3720 * @brief Compile parsed leaf node information.
3721 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003722 * @param[in] pnode Parsed leaf node.
Radek Krejcia3045382018-11-22 14:30:31 +01003723 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3724 * is enriched with the leaf-specific information.
3725 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3726 */
Radek Krejci19a96102018-11-15 13:38:09 +01003727static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003728lys_compile_node_leaf(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci19a96102018-11-15 13:38:09 +01003729{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003730 struct lysp_node_leaf *leaf_p = (struct lysp_node_leaf *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003731 struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
Michal Vasko7c8439f2020-08-05 13:25:19 +02003732 LY_ARRAY_COUNT_TYPE u;
Radek Krejci19a96102018-11-15 13:38:09 +01003733 LY_ERR ret = LY_SUCCESS;
3734
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003735 COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003736 if (leaf_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003737 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003738 ret = ly_set_add(&ctx->xpath, leaf, 0, NULL);
3739 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003740 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003741 if (leaf_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003742 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, leaf_p->units, 0, &leaf->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003743 leaf->flags |= LYS_SET_UNITS;
3744 }
Radek Krejcia1911222019-07-22 17:24:50 +02003745
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003746 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003747 ret = lys_compile_node_type(ctx, pnode, &leaf_p->type, leaf);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003748 LY_CHECK_GOTO(ret, done);
Radek Krejcia1911222019-07-22 17:24:50 +02003749
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003750 /* store/update default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003751 if (leaf_p->dflt.str) {
3752 LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, &leaf_p->dflt));
Radek Krejci76b3e962018-12-14 17:01:25 +01003753 leaf->flags |= LYS_SET_DFLT;
3754 }
Radek Krejci43699232018-11-23 14:59:46 +01003755
Michal Vasko7f45cf22020-10-01 12:49:44 +02003756 /* checks */
3757 if ((leaf->flags & LYS_SET_DFLT) && (leaf->flags & LYS_MAND_TRUE)) {
3758 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3759 "Invalid mandatory leaf with a default value.");
3760 return LY_EVALID;
3761 }
3762
Radek Krejci19a96102018-11-15 13:38:09 +01003763done:
3764 return ret;
3765}
3766
Radek Krejcia3045382018-11-22 14:30:31 +01003767/**
Radek Krejci0e5d8382018-11-28 16:37:53 +01003768 * @brief Compile parsed leaf-list node information.
3769 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02003770 * @param[in] pnode Parsed leaf-list node.
Radek Krejci0e5d8382018-11-28 16:37:53 +01003771 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
3772 * is enriched with the leaf-list-specific information.
3773 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
3774 */
3775static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003776lys_compile_node_leaflist(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci0e5d8382018-11-28 16:37:53 +01003777{
Michal Vasko7f45cf22020-10-01 12:49:44 +02003778 struct lysp_node_leaflist *llist_p = (struct lysp_node_leaflist *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02003779 struct lysc_node_leaflist *llist = (struct lysc_node_leaflist *)node;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003780 LY_ARRAY_COUNT_TYPE u;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003781 LY_ERR ret = LY_SUCCESS;
3782
Radek Krejcic71ac5b2019-09-10 15:34:22 +02003783 COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02003784 if (llist_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01003785 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02003786 ret = ly_set_add(&ctx->xpath, llist, 0, NULL);
3787 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01003788 }
Radek Krejciccd20f12019-02-15 14:12:27 +01003789 if (llist_p->units) {
Radek Krejci011e4aa2020-09-04 15:22:31 +02003790 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, llist_p->units, 0, &llist->units), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003791 llist->flags |= LYS_SET_UNITS;
3792 }
Radek Krejci0e5d8382018-11-28 16:37:53 +01003793
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003794 /* compile type */
Michal Vasko7f45cf22020-10-01 12:49:44 +02003795 ret = lys_compile_node_type(ctx, pnode, &llist_p->type, (struct lysc_node_leaf *)llist);
Radek Krejciba03a5a2020-08-27 14:40:41 +02003796 LY_CHECK_GOTO(ret, done);
Michal Vasko6a044b22020-01-15 12:25:39 +01003797
Michal Vaskoba99a3e2020-08-18 15:50:05 +02003798 /* store/update default values */
Radek Krejci0e5d8382018-11-28 16:37:53 +01003799 if (llist_p->dflts) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02003800 if (ctx->mod_def->version < LYS_VERSION_1_1) {
3801 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02003802 "Leaf-list default values are allowed only in YANG 1.1 modules.");
Michal Vasko7f45cf22020-10-01 12:49:44 +02003803 return LY_EVALID;
3804 }
3805
3806 LY_CHECK_GOTO(lysc_unres_llist_dflts_add(ctx, llist, llist_p->dflts), done);
Radek Krejciccd20f12019-02-15 14:12:27 +01003807 llist->flags |= LYS_SET_DFLT;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003808 }
3809
3810 llist->min = llist_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01003811 if (llist->min) {
3812 llist->flags |= LYS_MAND_TRUE;
3813 }
Radek Krejcib7408632018-11-28 17:12:11 +01003814 llist->max = llist_p->max ? llist_p->max : (uint32_t)-1;
Radek Krejci0e5d8382018-11-28 16:37:53 +01003815
Michal Vasko7f45cf22020-10-01 12:49:44 +02003816 /* checks */
3817 if ((llist->flags & LYS_SET_DFLT) && (llist->flags & LYS_MAND_TRUE)) {
3818 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
3819 "Invalid mandatory leaf-list with default value(s).");
3820 return LY_EVALID;
3821 }
3822
3823 if (llist->min > llist->max) {
3824 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Leaf-list min-elements %u is bigger than max-elements %u.",
Michal Vasko69730152020-10-09 16:30:07 +02003825 llist->min, llist->max);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003826 return LY_EVALID;
3827 }
3828
Radek Krejci0e5d8382018-11-28 16:37:53 +01003829done:
3830 return ret;
3831}
3832
3833/**
Radek Krejci90d4e922020-10-12 15:55:33 +02003834 * @brief Find the node according to the given descendant/absolute schema nodeid.
3835 * Used in unique, refine and augment statements.
3836 *
3837 * @param[in] ctx Compile context
3838 * @param[in] nodeid Descendant-schema-nodeid (according to the YANG grammar)
3839 * @param[in] nodeid_len Length of the given nodeid, if it is not NULL-terminated string.
3840 * @param[in] context_node Node where the nodeid is specified to correctly resolve prefixes and to start searching.
3841 * If no context node is provided, the nodeid is actually expected to be the absolute schema node .
3842 * @param[in] context_module Explicit module to resolve prefixes in @nodeid.
3843 * @param[in] nodetype Optional (can be 0) restriction for target's nodetype. If target exists, but does not match
3844 * the given nodetype, LY_EDENIED is returned (and target is provided), but no error message is printed.
3845 * The value can be even an ORed value to allow multiple nodetypes.
3846 * @param[out] target Found target node if any.
3847 * @param[out] result_flag Output parameter to announce if the schema nodeid goes through the action's input/output or a Notification.
3848 * The LYSC_OPT_RPC_INPUT, LYSC_OPT_RPC_OUTPUT and LYSC_OPT_NOTIFICATION are used as flags.
3849 * @return LY_ERR values - LY_ENOTFOUND, LY_EVALID, LY_EDENIED or LY_SUCCESS.
3850 */
3851static LY_ERR
3852lysc_resolve_schema_nodeid(struct lysc_ctx *ctx, const char *nodeid, size_t nodeid_len, const struct lysc_node *context_node,
3853 const struct lys_module *context_module, uint16_t nodetype, const struct lysc_node **target, uint16_t *result_flag)
3854{
3855 LY_ERR ret = LY_EVALID;
3856 const char *name, *prefix, *id;
3857 size_t name_len, prefix_len;
3858 const struct lys_module *mod;
3859 const char *nodeid_type;
3860 uint32_t getnext_extra_flag = 0;
3861 uint16_t current_nodetype = 0;
3862
3863 assert(nodeid);
3864 assert(target);
3865 assert(result_flag);
3866 *target = NULL;
3867 *result_flag = 0;
3868
3869 id = nodeid;
3870
3871 if (context_node) {
3872 /* descendant-schema-nodeid */
3873 nodeid_type = "descendant";
3874
3875 if (*id == '/') {
3876 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3877 "Invalid descendant-schema-nodeid value \"%.*s\" - absolute-schema-nodeid used.",
3878 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3879 return LY_EVALID;
3880 }
3881 } else {
3882 /* absolute-schema-nodeid */
3883 nodeid_type = "absolute";
3884
3885 if (*id != '/') {
3886 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3887 "Invalid absolute-schema-nodeid value \"%.*s\" - missing starting \"/\".",
3888 nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3889 return LY_EVALID;
3890 }
3891 ++id;
3892 }
3893
3894 while (*id && (ret = ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len)) == LY_SUCCESS) {
3895 if (prefix) {
3896 mod = lys_module_find_prefix(context_module, prefix, prefix_len);
3897 if (!mod) {
3898 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3899 "Invalid %s-schema-nodeid value \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
3900 nodeid_type, id - nodeid, nodeid, prefix_len, prefix, context_module->name);
3901 return LY_ENOTFOUND;
3902 }
3903 } else {
3904 mod = context_module;
3905 }
3906 if (context_node && (context_node->nodetype & (LYS_RPC | LYS_ACTION))) {
3907 /* move through input/output manually */
3908 if (mod != context_node->module) {
3909 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3910 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
3911 return LY_ENOTFOUND;
3912 }
3913 if (!ly_strncmp("input", name, name_len)) {
3914 context_node = (struct lysc_node *)&((struct lysc_action *)context_node)->input;
3915 } else if (!ly_strncmp("output", name, name_len)) {
3916 context_node = (struct lysc_node *)&((struct lysc_action *)context_node)->output;
3917 getnext_extra_flag = LYS_GETNEXT_OUTPUT;
3918 } else {
3919 /* only input or output is valid */
3920 context_node = NULL;
3921 }
3922 } else {
3923 context_node = lys_find_child(context_node, mod, name, name_len, 0,
3924 getnext_extra_flag | LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE);
3925 getnext_extra_flag = 0;
3926 }
3927 if (!context_node) {
3928 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3929 "Invalid %s-schema-nodeid value \"%.*s\" - target node not found.", nodeid_type, id - nodeid, nodeid);
3930 return LY_ENOTFOUND;
3931 }
3932 current_nodetype = context_node->nodetype;
3933
3934 if (current_nodetype == LYS_NOTIF) {
3935 (*result_flag) |= LYS_COMPILE_NOTIFICATION;
3936 } else if (current_nodetype == LYS_INPUT) {
3937 (*result_flag) |= LYS_COMPILE_RPC_INPUT;
3938 } else if (current_nodetype == LYS_OUTPUT) {
3939 (*result_flag) |= LYS_COMPILE_RPC_OUTPUT;
3940 }
3941
3942 if (!*id || (nodeid_len && ((size_t)(id - nodeid) >= nodeid_len))) {
3943 break;
3944 }
3945 if (*id != '/') {
3946 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3947 "Invalid %s-schema-nodeid value \"%.*s\" - missing \"/\" as node-identifier separator.",
3948 nodeid_type, id - nodeid + 1, nodeid);
3949 return LY_EVALID;
3950 }
3951 ++id;
3952 }
3953
3954 if (ret == LY_SUCCESS) {
3955 *target = context_node;
3956 if (nodetype && !(current_nodetype & nodetype)) {
3957 return LY_EDENIED;
3958 }
3959 } else {
3960 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
3961 "Invalid %s-schema-nodeid value \"%.*s\" - unexpected end of expression.",
3962 nodeid_type, nodeid_len ? nodeid_len : strlen(nodeid), nodeid);
3963 }
3964
3965 return ret;
3966}
3967
3968/**
Radek Krejci7af64242019-02-18 13:07:53 +01003969 * @brief Compile information about list's uniques.
3970 * @param[in] ctx Compile context.
Radek Krejci7af64242019-02-18 13:07:53 +01003971 * @param[in] uniques Sized array list of unique statements.
3972 * @param[in] list Compiled list where the uniques are supposed to be resolved and stored.
3973 * @return LY_ERR value.
3974 */
3975static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02003976lys_compile_node_list_unique(struct lysc_ctx *ctx, struct lysp_qname *uniques, struct lysc_node_list *list)
Radek Krejci7af64242019-02-18 13:07:53 +01003977{
3978 LY_ERR ret = LY_SUCCESS;
3979 struct lysc_node_leaf **key, ***unique;
Michal Vasko14654712020-02-06 08:35:21 +01003980 struct lysc_node *parent;
Radek Krejci7af64242019-02-18 13:07:53 +01003981 const char *keystr, *delim;
3982 size_t len;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02003983 LY_ARRAY_COUNT_TYPE v;
Radek Krejci1deb5be2020-08-26 16:43:36 +02003984 int8_t config; /* -1 - not yet seen; 0 - LYS_CONFIG_R; 1 - LYS_CONFIG_W */
Radek Krejci6eeb58f2019-02-22 16:29:37 +01003985 uint16_t flags;
Radek Krejci7af64242019-02-18 13:07:53 +01003986
Michal Vasko7f45cf22020-10-01 12:49:44 +02003987 LY_ARRAY_FOR(uniques, v) {
Radek Krejci7af64242019-02-18 13:07:53 +01003988 config = -1;
3989 LY_ARRAY_NEW_RET(ctx->ctx, list->uniques, unique, LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02003990 keystr = uniques[v].str;
Radek Krejci7af64242019-02-18 13:07:53 +01003991 while (keystr) {
3992 delim = strpbrk(keystr, " \t\n");
3993 if (delim) {
3994 len = delim - keystr;
3995 while (isspace(*delim)) {
3996 ++delim;
3997 }
3998 } else {
3999 len = strlen(keystr);
4000 }
4001
4002 /* unique node must be present */
4003 LY_ARRAY_NEW_RET(ctx->ctx, *unique, key, LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004004 ret = lysc_resolve_schema_nodeid(ctx, keystr, len, (struct lysc_node *)list, uniques[v].mod, LYS_LEAF,
Michal Vasko69730152020-10-09 16:30:07 +02004005 (const struct lysc_node **)key, &flags);
Radek Krejci7af64242019-02-18 13:07:53 +01004006 if (ret != LY_SUCCESS) {
4007 if (ret == LY_EDENIED) {
4008 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004009 "Unique's descendant-schema-nodeid \"%.*s\" refers to %s node instead of a leaf.",
4010 len, keystr, lys_nodetype2str((*key)->nodetype));
Radek Krejci7af64242019-02-18 13:07:53 +01004011 }
4012 return LY_EVALID;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004013 } else if (flags) {
4014 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004015 "Unique's descendant-schema-nodeid \"%.*s\" refers into %s node.",
Radek Krejci90d4e922020-10-12 15:55:33 +02004016 len, keystr, flags & LYS_COMPILE_NOTIFICATION ? "notification" : "RPC/action");
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004017 return LY_EVALID;
Radek Krejci7af64242019-02-18 13:07:53 +01004018 }
4019
4020 /* all referenced leafs must be of the same config type */
Michal Vasko69730152020-10-09 16:30:07 +02004021 if ((config != -1) && ((((*key)->flags & LYS_CONFIG_W) && (config == 0)) || (((*key)->flags & LYS_CONFIG_R) && (config == 1)))) {
Radek Krejci7af64242019-02-18 13:07:53 +01004022 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004023 "Unique statement \"%s\" refers to leaves with different config type.", uniques[v].str);
Radek Krejci7af64242019-02-18 13:07:53 +01004024 return LY_EVALID;
4025 } else if ((*key)->flags & LYS_CONFIG_W) {
4026 config = 1;
4027 } else { /* LYS_CONFIG_R */
4028 config = 0;
4029 }
4030
Michal Vasko14654712020-02-06 08:35:21 +01004031 /* we forbid referencing nested lists because it is unspecified what instance of such a list to use */
4032 for (parent = (*key)->parent; parent != (struct lysc_node *)list; parent = parent->parent) {
4033 if (parent->nodetype == LYS_LIST) {
4034 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004035 "Unique statement \"%s\" refers to a leaf in nested list \"%s\".", uniques[v].str, parent->name);
Michal Vasko14654712020-02-06 08:35:21 +01004036 return LY_EVALID;
4037 }
4038 }
4039
Radek Krejci7af64242019-02-18 13:07:53 +01004040 /* check status */
4041 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Radek Krejci0f969882020-08-21 16:56:47 +02004042 (*key)->flags, (*key)->module, (*key)->name));
Radek Krejci7af64242019-02-18 13:07:53 +01004043
4044 /* mark leaf as unique */
4045 (*key)->flags |= LYS_UNIQUE;
4046
4047 /* next unique value in line */
4048 keystr = delim;
4049 }
4050 /* next unique definition */
4051 }
4052
4053 return LY_SUCCESS;
4054}
4055
4056/**
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004057 * @brief Compile parsed list node information.
4058 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004059 * @param[in] pnode Parsed list node.
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004060 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
4061 * is enriched with the list-specific information.
4062 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4063 */
4064static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004065lys_compile_node_list(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004066{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004067 struct lysp_node_list *list_p = (struct lysp_node_list *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004068 struct lysc_node_list *list = (struct lysc_node_list *)node;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004069 struct lysp_node *child_p;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004070 struct lysc_node_leaf *key, *prev_key = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004071 size_t len;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004072 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004073 const char *keystr, *delim;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004074 LY_ERR ret = LY_SUCCESS;
4075
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004076 list->min = list_p->min;
Radek Krejcife909632019-02-12 15:34:42 +01004077 if (list->min) {
4078 list->flags |= LYS_MAND_TRUE;
4079 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004080 list->max = list_p->max ? list_p->max : (uint32_t)-1;
4081
4082 LY_LIST_FOR(list_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004083 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004084 }
4085
Radek Krejcic71ac5b2019-09-10 15:34:22 +02004086 COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02004087 if (list_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01004088 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02004089 LY_CHECK_RET(ly_set_add(&ctx->xpath, list, 0, NULL));
Michal Vasko5d8756a2019-11-07 15:21:00 +01004090 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004091
4092 /* keys */
4093 if ((list->flags & LYS_CONFIG_W) && (!list_p->key || !list_p->key[0])) {
4094 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Missing key in list representing configuration data.");
4095 return LY_EVALID;
4096 }
4097
4098 /* find all the keys (must be direct children) */
4099 keystr = list_p->key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004100 if (!keystr) {
4101 /* keyless list */
4102 list->flags |= LYS_KEYLESS;
4103 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004104 while (keystr) {
4105 delim = strpbrk(keystr, " \t\n");
4106 if (delim) {
4107 len = delim - keystr;
4108 while (isspace(*delim)) {
4109 ++delim;
4110 }
4111 } else {
4112 len = strlen(keystr);
4113 }
4114
4115 /* key node must be present */
Michal Vasko22df3f02020-08-24 13:29:22 +02004116 key = (struct lysc_node_leaf *)lys_find_child(node, node->module, keystr, len, LYS_LEAF, LYS_GETNEXT_NOCHOICE | LYS_GETNEXT_NOSTATECHECK);
Radek Krejci0fe9b512019-07-26 17:51:05 +02004117 if (!(key)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004118 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004119 "The list's key \"%.*s\" not found.", len, keystr);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004120 return LY_EVALID;
4121 }
4122 /* keys must be unique */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004123 if (key->flags & LYS_KEY) {
4124 /* the node was already marked as a key */
4125 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004126 "Duplicated key identifier \"%.*s\".", len, keystr);
Radek Krejci0fe9b512019-07-26 17:51:05 +02004127 return LY_EVALID;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004128 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02004129
Michal Vasko22df3f02020-08-24 13:29:22 +02004130 lysc_update_path(ctx, (struct lysc_node *)list, key->name);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004131 /* key must have the same config flag as the list itself */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004132 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004133 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Key of the configuration list must not be status leaf.");
4134 return LY_EVALID;
4135 }
Radek Krejci0bcdaed2019-01-10 10:21:34 +01004136 if (ctx->mod_def->version < LYS_VERSION_1_1) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004137 /* YANG 1.0 denies key to be of empty type */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004138 if (key->type->basetype == LY_TYPE_EMPTY) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004139 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004140 "List's key cannot be of \"empty\" type until it is in YANG 1.1 module.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004141 return LY_EVALID;
4142 }
4143 } else {
4144 /* when and if-feature are illegal on list keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004145 if (key->when) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004146 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004147 "List's key must not have any \"when\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004148 return LY_EVALID;
4149 }
Radek Krejci0fe9b512019-07-26 17:51:05 +02004150 if (key->iffeatures) {
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004151 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004152 "List's key must not have any \"if-feature\" statement.");
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004153 return LY_EVALID;
4154 }
4155 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004156
4157 /* check status */
4158 LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
Michal Vasko69730152020-10-09 16:30:07 +02004159 key->flags, key->module, key->name));
Radek Krejci76b3e962018-12-14 17:01:25 +01004160
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004161 /* ignore default values of the key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004162 if (key->dflt) {
4163 key->dflt->realtype->plugin->free(ctx->ctx, key->dflt);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02004164 lysc_type_free(ctx->ctx, (struct lysc_type *)key->dflt->realtype);
Radek Krejci0fe9b512019-07-26 17:51:05 +02004165 free(key->dflt);
4166 key->dflt = NULL;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004167 }
4168 /* mark leaf as key */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004169 key->flags |= LYS_KEY;
4170
4171 /* move it to the correct position */
Michal Vasko69730152020-10-09 16:30:07 +02004172 if ((prev_key && ((struct lysc_node *)prev_key != key->prev)) || (!prev_key && key->prev->next)) {
Radek Krejci0fe9b512019-07-26 17:51:05 +02004173 /* fix links in closest previous siblings of the key */
4174 if (key->next) {
4175 key->next->prev = key->prev;
4176 } else {
4177 /* last child */
4178 list->child->prev = key->prev;
4179 }
4180 if (key->prev->next) {
4181 key->prev->next = key->next;
4182 }
4183 /* fix links in the key */
4184 if (prev_key) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004185 key->prev = (struct lysc_node *)prev_key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004186 key->next = prev_key->next;
4187 } else {
4188 key->prev = list->child->prev;
4189 key->next = list->child;
4190 }
4191 /* fix links in closes future siblings of the key */
4192 if (prev_key) {
4193 if (prev_key->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004194 prev_key->next->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004195 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02004196 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004197 }
Michal Vasko22df3f02020-08-24 13:29:22 +02004198 prev_key->next = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004199 } else {
Michal Vasko22df3f02020-08-24 13:29:22 +02004200 list->child->prev = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004201 }
4202 /* fix links in parent */
4203 if (!key->prev->next) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004204 list->child = (struct lysc_node *)key;
Radek Krejci0fe9b512019-07-26 17:51:05 +02004205 }
4206 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004207
4208 /* next key value */
Radek Krejci0fe9b512019-07-26 17:51:05 +02004209 prev_key = key;
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004210 keystr = delim;
Radek Krejci327de162019-06-14 12:52:07 +02004211 lysc_update_path(ctx, NULL, NULL);
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004212 }
4213
4214 /* uniques */
4215 if (list_p->uniques) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004216 LY_CHECK_RET(lys_compile_node_list_unique(ctx, list_p->uniques, list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004217 }
4218
Michal Vasko7f45cf22020-10-01 12:49:44 +02004219 COMPILE_OP_ARRAY_GOTO(ctx, list_p->actions, list->actions, node, u, lys_compile_action, 0, ret, done);
4220 COMPILE_OP_ARRAY_GOTO(ctx, list_p->notifs, list->notifs, node, u, lys_compile_notif, 0, ret, done);
4221
4222 /* checks */
4223 if (list->min > list->max) {
4224 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "List min-elements %u is bigger than max-elements %u.",
Michal Vasko69730152020-10-09 16:30:07 +02004225 list->min, list->max);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004226 return LY_EVALID;
4227 }
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004228
4229done:
4230 return ret;
4231}
4232
Radek Krejcib56c7502019-02-13 14:19:54 +01004233/**
4234 * @brief Do some checks and set the default choice's case.
4235 *
4236 * Selects (and stores into ::lysc_node_choice#dflt) the default case and set LYS_SET_DFLT flag on it.
4237 *
4238 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004239 * @param[in] dflt Name of the default branch. Can even contain a prefix.
Radek Krejcib56c7502019-02-13 14:19:54 +01004240 * @param[in,out] ch The compiled choice node, its dflt member is filled to point to the default case node of the choice.
4241 * @return LY_ERR value.
4242 */
Radek Krejci76b3e962018-12-14 17:01:25 +01004243static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004244lys_compile_node_choice_dflt(struct lysc_ctx *ctx, struct lysp_qname *dflt, struct lysc_node_choice *ch)
Radek Krejci76b3e962018-12-14 17:01:25 +01004245{
Michal Vasko22df3f02020-08-24 13:29:22 +02004246 struct lysc_node *iter, *node = (struct lysc_node *)ch;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004247 const struct lys_module *mod;
Radek Krejci76b3e962018-12-14 17:01:25 +01004248 const char *prefix = NULL, *name;
4249 size_t prefix_len = 0;
4250
4251 /* could use lys_parse_nodeid(), but it checks syntax which is already done in this case by the parsers */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004252 name = strchr(dflt->str, ':');
Radek Krejci76b3e962018-12-14 17:01:25 +01004253 if (name) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004254 prefix = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004255 prefix_len = name - prefix;
4256 ++name;
4257 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004258 name = dflt->str;
Radek Krejci76b3e962018-12-14 17:01:25 +01004259 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004260 if (prefix) {
4261 mod = ly_resolve_prefix(ctx->ctx, prefix, prefix_len, LY_PREF_SCHEMA, (void *)dflt->mod);
4262 if (!mod) {
4263 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4264 "Default case prefix \"%.*s\" not found in imports of \"%s\".", prefix_len, prefix, dflt->mod->name);
4265 return LY_EVALID;
4266 }
4267 } else {
4268 mod = node->module;
Radek Krejci76b3e962018-12-14 17:01:25 +01004269 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004270
4271 ch->dflt = (struct lysc_node_case *)lys_find_child(node, mod, name, 0, LYS_CASE, LYS_GETNEXT_NOSTATECHECK | LYS_GETNEXT_WITHCASE);
Radek Krejci76b3e962018-12-14 17:01:25 +01004272 if (!ch->dflt) {
4273 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004274 "Default case \"%s\" not found.", dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004275 return LY_EVALID;
4276 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004277
Radek Krejci76b3e962018-12-14 17:01:25 +01004278 /* no mandatory nodes directly under the default case */
4279 LY_LIST_FOR(ch->dflt->child, iter) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004280 if (iter->parent != (struct lysc_node *)ch->dflt) {
Radek Krejcife13da42019-02-15 14:51:01 +01004281 break;
4282 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004283 if (iter->flags & LYS_MAND_TRUE) {
4284 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004285 "Mandatory node \"%s\" under the default case \"%s\".", iter->name, dflt->str);
Radek Krejci76b3e962018-12-14 17:01:25 +01004286 return LY_EVALID;
4287 }
4288 }
Radek Krejci76b3e962018-12-14 17:01:25 +01004289
Michal Vasko7f45cf22020-10-01 12:49:44 +02004290 if (ch->flags & LYS_MAND_TRUE) {
4291 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid mandatory choice with a default case.");
Radek Krejciccd20f12019-02-15 14:12:27 +01004292 return LY_EVALID;
4293 }
4294
Michal Vasko7f45cf22020-10-01 12:49:44 +02004295 ch->dflt->flags |= LYS_SET_DFLT;
Radek Krejciccd20f12019-02-15 14:12:27 +01004296 return LY_SUCCESS;
4297}
4298
Radek Krejci9bb94eb2018-12-04 16:48:35 +01004299/**
Michal Vasko20424b42020-08-31 12:29:38 +02004300 * @brief Compile choice children.
4301 *
4302 * @param[in] ctx Compile context
4303 * @param[in] child_p Parsed choice children nodes.
4304 * @param[in] node Compiled choice node to compile and add children to.
4305 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4306 */
4307static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004308lys_compile_node_choice_child(struct lysc_ctx *ctx, struct lysp_node *child_p, struct lysc_node *node,
4309 struct ly_set *child_set)
Michal Vasko20424b42020-08-31 12:29:38 +02004310{
4311 LY_ERR ret = LY_SUCCESS;
Radek Krejci8f5fad22020-09-15 16:50:54 +02004312 struct lysp_node *child_p_next = child_p->next;
Michal Vasko20424b42020-08-31 12:29:38 +02004313 struct lysp_node_case *cs_p;
4314
4315 if (child_p->nodetype == LYS_CASE) {
4316 /* standard case under choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004317 ret = lys_compile_node(ctx, child_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004318 } else {
4319 /* we need the implicit case first, so create a fake parsed case */
4320 cs_p = calloc(1, sizeof *cs_p);
4321 cs_p->nodetype = LYS_CASE;
Radek Krejci87e25252020-09-15 13:28:31 +02004322 DUP_STRING_GOTO(ctx->ctx, child_p->name, cs_p->name, ret, free_fake_node);
Michal Vasko20424b42020-08-31 12:29:38 +02004323 cs_p->child = child_p;
4324
4325 /* make the child the only case child */
Michal Vasko20424b42020-08-31 12:29:38 +02004326 child_p->next = NULL;
4327
4328 /* compile it normally */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004329 ret = lys_compile_node(ctx, (struct lysp_node *)cs_p, node, 0, child_set);
Michal Vasko20424b42020-08-31 12:29:38 +02004330
Radek Krejci87e25252020-09-15 13:28:31 +02004331free_fake_node:
Michal Vasko20424b42020-08-31 12:29:38 +02004332 /* free the fake parsed node and correct pointers back */
4333 cs_p->child = NULL;
4334 lysp_node_free(ctx->ctx, (struct lysp_node *)cs_p);
Radek Krejci8f5fad22020-09-15 16:50:54 +02004335 child_p->next = child_p_next;
Michal Vasko20424b42020-08-31 12:29:38 +02004336 }
4337
4338 return ret;
4339}
4340
4341/**
Radek Krejci056d0a82018-12-06 16:57:25 +01004342 * @brief Compile parsed choice node information.
Michal Vasko20424b42020-08-31 12:29:38 +02004343 *
Radek Krejci056d0a82018-12-06 16:57:25 +01004344 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004345 * @param[in] pnode Parsed choice node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004346 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
Radek Krejci76b3e962018-12-14 17:01:25 +01004347 * is enriched with the choice-specific information.
Radek Krejci056d0a82018-12-06 16:57:25 +01004348 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4349 */
4350static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004351lys_compile_node_choice(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004352{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004353 struct lysp_node_choice *ch_p = (struct lysp_node_choice *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004354 struct lysc_node_choice *ch = (struct lysc_node_choice *)node;
Michal Vasko20424b42020-08-31 12:29:38 +02004355 struct lysp_node *child_p;
Radek Krejci056d0a82018-12-06 16:57:25 +01004356 LY_ERR ret = LY_SUCCESS;
4357
Michal Vasko20424b42020-08-31 12:29:38 +02004358 assert(node->nodetype == LYS_CHOICE);
4359
Radek Krejci056d0a82018-12-06 16:57:25 +01004360 LY_LIST_FOR(ch_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004361 LY_CHECK_RET(lys_compile_node_choice_child(ctx, child_p, node, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004362 }
4363
4364 /* default branch */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004365 if (ch_p->dflt.str) {
4366 LY_CHECK_RET(lys_compile_node_choice_dflt(ctx, &ch_p->dflt, ch));
Radek Krejcia9026eb2018-12-12 16:04:47 +01004367 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004368
Radek Krejci9800fb82018-12-13 14:26:23 +01004369 return ret;
4370}
4371
4372/**
4373 * @brief Compile parsed anydata or anyxml node information.
4374 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02004375 * @param[in] pnode Parsed anydata or anyxml node.
Radek Krejci9800fb82018-12-13 14:26:23 +01004376 * @param[in,out] node Pre-prepared structure from lys_compile_node() with filled generic node information
4377 * is enriched with the any-specific information.
4378 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
4379 */
4380static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004381lys_compile_node_any(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci9800fb82018-12-13 14:26:23 +01004382{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004383 struct lysp_node_anydata *any_p = (struct lysp_node_anydata *)pnode;
Michal Vasko22df3f02020-08-24 13:29:22 +02004384 struct lysc_node_anydata *any = (struct lysc_node_anydata *)node;
Radek Krejci1deb5be2020-08-26 16:43:36 +02004385 LY_ARRAY_COUNT_TYPE u;
Radek Krejci9800fb82018-12-13 14:26:23 +01004386 LY_ERR ret = LY_SUCCESS;
4387
Radek Krejcic71ac5b2019-09-10 15:34:22 +02004388 COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, u, lys_compile_must, ret, done);
Radek Krejci90d4e922020-10-12 15:55:33 +02004389 if (any_p->musts && !(ctx->options & LYS_COMPILE_GROUPING)) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01004390 /* do not check "must" semantics in a grouping */
Radek Krejciba03a5a2020-08-27 14:40:41 +02004391 ret = ly_set_add(&ctx->xpath, any, 0, NULL);
4392 LY_CHECK_GOTO(ret, done);
Michal Vasko5d8756a2019-11-07 15:21:00 +01004393 }
Radek Krejci9800fb82018-12-13 14:26:23 +01004394
4395 if (any->flags & LYS_CONFIG_W) {
Radek Krejci5c4ed7b2020-08-12 11:29:44 +02004396 LOGWRN(ctx->ctx, "Use of %s to define configuration data is not recommended. %s",
Michal Vasko69730152020-10-09 16:30:07 +02004397 ly_stmt2str(any->nodetype == LYS_ANYDATA ? LY_STMT_ANYDATA : LY_STMT_ANYXML), ctx->path);
Radek Krejci9800fb82018-12-13 14:26:23 +01004398 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004399done:
4400 return ret;
4401}
4402
Radek Krejcib56c7502019-02-13 14:19:54 +01004403/**
Michal Vasko795b3752020-07-13 15:24:27 +02004404 * @brief Connect the node into the siblings list and check its name uniqueness. Also,
4405 * keep specific order of augments targetting the same node.
Radek Krejci056d0a82018-12-06 16:57:25 +01004406 *
4407 * @param[in] ctx Compile context
4408 * @param[in] parent Parent node holding the children list, in case of node from a choice's case,
4409 * the choice itself is expected instead of a specific case node.
4410 * @param[in] node Schema node to connect into the list.
4411 * @return LY_ERR value - LY_SUCCESS or LY_EEXIST.
Radek Krejci1c54f462020-05-12 17:25:34 +02004412 * In case of LY_EEXIST, the node is actually kept in the tree, so do not free it directly.
Radek Krejci056d0a82018-12-06 16:57:25 +01004413 */
4414static LY_ERR
Radek Krejciec4da802019-05-02 13:02:41 +02004415lys_compile_node_connect(struct lysc_ctx *ctx, struct lysc_node *parent, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004416{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004417 struct lysc_node **children, *anchor = NULL;
4418 int insert_after = 0;
Radek Krejci056d0a82018-12-06 16:57:25 +01004419
Michal Vasko20424b42020-08-31 12:29:38 +02004420 node->parent = parent;
4421
4422 if (parent) {
4423 if (parent->nodetype == LYS_CHOICE) {
4424 assert(node->nodetype == LYS_CASE);
4425 children = (struct lysc_node **)&((struct lysc_node_choice *)parent)->cases;
4426 } else {
4427 children = lysc_node_children_p(parent, ctx->options);
4428 }
4429 assert(children);
4430
Radek Krejci056d0a82018-12-06 16:57:25 +01004431 if (!(*children)) {
4432 /* first child */
4433 *children = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004434 } else if (node->flags & LYS_KEY) {
4435 /* special handling of adding keys */
4436 assert(node->module == parent->module);
4437 anchor = *children;
4438 if (anchor->flags & LYS_KEY) {
4439 while ((anchor->flags & LYS_KEY) && anchor->next) {
4440 anchor = anchor->next;
4441 }
4442 /* insert after the last key */
4443 insert_after = 1;
4444 } /* else insert before anchor (at the beginning) */
4445 } else if ((*children)->prev->module == node->module) {
4446 /* last child is from the same module, keep the order and insert at the end */
4447 anchor = (*children)->prev;
4448 insert_after = 1;
4449 } else if (parent->module == node->module) {
4450 /* adding module child after some augments were connected */
4451 for (anchor = *children; anchor->module == node->module; anchor = anchor->next) {}
4452 } else {
4453 /* some augments are already connected and we are connecting new ones,
4454 * keep module name order and insert the node into the children list */
4455 anchor = *children;
4456 do {
4457 anchor = anchor->prev;
Michal Vasko795b3752020-07-13 15:24:27 +02004458
Michal Vasko7f45cf22020-10-01 12:49:44 +02004459 /* check that we have not found the last augment node from our module or
4460 * the first augment node from a "smaller" module or
4461 * the first node from a local module */
Michal Vasko69730152020-10-09 16:30:07 +02004462 if ((anchor->module == node->module) || (strcmp(anchor->module->name, node->module->name) < 0) ||
4463 (anchor->module == parent->module)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004464 /* insert after */
4465 insert_after = 1;
4466 break;
4467 }
4468
4469 /* we have traversed all the nodes, insert before anchor (as the first node) */
4470 } while (anchor->prev->next);
4471 }
4472
4473 /* insert */
4474 if (anchor) {
4475 if (insert_after) {
4476 node->next = anchor->next;
4477 node->prev = anchor;
4478 anchor->next = node;
4479 if (node->next) {
4480 /* middle node */
4481 node->next->prev = node;
4482 } else {
4483 /* last node */
4484 (*children)->prev = node;
4485 }
Michal Vasko795b3752020-07-13 15:24:27 +02004486 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004487 node->next = anchor;
4488 node->prev = anchor->prev;
4489 anchor->prev = node;
4490 if (anchor == *children) {
4491 /* first node */
4492 *children = node;
4493 } else {
4494 /* middle node */
4495 node->prev->next = node;
4496 }
Michal Vasko795b3752020-07-13 15:24:27 +02004497 }
Michal Vasko20424b42020-08-31 12:29:38 +02004498 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004499
Michal Vasko20424b42020-08-31 12:29:38 +02004500 /* check the name uniqueness (even for an only child, it may be in case) */
4501 if (lys_compile_node_uniqness(ctx, parent, node->name, node)) {
4502 return LY_EEXIST;
4503 }
4504 } else {
4505 /* top-level element */
4506 if (!ctx->mod->compiled->data) {
4507 ctx->mod->compiled->data = node;
4508 } else {
4509 /* insert at the end of the module's top-level nodes list */
4510 ctx->mod->compiled->data->prev->next = node;
4511 node->prev = ctx->mod->compiled->data->prev;
4512 ctx->mod->compiled->data->prev = node;
4513 }
4514
4515 /* check the name uniqueness on top-level */
4516 if (lys_compile_node_uniqness(ctx, NULL, node->name, node)) {
4517 return LY_EEXIST;
Radek Krejci056d0a82018-12-06 16:57:25 +01004518 }
4519 }
Michal Vasko20424b42020-08-31 12:29:38 +02004520
Radek Krejci056d0a82018-12-06 16:57:25 +01004521 return LY_SUCCESS;
4522}
4523
Radek Krejci95710c92019-02-11 15:49:55 +01004524/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004525 * @brief Prepare the case structure in choice node for the new data node.
4526 *
4527 * It is able to handle implicit as well as explicit cases and the situation when the case has multiple data nodes and the case was already
4528 * created in the choice when the first child was processed.
4529 *
4530 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004531 * @param[in] pnode Node image from the parsed tree. If the case is explicit, it is the LYS_CASE node, but in case of implicit case,
Radek Krejci39424802020-08-12 09:31:00 +02004532 * it is the LYS_CHOICE, LYS_AUGMENT or LYS_GROUPING node.
Radek Krejcib56c7502019-02-13 14:19:54 +01004533 * @param[in] ch The compiled choice structure where the new case structures are created (if needed).
4534 * @param[in] child The new data node being part of a case (no matter if explicit or implicit).
4535 * @return The case structure where the child node belongs to, NULL in case of error. Note that the child is not connected into the siblings list,
4536 * it is linked from the case structure only in case it is its first child.
Radek Krejci95710c92019-02-11 15:49:55 +01004537 */
Michal Vasko20424b42020-08-31 12:29:38 +02004538static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004539lys_compile_node_case(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *node)
Radek Krejci056d0a82018-12-06 16:57:25 +01004540{
Michal Vasko20424b42020-08-31 12:29:38 +02004541 struct lysp_node *child_p;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004542 struct lysp_node_case *cs_p = (struct lysp_node_case *)pnode;
Radek Krejci056d0a82018-12-06 16:57:25 +01004543
Michal Vasko7f45cf22020-10-01 12:49:44 +02004544 if (pnode->nodetype & (LYS_CHOICE | LYS_AUGMENT | LYS_GROUPING)) {
Radek Krejci056d0a82018-12-06 16:57:25 +01004545 /* we have to add an implicit case node into the parent choice */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004546 } else if (pnode->nodetype == LYS_CASE) {
Michal Vasko20424b42020-08-31 12:29:38 +02004547 /* explicit parent case */
4548 LY_LIST_FOR(cs_p->child, child_p) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004549 LY_CHECK_RET(lys_compile_node(ctx, child_p, node, 0, NULL));
Radek Krejci056d0a82018-12-06 16:57:25 +01004550 }
Radek Krejci95710c92019-02-11 15:49:55 +01004551 } else {
Michal Vasko20424b42020-08-31 12:29:38 +02004552 LOGINT_RET(ctx->ctx);
Radek Krejci056d0a82018-12-06 16:57:25 +01004553 }
Radek Krejci056d0a82018-12-06 16:57:25 +01004554
Michal Vasko20424b42020-08-31 12:29:38 +02004555 return LY_SUCCESS;
Radek Krejci056d0a82018-12-06 16:57:25 +01004556}
4557
Radek Krejcib56c7502019-02-13 14:19:54 +01004558/**
Radek Krejcib56c7502019-02-13 14:19:54 +01004559 * @brief Set LYS_MAND_TRUE flag for the non-presence container parents.
4560 *
4561 * A non-presence container is mandatory in case it has at least one mandatory children. This function propagate
4562 * the flag to such parents from a mandatory children.
4563 *
4564 * @param[in] parent A schema node to be examined if the mandatory child make it also mandatory.
4565 * @param[in] add Flag to distinguish adding the mandatory flag (new mandatory children appeared) or removing the flag
4566 * (mandatory children was removed).
4567 */
Radek Krejci1deb5be2020-08-26 16:43:36 +02004568static void
Radek Krejci857189e2020-09-01 13:26:36 +02004569lys_compile_mandatory_parents(struct lysc_node *parent, ly_bool add)
Radek Krejcife909632019-02-12 15:34:42 +01004570{
4571 struct lysc_node *iter;
4572
4573 if (add) { /* set flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004574 for ( ; parent && parent->nodetype == LYS_CONTAINER && !(parent->flags & LYS_MAND_TRUE) && !(parent->flags & LYS_PRESENCE);
Radek Krejcife909632019-02-12 15:34:42 +01004575 parent = parent->parent) {
4576 parent->flags |= LYS_MAND_TRUE;
4577 }
4578 } else { /* unset flag */
Michal Vaskod989ba02020-08-24 10:59:24 +02004579 for ( ; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
Michal Vasko22df3f02020-08-24 13:29:22 +02004580 for (iter = (struct lysc_node *)lysc_node_children(parent, 0); iter; iter = iter->next) {
Radek Krejcif1421c22019-02-19 13:05:20 +01004581 if (iter->flags & LYS_MAND_TRUE) {
Radek Krejcife909632019-02-12 15:34:42 +01004582 /* there is another mandatory node */
4583 return;
4584 }
4585 }
4586 /* unset mandatory flag - there is no mandatory children in the non-presence container */
4587 parent->flags &= ~LYS_MAND_TRUE;
4588 }
4589 }
4590}
4591
Radek Krejci056d0a82018-12-06 16:57:25 +01004592/**
Radek Krejci3641f562019-02-13 15:38:40 +01004593 * @brief Compile the parsed augment connecting it into its target.
4594 *
4595 * It is expected that all the data referenced in path are present - augments are ordered so that augment B
4596 * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path
4597 * are already implemented and compiled.
4598 *
4599 * @param[in] ctx Compile context.
4600 * @param[in] aug_p Parsed augment to compile.
Michal Vasko7f45cf22020-10-01 12:49:44 +02004601 * @param[in] target Target node of the augment.
Radek Krejci3641f562019-02-13 15:38:40 +01004602 * @return LY_SUCCESS on success.
4603 * @return LY_EVALID on failure.
4604 */
Michal Vasko7f45cf22020-10-01 12:49:44 +02004605static LY_ERR
4606lys_compile_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, struct lysc_node *target)
Radek Krejci3641f562019-02-13 15:38:40 +01004607{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004608 LY_ERR ret = LY_SUCCESS;
4609 struct lysp_node *pnode;
Radek Krejci3641f562019-02-13 15:38:40 +01004610 struct lysc_node *node;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004611 struct lysc_when *when_shared = NULL;
4612 struct lysc_action **actions;
4613 struct lysc_notif **notifs;
Radek Krejci857189e2020-09-01 13:26:36 +02004614 ly_bool allow_mandatory = 0;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004615 LY_ARRAY_COUNT_TYPE u;
4616 struct ly_set child_set = {0};
4617 uint32_t i;
Radek Krejci3641f562019-02-13 15:38:40 +01004618
Michal Vasko7f45cf22020-10-01 12:49:44 +02004619 if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) {
4620 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4621 "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.",
4622 aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype));
4623 ret = LY_EVALID;
4624 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004625 }
4626
4627 /* check for mandatory nodes
4628 * - new cases augmenting some choice can have mandatory nodes
4629 * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement
4630 */
Michal Vasko69730152020-10-09 16:30:07 +02004631 if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->mod == target->module)) {
Radek Krejci3641f562019-02-13 15:38:40 +01004632 allow_mandatory = 1;
4633 }
4634
Michal Vasko7f45cf22020-10-01 12:49:44 +02004635 LY_LIST_FOR(aug_p->child, pnode) {
Radek Krejci3641f562019-02-13 15:38:40 +01004636 /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */
Michal Vasko69730152020-10-09 16:30:07 +02004637 if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) ||
4638 ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) ||
4639 ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) {
Radek Krejci3641f562019-02-13 15:38:40 +01004640 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004641 "Invalid augment of %s node which is not allowed to contain %s node \"%s\".",
4642 lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004643 ret = LY_EVALID;
4644 goto cleanup;
Radek Krejci3641f562019-02-13 15:38:40 +01004645 }
4646
4647 /* compile the children */
Michal Vasko20424b42020-08-31 12:29:38 +02004648 if (target->nodetype == LYS_CHOICE) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004649 LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004650 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004651 LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004652 }
4653
Michal Vasko7f45cf22020-10-01 12:49:44 +02004654 /* since the augment node is not present in the compiled tree, we need to pass some of its
4655 * statements to all its children */
4656 for (i = 0; i < child_set.count; ++i) {
4657 node = child_set.snodes[i];
4658 if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) {
4659 node->flags &= ~LYS_MAND_TRUE;
4660 lys_compile_mandatory_parents(target, 0);
4661 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004662 "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004663 ret = LY_EVALID;
4664 goto cleanup;
Radek Krejci7c7783d2020-04-08 15:34:39 +02004665 }
Radek Krejci3641f562019-02-13 15:38:40 +01004666
Michal Vasko7f45cf22020-10-01 12:49:44 +02004667 if (aug_p->when) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004668 /* pass augment's when to all the children */
4669 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target), node, &when_shared);
4670 LY_CHECK_GOTO(ret, cleanup);
Radek Krejci3641f562019-02-13 15:38:40 +01004671 }
4672 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004673 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004674 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004675
4676 switch (target->nodetype) {
4677 case LYS_CONTAINER:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004678 actions = &((struct lysc_node_container *)target)->actions;
4679 notifs = &((struct lysc_node_container *)target)->notifs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004680 break;
4681 case LYS_LIST:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004682 actions = &((struct lysc_node_list *)target)->actions;
4683 notifs = &((struct lysc_node_list *)target)->notifs;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004684 break;
4685 default:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004686 actions = NULL;
4687 notifs = NULL;
4688 break;
4689 }
4690
4691 if (aug_p->actions) {
4692 if (!actions) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004693 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004694 "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".",
4695 lys_nodetype2str(target->nodetype), aug_p->actions[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004696 ret = LY_EVALID;
4697 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004698 }
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004699
4700 /* compile actions into the target */
4701 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->actions, *actions, target, u, lys_compile_action, 0, ret, cleanup);
4702
4703 if (aug_p->when) {
4704 /* inherit when */
4705 LY_ARRAY_FOR(*actions, u) {
4706 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
4707 (struct lysc_node *)&(*actions)[u], &when_shared);
4708 LY_CHECK_GOTO(ret, cleanup);
4709 }
4710 }
4711 }
4712 if (aug_p->notifs) {
4713 if (!notifs) {
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004714 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004715 "Invalid augment of %s node which is not allowed to contain notification node \"%s\".",
4716 lys_nodetype2str(target->nodetype), aug_p->notifs[0].name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004717 ret = LY_EVALID;
4718 goto cleanup;
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004719 }
Michal Vaskoceab6dd2020-10-09 16:53:36 +02004720
4721 /* compile notifications into the target */
4722 COMPILE_OP_ARRAY_GOTO(ctx, aug_p->notifs, *notifs, target, u, lys_compile_notif, 0, ret, cleanup);
4723
4724 if (aug_p->when) {
4725 /* inherit when */
4726 LY_ARRAY_FOR(*notifs, u) {
4727 ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_xpath_context(target),
4728 (struct lysc_node *)&(*notifs)[u], &when_shared);
4729 LY_CHECK_GOTO(ret, cleanup);
4730 }
4731 }
Radek Krejci6eeb58f2019-02-22 16:29:37 +01004732 }
Radek Krejci3641f562019-02-13 15:38:40 +01004733
Michal Vasko7f45cf22020-10-01 12:49:44 +02004734cleanup:
4735 ly_set_erase(&child_set, NULL);
Radek Krejci3641f562019-02-13 15:38:40 +01004736 return ret;
4737}
4738
4739/**
Michal Vasko601ddb32020-08-31 16:25:35 +02004740 * @brief Find grouping for a uses.
Radek Krejcie86bf772018-12-14 11:39:53 +01004741 *
Michal Vasko601ddb32020-08-31 16:25:35 +02004742 * @param[in] ctx Compile context.
4743 * @param[in] uses_p Parsed uses node.
4744 * @param[out] gpr_p Found grouping on success.
4745 * @param[out] grp_mod Module of @p grp_p on success.
4746 * @return LY_ERR value.
Radek Krejcie86bf772018-12-14 11:39:53 +01004747 */
4748static LY_ERR
Michal Vasko601ddb32020-08-31 16:25:35 +02004749lys_compile_uses_find_grouping(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysp_grp **grp_p,
4750 struct lys_module **grp_mod)
Radek Krejcie86bf772018-12-14 11:39:53 +01004751{
Michal Vasko7f45cf22020-10-01 12:49:44 +02004752 struct lysp_node *pnode;
Michal Vasko601ddb32020-08-31 16:25:35 +02004753 struct lysp_grp *grp;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02004754 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci857189e2020-09-01 13:26:36 +02004755 ly_bool found = 0;
Radek Krejcie86bf772018-12-14 11:39:53 +01004756 const char *id, *name, *prefix;
4757 size_t prefix_len, name_len;
Michal Vasko601ddb32020-08-31 16:25:35 +02004758 struct lys_module *mod;
4759
4760 *grp_p = NULL;
4761 *grp_mod = NULL;
Radek Krejcie86bf772018-12-14 11:39:53 +01004762
4763 /* search for the grouping definition */
Radek Krejcie86bf772018-12-14 11:39:53 +01004764 id = uses_p->name;
Radek Krejcib4a4a272019-06-10 12:44:52 +02004765 LY_CHECK_RET(ly_parse_nodeid(&id, &prefix, &prefix_len, &name, &name_len), LY_EVALID);
Radek Krejcie86bf772018-12-14 11:39:53 +01004766 if (prefix) {
4767 mod = lys_module_find_prefix(ctx->mod_def, prefix, prefix_len);
4768 if (!mod) {
4769 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02004770 "Invalid prefix used for grouping reference.", uses_p->name);
Radek Krejcie86bf772018-12-14 11:39:53 +01004771 return LY_EVALID;
4772 }
4773 } else {
4774 mod = ctx->mod_def;
4775 }
4776 if (mod == ctx->mod_def) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02004777 for (pnode = uses_p->parent; !found && pnode; pnode = pnode->parent) {
4778 grp = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcie86bf772018-12-14 11:39:53 +01004779 LY_ARRAY_FOR(grp, u) {
4780 if (!strcmp(grp[u].name, name)) {
4781 grp = &grp[u];
4782 found = 1;
4783 break;
4784 }
4785 }
4786 }
4787 }
4788 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004789 /* search in top-level groupings of the main module ... */
Radek Krejcie86bf772018-12-14 11:39:53 +01004790 grp = mod->parsed->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004791 LY_ARRAY_FOR(grp, u) {
4792 if (!strcmp(grp[u].name, name)) {
4793 grp = &grp[u];
4794 found = 1;
4795 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004796 }
4797 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004798 if (!found) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004799 /* ... and all the submodules */
Michal Vasko601ddb32020-08-31 16:25:35 +02004800 LY_ARRAY_FOR(mod->parsed->includes, u) {
Radek Krejci76b3e962018-12-14 17:01:25 +01004801 grp = mod->parsed->includes[u].submodule->groupings;
Michal Vasko601ddb32020-08-31 16:25:35 +02004802 LY_ARRAY_FOR(grp, v) {
4803 if (!strcmp(grp[v].name, name)) {
4804 grp = &grp[v];
4805 found = 1;
4806 break;
Radek Krejci76b3e962018-12-14 17:01:25 +01004807 }
4808 }
Michal Vasko601ddb32020-08-31 16:25:35 +02004809 if (found) {
4810 break;
4811 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004812 }
4813 }
4814 }
4815 if (!found) {
4816 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02004817 "Grouping \"%s\" referenced by a uses statement not found.", uses_p->name);
Radek Krejcie86bf772018-12-14 11:39:53 +01004818 return LY_EVALID;
4819 }
4820
Radek Krejci90d4e922020-10-12 15:55:33 +02004821 if (!(ctx->options & LYS_COMPILE_GROUPING)) {
Radek Krejcif2de0ed2019-05-02 14:13:18 +02004822 /* remember that the grouping is instantiated to avoid its standalone validation */
4823 grp->flags |= LYS_USED_GRP;
4824 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004825
Michal Vasko601ddb32020-08-31 16:25:35 +02004826 *grp_p = grp;
4827 *grp_mod = mod;
4828 return LY_SUCCESS;
4829}
Radek Krejcie86bf772018-12-14 11:39:53 +01004830
Michal Vasko7f45cf22020-10-01 12:49:44 +02004831static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest,
4832 size_t nametest_len, const struct lys_module *local_mod, const char **name, size_t *name_len);
4833
Michal Vasko601ddb32020-08-31 16:25:35 +02004834static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02004835lys_nodeid_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct lys_module **target_mod,
4836 struct lyxp_expr **expr)
Michal Vasko601ddb32020-08-31 16:25:35 +02004837{
Michal Vasko601ddb32020-08-31 16:25:35 +02004838 LY_ERR ret = LY_SUCCESS;
Michal Vasko7f45cf22020-10-01 12:49:44 +02004839 struct lyxp_expr *e = NULL;
4840 struct lys_module *tmod = NULL, *mod;
4841 const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid";
4842 uint32_t i;
Radek Krejcie86bf772018-12-14 11:39:53 +01004843
Michal Vasko7f45cf22020-10-01 12:49:44 +02004844 /* parse */
4845 ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e);
4846 if (ret) {
4847 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.",
4848 nodeid_type, nodeid);
4849 ret = LY_EVALID;
4850 goto cleanup;
Radek Krejci01342af2019-01-03 15:18:08 +01004851 }
Radek Krejcie86bf772018-12-14 11:39:53 +01004852
Michal Vasko7f45cf22020-10-01 12:49:44 +02004853 if (abs) {
4854 /* absolute schema nodeid */
4855 i = 0;
4856 } else {
4857 /* descendant schema nodeid */
4858 if (e->tokens[0] != LYXP_TOKEN_NAMETEST) {
4859 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4860 nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]);
Michal Vasko20424b42020-08-31 12:29:38 +02004861 ret = LY_EVALID;
Radek Krejcifc11bd72019-04-11 16:00:05 +02004862 goto cleanup;
Radek Krejcif2271f12019-01-07 16:42:23 +01004863 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004864 i = 1;
4865 }
Radek Krejcif2271f12019-01-07 16:42:23 +01004866
Michal Vasko7f45cf22020-10-01 12:49:44 +02004867 /* check all the tokens */
4868 for ( ; i < e->used; i += 2) {
4869 if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) {
4870 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".",
4871 nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]);
4872 ret = LY_EVALID;
4873 goto cleanup;
4874 } else if (e->used == i + 1) {
4875 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
4876 "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr);
4877 ret = LY_EVALID;
4878 goto cleanup;
4879 } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) {
4880 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".",
4881 nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]);
4882 ret = LY_EVALID;
4883 goto cleanup;
4884 } else if (abs) {
4885 mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1],
4886 e->tok_len[i + 1], ctx->mod_def, NULL, NULL);
4887 LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup);
4888
4889 /* only keep the first module */
4890 if (!tmod) {
4891 tmod = mod;
Radek Krejcif2271f12019-01-07 16:42:23 +01004892 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02004893
4894 /* all the modules must be implemented */
4895 if (!mod->implemented) {
Michal Vasko89b5c072020-10-06 13:52:44 +02004896 ret = lys_set_implemented(mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004897 LY_CHECK_GOTO(ret, cleanup);
4898 }
4899 }
4900 }
4901
4902cleanup:
4903 if (ret || !expr) {
4904 lyxp_expr_free(ctx->ctx, e);
4905 e = NULL;
4906 }
4907 if (expr) {
4908 *expr = ret ? NULL : e;
4909 }
4910 if (target_mod) {
4911 *target_mod = ret ? NULL : tmod;
4912 }
4913 return ret;
4914}
4915
4916/**
4917 * @brief Check whether 2 schema nodeids match.
4918 *
4919 * @param[in] ctx libyang context.
4920 * @param[in] exp1 First schema nodeid.
4921 * @param[in] exp1_mod Module of @p exp1 nodes without any prefix.
4922 * @param[in] exp2 Second schema nodeid.
4923 * @param[in] exp2_mod Module of @p exp2 nodes without any prefix.
4924 * @return Whether the schema nodeids match or not.
4925 */
4926static ly_bool
4927lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lys_module *exp1_mod,
4928 const struct lyxp_expr *exp2, const struct lys_module *exp2_mod)
4929{
4930 uint32_t i;
4931 const struct lys_module *mod1, *mod2;
4932 const char *name1, *name2;
4933 size_t name1_len, name2_len;
4934
4935 if (exp1->used != exp2->used) {
4936 return 0;
4937 }
4938
4939 for (i = 0; i < exp1->used; ++i) {
4940 assert(exp1->tokens[i] == exp2->tokens[i]);
4941
4942 if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) {
4943 /* check modules of all the nodes in the node ID */
4944 mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_mod,
4945 &name1, &name1_len);
4946 assert(mod1);
4947 mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_mod,
4948 &name2, &name2_len);
4949 assert(mod2);
4950
4951 /* compare modules */
4952 if (mod1 != mod2) {
4953 return 0;
4954 }
4955
4956 /* compare names */
4957 if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) {
4958 return 0;
4959 }
4960 }
4961 }
4962
4963 return 1;
4964}
4965
4966/**
4967 * @brief Prepare any uses augments and refines in the context to be applied during uses descendant node compilation.
4968 *
4969 * @param[in] ctx Compile context.
4970 * @param[in] uses_p Parsed uses structure with augments and refines.
4971 * @param[in] ctx_node Context node of @p uses_p meaning its first data definiition parent.
4972 * @return LY_ERR value.
4973 */
4974static LY_ERR
4975lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node)
4976{
4977 LY_ERR ret = LY_SUCCESS;
4978 LY_ARRAY_COUNT_TYPE u;
4979 struct lyxp_expr *exp = NULL;
4980 struct lysc_augment *aug;
4981 struct lysc_refine *rfn;
4982 struct lysp_refine **new_rfn;
4983 uint32_t i;
4984
4985 LY_ARRAY_FOR(uses_p->augments, u) {
4986 lysc_update_path(ctx, NULL, "{augment}");
4987 lysc_update_path(ctx, NULL, uses_p->augments[u].nodeid);
4988
4989 /* parse the nodeid */
4990 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->augments[u].nodeid, 0, NULL, &exp), cleanup);
4991
4992 /* allocate new compiled augment and store it in the set */
4993 aug = calloc(1, sizeof *aug);
4994 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02004995 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02004996
4997 aug->nodeid = exp;
4998 exp = NULL;
4999 aug->nodeid_ctx_node = ctx_node;
5000 aug->aug_p = &uses_p->augments[u];
5001
5002 lysc_update_path(ctx, NULL, NULL);
5003 lysc_update_path(ctx, NULL, NULL);
5004 }
5005
5006 LY_ARRAY_FOR(uses_p->refines, u) {
5007 lysc_update_path(ctx, NULL, "{refine}");
5008 lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid);
5009
5010 /* parse the nodeid */
5011 LY_CHECK_GOTO(ret = lys_nodeid_check(ctx, uses_p->refines[u].nodeid, 0, NULL, &exp), cleanup);
5012
5013 /* try to find the node in already compiled refines */
5014 rfn = NULL;
5015 for (i = 0; i < ctx->uses_rfns.count; ++i) {
5016 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->mod_def, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid,
5017 ctx->mod_def)) {
5018 rfn = ctx->uses_rfns.objs[i];
5019 break;
Radek Krejcif2271f12019-01-07 16:42:23 +01005020 }
5021 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005022
Michal Vasko7f45cf22020-10-01 12:49:44 +02005023 if (!rfn) {
5024 /* allocate new compiled refine */
5025 rfn = calloc(1, sizeof *rfn);
5026 LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02005027 LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005028
5029 rfn->nodeid = exp;
5030 exp = NULL;
5031 rfn->nodeid_ctx_node = ctx_node;
5032 } else {
5033 /* just free exp */
5034 lyxp_expr_free(ctx->ctx, exp);
5035 exp = NULL;
5036 }
5037
5038 /* add new parsed refine structure */
5039 LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup);
5040 *new_rfn = &uses_p->refines[u];
5041
5042 lysc_update_path(ctx, NULL, NULL);
Michal Vasko601ddb32020-08-31 16:25:35 +02005043 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif2271f12019-01-07 16:42:23 +01005044 }
5045
Michal Vasko601ddb32020-08-31 16:25:35 +02005046cleanup:
Michal Vasko7f45cf22020-10-01 12:49:44 +02005047 lyxp_expr_free(ctx->ctx, exp);
Michal Vasko601ddb32020-08-31 16:25:35 +02005048 return ret;
5049}
5050
5051/**
5052 * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
5053 * If present, also apply uses's modificators.
5054 *
5055 * @param[in] ctx Compile context
5056 * @param[in] uses_p Parsed uses schema node.
5057 * @param[in] parent Compiled parent node where the content of the referenced grouping is supposed to be connected. It is
5058 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
5059 * the compile context.
5060 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
5061 */
5062static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02005063lys_compile_uses(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, struct lysc_node *parent, struct ly_set *child_set)
Michal Vasko601ddb32020-08-31 16:25:35 +02005064{
Michal Vasko7f45cf22020-10-01 12:49:44 +02005065 struct lysp_node *pnode;
5066 struct lysc_node *child;
Michal Vasko601ddb32020-08-31 16:25:35 +02005067 struct lysp_grp *grp = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005068 uint32_t i, grp_stack_count;
Michal Vaskoaf702452020-10-02 09:02:55 +02005069 struct lys_module *grp_mod, *mod_old = ctx->mod_def;
Michal Vasko601ddb32020-08-31 16:25:35 +02005070 LY_ERR ret = LY_SUCCESS;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005071 struct lysc_when *when_shared = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005072 LY_ARRAY_COUNT_TYPE u;
Michal Vasko601ddb32020-08-31 16:25:35 +02005073 struct lysc_notif **notifs = NULL;
5074 struct lysc_action **actions = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005075 struct ly_set uses_child_set = {0};
Michal Vasko601ddb32020-08-31 16:25:35 +02005076
5077 /* find the referenced grouping */
5078 LY_CHECK_RET(lys_compile_uses_find_grouping(ctx, uses_p, &grp, &grp_mod));
5079
5080 /* grouping must not reference themselves - stack in ctx maintains list of groupings currently being applied */
5081 grp_stack_count = ctx->groupings.count;
5082 LY_CHECK_RET(ly_set_add(&ctx->groupings, (void *)grp, 0, NULL));
5083 if (grp_stack_count == ctx->groupings.count) {
5084 /* the target grouping is already in the stack, so we are already inside it -> circular dependency */
5085 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005086 "Grouping \"%s\" references itself through a uses statement.", grp->name);
Michal Vasko601ddb32020-08-31 16:25:35 +02005087 return LY_EVALID;
5088 }
5089
Michal Vasko7f45cf22020-10-01 12:49:44 +02005090 /* check status */
5091 ret = lysc_check_status(ctx, uses_p->flags, ctx->mod_def, uses_p->name, grp->flags, grp_mod, grp->name);
5092 LY_CHECK_GOTO(ret, cleanup);
5093
5094 /* compile any augments and refines so they can be applied during the grouping nodes compilation */
5095 ret = lys_precompile_uses_augments_refines(ctx, uses_p, parent);
5096 LY_CHECK_GOTO(ret, cleanup);
5097
Michal Vasko601ddb32020-08-31 16:25:35 +02005098 /* switch context's mod_def */
Michal Vasko601ddb32020-08-31 16:25:35 +02005099 ctx->mod_def = grp_mod;
5100
Michal Vasko601ddb32020-08-31 16:25:35 +02005101 /* compile data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005102 LY_LIST_FOR(grp->data, pnode) {
Michal Vasko601ddb32020-08-31 16:25:35 +02005103 /* 0x3 in uses_status is a special bits combination to be able to detect status flags from uses */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005104 ret = lys_compile_node(ctx, pnode, parent, (uses_p->flags & LYS_STATUS_MASK) | 0x3, &uses_child_set);
Michal Vasko601ddb32020-08-31 16:25:35 +02005105 LY_CHECK_GOTO(ret, cleanup);
5106 }
5107
Michal Vasko7f45cf22020-10-01 12:49:44 +02005108 if (child_set) {
5109 /* add these children to our compiled child_set as well since uses is a schema-only node */
Radek Krejci3d92e442020-10-12 12:48:13 +02005110 LY_CHECK_GOTO(ret = ly_set_merge(child_set, &uses_child_set, 1, NULL), cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02005111 }
5112
Michal Vasko7f45cf22020-10-01 12:49:44 +02005113 if (uses_p->when) {
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005114 /* pass uses's when to all the data children */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005115 for (i = 0; i < uses_child_set.count; ++i) {
5116 child = uses_child_set.snodes[i];
5117
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005118 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent), child, &when_shared);
5119 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko601ddb32020-08-31 16:25:35 +02005120 }
5121 }
5122
5123 /* compile actions */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005124 if (grp->actions) {
5125 actions = parent ? lysc_node_actions_p(parent) : &ctx->mod->compiled->rpcs;
5126 if (!actions) {
5127 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
Michal Vasko69730152020-10-09 16:30:07 +02005128 grp->actions[0].name, lys_nodetype2str(grp->actions[0].nodetype), parent->name,
5129 lys_nodetype2str(parent->nodetype));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005130 ret = LY_EVALID;
5131 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02005132 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005133 COMPILE_OP_ARRAY_GOTO(ctx, grp->actions, *actions, parent, u, lys_compile_action, 0, ret, cleanup);
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005134
5135 if (uses_p->when) {
5136 /* inherit when */
5137 LY_ARRAY_FOR(*actions, u) {
5138 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent),
5139 (struct lysc_node *)&(*actions)[u], &when_shared);
5140 LY_CHECK_GOTO(ret, cleanup);
5141 }
5142 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005143 }
5144
5145 /* compile notifications */
Michal Vasko7f45cf22020-10-01 12:49:44 +02005146 if (grp->notifs) {
5147 notifs = parent ? lysc_node_notifs_p(parent) : &ctx->mod->compiled->notifs;
5148 if (!notifs) {
5149 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid child %s \"%s\" of uses parent %s \"%s\" node.",
Michal Vasko69730152020-10-09 16:30:07 +02005150 grp->notifs[0].name, lys_nodetype2str(grp->notifs[0].nodetype), parent->name,
5151 lys_nodetype2str(parent->nodetype));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005152 ret = LY_EVALID;
5153 goto cleanup;
Michal Vasko601ddb32020-08-31 16:25:35 +02005154 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005155 COMPILE_OP_ARRAY_GOTO(ctx, grp->notifs, *notifs, parent, u, lys_compile_notif, 0, ret, cleanup);
Michal Vaskoceab6dd2020-10-09 16:53:36 +02005156
5157 if (uses_p->when) {
5158 /* inherit when */
5159 LY_ARRAY_FOR(*notifs, u) {
5160 ret = lys_compile_when(ctx, uses_p->when, uses_p->flags, lysc_xpath_context(parent),
5161 (struct lysc_node *)&(*notifs)[u], &when_shared);
5162 LY_CHECK_GOTO(ret, cleanup);
5163 }
5164 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005165 }
5166
Michal Vasko7f45cf22020-10-01 12:49:44 +02005167 /* check that all augments were applied */
5168 for (i = 0; i < ctx->uses_augs.count; ++i) {
5169 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005170 "Augment target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko891d7532020-10-07 09:41:38 +02005171 ((struct lysc_augment *)ctx->uses_augs.objs[i])->nodeid->expr, grp->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005172 ret = LY_ENOTFOUND;
Michal Vasko601ddb32020-08-31 16:25:35 +02005173 }
Michal Vasko601ddb32020-08-31 16:25:35 +02005174 LY_CHECK_GOTO(ret, cleanup);
5175
Michal Vasko7f45cf22020-10-01 12:49:44 +02005176 /* check that all refines were applied */
5177 for (i = 0; i < ctx->uses_rfns.count; ++i) {
5178 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02005179 "Refine(s) target node \"%s\" in grouping \"%s\" was not found.",
Michal Vasko891d7532020-10-07 09:41:38 +02005180 ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid->expr, grp->name);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005181 ret = LY_ENOTFOUND;
Radek Krejcic6b4f442020-08-12 14:45:18 +02005182 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02005183 LY_CHECK_GOTO(ret, cleanup);
Radek Krejcifc11bd72019-04-11 16:00:05 +02005184
5185cleanup:
Radek Krejcie86bf772018-12-14 11:39:53 +01005186 /* reload previous context's mod_def */
5187 ctx->mod_def = mod_old;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005188
Radek Krejcie86bf772018-12-14 11:39:53 +01005189 /* remove the grouping from the stack for circular groupings dependency check */
5190 ly_set_rm_index(&ctx->groupings, ctx->groupings.count - 1, NULL);
5191 assert(ctx->groupings.count == grp_stack_count);
5192
Michal Vasko7f45cf22020-10-01 12:49:44 +02005193 ly_set_erase(&uses_child_set, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01005194 return ret;
5195}
5196
Radek Krejci327de162019-06-14 12:52:07 +02005197static int
5198lys_compile_grouping_pathlog(struct lysc_ctx *ctx, struct lysp_node *node, char **path)
5199{
5200 struct lysp_node *iter;
5201 int len = 0;
5202
5203 *path = NULL;
5204 for (iter = node; iter && len >= 0; iter = iter->parent) {
5205 char *s = *path;
5206 char *id;
5207
5208 switch (iter->nodetype) {
5209 case LYS_USES:
Radek Krejci200f1062020-07-11 22:51:03 +02005210 LY_CHECK_RET(asprintf(&id, "{uses='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005211 break;
5212 case LYS_GROUPING:
Radek Krejci200f1062020-07-11 22:51:03 +02005213 LY_CHECK_RET(asprintf(&id, "{grouping='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005214 break;
5215 case LYS_AUGMENT:
Radek Krejci200f1062020-07-11 22:51:03 +02005216 LY_CHECK_RET(asprintf(&id, "{augment='%s'}", iter->name) == -1, -1);
Radek Krejci327de162019-06-14 12:52:07 +02005217 break;
5218 default:
5219 id = strdup(iter->name);
5220 break;
5221 }
5222
5223 if (!iter->parent) {
5224 /* print prefix */
5225 len = asprintf(path, "/%s:%s%s", ctx->mod->name, id, s ? s : "");
5226 } else {
5227 /* prefix is the same as in parent */
5228 len = asprintf(path, "/%s%s", id, s ? s : "");
5229 }
5230 free(s);
5231 free(id);
5232 }
5233
5234 if (len < 0) {
5235 free(*path);
5236 *path = NULL;
5237 } else if (len == 0) {
5238 *path = strdup("/");
5239 len = 1;
5240 }
5241 return len;
5242}
5243
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005244/**
5245 * @brief Validate groupings that were defined but not directly used in the schema itself.
5246 *
5247 * The grouping does not need to be compiled (and it is compiled here, but the result is forgotten immediately),
5248 * but to have the complete result of the schema validity, even such groupings are supposed to be checked.
5249 */
5250static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02005251lys_compile_grouping(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysp_grp *grp)
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005252{
5253 LY_ERR ret;
Radek Krejci327de162019-06-14 12:52:07 +02005254 char *path;
5255 int len;
5256
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005257 struct lysp_node_uses fake_uses = {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005258 .parent = pnode,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005259 .nodetype = LYS_USES,
5260 .flags = 0, .next = NULL,
5261 .name = grp->name,
5262 .dsc = NULL, .ref = NULL, .when = NULL, .iffeatures = NULL, .exts = NULL,
5263 .refines = NULL, .augments = NULL
5264 };
5265 struct lysc_node_container fake_container = {
5266 .nodetype = LYS_CONTAINER,
Michal Vasko7f45cf22020-10-01 12:49:44 +02005267 .flags = pnode ? (pnode->flags & LYS_FLAGS_COMPILED_MASK) : 0,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005268 .module = ctx->mod,
5269 .sp = NULL, .parent = NULL, .next = NULL,
Michal Vasko22df3f02020-08-24 13:29:22 +02005270 .prev = (struct lysc_node *)&fake_container,
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005271 .name = "fake",
5272 .dsc = NULL, .ref = NULL, .exts = NULL, .iffeatures = NULL, .when = NULL,
5273 .child = NULL, .musts = NULL, .actions = NULL, .notifs = NULL
5274 };
5275
5276 if (grp->parent) {
5277 LOGWRN(ctx->ctx, "Locally scoped grouping \"%s\" not used.", grp->name);
5278 }
Radek Krejci327de162019-06-14 12:52:07 +02005279
5280 len = lys_compile_grouping_pathlog(ctx, grp->parent, &path);
5281 if (len < 0) {
5282 LOGMEM(ctx->ctx);
5283 return LY_EMEM;
5284 }
5285 strncpy(ctx->path, path, LYSC_CTX_BUFSIZE - 1);
Radek Krejci1deb5be2020-08-26 16:43:36 +02005286 ctx->path_len = (uint32_t)len;
Radek Krejci327de162019-06-14 12:52:07 +02005287 free(path);
5288
5289 lysc_update_path(ctx, NULL, "{grouping}");
5290 lysc_update_path(ctx, NULL, grp->name);
Michal Vasko22df3f02020-08-24 13:29:22 +02005291 ret = lys_compile_uses(ctx, &fake_uses, (struct lysc_node *)&fake_container, NULL);
Radek Krejci327de162019-06-14 12:52:07 +02005292 lysc_update_path(ctx, NULL, NULL);
5293 lysc_update_path(ctx, NULL, NULL);
5294
5295 ctx->path_len = 1;
5296 ctx->path[1] = '\0';
Radek Krejcif2de0ed2019-05-02 14:13:18 +02005297
5298 /* cleanup */
5299 lysc_node_container_free(ctx->ctx, &fake_container);
5300
5301 return ret;
5302}
Radek Krejcife909632019-02-12 15:34:42 +01005303
Radek Krejcie86bf772018-12-14 11:39:53 +01005304/**
Michal Vasko20424b42020-08-31 12:29:38 +02005305 * @brief Set config flags for a node.
5306 *
5307 * @param[in] ctx Compile context.
5308 * @param[in] node Compiled node config to set.
5309 * @param[in] parent Parent of @p node.
5310 * @return LY_ERR value.
5311 */
5312static LY_ERR
5313lys_compile_config(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_node *parent)
5314{
5315 if (node->nodetype == LYS_CASE) {
5316 /* case never has any config */
5317 assert(!(node->flags & LYS_CONFIG_MASK));
5318 return LY_SUCCESS;
5319 }
5320
5321 /* adjust parent to always get the ancestor with config */
5322 if (parent && (parent->nodetype == LYS_CASE)) {
5323 parent = parent->parent;
5324 assert(parent);
5325 }
5326
Radek Krejci90d4e922020-10-12 15:55:33 +02005327 if (ctx->options & (LYS_COMPILE_RPC_INPUT | LYS_COMPILE_RPC_OUTPUT)) {
Michal Vasko20424b42020-08-31 12:29:38 +02005328 /* ignore config statements inside RPC/action data */
5329 node->flags &= ~LYS_CONFIG_MASK;
Radek Krejci90d4e922020-10-12 15:55:33 +02005330 node->flags |= (ctx->options & LYS_COMPILE_RPC_INPUT) ? LYS_CONFIG_W : LYS_CONFIG_R;
5331 } else if (ctx->options & LYS_COMPILE_NOTIFICATION) {
Michal Vasko20424b42020-08-31 12:29:38 +02005332 /* ignore config statements inside Notification data */
5333 node->flags &= ~LYS_CONFIG_MASK;
5334 node->flags |= LYS_CONFIG_R;
5335 } else if (!(node->flags & LYS_CONFIG_MASK)) {
5336 /* config not explicitely set, inherit it from parent */
5337 if (parent) {
5338 node->flags |= parent->flags & LYS_CONFIG_MASK;
5339 } else {
5340 /* default is config true */
5341 node->flags |= LYS_CONFIG_W;
5342 }
5343 } else {
5344 /* config set explicitely */
5345 node->flags |= LYS_SET_CONFIG;
5346 }
5347
5348 if (parent && (parent->flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
5349 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02005350 "Configuration node cannot be child of any state data node.");
Michal Vasko20424b42020-08-31 12:29:38 +02005351 return LY_EVALID;
5352 }
5353
5354 return LY_SUCCESS;
5355}
5356
Michal Vasko7f45cf22020-10-01 12:49:44 +02005357static LY_ERR
5358lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext)
5359{
5360 LY_ERR ret = LY_SUCCESS;
5361
5362 *ext = *orig_ext;
5363 DUP_STRING(ctx, orig_ext->name, ext->name, ret);
5364 DUP_STRING(ctx, orig_ext->argument, ext->argument, ret);
5365
5366 return ret;
5367}
5368
5369static LY_ERR
5370lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr)
5371{
5372 LY_ERR ret = LY_SUCCESS;
5373
5374 if (orig_restr) {
5375 DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret);
5376 restr->arg.mod = orig_restr->arg.mod;
5377 DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret);
5378 DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret);
5379 DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret);
5380 DUP_STRING(ctx, orig_restr->ref, restr->ref, ret);
5381 DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup);
5382 }
5383
5384 return ret;
5385}
5386
5387static LY_ERR
5388lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str)
5389{
5390 LY_ERR ret = LY_SUCCESS;
5391
5392 DUP_STRING(ctx, *orig_str, *str, ret);
5393
5394 return ret;
5395}
5396
5397static LY_ERR
5398lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname)
5399{
5400 LY_ERR ret = LY_SUCCESS;
5401
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005402 if (!orig_qname->str) {
5403 return LY_SUCCESS;
5404 }
5405
Michal Vasko7f45cf22020-10-01 12:49:44 +02005406 DUP_STRING(ctx, orig_qname->str, qname->str, ret);
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005407 assert(orig_qname->mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005408 qname->mod = orig_qname->mod;
5409
5410 return ret;
5411}
5412
5413static LY_ERR
5414lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm)
5415{
5416 LY_ERR ret = LY_SUCCESS;
5417
5418 DUP_STRING(ctx, orig_enm->name, enm->name, ret);
5419 DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret);
5420 DUP_STRING(ctx, orig_enm->ref, enm->ref, ret);
5421 enm->value = orig_enm->value;
5422 DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup);
5423 DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup);
5424 enm->flags = orig_enm->flags;
5425
5426 return ret;
5427}
5428
5429static LY_ERR
5430lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type)
5431{
5432 LY_ERR ret = LY_SUCCESS;
5433
5434 DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done);
5435
5436 if (orig_type->range) {
5437 type->range = calloc(1, sizeof *type->range);
5438 LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM);
5439 LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range));
5440 }
5441
5442 if (orig_type->length) {
5443 type->length = calloc(1, sizeof *type->length);
5444 LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM);
5445 LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length));
5446 }
5447
5448 DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup);
5449 DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup);
5450 DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup);
5451 LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done);
5452 DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup);
5453 DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup);
5454 DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup);
5455
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005456 type->mod = orig_type->mod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005457 type->compiled = orig_type->compiled;
5458
5459 type->fraction_digits = orig_type->fraction_digits;
5460 type->require_instance = orig_type->require_instance;
5461 type->flags = orig_type->flags;
5462
5463done:
5464 return ret;
5465}
5466
5467static LY_ERR
5468lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when)
5469{
5470 LY_ERR ret = LY_SUCCESS;
5471
5472 DUP_STRING(ctx, orig_when->cond, when->cond, ret);
5473 DUP_STRING(ctx, orig_when->dsc, when->dsc, ret);
5474 DUP_STRING(ctx, orig_when->ref, when->ref, ret);
5475 DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup);
5476
5477 return ret;
5478}
5479
5480static LY_ERR
5481lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5482{
5483 LY_ERR ret = LY_SUCCESS;
5484
5485 node->parent = NULL;
5486 node->nodetype = orig->nodetype;
5487 node->flags = orig->flags;
5488 node->next = NULL;
5489 DUP_STRING(ctx, orig->name, node->name, ret);
5490 DUP_STRING(ctx, orig->dsc, node->dsc, ret);
5491 DUP_STRING(ctx, orig->ref, node->ref, ret);
5492
5493 if (orig->when) {
5494 node->when = calloc(1, sizeof *node->when);
5495 LY_CHECK_ERR_RET(!node->when, LOGMEM(ctx), LY_EMEM);
5496 LY_CHECK_RET(lysp_when_dup(ctx, node->when, orig->when));
5497 }
5498
5499 DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup);
5500 DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup);
5501
5502 return ret;
5503}
5504
5505static LY_ERR
5506lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig)
5507{
5508 LY_ERR ret = LY_SUCCESS;
5509 struct lysp_node_container *cont;
5510 const struct lysp_node_container *orig_cont;
5511 struct lysp_node_leaf *leaf;
5512 const struct lysp_node_leaf *orig_leaf;
5513 struct lysp_node_leaflist *llist;
5514 const struct lysp_node_leaflist *orig_llist;
5515 struct lysp_node_list *list;
5516 const struct lysp_node_list *orig_list;
5517 struct lysp_node_choice *choice;
5518 const struct lysp_node_choice *orig_choice;
5519 struct lysp_node_case *cas;
5520 const struct lysp_node_case *orig_cas;
5521 struct lysp_node_anydata *any;
5522 const struct lysp_node_anydata *orig_any;
5523
5524 assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA));
5525
5526 /* common part */
5527 LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig));
5528
5529 /* specific part */
5530 switch (node->nodetype) {
5531 case LYS_CONTAINER:
5532 cont = (struct lysp_node_container *)node;
5533 orig_cont = (const struct lysp_node_container *)orig;
5534
5535 DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup);
5536 DUP_STRING(ctx, orig_cont->presence, cont->presence, ret);
5537 /* we do not need the rest */
5538 break;
5539 case LYS_LEAF:
5540 leaf = (struct lysp_node_leaf *)node;
5541 orig_leaf = (const struct lysp_node_leaf *)orig;
5542
5543 DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup);
5544 LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type));
5545 DUP_STRING(ctx, orig_leaf->units, leaf->units, ret);
Michal Vaskoe9c050f2020-10-06 14:01:23 +02005546 LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt));
Michal Vasko7f45cf22020-10-01 12:49:44 +02005547 break;
5548 case LYS_LEAFLIST:
5549 llist = (struct lysp_node_leaflist *)node;
5550 orig_llist = (const struct lysp_node_leaflist *)orig;
5551
5552 DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup);
5553 LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type));
5554 DUP_STRING(ctx, orig_llist->units, llist->units, ret);
5555 DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup);
5556 llist->min = orig_llist->min;
5557 llist->max = orig_llist->max;
5558 break;
5559 case LYS_LIST:
5560 list = (struct lysp_node_list *)node;
5561 orig_list = (const struct lysp_node_list *)orig;
5562
5563 DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup);
5564 DUP_STRING(ctx, orig_list->key, list->key, ret);
5565 /* we do not need these arrays */
5566 DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup);
5567 list->min = orig_list->min;
5568 list->max = orig_list->max;
5569 break;
5570 case LYS_CHOICE:
5571 choice = (struct lysp_node_choice *)node;
5572 orig_choice = (const struct lysp_node_choice *)orig;
5573
5574 /* we do not need children */
5575 LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt));
5576 break;
5577 case LYS_CASE:
5578 cas = (struct lysp_node_case *)node;
5579 orig_cas = (const struct lysp_node_case *)orig;
5580
5581 /* we do not need children */
5582 (void)cas;
5583 (void)orig_cas;
5584 break;
5585 case LYS_ANYDATA:
5586 case LYS_ANYXML:
5587 any = (struct lysp_node_anydata *)node;
5588 orig_any = (const struct lysp_node_anydata *)orig;
5589
5590 DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup);
5591 break;
5592 default:
5593 LOGINT_RET(ctx);
5594 }
5595
5596 return ret;
5597}
5598
5599static LY_ERR
5600lysp_action_inout_dup(const struct ly_ctx *ctx, struct lysp_action_inout *inout, const struct lysp_action_inout *orig)
5601{
5602 inout->parent = NULL;
5603 inout->nodetype = orig->nodetype;
5604 DUP_ARRAY(ctx, orig->musts, inout->musts, lysp_restr_dup);
5605 /* we dot need these arrays */
5606 DUP_ARRAY(ctx, orig->exts, inout->exts, lysp_ext_dup);
5607
5608 return LY_SUCCESS;
5609}
5610
5611static LY_ERR
5612lysp_action_dup(const struct ly_ctx *ctx, struct lysp_action *act, const struct lysp_action *orig)
5613{
5614 LY_ERR ret = LY_SUCCESS;
5615
5616 act->parent = NULL;
5617 act->nodetype = orig->nodetype;
5618 act->flags = orig->flags;
5619 DUP_STRING(ctx, orig->name, act->name, ret);
5620 DUP_STRING(ctx, orig->dsc, act->dsc, ret);
5621 DUP_STRING(ctx, orig->ref, act->ref, ret);
5622 DUP_ARRAY(ctx, orig->iffeatures, act->iffeatures, lysp_qname_dup);
5623
5624 act->input.nodetype = orig->input.nodetype;
5625 act->output.nodetype = orig->output.nodetype;
5626 /* we do not need choldren of in/out */
5627 DUP_ARRAY(ctx, orig->exts, act->exts, lysp_ext_dup);
5628
5629 return ret;
5630}
5631
5632static LY_ERR
5633lysp_notif_dup(const struct ly_ctx *ctx, struct lysp_notif *notif, const struct lysp_notif *orig)
5634{
5635 LY_ERR ret = LY_SUCCESS;
5636
5637 notif->parent = NULL;
5638 notif->nodetype = orig->nodetype;
5639 notif->flags = orig->flags;
5640 DUP_STRING(ctx, orig->name, notif->name, ret);
5641 DUP_STRING(ctx, orig->dsc, notif->dsc, ret);
5642 DUP_STRING(ctx, orig->ref, notif->ref, ret);
5643 DUP_ARRAY(ctx, orig->iffeatures, notif->iffeatures, lysp_qname_dup);
5644 DUP_ARRAY(ctx, orig->musts, notif->musts, lysp_restr_dup);
5645 /* we do not need these arrays */
5646 DUP_ARRAY(ctx, orig->exts, notif->exts, lysp_ext_dup);
5647
5648 return ret;
5649}
5650
5651/**
5652 * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied.
5653 *
5654 * @param[in] ctx libyang context.
5655 * @param[in] pnode Node to duplicate.
5656 * @param[in] with_links Whether to also copy any links (child, parent pointers).
5657 * @param[out] dup_p Duplicated parsed node.
5658 * @return LY_ERR value.
5659 */
5660static LY_ERR
5661lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p)
5662{
Michal Vaskoaf702452020-10-02 09:02:55 +02005663 LY_ERR ret = LY_SUCCESS;
5664 void *mem = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005665
5666 if (!pnode) {
5667 *dup_p = NULL;
5668 return LY_SUCCESS;
5669 }
5670
5671 switch (pnode->nodetype) {
5672 case LYS_CONTAINER:
5673 mem = calloc(1, sizeof(struct lysp_node_container));
Michal Vaskoaf702452020-10-02 09:02:55 +02005674 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5675 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005676 break;
5677 case LYS_LEAF:
5678 mem = calloc(1, sizeof(struct lysp_node_leaf));
Michal Vaskoaf702452020-10-02 09:02:55 +02005679 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5680 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005681 break;
5682 case LYS_LEAFLIST:
5683 mem = calloc(1, sizeof(struct lysp_node_leaflist));
Michal Vaskoaf702452020-10-02 09:02:55 +02005684 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5685 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005686 break;
5687 case LYS_LIST:
5688 mem = calloc(1, sizeof(struct lysp_node_list));
Michal Vaskoaf702452020-10-02 09:02:55 +02005689 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5690 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005691 break;
5692 case LYS_CHOICE:
5693 mem = calloc(1, sizeof(struct lysp_node_choice));
Michal Vaskoaf702452020-10-02 09:02:55 +02005694 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5695 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005696 break;
5697 case LYS_CASE:
5698 mem = calloc(1, sizeof(struct lysp_node_case));
Michal Vaskoaf702452020-10-02 09:02:55 +02005699 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5700 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005701 break;
5702 case LYS_ANYDATA:
5703 case LYS_ANYXML:
5704 mem = calloc(1, sizeof(struct lysp_node_anydata));
Michal Vaskoaf702452020-10-02 09:02:55 +02005705 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5706 LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005707 break;
5708 case LYS_INPUT:
5709 case LYS_OUTPUT:
5710 mem = calloc(1, sizeof(struct lysp_action_inout));
Michal Vaskoaf702452020-10-02 09:02:55 +02005711 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5712 LY_CHECK_GOTO(ret = lysp_action_inout_dup(ctx, mem, (struct lysp_action_inout *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005713 break;
5714 case LYS_ACTION:
5715 case LYS_RPC:
5716 mem = calloc(1, sizeof(struct lysp_action));
Michal Vaskoaf702452020-10-02 09:02:55 +02005717 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5718 LY_CHECK_GOTO(ret = lysp_action_dup(ctx, mem, (struct lysp_action *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005719 break;
5720 case LYS_NOTIF:
5721 mem = calloc(1, sizeof(struct lysp_notif));
Michal Vaskoaf702452020-10-02 09:02:55 +02005722 LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup);
5723 LY_CHECK_GOTO(ret = lysp_notif_dup(ctx, mem, (struct lysp_notif *)pnode), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005724 break;
5725 default:
5726 LOGINT_RET(ctx);
5727 }
5728
5729 if (with_links) {
5730 /* copy also parent and child pointers */
5731 ((struct lysp_node *)mem)->parent = pnode->parent;
5732 switch (pnode->nodetype) {
5733 case LYS_CONTAINER:
5734 ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child;
5735 break;
5736 case LYS_LIST:
5737 ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child;
5738 break;
5739 case LYS_CHOICE:
5740 ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child;
5741 break;
5742 case LYS_CASE:
5743 ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child;
5744 break;
5745 default:
5746 break;
5747 }
5748 }
5749
Michal Vaskoaf702452020-10-02 09:02:55 +02005750cleanup:
5751 if (ret) {
5752 free(mem);
5753 } else {
5754 *dup_p = mem;
5755 }
5756 return ret;
Michal Vasko7f45cf22020-10-01 12:49:44 +02005757}
5758
5759#define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \
5760 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \
5761 AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\
5762 ret = LY_EVALID; \
5763 goto cleanup;
5764
5765#define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \
5766 if (LY_ARRAY_COUNT(ARRAY) > MAX) { \
5767 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \
5768 AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \
5769 ret = LY_EVALID; \
5770 goto cleanup; \
5771 }
5772
5773/**
5774 * @brief Apply refine.
5775 *
5776 * @param[in] ctx Compile context.
5777 * @param[in] rfn Refine to apply.
5778 * @param[in,out] target Refine target.
5779 * @return LY_ERR value.
5780 */
5781static LY_ERR
5782lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target)
5783{
5784 LY_ERR ret = LY_SUCCESS;
5785 LY_ARRAY_COUNT_TYPE u;
5786 struct lysp_qname *qname;
5787 struct lysp_restr **musts, *must;
5788 uint32_t *num;
5789
5790 /* default value */
5791 if (rfn->dflts) {
5792 switch (target->nodetype) {
5793 case LYS_LEAF:
5794 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5795
5796 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
5797 DUP_STRING_GOTO(ctx->ctx, rfn->dflts[0], ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
5798 ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
5799 break;
5800 case LYS_LEAFLIST:
5801 if (ctx->mod->version < LYS_VERSION_1_1) {
5802 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
5803 "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules.");
5804 ret = LY_EVALID;
5805 goto cleanup;
5806 }
5807
5808 FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free);
5809 ((struct lysp_node_leaflist *)target)->dflts = NULL;
5810 LY_ARRAY_FOR(rfn->dflts, u) {
5811 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
5812 DUP_STRING_GOTO(ctx->ctx, rfn->dflts[u], qname->str, ret, cleanup);
5813 qname->mod = ctx->mod;
5814 }
5815 break;
5816 case LYS_CHOICE:
5817 AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default");
5818
5819 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
5820 DUP_STRING_GOTO(ctx->ctx, rfn->dflts[0], ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
5821 ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
5822 break;
5823 default:
5824 AMEND_WRONG_NODETYPE("refine", "replace", "default");
5825 }
5826 }
5827
5828 /* description */
5829 if (rfn->dsc) {
5830 FREE_STRING(ctx->ctx, target->dsc);
5831 DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup);
5832 }
5833
5834 /* reference */
5835 if (rfn->ref) {
5836 FREE_STRING(ctx->ctx, target->ref);
5837 DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup);
5838 }
5839
5840 /* config */
5841 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci90d4e922020-10-12 15:55:33 +02005842 if (ctx->options & (LYS_COMPILE_NOTIFICATION | LYS_COMPILE_RPC_INPUT | LYS_COMPILE_RPC_OUTPUT)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02005843 LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).",
Radek Krejci90d4e922020-10-12 15:55:33 +02005844 ctx->options & LYS_COMPILE_NOTIFICATION ? "notification" : "RPC/action", ctx->path);
Michal Vasko7f45cf22020-10-01 12:49:44 +02005845 } else {
5846 target->flags &= ~LYS_CONFIG_MASK;
5847 target->flags |= rfn->flags & LYS_CONFIG_MASK;
5848 }
5849 }
5850
5851 /* mandatory */
5852 if (rfn->flags & LYS_MAND_MASK) {
5853 switch (target->nodetype) {
5854 case LYS_LEAF:
5855 case LYS_CHOICE:
5856 case LYS_ANYDATA:
5857 case LYS_ANYXML:
5858 break;
5859 default:
5860 AMEND_WRONG_NODETYPE("refine", "replace", "mandatory");
5861 }
5862
5863 target->flags &= ~LYS_MAND_MASK;
5864 target->flags |= rfn->flags & LYS_MAND_MASK;
5865 }
5866
5867 /* presence */
5868 if (rfn->presence) {
5869 switch (target->nodetype) {
5870 case LYS_CONTAINER:
5871 break;
5872 default:
5873 AMEND_WRONG_NODETYPE("refine", "replace", "presence");
5874 }
5875
5876 FREE_STRING(ctx->ctx, ((struct lysp_node_container *)target)->presence);
5877 DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup);
5878 }
5879
5880 /* must */
5881 if (rfn->musts) {
5882 switch (target->nodetype) {
5883 case LYS_CONTAINER:
5884 case LYS_LIST:
5885 case LYS_LEAF:
5886 case LYS_LEAFLIST:
5887 case LYS_ANYDATA:
5888 case LYS_ANYXML:
5889 musts = &((struct lysp_node_container *)target)->musts;
5890 break;
5891 default:
5892 AMEND_WRONG_NODETYPE("refine", "add", "must");
5893 }
5894
5895 LY_ARRAY_FOR(rfn->musts, u) {
5896 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
5897 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup);
5898 }
5899 }
5900
5901 /* min-elements */
5902 if (rfn->flags & LYS_SET_MIN) {
5903 switch (target->nodetype) {
5904 case LYS_LEAFLIST:
5905 num = &((struct lysp_node_leaflist *)target)->min;
5906 break;
5907 case LYS_LIST:
5908 num = &((struct lysp_node_list *)target)->min;
5909 break;
5910 default:
5911 AMEND_WRONG_NODETYPE("refine", "replace", "min-elements");
5912 }
5913
5914 *num = rfn->min;
5915 }
5916
5917 /* max-elements */
5918 if (rfn->flags & LYS_SET_MAX) {
5919 switch (target->nodetype) {
5920 case LYS_LEAFLIST:
5921 num = &((struct lysp_node_leaflist *)target)->max;
5922 break;
5923 case LYS_LIST:
5924 num = &((struct lysp_node_list *)target)->max;
5925 break;
5926 default:
5927 AMEND_WRONG_NODETYPE("refine", "replace", "max-elements");
5928 }
5929
5930 *num = rfn->max;
5931 }
5932
5933 /* if-feature */
5934 if (rfn->iffeatures) {
5935 switch (target->nodetype) {
5936 case LYS_LEAF:
5937 case LYS_LEAFLIST:
5938 case LYS_LIST:
5939 case LYS_CONTAINER:
5940 case LYS_CHOICE:
5941 case LYS_CASE:
5942 case LYS_ANYDATA:
5943 case LYS_ANYXML:
5944 break;
5945 default:
5946 AMEND_WRONG_NODETYPE("refine", "add", "if-feature");
5947 }
5948
5949 LY_ARRAY_FOR(rfn->iffeatures, u) {
5950 LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup);
5951 DUP_STRING_GOTO(ctx->ctx, rfn->iffeatures[u].str, qname->str, ret, cleanup);
5952 qname->mod = ctx->mod;
5953 }
5954 }
5955
5956 /* extension */
5957 /* TODO refine extensions */
5958
5959cleanup:
5960 return ret;
5961}
5962
5963/**
5964 * @brief Apply deviate add.
5965 *
5966 * @param[in] ctx Compile context.
5967 * @param[in] d Deviate add to apply.
5968 * @param[in,out] target Deviation target.
5969 * @return LY_ERR value.
5970 */
5971static LY_ERR
5972lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target)
5973{
5974 LY_ERR ret = LY_SUCCESS;
5975 LY_ARRAY_COUNT_TYPE u;
5976 struct lysp_qname *qname;
5977 uint32_t *num;
5978 struct lysp_restr **musts, *must;
5979
5980#define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \
5981 if (((TYPE)target)->MEMBER) { \
5982 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
5983 "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \
5984 PROPERTY, ((TYPE)target)->VALUEMEMBER); \
5985 ret = LY_EVALID; \
5986 goto cleanup; \
5987 }
5988
5989 /* [units-stmt] */
5990 if (d->units) {
5991 switch (target->nodetype) {
5992 case LYS_LEAF:
5993 case LYS_LEAFLIST:
5994 break;
5995 default:
5996 AMEND_WRONG_NODETYPE("deviation", "add", "units");
5997 }
5998
5999 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units);
6000 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
6001 }
6002
6003 /* *must-stmt */
6004 if (d->musts) {
6005 switch (target->nodetype) {
6006 case LYS_CONTAINER:
6007 case LYS_LIST:
6008 case LYS_LEAF:
6009 case LYS_LEAFLIST:
6010 case LYS_ANYDATA:
6011 case LYS_ANYXML:
6012 musts = &((struct lysp_node_container *)target)->musts;
6013 break;
6014 case LYS_NOTIF:
6015 musts = &((struct lysp_notif *)target)->musts;
6016 break;
6017 case LYS_INPUT:
6018 case LYS_OUTPUT:
6019 musts = &((struct lysp_action_inout *)target)->musts;
6020 break;
6021 default:
6022 AMEND_WRONG_NODETYPE("deviation", "add", "must");
6023 }
6024
6025 LY_ARRAY_FOR(d->musts, u) {
6026 LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup);
6027 LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup);
6028 }
6029 }
6030
6031 /* *unique-stmt */
6032 if (d->uniques) {
6033 switch (target->nodetype) {
6034 case LYS_LIST:
6035 break;
6036 default:
6037 AMEND_WRONG_NODETYPE("deviation", "add", "unique");
6038 }
6039
6040 LY_ARRAY_FOR(d->uniques, u) {
6041 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup);
6042 DUP_STRING_GOTO(ctx->ctx, d->uniques[u], qname->str, ret, cleanup);
6043 qname->mod = ctx->mod;
6044 }
6045 }
6046
6047 /* *default-stmt */
6048 if (d->dflts) {
6049 switch (target->nodetype) {
6050 case LYS_LEAF:
6051 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6052 DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str);
6053
6054 DUP_STRING_GOTO(ctx->ctx, d->dflts[0], ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
6055 ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
6056 break;
6057 case LYS_LEAFLIST:
6058 LY_ARRAY_FOR(d->dflts, u) {
6059 LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup);
6060 DUP_STRING_GOTO(ctx->ctx, d->dflts[u], qname->str, ret, cleanup);
6061 qname->mod = ctx->mod;
6062 }
6063 break;
6064 case LYS_CHOICE:
6065 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6066 DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str);
6067
6068 DUP_STRING_GOTO(ctx->ctx, d->dflts[0], ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
6069 ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
6070 break;
6071 default:
6072 AMEND_WRONG_NODETYPE("deviation", "add", "default");
6073 }
6074 }
6075
6076 /* [config-stmt] */
6077 if (d->flags & LYS_CONFIG_MASK) {
6078 switch (target->nodetype) {
6079 case LYS_CONTAINER:
6080 case LYS_LEAF:
6081 case LYS_LEAFLIST:
6082 case LYS_LIST:
6083 case LYS_CHOICE:
6084 case LYS_ANYDATA:
6085 case LYS_ANYXML:
6086 break;
6087 default:
6088 AMEND_WRONG_NODETYPE("deviation", "add", "config");
6089 }
6090
6091 if (target->flags & LYS_CONFIG_MASK) {
6092 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6093 "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").",
6094 target->flags & LYS_CONFIG_W ? "true" : "false");
6095 ret = LY_EVALID;
6096 goto cleanup;
6097 }
6098
6099 target->flags |= d->flags & LYS_CONFIG_MASK;
6100 }
6101
6102 /* [mandatory-stmt] */
6103 if (d->flags & LYS_MAND_MASK) {
6104 switch (target->nodetype) {
6105 case LYS_LEAF:
6106 case LYS_CHOICE:
6107 case LYS_ANYDATA:
6108 case LYS_ANYXML:
6109 break;
6110 default:
6111 AMEND_WRONG_NODETYPE("deviation", "add", "mandatory");
6112 }
6113
6114 if (target->flags & LYS_MAND_MASK) {
6115 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6116 "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
6117 target->flags & LYS_MAND_TRUE ? "true" : "false");
6118 ret = LY_EVALID;
6119 goto cleanup;
6120 }
6121
6122 target->flags |= d->flags & LYS_MAND_MASK;
6123 }
6124
6125 /* [min-elements-stmt] */
6126 if (d->flags & LYS_SET_MIN) {
6127 switch (target->nodetype) {
6128 case LYS_LEAFLIST:
6129 num = &((struct lysp_node_leaflist *)target)->min;
6130 break;
6131 case LYS_LIST:
6132 num = &((struct lysp_node_list *)target)->min;
6133 break;
6134 default:
6135 AMEND_WRONG_NODETYPE("deviation", "add", "min-elements");
6136 }
6137
6138 if (target->flags & LYS_SET_MIN) {
6139 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6140 "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num);
6141 ret = LY_EVALID;
6142 goto cleanup;
6143 }
6144
6145 *num = d->min;
6146 }
6147
6148 /* [max-elements-stmt] */
6149 if (d->flags & LYS_SET_MAX) {
6150 switch (target->nodetype) {
6151 case LYS_LEAFLIST:
6152 num = &((struct lysp_node_leaflist *)target)->max;
6153 break;
6154 case LYS_LIST:
6155 num = &((struct lysp_node_list *)target)->max;
6156 break;
6157 default:
6158 AMEND_WRONG_NODETYPE("deviation", "add", "max-elements");
6159 }
6160
6161 if (target->flags & LYS_SET_MAX) {
6162 if (*num) {
6163 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6164 "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").",
6165 *num);
6166 } else {
6167 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6168 "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\").");
6169 }
6170 ret = LY_EVALID;
6171 goto cleanup;
6172 }
6173
6174 *num = d->max;
6175 }
6176
6177cleanup:
6178 return ret;
6179}
6180
6181/**
6182 * @brief Apply deviate delete.
6183 *
6184 * @param[in] ctx Compile context.
6185 * @param[in] d Deviate delete to apply.
6186 * @param[in,out] target Deviation target.
6187 * @return LY_ERR value.
6188 */
6189static LY_ERR
6190lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target)
6191{
6192 LY_ERR ret = LY_SUCCESS;
6193 struct lysp_restr **musts;
6194 LY_ARRAY_COUNT_TYPE u, v;
6195 struct lysp_qname **uniques, **dflts;
6196
6197#define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \
6198 LY_ARRAY_FOR(d->DEV_ARRAY, u) { \
6199 int found = 0; \
6200 LY_ARRAY_FOR(ORIG_ARRAY, v) { \
6201 if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \
6202 found = 1; \
6203 break; \
6204 } \
6205 } \
6206 if (!found) { \
6207 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
6208 "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \
6209 PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \
6210 ret = LY_EVALID; \
6211 goto cleanup; \
6212 } \
6213 LY_ARRAY_DECREMENT(ORIG_ARRAY); \
6214 FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \
6215 memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \
6216 } \
6217 if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \
6218 LY_ARRAY_FREE(ORIG_ARRAY); \
6219 ORIG_ARRAY = NULL; \
6220 }
6221
6222#define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
6223 if (!((TYPE)target)->MEMBER) { \
6224 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
6225 ret = LY_EVALID; \
6226 goto cleanup; \
6227 } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \
6228 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, \
6229 "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \
6230 PROPERTY, VALUE, ((TYPE)target)->MEMBER); \
6231 ret = LY_EVALID; \
6232 goto cleanup; \
6233 }
6234
6235 /* [units-stmt] */
6236 if (d->units) {
6237 switch (target->nodetype) {
6238 case LYS_LEAF:
6239 case LYS_LEAFLIST:
6240 break;
6241 default:
6242 AMEND_WRONG_NODETYPE("deviation", "delete", "units");
6243 }
6244
6245 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units);
6246 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6247 ((struct lysp_node_leaf *)target)->units = NULL;
6248 }
6249
6250 /* *must-stmt */
6251 if (d->musts) {
6252 switch (target->nodetype) {
6253 case LYS_CONTAINER:
6254 case LYS_LIST:
6255 case LYS_LEAF:
6256 case LYS_LEAFLIST:
6257 case LYS_ANYDATA:
6258 case LYS_ANYXML:
6259 musts = &((struct lysp_node_container *)target)->musts;
6260 break;
6261 case LYS_NOTIF:
6262 musts = &((struct lysp_notif *)target)->musts;
6263 break;
6264 case LYS_INPUT:
6265 case LYS_OUTPUT:
6266 musts = &((struct lysp_action_inout *)target)->musts;
6267 break;
6268 default:
6269 AMEND_WRONG_NODETYPE("deviation", "delete", "must");
6270 }
6271
6272 DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must");
6273 }
6274
6275 /* *unique-stmt */
6276 if (d->uniques) {
6277 switch (target->nodetype) {
6278 case LYS_LIST:
6279 break;
6280 default:
6281 AMEND_WRONG_NODETYPE("deviation", "delete", "unique");
6282 }
6283
6284 uniques = &((struct lysp_node_list *)target)->uniques;
6285 DEV_DEL_ARRAY(uniques, *uniques, , .str, lysp_qname_free, "unique");
6286 }
6287
6288 /* *default-stmt */
6289 if (d->dflts) {
6290 switch (target->nodetype) {
6291 case LYS_LEAF:
6292 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6293 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0]);
6294
6295 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
6296 ((struct lysp_node_leaf *)target)->dflt.str = NULL;
6297 break;
6298 case LYS_LEAFLIST:
6299 dflts = &((struct lysp_node_leaflist *)target)->dflts;
6300 DEV_DEL_ARRAY(dflts, *dflts, , .str, lysp_qname_free, "default");
6301 break;
6302 case LYS_CHOICE:
6303 AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default");
6304 DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0]);
6305
6306 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
6307 ((struct lysp_node_choice *)target)->dflt.str = NULL;
6308 break;
6309 default:
6310 AMEND_WRONG_NODETYPE("deviation", "delete", "default");
6311 }
6312 }
6313
6314cleanup:
6315 return ret;
6316}
6317
6318/**
6319 * @brief Apply deviate replace.
6320 *
6321 * @param[in] ctx Compile context.
6322 * @param[in] d Deviate replace to apply.
6323 * @param[in,out] target Deviation target.
6324 * @return LY_ERR value.
6325 */
6326static LY_ERR
6327lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target)
6328{
6329 LY_ERR ret = LY_SUCCESS;
6330 uint32_t *num;
6331
6332#define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \
6333 if (!((TYPE)target)->MEMBER) { \
6334 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \
6335 ret = LY_EVALID; \
6336 goto cleanup; \
6337 }
6338
6339 /* [type-stmt] */
6340 if (d->type) {
6341 switch (target->nodetype) {
6342 case LYS_LEAF:
6343 case LYS_LEAFLIST:
6344 break;
6345 default:
6346 AMEND_WRONG_NODETYPE("deviation", "replace", "type");
6347 }
6348
6349 lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type);
6350 lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type);
6351 }
6352
6353 /* [units-stmt] */
6354 if (d->units) {
6355 switch (target->nodetype) {
6356 case LYS_LEAF:
6357 case LYS_LEAFLIST:
6358 break;
6359 default:
6360 AMEND_WRONG_NODETYPE("deviation", "replace", "units");
6361 }
6362
6363 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units);
6364 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->units);
6365 DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup);
6366 }
6367
6368 /* [default-stmt] */
6369 if (d->dflt) {
6370 switch (target->nodetype) {
6371 case LYS_LEAF:
6372 DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt);
6373
6374 FREE_STRING(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str);
6375 DUP_STRING_GOTO(ctx->ctx, d->dflt, ((struct lysp_node_leaf *)target)->dflt.str, ret, cleanup);
6376 ((struct lysp_node_leaf *)target)->dflt.mod = ctx->mod;
6377 break;
6378 case LYS_CHOICE:
6379 DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt);
6380
6381 FREE_STRING(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str);
6382 DUP_STRING_GOTO(ctx->ctx, d->dflt, ((struct lysp_node_choice *)target)->dflt.str, ret, cleanup);
6383 ((struct lysp_node_choice *)target)->dflt.mod = ctx->mod;
6384 break;
6385 default:
6386 AMEND_WRONG_NODETYPE("deviation", "replace", "default");
6387 }
6388 }
6389
6390 /* [config-stmt] */
6391 if (d->flags & LYS_CONFIG_MASK) {
6392 switch (target->nodetype) {
6393 case LYS_CONTAINER:
6394 case LYS_LEAF:
6395 case LYS_LEAFLIST:
6396 case LYS_LIST:
6397 case LYS_CHOICE:
6398 case LYS_ANYDATA:
6399 case LYS_ANYXML:
6400 break;
6401 default:
6402 AMEND_WRONG_NODETYPE("deviation", "replace", "config");
6403 }
6404
6405 if (!(target->flags & LYS_CONFIG_MASK)) {
6406 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6407 "replacing", "config", d->flags & LYS_CONFIG_W ? "config true" : "config false");
6408 ret = LY_EVALID;
6409 goto cleanup;
6410 }
6411
6412 target->flags &= ~LYS_CONFIG_MASK;
6413 target->flags |= d->flags & LYS_CONFIG_MASK;
6414 }
6415
6416 /* [mandatory-stmt] */
6417 if (d->flags & LYS_MAND_MASK) {
6418 switch (target->nodetype) {
6419 case LYS_LEAF:
6420 case LYS_CHOICE:
6421 case LYS_ANYDATA:
6422 case LYS_ANYXML:
6423 break;
6424 default:
6425 AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory");
6426 }
6427
6428 if (!(target->flags & LYS_MAND_MASK)) {
6429 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT,
6430 "replacing", "mandatory", d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
6431 ret = LY_EVALID;
6432 goto cleanup;
6433 }
6434
6435 target->flags &= ~LYS_MAND_MASK;
6436 target->flags |= d->flags & LYS_MAND_MASK;
6437 }
6438
6439 /* [min-elements-stmt] */
6440 if (d->flags & LYS_SET_MIN) {
6441 switch (target->nodetype) {
6442 case LYS_LEAFLIST:
6443 num = &((struct lysp_node_leaflist *)target)->min;
6444 break;
6445 case LYS_LIST:
6446 num = &((struct lysp_node_list *)target)->min;
6447 break;
6448 default:
6449 AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements");
6450 }
6451
6452 if (!(target->flags & LYS_SET_MIN)) {
6453 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6454 "Invalid deviation replacing \"min-elements\" property which is not present.");
6455 ret = LY_EVALID;
6456 goto cleanup;
6457 }
6458
6459 *num = d->min;
6460 }
6461
6462 /* [max-elements-stmt] */
6463 if (d->flags & LYS_SET_MAX) {
6464 switch (target->nodetype) {
6465 case LYS_LEAFLIST:
6466 num = &((struct lysp_node_leaflist *)target)->max;
6467 break;
6468 case LYS_LIST:
6469 num = &((struct lysp_node_list *)target)->max;
6470 break;
6471 default:
6472 AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements");
6473 }
6474
6475 if (!(target->flags & LYS_SET_MAX)) {
6476 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
6477 "Invalid deviation replacing \"max-elements\" property which is not present.");
6478 ret = LY_EVALID;
6479 goto cleanup;
6480 }
6481
6482 *num = d->max;
6483 }
6484
6485cleanup:
6486 return ret;
6487}
6488
6489/**
6490 * @brief Get module of a single nodeid node name test.
6491 *
6492 * @param[in] ctx libyang context.
6493 * @param[in] nametest Nametest with an optional prefix.
6494 * @param[in] nametest_len Length of @p nametest.
6495 * @param[in] local_mod Module to return in case of no prefix.
6496 * @param[out] name Optional pointer to the name test without the prefix.
6497 * @param[out] name_len Length of @p name.
6498 * @return Resolved module.
6499 */
6500static const struct lys_module *
6501lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len,
6502 const struct lys_module *local_mod, const char **name, size_t *name_len)
6503{
6504 const struct lys_module *target_mod;
6505 const char *ptr;
6506
6507 ptr = ly_strnchr(nametest, ':', nametest_len);
6508 if (ptr) {
6509 target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_PREF_SCHEMA, (void *)local_mod);
6510 if (!target_mod) {
6511 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
6512 "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
6513 nametest_len, nametest, ptr - nametest, nametest, local_mod->name);
6514 return NULL;
6515 }
6516
6517 if (name) {
6518 *name = ptr + 1;
6519 *name_len = nametest_len - ((ptr - nametest) + 1);
6520 }
6521 } else {
6522 target_mod = local_mod;
6523 if (name) {
6524 *name = nametest;
6525 *name_len = nametest_len;
6526 }
6527 }
6528
6529 return target_mod;
6530}
6531
6532/**
6533 * @brief Check whether a parsed node matches a single schema nodeid name test.
6534 *
6535 * @param[in] pnode Parsed node to consider.
6536 * @param[in] pnode_mod Compiled @p pnode to-be module.
6537 * @param[in] mod Expected module.
6538 * @param[in] name Expected name.
6539 * @param[in] name_len Length of @p name.
6540 * @return Whether it is a match or not.
6541 */
6542static ly_bool
6543lysp_schema_nodeid_match_pnode(const struct lysp_node *pnode, const struct lys_module *pnode_mod,
6544 const struct lys_module *mod, const char *name, size_t name_len)
6545{
6546 const char *pname;
6547
6548 /* compare with the module of the node */
6549 if (pnode_mod != mod) {
6550 return 0;
6551 }
6552
6553 /* compare names */
6554 if (pnode->nodetype & (LYS_ACTION | LYS_RPC)) {
6555 pname = ((struct lysp_action *)pnode)->name;
6556 } else if (pnode->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6557 pname = (pnode->nodetype & LYS_INPUT) ? "input" : "output";
6558 } else {
6559 pname = pnode->name;
6560 }
6561 if (ly_strncmp(pname, name, name_len)) {
6562 return 0;
6563 }
6564
6565 return 1;
6566}
6567
6568/**
6569 * @brief Check whether a compiled node matches a single schema nodeid name test.
6570 *
6571 * @param[in,out] node Compiled node to consider. On a match it is moved to its parent.
6572 * @param[in] mod Expected module.
6573 * @param[in] name Expected name.
6574 * @param[in] name_len Length of @p name.
6575 * @return Whether it is a match or not.
6576 */
6577static ly_bool
6578lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name,
6579 size_t name_len)
6580{
6581 const struct lys_module *node_mod;
6582 const char *node_name;
6583
6584 /* compare with the module of the node */
6585 if ((*node)->nodetype == LYS_INPUT) {
6586 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input)))->module;
6587 } else if ((*node)->nodetype == LYS_OUTPUT) {
6588 node_mod = ((struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output)))->module;
6589 } else {
6590 node_mod = (*node)->module;
6591 }
6592 if (node_mod != mod) {
6593 return 0;
6594 }
6595
6596 /* compare names */
6597 if ((*node)->nodetype == LYS_INPUT) {
6598 node_name = "input";
6599 } else if ((*node)->nodetype == LYS_OUTPUT) {
6600 node_name = "output";
6601 } else {
6602 node_name = (*node)->name;
6603 }
6604 if (ly_strncmp(node_name, name, name_len)) {
6605 return 0;
6606 }
6607
6608 if ((*node)->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6609 /* move up from input/output */
6610 if ((*node)->nodetype == LYS_INPUT) {
6611 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, input));
6612 } else {
6613 (*node) = (struct lysc_node *)(((char *)*node) - offsetof(struct lysc_action, output));
6614 }
6615 } else if ((*node)->parent && ((*node)->parent->nodetype & (LYS_RPC | LYS_ACTION))) {
6616 /* move to the input/output */
6617 if ((*node)->flags & LYS_CONFIG_W) {
6618 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->input;
6619 } else {
6620 *node = (struct lysc_node *)&((struct lysc_action *)(*node)->parent)->output;
6621 }
6622 } else {
6623 /* move to next parent */
6624 *node = (*node)->parent;
6625 }
6626
6627 return 1;
6628}
6629
6630/**
6631 * @brief Check whether a node matches specific schema nodeid.
6632 *
6633 * @param[in] exp Parsed nodeid to match.
6634 * @param[in] exp_mod Module to use for nodes in @p exp without a prefix.
6635 * @param[in] ctx_node Initial context node that should match, only for descendant paths.
6636 * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched.
6637 * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled.
6638 * @param[in] pnode_mod Compiled @p pnode to-be module.
6639 * @return Whether it is a match or not.
6640 */
6641static ly_bool
6642lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lys_module *exp_mod, const struct lysc_node *ctx_node,
6643 const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod)
6644{
6645 uint32_t i;
6646 const struct lys_module *mod;
6647 const char *name;
6648 size_t name_len;
6649
6650 /* compare last node in the node ID */
6651 i = exp->used - 1;
6652
6653 /* get exp node ID module */
6654 mod = lys_schema_node_get_module(exp_mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_mod, &name, &name_len);
6655 assert(mod);
6656
6657 if (pnode) {
6658 /* compare on the last parsed-only node */
6659 if (!lysp_schema_nodeid_match_pnode(pnode, pnode_mod, mod, name, name_len)) {
6660 return 0;
6661 }
6662 } else {
6663 /* using parent directly */
6664 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6665 return 0;
6666 }
6667 }
6668
6669 /* now compare all the compiled parents */
6670 while (i > 1) {
6671 i -= 2;
6672 assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST);
6673
6674 if (!parent) {
6675 /* no more parents but path continues */
6676 return 0;
6677 }
6678
6679 /* get exp node ID module */
6680 mod = lys_schema_node_get_module(exp_mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_mod, &name,
6681 &name_len);
6682 assert(mod);
6683
6684 /* compare with the parent */
6685 if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) {
6686 return 0;
6687 }
6688 }
6689
6690 if (ctx_node && (ctx_node != parent)) {
6691 /* descendant path has not finished in the context node */
6692 return 0;
6693 } else if (!ctx_node && parent) {
6694 /* some parent was not matched */
6695 return 0;
6696 }
6697
6698 return 1;
6699}
6700
6701static void
6702lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug)
6703{
6704 if (aug) {
6705 lyxp_expr_free(ctx, aug->nodeid);
6706
6707 free(aug);
6708 }
6709}
6710
6711static void
6712lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev)
6713{
6714 if (dev) {
6715 lyxp_expr_free(ctx, dev->nodeid);
6716 LY_ARRAY_FREE(dev->devs);
6717 LY_ARRAY_FREE(dev->dev_mods);
6718
6719 free(dev);
6720 }
6721}
6722
6723static void
6724lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn)
6725{
6726 if (rfn) {
6727 lyxp_expr_free(ctx, rfn->nodeid);
6728 LY_ARRAY_FREE(rfn->rfns);
6729
6730 free(rfn);
6731 }
6732}
6733
6734static void
6735lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode)
6736{
6737 if (!dev_pnode) {
6738 return;
6739 }
6740
6741 switch (dev_pnode->nodetype) {
6742 case LYS_CONTAINER:
6743 ((struct lysp_node_container *)dev_pnode)->child = NULL;
6744 break;
6745 case LYS_LIST:
6746 ((struct lysp_node_list *)dev_pnode)->child = NULL;
6747 break;
6748 case LYS_CHOICE:
6749 ((struct lysp_node_choice *)dev_pnode)->child = NULL;
6750 break;
6751 case LYS_CASE:
6752 ((struct lysp_node_case *)dev_pnode)->child = NULL;
6753 break;
6754 case LYS_LEAF:
6755 case LYS_LEAFLIST:
6756 case LYS_ANYXML:
6757 case LYS_ANYDATA:
6758 /* no children */
6759 break;
6760 case LYS_NOTIF:
6761 ((struct lysp_notif *)dev_pnode)->data = NULL;
6762 lysp_notif_free((struct ly_ctx *)ctx, (struct lysp_notif *)dev_pnode);
6763 free(dev_pnode);
6764 return;
6765 case LYS_RPC:
6766 case LYS_ACTION:
6767 ((struct lysp_action *)dev_pnode)->input.data = NULL;
6768 ((struct lysp_action *)dev_pnode)->output.data = NULL;
6769 lysp_action_free((struct ly_ctx *)ctx, (struct lysp_action *)dev_pnode);
6770 free(dev_pnode);
6771 return;
6772 case LYS_INPUT:
6773 case LYS_OUTPUT:
6774 ((struct lysp_action_inout *)dev_pnode)->data = NULL;
6775 lysp_action_inout_free((struct ly_ctx *)ctx, (struct lysp_action_inout *)dev_pnode);
6776 free(dev_pnode);
6777 return;
6778 default:
6779 LOGINT(ctx);
6780 return;
6781 }
6782
6783 lysp_node_free((struct ly_ctx *)ctx, dev_pnode);
6784}
6785
6786/**
6787 * @brief Compile and apply any precompiled deviations and refines targetting a node.
6788 *
6789 * @param[in] ctx Compile context.
6790 * @param[in] pnode Parsed node to consider.
6791 * @param[in] parent First compiled parent of @p pnode.
6792 * @param[out] dev_pnode Copy of parsed node @p pnode with deviations and refines, if any. NULL if there are none.
6793 * @param[out] no_supported Whether a not-supported deviation is defined for the node.
6794 * @return LY_ERR value.
6795 */
6796static LY_ERR
6797lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent,
6798 struct lysp_node **dev_pnode, ly_bool *not_supported)
6799{
6800 LY_ERR ret = LY_SUCCESS;
6801 uint32_t i;
6802 LY_ARRAY_COUNT_TYPE u;
6803 struct lys_module *orig_mod = ctx->mod, *orig_mod_def = ctx->mod_def;
6804 char orig_path[LYSC_CTX_BUFSIZE];
6805 struct lysc_refine *rfn;
6806 struct lysc_deviation *dev;
6807 struct lysp_deviation *dev_p;
6808 struct lysp_deviate *d;
6809
6810 *dev_pnode = NULL;
6811 *not_supported = 0;
6812
6813 for (i = 0; i < ctx->uses_rfns.count; ++i) {
6814 rfn = ctx->uses_rfns.objs[i];
6815
6816 if (!lysp_schema_nodeid_match(rfn->nodeid, ctx->mod, rfn->nodeid_ctx_node, parent, pnode, ctx->mod)) {
6817 /* not our target node */
6818 continue;
6819 }
6820
6821 if (!*dev_pnode) {
6822 /* first refine on this node, create a copy first */
6823 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6824 }
6825
6826 /* apply all the refines by changing (the copy of) the parsed node */
6827 LY_ARRAY_FOR(rfn->rfns, u) {
6828 /* apply refine, keep the current path and add to it */
6829 lysc_update_path(ctx, NULL, "{refine}");
6830 lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid);
6831 ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode);
6832 lysc_update_path(ctx, NULL, NULL);
6833 lysc_update_path(ctx, NULL, NULL);
6834 LY_CHECK_GOTO(ret, cleanup);
6835 }
6836
6837 /* refine was applied, remove it */
6838 lysc_refine_free(ctx->ctx, rfn);
6839 ly_set_rm_index(&ctx->uses_rfns, i, NULL);
6840
6841 /* all the refines for one target node are in one structure, we are done */
6842 break;
6843 }
6844
6845 for (i = 0; i < ctx->devs.count; ++i) {
6846 dev = ctx->devs.objs[i];
6847
6848 if (!lysp_schema_nodeid_match(dev->nodeid, dev->nodeid_mod, NULL, parent, pnode, ctx->mod_def)) {
6849 /* not our target node */
6850 continue;
6851 }
6852
6853 if (dev->not_supported) {
6854 /* it is not supported, no more deviations */
6855 *not_supported = 1;
6856 goto dev_applied;
6857 }
6858
6859 if (!*dev_pnode) {
6860 /* first deviation on this node, create a copy first */
6861 LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup);
6862 }
6863
6864 /* apply all the deviates by changing (the copy of) the parsed node */
6865 LY_ARRAY_FOR(dev->devs, u) {
6866 dev_p = dev->devs[u];
6867 LY_LIST_FOR(dev_p->deviates, d) {
6868 /* generate correct path */
6869 strcpy(orig_path, ctx->path);
6870 ctx->path_len = 1;
6871 ctx->mod = (struct lys_module *)dev->dev_mods[u];
6872 ctx->mod_def = (struct lys_module *)dev->dev_mods[u];
6873 lysc_update_path(ctx, NULL, "{deviation}");
6874 lysc_update_path(ctx, NULL, dev_p->nodeid);
6875
6876 switch (d->mod) {
6877 case LYS_DEV_ADD:
6878 ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode);
6879 break;
6880 case LYS_DEV_DELETE:
6881 ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode);
6882 break;
6883 case LYS_DEV_REPLACE:
6884 ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode);
6885 break;
6886 default:
6887 LOGINT(ctx->ctx);
6888 ret = LY_EINT;
6889 }
6890
6891 /* restore previous path */
6892 strcpy(ctx->path, orig_path);
6893 ctx->path_len = strlen(ctx->path);
6894 ctx->mod = orig_mod;
6895 ctx->mod_def = orig_mod_def;
6896
6897 LY_CHECK_GOTO(ret, cleanup);
6898 }
6899 }
6900
6901dev_applied:
6902 /* deviation was applied, remove it */
6903 lysc_deviation_free(ctx->ctx, dev);
6904 ly_set_rm_index(&ctx->devs, i, NULL);
6905
6906 /* all the deviations for one target node are in one structure, we are done */
6907 break;
6908 }
6909
6910cleanup:
6911 if (ret) {
6912 lysp_dev_node_free(ctx->ctx, *dev_pnode);
6913 *dev_pnode = NULL;
6914 *not_supported = 0;
6915 }
6916 return ret;
6917}
6918
6919/**
6920 * @brief Compile and apply any precompiled top-level or uses augments targetting a node.
6921 *
6922 * @param[in] ctx Compile context.
6923 * @param[in] node Compiled node to consider.
6924 * @return LY_ERR value.
6925 */
6926static LY_ERR
6927lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node)
6928{
6929 LY_ERR ret = LY_SUCCESS;
6930 struct lys_module *orig_mod = ctx->mod, *orig_mod_def = ctx->mod_def;
6931 uint32_t i;
6932 char orig_path[LYSC_CTX_BUFSIZE];
6933 struct lysc_augment *aug;
6934
6935 /* uses augments */
6936 for (i = 0; i < ctx->uses_augs.count; ) {
6937 aug = ctx->uses_augs.objs[i];
6938
6939 if (!lysp_schema_nodeid_match(aug->nodeid, ctx->mod, aug->nodeid_ctx_node, node, NULL, NULL)) {
6940 /* not our target node */
6941 ++i;
6942 continue;
6943 }
6944
6945 /* apply augment, keep the current path and add to it */
6946 lysc_update_path(ctx, NULL, "{augment}");
6947 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
6948 ret = lys_compile_augment(ctx, aug->aug_p, node);
6949 lysc_update_path(ctx, NULL, NULL);
6950 lysc_update_path(ctx, NULL, NULL);
6951 LY_CHECK_GOTO(ret, cleanup);
6952
6953 /* augment was applied, remove it (index may have changed because other augments could have been applied) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02006954 ly_set_rm(&ctx->uses_augs, aug, NULL);
Michal Vaskoaf702452020-10-02 09:02:55 +02006955 lysc_augment_free(ctx->ctx, aug);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006956 }
6957
6958 /* top-level augments */
6959 for (i = 0; i < ctx->augs.count; ) {
6960 aug = ctx->augs.objs[i];
6961
6962 if (!lysp_schema_nodeid_match(aug->nodeid, aug->nodeid_mod, NULL, node, NULL, NULL)) {
6963 /* not our target node */
6964 ++i;
6965 continue;
6966 }
6967
6968 /* apply augment, use the path and modules from the augment */
6969 strcpy(orig_path, ctx->path);
6970 ctx->path_len = 1;
6971 lysc_update_path(ctx, NULL, "{augment}");
6972 lysc_update_path(ctx, NULL, aug->aug_p->nodeid);
6973 ctx->mod = (struct lys_module *)aug->nodeid_mod;
6974 ctx->mod_def = (struct lys_module *)aug->nodeid_mod;
6975 ret = lys_compile_augment(ctx, aug->aug_p, node);
6976 strcpy(ctx->path, orig_path);
6977 ctx->path_len = strlen(ctx->path);
6978 LY_CHECK_GOTO(ret, cleanup);
6979
6980 /* augment was applied, remove it */
Michal Vasko7f45cf22020-10-01 12:49:44 +02006981 ly_set_rm(&ctx->augs, aug, NULL);
Michal Vaskoaf702452020-10-02 09:02:55 +02006982 lysc_augment_free(ctx->ctx, aug);
Michal Vasko7f45cf22020-10-01 12:49:44 +02006983 }
6984
6985cleanup:
6986 ctx->mod = orig_mod;
6987 ctx->mod_def = orig_mod_def;
6988 return ret;
6989}
6990
6991/**
6992 * @brief Prepare a top-level augment to be applied during data nodes compilation.
6993 *
6994 * @param[in] ctx Compile context.
6995 * @param[in] aug_p Parsed augment to be applied.
6996 * @param[in] mod_def Local module for @p aug_p.
6997 * @return LY_ERR value.
6998 */
6999static LY_ERR
7000lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_augment *aug_p, const struct lys_module *mod_def)
7001{
7002 LY_ERR ret = LY_SUCCESS;
7003 struct lyxp_expr *exp = NULL;
7004 struct lysc_augment *aug;
7005 const struct lys_module *mod;
7006
7007 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
7008 ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp);
7009 LY_CHECK_GOTO(ret, cleanup);
7010
7011 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], mod_def, NULL, NULL);
7012 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
7013 if (mod != ctx->mod) {
7014 /* augment for another module, ignore */
7015 goto cleanup;
7016 }
7017
7018 /* allocate new compiled augment and store it in the set */
7019 aug = calloc(1, sizeof *aug);
7020 LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02007021 LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007022
7023 aug->nodeid = exp;
7024 exp = NULL;
7025 aug->nodeid_mod = mod_def;
7026 aug->aug_p = aug_p;
7027
7028cleanup:
7029 lyxp_expr_free(ctx->ctx, exp);
7030 return ret;
7031}
7032
7033/**
7034 * @brief Prepare all top-level augments for the current module to be applied during data nodes compilation.
7035 *
7036 * @param[in] ctx Compile context.
7037 * @return LY_ERR value.
7038 */
7039static LY_ERR
7040lys_precompile_own_augments(struct lysc_ctx *ctx)
7041{
7042 LY_ARRAY_COUNT_TYPE u, v, w;
7043 const struct lys_module *aug_mod;
7044
7045 LY_ARRAY_FOR(ctx->mod->augmented_by, u) {
7046 aug_mod = ctx->mod->augmented_by[u];
7047
7048 /* collect all module augments */
7049 LY_ARRAY_FOR(aug_mod->parsed->augments, v) {
7050 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->augments[v], aug_mod));
7051 }
7052
7053 /* collect all submodules augments */
7054 LY_ARRAY_FOR(aug_mod->parsed->includes, v) {
7055 LY_ARRAY_FOR(aug_mod->parsed->includes[v].submodule->augments, w) {
7056 LY_CHECK_RET(lys_precompile_own_augment(ctx, &aug_mod->parsed->includes[v].submodule->augments[w], aug_mod));
7057 }
7058 }
7059 }
7060
7061 return LY_SUCCESS;
7062}
7063
7064/**
7065 * @brief Prepare a deviation to be applied during data nodes compilation.
7066 *
7067 * @param[in] ctx Compile context.
7068 * @param[in] dev_p Parsed deviation to be applied.
7069 * @param[in] mod_def Local module for @p dev_p.
7070 * @return LY_ERR value.
7071 */
7072static LY_ERR
7073lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lys_module *mod_def)
7074{
7075 LY_ERR ret = LY_SUCCESS;
7076 struct lysc_deviation *dev = NULL;
7077 struct lyxp_expr *exp = NULL;
7078 struct lysp_deviation **new_dev;
7079 const struct lys_module *mod, **new_dev_mod;
7080 uint32_t i;
7081
7082 /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */
7083 ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp);
7084 LY_CHECK_GOTO(ret, cleanup);
7085
7086 mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], mod_def, NULL, NULL);
7087 LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup);
7088 if (mod != ctx->mod) {
7089 /* deviation for another module, ignore */
7090 goto cleanup;
7091 }
7092
7093 /* try to find the node in already compiled deviations */
7094 for (i = 0; i < ctx->devs.count; ++i) {
7095 if (lys_abs_schema_nodeid_match(ctx->ctx, exp, mod_def, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid,
7096 ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid_mod)) {
7097 dev = ctx->devs.objs[i];
7098 break;
7099 }
7100 }
7101
7102 if (!dev) {
7103 /* allocate new compiled deviation */
7104 dev = calloc(1, sizeof *dev);
7105 LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci3d92e442020-10-12 12:48:13 +02007106 LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007107
7108 dev->nodeid = exp;
7109 exp = NULL;
7110 dev->nodeid_mod = mod_def;
7111 }
7112
7113 /* add new parsed deviation structure */
7114 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup);
7115 *new_dev = dev_p;
7116 LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_mods, new_dev_mod, ret, cleanup);
7117 *new_dev_mod = mod_def;
7118
7119cleanup:
7120 lyxp_expr_free(ctx->ctx, exp);
7121 return ret;
7122}
7123
7124/**
7125 * @brief Prepare all deviations for the current module to be applied during data nodes compilation.
7126 *
7127 * @param[in] ctx Compile context.
7128 * @return LY_ERR value.
7129 */
7130static LY_ERR
7131lys_precompile_own_deviations(struct lysc_ctx *ctx)
7132{
7133 LY_ARRAY_COUNT_TYPE u, v, w;
7134 const struct lys_module *dev_mod;
7135 struct lysc_deviation *dev;
7136 struct lysp_deviate *d;
7137 int not_supported;
7138 uint32_t i;
7139
7140 LY_ARRAY_FOR(ctx->mod->deviated_by, u) {
7141 dev_mod = ctx->mod->deviated_by[u];
7142
7143 /* compile all module deviations */
7144 LY_ARRAY_FOR(dev_mod->parsed->deviations, v) {
7145 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod));
7146 }
7147
7148 /* compile all submodules deviations */
7149 LY_ARRAY_FOR(dev_mod->parsed->includes, v) {
7150 LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) {
7151 LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w], dev_mod));
7152 }
7153 }
7154 }
7155
7156 /* set not-supported flags for all the deviations */
7157 for (i = 0; i < ctx->devs.count; ++i) {
7158 dev = ctx->devs.objs[i];
7159 not_supported = 0;
7160
7161 LY_ARRAY_FOR(dev->devs, u) {
7162 LY_LIST_FOR(dev->devs[u]->deviates, d) {
7163 if (d->mod == LYS_DEV_NOT_SUPPORTED) {
7164 not_supported = 1;
7165 break;
7166 }
7167 }
7168 if (not_supported) {
7169 break;
7170 }
7171 }
7172 if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) {
7173 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
7174 "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr);
7175 return LY_EVALID;
7176 }
7177
7178 dev->not_supported = not_supported;
7179 }
7180
7181 return LY_SUCCESS;
7182}
7183
Michal Vasko20424b42020-08-31 12:29:38 +02007184/**
Radek Krejcia3045382018-11-22 14:30:31 +01007185 * @brief Compile parsed schema node information.
7186 * @param[in] ctx Compile context
Michal Vasko7f45cf22020-10-01 12:49:44 +02007187 * @param[in] pnode Parsed schema node.
Radek Krejcia3045382018-11-22 14:30:31 +01007188 * @param[in] parent Compiled parent node where the current node is supposed to be connected. It is
7189 * NULL for top-level nodes, in such a case the module where the node will be connected is taken from
7190 * the compile context.
Radek Krejcib1b59152019-01-07 13:21:56 +01007191 * @param[in] uses_status If the node is being placed instead of uses, here we have the uses's status value (as node's flags).
7192 * Zero means no uses, non-zero value with no status bit set mean the default status.
Radek Krejcia3045382018-11-22 14:30:31 +01007193 * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
7194 */
Radek Krejci19a96102018-11-15 13:38:09 +01007195static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007196lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *pnode, struct lysc_node *parent, uint16_t uses_status,
7197 struct ly_set *child_set)
Radek Krejci19a96102018-11-15 13:38:09 +01007198{
Radek Krejci1c54f462020-05-12 17:25:34 +02007199 LY_ERR ret = LY_SUCCESS;
Radek Krejcic6b4f442020-08-12 14:45:18 +02007200 struct lysc_node *node = NULL;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007201 struct lysp_node *dev_pnode = NULL, *orig_pnode = pnode;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007202 LY_ARRAY_COUNT_TYPE u;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007203 ly_bool not_supported;
Michal Vasko69730152020-10-09 16:30:07 +02007204
Michal Vasko22df3f02020-08-24 13:29:22 +02007205 LY_ERR (*node_compile_spec)(struct lysc_ctx *, struct lysp_node *, struct lysc_node *);
Radek Krejci19a96102018-11-15 13:38:09 +01007206
Michal Vasko7f45cf22020-10-01 12:49:44 +02007207 if (pnode->nodetype != LYS_USES) {
7208 lysc_update_path(ctx, parent, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02007209 } else {
7210 lysc_update_path(ctx, NULL, "{uses}");
Michal Vasko7f45cf22020-10-01 12:49:44 +02007211 lysc_update_path(ctx, NULL, pnode->name);
Radek Krejci327de162019-06-14 12:52:07 +02007212 }
7213
Michal Vasko7f45cf22020-10-01 12:49:44 +02007214 switch (pnode->nodetype) {
Radek Krejci19a96102018-11-15 13:38:09 +01007215 case LYS_CONTAINER:
Michal Vasko22df3f02020-08-24 13:29:22 +02007216 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_container));
Radek Krejci19a96102018-11-15 13:38:09 +01007217 node_compile_spec = lys_compile_node_container;
7218 break;
7219 case LYS_LEAF:
Michal Vasko22df3f02020-08-24 13:29:22 +02007220 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaf));
Radek Krejci19a96102018-11-15 13:38:09 +01007221 node_compile_spec = lys_compile_node_leaf;
7222 break;
7223 case LYS_LIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02007224 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_list));
Radek Krejci9bb94eb2018-12-04 16:48:35 +01007225 node_compile_spec = lys_compile_node_list;
Radek Krejci19a96102018-11-15 13:38:09 +01007226 break;
7227 case LYS_LEAFLIST:
Michal Vasko22df3f02020-08-24 13:29:22 +02007228 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_leaflist));
Radek Krejci0e5d8382018-11-28 16:37:53 +01007229 node_compile_spec = lys_compile_node_leaflist;
Radek Krejci19a96102018-11-15 13:38:09 +01007230 break;
Radek Krejci19a96102018-11-15 13:38:09 +01007231 case LYS_CHOICE:
Michal Vasko22df3f02020-08-24 13:29:22 +02007232 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_choice));
Radek Krejci056d0a82018-12-06 16:57:25 +01007233 node_compile_spec = lys_compile_node_choice;
Radek Krejci19a96102018-11-15 13:38:09 +01007234 break;
Michal Vasko891d7532020-10-07 09:41:38 +02007235 case LYS_CASE:
Michal Vasko20424b42020-08-31 12:29:38 +02007236 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_case));
7237 node_compile_spec = lys_compile_node_case;
7238 break;
Radek Krejci19a96102018-11-15 13:38:09 +01007239 case LYS_ANYXML:
7240 case LYS_ANYDATA:
Michal Vasko22df3f02020-08-24 13:29:22 +02007241 node = (struct lysc_node *)calloc(1, sizeof(struct lysc_node_anydata));
Radek Krejci9800fb82018-12-13 14:26:23 +01007242 node_compile_spec = lys_compile_node_any;
Radek Krejci19a96102018-11-15 13:38:09 +01007243 break;
Radek Krejcie86bf772018-12-14 11:39:53 +01007244 case LYS_USES:
Michal Vasko7f45cf22020-10-01 12:49:44 +02007245 ret = lys_compile_uses(ctx, (struct lysp_node_uses *)pnode, parent, child_set);
Radek Krejci327de162019-06-14 12:52:07 +02007246 lysc_update_path(ctx, NULL, NULL);
7247 lysc_update_path(ctx, NULL, NULL);
7248 return ret;
Radek Krejci19a96102018-11-15 13:38:09 +01007249 default:
7250 LOGINT(ctx->ctx);
7251 return LY_EINT;
7252 }
7253 LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007254
7255 /* compile any deviations for this node */
7256 LY_CHECK_ERR_RET(ret = lys_compile_node_deviations_refines(ctx, pnode, parent, &dev_pnode, &not_supported),
7257 free(node), ret);
7258 if (not_supported) {
7259 free(node);
7260 lysc_update_path(ctx, NULL, NULL);
7261 return LY_SUCCESS;
7262 } else if (dev_pnode) {
7263 pnode = dev_pnode;
7264 }
7265
7266 node->nodetype = pnode->nodetype;
Radek Krejci19a96102018-11-15 13:38:09 +01007267 node->module = ctx->mod;
7268 node->prev = node;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007269 node->flags = pnode->flags & LYS_FLAGS_COMPILED_MASK;
Radek Krejci19a96102018-11-15 13:38:09 +01007270
7271 /* config */
Michal Vasko20424b42020-08-31 12:29:38 +02007272 ret = lys_compile_config(ctx, node, parent);
7273 LY_CHECK_GOTO(ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007274
Michal Vasko20424b42020-08-31 12:29:38 +02007275 /* list ordering */
Radek Krejcia6d57732018-11-29 13:40:37 +01007276 if (node->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
7277 if ((node->flags & LYS_CONFIG_R) && (node->flags & LYS_ORDBY_MASK)) {
Radek Krejcifc11bd72019-04-11 16:00:05 +02007278 LOGWRN(ctx->ctx, "The ordered-by statement is ignored in lists representing %s (%s).",
Radek Krejci90d4e922020-10-12 15:55:33 +02007279 (ctx->options & LYS_COMPILE_RPC_OUTPUT) ? "RPC/action output parameters" :
7280 (ctx->options & LYS_COMPILE_NOTIFICATION) ? "notification content" : "state data", ctx->path);
Radek Krejcia6d57732018-11-29 13:40:37 +01007281 node->flags &= ~LYS_ORDBY_MASK;
7282 node->flags |= LYS_ORDBY_SYSTEM;
7283 } else if (!(node->flags & LYS_ORDBY_MASK)) {
7284 /* default ordering is system */
7285 node->flags |= LYS_ORDBY_SYSTEM;
7286 }
7287 }
7288
Radek Krejci19a96102018-11-15 13:38:09 +01007289 /* status - it is not inherited by specification, but it does not make sense to have
7290 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
Michal Vasko20424b42020-08-31 12:29:38 +02007291 LY_CHECK_GOTO(ret = lys_compile_status(ctx, &node->flags, uses_status ? uses_status : (parent ? parent->flags : 0)), error);
Radek Krejci19a96102018-11-15 13:38:09 +01007292
Radek Krejci90d4e922020-10-12 15:55:33 +02007293 node->sp = orig_pnode;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007294 DUP_STRING_GOTO(ctx->ctx, pnode->name, node->name, ret, error);
7295 DUP_STRING_GOTO(ctx->ctx, pnode->dsc, node->dsc, ret, error);
7296 DUP_STRING_GOTO(ctx->ctx, pnode->ref, node->ref, ret, error);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007297 COMPILE_ARRAY_GOTO(ctx, pnode->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01007298
Michal Vasko20424b42020-08-31 12:29:38 +02007299 /* insert into parent's children/compiled module (we can no longer free the node separately on error) */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007300 LY_CHECK_GOTO(ret = lys_compile_node_connect(ctx, parent, node), cleanup);
7301
Michal Vasko4865ac42020-10-12 16:31:06 +02007302 if (pnode->when) {
7303 /* compile when */
7304 ret = lys_compile_when(ctx, pnode->when, pnode->flags, lysc_xpath_context(node), node, NULL);
7305 LY_CHECK_GOTO(ret, cleanup);
7306 }
7307
Michal Vasko7f45cf22020-10-01 12:49:44 +02007308 /* connect any augments */
7309 LY_CHECK_GOTO(ret = lys_compile_node_augments(ctx, node), cleanup);
Michal Vasko20424b42020-08-31 12:29:38 +02007310
Radek Krejci19a96102018-11-15 13:38:09 +01007311 /* nodetype-specific part */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007312 LY_CHECK_GOTO(ret = node_compile_spec(ctx, pnode, node), cleanup);
Radek Krejci19a96102018-11-15 13:38:09 +01007313
Michal Vasko20424b42020-08-31 12:29:38 +02007314 /* final compilation tasks that require the node to be connected */
Michal Vasko7f45cf22020-10-01 12:49:44 +02007315 COMPILE_EXTS_GOTO(ctx, pnode->exts, node->exts, node, LYEXT_PAR_NODE, ret, cleanup);
Radek Krejcife909632019-02-12 15:34:42 +01007316 if (node->flags & LYS_MAND_TRUE) {
Michal Vasko20424b42020-08-31 12:29:38 +02007317 /* inherit LYS_MAND_TRUE in parent containers */
Radek Krejcife909632019-02-12 15:34:42 +01007318 lys_compile_mandatory_parents(parent, 1);
7319 }
7320
Michal Vasko7f45cf22020-10-01 12:49:44 +02007321 if (child_set) {
7322 /* add the new node into set */
Radek Krejci3d92e442020-10-12 12:48:13 +02007323 LY_CHECK_GOTO(ret = ly_set_add(child_set, node, 1, NULL), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007324 }
7325
Radek Krejci327de162019-06-14 12:52:07 +02007326 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007327 lysp_dev_node_free(ctx->ctx, dev_pnode);
Radek Krejci19a96102018-11-15 13:38:09 +01007328 return LY_SUCCESS;
7329
7330error:
7331 lysc_node_free(ctx->ctx, node);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007332cleanup:
7333 if (dev_pnode) {
7334 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_OTHER, "Compilation of a deviated and/or refined node failed.");
7335 lysp_dev_node_free(ctx->ctx, dev_pnode);
7336 }
Radek Krejci19a96102018-11-15 13:38:09 +01007337 return ret;
7338}
7339
Michal Vaskoccc062a2020-08-13 08:34:50 +02007340/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007341 * @brief Add a module reference into an array, checks for duplicities.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007342 *
7343 * @param[in] ctx Compile context.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007344 * @param[in] mod Module reference to add.
7345 * @param[in,out] mod_array Module sized array to add to.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007346 * @return LY_ERR value.
7347 */
7348static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007349lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007350{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007351 LY_ARRAY_COUNT_TYPE u;
7352 struct lys_module **new_mod;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007353
Michal Vasko7f45cf22020-10-01 12:49:44 +02007354 LY_ARRAY_FOR(*mod_array, u) {
7355 if ((*mod_array)[u] == mod) {
7356 /* already there */
7357 return LY_EEXIST;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007358 }
7359 }
7360
Michal Vasko7f45cf22020-10-01 12:49:44 +02007361 /* add the new module ref */
7362 LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM);
7363 *new_mod = mod;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007364
7365 return LY_SUCCESS;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007366}
7367
Michal Vaskoccc062a2020-08-13 08:34:50 +02007368/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007369 * @brief Compile top-level augments and deviations defined in the current module.
Michal Vasko89b5c072020-10-06 13:52:44 +02007370 * Generally, just add the module refence to the target modules. But in case
7371 * of foreign augments, they are directly applied.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007372 *
7373 * @param[in] ctx Compile context.
Michal Vaskoccc062a2020-08-13 08:34:50 +02007374 * @return LY_ERR value.
7375 */
7376static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02007377lys_precompile_augments_deviations(struct lysc_ctx *ctx)
Michal Vaskoccc062a2020-08-13 08:34:50 +02007378{
Michal Vasko7f45cf22020-10-01 12:49:44 +02007379 LY_ERR ret = LY_SUCCESS;
7380 LY_ARRAY_COUNT_TYPE u, v;
7381 const struct lysp_module *mod_p;
7382 const struct lysc_node *target;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007383 struct lys_module *mod;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007384 struct lysp_submodule *submod;
7385 ly_bool has_dev = 0;
7386 uint16_t flags;
7387 uint32_t idx, opt_prev = ctx->options;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007388
Michal Vasko89b5c072020-10-06 13:52:44 +02007389 for (idx = 0; idx < ctx->ctx->implementing.count; ++idx) {
7390 if (ctx->mod == ctx->ctx->implementing.objs[idx]) {
7391 break;
7392 }
7393 }
7394 if (idx == ctx->ctx->implementing.count) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02007395 /* it was already implemented and all the augments and deviations fully applied */
7396 return LY_SUCCESS;
Michal Vaskoccc062a2020-08-13 08:34:50 +02007397 }
7398
Michal Vasko89b5c072020-10-06 13:52:44 +02007399 mod_p = ctx->mod->parsed;
7400
Michal Vasko7f45cf22020-10-01 12:49:44 +02007401 LY_ARRAY_FOR(mod_p->augments, u) {
7402 lysc_update_path(ctx, NULL, "{augment}");
7403 lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007404
Michal Vasko7f45cf22020-10-01 12:49:44 +02007405 /* get target module */
7406 ret = lys_nodeid_check(ctx, mod_p->augments[u].nodeid, 1, &mod, NULL);
7407 LY_CHECK_RET(ret);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007408
Michal Vasko7f45cf22020-10-01 12:49:44 +02007409 /* add this module into the target module augmented_by, if not there already from previous augments */
7410 lys_array_add_mod_ref(ctx, ctx->mod, &mod->augmented_by);
Michal Vaskoccc062a2020-08-13 08:34:50 +02007411
Michal Vasko7f45cf22020-10-01 12:49:44 +02007412 /* if we are compiling this module, we cannot add augments to it yet */
7413 if (mod != ctx->mod) {
7414 /* apply the augment, find the target node first */
7415 flags = 0;
7416 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->mod_def, 0, &target, &flags);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02007417 LY_CHECK_RET(ret);
7418
Michal Vasko7f45cf22020-10-01 12:49:44 +02007419 /* apply the augment */
7420 ctx->options |= flags;
7421 ret = lys_compile_augment(ctx, &mod_p->augments[u], (struct lysc_node *)target);
7422 ctx->options = opt_prev;
7423 LY_CHECK_RET(ret);
Radek Krejciccd20f12019-02-15 14:12:27 +01007424 }
Radek Krejci327de162019-06-14 12:52:07 +02007425
7426 lysc_update_path(ctx, NULL, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007427 lysc_update_path(ctx, NULL, NULL);
Radek Krejciccd20f12019-02-15 14:12:27 +01007428 }
7429
Michal Vasko7f45cf22020-10-01 12:49:44 +02007430 LY_ARRAY_FOR(mod_p->deviations, u) {
7431 /* get target module */
7432 lysc_update_path(ctx, NULL, "{deviation}");
7433 lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid);
7434 ret = lys_nodeid_check(ctx, mod_p->deviations[u].nodeid, 1, &mod, NULL);
7435 lysc_update_path(ctx, NULL, NULL);
7436 lysc_update_path(ctx, NULL, NULL);
7437 LY_CHECK_RET(ret);
Radek Krejciba03a5a2020-08-27 14:40:41 +02007438
Michal Vasko7f45cf22020-10-01 12:49:44 +02007439 /* add this module into the target module deviated_by, if not there already from previous deviations */
7440 lys_array_add_mod_ref(ctx, ctx->mod, &mod->deviated_by);
7441
7442 /* new deviation added to the target module */
7443 has_dev = 1;
7444 }
7445
7446 /* the same for augments and deviations in submodules */
7447 LY_ARRAY_FOR(mod_p->includes, v) {
7448 submod = mod_p->includes[v].submodule;
7449 LY_ARRAY_FOR(submod->augments, u) {
7450 lysc_update_path(ctx, NULL, "{augment}");
7451 lysc_update_path(ctx, NULL, submod->augments[u].nodeid);
7452
7453 ret = lys_nodeid_check(ctx, submod->augments[u].nodeid, 1, &mod, NULL);
7454 LY_CHECK_RET(ret);
7455
7456 lys_array_add_mod_ref(ctx, ctx->mod, &mod->augmented_by);
7457 if (mod != ctx->mod) {
7458 flags = 0;
7459 ret = lysc_resolve_schema_nodeid(ctx, mod_p->augments[u].nodeid, 0, NULL, ctx->mod_def, 0, &target, &flags);
7460 LY_CHECK_RET(ret);
7461
7462 ctx->options |= flags;
7463 ret = lys_compile_augment(ctx, &submod->augments[u], (struct lysc_node *)target);
7464 ctx->options = opt_prev;
7465 LY_CHECK_RET(ret);
Radek Krejcif538ce52019-03-05 10:46:14 +01007466 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007467
7468 lysc_update_path(ctx, NULL, NULL);
7469 lysc_update_path(ctx, NULL, NULL);
Radek Krejcif538ce52019-03-05 10:46:14 +01007470 }
7471
Michal Vasko7f45cf22020-10-01 12:49:44 +02007472 LY_ARRAY_FOR(submod->deviations, u) {
7473 lysc_update_path(ctx, NULL, "{deviation}");
7474 lysc_update_path(ctx, NULL, submod->deviations[u].nodeid);
7475 ret = lys_nodeid_check(ctx, submod->deviations[u].nodeid, 1, &mod, NULL);
7476 lysc_update_path(ctx, NULL, NULL);
7477 lysc_update_path(ctx, NULL, NULL);
7478 LY_CHECK_RET(ret);
Radek Krejcifc11bd72019-04-11 16:00:05 +02007479
Michal Vasko7f45cf22020-10-01 12:49:44 +02007480 lys_array_add_mod_ref(ctx, ctx->mod, &mod->deviated_by);
7481 has_dev = 1;
Michal Vaskoe6143202020-07-03 13:02:08 +02007482 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007483 }
7484
Michal Vasko7f45cf22020-10-01 12:49:44 +02007485 if (!has_dev) {
7486 /* no need to recompile any modules */
7487 return LY_SUCCESS;
7488 }
7489
7490 /* free all the modules in descending order */
7491 idx = ctx->ctx->list.count;
7492 do {
7493 --idx;
7494 mod = ctx->ctx->list.objs[idx];
7495 /* skip this module */
7496 if (mod == mod_p->mod) {
7497 continue;
7498 }
7499
7500 if (mod->implemented && mod->compiled) {
7501 /* keep information about features state in the module */
7502 lys_feature_precompile_revert(ctx, mod);
7503
7504 /* free the module */
7505 lysc_module_free(mod->compiled, NULL);
7506 mod->compiled = NULL;
7507 }
7508 } while (idx);
7509
7510 /* recompile all the modules in ascending order */
7511 for (idx = 0; idx < ctx->ctx->list.count; ++idx) {
7512 mod = ctx->ctx->list.objs[idx];
7513
7514 /* skip this module */
7515 if (mod == mod_p->mod) {
7516 continue;
7517 }
7518
7519 if (mod->implemented) {
7520 /* compile */
Michal Vasko89b5c072020-10-06 13:52:44 +02007521 LY_CHECK_GOTO(ret = lys_compile(mod, 0), cleanup);
Michal Vasko7f45cf22020-10-01 12:49:44 +02007522 }
7523 }
Radek Krejciccd20f12019-02-15 14:12:27 +01007524
7525cleanup:
Radek Krejcid05cbd92018-12-05 14:26:40 +01007526 return ret;
7527}
7528
Radek Krejci335332a2019-09-05 13:03:35 +02007529static void *
7530lys_compile_extension_instance_storage(enum ly_stmt stmt, struct lysc_ext_substmt *substmts)
7531{
Radek Krejci1deb5be2020-08-26 16:43:36 +02007532 for (LY_ARRAY_COUNT_TYPE u = 0; substmts[u].stmt; ++u) {
Radek Krejci335332a2019-09-05 13:03:35 +02007533 if (substmts[u].stmt == stmt) {
7534 return substmts[u].storage;
7535 }
7536 }
7537 return NULL;
7538}
7539
7540LY_ERR
7541lys_compile_extension_instance(struct lysc_ctx *ctx, const struct lysp_ext_instance *ext, struct lysc_ext_substmt *substmts)
7542{
7543 LY_ERR ret = LY_EVALID, r;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007544 LY_ARRAY_COUNT_TYPE u;
Radek Krejci335332a2019-09-05 13:03:35 +02007545 struct lysp_stmt *stmt;
Michal Vasko7f45cf22020-10-01 12:49:44 +02007546 struct lysp_qname qname;
Radek Krejci335332a2019-09-05 13:03:35 +02007547 void *parsed = NULL, **compiled = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007548
7549 /* check for invalid substatements */
7550 for (stmt = ext->child; stmt; stmt = stmt->next) {
Radek Krejcif56e2a42019-09-09 14:15:25 +02007551 if (stmt->flags & (LYS_YIN_ATTR | LYS_YIN_ARGUMENT)) {
7552 continue;
7553 }
Radek Krejci335332a2019-09-05 13:03:35 +02007554 for (u = 0; substmts[u].stmt; ++u) {
7555 if (substmts[u].stmt == stmt->kw) {
7556 break;
7557 }
7558 }
7559 if (!substmts[u].stmt) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007560 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s%s%s\" extension instance.",
Michal Vasko69730152020-10-09 16:30:07 +02007561 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007562 goto cleanup;
7563 }
Radek Krejci335332a2019-09-05 13:03:35 +02007564 }
7565
Radek Krejciad5963b2019-09-06 16:03:05 +02007566 /* TODO store inherited data, e.g. status first, but mark them somehow to allow to overwrite them and not detect duplicity */
7567
Radek Krejci335332a2019-09-05 13:03:35 +02007568 /* keep order of the processing the same as the order in the defined substmts,
7569 * the order is important for some of the statements depending on others (e.g. type needs status and units) */
7570 for (u = 0; substmts[u].stmt; ++u) {
Radek Krejci857189e2020-09-01 13:26:36 +02007571 ly_bool stmt_present = 0;
Radek Krejciad5963b2019-09-06 16:03:05 +02007572
Radek Krejci335332a2019-09-05 13:03:35 +02007573 for (stmt = ext->child; stmt; stmt = stmt->next) {
7574 if (substmts[u].stmt != stmt->kw) {
7575 continue;
7576 }
7577
Radek Krejciad5963b2019-09-06 16:03:05 +02007578 stmt_present = 1;
Radek Krejci335332a2019-09-05 13:03:35 +02007579 if (substmts[u].storage) {
7580 switch (stmt->kw) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007581 case LY_STMT_STATUS:
7582 assert(substmts[u].cardinality < LY_STMT_CARD_SOME);
7583 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &substmts[u].storage, /* TODO */ NULL), ret = r, cleanup);
7584 break;
7585 case LY_STMT_UNITS: {
7586 const char **units;
7587
7588 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7589 /* single item */
7590 if (*((const char **)substmts[u].storage)) {
7591 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7592 goto cleanup;
7593 }
7594 units = (const char **)substmts[u].storage;
7595 } else {
7596 /* sized array */
7597 const char ***units_array = (const char ***)substmts[u].storage;
7598 LY_ARRAY_NEW_GOTO(ctx->ctx, *units_array, units, ret, cleanup);
7599 }
Radek Krejci011e4aa2020-09-04 15:22:31 +02007600 r = lydict_insert(ctx->ctx, stmt->arg, 0, units);
7601 LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007602 break;
7603 }
Radek Krejci335332a2019-09-05 13:03:35 +02007604 case LY_STMT_TYPE: {
7605 uint16_t *flags = lys_compile_extension_instance_storage(LY_STMT_STATUS, substmts);
7606 const char **units = lys_compile_extension_instance_storage(LY_STMT_UNITS, substmts);
7607
7608 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7609 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007610 if (*(struct lysc_type **)substmts[u].storage) {
Radek Krejci335332a2019-09-05 13:03:35 +02007611 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7612 goto cleanup;
7613 }
7614 compiled = substmts[u].storage;
7615 } else {
7616 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007617 struct lysc_type ***types = (struct lysc_type ***)substmts[u].storage, **type = NULL;
Radek Krejci335332a2019-09-05 13:03:35 +02007618 LY_ARRAY_NEW_GOTO(ctx->ctx, *types, type, ret, cleanup);
Michal Vasko22df3f02020-08-24 13:29:22 +02007619 compiled = (void *)type;
Radek Krejci335332a2019-09-05 13:03:35 +02007620 }
7621
Radek Krejciad5963b2019-09-06 16:03:05 +02007622 LY_CHECK_ERR_GOTO(r = lysp_stmt_parse(ctx, stmt, stmt->kw, &parsed, NULL), ret = r, cleanup);
Michal Vasko22df3f02020-08-24 13:29:22 +02007623 LY_CHECK_ERR_GOTO(r = lys_compile_type(ctx, ext->parent_type == LYEXT_PAR_NODE ? ((struct lysc_node *)ext->parent)->sp : NULL,
Michal Vasko69730152020-10-09 16:30:07 +02007624 flags ? *flags : 0, ctx->mod_def->parsed, ext->name, parsed, (struct lysc_type **)compiled,
7625 units && !*units ? units : NULL, NULL), lysp_type_free(ctx->ctx, parsed); free(parsed); ret = r, cleanup);
Radek Krejci38d85362019-09-05 16:26:38 +02007626 lysp_type_free(ctx->ctx, parsed);
7627 free(parsed);
Radek Krejci335332a2019-09-05 13:03:35 +02007628 break;
7629 }
Radek Krejciad5963b2019-09-06 16:03:05 +02007630 case LY_STMT_IF_FEATURE: {
7631 struct lysc_iffeature *iff = NULL;
7632
7633 if (substmts[u].cardinality < LY_STMT_CARD_SOME) {
7634 /* single item */
Michal Vasko22df3f02020-08-24 13:29:22 +02007635 if (((struct lysc_iffeature *)substmts[u].storage)->features) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007636 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DUPSTMT, stmt->stmt);
7637 goto cleanup;
7638 }
Michal Vasko22df3f02020-08-24 13:29:22 +02007639 iff = (struct lysc_iffeature *)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007640 } else {
7641 /* sized array */
Michal Vasko22df3f02020-08-24 13:29:22 +02007642 struct lysc_iffeature **iffs = (struct lysc_iffeature **)substmts[u].storage;
Radek Krejciad5963b2019-09-06 16:03:05 +02007643 LY_ARRAY_NEW_GOTO(ctx->ctx, *iffs, iff, ret, cleanup);
7644 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02007645 qname.str = stmt->arg;
7646 qname.mod = ctx->mod_def;
7647 LY_CHECK_ERR_GOTO(r = lys_compile_iffeature(ctx, &qname, iff), ret = r, cleanup);
Radek Krejciad5963b2019-09-06 16:03:05 +02007648 break;
7649 }
7650 /* TODO support other substatements (parse stmt to lysp and then compile lysp to lysc),
7651 * also note that in many statements their extensions are not taken into account */
Radek Krejci335332a2019-09-05 13:03:35 +02007652 default:
Radek Krejciad5963b2019-09-06 16:03:05 +02007653 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Statement \"%s\" is not supported as an extension (found in \"%s%s%s\") substatement.",
Michal Vasko69730152020-10-09 16:30:07 +02007654 stmt->stmt, ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejci335332a2019-09-05 13:03:35 +02007655 goto cleanup;
7656 }
7657 }
Radek Krejci335332a2019-09-05 13:03:35 +02007658 }
Radek Krejci335332a2019-09-05 13:03:35 +02007659
Michal Vasko69730152020-10-09 16:30:07 +02007660 if (((substmts[u].cardinality == LY_STMT_CARD_MAND) || (substmts[u].cardinality == LY_STMT_CARD_SOME)) && !stmt_present) {
Radek Krejciad5963b2019-09-06 16:03:05 +02007661 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s%s%s\".",
Michal Vasko69730152020-10-09 16:30:07 +02007662 ly_stmt2str(substmts[u].stmt), ext->name, ext->argument ? " " : "", ext->argument ? ext->argument : "");
Radek Krejciad5963b2019-09-06 16:03:05 +02007663 goto cleanup;
7664 }
Radek Krejci335332a2019-09-05 13:03:35 +02007665 }
7666
7667 ret = LY_SUCCESS;
7668
7669cleanup:
Radek Krejci335332a2019-09-05 13:03:35 +02007670 return ret;
7671}
7672
Michal Vasko175012e2019-11-06 15:49:14 +01007673/**
Michal Vaskoecd62de2019-11-13 12:35:11 +01007674 * @brief Check when for cyclic dependencies.
Michal Vasko7f45cf22020-10-01 12:49:44 +02007675 *
Michal Vaskoecd62de2019-11-13 12:35:11 +01007676 * @param[in] set Set with all the referenced nodes.
7677 * @param[in] node Node whose "when" referenced nodes are in @p set.
7678 * @return LY_ERR value
7679 */
7680static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007681lys_compile_unres_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
Michal Vaskoecd62de2019-11-13 12:35:11 +01007682{
7683 struct lyxp_set tmp_set;
7684 struct lyxp_set_scnode *xp_scnode;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007685 uint32_t i, j;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007686 LY_ARRAY_COUNT_TYPE u;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007687 struct lysc_when *when;
7688 LY_ERR ret = LY_SUCCESS;
7689
7690 memset(&tmp_set, 0, sizeof tmp_set);
7691
7692 /* prepare in_ctx of the set */
Michal Vaskod989ba02020-08-24 10:59:24 +02007693 for (i = 0; i < set->used; ++i) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007694 xp_scnode = &set->val.scnodes[i];
7695
Michal Vasko5c4e5892019-11-14 12:31:38 +01007696 if (xp_scnode->in_ctx != -1) {
7697 /* check node when, skip the context node (it was just checked) */
Michal Vaskoecd62de2019-11-13 12:35:11 +01007698 xp_scnode->in_ctx = 1;
7699 }
7700 }
7701
7702 for (i = 0; i < set->used; ++i) {
7703 xp_scnode = &set->val.scnodes[i];
7704 if (xp_scnode->in_ctx != 1) {
7705 /* already checked */
7706 continue;
7707 }
7708
Michal Vasko69730152020-10-09 16:30:07 +02007709 if ((xp_scnode->type != LYXP_NODE_ELEM) || (xp_scnode->scnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) ||
7710 !xp_scnode->scnode->when) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007711 /* no when to check */
7712 xp_scnode->in_ctx = 0;
7713 continue;
7714 }
7715
7716 node = xp_scnode->scnode;
7717 do {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007718 LY_ARRAY_FOR(node->when, u) {
7719 when = node->when[u];
Michal Vaskoc8a230d2020-08-14 12:17:10 +02007720 ret = lyxp_atomize(when->cond, LY_PREF_SCHEMA, when->module, when->context,
Michal Vasko69730152020-10-09 16:30:07 +02007721 when->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, LYXP_SCNODE_SCHEMA);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007722 if (ret != LY_SUCCESS) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007723 LOGVAL(set->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when->cond->expr);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007724 goto cleanup;
7725 }
7726
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007727 for (j = 0; j < tmp_set.used; ++j) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007728 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007729 if (tmp_set.val.scnodes[j].type == LYXP_NODE_ELEM) {
Michal Vaskoecd62de2019-11-13 12:35:11 +01007730 /* try to find this node in our set */
Radek Krejciaa6b53f2020-08-27 15:19:03 +02007731 uint32_t idx;
7732 if (lyxp_set_scnode_contains(set, tmp_set.val.scnodes[j].scnode, LYXP_NODE_ELEM, -1, &idx) && (set->val.scnodes[idx].in_ctx == -1)) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007733 LOGVAL(set->ctx, LY_VLOG_LYSC, node, LY_VCODE_CIRC_WHEN, node->name, set->val.scnodes[idx].scnode->name);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007734 ret = LY_EVALID;
7735 goto cleanup;
7736 }
7737
7738 /* needs to be checked, if in both sets, will be ignored */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007739 tmp_set.val.scnodes[j].in_ctx = 1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007740 } else {
7741 /* no when, nothing to check */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007742 tmp_set.val.scnodes[j].in_ctx = 0;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007743 }
7744 }
7745
7746 /* merge this set into the global when set */
7747 lyxp_set_scnode_merge(set, &tmp_set);
7748 }
7749
7750 /* check when of non-data parents as well */
7751 node = node->parent;
7752 } while (node && (node->nodetype & (LYS_CASE | LYS_CHOICE)));
7753
Michal Vasko251f56e2019-11-14 16:06:47 +01007754 /* this node when was checked (xp_scnode could have been reallocd) */
7755 set->val.scnodes[i].in_ctx = -1;
Michal Vaskoecd62de2019-11-13 12:35:11 +01007756 }
7757
7758cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007759 lyxp_set_free_content(&tmp_set);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007760 return ret;
7761}
7762
7763/**
Michal Vasko7f45cf22020-10-01 12:49:44 +02007764 * @brief Check when/must expressions of a node on a complete compiled schema tree.
7765 *
Michal Vasko175012e2019-11-06 15:49:14 +01007766 * @param[in] ctx Compile context.
7767 * @param[in] node Node to check.
7768 * @return LY_ERR value
7769 */
7770static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007771lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
Michal Vasko175012e2019-11-06 15:49:14 +01007772{
Michal Vasko175012e2019-11-06 15:49:14 +01007773 struct lyxp_set tmp_set;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007774 uint32_t i;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007775 LY_ARRAY_COUNT_TYPE u;
Radek Krejci1deb5be2020-08-26 16:43:36 +02007776 uint32_t opts;
Radek Krejci857189e2020-09-01 13:26:36 +02007777 ly_bool input_done = 0;
Michal Vasko175012e2019-11-06 15:49:14 +01007778 struct lysc_when **when = NULL;
7779 struct lysc_must *musts = NULL;
7780 LY_ERR ret = LY_SUCCESS;
Michal Vasko6b26e742020-07-17 15:02:10 +02007781 const struct lysc_node *op;
Michal Vasko175012e2019-11-06 15:49:14 +01007782
7783 memset(&tmp_set, 0, sizeof tmp_set);
Michal Vasko5d8756a2019-11-07 15:21:00 +01007784 opts = LYXP_SCNODE_SCHEMA;
Michal Vasko6b26e742020-07-17 15:02:10 +02007785 if (node->flags & LYS_CONFIG_R) {
Michal Vasko2b7e5582020-10-07 12:31:23 +02007786 for (op = node->parent; op && !(op->nodetype & (LYS_RPC | LYS_ACTION)); op = op->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02007787 if (op) {
7788 /* we are actually in output */
7789 opts = LYXP_SCNODE_OUTPUT;
7790 }
7791 }
Michal Vasko175012e2019-11-06 15:49:14 +01007792
7793 switch (node->nodetype) {
7794 case LYS_CONTAINER:
7795 when = ((struct lysc_node_container *)node)->when;
7796 musts = ((struct lysc_node_container *)node)->musts;
7797 break;
7798 case LYS_CHOICE:
7799 when = ((struct lysc_node_choice *)node)->when;
7800 break;
7801 case LYS_LEAF:
7802 when = ((struct lysc_node_leaf *)node)->when;
7803 musts = ((struct lysc_node_leaf *)node)->musts;
7804 break;
7805 case LYS_LEAFLIST:
7806 when = ((struct lysc_node_leaflist *)node)->when;
7807 musts = ((struct lysc_node_leaflist *)node)->musts;
7808 break;
7809 case LYS_LIST:
7810 when = ((struct lysc_node_list *)node)->when;
7811 musts = ((struct lysc_node_list *)node)->musts;
7812 break;
7813 case LYS_ANYXML:
7814 case LYS_ANYDATA:
7815 when = ((struct lysc_node_anydata *)node)->when;
7816 musts = ((struct lysc_node_anydata *)node)->musts;
7817 break;
7818 case LYS_CASE:
7819 when = ((struct lysc_node_case *)node)->when;
7820 break;
7821 case LYS_NOTIF:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007822 when = ((struct lysc_notif *)node)->when;
Michal Vasko175012e2019-11-06 15:49:14 +01007823 musts = ((struct lysc_notif *)node)->musts;
7824 break;
Michal Vasko1bf09392020-03-27 12:38:10 +01007825 case LYS_RPC:
Michal Vasko5d8756a2019-11-07 15:21:00 +01007826 case LYS_ACTION:
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007827 /* first process when and input musts */
7828 when = ((struct lysc_action *)node)->when;
Michal Vasko5d8756a2019-11-07 15:21:00 +01007829 musts = ((struct lysc_action *)node)->input.musts;
7830 break;
Michal Vasko175012e2019-11-06 15:49:14 +01007831 default:
7832 /* nothing to check */
7833 break;
7834 }
7835
Michal Vasko175012e2019-11-06 15:49:14 +01007836 /* check "when" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007837 LY_ARRAY_FOR(when, u) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +02007838 ret = lyxp_atomize(when[u]->cond, LY_PREF_SCHEMA, when[u]->module, when[u]->context ? when[u]->context : node,
Michal Vasko69730152020-10-09 16:30:07 +02007839 when[u]->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, opts);
Michal Vasko175012e2019-11-06 15:49:14 +01007840 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007841 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when[u]->cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007842 goto cleanup;
7843 }
7844
Michal Vaskodc052f32019-11-07 11:11:38 +01007845 ctx->path[0] = '\0';
7846 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007847 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko5c4e5892019-11-14 12:31:38 +01007848 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007849 if ((tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (tmp_set.val.scnodes[i].in_ctx != -1)) {
7850 struct lysc_node *schema = tmp_set.val.scnodes[i].scnode;
Michal Vasko175012e2019-11-06 15:49:14 +01007851
Michal Vaskoecd62de2019-11-13 12:35:11 +01007852 /* XPath expression cannot reference "lower" status than the node that has the definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007853 ret = lysc_check_status(ctx, when[u]->flags, when[u]->module, node->name, schema->flags, schema->module,
Michal Vasko69730152020-10-09 16:30:07 +02007854 schema->name);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007855 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007856
7857 /* check dummy node accessing */
7858 if (schema == node) {
Michal Vaskof6e51882019-12-16 09:59:45 +01007859 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LY_VCODE_DUMMY_WHEN, node->name);
Michal Vasko5c4e5892019-11-14 12:31:38 +01007860 ret = LY_EVALID;
7861 goto cleanup;
7862 }
Michal Vasko175012e2019-11-06 15:49:14 +01007863 }
7864 }
7865
Michal Vaskoecd62de2019-11-13 12:35:11 +01007866 /* check cyclic dependencies */
Michal Vasko004d3152020-06-11 19:59:22 +02007867 ret = lys_compile_unres_when_cyclic(&tmp_set, node);
Michal Vaskoecd62de2019-11-13 12:35:11 +01007868 LY_CHECK_GOTO(ret, cleanup);
7869
Michal Vaskod3678892020-05-21 10:06:58 +02007870 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007871 }
7872
Michal Vasko5d8756a2019-11-07 15:21:00 +01007873check_musts:
Michal Vasko175012e2019-11-06 15:49:14 +01007874 /* check "must" */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007875 LY_ARRAY_FOR(musts, u) {
Michal Vaskoc8a230d2020-08-14 12:17:10 +02007876 ret = lyxp_atomize(musts[u].cond, LY_PREF_SCHEMA, musts[u].module, node, LYXP_NODE_ELEM, &tmp_set, opts);
Michal Vasko175012e2019-11-06 15:49:14 +01007877 if (ret != LY_SUCCESS) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007878 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid must restriction \"%s\".", musts[u].cond->expr);
Michal Vasko175012e2019-11-06 15:49:14 +01007879 goto cleanup;
7880 }
7881
Michal Vaskodc052f32019-11-07 11:11:38 +01007882 ctx->path[0] = '\0';
7883 lysc_path((struct lysc_node *)node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007884 for (i = 0; i < tmp_set.used; ++i) {
Michal Vasko175012e2019-11-06 15:49:14 +01007885 /* skip roots'n'stuff */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007886 if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
Michal Vasko175012e2019-11-06 15:49:14 +01007887 /* XPath expression cannot reference "lower" status than the node that has the definition */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02007888 ret = lysc_check_status(ctx, node->flags, musts[u].module, node->name, tmp_set.val.scnodes[i].scnode->flags,
Michal Vasko69730152020-10-09 16:30:07 +02007889 tmp_set.val.scnodes[i].scnode->module, tmp_set.val.scnodes[i].scnode->name);
Michal Vasko175012e2019-11-06 15:49:14 +01007890 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko175012e2019-11-06 15:49:14 +01007891 }
7892 }
7893
Michal Vaskod3678892020-05-21 10:06:58 +02007894 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007895 }
7896
Michal Vasko1bf09392020-03-27 12:38:10 +01007897 if ((node->nodetype & (LYS_RPC | LYS_ACTION)) && !input_done) {
Michal Vasko5d8756a2019-11-07 15:21:00 +01007898 /* now check output musts */
7899 input_done = 1;
Michal Vaskoceab6dd2020-10-09 16:53:36 +02007900 when = NULL;
Michal Vasko5d8756a2019-11-07 15:21:00 +01007901 musts = ((struct lysc_action *)node)->output.musts;
7902 opts = LYXP_SCNODE_OUTPUT;
7903 goto check_musts;
7904 }
7905
Michal Vasko175012e2019-11-06 15:49:14 +01007906cleanup:
Michal Vaskod3678892020-05-21 10:06:58 +02007907 lyxp_set_free_content(&tmp_set);
Michal Vasko175012e2019-11-06 15:49:14 +01007908 return ret;
7909}
7910
Michal Vasko7f45cf22020-10-01 12:49:44 +02007911/**
7912 * @brief Check leafref for its target existence on a complete compiled schema tree.
7913 *
7914 * @param[in] ctx Compile context.
7915 * @param[in] node Context node for the leafref.
7916 * @param[in] lref Leafref to resolve.
7917 * @return LY_ERR value.
7918 */
Michal Vasko8d544252020-03-02 10:19:52 +01007919static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02007920lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref)
7921{
Michal Vasko6b26e742020-07-17 15:02:10 +02007922 const struct lysc_node *target = NULL, *siter;
Michal Vasko004d3152020-06-11 19:59:22 +02007923 struct ly_path *p;
7924 struct lysc_type *type;
7925
7926 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
7927
7928 /* try to find the target */
Michal Vasko00cbf532020-06-15 13:58:47 +02007929 LY_CHECK_RET(ly_path_compile(ctx->ctx, node->module, node, lref->path, LY_PATH_LREF_TRUE,
Michal Vasko69730152020-10-09 16:30:07 +02007930 lysc_is_output(node) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
7931 LY_PREF_SCHEMA, (void *)lref->path_mod, &p));
Michal Vasko004d3152020-06-11 19:59:22 +02007932
7933 /* get the target node */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02007934 target = p[LY_ARRAY_COUNT(p) - 1].node;
Michal Vasko004d3152020-06-11 19:59:22 +02007935 ly_path_free(node->module->ctx, p);
7936
7937 if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7938 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007939 "Invalid leafref path \"%s\" - target node is %s instead of leaf or leaf-list.",
7940 lref->path->expr, lys_nodetype2str(target->nodetype));
Michal Vasko004d3152020-06-11 19:59:22 +02007941 return LY_EVALID;
7942 }
7943
7944 /* check status */
7945 ctx->path[0] = '\0';
7946 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
7947 ctx->path_len = strlen(ctx->path);
7948 if (lysc_check_status(ctx, node->flags, node->module, node->name, target->flags, target->module, target->name)) {
7949 return LY_EVALID;
7950 }
7951 ctx->path_len = 1;
7952 ctx->path[1] = '\0';
7953
7954 /* check config */
Michal Vasko6b26e742020-07-17 15:02:10 +02007955 if (lref->require_instance) {
Radek Krejci1e008d22020-08-17 11:37:37 +02007956 for (siter = node->parent; siter && !(siter->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); siter = siter->parent) {}
Michal Vasko6b26e742020-07-17 15:02:10 +02007957 if (!siter && (node->flags & LYS_CONFIG_W) && (target->flags & LYS_CONFIG_R)) {
Michal Vasko004d3152020-06-11 19:59:22 +02007958 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
Michal Vasko69730152020-10-09 16:30:07 +02007959 " to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007960 return LY_EVALID;
7961 }
7962 }
7963
7964 /* store the target's type and check for circular chain of leafrefs */
7965 lref->realtype = ((struct lysc_node_leaf *)target)->type;
7966 for (type = lref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref *)type)->realtype) {
7967 if (type == (struct lysc_type *)lref) {
7968 /* circular chain detected */
7969 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007970 "Invalid leafref path \"%s\" - circular chain of leafrefs detected.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007971 return LY_EVALID;
7972 }
7973 }
7974
7975 /* check if leafref and its target are under common if-features */
7976 if (lys_compile_leafref_features_validate(node, target)) {
7977 LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +02007978 "Invalid leafref path \"%s\" - set of features applicable to the leafref target is not a subset of"
7979 " features applicable to the leafref itself.", lref->path->expr);
Michal Vasko004d3152020-06-11 19:59:22 +02007980 return LY_EVALID;
7981 }
7982
7983 return LY_SUCCESS;
7984}
7985
7986static LY_ERR
Michal Vasko8d544252020-03-02 10:19:52 +01007987lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
7988{
7989 struct lysc_ext_instance *ext;
7990 struct lysp_ext_instance *ext_p = NULL;
7991 struct lysp_stmt *stmt;
7992 const struct lys_module *ext_mod;
7993 LY_ERR ret = LY_SUCCESS;
7994
7995 /* create the parsed extension instance manually */
7996 ext_p = calloc(1, sizeof *ext_p);
7997 LY_CHECK_ERR_GOTO(!ext_p, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02007998 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "md:annotation", 0, &ext_p->name), cleanup);
7999 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "default", 0, &ext_p->argument), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01008000 ext_p->insubstmt = LYEXT_SUBSTMT_SELF;
8001 ext_p->insubstmt_index = 0;
8002
Radek Krejci87e25252020-09-15 13:28:31 +02008003 ext_p->child = stmt = calloc(1, sizeof *ext_p->child);
8004 LY_CHECK_ERR_GOTO(!stmt, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
Radek Krejci011e4aa2020-09-04 15:22:31 +02008005 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "type", 0, &stmt->stmt), cleanup);
8006 LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, "boolean", 0, &stmt->arg), cleanup);
Michal Vasko8d544252020-03-02 10:19:52 +01008007 stmt->kw = LY_STMT_TYPE;
Michal Vasko8d544252020-03-02 10:19:52 +01008008
8009 /* allocate new extension instance */
8010 LY_ARRAY_NEW_GOTO(mod->ctx, mod->compiled->exts, ext, ret, cleanup);
8011
8012 /* manually get extension definition module */
8013 ext_mod = ly_ctx_get_module_latest(ctx->ctx, "ietf-yang-metadata");
8014
8015 /* compile the extension instance */
8016 LY_CHECK_GOTO(ret = lys_compile_ext(ctx, ext_p, ext, mod->compiled, LYEXT_PAR_MODULE, ext_mod), cleanup);
8017
8018cleanup:
8019 lysp_ext_instance_free(ctx->ctx, ext_p);
8020 free(ext_p);
8021 return ret;
8022}
8023
Michal Vasko7f45cf22020-10-01 12:49:44 +02008024/**
8025 * @brief Compile default value(s) for leaf or leaf-list expecting a complete compiled schema tree.
8026 *
8027 * @param[in] ctx Compile context.
8028 * @param[in] node Leaf or leaf-list to compile the default value(s) for.
8029 * @param[in] type Type of the default value.
8030 * @param[in] dflt Default value.
8031 * @param[in] dflt_mod Local module for @p dflt.
8032 * @param[in,out] storage Storage for the compiled default value.
8033 * @return LY_ERR value.
8034 */
Michal Vasko004d3152020-06-11 19:59:22 +02008035static LY_ERR
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008036lys_compile_unres_dflt(struct lysc_ctx *ctx, struct lysc_node *node, struct lysc_type *type, const char *dflt,
Radek Krejci0f969882020-08-21 16:56:47 +02008037 const struct lys_module *dflt_mod, struct lyd_value *storage)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008038{
8039 LY_ERR ret;
8040 struct ly_err_item *err = NULL;
8041
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008042 ret = type->plugin->store(ctx->ctx, type, dflt, strlen(dflt), 0, LY_PREF_SCHEMA, (void *)dflt_mod, LYD_HINT_SCHEMA,
Michal Vasko69730152020-10-09 16:30:07 +02008043 node, storage, &err);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008044 if (ret == LY_EINCOMPLETE) {
8045 /* we have no data so we will not be resolving it */
8046 ret = LY_SUCCESS;
8047 }
8048
8049 if (ret) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008050 ctx->path[0] = '\0';
8051 lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008052 if (err) {
8053 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02008054 "Invalid default - value does not fit the type (%s).", err->msg);
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008055 ly_err_free(err);
8056 } else {
8057 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko69730152020-10-09 16:30:07 +02008058 "Invalid default - value does not fit the type.");
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008059 }
8060 return ret;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008061 }
Michal Vaskofeca4fb2020-10-05 08:58:40 +02008062
8063 ++((struct lysc_type *)storage->realtype)->refcount;
8064 return LY_SUCCESS;
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008065}
8066
Michal Vasko7f45cf22020-10-01 12:49:44 +02008067/**
8068 * @brief Compile default value of a leaf expecting a complete compiled schema tree.
8069 *
8070 * @param[in] ctx Compile context.
8071 * @param[in] leaf Leaf that the default value is for.
8072 * @param[in] dflt Default value to compile.
8073 * @return LY_ERR value.
8074 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008075static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02008076lys_compile_unres_leaf_dlft(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, struct lysp_qname *dflt)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008077{
8078 LY_ERR ret;
8079
8080 assert(!leaf->dflt);
8081
8082 if (leaf->flags & (LYS_MAND_TRUE | LYS_KEY)) {
8083 /* ignore default values for keys and mandatory leaves */
8084 return LY_SUCCESS;
8085 }
8086
8087 /* allocate the default value */
8088 leaf->dflt = calloc(1, sizeof *leaf->dflt);
8089 LY_CHECK_ERR_RET(!leaf->dflt, LOGMEM(ctx->ctx), LY_EMEM);
8090
8091 /* store the default value */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008092 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)leaf, leaf->type, dflt->str, dflt->mod, leaf->dflt);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008093 if (ret) {
8094 free(leaf->dflt);
8095 leaf->dflt = NULL;
8096 }
8097
8098 return ret;
8099}
8100
Michal Vasko7f45cf22020-10-01 12:49:44 +02008101/**
8102 * @brief Compile default values of a leaf-list expecting a complete compiled schema tree.
8103 *
8104 * @param[in] ctx Compile context.
8105 * @param[in] llist Leaf-list that the default value(s) are for.
8106 * @param[in] dflt Default value to compile, in case of a single value.
8107 * @param[in] dflts Sized array of default values, in case of more values.
8108 * @return LY_ERR value.
8109 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008110static LY_ERR
Michal Vasko7f45cf22020-10-01 12:49:44 +02008111lys_compile_unres_llist_dflts(struct lysc_ctx *ctx, struct lysc_node_leaflist *llist, struct lysp_qname *dflt,
8112 struct lysp_qname *dflts)
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008113{
8114 LY_ERR ret;
8115 LY_ARRAY_COUNT_TYPE orig_count, u, v;
8116
8117 assert(dflt || dflts);
8118
8119 if (llist->dflts) {
8120 /* there were already some defaults and we are adding new by deviations */
8121 assert(dflts);
8122 orig_count = LY_ARRAY_COUNT(llist->dflts);
8123 } else {
8124 orig_count = 0;
8125 }
8126
8127 /* allocate new items */
8128 if (dflts) {
8129 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + LY_ARRAY_COUNT(dflts), LY_EMEM);
8130 } else {
8131 LY_ARRAY_CREATE_RET(ctx->ctx, llist->dflts, orig_count + 1, LY_EMEM);
8132 }
8133
8134 /* fill each new default value */
8135 if (dflts) {
8136 LY_ARRAY_FOR(dflts, u) {
8137 llist->dflts[orig_count + u] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008138 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflts[u].str, dflts[u].mod,
8139 llist->dflts[orig_count + u]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008140 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count + u]), ret);
8141 LY_ARRAY_INCREMENT(llist->dflts);
8142 }
8143 } else {
8144 llist->dflts[orig_count] = calloc(1, sizeof **llist->dflts);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008145 ret = lys_compile_unres_dflt(ctx, (struct lysc_node *)llist, llist->type, dflt->str, dflt->mod,
8146 llist->dflts[orig_count]);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008147 LY_CHECK_ERR_RET(ret, free(llist->dflts[orig_count]), ret);
8148 LY_ARRAY_INCREMENT(llist->dflts);
8149 }
8150
8151 /* check default value uniqueness */
8152 if (llist->flags & LYS_CONFIG_W) {
8153 /* configuration data values must be unique - so check the default values */
8154 for (u = orig_count; u < LY_ARRAY_COUNT(llist->dflts); ++u) {
8155 for (v = 0; v < u; ++v) {
8156 if (!llist->dflts[u]->realtype->plugin->compare(llist->dflts[u], llist->dflts[v])) {
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008157 lysc_update_path(ctx, llist->parent, llist->name);
8158 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
Michal Vasko7f45cf22020-10-01 12:49:44 +02008159 "Configuration leaf-list has multiple defaults of the same value \"%s\".",
8160 llist->dflts[u]->canonical);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008161 lysc_update_path(ctx, NULL, NULL);
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008162 return LY_EVALID;
8163 }
8164 }
8165 }
8166 }
8167
8168 return LY_SUCCESS;
8169}
8170
Michal Vasko7f45cf22020-10-01 12:49:44 +02008171/**
8172 * @brief Finish compilation of all the unres sets of a compile context.
8173 *
8174 * @param[in] ctx Compile context with unres sets.
8175 * @return LY_ERR value.
8176 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008177static LY_ERR
Michal Vasko004d3152020-06-11 19:59:22 +02008178lys_compile_unres(struct lysc_ctx *ctx)
8179{
8180 struct lysc_node *node;
8181 struct lysc_type *type, *typeiter;
8182 struct lysc_type_leafref *lref;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008183 struct lysc_augment *aug;
8184 struct lysc_deviation *dev;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02008185 LY_ARRAY_COUNT_TYPE v;
Michal Vasko004d3152020-06-11 19:59:22 +02008186 uint32_t i;
8187
8188 /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
8189 * can be also leafref, in case it is already resolved, go through the chain and check that it does not
8190 * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
8191 for (i = 0; i < ctx->leafrefs.count; ++i) {
8192 node = ctx->leafrefs.objs[i];
8193 assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
8194 type = ((struct lysc_node_leaf *)node)->type;
8195 if (type->basetype == LY_TYPE_LEAFREF) {
8196 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, (struct lysc_type_leafref *)type));
8197 } else if (type->basetype == LY_TYPE_UNION) {
8198 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
8199 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
8200 lref = (struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v];
8201 LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, lref));
8202 }
8203 }
8204 }
8205 }
8206 for (i = 0; i < ctx->leafrefs.count; ++i) {
8207 /* store pointer to the real type */
8208 type = ((struct lysc_node_leaf *)ctx->leafrefs.objs[i])->type;
8209 if (type->basetype == LY_TYPE_LEAFREF) {
Michal Vasko22df3f02020-08-24 13:29:22 +02008210 for (typeiter = ((struct lysc_type_leafref *)type)->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02008211 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02008212 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
8213 ((struct lysc_type_leafref *)type)->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02008214 } else if (type->basetype == LY_TYPE_UNION) {
Michal Vasko22df3f02020-08-24 13:29:22 +02008215 LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
8216 if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
8217 for (typeiter = ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype;
Michal Vasko004d3152020-06-11 19:59:22 +02008218 typeiter->basetype == LY_TYPE_LEAFREF;
Michal Vasko22df3f02020-08-24 13:29:22 +02008219 typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
8220 ((struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v])->realtype = typeiter;
Michal Vasko004d3152020-06-11 19:59:22 +02008221 }
8222 }
8223 }
8224 }
8225
8226 /* check xpath */
8227 for (i = 0; i < ctx->xpath.count; ++i) {
8228 LY_CHECK_RET(lys_compile_unres_xpath(ctx, ctx->xpath.objs[i]));
8229 }
8230
8231 /* finish incomplete default values compilation */
8232 for (i = 0; i < ctx->dflts.count; ++i) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008233 struct lysc_unres_dflt *r = ctx->dflts.objs[i];
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008234 if (r->leaf->nodetype == LYS_LEAF) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008235 LY_CHECK_RET(lys_compile_unres_leaf_dlft(ctx, r->leaf, r->dflt));
Michal Vaskoba99a3e2020-08-18 15:50:05 +02008236 } else {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008237 LY_CHECK_RET(lys_compile_unres_llist_dflts(ctx, r->llist, r->dflt, r->dflts));
Michal Vasko004d3152020-06-11 19:59:22 +02008238 }
Michal Vasko004d3152020-06-11 19:59:22 +02008239 }
8240
Michal Vasko7f45cf22020-10-01 12:49:44 +02008241 /* check that all augments were applied */
8242 for (i = 0; i < ctx->augs.count; ++i) {
8243 aug = ctx->augs.objs[i];
8244 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
8245 "Augment target node \"%s\" from module \"%s\" was not found.", aug->nodeid->expr,
8246 aug->nodeid_mod->name);
8247 }
8248 if (ctx->augs.count) {
8249 return LY_ENOTFOUND;
8250 }
8251
8252 /* check that all deviations were applied */
8253 for (i = 0; i < ctx->devs.count; ++i) {
8254 dev = ctx->devs.objs[i];
8255 LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE,
8256 "Deviation(s) target node \"%s\" from module \"%s\" was not found.", dev->nodeid->expr,
8257 dev->nodeid_mod->name);
8258 }
8259 if (ctx->devs.count) {
8260 return LY_ENOTFOUND;
8261 }
8262
8263 return LY_SUCCESS;
8264}
8265
Michal Vasko89b5c072020-10-06 13:52:44 +02008266void
8267lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
Michal Vasko7f45cf22020-10-01 12:49:44 +02008268{
8269 uint32_t i;
8270 LY_ARRAY_COUNT_TYPE u, count;
8271 struct lys_module *m;
8272
Michal Vasko89b5c072020-10-06 13:52:44 +02008273 for (i = 0; i < ctx->list.count; ++i) {
8274 m = ctx->list.objs[i];
Michal Vasko7f45cf22020-10-01 12:49:44 +02008275
8276 if (m->augmented_by) {
8277 count = LY_ARRAY_COUNT(m->augmented_by);
8278 for (u = 0; u < count; ++u) {
8279 if (m->augmented_by[u] == mod) {
8280 /* keep the order */
8281 if (u < count - 1) {
8282 memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by);
8283 }
8284 LY_ARRAY_DECREMENT(m->augmented_by);
8285 break;
8286 }
8287 }
8288 if (!LY_ARRAY_COUNT(m->augmented_by)) {
8289 LY_ARRAY_FREE(m->augmented_by);
8290 m->augmented_by = NULL;
8291 }
8292 }
8293
8294 if (m->deviated_by) {
8295 count = LY_ARRAY_COUNT(m->deviated_by);
8296 for (u = 0; u < count; ++u) {
8297 if (m->deviated_by[u] == mod) {
8298 /* keep the order */
8299 if (u < count - 1) {
8300 memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by);
8301 }
8302 LY_ARRAY_DECREMENT(m->deviated_by);
8303 break;
8304 }
8305 }
8306 if (!LY_ARRAY_COUNT(m->deviated_by)) {
8307 LY_ARRAY_FREE(m->deviated_by);
8308 m->deviated_by = NULL;
8309 }
8310 }
8311 }
8312}
8313
8314/**
8315 * @brief Compile features in the current module and all its submodules.
8316 *
8317 * @param[in] ctx Compile context.
8318 * @return LY_ERR value.
8319 */
8320static LY_ERR
8321lys_compile_features(struct lysc_ctx *ctx)
8322{
8323 struct lysp_submodule *submod;
8324 LY_ARRAY_COUNT_TYPE u, v;
8325
8326 if (!ctx->mod->features) {
8327 /* features are compiled directly into the module structure,
8328 * but it must be done in two steps to allow forward references (via if-feature) between the features themselves */
8329 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, ctx->mod->parsed->features, &ctx->mod->features));
8330 LY_ARRAY_FOR(ctx->mod->parsed->includes, v) {
8331 submod = ctx->mod->parsed->includes[v].submodule;
8332 LY_CHECK_RET(lys_feature_precompile(ctx, NULL, NULL, submod->features, &ctx->mod->features));
8333 }
8334 }
8335
8336 /* finish feature compilation, not only for the main module, but also for the submodules.
8337 * Due to possible forward references, it must be done when all the features (including submodules)
8338 * are present. */
8339 LY_ARRAY_FOR(ctx->mod->parsed->features, u) {
8340 LY_CHECK_RET(lys_feature_precompile_finish(ctx, &ctx->mod->parsed->features[u], ctx->mod->features));
8341 }
8342
8343 lysc_update_path(ctx, NULL, "{submodule}");
8344 LY_ARRAY_FOR(ctx->mod->parsed->includes, v) {
8345 submod = ctx->mod->parsed->includes[v].submodule;
8346
8347 lysc_update_path(ctx, NULL, submod->name);
8348 LY_ARRAY_FOR(submod->features, u) {
8349 LY_CHECK_RET(lys_feature_precompile_finish(ctx, &submod->features[u], ctx->mod->features));
8350 }
8351 lysc_update_path(ctx, NULL, NULL);
8352 }
8353 lysc_update_path(ctx, NULL, NULL);
8354
8355 return LY_SUCCESS;
8356}
8357
8358/**
8359 * @brief Compile identites in the current module and all its submodules.
8360 *
8361 * @param[in] ctx Compile context.
8362 * @return LY_ERR value.
8363 */
8364static LY_ERR
8365lys_compile_identities(struct lysc_ctx *ctx)
8366{
8367 struct lysp_submodule *submod;
8368 LY_ARRAY_COUNT_TYPE u;
8369
8370 if (!ctx->mod->identities) {
8371 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, ctx->mod->parsed->identities, &ctx->mod->identities));
8372 LY_ARRAY_FOR(ctx->mod->parsed->includes, u) {
8373 submod = ctx->mod->parsed->includes[u].submodule;
8374 LY_CHECK_RET(lys_identity_precompile(ctx, NULL, NULL, submod->identities, &ctx->mod->identities));
8375 }
8376 }
8377
8378 if (ctx->mod->parsed->identities) {
8379 LY_CHECK_RET(lys_compile_identities_derived(ctx, ctx->mod->parsed->identities, ctx->mod->identities));
8380 }
8381 lysc_update_path(ctx, NULL, "{submodule}");
8382 LY_ARRAY_FOR(ctx->mod->parsed->includes, u) {
8383
8384 submod = ctx->mod->parsed->includes[u].submodule;
8385 if (submod->identities) {
8386 lysc_update_path(ctx, NULL, submod->name);
8387 LY_CHECK_RET(lys_compile_identities_derived(ctx, submod->identities, ctx->mod->identities));
8388 lysc_update_path(ctx, NULL, NULL);
8389 }
8390 }
8391 lysc_update_path(ctx, NULL, NULL);
8392
Michal Vasko004d3152020-06-11 19:59:22 +02008393 return LY_SUCCESS;
8394}
8395
Radek Krejci19a96102018-11-15 13:38:09 +01008396LY_ERR
Michal Vasko7a0b0762020-09-02 16:37:01 +02008397lys_compile(struct lys_module *mod, uint32_t options)
Radek Krejci19a96102018-11-15 13:38:09 +01008398{
8399 struct lysc_ctx ctx = {0};
8400 struct lysc_module *mod_c;
8401 struct lysp_module *sp;
Michal Vasko7f45cf22020-10-01 12:49:44 +02008402 struct lysp_submodule *submod;
8403 struct lysp_node *pnode;
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008404 struct lysp_grp *grps;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02008405 LY_ARRAY_COUNT_TYPE u, v;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02008406 uint32_t i;
Radek Krejcid05cbd92018-12-05 14:26:40 +01008407 LY_ERR ret = LY_SUCCESS;
Radek Krejci19a96102018-11-15 13:38:09 +01008408
Michal Vasko7a0b0762020-09-02 16:37:01 +02008409 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, !mod->compiled, mod->ctx, LY_EINVAL);
Radek Krejci096235c2019-01-11 11:12:19 +01008410
Michal Vasko7a0b0762020-09-02 16:37:01 +02008411 if (!mod->implemented) {
Radek Krejci096235c2019-01-11 11:12:19 +01008412 /* just imported modules are not compiled */
8413 return LY_SUCCESS;
8414 }
8415
Michal Vasko7f45cf22020-10-01 12:49:44 +02008416 /* context will be changed */
8417 ++mod->ctx->module_set_id;
8418
Michal Vasko7a0b0762020-09-02 16:37:01 +02008419 sp = mod->parsed;
Radek Krejci19a96102018-11-15 13:38:09 +01008420
Michal Vasko7a0b0762020-09-02 16:37:01 +02008421 ctx.ctx = mod->ctx;
8422 ctx.mod = mod;
8423 ctx.mod_def = mod;
Radek Krejciec4da802019-05-02 13:02:41 +02008424 ctx.options = options;
Radek Krejci327de162019-06-14 12:52:07 +02008425 ctx.path_len = 1;
8426 ctx.path[0] = '/';
Radek Krejci19a96102018-11-15 13:38:09 +01008427
Michal Vasko7a0b0762020-09-02 16:37:01 +02008428 mod->compiled = mod_c = calloc(1, sizeof *mod_c);
8429 LY_CHECK_ERR_RET(!mod_c, LOGMEM(mod->ctx), LY_EMEM);
8430 mod_c->mod = mod;
Radek Krejci19a96102018-11-15 13:38:09 +01008431
Michal Vasko7f45cf22020-10-01 12:49:44 +02008432 /* process imports */
Michal Vasko7c8439f2020-08-05 13:25:19 +02008433 LY_ARRAY_FOR(sp->imports, u) {
8434 LY_CHECK_GOTO(ret = lys_compile_import(&ctx, &sp->imports[u]), error);
8435 }
Radek Krejci0935f412019-08-20 16:15:18 +02008436
Michal Vasko7f45cf22020-10-01 12:49:44 +02008437 /* features */
8438 LY_CHECK_GOTO(ret = lys_compile_features(&ctx), error);
Radek Krejci14915cc2020-09-14 17:28:13 +02008439
8440 /* identities, work similarly to features with the precompilation */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008441 LY_CHECK_GOTO(ret = lys_compile_identities(&ctx), error);
8442
8443 /* augments and deviations */
8444 LY_CHECK_GOTO(ret = lys_precompile_augments_deviations(&ctx), error);
8445
8446 /* compile augments and deviations of our module from other modules so they can be applied during compilation */
8447 LY_CHECK_GOTO(ret = lys_precompile_own_augments(&ctx), error);
8448 LY_CHECK_GOTO(ret = lys_precompile_own_deviations(&ctx), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008449
Radek Krejci95710c92019-02-11 15:49:55 +01008450 /* data nodes */
Michal Vasko7f45cf22020-10-01 12:49:44 +02008451 LY_LIST_FOR(sp->data, pnode) {
8452 LY_CHECK_GOTO(ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL), error);
Radek Krejci19a96102018-11-15 13:38:09 +01008453 }
Radek Krejci95710c92019-02-11 15:49:55 +01008454
Michal Vasko7f45cf22020-10-01 12:49:44 +02008455 /* top-level RPCs and notifications */
8456 COMPILE_OP_ARRAY_GOTO(&ctx, sp->rpcs, mod_c->rpcs, NULL, u, lys_compile_action, 0, ret, error);
8457 COMPILE_OP_ARRAY_GOTO(&ctx, sp->notifs, mod_c->notifs, NULL, u, lys_compile_notif, 0, ret, error);
Radek Krejciccd20f12019-02-15 14:12:27 +01008458
Michal Vasko7f45cf22020-10-01 12:49:44 +02008459 /* extension instances */
Radek Krejci0935f412019-08-20 16:15:18 +02008460 COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
Radek Krejci19a96102018-11-15 13:38:09 +01008461
Michal Vasko7f45cf22020-10-01 12:49:44 +02008462 /* the same for submodules */
8463 LY_ARRAY_FOR(sp->includes, u) {
8464 submod = sp->includes[u].submodule;
8465 LY_LIST_FOR(submod->data, pnode) {
8466 ret = lys_compile_node(&ctx, pnode, NULL, 0, NULL);
8467 LY_CHECK_GOTO(ret, error);
8468 }
8469
8470 COMPILE_OP_ARRAY_GOTO(&ctx, submod->rpcs, mod_c->rpcs, NULL, v, lys_compile_action, 0, ret, error);
8471 COMPILE_OP_ARRAY_GOTO(&ctx, submod->notifs, mod_c->notifs, NULL, v, lys_compile_notif, 0, ret, error);
8472
8473 COMPILE_EXTS_GOTO(&ctx, submod->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
8474 }
8475
Michal Vasko004d3152020-06-11 19:59:22 +02008476 /* finish compilation for all unresolved items in the context */
8477 LY_CHECK_GOTO(ret = lys_compile_unres(&ctx), error);
Radek Krejci474f9b82019-07-24 11:36:37 +02008478
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008479 /* validate non-instantiated groupings from the parsed schema,
8480 * without it we would accept even the schemas with invalid grouping specification */
Radek Krejci90d4e922020-10-12 15:55:33 +02008481 ctx.options |= LYS_COMPILE_GROUPING;
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008482 LY_ARRAY_FOR(sp->groupings, u) {
8483 if (!(sp->groupings[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008484 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &sp->groupings[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008485 }
8486 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008487 LY_LIST_FOR(sp->data, pnode) {
8488 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008489 LY_ARRAY_FOR(grps, u) {
8490 if (!(grps[u].flags & LYS_USED_GRP)) {
Michal Vasko7f45cf22020-10-01 12:49:44 +02008491 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
Radek Krejcif2de0ed2019-05-02 14:13:18 +02008492 }
8493 }
8494 }
Michal Vasko7f45cf22020-10-01 12:49:44 +02008495 LY_ARRAY_FOR(sp->includes, u) {
8496 submod = sp->includes[u].submodule;
8497 LY_ARRAY_FOR(submod->groupings, u) {
8498 if (!(submod->groupings[u].flags & LYS_USED_GRP)) {
8499 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &submod->groupings[u]), error);
8500 }
8501 }
8502 LY_LIST_FOR(submod->data, pnode) {
8503 grps = (struct lysp_grp *)lysp_node_groupings(pnode);
8504 LY_ARRAY_FOR(grps, u) {
8505 if (!(grps[u].flags & LYS_USED_GRP)) {
8506 LY_CHECK_GOTO(ret = lys_compile_grouping(&ctx, pnode, &grps[u]), error);
8507 }
8508 }
8509 }
Radek Krejci474f9b82019-07-24 11:36:37 +02008510 }
8511
Michal Vasko8d544252020-03-02 10:19:52 +01008512#if 0
8513 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
8514 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
8515 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
8516 * the anotation definitions available in the internal schema structure. */
8517 if (ly_strequal(mod->name, "ietf-netconf", 0)) {
8518 if (lyp_add_ietf_netconf_annotations(mod)) {
8519 lys_free(mod, NULL, 1, 1);
8520 return NULL;
8521 }
8522 }
8523#endif
8524
8525 /* add ietf-netconf-with-defaults "default" metadata to the compiled module */
Michal Vasko7a0b0762020-09-02 16:37:01 +02008526 if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
8527 LY_CHECK_GOTO(ret = lys_compile_ietf_netconf_wd_annotation(&ctx, mod), error);
Michal Vasko8d544252020-03-02 10:19:52 +01008528 }
8529
Michal Vasko7f45cf22020-10-01 12:49:44 +02008530 /* there can be no leftover deviations */
8531 LY_CHECK_ERR_GOTO(ctx.devs.count, LOGINT(ctx.ctx); ret = LY_EINT, error);
8532
8533 for (i = 0; i < ctx.dflts.count; ++i) {
8534 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8535 }
8536 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008537 ly_set_erase(&ctx.xpath, NULL);
8538 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008539 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008540 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008541 ly_set_erase(&ctx.augs, NULL);
8542 ly_set_erase(&ctx.devs, NULL);
8543 ly_set_erase(&ctx.uses_augs, NULL);
8544 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejcia3045382018-11-22 14:30:31 +01008545
Radek Krejci19a96102018-11-15 13:38:09 +01008546 return LY_SUCCESS;
8547
8548error:
Michal Vasko89b5c072020-10-06 13:52:44 +02008549 lys_precompile_augments_deviations_revert(ctx.ctx, mod);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008550 lys_feature_precompile_revert(&ctx, mod);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008551 for (i = 0; i < ctx.dflts.count; ++i) {
8552 lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
8553 }
8554 ly_set_erase(&ctx.dflts, NULL);
Michal Vasko004d3152020-06-11 19:59:22 +02008555 ly_set_erase(&ctx.xpath, NULL);
8556 ly_set_erase(&ctx.leafrefs, NULL);
Radek Krejcie86bf772018-12-14 11:39:53 +01008557 ly_set_erase(&ctx.groupings, NULL);
Radek Krejci99b5b2a2019-04-30 16:57:04 +02008558 ly_set_erase(&ctx.tpdf_chain, NULL);
Michal Vasko7f45cf22020-10-01 12:49:44 +02008559 for (i = 0; i < ctx.augs.count; ++i) {
8560 lysc_augment_free(ctx.ctx, ctx.augs.objs[i]);
8561 }
8562 ly_set_erase(&ctx.augs, NULL);
8563 for (i = 0; i < ctx.devs.count; ++i) {
8564 lysc_deviation_free(ctx.ctx, ctx.devs.objs[i]);
8565 }
8566 ly_set_erase(&ctx.devs, NULL);
8567 for (i = 0; i < ctx.uses_augs.count; ++i) {
8568 lysc_augment_free(ctx.ctx, ctx.uses_augs.objs[i]);
8569 }
8570 ly_set_erase(&ctx.uses_augs, NULL);
8571 for (i = 0; i < ctx.uses_rfns.count; ++i) {
8572 lysc_refine_free(ctx.ctx, ctx.uses_rfns.objs[i]);
8573 }
8574 ly_set_erase(&ctx.uses_rfns, NULL);
Radek Krejci19a96102018-11-15 13:38:09 +01008575 lysc_module_free(mod_c, NULL);
Michal Vasko7a0b0762020-09-02 16:37:01 +02008576 mod->compiled = NULL;
Radek Krejci95710c92019-02-11 15:49:55 +01008577
Radek Krejci19a96102018-11-15 13:38:09 +01008578 return ret;
8579}