/src/libyang/src/schema_compile_amend.c
Line | Count | Source |
1 | | /** |
2 | | * @file schema_compile_amend.c |
3 | | * @author Radek Krejci <rkrejci@cesnet.cz> |
4 | | * @brief Schema compilation of augments, deviations, and refines. |
5 | | * |
6 | | * Copyright (c) 2015 - 2020 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 | | |
15 | | #define _GNU_SOURCE |
16 | | |
17 | | #include "schema_compile_amend.h" |
18 | | |
19 | | #include <assert.h> |
20 | | #include <stddef.h> |
21 | | #include <stdint.h> |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | |
25 | | #include "common.h" |
26 | | #include "dict.h" |
27 | | #include "log.h" |
28 | | #include "plugins_exts_compile.h" |
29 | | #include "schema_compile.h" |
30 | | #include "schema_compile_node.h" |
31 | | #include "schema_features.h" |
32 | | #include "set.h" |
33 | | #include "tree.h" |
34 | | #include "tree_edit.h" |
35 | | #include "tree_schema.h" |
36 | | #include "tree_schema_internal.h" |
37 | | #include "xpath.h" |
38 | | |
39 | | static const struct lys_module *lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, |
40 | | size_t nametest_len, const struct lysp_module *mod, const char **name, size_t *name_len); |
41 | | |
42 | | /** |
43 | | * @brief Check the syntax of a node-id and collect all the referenced modules. |
44 | | * |
45 | | * @param[in] ctx Compile context. |
46 | | * @param[in] nodeid Node-id to check. |
47 | | * @param[in] abs Whether @p nodeid is absolute. |
48 | | * @param[in,out] mod_set Set to add referenced modules into. |
49 | | * @param[out] expr Optional node-id parsed into an expression. |
50 | | * @param[out] target_mod Optional target module of the node-id. |
51 | | * @return LY_ERR value. |
52 | | */ |
53 | | static LY_ERR |
54 | | lys_nodeid_mod_check(struct lysc_ctx *ctx, const char *nodeid, ly_bool abs, struct ly_set *mod_set, |
55 | | struct lyxp_expr **expr, struct lys_module **target_mod) |
56 | 0 | { |
57 | 0 | LY_ERR ret = LY_SUCCESS; |
58 | 0 | struct lyxp_expr *e = NULL; |
59 | 0 | struct lys_module *tmod = NULL, *mod; |
60 | 0 | const char *nodeid_type = abs ? "absolute-schema-nodeid" : "descendant-schema-nodeid"; |
61 | 0 | uint32_t i; |
62 | | |
63 | | /* parse */ |
64 | 0 | ret = lyxp_expr_parse(ctx->ctx, nodeid, strlen(nodeid), 0, &e); |
65 | 0 | if (ret) { |
66 | 0 | LOGVAL(ctx->ctx, LYVE_SYNTAX_YANG, "Invalid %s value \"%s\" - invalid syntax.", |
67 | 0 | nodeid_type, nodeid); |
68 | 0 | ret = LY_EVALID; |
69 | 0 | goto cleanup; |
70 | 0 | } |
71 | | |
72 | 0 | if (abs) { |
73 | | /* absolute schema nodeid */ |
74 | 0 | i = 0; |
75 | 0 | } else { |
76 | | /* descendant schema nodeid */ |
77 | 0 | if (e->tokens[0] != LYXP_TOKEN_NAMETEST) { |
78 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".", |
79 | 0 | nodeid_type, nodeid, e->tok_len[0], e->expr + e->tok_pos[0]); |
80 | 0 | ret = LY_EVALID; |
81 | 0 | goto cleanup; |
82 | 0 | } |
83 | 0 | i = 1; |
84 | 0 | } |
85 | | |
86 | | /* check all the tokens */ |
87 | 0 | for ( ; i < e->used; i += 2) { |
88 | 0 | if (e->tokens[i] != LYXP_TOKEN_OPER_PATH) { |
89 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - \"/\" expected instead of \"%.*s\".", |
90 | 0 | nodeid_type, nodeid, e->tok_len[i], e->expr + e->tok_pos[i]); |
91 | 0 | ret = LY_EVALID; |
92 | 0 | goto cleanup; |
93 | 0 | } else if (e->used == i + 1) { |
94 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
95 | 0 | "Invalid %s value \"%s\" - unexpected end of expression.", nodeid_type, e->expr); |
96 | 0 | ret = LY_EVALID; |
97 | 0 | goto cleanup; |
98 | 0 | } else if (e->tokens[i + 1] != LYXP_TOKEN_NAMETEST) { |
99 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s value \"%s\" - name test expected instead of \"%.*s\".", |
100 | 0 | nodeid_type, nodeid, e->tok_len[i + 1], e->expr + e->tok_pos[i + 1]); |
101 | 0 | ret = LY_EVALID; |
102 | 0 | goto cleanup; |
103 | 0 | } else if (abs) { |
104 | 0 | mod = (struct lys_module *)lys_schema_node_get_module(ctx->ctx, e->expr + e->tok_pos[i + 1], |
105 | 0 | e->tok_len[i + 1], ctx->pmod, NULL, NULL); |
106 | 0 | LY_CHECK_ERR_GOTO(!mod, ret = LY_EVALID, cleanup); |
107 | | |
108 | | /* only keep the first module */ |
109 | 0 | if (!tmod) { |
110 | 0 | tmod = mod; |
111 | 0 | } |
112 | | |
113 | | /* store the referenced module */ |
114 | 0 | LY_CHECK_GOTO(ret = ly_set_add(mod_set, mod, 0, NULL), cleanup); |
115 | 0 | } |
116 | 0 | } |
117 | | |
118 | 0 | cleanup: |
119 | 0 | if (ret || !expr) { |
120 | 0 | lyxp_expr_free(ctx->ctx, e); |
121 | 0 | e = NULL; |
122 | 0 | } |
123 | 0 | if (expr) { |
124 | 0 | *expr = ret ? NULL : e; |
125 | 0 | } |
126 | 0 | if (target_mod) { |
127 | 0 | *target_mod = ret ? NULL : tmod; |
128 | 0 | } |
129 | 0 | return ret; |
130 | 0 | } |
131 | | |
132 | | /** |
133 | | * @brief Check whether 2 schema nodeids match. |
134 | | * |
135 | | * @param[in] ctx libyang context. |
136 | | * @param[in] exp1 First schema nodeid. |
137 | | * @param[in] exp1p_mod Module of @p exp1 nodes without any prefix. |
138 | | * @param[in] exp2 Second schema nodeid. |
139 | | * @param[in] exp2_pmod Module of @p exp2 nodes without any prefix. |
140 | | * @return Whether the schema nodeids match or not. |
141 | | */ |
142 | | static ly_bool |
143 | | lys_abs_schema_nodeid_match(const struct ly_ctx *ctx, const struct lyxp_expr *exp1, const struct lysp_module *exp1_pmod, |
144 | | const struct lyxp_expr *exp2, const struct lysp_module *exp2_pmod) |
145 | 0 | { |
146 | 0 | uint32_t i; |
147 | 0 | const struct lys_module *mod1, *mod2; |
148 | 0 | const char *name1 = NULL, *name2 = NULL; |
149 | 0 | size_t name1_len = 0, name2_len = 0; |
150 | |
|
151 | 0 | if (exp1->used != exp2->used) { |
152 | 0 | return 0; |
153 | 0 | } |
154 | | |
155 | 0 | for (i = 0; i < exp1->used; ++i) { |
156 | 0 | assert(exp1->tokens[i] == exp2->tokens[i]); |
157 | |
|
158 | 0 | if (exp1->tokens[i] == LYXP_TOKEN_NAMETEST) { |
159 | | /* check modules of all the nodes in the node ID */ |
160 | 0 | mod1 = lys_schema_node_get_module(ctx, exp1->expr + exp1->tok_pos[i], exp1->tok_len[i], exp1_pmod, |
161 | 0 | &name1, &name1_len); |
162 | 0 | assert(mod1); |
163 | 0 | mod2 = lys_schema_node_get_module(ctx, exp2->expr + exp2->tok_pos[i], exp2->tok_len[i], exp2_pmod, |
164 | 0 | &name2, &name2_len); |
165 | 0 | assert(mod2); |
166 | | |
167 | | /* compare modules */ |
168 | 0 | if (mod1 != mod2) { |
169 | 0 | return 0; |
170 | 0 | } |
171 | | |
172 | | /* compare names */ |
173 | 0 | if ((name1_len != name2_len) || strncmp(name1, name2, name1_len)) { |
174 | 0 | return 0; |
175 | 0 | } |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | 0 | return 1; |
180 | 0 | } |
181 | | |
182 | | LY_ERR |
183 | | lys_precompile_uses_augments_refines(struct lysc_ctx *ctx, struct lysp_node_uses *uses_p, const struct lysc_node *ctx_node) |
184 | 0 | { |
185 | 0 | LY_ERR ret = LY_SUCCESS; |
186 | 0 | struct lyxp_expr *exp = NULL; |
187 | 0 | struct lysc_augment *aug; |
188 | 0 | struct lysp_node_augment *aug_p; |
189 | 0 | struct lysc_refine *rfn; |
190 | 0 | struct lysp_refine **new_rfn; |
191 | 0 | LY_ARRAY_COUNT_TYPE u; |
192 | 0 | uint32_t i; |
193 | 0 | struct ly_set mod_set = {0}; |
194 | |
|
195 | 0 | LY_LIST_FOR(uses_p->augments, aug_p) { |
196 | 0 | lysc_update_path(ctx, NULL, "{augment}"); |
197 | 0 | lysc_update_path(ctx, NULL, aug_p->nodeid); |
198 | | |
199 | | /* parse the nodeid */ |
200 | 0 | LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, aug_p->nodeid, 0, &mod_set, &exp, NULL), cleanup); |
201 | | |
202 | | /* allocate new compiled augment and store it in the set */ |
203 | 0 | aug = calloc(1, sizeof *aug); |
204 | 0 | LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup); |
205 | 0 | LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_augs, aug, 1, NULL), cleanup); |
206 | |
|
207 | 0 | aug->nodeid = exp; |
208 | 0 | exp = NULL; |
209 | 0 | aug->aug_pmod = ctx->pmod; |
210 | 0 | aug->nodeid_ctx_node = ctx_node; |
211 | 0 | aug->aug_p = aug_p; |
212 | |
|
213 | 0 | lysc_update_path(ctx, NULL, NULL); |
214 | 0 | lysc_update_path(ctx, NULL, NULL); |
215 | 0 | } |
216 | | |
217 | 0 | LY_ARRAY_FOR(uses_p->refines, u) { |
218 | 0 | lysc_update_path(ctx, NULL, "{refine}"); |
219 | 0 | lysc_update_path(ctx, NULL, uses_p->refines[u].nodeid); |
220 | | |
221 | | /* parse the nodeid */ |
222 | 0 | LY_CHECK_GOTO(ret = lys_nodeid_mod_check(ctx, uses_p->refines[u].nodeid, 0, &mod_set, &exp, NULL), cleanup); |
223 | | |
224 | | /* try to find the node in already compiled refines */ |
225 | 0 | rfn = NULL; |
226 | 0 | for (i = 0; i < ctx->uses_rfns.count; ++i) { |
227 | 0 | if (lys_abs_schema_nodeid_match(ctx->ctx, exp, ctx->pmod, ((struct lysc_refine *)ctx->uses_rfns.objs[i])->nodeid, |
228 | 0 | ctx->pmod)) { |
229 | 0 | rfn = ctx->uses_rfns.objs[i]; |
230 | 0 | break; |
231 | 0 | } |
232 | 0 | } |
233 | |
|
234 | 0 | if (!rfn) { |
235 | | /* allocate new compiled refine */ |
236 | 0 | rfn = calloc(1, sizeof *rfn); |
237 | 0 | LY_CHECK_ERR_GOTO(!rfn, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup); |
238 | 0 | LY_CHECK_GOTO(ret = ly_set_add(&ctx->uses_rfns, rfn, 1, NULL), cleanup); |
239 | |
|
240 | 0 | rfn->nodeid = exp; |
241 | 0 | exp = NULL; |
242 | 0 | rfn->nodeid_pmod = ctx->cur_mod->parsed; |
243 | 0 | rfn->nodeid_ctx_node = ctx_node; |
244 | 0 | rfn->uses_p = uses_p; |
245 | 0 | } else { |
246 | | /* just free exp */ |
247 | 0 | lyxp_expr_free(ctx->ctx, exp); |
248 | 0 | exp = NULL; |
249 | 0 | } |
250 | | |
251 | | /* add new parsed refine structure */ |
252 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, rfn->rfns, new_rfn, ret, cleanup); |
253 | 0 | *new_rfn = &uses_p->refines[u]; |
254 | |
|
255 | 0 | lysc_update_path(ctx, NULL, NULL); |
256 | 0 | lysc_update_path(ctx, NULL, NULL); |
257 | 0 | } |
258 | | |
259 | 0 | cleanup: |
260 | 0 | if (ret) { |
261 | 0 | lysc_update_path(ctx, NULL, NULL); |
262 | 0 | lysc_update_path(ctx, NULL, NULL); |
263 | 0 | } |
264 | | /* should include only this module, will fail later if not */ |
265 | 0 | ly_set_erase(&mod_set, NULL); |
266 | 0 | lyxp_expr_free(ctx->ctx, exp); |
267 | 0 | return ret; |
268 | 0 | } |
269 | | |
270 | | static LY_ERR |
271 | | lysp_ext_dup(const struct ly_ctx *ctx, struct lysp_ext_instance *ext, const struct lysp_ext_instance *orig_ext) |
272 | 0 | { |
273 | 0 | LY_ERR ret = LY_SUCCESS; |
274 | |
|
275 | 0 | *ext = *orig_ext; |
276 | 0 | DUP_STRING(ctx, orig_ext->name, ext->name, ret); |
277 | 0 | DUP_STRING(ctx, orig_ext->argument, ext->argument, ret); |
278 | |
|
279 | 0 | return ret; |
280 | 0 | } |
281 | | |
282 | | static LY_ERR |
283 | | lysp_restr_dup(const struct ly_ctx *ctx, struct lysp_restr *restr, const struct lysp_restr *orig_restr) |
284 | 0 | { |
285 | 0 | LY_ERR ret = LY_SUCCESS; |
286 | |
|
287 | 0 | if (orig_restr) { |
288 | 0 | DUP_STRING(ctx, orig_restr->arg.str, restr->arg.str, ret); |
289 | 0 | restr->arg.mod = orig_restr->arg.mod; |
290 | 0 | DUP_STRING(ctx, orig_restr->emsg, restr->emsg, ret); |
291 | 0 | DUP_STRING(ctx, orig_restr->eapptag, restr->eapptag, ret); |
292 | 0 | DUP_STRING(ctx, orig_restr->dsc, restr->dsc, ret); |
293 | 0 | DUP_STRING(ctx, orig_restr->ref, restr->ref, ret); |
294 | 0 | DUP_ARRAY(ctx, orig_restr->exts, restr->exts, lysp_ext_dup); |
295 | 0 | } |
296 | | |
297 | 0 | return ret; |
298 | 0 | } |
299 | | |
300 | | static LY_ERR |
301 | | lysp_string_dup(const struct ly_ctx *ctx, const char **str, const char **orig_str) |
302 | 0 | { |
303 | 0 | LY_ERR ret = LY_SUCCESS; |
304 | |
|
305 | 0 | DUP_STRING(ctx, *orig_str, *str, ret); |
306 | |
|
307 | 0 | return ret; |
308 | 0 | } |
309 | | |
310 | | LY_ERR |
311 | | lysp_qname_dup(const struct ly_ctx *ctx, struct lysp_qname *qname, const struct lysp_qname *orig_qname) |
312 | 0 | { |
313 | 0 | LY_ERR ret = LY_SUCCESS; |
314 | |
|
315 | 0 | if (!orig_qname->str) { |
316 | 0 | return LY_SUCCESS; |
317 | 0 | } |
318 | | |
319 | 0 | DUP_STRING(ctx, orig_qname->str, qname->str, ret); |
320 | 0 | assert(orig_qname->mod); |
321 | 0 | qname->mod = orig_qname->mod; |
322 | |
|
323 | 0 | return ret; |
324 | 0 | } |
325 | | |
326 | | static LY_ERR |
327 | | lysp_type_enum_dup(const struct ly_ctx *ctx, struct lysp_type_enum *enm, const struct lysp_type_enum *orig_enm) |
328 | 0 | { |
329 | 0 | LY_ERR ret = LY_SUCCESS; |
330 | |
|
331 | 0 | DUP_STRING(ctx, orig_enm->name, enm->name, ret); |
332 | 0 | DUP_STRING(ctx, orig_enm->dsc, enm->dsc, ret); |
333 | 0 | DUP_STRING(ctx, orig_enm->ref, enm->ref, ret); |
334 | 0 | enm->value = orig_enm->value; |
335 | 0 | DUP_ARRAY(ctx, orig_enm->iffeatures, enm->iffeatures, lysp_qname_dup); |
336 | 0 | DUP_ARRAY(ctx, orig_enm->exts, enm->exts, lysp_ext_dup); |
337 | 0 | enm->flags = orig_enm->flags; |
338 | |
|
339 | 0 | return ret; |
340 | 0 | } |
341 | | |
342 | | static LY_ERR |
343 | | lysp_type_dup(const struct ly_ctx *ctx, struct lysp_type *type, const struct lysp_type *orig_type) |
344 | 0 | { |
345 | 0 | LY_ERR ret = LY_SUCCESS; |
346 | |
|
347 | 0 | DUP_STRING_GOTO(ctx, orig_type->name, type->name, ret, done); |
348 | |
|
349 | 0 | if (orig_type->range) { |
350 | 0 | type->range = calloc(1, sizeof *type->range); |
351 | 0 | LY_CHECK_ERR_RET(!type->range, LOGMEM(ctx), LY_EMEM); |
352 | 0 | LY_CHECK_RET(lysp_restr_dup(ctx, type->range, orig_type->range)); |
353 | 0 | } |
354 | | |
355 | 0 | if (orig_type->length) { |
356 | 0 | type->length = calloc(1, sizeof *type->length); |
357 | 0 | LY_CHECK_ERR_RET(!type->length, LOGMEM(ctx), LY_EMEM); |
358 | 0 | LY_CHECK_RET(lysp_restr_dup(ctx, type->length, orig_type->length)); |
359 | 0 | } |
360 | | |
361 | 0 | DUP_ARRAY(ctx, orig_type->patterns, type->patterns, lysp_restr_dup); |
362 | 0 | DUP_ARRAY(ctx, orig_type->enums, type->enums, lysp_type_enum_dup); |
363 | 0 | DUP_ARRAY(ctx, orig_type->bits, type->bits, lysp_type_enum_dup); |
364 | 0 | LY_CHECK_GOTO(ret = lyxp_expr_dup(ctx, orig_type->path, &type->path), done); |
365 | 0 | DUP_ARRAY(ctx, orig_type->bases, type->bases, lysp_string_dup); |
366 | 0 | DUP_ARRAY(ctx, orig_type->types, type->types, lysp_type_dup); |
367 | 0 | DUP_ARRAY(ctx, orig_type->exts, type->exts, lysp_ext_dup); |
368 | |
|
369 | 0 | type->pmod = orig_type->pmod; |
370 | 0 | type->compiled = orig_type->compiled; |
371 | |
|
372 | 0 | type->fraction_digits = orig_type->fraction_digits; |
373 | 0 | type->require_instance = orig_type->require_instance; |
374 | 0 | type->flags = orig_type->flags; |
375 | |
|
376 | 0 | done: |
377 | 0 | return ret; |
378 | 0 | } |
379 | | |
380 | | static LY_ERR |
381 | | lysp_when_dup(const struct ly_ctx *ctx, struct lysp_when *when, const struct lysp_when *orig_when) |
382 | 0 | { |
383 | 0 | LY_ERR ret = LY_SUCCESS; |
384 | |
|
385 | 0 | DUP_STRING(ctx, orig_when->cond, when->cond, ret); |
386 | 0 | DUP_STRING(ctx, orig_when->dsc, when->dsc, ret); |
387 | 0 | DUP_STRING(ctx, orig_when->ref, when->ref, ret); |
388 | 0 | DUP_ARRAY(ctx, orig_when->exts, when->exts, lysp_ext_dup); |
389 | |
|
390 | 0 | return ret; |
391 | 0 | } |
392 | | |
393 | | static LY_ERR |
394 | | lysp_node_common_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig) |
395 | 0 | { |
396 | 0 | LY_ERR ret = LY_SUCCESS; |
397 | |
|
398 | 0 | node->parent = NULL; |
399 | 0 | node->nodetype = orig->nodetype; |
400 | 0 | node->flags = orig->flags; |
401 | 0 | node->next = NULL; |
402 | 0 | DUP_STRING(ctx, orig->name, node->name, ret); |
403 | 0 | DUP_STRING(ctx, orig->dsc, node->dsc, ret); |
404 | 0 | DUP_STRING(ctx, orig->ref, node->ref, ret); |
405 | 0 | DUP_ARRAY(ctx, orig->iffeatures, node->iffeatures, lysp_qname_dup); |
406 | 0 | DUP_ARRAY(ctx, orig->exts, node->exts, lysp_ext_dup); |
407 | |
|
408 | 0 | return ret; |
409 | 0 | } |
410 | | |
411 | | #define DUP_PWHEN(CTX, ORIG, NEW) \ |
412 | 0 | if (ORIG) { \ |
413 | 0 | NEW = calloc(1, sizeof *NEW); \ |
414 | 0 | LY_CHECK_ERR_RET(!NEW, LOGMEM(CTX), LY_EMEM); \ |
415 | 0 | LY_CHECK_RET(lysp_when_dup(CTX, NEW, ORIG)); \ |
416 | 0 | } |
417 | | |
418 | | static LY_ERR |
419 | | lysp_node_dup(const struct ly_ctx *ctx, struct lysp_node *node, const struct lysp_node *orig) |
420 | 0 | { |
421 | 0 | LY_ERR ret = LY_SUCCESS; |
422 | 0 | struct lysp_node_container *cont; |
423 | 0 | const struct lysp_node_container *orig_cont; |
424 | 0 | struct lysp_node_leaf *leaf; |
425 | 0 | const struct lysp_node_leaf *orig_leaf; |
426 | 0 | struct lysp_node_leaflist *llist; |
427 | 0 | const struct lysp_node_leaflist *orig_llist; |
428 | 0 | struct lysp_node_list *list; |
429 | 0 | const struct lysp_node_list *orig_list; |
430 | 0 | struct lysp_node_choice *choice; |
431 | 0 | const struct lysp_node_choice *orig_choice; |
432 | 0 | struct lysp_node_case *cas; |
433 | 0 | const struct lysp_node_case *orig_cas; |
434 | 0 | struct lysp_node_anydata *any; |
435 | 0 | const struct lysp_node_anydata *orig_any; |
436 | 0 | struct lysp_node_action *action; |
437 | 0 | const struct lysp_node_action *orig_action; |
438 | 0 | struct lysp_node_action_inout *action_inout; |
439 | 0 | const struct lysp_node_action_inout *orig_action_inout; |
440 | 0 | struct lysp_node_notif *notif; |
441 | 0 | const struct lysp_node_notif *orig_notif; |
442 | |
|
443 | 0 | assert(orig->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_ANYDATA | |
444 | 0 | LYS_RPC | LYS_ACTION | LYS_NOTIF)); |
445 | | |
446 | | /* common part */ |
447 | 0 | LY_CHECK_RET(lysp_node_common_dup(ctx, node, orig)); |
448 | | |
449 | | /* specific part */ |
450 | 0 | switch (node->nodetype) { |
451 | 0 | case LYS_CONTAINER: |
452 | 0 | cont = (struct lysp_node_container *)node; |
453 | 0 | orig_cont = (const struct lysp_node_container *)orig; |
454 | |
|
455 | 0 | DUP_PWHEN(ctx, orig_cont->when, cont->when); |
456 | 0 | DUP_ARRAY(ctx, orig_cont->musts, cont->musts, lysp_restr_dup); |
457 | 0 | DUP_STRING(ctx, orig_cont->presence, cont->presence, ret); |
458 | | /* we do not need the rest */ |
459 | 0 | break; |
460 | 0 | case LYS_LEAF: |
461 | 0 | leaf = (struct lysp_node_leaf *)node; |
462 | 0 | orig_leaf = (const struct lysp_node_leaf *)orig; |
463 | |
|
464 | 0 | DUP_PWHEN(ctx, orig_leaf->when, leaf->when); |
465 | 0 | DUP_ARRAY(ctx, orig_leaf->musts, leaf->musts, lysp_restr_dup); |
466 | 0 | LY_CHECK_RET(lysp_type_dup(ctx, &leaf->type, &orig_leaf->type)); |
467 | 0 | DUP_STRING(ctx, orig_leaf->units, leaf->units, ret); |
468 | 0 | LY_CHECK_RET(lysp_qname_dup(ctx, &leaf->dflt, &orig_leaf->dflt)); |
469 | 0 | break; |
470 | 0 | case LYS_LEAFLIST: |
471 | 0 | llist = (struct lysp_node_leaflist *)node; |
472 | 0 | orig_llist = (const struct lysp_node_leaflist *)orig; |
473 | |
|
474 | 0 | DUP_PWHEN(ctx, orig_llist->when, llist->when); |
475 | 0 | DUP_ARRAY(ctx, orig_llist->musts, llist->musts, lysp_restr_dup); |
476 | 0 | LY_CHECK_RET(lysp_type_dup(ctx, &llist->type, &orig_llist->type)); |
477 | 0 | DUP_STRING(ctx, orig_llist->units, llist->units, ret); |
478 | 0 | DUP_ARRAY(ctx, orig_llist->dflts, llist->dflts, lysp_qname_dup); |
479 | 0 | llist->min = orig_llist->min; |
480 | 0 | llist->max = orig_llist->max; |
481 | 0 | break; |
482 | 0 | case LYS_LIST: |
483 | 0 | list = (struct lysp_node_list *)node; |
484 | 0 | orig_list = (const struct lysp_node_list *)orig; |
485 | |
|
486 | 0 | DUP_PWHEN(ctx, orig_list->when, list->when); |
487 | 0 | DUP_ARRAY(ctx, orig_list->musts, list->musts, lysp_restr_dup); |
488 | 0 | DUP_STRING(ctx, orig_list->key, list->key, ret); |
489 | | /* we do not need these arrays */ |
490 | 0 | DUP_ARRAY(ctx, orig_list->uniques, list->uniques, lysp_qname_dup); |
491 | 0 | list->min = orig_list->min; |
492 | 0 | list->max = orig_list->max; |
493 | 0 | break; |
494 | 0 | case LYS_CHOICE: |
495 | 0 | choice = (struct lysp_node_choice *)node; |
496 | 0 | orig_choice = (const struct lysp_node_choice *)orig; |
497 | |
|
498 | 0 | DUP_PWHEN(ctx, orig_choice->when, choice->when); |
499 | | /* we do not need children */ |
500 | 0 | LY_CHECK_RET(lysp_qname_dup(ctx, &choice->dflt, &orig_choice->dflt)); |
501 | 0 | break; |
502 | 0 | case LYS_CASE: |
503 | 0 | cas = (struct lysp_node_case *)node; |
504 | 0 | orig_cas = (const struct lysp_node_case *)orig; |
505 | |
|
506 | 0 | DUP_PWHEN(ctx, orig_cas->when, cas->when); |
507 | | /* we do not need children */ |
508 | 0 | break; |
509 | 0 | case LYS_ANYDATA: |
510 | 0 | case LYS_ANYXML: |
511 | 0 | any = (struct lysp_node_anydata *)node; |
512 | 0 | orig_any = (const struct lysp_node_anydata *)orig; |
513 | |
|
514 | 0 | DUP_PWHEN(ctx, orig_any->when, any->when); |
515 | 0 | DUP_ARRAY(ctx, orig_any->musts, any->musts, lysp_restr_dup); |
516 | 0 | break; |
517 | 0 | case LYS_RPC: |
518 | 0 | case LYS_ACTION: |
519 | 0 | action = (struct lysp_node_action *)node; |
520 | 0 | orig_action = (const struct lysp_node_action *)orig; |
521 | |
|
522 | 0 | action->input.nodetype = orig_action->input.nodetype; |
523 | 0 | action->output.nodetype = orig_action->output.nodetype; |
524 | | /* we do not need the rest */ |
525 | 0 | break; |
526 | 0 | case LYS_INPUT: |
527 | 0 | case LYS_OUTPUT: |
528 | 0 | action_inout = (struct lysp_node_action_inout *)node; |
529 | 0 | orig_action_inout = (const struct lysp_node_action_inout *)orig; |
530 | |
|
531 | 0 | DUP_ARRAY(ctx, orig_action_inout->musts, action_inout->musts, lysp_restr_dup); |
532 | | /* we do not need the rest */ |
533 | 0 | break; |
534 | 0 | case LYS_NOTIF: |
535 | 0 | notif = (struct lysp_node_notif *)node; |
536 | 0 | orig_notif = (const struct lysp_node_notif *)orig; |
537 | |
|
538 | 0 | DUP_ARRAY(ctx, orig_notif->musts, notif->musts, lysp_restr_dup); |
539 | | /* we do not need the rest */ |
540 | 0 | break; |
541 | 0 | default: |
542 | 0 | LOGINT_RET(ctx); |
543 | 0 | } |
544 | | |
545 | 0 | return ret; |
546 | 0 | } |
547 | | |
548 | | /** |
549 | | * @brief Duplicate a single parsed node. Only attributes that are used in compilation are copied. |
550 | | * |
551 | | * @param[in] ctx libyang context. |
552 | | * @param[in] pnode Node to duplicate. |
553 | | * @param[in] with_links Whether to also copy any links (child, parent pointers). |
554 | | * @param[out] dup_p Duplicated parsed node. |
555 | | * @return LY_ERR value. |
556 | | */ |
557 | | static LY_ERR |
558 | | lysp_dup_single(const struct ly_ctx *ctx, const struct lysp_node *pnode, ly_bool with_links, struct lysp_node **dup_p) |
559 | 0 | { |
560 | 0 | LY_ERR ret = LY_SUCCESS; |
561 | 0 | void *mem = NULL; |
562 | |
|
563 | 0 | if (!pnode) { |
564 | 0 | *dup_p = NULL; |
565 | 0 | return LY_SUCCESS; |
566 | 0 | } |
567 | | |
568 | 0 | switch (pnode->nodetype) { |
569 | 0 | case LYS_CONTAINER: |
570 | 0 | mem = calloc(1, sizeof(struct lysp_node_container)); |
571 | 0 | break; |
572 | 0 | case LYS_LEAF: |
573 | 0 | mem = calloc(1, sizeof(struct lysp_node_leaf)); |
574 | 0 | break; |
575 | 0 | case LYS_LEAFLIST: |
576 | 0 | mem = calloc(1, sizeof(struct lysp_node_leaflist)); |
577 | 0 | break; |
578 | 0 | case LYS_LIST: |
579 | 0 | mem = calloc(1, sizeof(struct lysp_node_list)); |
580 | 0 | break; |
581 | 0 | case LYS_CHOICE: |
582 | 0 | mem = calloc(1, sizeof(struct lysp_node_choice)); |
583 | 0 | break; |
584 | 0 | case LYS_CASE: |
585 | 0 | mem = calloc(1, sizeof(struct lysp_node_case)); |
586 | 0 | break; |
587 | 0 | case LYS_ANYDATA: |
588 | 0 | case LYS_ANYXML: |
589 | 0 | mem = calloc(1, sizeof(struct lysp_node_anydata)); |
590 | 0 | break; |
591 | 0 | case LYS_INPUT: |
592 | 0 | case LYS_OUTPUT: |
593 | 0 | mem = calloc(1, sizeof(struct lysp_node_action_inout)); |
594 | 0 | break; |
595 | 0 | case LYS_ACTION: |
596 | 0 | case LYS_RPC: |
597 | 0 | mem = calloc(1, sizeof(struct lysp_node_action)); |
598 | 0 | break; |
599 | 0 | case LYS_NOTIF: |
600 | 0 | mem = calloc(1, sizeof(struct lysp_node_notif)); |
601 | 0 | break; |
602 | 0 | default: |
603 | 0 | LOGINT_RET(ctx); |
604 | 0 | } |
605 | 0 | LY_CHECK_ERR_GOTO(!mem, LOGMEM(ctx); ret = LY_EMEM, cleanup); |
606 | 0 | LY_CHECK_GOTO(ret = lysp_node_dup(ctx, mem, pnode), cleanup); |
607 | |
|
608 | 0 | if (with_links) { |
609 | | /* copy also parent and child pointers */ |
610 | 0 | ((struct lysp_node *)mem)->parent = pnode->parent; |
611 | 0 | switch (pnode->nodetype) { |
612 | 0 | case LYS_CONTAINER: |
613 | 0 | ((struct lysp_node_container *)mem)->child = ((struct lysp_node_container *)pnode)->child; |
614 | 0 | break; |
615 | 0 | case LYS_LIST: |
616 | 0 | ((struct lysp_node_list *)mem)->child = ((struct lysp_node_list *)pnode)->child; |
617 | 0 | break; |
618 | 0 | case LYS_CHOICE: |
619 | 0 | ((struct lysp_node_choice *)mem)->child = ((struct lysp_node_choice *)pnode)->child; |
620 | 0 | break; |
621 | 0 | case LYS_CASE: |
622 | 0 | ((struct lysp_node_case *)mem)->child = ((struct lysp_node_case *)pnode)->child; |
623 | 0 | break; |
624 | 0 | default: |
625 | 0 | break; |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | 0 | cleanup: |
630 | 0 | if (ret) { |
631 | 0 | free(mem); |
632 | 0 | } else { |
633 | 0 | *dup_p = mem; |
634 | 0 | } |
635 | 0 | return ret; |
636 | 0 | } |
637 | | |
638 | | #define AMEND_WRONG_NODETYPE(AMEND_STR, OP_STR, PROPERTY) \ |
639 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid %s of %s node - it is not possible to %s \"%s\" property.", \ |
640 | 0 | AMEND_STR, lys_nodetype2str(target->nodetype), OP_STR, PROPERTY);\ |
641 | 0 | ret = LY_EVALID; \ |
642 | 0 | goto cleanup; |
643 | | |
644 | | #define AMEND_CHECK_CARDINALITY(ARRAY, MAX, AMEND_STR, PROPERTY) \ |
645 | 0 | if (LY_ARRAY_COUNT(ARRAY) > MAX) { \ |
646 | 0 | LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Invalid %s of %s with too many (%"LY_PRI_ARRAY_COUNT_TYPE") %s properties.", \ |
647 | 0 | AMEND_STR, lys_nodetype2str(target->nodetype), LY_ARRAY_COUNT(ARRAY), PROPERTY); \ |
648 | 0 | ret = LY_EVALID; \ |
649 | 0 | goto cleanup; \ |
650 | 0 | } |
651 | | |
652 | | /** |
653 | | * @brief Apply refine. |
654 | | * |
655 | | * @param[in] ctx Compile context. |
656 | | * @param[in] rfn Refine to apply. |
657 | | * @param[in,out] target Refine target. |
658 | | * @return LY_ERR value. |
659 | | */ |
660 | | static LY_ERR |
661 | | lys_apply_refine(struct lysc_ctx *ctx, struct lysp_refine *rfn, struct lysp_node *target) |
662 | 0 | { |
663 | 0 | LY_ERR ret = LY_SUCCESS; |
664 | 0 | LY_ARRAY_COUNT_TYPE u; |
665 | 0 | struct lysp_qname *qname; |
666 | 0 | struct lysp_restr **musts, *must; |
667 | 0 | uint32_t *num; |
668 | | |
669 | | /* default value */ |
670 | 0 | if (rfn->dflts) { |
671 | 0 | switch (target->nodetype) { |
672 | 0 | case LYS_LEAF: |
673 | 0 | AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default"); |
674 | |
|
675 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str); |
676 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &rfn->dflts[0]), cleanup); |
677 | 0 | break; |
678 | 0 | case LYS_LEAFLIST: |
679 | 0 | if (rfn->dflts[0].mod->version < LYS_VERSION_1_1) { |
680 | 0 | LOGVAL(ctx->ctx, LYVE_SEMANTICS, |
681 | 0 | "Invalid refine of default in leaf-list - the default statement is allowed only in YANG 1.1 modules."); |
682 | 0 | ret = LY_EVALID; |
683 | 0 | goto cleanup; |
684 | 0 | } |
685 | | |
686 | 0 | FREE_ARRAY(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, lysp_qname_free); |
687 | 0 | ((struct lysp_node_leaflist *)target)->dflts = NULL; |
688 | 0 | LY_ARRAY_FOR(rfn->dflts, u) { |
689 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup); |
690 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->dflts[u]), cleanup); |
691 | 0 | } |
692 | 0 | break; |
693 | 0 | case LYS_CHOICE: |
694 | 0 | AMEND_CHECK_CARDINALITY(rfn->dflts, 1, "refine", "default"); |
695 | |
|
696 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str); |
697 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &rfn->dflts[0]), cleanup); |
698 | 0 | break; |
699 | 0 | default: |
700 | 0 | AMEND_WRONG_NODETYPE("refine", "replace", "default"); |
701 | 0 | } |
702 | 0 | } |
703 | | |
704 | | /* description */ |
705 | 0 | if (rfn->dsc) { |
706 | 0 | lydict_remove(ctx->ctx, target->dsc); |
707 | 0 | DUP_STRING_GOTO(ctx->ctx, rfn->dsc, target->dsc, ret, cleanup); |
708 | 0 | } |
709 | | |
710 | | /* reference */ |
711 | 0 | if (rfn->ref) { |
712 | 0 | lydict_remove(ctx->ctx, target->ref); |
713 | 0 | DUP_STRING_GOTO(ctx->ctx, rfn->ref, target->ref, ret, cleanup); |
714 | 0 | } |
715 | | |
716 | | /* config */ |
717 | 0 | if (rfn->flags & LYS_CONFIG_MASK) { |
718 | 0 | if (ctx->options & LYS_COMPILE_NO_CONFIG) { |
719 | 0 | LOGWRN(ctx->ctx, "Refining config inside %s has no effect (%s).", |
720 | 0 | (ctx->options & (LYS_IS_INPUT | LYS_IS_OUTPUT)) ? "RPC/action" : |
721 | 0 | ctx->options & LYS_IS_NOTIF ? "notification" : "a subtree ignoring config", ctx->path); |
722 | 0 | } else { |
723 | 0 | target->flags &= ~LYS_CONFIG_MASK; |
724 | 0 | target->flags |= rfn->flags & LYS_CONFIG_MASK; |
725 | 0 | } |
726 | 0 | } |
727 | | |
728 | | /* mandatory */ |
729 | 0 | if (rfn->flags & LYS_MAND_MASK) { |
730 | 0 | switch (target->nodetype) { |
731 | 0 | case LYS_LEAF: |
732 | 0 | case LYS_CHOICE: |
733 | 0 | case LYS_ANYDATA: |
734 | 0 | case LYS_ANYXML: |
735 | 0 | break; |
736 | 0 | default: |
737 | 0 | AMEND_WRONG_NODETYPE("refine", "replace", "mandatory"); |
738 | 0 | } |
739 | | |
740 | 0 | target->flags &= ~LYS_MAND_MASK; |
741 | 0 | target->flags |= rfn->flags & LYS_MAND_MASK; |
742 | 0 | } |
743 | | |
744 | | /* presence */ |
745 | 0 | if (rfn->presence) { |
746 | 0 | switch (target->nodetype) { |
747 | 0 | case LYS_CONTAINER: |
748 | 0 | break; |
749 | 0 | default: |
750 | 0 | AMEND_WRONG_NODETYPE("refine", "replace", "presence"); |
751 | 0 | } |
752 | | |
753 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_container *)target)->presence); |
754 | 0 | DUP_STRING_GOTO(ctx->ctx, rfn->presence, ((struct lysp_node_container *)target)->presence, ret, cleanup); |
755 | 0 | } |
756 | | |
757 | | /* must */ |
758 | 0 | if (rfn->musts) { |
759 | 0 | switch (target->nodetype) { |
760 | 0 | case LYS_CONTAINER: |
761 | 0 | case LYS_LIST: |
762 | 0 | case LYS_LEAF: |
763 | 0 | case LYS_LEAFLIST: |
764 | 0 | case LYS_ANYDATA: |
765 | 0 | case LYS_ANYXML: |
766 | 0 | musts = &((struct lysp_node_container *)target)->musts; |
767 | 0 | break; |
768 | 0 | default: |
769 | 0 | AMEND_WRONG_NODETYPE("refine", "add", "must"); |
770 | 0 | } |
771 | | |
772 | 0 | LY_ARRAY_FOR(rfn->musts, u) { |
773 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup); |
774 | 0 | LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &rfn->musts[u]), cleanup); |
775 | 0 | } |
776 | 0 | } |
777 | | |
778 | | /* min-elements */ |
779 | 0 | if (rfn->flags & LYS_SET_MIN) { |
780 | 0 | switch (target->nodetype) { |
781 | 0 | case LYS_LEAFLIST: |
782 | 0 | num = &((struct lysp_node_leaflist *)target)->min; |
783 | 0 | break; |
784 | 0 | case LYS_LIST: |
785 | 0 | num = &((struct lysp_node_list *)target)->min; |
786 | 0 | break; |
787 | 0 | default: |
788 | 0 | AMEND_WRONG_NODETYPE("refine", "replace", "min-elements"); |
789 | 0 | } |
790 | | |
791 | 0 | *num = rfn->min; |
792 | 0 | } |
793 | | |
794 | | /* max-elements */ |
795 | 0 | if (rfn->flags & LYS_SET_MAX) { |
796 | 0 | switch (target->nodetype) { |
797 | 0 | case LYS_LEAFLIST: |
798 | 0 | num = &((struct lysp_node_leaflist *)target)->max; |
799 | 0 | break; |
800 | 0 | case LYS_LIST: |
801 | 0 | num = &((struct lysp_node_list *)target)->max; |
802 | 0 | break; |
803 | 0 | default: |
804 | 0 | AMEND_WRONG_NODETYPE("refine", "replace", "max-elements"); |
805 | 0 | } |
806 | | |
807 | 0 | *num = rfn->max; |
808 | 0 | } |
809 | | |
810 | | /* if-feature */ |
811 | 0 | if (rfn->iffeatures) { |
812 | 0 | switch (target->nodetype) { |
813 | 0 | case LYS_LEAF: |
814 | 0 | case LYS_LEAFLIST: |
815 | 0 | case LYS_LIST: |
816 | 0 | case LYS_CONTAINER: |
817 | 0 | case LYS_CHOICE: |
818 | 0 | case LYS_CASE: |
819 | 0 | case LYS_ANYDATA: |
820 | 0 | case LYS_ANYXML: |
821 | 0 | break; |
822 | 0 | default: |
823 | 0 | AMEND_WRONG_NODETYPE("refine", "add", "if-feature"); |
824 | 0 | } |
825 | | |
826 | 0 | LY_ARRAY_FOR(rfn->iffeatures, u) { |
827 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, target->iffeatures, qname, ret, cleanup); |
828 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &rfn->iffeatures[u]), cleanup); |
829 | 0 | } |
830 | 0 | } |
831 | | |
832 | | /* extension */ |
833 | | /* TODO refine extensions */ |
834 | | |
835 | 0 | cleanup: |
836 | 0 | return ret; |
837 | 0 | } |
838 | | |
839 | | /** |
840 | | * @brief Apply deviate add. |
841 | | * |
842 | | * @param[in] ctx Compile context. |
843 | | * @param[in] d Deviate add to apply. |
844 | | * @param[in,out] target Deviation target. |
845 | | * @return LY_ERR value. |
846 | | */ |
847 | | static LY_ERR |
848 | | lys_apply_deviate_add(struct lysc_ctx *ctx, struct lysp_deviate_add *d, struct lysp_node *target) |
849 | 0 | { |
850 | 0 | LY_ERR ret = LY_SUCCESS; |
851 | 0 | LY_ARRAY_COUNT_TYPE u; |
852 | 0 | struct lysp_qname *qname; |
853 | 0 | uint32_t *num; |
854 | 0 | struct lysp_restr **musts, *must; |
855 | |
|
856 | 0 | #define DEV_CHECK_NONPRESENCE(TYPE, MEMBER, PROPERTY, VALUEMEMBER) \ |
857 | 0 | if (((TYPE)target)->MEMBER) { \ |
858 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation adding \"%s\" property which already exists (with value \"%s\").", \ |
859 | 0 | PROPERTY, ((TYPE)target)->VALUEMEMBER); \ |
860 | 0 | ret = LY_EVALID; \ |
861 | 0 | goto cleanup; \ |
862 | 0 | } |
863 | | |
864 | | /* [units-stmt] */ |
865 | 0 | if (d->units) { |
866 | 0 | switch (target->nodetype) { |
867 | 0 | case LYS_LEAF: |
868 | 0 | case LYS_LEAFLIST: |
869 | 0 | break; |
870 | 0 | default: |
871 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "units"); |
872 | 0 | } |
873 | | |
874 | 0 | DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, units, "units", units); |
875 | 0 | DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup); |
876 | 0 | } |
877 | | |
878 | | /* *must-stmt */ |
879 | 0 | if (d->musts) { |
880 | 0 | musts = lysp_node_musts_p(target); |
881 | 0 | if (!musts) { |
882 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "must"); |
883 | 0 | } |
884 | | |
885 | 0 | LY_ARRAY_FOR(d->musts, u) { |
886 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, *musts, must, ret, cleanup); |
887 | 0 | LY_CHECK_GOTO(ret = lysp_restr_dup(ctx->ctx, must, &d->musts[u]), cleanup); |
888 | 0 | } |
889 | 0 | } |
890 | | |
891 | | /* *unique-stmt */ |
892 | 0 | if (d->uniques) { |
893 | 0 | switch (target->nodetype) { |
894 | 0 | case LYS_LIST: |
895 | 0 | break; |
896 | 0 | default: |
897 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "unique"); |
898 | 0 | } |
899 | | |
900 | 0 | LY_ARRAY_FOR(d->uniques, u) { |
901 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_list *)target)->uniques, qname, ret, cleanup); |
902 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->uniques[u]), cleanup); |
903 | 0 | } |
904 | 0 | } |
905 | | |
906 | | /* *default-stmt */ |
907 | 0 | if (d->dflts) { |
908 | 0 | switch (target->nodetype) { |
909 | 0 | case LYS_LEAF: |
910 | 0 | AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default"); |
911 | 0 | DEV_CHECK_NONPRESENCE(struct lysp_node_leaf *, dflt.str, "default", dflt.str); |
912 | |
|
913 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflts[0]), cleanup); |
914 | 0 | break; |
915 | 0 | case LYS_LEAFLIST: |
916 | 0 | LY_ARRAY_FOR(d->dflts, u) { |
917 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, ((struct lysp_node_leaflist *)target)->dflts, qname, ret, cleanup); |
918 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, qname, &d->dflts[u]), cleanup); |
919 | 0 | } |
920 | 0 | break; |
921 | 0 | case LYS_CHOICE: |
922 | 0 | AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default"); |
923 | 0 | DEV_CHECK_NONPRESENCE(struct lysp_node_choice *, dflt.str, "default", dflt.str); |
924 | |
|
925 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflts[0]), cleanup); |
926 | 0 | break; |
927 | 0 | default: |
928 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "default"); |
929 | 0 | } |
930 | 0 | } |
931 | | |
932 | | /* [config-stmt] */ |
933 | 0 | if (d->flags & LYS_CONFIG_MASK) { |
934 | 0 | switch (target->nodetype) { |
935 | 0 | case LYS_CONTAINER: |
936 | 0 | case LYS_LEAF: |
937 | 0 | case LYS_LEAFLIST: |
938 | 0 | case LYS_LIST: |
939 | 0 | case LYS_CHOICE: |
940 | 0 | case LYS_ANYDATA: |
941 | 0 | case LYS_ANYXML: |
942 | 0 | break; |
943 | 0 | default: |
944 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "config"); |
945 | 0 | } |
946 | | |
947 | 0 | if (target->flags & LYS_CONFIG_MASK) { |
948 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
949 | 0 | "Invalid deviation adding \"config\" property which already exists (with value \"config %s\").", |
950 | 0 | target->flags & LYS_CONFIG_W ? "true" : "false"); |
951 | 0 | ret = LY_EVALID; |
952 | 0 | goto cleanup; |
953 | 0 | } |
954 | | |
955 | 0 | target->flags |= d->flags & LYS_CONFIG_MASK; |
956 | 0 | } |
957 | | |
958 | | /* [mandatory-stmt] */ |
959 | 0 | if (d->flags & LYS_MAND_MASK) { |
960 | 0 | switch (target->nodetype) { |
961 | 0 | case LYS_LEAF: |
962 | 0 | case LYS_CHOICE: |
963 | 0 | case LYS_ANYDATA: |
964 | 0 | case LYS_ANYXML: |
965 | 0 | break; |
966 | 0 | default: |
967 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "mandatory"); |
968 | 0 | } |
969 | | |
970 | 0 | if (target->flags & LYS_MAND_MASK) { |
971 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
972 | 0 | "Invalid deviation adding \"mandatory\" property which already exists (with value \"mandatory %s\").", |
973 | 0 | target->flags & LYS_MAND_TRUE ? "true" : "false"); |
974 | 0 | ret = LY_EVALID; |
975 | 0 | goto cleanup; |
976 | 0 | } |
977 | | |
978 | 0 | target->flags |= d->flags & LYS_MAND_MASK; |
979 | 0 | } |
980 | | |
981 | | /* [min-elements-stmt] */ |
982 | 0 | if (d->flags & LYS_SET_MIN) { |
983 | 0 | switch (target->nodetype) { |
984 | 0 | case LYS_LEAFLIST: |
985 | 0 | num = &((struct lysp_node_leaflist *)target)->min; |
986 | 0 | break; |
987 | 0 | case LYS_LIST: |
988 | 0 | num = &((struct lysp_node_list *)target)->min; |
989 | 0 | break; |
990 | 0 | default: |
991 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "min-elements"); |
992 | 0 | } |
993 | | |
994 | 0 | if (target->flags & LYS_SET_MIN) { |
995 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
996 | 0 | "Invalid deviation adding \"min-elements\" property which already exists (with value \"%u\").", *num); |
997 | 0 | ret = LY_EVALID; |
998 | 0 | goto cleanup; |
999 | 0 | } |
1000 | | |
1001 | 0 | *num = d->min; |
1002 | 0 | } |
1003 | | |
1004 | | /* [max-elements-stmt] */ |
1005 | 0 | if (d->flags & LYS_SET_MAX) { |
1006 | 0 | switch (target->nodetype) { |
1007 | 0 | case LYS_LEAFLIST: |
1008 | 0 | num = &((struct lysp_node_leaflist *)target)->max; |
1009 | 0 | break; |
1010 | 0 | case LYS_LIST: |
1011 | 0 | num = &((struct lysp_node_list *)target)->max; |
1012 | 0 | break; |
1013 | 0 | default: |
1014 | 0 | AMEND_WRONG_NODETYPE("deviation", "add", "max-elements"); |
1015 | 0 | } |
1016 | | |
1017 | 0 | if (target->flags & LYS_SET_MAX) { |
1018 | 0 | if (*num) { |
1019 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
1020 | 0 | "Invalid deviation adding \"max-elements\" property which already exists (with value \"%u\").", |
1021 | 0 | *num); |
1022 | 0 | } else { |
1023 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
1024 | 0 | "Invalid deviation adding \"max-elements\" property which already exists (with value \"unbounded\")."); |
1025 | 0 | } |
1026 | 0 | ret = LY_EVALID; |
1027 | 0 | goto cleanup; |
1028 | 0 | } |
1029 | | |
1030 | 0 | *num = d->max; |
1031 | 0 | } |
1032 | | |
1033 | 0 | cleanup: |
1034 | 0 | return ret; |
1035 | 0 | } |
1036 | | |
1037 | | /** |
1038 | | * @brief Apply deviate delete. |
1039 | | * |
1040 | | * @param[in] ctx Compile context. |
1041 | | * @param[in] d Deviate delete to apply. |
1042 | | * @param[in,out] target Deviation target. |
1043 | | * @return LY_ERR value. |
1044 | | */ |
1045 | | static LY_ERR |
1046 | | lys_apply_deviate_delete(struct lysc_ctx *ctx, struct lysp_deviate_del *d, struct lysp_node *target) |
1047 | 0 | { |
1048 | 0 | LY_ERR ret = LY_SUCCESS; |
1049 | 0 | struct lysp_restr **musts; |
1050 | 0 | LY_ARRAY_COUNT_TYPE u, v; |
1051 | 0 | struct lysp_qname **uniques, **dflts; |
1052 | |
|
1053 | 0 | #define DEV_DEL_ARRAY(DEV_ARRAY, ORIG_ARRAY, DEV_MEMBER, ORIG_MEMBER, FREE_FUNC, PROPERTY) \ |
1054 | 0 | LY_ARRAY_FOR(d->DEV_ARRAY, u) { \ |
1055 | 0 | int found = 0; \ |
1056 | 0 | LY_ARRAY_FOR(ORIG_ARRAY, v) { \ |
1057 | 0 | if (!strcmp(d->DEV_ARRAY[u]DEV_MEMBER, (ORIG_ARRAY)[v]ORIG_MEMBER)) { \ |
1058 | 0 | found = 1; \ |
1059 | 0 | break; \ |
1060 | 0 | } \ |
1061 | 0 | } \ |
1062 | 0 | if (!found) { \ |
1063 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, \ |
1064 | 0 | "Invalid deviation deleting \"%s\" property \"%s\" which does not match any of the target's property values.", \ |
1065 | 0 | PROPERTY, d->DEV_ARRAY[u]DEV_MEMBER); \ |
1066 | 0 | ret = LY_EVALID; \ |
1067 | 0 | goto cleanup; \ |
1068 | 0 | } \ |
1069 | 0 | LY_ARRAY_DECREMENT(ORIG_ARRAY); \ |
1070 | 0 | FREE_FUNC(ctx->ctx, &(ORIG_ARRAY)[v]); \ |
1071 | 0 | memmove(&(ORIG_ARRAY)[v], &(ORIG_ARRAY)[v + 1], (LY_ARRAY_COUNT(ORIG_ARRAY) - v) * sizeof *(ORIG_ARRAY)); \ |
1072 | 0 | } \ |
1073 | 0 | if (!LY_ARRAY_COUNT(ORIG_ARRAY)) { \ |
1074 | 0 | LY_ARRAY_FREE(ORIG_ARRAY); \ |
1075 | 0 | ORIG_ARRAY = NULL; \ |
1076 | 0 | } |
1077 | |
|
1078 | 0 | #define DEV_CHECK_PRESENCE_VALUE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \ |
1079 | 0 | if (!((TYPE)target)->MEMBER) { \ |
1080 | 0 | LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \ |
1081 | 0 | ret = LY_EVALID; \ |
1082 | 0 | goto cleanup; \ |
1083 | 0 | } else if (strcmp(((TYPE)target)->MEMBER, VALUE)) { \ |
1084 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, \ |
1085 | 0 | "Invalid deviation deleting \"%s\" property \"%s\" which does not match the target's property value \"%s\".", \ |
1086 | 0 | PROPERTY, VALUE, ((TYPE)target)->MEMBER); \ |
1087 | 0 | ret = LY_EVALID; \ |
1088 | 0 | goto cleanup; \ |
1089 | 0 | } |
1090 | | |
1091 | | /* [units-stmt] */ |
1092 | 0 | if (d->units) { |
1093 | 0 | switch (target->nodetype) { |
1094 | 0 | case LYS_LEAF: |
1095 | 0 | case LYS_LEAFLIST: |
1096 | 0 | break; |
1097 | 0 | default: |
1098 | 0 | AMEND_WRONG_NODETYPE("deviation", "delete", "units"); |
1099 | 0 | } |
1100 | | |
1101 | 0 | DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, units, "deleting", "units", d->units); |
1102 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units); |
1103 | 0 | ((struct lysp_node_leaf *)target)->units = NULL; |
1104 | 0 | } |
1105 | | |
1106 | | /* *must-stmt */ |
1107 | 0 | if (d->musts) { |
1108 | 0 | musts = lysp_node_musts_p(target); |
1109 | 0 | if (!musts) { |
1110 | 0 | AMEND_WRONG_NODETYPE("deviation", "delete", "must"); |
1111 | 0 | } |
1112 | | |
1113 | 0 | DEV_DEL_ARRAY(musts, *musts, .arg.str, .arg.str, lysp_restr_free, "must"); |
1114 | 0 | } |
1115 | | |
1116 | | /* *unique-stmt */ |
1117 | 0 | if (d->uniques) { |
1118 | 0 | switch (target->nodetype) { |
1119 | 0 | case LYS_LIST: |
1120 | 0 | break; |
1121 | 0 | default: |
1122 | 0 | AMEND_WRONG_NODETYPE("deviation", "delete", "unique"); |
1123 | 0 | } |
1124 | | |
1125 | 0 | uniques = &((struct lysp_node_list *)target)->uniques; |
1126 | 0 | DEV_DEL_ARRAY(uniques, *uniques, .str, .str, lysp_qname_free, "unique"); |
1127 | 0 | } |
1128 | | |
1129 | | /* *default-stmt */ |
1130 | 0 | if (d->dflts) { |
1131 | 0 | switch (target->nodetype) { |
1132 | 0 | case LYS_LEAF: |
1133 | 0 | AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default"); |
1134 | 0 | DEV_CHECK_PRESENCE_VALUE(struct lysp_node_leaf *, dflt.str, "deleting", "default", d->dflts[0].str); |
1135 | |
|
1136 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str); |
1137 | 0 | ((struct lysp_node_leaf *)target)->dflt.str = NULL; |
1138 | 0 | break; |
1139 | 0 | case LYS_LEAFLIST: |
1140 | 0 | dflts = &((struct lysp_node_leaflist *)target)->dflts; |
1141 | 0 | DEV_DEL_ARRAY(dflts, *dflts, .str, .str, lysp_qname_free, "default"); |
1142 | 0 | break; |
1143 | 0 | case LYS_CHOICE: |
1144 | 0 | AMEND_CHECK_CARDINALITY(d->dflts, 1, "deviation", "default"); |
1145 | 0 | DEV_CHECK_PRESENCE_VALUE(struct lysp_node_choice *, dflt.str, "deleting", "default", d->dflts[0].str); |
1146 | |
|
1147 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str); |
1148 | 0 | ((struct lysp_node_choice *)target)->dflt.str = NULL; |
1149 | 0 | break; |
1150 | 0 | default: |
1151 | 0 | AMEND_WRONG_NODETYPE("deviation", "delete", "default"); |
1152 | 0 | } |
1153 | 0 | } |
1154 | | |
1155 | 0 | cleanup: |
1156 | 0 | return ret; |
1157 | 0 | } |
1158 | | |
1159 | | /** |
1160 | | * @brief Apply deviate replace. |
1161 | | * |
1162 | | * @param[in] ctx Compile context. |
1163 | | * @param[in] d Deviate replace to apply. |
1164 | | * @param[in,out] target Deviation target. |
1165 | | * @return LY_ERR value. |
1166 | | */ |
1167 | | static LY_ERR |
1168 | | lys_apply_deviate_replace(struct lysc_ctx *ctx, struct lysp_deviate_rpl *d, struct lysp_node *target) |
1169 | 0 | { |
1170 | 0 | LY_ERR ret = LY_SUCCESS; |
1171 | 0 | uint32_t *num; |
1172 | |
|
1173 | 0 | #define DEV_CHECK_PRESENCE(TYPE, MEMBER, DEVTYPE, PROPERTY, VALUE) \ |
1174 | 0 | if (!((TYPE)target)->MEMBER) { \ |
1175 | 0 | LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, DEVTYPE, PROPERTY, VALUE); \ |
1176 | 0 | ret = LY_EVALID; \ |
1177 | 0 | goto cleanup; \ |
1178 | 0 | } |
1179 | | |
1180 | | /* [type-stmt] */ |
1181 | 0 | if (d->type) { |
1182 | 0 | switch (target->nodetype) { |
1183 | 0 | case LYS_LEAF: |
1184 | 0 | case LYS_LEAFLIST: |
1185 | 0 | break; |
1186 | 0 | default: |
1187 | 0 | AMEND_WRONG_NODETYPE("deviation", "replace", "type"); |
1188 | 0 | } |
1189 | | |
1190 | 0 | lysp_type_free(ctx->ctx, &((struct lysp_node_leaf *)target)->type); |
1191 | 0 | lysp_type_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->type, d->type); |
1192 | 0 | } |
1193 | | |
1194 | | /* [units-stmt] */ |
1195 | 0 | if (d->units) { |
1196 | 0 | switch (target->nodetype) { |
1197 | 0 | case LYS_LEAF: |
1198 | 0 | case LYS_LEAFLIST: |
1199 | 0 | break; |
1200 | 0 | default: |
1201 | 0 | AMEND_WRONG_NODETYPE("deviation", "replace", "units"); |
1202 | 0 | } |
1203 | | |
1204 | 0 | DEV_CHECK_PRESENCE(struct lysp_node_leaf *, units, "replacing", "units", d->units); |
1205 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->units); |
1206 | 0 | DUP_STRING_GOTO(ctx->ctx, d->units, ((struct lysp_node_leaf *)target)->units, ret, cleanup); |
1207 | 0 | } |
1208 | | |
1209 | | /* [default-stmt] */ |
1210 | 0 | if (d->dflt.str) { |
1211 | 0 | switch (target->nodetype) { |
1212 | 0 | case LYS_LEAF: |
1213 | 0 | DEV_CHECK_PRESENCE(struct lysp_node_leaf *, dflt.str, "replacing", "default", d->dflt.str); |
1214 | |
|
1215 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_leaf *)target)->dflt.str); |
1216 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_leaf *)target)->dflt, &d->dflt), cleanup); |
1217 | 0 | break; |
1218 | 0 | case LYS_CHOICE: |
1219 | 0 | DEV_CHECK_PRESENCE(struct lysp_node_choice *, dflt.str, "replacing", "default", d->dflt); |
1220 | |
|
1221 | 0 | lydict_remove(ctx->ctx, ((struct lysp_node_choice *)target)->dflt.str); |
1222 | 0 | LY_CHECK_GOTO(ret = lysp_qname_dup(ctx->ctx, &((struct lysp_node_choice *)target)->dflt, &d->dflt), cleanup); |
1223 | 0 | break; |
1224 | 0 | default: |
1225 | 0 | AMEND_WRONG_NODETYPE("deviation", "replace", "default"); |
1226 | 0 | } |
1227 | 0 | } |
1228 | | |
1229 | | /* [config-stmt] */ |
1230 | 0 | if (d->flags & LYS_CONFIG_MASK) { |
1231 | 0 | switch (target->nodetype) { |
1232 | 0 | case LYS_CONTAINER: |
1233 | 0 | case LYS_LEAF: |
1234 | 0 | case LYS_LEAFLIST: |
1235 | 0 | case LYS_LIST: |
1236 | 0 | case LYS_CHOICE: |
1237 | 0 | case LYS_ANYDATA: |
1238 | 0 | case LYS_ANYXML: |
1239 | 0 | break; |
1240 | 0 | default: |
1241 | 0 | AMEND_WRONG_NODETYPE("deviation", "replace", "config"); |
1242 | 0 | } |
1243 | | |
1244 | 0 | if (!(target->flags & LYS_CONFIG_MASK)) { |
1245 | 0 | LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "config", |
1246 | 0 | d->flags & LYS_CONFIG_W ? "config true" : "config false"); |
1247 | 0 | ret = LY_EVALID; |
1248 | 0 | goto cleanup; |
1249 | 0 | } |
1250 | | |
1251 | 0 | target->flags &= ~LYS_CONFIG_MASK; |
1252 | 0 | target->flags |= d->flags & LYS_CONFIG_MASK; |
1253 | 0 | } |
1254 | | |
1255 | | /* [mandatory-stmt] */ |
1256 | 0 | if (d->flags & LYS_MAND_MASK) { |
1257 | 0 | switch (target->nodetype) { |
1258 | 0 | case LYS_LEAF: |
1259 | 0 | case LYS_CHOICE: |
1260 | 0 | case LYS_ANYDATA: |
1261 | 0 | case LYS_ANYXML: |
1262 | 0 | break; |
1263 | 0 | default: |
1264 | 0 | AMEND_WRONG_NODETYPE("deviation", "replace", "mandatory"); |
1265 | 0 | } |
1266 | | |
1267 | 0 | if (!(target->flags & LYS_MAND_MASK)) { |
1268 | 0 | LOGVAL(ctx->ctx, LY_VCODE_DEV_NOT_PRESENT, "replacing", "mandatory", |
1269 | 0 | d->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false"); |
1270 | 0 | ret = LY_EVALID; |
1271 | 0 | goto cleanup; |
1272 | 0 | } |
1273 | | |
1274 | 0 | target->flags &= ~LYS_MAND_MASK; |
1275 | 0 | target->flags |= d->flags & LYS_MAND_MASK; |
1276 | 0 | } |
1277 | | |
1278 | | /* [min-elements-stmt] */ |
1279 | 0 | if (d->flags & LYS_SET_MIN) { |
1280 | 0 | switch (target->nodetype) { |
1281 | 0 | case LYS_LEAFLIST: |
1282 | 0 | num = &((struct lysp_node_leaflist *)target)->min; |
1283 | 0 | break; |
1284 | 0 | case LYS_LIST: |
1285 | 0 | num = &((struct lysp_node_list *)target)->min; |
1286 | 0 | break; |
1287 | 0 | default: |
1288 | 0 | AMEND_WRONG_NODETYPE("deviation", "replace", "min-elements"); |
1289 | 0 | } |
1290 | | |
1291 | 0 | if (!(target->flags & LYS_SET_MIN)) { |
1292 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"min-elements\" property which is not present."); |
1293 | 0 | ret = LY_EVALID; |
1294 | 0 | goto cleanup; |
1295 | 0 | } |
1296 | | |
1297 | 0 | *num = d->min; |
1298 | 0 | } |
1299 | | |
1300 | | /* [max-elements-stmt] */ |
1301 | 0 | if (d->flags & LYS_SET_MAX) { |
1302 | 0 | switch (target->nodetype) { |
1303 | 0 | case LYS_LEAFLIST: |
1304 | 0 | num = &((struct lysp_node_leaflist *)target)->max; |
1305 | 0 | break; |
1306 | 0 | case LYS_LIST: |
1307 | 0 | num = &((struct lysp_node_list *)target)->max; |
1308 | 0 | break; |
1309 | 0 | default: |
1310 | 0 | AMEND_WRONG_NODETYPE("deviation", "replace", "max-elements"); |
1311 | 0 | } |
1312 | | |
1313 | 0 | if (!(target->flags & LYS_SET_MAX)) { |
1314 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, "Invalid deviation replacing \"max-elements\" property which is not present."); |
1315 | 0 | ret = LY_EVALID; |
1316 | 0 | goto cleanup; |
1317 | 0 | } |
1318 | | |
1319 | 0 | *num = d->max; |
1320 | 0 | } |
1321 | | |
1322 | 0 | cleanup: |
1323 | 0 | return ret; |
1324 | 0 | } |
1325 | | |
1326 | | /** |
1327 | | * @brief Get module of a single nodeid node name test. |
1328 | | * |
1329 | | * @param[in] ctx libyang context. |
1330 | | * @param[in] nametest Nametest with an optional prefix. |
1331 | | * @param[in] nametest_len Length of @p nametest. |
1332 | | * @param[in] mod Both current and prefix module for resolving prefixes and to return in case of no prefix. |
1333 | | * @param[out] name Optional pointer to the name test without the prefix. |
1334 | | * @param[out] name_len Length of @p name. |
1335 | | * @return Resolved module. |
1336 | | */ |
1337 | | static const struct lys_module * |
1338 | | lys_schema_node_get_module(const struct ly_ctx *ctx, const char *nametest, size_t nametest_len, |
1339 | | const struct lysp_module *mod, const char **name, size_t *name_len) |
1340 | 0 | { |
1341 | 0 | const struct lys_module *target_mod; |
1342 | 0 | const char *ptr; |
1343 | |
|
1344 | 0 | ptr = ly_strnchr(nametest, ':', nametest_len); |
1345 | 0 | if (ptr) { |
1346 | 0 | target_mod = ly_resolve_prefix(ctx, nametest, ptr - nametest, LY_VALUE_SCHEMA, (void *)mod); |
1347 | 0 | if (!target_mod) { |
1348 | 0 | LOGVAL(ctx, LYVE_REFERENCE, |
1349 | 0 | "Invalid absolute-schema-nodeid nametest \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".", |
1350 | 0 | (int)nametest_len, nametest, (int)(ptr - nametest), nametest, LYSP_MODULE_NAME(mod)); |
1351 | 0 | return NULL; |
1352 | 0 | } |
1353 | | |
1354 | 0 | if (name) { |
1355 | 0 | *name = ptr + 1; |
1356 | 0 | *name_len = nametest_len - ((ptr - nametest) + 1); |
1357 | 0 | } |
1358 | 0 | } else { |
1359 | 0 | target_mod = mod->mod; |
1360 | 0 | if (name) { |
1361 | 0 | *name = nametest; |
1362 | 0 | *name_len = nametest_len; |
1363 | 0 | } |
1364 | 0 | } |
1365 | | |
1366 | 0 | return target_mod; |
1367 | 0 | } |
1368 | | |
1369 | | /** |
1370 | | * @brief Check whether a compiled node matches a single schema nodeid name test. |
1371 | | * |
1372 | | * @param[in,out] node Compiled node to consider. On a match it is moved to its parent. |
1373 | | * @param[in] mod Expected module. |
1374 | | * @param[in] name Expected name. |
1375 | | * @param[in] name_len Length of @p name. |
1376 | | * @return Whether it is a match or not. |
1377 | | */ |
1378 | | static ly_bool |
1379 | | lysp_schema_nodeid_match_node(const struct lysc_node **node, const struct lys_module *mod, const char *name, |
1380 | | size_t name_len) |
1381 | 0 | { |
1382 | | /* compare with the module of the node */ |
1383 | 0 | if ((*node)->module != mod) { |
1384 | 0 | return 0; |
1385 | 0 | } |
1386 | | |
1387 | | /* compare names */ |
1388 | 0 | if (ly_strncmp((*node)->name, name, name_len)) { |
1389 | 0 | return 0; |
1390 | 0 | } |
1391 | | |
1392 | | /* move to next parent */ |
1393 | 0 | *node = (*node)->parent; |
1394 | |
|
1395 | 0 | return 1; |
1396 | 0 | } |
1397 | | |
1398 | | /** |
1399 | | * @brief Check whether a node matches specific schema nodeid. |
1400 | | * |
1401 | | * @param[in] exp Parsed nodeid to match. |
1402 | | * @param[in] exp_pmod Module to use for nodes in @p exp without a prefix. |
1403 | | * @param[in] ctx_node Initial context node that should match, only for descendant paths. |
1404 | | * @param[in] parent First compiled parent to consider. If @p pnode is NULL, it is condered the node to be matched. |
1405 | | * @param[in] pnode Parsed node to be matched. May be NULL if the target node was already compiled. |
1406 | | * @param[in] pnode_mod Compiled @p pnode to-be module. |
1407 | | * @return Whether it is a match or not. |
1408 | | */ |
1409 | | static ly_bool |
1410 | | lysp_schema_nodeid_match(const struct lyxp_expr *exp, const struct lysp_module *exp_pmod, const struct lysc_node *ctx_node, |
1411 | | const struct lysc_node *parent, const struct lysp_node *pnode, const struct lys_module *pnode_mod) |
1412 | 0 | { |
1413 | 0 | uint32_t i; |
1414 | 0 | const struct lys_module *mod; |
1415 | 0 | const char *name = NULL; |
1416 | 0 | size_t name_len = 0; |
1417 | | |
1418 | | /* compare last node in the node ID */ |
1419 | 0 | i = exp->used - 1; |
1420 | | |
1421 | | /* get exp node ID module */ |
1422 | 0 | mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name, &name_len); |
1423 | 0 | assert(mod); |
1424 | |
|
1425 | 0 | if (pnode) { |
1426 | | /* compare on the last parsed-only node */ |
1427 | 0 | if ((pnode_mod != mod) || ly_strncmp(pnode->name, name, name_len)) { |
1428 | 0 | return 0; |
1429 | 0 | } |
1430 | 0 | } else { |
1431 | | /* using parent directly */ |
1432 | 0 | if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) { |
1433 | 0 | return 0; |
1434 | 0 | } |
1435 | 0 | } |
1436 | | |
1437 | | /* now compare all the compiled parents */ |
1438 | 0 | while (i > 1) { |
1439 | 0 | i -= 2; |
1440 | 0 | assert(exp->tokens[i] == LYXP_TOKEN_NAMETEST); |
1441 | |
|
1442 | 0 | if (!parent) { |
1443 | | /* no more parents but path continues */ |
1444 | 0 | return 0; |
1445 | 0 | } |
1446 | | |
1447 | | /* get exp node ID module */ |
1448 | 0 | mod = lys_schema_node_get_module(exp_pmod->mod->ctx, exp->expr + exp->tok_pos[i], exp->tok_len[i], exp_pmod, &name, |
1449 | 0 | &name_len); |
1450 | 0 | assert(mod); |
1451 | | |
1452 | | /* compare with the parent */ |
1453 | 0 | if (!lysp_schema_nodeid_match_node(&parent, mod, name, name_len)) { |
1454 | 0 | return 0; |
1455 | 0 | } |
1456 | 0 | } |
1457 | | |
1458 | 0 | if (ctx_node && (ctx_node != parent)) { |
1459 | | /* descendant path has not finished in the context node */ |
1460 | 0 | return 0; |
1461 | 0 | } else if (!ctx_node && parent) { |
1462 | | /* some parent was not matched */ |
1463 | 0 | return 0; |
1464 | 0 | } |
1465 | | |
1466 | 0 | return 1; |
1467 | 0 | } |
1468 | | |
1469 | | void |
1470 | | lysc_augment_free(const struct ly_ctx *ctx, struct lysc_augment *aug) |
1471 | 0 | { |
1472 | 0 | if (aug) { |
1473 | 0 | lyxp_expr_free(ctx, aug->nodeid); |
1474 | |
|
1475 | 0 | free(aug); |
1476 | 0 | } |
1477 | 0 | } |
1478 | | |
1479 | | void |
1480 | | lysc_deviation_free(const struct ly_ctx *ctx, struct lysc_deviation *dev) |
1481 | 0 | { |
1482 | 0 | if (dev) { |
1483 | 0 | lyxp_expr_free(ctx, dev->nodeid); |
1484 | 0 | LY_ARRAY_FREE(dev->devs); |
1485 | 0 | LY_ARRAY_FREE(dev->dev_pmods); |
1486 | |
|
1487 | 0 | free(dev); |
1488 | 0 | } |
1489 | 0 | } |
1490 | | |
1491 | | void |
1492 | | lysc_refine_free(const struct ly_ctx *ctx, struct lysc_refine *rfn) |
1493 | 0 | { |
1494 | 0 | if (rfn) { |
1495 | 0 | lyxp_expr_free(ctx, rfn->nodeid); |
1496 | 0 | LY_ARRAY_FREE(rfn->rfns); |
1497 | |
|
1498 | 0 | free(rfn); |
1499 | 0 | } |
1500 | 0 | } |
1501 | | |
1502 | | void |
1503 | | lysp_dev_node_free(const struct ly_ctx *ctx, struct lysp_node *dev_pnode) |
1504 | 0 | { |
1505 | 0 | if (!dev_pnode) { |
1506 | 0 | return; |
1507 | 0 | } |
1508 | | |
1509 | 0 | switch (dev_pnode->nodetype) { |
1510 | 0 | case LYS_CONTAINER: |
1511 | 0 | ((struct lysp_node_container *)dev_pnode)->child = NULL; |
1512 | 0 | break; |
1513 | 0 | case LYS_LIST: |
1514 | 0 | ((struct lysp_node_list *)dev_pnode)->child = NULL; |
1515 | 0 | break; |
1516 | 0 | case LYS_CHOICE: |
1517 | 0 | ((struct lysp_node_choice *)dev_pnode)->child = NULL; |
1518 | 0 | break; |
1519 | 0 | case LYS_CASE: |
1520 | 0 | ((struct lysp_node_case *)dev_pnode)->child = NULL; |
1521 | 0 | break; |
1522 | 0 | case LYS_LEAF: |
1523 | 0 | case LYS_LEAFLIST: |
1524 | 0 | case LYS_ANYXML: |
1525 | 0 | case LYS_ANYDATA: |
1526 | | /* no children */ |
1527 | 0 | break; |
1528 | 0 | case LYS_NOTIF: |
1529 | 0 | ((struct lysp_node_notif *)dev_pnode)->child = NULL; |
1530 | 0 | break; |
1531 | 0 | case LYS_RPC: |
1532 | 0 | case LYS_ACTION: |
1533 | 0 | ((struct lysp_node_action *)dev_pnode)->input.child = NULL; |
1534 | 0 | ((struct lysp_node_action *)dev_pnode)->output.child = NULL; |
1535 | 0 | break; |
1536 | 0 | case LYS_INPUT: |
1537 | 0 | case LYS_OUTPUT: |
1538 | 0 | ((struct lysp_node_action_inout *)dev_pnode)->child = NULL; |
1539 | 0 | lysp_node_free((struct ly_ctx *)ctx, dev_pnode); |
1540 | 0 | free(dev_pnode); |
1541 | 0 | return; |
1542 | 0 | default: |
1543 | 0 | LOGINT(ctx); |
1544 | 0 | return; |
1545 | 0 | } |
1546 | | |
1547 | 0 | lysp_node_free((struct ly_ctx *)ctx, dev_pnode); |
1548 | 0 | } |
1549 | | |
1550 | | LY_ERR |
1551 | | lys_compile_node_deviations_refines(struct lysc_ctx *ctx, const struct lysp_node *pnode, const struct lysc_node *parent, |
1552 | | struct lysp_node **dev_pnode, ly_bool *not_supported) |
1553 | 0 | { |
1554 | 0 | LY_ERR ret = LY_SUCCESS; |
1555 | 0 | uint32_t i; |
1556 | 0 | LY_ARRAY_COUNT_TYPE u; |
1557 | 0 | struct lys_module *orig_mod = ctx->cur_mod; |
1558 | 0 | struct lysp_module *orig_pmod = ctx->pmod; |
1559 | 0 | char orig_path[LYSC_CTX_BUFSIZE]; |
1560 | 0 | struct lysc_refine *rfn; |
1561 | 0 | struct lysc_deviation *dev; |
1562 | 0 | struct lysp_deviation *dev_p; |
1563 | 0 | struct lysp_deviate *d; |
1564 | |
|
1565 | 0 | *dev_pnode = NULL; |
1566 | 0 | *not_supported = 0; |
1567 | |
|
1568 | 0 | for (i = 0; i < ctx->uses_rfns.count; ++i) { |
1569 | 0 | rfn = ctx->uses_rfns.objs[i]; |
1570 | |
|
1571 | 0 | if (!lysp_schema_nodeid_match(rfn->nodeid, rfn->nodeid_pmod, rfn->nodeid_ctx_node, parent, pnode, orig_mod)) { |
1572 | | /* not our target node */ |
1573 | 0 | continue; |
1574 | 0 | } |
1575 | | |
1576 | 0 | if (!*dev_pnode) { |
1577 | | /* first refine on this node, create a copy first */ |
1578 | 0 | LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup); |
1579 | 0 | } |
1580 | | |
1581 | | /* use modules from the refine */ |
1582 | 0 | ctx->cur_mod = rfn->nodeid_pmod->mod; |
1583 | 0 | ctx->pmod = (struct lysp_module *)rfn->nodeid_pmod; |
1584 | | |
1585 | | /* apply all the refines by changing (the copy of) the parsed node */ |
1586 | 0 | LY_ARRAY_FOR(rfn->rfns, u) { |
1587 | | /* keep the current path and add to it */ |
1588 | 0 | lysc_update_path(ctx, NULL, "{refine}"); |
1589 | 0 | lysc_update_path(ctx, NULL, rfn->rfns[u]->nodeid); |
1590 | | |
1591 | | /* apply refine and restore the path */ |
1592 | 0 | ret = lys_apply_refine(ctx, rfn->rfns[u], *dev_pnode); |
1593 | 0 | lysc_update_path(ctx, NULL, NULL); |
1594 | 0 | lysc_update_path(ctx, NULL, NULL); |
1595 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1596 | 0 | } |
1597 | | |
1598 | | /* refine was applied, remove it */ |
1599 | 0 | lysc_refine_free(ctx->ctx, rfn); |
1600 | 0 | ly_set_rm_index(&ctx->uses_rfns, i, NULL); |
1601 | | |
1602 | | /* all the refines for one target node are in one structure, we are done */ |
1603 | 0 | break; |
1604 | 0 | } |
1605 | | |
1606 | 0 | for (i = 0; i < ctx->devs.count; ++i) { |
1607 | 0 | dev = ctx->devs.objs[i]; |
1608 | |
|
1609 | 0 | if (!lysp_schema_nodeid_match(dev->nodeid, dev->dev_pmods[0], NULL, parent, pnode, orig_mod)) { |
1610 | | /* not our target node */ |
1611 | 0 | continue; |
1612 | 0 | } |
1613 | | |
1614 | 0 | if (dev->not_supported) { |
1615 | | /* it is not supported, no more deviations */ |
1616 | 0 | *not_supported = 1; |
1617 | 0 | goto dev_applied; |
1618 | 0 | } |
1619 | | |
1620 | 0 | if (!*dev_pnode) { |
1621 | | /* first deviation on this node, create a copy first */ |
1622 | 0 | LY_CHECK_GOTO(ret = lysp_dup_single(ctx->ctx, pnode, 1, dev_pnode), cleanup); |
1623 | 0 | } |
1624 | | |
1625 | | /* apply all the deviates by changing (the copy of) the parsed node */ |
1626 | 0 | LY_ARRAY_FOR(dev->devs, u) { |
1627 | 0 | dev_p = dev->devs[u]; |
1628 | 0 | LY_LIST_FOR(dev_p->deviates, d) { |
1629 | | /* generate correct path */ |
1630 | 0 | strcpy(orig_path, ctx->path); |
1631 | 0 | ctx->path_len = 1; |
1632 | 0 | ctx->cur_mod = dev->dev_pmods[u]->mod; |
1633 | 0 | ctx->pmod = (struct lysp_module *)dev->dev_pmods[u]; |
1634 | 0 | lysc_update_path(ctx, NULL, "{deviation}"); |
1635 | 0 | lysc_update_path(ctx, NULL, dev_p->nodeid); |
1636 | |
|
1637 | 0 | switch (d->mod) { |
1638 | 0 | case LYS_DEV_ADD: |
1639 | 0 | ret = lys_apply_deviate_add(ctx, (struct lysp_deviate_add *)d, *dev_pnode); |
1640 | 0 | break; |
1641 | 0 | case LYS_DEV_DELETE: |
1642 | 0 | ret = lys_apply_deviate_delete(ctx, (struct lysp_deviate_del *)d, *dev_pnode); |
1643 | 0 | break; |
1644 | 0 | case LYS_DEV_REPLACE: |
1645 | 0 | ret = lys_apply_deviate_replace(ctx, (struct lysp_deviate_rpl *)d, *dev_pnode); |
1646 | 0 | break; |
1647 | 0 | default: |
1648 | 0 | LOGINT(ctx->ctx); |
1649 | 0 | ret = LY_EINT; |
1650 | 0 | } |
1651 | | |
1652 | | /* restore previous path */ |
1653 | 0 | strcpy(ctx->path, orig_path); |
1654 | 0 | ctx->path_len = strlen(ctx->path); |
1655 | |
|
1656 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1657 | 0 | } |
1658 | 0 | } |
1659 | | |
1660 | 0 | dev_applied: |
1661 | | /* deviation was applied, remove it */ |
1662 | 0 | lysc_deviation_free(ctx->ctx, dev); |
1663 | 0 | ly_set_rm_index(&ctx->devs, i, NULL); |
1664 | | |
1665 | | /* all the deviations for one target node are in one structure, we are done */ |
1666 | 0 | break; |
1667 | 0 | } |
1668 | | |
1669 | 0 | cleanup: |
1670 | 0 | ctx->cur_mod = orig_mod; |
1671 | 0 | ctx->pmod = orig_pmod; |
1672 | 0 | if (ret) { |
1673 | 0 | lysp_dev_node_free(ctx->ctx, *dev_pnode); |
1674 | 0 | *dev_pnode = NULL; |
1675 | 0 | *not_supported = 0; |
1676 | 0 | } |
1677 | 0 | return ret; |
1678 | 0 | } |
1679 | | |
1680 | | /** |
1681 | | * @brief Compile the parsed augment connecting it into its target. |
1682 | | * |
1683 | | * It is expected that all the data referenced in path are present - augments are ordered so that augment B |
1684 | | * targeting data from augment A is being compiled after augment A. Also the modules referenced in the path |
1685 | | * are already implemented and compiled. |
1686 | | * |
1687 | | * @param[in] ctx Compile context. |
1688 | | * @param[in] aug_p Parsed augment to compile. |
1689 | | * @param[in] target Target node of the augment. |
1690 | | * @return LY_SUCCESS on success. |
1691 | | * @return LY_EVALID on failure. |
1692 | | */ |
1693 | | static LY_ERR |
1694 | | lys_compile_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, struct lysc_node *target) |
1695 | 0 | { |
1696 | 0 | LY_ERR ret = LY_SUCCESS; |
1697 | 0 | struct lysp_node *pnode; |
1698 | 0 | struct lysc_node *node; |
1699 | 0 | struct lysc_when *when_shared = NULL; |
1700 | 0 | struct lysc_node_action **actions; |
1701 | 0 | struct lysc_node_notif **notifs; |
1702 | 0 | ly_bool allow_mandatory = 0, enabled; |
1703 | 0 | struct ly_set child_set = {0}; |
1704 | 0 | uint32_t i, opt_prev = ctx->options; |
1705 | |
|
1706 | 0 | if (!(target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF))) { |
1707 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
1708 | 0 | "Augment's %s-schema-nodeid \"%s\" refers to a %s node which is not an allowed augment's target.", |
1709 | 0 | aug_p->nodeid[0] == '/' ? "absolute" : "descendant", aug_p->nodeid, lys_nodetype2str(target->nodetype)); |
1710 | 0 | ret = LY_EVALID; |
1711 | 0 | goto cleanup; |
1712 | 0 | } |
1713 | | |
1714 | | /* check for mandatory nodes |
1715 | | * - new cases augmenting some choice can have mandatory nodes |
1716 | | * - mandatory nodes are allowed only in case the augmentation is made conditional with a when statement |
1717 | | */ |
1718 | 0 | if (aug_p->when || (target->nodetype == LYS_CHOICE) || (ctx->cur_mod == target->module)) { |
1719 | 0 | allow_mandatory = 1; |
1720 | 0 | } |
1721 | |
|
1722 | 0 | LY_LIST_FOR(aug_p->child, pnode) { |
1723 | | /* check if the subnode can be connected to the found target (e.g. case cannot be inserted into container) */ |
1724 | 0 | if (((pnode->nodetype == LYS_CASE) && (target->nodetype != LYS_CHOICE)) || |
1725 | 0 | ((pnode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && !(target->nodetype & (LYS_CONTAINER | LYS_LIST))) || |
1726 | 0 | ((pnode->nodetype == LYS_USES) && (target->nodetype == LYS_CHOICE))) { |
1727 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
1728 | 0 | "Invalid augment of %s node which is not allowed to contain %s node \"%s\".", |
1729 | 0 | lys_nodetype2str(target->nodetype), lys_nodetype2str(pnode->nodetype), pnode->name); |
1730 | 0 | ret = LY_EVALID; |
1731 | 0 | goto cleanup; |
1732 | 0 | } |
1733 | | |
1734 | | /* compile the children */ |
1735 | 0 | if (target->nodetype == LYS_CHOICE) { |
1736 | 0 | LY_CHECK_GOTO(ret = lys_compile_node_choice_child(ctx, pnode, target, &child_set), cleanup); |
1737 | 0 | } else if (target->nodetype & (LYS_INPUT | LYS_OUTPUT)) { |
1738 | 0 | if (target->nodetype == LYS_INPUT) { |
1739 | 0 | ctx->options |= LYS_COMPILE_RPC_INPUT; |
1740 | 0 | } else { |
1741 | 0 | ctx->options |= LYS_COMPILE_RPC_OUTPUT; |
1742 | 0 | } |
1743 | 0 | LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup); |
1744 | 0 | } else { |
1745 | 0 | LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup); |
1746 | 0 | } |
1747 | | |
1748 | | /* eval if-features again for the rest of this node processing */ |
1749 | 0 | LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup); |
1750 | 0 | if (!enabled) { |
1751 | 0 | ctx->options |= LYS_COMPILE_DISABLED; |
1752 | 0 | } |
1753 | | |
1754 | | /* since the augment node is not present in the compiled tree, we need to pass some of its |
1755 | | * statements to all its children */ |
1756 | 0 | for (i = 0; i < child_set.count; ++i) { |
1757 | 0 | node = child_set.snodes[i]; |
1758 | 0 | if (!allow_mandatory && (node->flags & LYS_CONFIG_W) && (node->flags & LYS_MAND_TRUE)) { |
1759 | 0 | node->flags &= ~LYS_MAND_TRUE; |
1760 | 0 | lys_compile_mandatory_parents(target, 0); |
1761 | 0 | LOGVAL(ctx->ctx, LYVE_SEMANTICS, |
1762 | 0 | "Invalid augment adding mandatory node \"%s\" without making it conditional via when statement.", node->name); |
1763 | 0 | ret = LY_EVALID; |
1764 | 0 | goto cleanup; |
1765 | 0 | } |
1766 | | |
1767 | 0 | if (aug_p->when) { |
1768 | | /* pass augment's when to all the children */ |
1769 | 0 | ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_data_node(target), node, &when_shared); |
1770 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1771 | 0 | } |
1772 | 0 | } |
1773 | 0 | ly_set_erase(&child_set, NULL); |
1774 | | |
1775 | | /* restore options */ |
1776 | 0 | ctx->options = opt_prev; |
1777 | 0 | } |
1778 | | |
1779 | 0 | actions = lysc_node_actions_p(target); |
1780 | 0 | notifs = lysc_node_notifs_p(target); |
1781 | |
|
1782 | 0 | if (aug_p->actions) { |
1783 | 0 | if (!actions) { |
1784 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
1785 | 0 | "Invalid augment of %s node which is not allowed to contain RPC/action node \"%s\".", |
1786 | 0 | lys_nodetype2str(target->nodetype), aug_p->actions->name); |
1787 | 0 | ret = LY_EVALID; |
1788 | 0 | goto cleanup; |
1789 | 0 | } |
1790 | | |
1791 | | /* compile actions into the target */ |
1792 | 0 | LY_LIST_FOR((struct lysp_node *)aug_p->actions, pnode) { |
1793 | 0 | LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup); |
1794 | | |
1795 | | /* eval if-features again for the rest of this node processing */ |
1796 | 0 | LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup); |
1797 | 0 | if (!enabled) { |
1798 | 0 | ctx->options |= LYS_COMPILE_DISABLED; |
1799 | 0 | } |
1800 | | |
1801 | | /* since the augment node is not present in the compiled tree, we need to pass some of its |
1802 | | * statements to all its children */ |
1803 | 0 | for (i = 0; i < child_set.count; ++i) { |
1804 | 0 | node = child_set.snodes[i]; |
1805 | 0 | if (aug_p->when) { |
1806 | | /* pass augment's when to all the actions */ |
1807 | 0 | ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_data_node(target), node, &when_shared); |
1808 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1809 | 0 | } |
1810 | 0 | } |
1811 | 0 | ly_set_erase(&child_set, NULL); |
1812 | | |
1813 | | /* restore options */ |
1814 | 0 | ctx->options = opt_prev; |
1815 | 0 | } |
1816 | 0 | } |
1817 | 0 | if (aug_p->notifs) { |
1818 | 0 | if (!notifs) { |
1819 | 0 | LOGVAL(ctx->ctx, LYVE_REFERENCE, |
1820 | 0 | "Invalid augment of %s node which is not allowed to contain notification node \"%s\".", |
1821 | 0 | lys_nodetype2str(target->nodetype), aug_p->notifs->name); |
1822 | 0 | ret = LY_EVALID; |
1823 | 0 | goto cleanup; |
1824 | 0 | } |
1825 | | |
1826 | | /* compile notifications into the target */ |
1827 | 0 | LY_LIST_FOR((struct lysp_node *)aug_p->notifs, pnode) { |
1828 | 0 | LY_CHECK_GOTO(ret = lys_compile_node(ctx, pnode, target, 0, &child_set), cleanup); |
1829 | | |
1830 | | /* eval if-features again for the rest of this node processing */ |
1831 | 0 | LY_CHECK_GOTO(ret = lys_eval_iffeatures(ctx->ctx, pnode->iffeatures, &enabled), cleanup); |
1832 | 0 | if (!enabled) { |
1833 | 0 | ctx->options |= LYS_COMPILE_DISABLED; |
1834 | 0 | } |
1835 | | |
1836 | | /* since the augment node is not present in the compiled tree, we need to pass some of its |
1837 | | * statements to all its children */ |
1838 | 0 | for (i = 0; i < child_set.count; ++i) { |
1839 | 0 | node = child_set.snodes[i]; |
1840 | 0 | if (aug_p->when) { |
1841 | | /* pass augment's when to all the actions */ |
1842 | 0 | ret = lys_compile_when(ctx, aug_p->when, aug_p->flags, lysc_data_node(target), node, &when_shared); |
1843 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1844 | 0 | } |
1845 | 0 | } |
1846 | 0 | ly_set_erase(&child_set, NULL); |
1847 | | |
1848 | | /* restore options */ |
1849 | 0 | ctx->options = opt_prev; |
1850 | 0 | } |
1851 | 0 | } |
1852 | | |
1853 | 0 | cleanup: |
1854 | 0 | ly_set_erase(&child_set, NULL); |
1855 | 0 | ctx->options = opt_prev; |
1856 | 0 | return ret; |
1857 | 0 | } |
1858 | | |
1859 | | LY_ERR |
1860 | | lys_compile_node_augments(struct lysc_ctx *ctx, struct lysc_node *node) |
1861 | 0 | { |
1862 | 0 | LY_ERR ret = LY_SUCCESS; |
1863 | 0 | struct lys_module *orig_mod = ctx->cur_mod; |
1864 | 0 | struct lysp_module *orig_pmod = ctx->pmod; |
1865 | 0 | uint32_t i; |
1866 | 0 | char orig_path[LYSC_CTX_BUFSIZE]; |
1867 | 0 | struct lysc_augment *aug; |
1868 | | |
1869 | | /* uses augments */ |
1870 | 0 | for (i = 0; i < ctx->uses_augs.count; ) { |
1871 | 0 | aug = ctx->uses_augs.objs[i]; |
1872 | |
|
1873 | 0 | if (!lysp_schema_nodeid_match(aug->nodeid, orig_mod->parsed, aug->nodeid_ctx_node, node, NULL, NULL)) { |
1874 | | /* not our target node */ |
1875 | 0 | ++i; |
1876 | 0 | continue; |
1877 | 0 | } |
1878 | | |
1879 | | /* use the path and modules from the augment */ |
1880 | 0 | lysc_update_path(ctx, NULL, "{augment}"); |
1881 | 0 | lysc_update_path(ctx, NULL, aug->aug_p->nodeid); |
1882 | 0 | ctx->pmod = (struct lysp_module *)aug->aug_pmod; |
1883 | | |
1884 | | /* apply augment, restore the path */ |
1885 | 0 | ret = lys_compile_augment(ctx, aug->aug_p, node); |
1886 | 0 | lysc_update_path(ctx, NULL, NULL); |
1887 | 0 | lysc_update_path(ctx, NULL, NULL); |
1888 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1889 | | |
1890 | | /* augment was applied, remove it (index may have changed because other augments could have been applied) */ |
1891 | 0 | ly_set_rm(&ctx->uses_augs, aug, NULL); |
1892 | 0 | lysc_augment_free(ctx->ctx, aug); |
1893 | 0 | } |
1894 | | |
1895 | | /* top-level augments */ |
1896 | 0 | for (i = 0; i < ctx->augs.count; ) { |
1897 | 0 | aug = ctx->augs.objs[i]; |
1898 | |
|
1899 | 0 | if (!lysp_schema_nodeid_match(aug->nodeid, aug->aug_pmod, NULL, node, NULL, NULL)) { |
1900 | | /* not our target node */ |
1901 | 0 | ++i; |
1902 | 0 | continue; |
1903 | 0 | } |
1904 | | |
1905 | | /* use the path and modules from the augment */ |
1906 | 0 | strcpy(orig_path, ctx->path); |
1907 | 0 | ctx->path_len = 1; |
1908 | 0 | ctx->cur_mod = aug->aug_pmod->mod; |
1909 | 0 | ctx->pmod = (struct lysp_module *)aug->aug_pmod; |
1910 | 0 | lysc_update_path(ctx, NULL, "{augment}"); |
1911 | 0 | lysc_update_path(ctx, NULL, aug->aug_p->nodeid); |
1912 | | |
1913 | | /* apply augment, restore the path */ |
1914 | 0 | ret = lys_compile_augment(ctx, aug->aug_p, node); |
1915 | 0 | strcpy(ctx->path, orig_path); |
1916 | 0 | ctx->path_len = strlen(ctx->path); |
1917 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1918 | | |
1919 | | /* augment was applied, remove it */ |
1920 | 0 | ly_set_rm(&ctx->augs, aug, NULL); |
1921 | 0 | lysc_augment_free(ctx->ctx, aug); |
1922 | 0 | } |
1923 | | |
1924 | 0 | cleanup: |
1925 | 0 | ctx->cur_mod = orig_mod; |
1926 | 0 | ctx->pmod = orig_pmod; |
1927 | 0 | return ret; |
1928 | 0 | } |
1929 | | |
1930 | | /** |
1931 | | * @brief Prepare a top-level augment to be applied during data nodes compilation. |
1932 | | * |
1933 | | * @param[in] ctx Compile context. |
1934 | | * @param[in] aug_p Parsed augment to be applied. |
1935 | | * @param[in] pmod Both current and prefix module for @p aug_p. |
1936 | | * @return LY_ERR value. |
1937 | | */ |
1938 | | static LY_ERR |
1939 | | lys_precompile_own_augment(struct lysc_ctx *ctx, struct lysp_node_augment *aug_p, const struct lysp_module *pmod) |
1940 | 0 | { |
1941 | 0 | LY_ERR ret = LY_SUCCESS; |
1942 | 0 | struct lyxp_expr *exp = NULL; |
1943 | 0 | struct lysc_augment *aug; |
1944 | 0 | const struct lys_module *mod; |
1945 | | |
1946 | | /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */ |
1947 | 0 | ret = lyxp_expr_parse(ctx->ctx, aug_p->nodeid, strlen(aug_p->nodeid), 0, &exp); |
1948 | 0 | LY_CHECK_GOTO(ret, cleanup); |
1949 | |
|
1950 | 0 | mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL); |
1951 | 0 | LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup); |
1952 | 0 | if (mod != ctx->cur_mod) { |
1953 | | /* augment for another module, ignore */ |
1954 | 0 | goto cleanup; |
1955 | 0 | } |
1956 | | |
1957 | | /* allocate new compiled augment and store it in the set */ |
1958 | 0 | aug = calloc(1, sizeof *aug); |
1959 | 0 | LY_CHECK_ERR_GOTO(!aug, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup); |
1960 | 0 | LY_CHECK_GOTO(ret = ly_set_add(&ctx->augs, aug, 1, NULL), cleanup); |
1961 | |
|
1962 | 0 | aug->nodeid = exp; |
1963 | 0 | exp = NULL; |
1964 | 0 | aug->aug_pmod = pmod; |
1965 | 0 | aug->aug_p = aug_p; |
1966 | |
|
1967 | 0 | cleanup: |
1968 | 0 | lyxp_expr_free(ctx->ctx, exp); |
1969 | 0 | return ret; |
1970 | 0 | } |
1971 | | |
1972 | | LY_ERR |
1973 | | lys_precompile_own_augments(struct lysc_ctx *ctx) |
1974 | 0 | { |
1975 | 0 | LY_ARRAY_COUNT_TYPE u, v; |
1976 | |
|
1977 | 0 | LY_ARRAY_FOR(ctx->cur_mod->augmented_by, u) { |
1978 | 0 | const struct lys_module *aug_mod = ctx->cur_mod->augmented_by[u]; |
1979 | 0 | struct lysp_node_augment *aug; |
1980 | | |
1981 | | /* collect all module augments */ |
1982 | 0 | LY_LIST_FOR(aug_mod->parsed->augments, aug) { |
1983 | 0 | LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, aug_mod->parsed)); |
1984 | 0 | } |
1985 | | |
1986 | | /* collect all submodules augments */ |
1987 | 0 | LY_ARRAY_FOR(aug_mod->parsed->includes, v) { |
1988 | 0 | LY_LIST_FOR(aug_mod->parsed->includes[v].submodule->augments, aug) { |
1989 | 0 | LY_CHECK_RET(lys_precompile_own_augment(ctx, aug, (struct lysp_module *)aug_mod->parsed->includes[v].submodule)); |
1990 | 0 | } |
1991 | 0 | } |
1992 | 0 | } |
1993 | | |
1994 | 0 | return LY_SUCCESS; |
1995 | 0 | } |
1996 | | |
1997 | | /** |
1998 | | * @brief Prepare a deviation to be applied during data nodes compilation. |
1999 | | * |
2000 | | * @param[in] ctx Compile context. |
2001 | | * @param[in] dev_p Parsed deviation to be applied. |
2002 | | * @param[in] pmod Both current and prefix module for @p dev_p. |
2003 | | * @return LY_ERR value. |
2004 | | */ |
2005 | | static LY_ERR |
2006 | | lys_precompile_own_deviation(struct lysc_ctx *ctx, struct lysp_deviation *dev_p, const struct lysp_module *pmod) |
2007 | 0 | { |
2008 | 0 | LY_ERR ret = LY_SUCCESS; |
2009 | 0 | struct lysc_deviation *dev = NULL; |
2010 | 0 | struct lyxp_expr *exp = NULL; |
2011 | 0 | struct lysp_deviation **new_dev; |
2012 | 0 | const struct lys_module *mod; |
2013 | 0 | const struct lysp_module **new_dev_pmod; |
2014 | 0 | uint32_t i; |
2015 | | |
2016 | | /* parse its target, it was already parsed and fully checked (except for the existence of the nodes) */ |
2017 | 0 | ret = lyxp_expr_parse(ctx->ctx, dev_p->nodeid, strlen(dev_p->nodeid), 0, &exp); |
2018 | 0 | LY_CHECK_GOTO(ret, cleanup); |
2019 | |
|
2020 | 0 | mod = lys_schema_node_get_module(ctx->ctx, exp->expr + exp->tok_pos[1], exp->tok_len[1], pmod, NULL, NULL); |
2021 | 0 | LY_CHECK_ERR_GOTO(!mod, LOGINT(ctx->ctx); ret = LY_EINT, cleanup); |
2022 | 0 | if (mod != ctx->cur_mod) { |
2023 | | /* deviation for another module, ignore */ |
2024 | 0 | goto cleanup; |
2025 | 0 | } |
2026 | | |
2027 | | /* try to find the node in already compiled deviations */ |
2028 | 0 | for (i = 0; i < ctx->devs.count; ++i) { |
2029 | 0 | if (lys_abs_schema_nodeid_match(ctx->ctx, exp, pmod, ((struct lysc_deviation *)ctx->devs.objs[i])->nodeid, |
2030 | 0 | ((struct lysc_deviation *)ctx->devs.objs[i])->dev_pmods[0])) { |
2031 | 0 | dev = ctx->devs.objs[i]; |
2032 | 0 | break; |
2033 | 0 | } |
2034 | 0 | } |
2035 | |
|
2036 | 0 | if (!dev) { |
2037 | | /* allocate new compiled deviation */ |
2038 | 0 | dev = calloc(1, sizeof *dev); |
2039 | 0 | LY_CHECK_ERR_GOTO(!dev, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup); |
2040 | 0 | LY_CHECK_GOTO(ret = ly_set_add(&ctx->devs, dev, 1, NULL), cleanup); |
2041 | |
|
2042 | 0 | dev->nodeid = exp; |
2043 | 0 | exp = NULL; |
2044 | 0 | } |
2045 | | |
2046 | | /* add new parsed deviation structure */ |
2047 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, dev->devs, new_dev, ret, cleanup); |
2048 | 0 | *new_dev = dev_p; |
2049 | 0 | LY_ARRAY_NEW_GOTO(ctx->ctx, dev->dev_pmods, new_dev_pmod, ret, cleanup); |
2050 | 0 | *new_dev_pmod = pmod; |
2051 | |
|
2052 | 0 | cleanup: |
2053 | 0 | lyxp_expr_free(ctx->ctx, exp); |
2054 | 0 | return ret; |
2055 | 0 | } |
2056 | | |
2057 | | LY_ERR |
2058 | | lys_precompile_own_deviations(struct lysc_ctx *ctx) |
2059 | 0 | { |
2060 | 0 | LY_ARRAY_COUNT_TYPE u, v, w; |
2061 | 0 | const struct lys_module *dev_mod; |
2062 | 0 | struct lysc_deviation *dev; |
2063 | 0 | struct lysp_deviate *d; |
2064 | 0 | int not_supported; |
2065 | 0 | uint32_t i; |
2066 | |
|
2067 | 0 | LY_ARRAY_FOR(ctx->cur_mod->deviated_by, u) { |
2068 | 0 | dev_mod = ctx->cur_mod->deviated_by[u]; |
2069 | | |
2070 | | /* compile all module deviations */ |
2071 | 0 | LY_ARRAY_FOR(dev_mod->parsed->deviations, v) { |
2072 | 0 | LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->deviations[v], dev_mod->parsed)); |
2073 | 0 | } |
2074 | | |
2075 | | /* compile all submodules deviations */ |
2076 | 0 | LY_ARRAY_FOR(dev_mod->parsed->includes, v) { |
2077 | 0 | LY_ARRAY_FOR(dev_mod->parsed->includes[v].submodule->deviations, w) { |
2078 | 0 | LY_CHECK_RET(lys_precompile_own_deviation(ctx, &dev_mod->parsed->includes[v].submodule->deviations[w], |
2079 | 0 | (struct lysp_module *)dev_mod->parsed->includes[v].submodule)); |
2080 | 0 | } |
2081 | 0 | } |
2082 | 0 | } |
2083 | | |
2084 | | /* set not-supported flags for all the deviations */ |
2085 | 0 | for (i = 0; i < ctx->devs.count; ++i) { |
2086 | 0 | dev = ctx->devs.objs[i]; |
2087 | 0 | not_supported = 0; |
2088 | |
|
2089 | 0 | LY_ARRAY_FOR(dev->devs, u) { |
2090 | 0 | LY_LIST_FOR(dev->devs[u]->deviates, d) { |
2091 | 0 | if (d->mod == LYS_DEV_NOT_SUPPORTED) { |
2092 | 0 | not_supported = 1; |
2093 | 0 | break; |
2094 | 0 | } |
2095 | 0 | } |
2096 | 0 | if (not_supported) { |
2097 | 0 | break; |
2098 | 0 | } |
2099 | 0 | } |
2100 | 0 | if (not_supported && (LY_ARRAY_COUNT(dev->devs) > 1)) { |
2101 | 0 | LOGVAL(ctx->ctx, LYVE_SEMANTICS, |
2102 | 0 | "Multiple deviations of \"%s\" with one of them being \"not-supported\".", dev->nodeid->expr); |
2103 | 0 | return LY_EVALID; |
2104 | 0 | } |
2105 | | |
2106 | 0 | dev->not_supported = not_supported; |
2107 | 0 | } |
2108 | | |
2109 | 0 | return LY_SUCCESS; |
2110 | 0 | } |
2111 | | |
2112 | | /** |
2113 | | * @brief Add a module reference into an array, checks for duplicities. |
2114 | | * |
2115 | | * @param[in] ctx Compile context. |
2116 | | * @param[in] mod Module reference to add. |
2117 | | * @param[in,out] mod_array Module sized array to add to. |
2118 | | * @return LY_ERR value. |
2119 | | */ |
2120 | | static LY_ERR |
2121 | | lys_array_add_mod_ref(struct lysc_ctx *ctx, struct lys_module *mod, struct lys_module ***mod_array) |
2122 | 0 | { |
2123 | 0 | LY_ARRAY_COUNT_TYPE u; |
2124 | 0 | struct lys_module **new_mod; |
2125 | |
|
2126 | 0 | LY_ARRAY_FOR(*mod_array, u) { |
2127 | 0 | if ((*mod_array)[u] == mod) { |
2128 | | /* already there */ |
2129 | 0 | return LY_EEXIST; |
2130 | 0 | } |
2131 | 0 | } |
2132 | | |
2133 | | /* add the new module ref */ |
2134 | 0 | LY_ARRAY_NEW_RET(ctx->ctx, *mod_array, new_mod, LY_EMEM); |
2135 | 0 | *new_mod = mod; |
2136 | |
|
2137 | 0 | return LY_SUCCESS; |
2138 | 0 | } |
2139 | | |
2140 | | /** |
2141 | | * @brief Check whether all modules in a set are implemented. |
2142 | | * |
2143 | | * @param[in] mod_set Module set to check. |
2144 | | * @return Whether all modules are implemented or not. |
2145 | | */ |
2146 | | static ly_bool |
2147 | | lys_precompile_mod_set_all_implemented(const struct ly_set *mod_set) |
2148 | 0 | { |
2149 | 0 | uint32_t i; |
2150 | 0 | const struct lys_module *mod; |
2151 | |
|
2152 | 0 | for (i = 0; i < mod_set->count; ++i) { |
2153 | 0 | mod = mod_set->objs[i]; |
2154 | 0 | if (!mod->implemented) { |
2155 | 0 | return 0; |
2156 | 0 | } |
2157 | 0 | } |
2158 | | |
2159 | 0 | return 1; |
2160 | 0 | } |
2161 | | |
2162 | | LY_ERR |
2163 | | lys_precompile_augments_deviations(struct lysc_ctx *ctx) |
2164 | 0 | { |
2165 | 0 | LY_ERR ret = LY_SUCCESS; |
2166 | 0 | LY_ARRAY_COUNT_TYPE u, v; |
2167 | 0 | const struct lysp_module *mod_p; |
2168 | 0 | struct lys_module *mod; |
2169 | 0 | struct lysp_submodule *submod; |
2170 | 0 | struct lysp_node_augment *aug; |
2171 | 0 | uint32_t idx; |
2172 | 0 | struct ly_set mod_set = {0}, set = {0}; |
2173 | |
|
2174 | 0 | mod_p = ctx->cur_mod->parsed; |
2175 | |
|
2176 | 0 | LY_LIST_FOR(mod_p->augments, aug) { |
2177 | | /* get target module */ |
2178 | 0 | lysc_update_path(ctx, NULL, "{augment}"); |
2179 | 0 | lysc_update_path(ctx, NULL, aug->nodeid); |
2180 | 0 | ret = lys_nodeid_mod_check(ctx, aug->nodeid, 1, &set, NULL, &mod); |
2181 | 0 | lysc_update_path(ctx, NULL, NULL); |
2182 | 0 | lysc_update_path(ctx, NULL, NULL); |
2183 | 0 | LY_CHECK_GOTO(ret, cleanup); |
2184 | | |
2185 | | /* add this module into the target module augmented_by, if not there and implemented */ |
2186 | 0 | if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by) != LY_EEXIST) || |
2187 | 0 | !lys_precompile_mod_set_all_implemented(&set)) { |
2188 | 0 | LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup); |
2189 | 0 | } |
2190 | 0 | ly_set_erase(&set, NULL); |
2191 | 0 | } |
2192 | | |
2193 | 0 | LY_ARRAY_FOR(mod_p->deviations, u) { |
2194 | | /* get target module */ |
2195 | 0 | lysc_update_path(ctx, NULL, "{deviation}"); |
2196 | 0 | lysc_update_path(ctx, NULL, mod_p->deviations[u].nodeid); |
2197 | 0 | ret = lys_nodeid_mod_check(ctx, mod_p->deviations[u].nodeid, 1, &set, NULL, &mod); |
2198 | 0 | lysc_update_path(ctx, NULL, NULL); |
2199 | 0 | lysc_update_path(ctx, NULL, NULL); |
2200 | 0 | LY_CHECK_GOTO(ret, cleanup); |
2201 | | |
2202 | | /* add this module into the target module deviated_by, if not there and implemented */ |
2203 | 0 | if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by) != LY_EEXIST) || |
2204 | 0 | !lys_precompile_mod_set_all_implemented(&set)) { |
2205 | 0 | LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup); |
2206 | 0 | } |
2207 | 0 | ly_set_erase(&set, NULL); |
2208 | 0 | } |
2209 | | |
2210 | | /* the same for augments and deviations in submodules */ |
2211 | 0 | LY_ARRAY_FOR(mod_p->includes, v) { |
2212 | 0 | submod = mod_p->includes[v].submodule; |
2213 | 0 | LY_LIST_FOR(submod->augments, aug) { |
2214 | 0 | lysc_update_path(ctx, NULL, "{augment}"); |
2215 | 0 | lysc_update_path(ctx, NULL, aug->nodeid); |
2216 | 0 | ret = lys_nodeid_mod_check(ctx, aug->nodeid, 1, &set, NULL, &mod); |
2217 | 0 | lysc_update_path(ctx, NULL, NULL); |
2218 | 0 | lysc_update_path(ctx, NULL, NULL); |
2219 | 0 | LY_CHECK_GOTO(ret, cleanup); |
2220 | |
|
2221 | 0 | if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->augmented_by) != LY_EEXIST) || |
2222 | 0 | !lys_precompile_mod_set_all_implemented(&set)) { |
2223 | 0 | LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup); |
2224 | 0 | } |
2225 | 0 | ly_set_erase(&set, NULL); |
2226 | 0 | } |
2227 | | |
2228 | 0 | LY_ARRAY_FOR(submod->deviations, u) { |
2229 | 0 | lysc_update_path(ctx, NULL, "{deviation}"); |
2230 | 0 | lysc_update_path(ctx, NULL, submod->deviations[u].nodeid); |
2231 | 0 | ret = lys_nodeid_mod_check(ctx, submod->deviations[u].nodeid, 1, &set, NULL, &mod); |
2232 | 0 | lysc_update_path(ctx, NULL, NULL); |
2233 | 0 | lysc_update_path(ctx, NULL, NULL); |
2234 | 0 | LY_CHECK_GOTO(ret, cleanup); |
2235 | |
|
2236 | 0 | if ((lys_array_add_mod_ref(ctx, ctx->cur_mod, &mod->deviated_by) != LY_EEXIST) || |
2237 | 0 | !lys_precompile_mod_set_all_implemented(&set)) { |
2238 | 0 | LY_CHECK_GOTO(ret = ly_set_merge(&mod_set, &set, 0, NULL), cleanup); |
2239 | 0 | } |
2240 | 0 | ly_set_erase(&set, NULL); |
2241 | 0 | } |
2242 | 0 | } |
2243 | | |
2244 | 0 | if (mod_set.count) { |
2245 | | /* descending order to make sure the modules are implemented in the right order */ |
2246 | 0 | idx = mod_set.count; |
2247 | 0 | do { |
2248 | 0 | --idx; |
2249 | 0 | mod = mod_set.objs[idx]; |
2250 | |
|
2251 | 0 | if (mod == ctx->cur_mod) { |
2252 | | /* will be applied normally later */ |
2253 | 0 | continue; |
2254 | 0 | } |
2255 | | |
2256 | 0 | if (!mod->implemented) { |
2257 | | /* implement (compile) the target module with our augments/deviations */ |
2258 | 0 | LY_CHECK_GOTO(ret = lys_set_implemented_r(mod, NULL, ctx->unres), cleanup); |
2259 | 0 | } else if (!ctx->unres->full_compilation) { |
2260 | | /* target module was already compiled, we need to recompile it */ |
2261 | 0 | ctx->unres->recompile = 1; |
2262 | 0 | } |
2263 | | /* else the module is implemented and was compiled in this compilation run or will yet be; |
2264 | | * we actually do not need the module compiled now because its compiled nodes will not be accessed, |
2265 | | * augments/deviations are applied during the target module compilation and the rest is in global unres */ |
2266 | | |
2267 | 0 | if (ctx->unres->recompile) { |
2268 | | /* we need some module recompiled and cannot continue */ |
2269 | 0 | goto cleanup; |
2270 | 0 | } |
2271 | 0 | } while (idx); |
2272 | 0 | } |
2273 | | |
2274 | 0 | cleanup: |
2275 | 0 | ly_set_erase(&set, NULL); |
2276 | 0 | ly_set_erase(&mod_set, NULL); |
2277 | 0 | return ret; |
2278 | 0 | } |
2279 | | |
2280 | | void |
2281 | | lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod) |
2282 | 0 | { |
2283 | 0 | uint32_t i; |
2284 | 0 | LY_ARRAY_COUNT_TYPE u, count; |
2285 | 0 | struct lys_module *m; |
2286 | |
|
2287 | 0 | for (i = 0; i < ctx->list.count; ++i) { |
2288 | 0 | m = ctx->list.objs[i]; |
2289 | |
|
2290 | 0 | if (m->augmented_by) { |
2291 | 0 | count = LY_ARRAY_COUNT(m->augmented_by); |
2292 | 0 | for (u = 0; u < count; ++u) { |
2293 | 0 | if (m->augmented_by[u] == mod) { |
2294 | | /* keep the order */ |
2295 | 0 | if (u < count - 1) { |
2296 | 0 | memmove(m->augmented_by + u, m->augmented_by + u + 1, (count - u) * sizeof *m->augmented_by); |
2297 | 0 | } |
2298 | 0 | LY_ARRAY_DECREMENT(m->augmented_by); |
2299 | 0 | break; |
2300 | 0 | } |
2301 | 0 | } |
2302 | 0 | if (!LY_ARRAY_COUNT(m->augmented_by)) { |
2303 | 0 | LY_ARRAY_FREE(m->augmented_by); |
2304 | 0 | m->augmented_by = NULL; |
2305 | 0 | } |
2306 | 0 | } |
2307 | |
|
2308 | 0 | if (m->deviated_by) { |
2309 | 0 | count = LY_ARRAY_COUNT(m->deviated_by); |
2310 | 0 | for (u = 0; u < count; ++u) { |
2311 | 0 | if (m->deviated_by[u] == mod) { |
2312 | | /* keep the order */ |
2313 | 0 | if (u < count - 1) { |
2314 | 0 | memmove(m->deviated_by + u, m->deviated_by + u + 1, (count - u) * sizeof *m->deviated_by); |
2315 | 0 | } |
2316 | 0 | LY_ARRAY_DECREMENT(m->deviated_by); |
2317 | 0 | break; |
2318 | 0 | } |
2319 | 0 | } |
2320 | 0 | if (!LY_ARRAY_COUNT(m->deviated_by)) { |
2321 | 0 | LY_ARRAY_FREE(m->deviated_by); |
2322 | | m->deviated_by = NULL; |
2323 | 0 | } |
2324 | 0 | } |
2325 | 0 | } |
2326 | 0 | } |