blob: e82ff023b4df553d19f6e7af856d2f95089fe005 [file] [log] [blame]
Radek Krejci3f5e3db2018-10-11 15:57:47 +02001/**
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 */
Radek Krejcib7db73a2018-10-24 14:18:40 +020014
15#include "common.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020016
Radek Krejci151a5b72018-10-19 14:21:44 +020017#include <ctype.h>
Radek Krejcid33273d2018-10-25 14:55:52 +020018#include <dirent.h>
Radek Krejci86d106e2018-10-18 09:53:19 +020019#include <errno.h>
20#include <fcntl.h>
21#include <linux/limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <unistd.h>
Radek Krejci3f5e3db2018-10-11 15:57:47 +020027
28#include "libyang.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020029#include "context.h"
Radek Krejci70853c52018-10-15 14:46:16 +020030#include "tree_schema_internal.h"
Radek Krejci3f5e3db2018-10-11 15:57:47 +020031
Radek Krejci2c4e7172018-10-19 15:56:26 +020032#define FREE_ARRAY(CTX, ARRAY, FUNC) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FUNC(CTX, &ARRAY[c__], dict);}LY_ARRAY_FREE(ARRAY);}
Radek Krejcidd4e8d42018-10-16 14:55:43 +020033#define FREE_MEMBER(CTX, MEMBER, FUNC) if (MEMBER) {FUNC(CTX, MEMBER, dict);free(MEMBER);}
Radek Krejci151a5b72018-10-19 14:21:44 +020034#define FREE_STRING(CTX, STRING, DICT) if (DICT && STRING) {lydict_remove(CTX, STRING);}
Radek Krejci2c4e7172018-10-19 15:56:26 +020035#define FREE_STRINGS(CTX, ARRAY, DICT) {uint64_t c__; LY_ARRAY_FOR(ARRAY, c__){FREE_STRING(CTX, ARRAY[c__], DICT);}LY_ARRAY_FREE(ARRAY);}
Radek Krejci6f7feb62018-10-12 15:23:02 +020036
Radek Krejci6d6e4e42018-10-29 13:28:19 +010037#define COMPILE_ARRAY_GOTO(CTX, ARRAY_P, ARRAY_C, OPTIONS, ITER, FUNC, RET, GOTO) \
38 if (ARRAY_P) { \
Radek Krejcibd8d9ba2018-11-02 16:06:26 +010039 LY_ARRAY_CREATE_GOTO((CTX)->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
Radek Krejci6d6e4e42018-10-29 13:28:19 +010040 for (ITER = 0; ITER < LY_ARRAY_SIZE(ARRAY_P); ++ITER) { \
Radek Krejci87616bb2018-10-31 13:30:52 +010041 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejcice8c1592018-10-29 15:35:51 +010042 RET = FUNC(CTX, &(ARRAY_P)[ITER], OPTIONS, &(ARRAY_C)[ITER]); \
Radek Krejci6d6e4e42018-10-29 13:28:19 +010043 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
Radek Krejci6d6e4e42018-10-29 13:28:19 +010044 } \
45 }
46
Radek Krejcidd4e8d42018-10-16 14:55:43 +020047static void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict);
48static void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020049
Radek Krejcibd8d9ba2018-11-02 16:06:26 +010050#define LYSC_CTX_BUFSIZE 4078
Radek Krejci86d106e2018-10-18 09:53:19 +020051struct lysc_ctx {
Radek Krejcibd8d9ba2018-11-02 16:06:26 +010052 struct ly_ctx *ctx;
53 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +020054 uint16_t path_len;
55 char path[LYSC_CTX_BUFSIZE];
56};
57
Radek Krejci6f7feb62018-10-12 15:23:02 +020058static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020059lysp_stmt_free(struct ly_ctx *ctx, struct lysp_stmt *stmt, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020060{
61 struct lysp_stmt *child, *next;
62
Radek Krejci151a5b72018-10-19 14:21:44 +020063 FREE_STRING(ctx, stmt->stmt, dict);
64 FREE_STRING(ctx, stmt->arg, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020065
66 LY_LIST_FOR_SAFE(stmt->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020067 lysp_stmt_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020068 }
69
70 free(stmt);
71}
72
73static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020074lysp_ext_instance_free(struct ly_ctx *ctx, struct lysp_ext_instance *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020075{
76 struct lysp_stmt *stmt, *next;
77
Radek Krejci151a5b72018-10-19 14:21:44 +020078 FREE_STRING(ctx, ext->name, dict);
79 FREE_STRING(ctx, ext->argument, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020080
81 LY_LIST_FOR_SAFE(ext->child, next, stmt) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020082 lysp_stmt_free(ctx, stmt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020083 }
84}
85
86static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020087lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020088{
Radek Krejci086c7132018-10-26 15:29:04 +020089 /* imported module is freed directly from the context's list */
Radek Krejci151a5b72018-10-19 14:21:44 +020090 FREE_STRING(ctx, import->name, dict);
91 FREE_STRING(ctx, import->prefix, dict);
92 FREE_STRING(ctx, import->dsc, dict);
93 FREE_STRING(ctx, import->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +020094 FREE_ARRAY(ctx, import->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +020095}
96
97static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020098lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020099{
Radek Krejcibbe09a92018-11-08 09:36:54 +0100100 if (include->submodule) {
Radek Krejcid33273d2018-10-25 14:55:52 +0200101 lysp_module_free(include->submodule);
102 }
Radek Krejcif8f882a2018-10-31 14:51:15 +0100103 dict = 1; /* includes not present in compiled tree, so the data are not reused there in anyway */
Radek Krejci086c7132018-10-26 15:29:04 +0200104 FREE_STRING(ctx, include->name, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200105 FREE_STRING(ctx, include->dsc, dict);
106 FREE_STRING(ctx, include->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200107 FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200108}
109
110static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200111lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200112{
Radek Krejci151a5b72018-10-19 14:21:44 +0200113 FREE_STRING(ctx, rev->dsc, dict);
114 FREE_STRING(ctx, rev->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200115 FREE_ARRAY(ctx, rev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200116}
117
118static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200119lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200120{
Radek Krejci151a5b72018-10-19 14:21:44 +0200121 FREE_STRING(ctx, ext->name, dict);
122 FREE_STRING(ctx, ext->argument, dict);
123 FREE_STRING(ctx, ext->dsc, dict);
124 FREE_STRING(ctx, ext->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200125 FREE_ARRAY(ctx, ext->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200126}
127
128static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200129lysp_feature_free(struct ly_ctx *ctx, struct lysp_feature *feat, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200130{
Radek Krejci151a5b72018-10-19 14:21:44 +0200131 FREE_STRING(ctx, feat->name, dict);
132 FREE_STRINGS(ctx, feat->iffeatures, 1);
133 FREE_STRING(ctx, feat->dsc, dict);
134 FREE_STRING(ctx, feat->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200135 FREE_ARRAY(ctx, feat->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200136}
137
138static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200139lysp_ident_free(struct ly_ctx *ctx, struct lysp_ident *ident, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200140{
Radek Krejci151a5b72018-10-19 14:21:44 +0200141 FREE_STRING(ctx, ident->name, dict);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200142 FREE_STRINGS(ctx, ident->iffeatures, 1);
Radek Krejci151a5b72018-10-19 14:21:44 +0200143 FREE_STRINGS(ctx, ident->bases, dict);
144 FREE_STRING(ctx, ident->dsc, dict);
145 FREE_STRING(ctx, ident->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200146 FREE_ARRAY(ctx, ident->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200147}
148
149static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200150lysp_restr_free(struct ly_ctx *ctx, struct lysp_restr *restr, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200151{
Radek Krejci151a5b72018-10-19 14:21:44 +0200152 FREE_STRING(ctx, restr->arg, dict);
153 FREE_STRING(ctx, restr->emsg, dict);
154 FREE_STRING(ctx, restr->eapptag, dict);
155 FREE_STRING(ctx, restr->dsc, dict);
156 FREE_STRING(ctx, restr->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200157 FREE_ARRAY(ctx, restr->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200158}
159
160static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200161lysp_type_enum_free(struct ly_ctx *ctx, struct lysp_type_enum *item, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200162{
Radek Krejci151a5b72018-10-19 14:21:44 +0200163 FREE_STRING(ctx, item->name, dict);
164 FREE_STRING(ctx, item->dsc, dict);
165 FREE_STRING(ctx, item->ref, dict);
166 FREE_STRINGS(ctx, item->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200167 FREE_ARRAY(ctx, item->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200168}
169
170static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200171lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200172{
Radek Krejci151a5b72018-10-19 14:21:44 +0200173 FREE_STRING(ctx, type->name, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200174 FREE_MEMBER(ctx, type->range, lysp_restr_free);
175 FREE_MEMBER(ctx, type->length, lysp_restr_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200176 FREE_ARRAY(ctx, type->patterns, lysp_restr_free);
177 FREE_ARRAY(ctx, type->enums, lysp_type_enum_free);
178 FREE_ARRAY(ctx, type->bits, lysp_type_enum_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200179 FREE_STRING(ctx, type->path, dict);
180 FREE_STRINGS(ctx, type->bases, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200181 FREE_ARRAY(ctx, type->types, lysp_type_free);
182 FREE_ARRAY(ctx, type->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200183}
184
185static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200186lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200187{
Radek Krejci151a5b72018-10-19 14:21:44 +0200188 FREE_STRING(ctx, tpdf->name, dict);
189 FREE_STRING(ctx, tpdf->units, dict);
190 FREE_STRING(ctx, tpdf->dflt, dict);
191 FREE_STRING(ctx, tpdf->dsc, dict);
192 FREE_STRING(ctx, tpdf->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200193 FREE_ARRAY(ctx, tpdf->exts, lysp_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200194 lysp_type_free(ctx, &tpdf->type, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200195}
196
197static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200198lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200199{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200200 struct lysp_node *node, *next;
201
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200202 FREE_ARRAY(ctx, inout->musts, lysp_restr_free);
203 FREE_ARRAY(ctx, inout->typedefs, lysp_tpdf_free);
204 FREE_ARRAY(ctx, inout->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200205 LY_LIST_FOR_SAFE(inout->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200206 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200207 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200208 FREE_ARRAY(ctx, inout->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200209
210}
211
212static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200213lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200214{
Radek Krejci151a5b72018-10-19 14:21:44 +0200215 FREE_STRING(ctx, action->name, dict);
216 FREE_STRING(ctx, action->dsc, dict);
217 FREE_STRING(ctx, action->ref, dict);
218 FREE_STRINGS(ctx, action->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200219 FREE_ARRAY(ctx, action->typedefs, lysp_tpdf_free);
220 FREE_ARRAY(ctx, action->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200221 FREE_MEMBER(ctx, action->input, lysp_action_inout_free);
222 FREE_MEMBER(ctx, action->output, lysp_action_inout_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200223 FREE_ARRAY(ctx, action->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200224}
225
226static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200227lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200228{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200229 struct lysp_node *node, *next;
230
Radek Krejci151a5b72018-10-19 14:21:44 +0200231 FREE_STRING(ctx, notif->name, dict);
232 FREE_STRING(ctx, notif->dsc, dict);
233 FREE_STRING(ctx, notif->ref, dict);
234 FREE_STRINGS(ctx, notif->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200235 FREE_ARRAY(ctx, notif->musts, lysp_restr_free);
236 FREE_ARRAY(ctx, notif->typedefs, lysp_tpdf_free);
237 FREE_ARRAY(ctx, notif->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200238 LY_LIST_FOR_SAFE(notif->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200239 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200240 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200241 FREE_ARRAY(ctx, notif->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200242}
243
244static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200245lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200246{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200247 struct lysp_node *node, *next;
248
Radek Krejci151a5b72018-10-19 14:21:44 +0200249 FREE_STRING(ctx, grp->name, dict);
250 FREE_STRING(ctx, grp->dsc, dict);
251 FREE_STRING(ctx, grp->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200252 FREE_ARRAY(ctx, grp->typedefs, lysp_tpdf_free);
253 FREE_ARRAY(ctx, grp->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200254 LY_LIST_FOR_SAFE(grp->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200255 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200256 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200257 FREE_ARRAY(ctx, grp->actions, lysp_action_free);
258 FREE_ARRAY(ctx, grp->notifs, lysp_notif_free);
259 FREE_ARRAY(ctx, grp->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200260}
261
262static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200263lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200264{
Radek Krejci151a5b72018-10-19 14:21:44 +0200265 FREE_STRING(ctx, when->cond, dict);
266 FREE_STRING(ctx, when->dsc, dict);
267 FREE_STRING(ctx, when->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200268 FREE_ARRAY(ctx, when->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200269}
270
271static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200272lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200273{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200274 struct lysp_node *node, *next;
275
Radek Krejci151a5b72018-10-19 14:21:44 +0200276 FREE_STRING(ctx, augment->nodeid, dict);
277 FREE_STRING(ctx, augment->dsc, dict);
278 FREE_STRING(ctx, augment->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200279 FREE_MEMBER(ctx, augment->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200280 FREE_STRINGS(ctx, augment->iffeatures, 1);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200281 LY_LIST_FOR_SAFE(augment->child, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200282 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200283 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200284 FREE_ARRAY(ctx, augment->actions, lysp_action_free);
285 FREE_ARRAY(ctx, augment->notifs, lysp_notif_free);
286 FREE_ARRAY(ctx, augment->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200287}
288
289static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200290lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200291{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200292 struct lysp_deviate_add *add = (struct lysp_deviate_add*)d;
293 struct lysp_deviate_rpl *rpl = (struct lysp_deviate_rpl*)d;
294
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200295 FREE_ARRAY(ctx, d->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200296 switch(d->mod) {
297 case LYS_DEV_NOT_SUPPORTED:
298 /* nothing to do */
299 break;
300 case LYS_DEV_ADD:
301 case LYS_DEV_DELETE: /* compatible for dynamically allocated data */
Radek Krejci151a5b72018-10-19 14:21:44 +0200302 FREE_STRING(ctx, add->units, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200303 FREE_ARRAY(ctx, add->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200304 FREE_STRINGS(ctx, add->uniques, dict);
305 FREE_STRINGS(ctx, add->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200306 break;
307 case LYS_DEV_REPLACE:
308 FREE_MEMBER(ctx, rpl->type, lysp_type_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200309 FREE_STRING(ctx, rpl->units, dict);
310 FREE_STRING(ctx, rpl->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200311 break;
312 default:
313 LOGINT(ctx);
314 break;
315 }
316}
317
318static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200319lysp_deviation_free(struct ly_ctx *ctx, struct lysp_deviation *dev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200320{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200321 struct lysp_deviate *next, *iter;
322
Radek Krejci151a5b72018-10-19 14:21:44 +0200323 FREE_STRING(ctx, dev->nodeid, dict);
324 FREE_STRING(ctx, dev->dsc, dict);
325 FREE_STRING(ctx, dev->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200326 LY_LIST_FOR_SAFE(dev->deviates, next, iter) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200327 lysp_deviate_free(ctx, iter, dict);
Michal Vasko8447f6a2018-10-15 10:56:16 +0200328 free(iter);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200329 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200330 FREE_ARRAY(ctx, dev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200331}
332
333static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200334lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200335{
Radek Krejci151a5b72018-10-19 14:21:44 +0200336 FREE_STRING(ctx, ref->nodeid, dict);
337 FREE_STRING(ctx, ref->dsc, dict);
338 FREE_STRING(ctx, ref->ref, dict);
339 FREE_STRINGS(ctx, ref->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200340 FREE_ARRAY(ctx, ref->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200341 FREE_STRING(ctx, ref->presence, dict);
342 FREE_STRINGS(ctx, ref->dflts, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200343 FREE_ARRAY(ctx, ref->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200344}
345
346static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200347lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200348{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200349 struct lysp_node *child, *next;
350
Radek Krejci151a5b72018-10-19 14:21:44 +0200351 FREE_STRING(ctx, node->name, dict);
352 FREE_STRING(ctx, node->dsc, dict);
353 FREE_STRING(ctx, node->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200354 FREE_MEMBER(ctx, node->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200355 FREE_STRINGS(ctx, node->iffeatures, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200356 FREE_ARRAY(ctx, node->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200357
358 switch(node->nodetype) {
359 case LYS_CONTAINER:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200360 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200361 FREE_STRING(ctx, ((struct lysp_node_container*)node)->presence, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200362 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->typedefs, lysp_tpdf_free);
363 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200364 LY_LIST_FOR_SAFE(((struct lysp_node_container*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200365 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200366 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200367 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->actions, lysp_action_free);
368 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->notifs, lysp_notif_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200369 break;
370 case LYS_LEAF:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200371 FREE_ARRAY(ctx, ((struct lysp_node_leaf*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200372 lysp_type_free(ctx, &((struct lysp_node_leaf*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200373 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->units, dict);
374 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200375 break;
376 case LYS_LEAFLIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200377 FREE_ARRAY(ctx, ((struct lysp_node_leaflist*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200378 lysp_type_free(ctx, &((struct lysp_node_leaflist*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200379 FREE_STRING(ctx, ((struct lysp_node_leaflist*)node)->units, dict);
380 FREE_STRINGS(ctx, ((struct lysp_node_leaflist*)node)->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200381 break;
382 case LYS_LIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200383 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200384 FREE_STRING(ctx, ((struct lysp_node_list*)node)->key, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200385 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->typedefs, lysp_tpdf_free);
386 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200387 LY_LIST_FOR_SAFE(((struct lysp_node_list*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200388 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200389 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200390 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->actions, lysp_action_free);
391 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->notifs, lysp_notif_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200392 FREE_STRINGS(ctx, ((struct lysp_node_list*)node)->uniques, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200393 break;
394 case LYS_CHOICE:
395 LY_LIST_FOR_SAFE(((struct lysp_node_choice*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200396 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200397 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200398 FREE_STRING(ctx, ((struct lysp_node_choice*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200399 break;
400 case LYS_CASE:
401 LY_LIST_FOR_SAFE(((struct lysp_node_case*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200402 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200403 }
404 break;
405 case LYS_ANYDATA:
406 case LYS_ANYXML:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200407 FREE_ARRAY(ctx, ((struct lysp_node_anydata*)node)->musts, lysp_restr_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200408 break;
409 case LYS_USES:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200410 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->refines, lysp_refine_free);
411 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->augments, lysp_augment_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200412 break;
413 default:
414 LOGINT(ctx);
415 }
416
417 free(node);
418}
419
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200420static void
421lysp_module_free_(struct lysp_module *module, int dict)
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200422{
423 struct ly_ctx *ctx;
Radek Krejci6f7feb62018-10-12 15:23:02 +0200424 struct lysp_node *node, *next;
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200425
426 LY_CHECK_ARG_RET(NULL, module,);
427 ctx = module->ctx;
428
Radek Krejci151a5b72018-10-19 14:21:44 +0200429 FREE_STRING(ctx, module->name, dict);
430 FREE_STRING(ctx, module->filepath, dict);
431 FREE_STRING(ctx, module->ns, dict); /* or belongs-to */
432 FREE_STRING(ctx, module->prefix, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200433
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200434 FREE_ARRAY(ctx, module->imports, lysp_import_free);
435 FREE_ARRAY(ctx, module->includes, lysp_include_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200436
Radek Krejci151a5b72018-10-19 14:21:44 +0200437 FREE_STRING(ctx, module->org, dict);
438 FREE_STRING(ctx, module->contact, dict);
439 FREE_STRING(ctx, module->dsc, dict);
440 FREE_STRING(ctx, module->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200441
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200442 FREE_ARRAY(ctx, module->revs, lysp_revision_free);
443 FREE_ARRAY(ctx, module->extensions, lysp_ext_free);
444 FREE_ARRAY(ctx, module->features, lysp_feature_free);
445 FREE_ARRAY(ctx, module->identities, lysp_ident_free);
446 FREE_ARRAY(ctx, module->typedefs, lysp_tpdf_free);
447 FREE_ARRAY(ctx, module->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200448 LY_LIST_FOR_SAFE(module->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200449 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200450 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200451 FREE_ARRAY(ctx, module->augments, lysp_augment_free);
452 FREE_ARRAY(ctx, module->rpcs, lysp_action_free);
453 FREE_ARRAY(ctx, module->notifs, lysp_notif_free);
454 FREE_ARRAY(ctx, module->deviations, lysp_deviation_free);
455 FREE_ARRAY(ctx, module->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200456
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200457 free(module);
458}
459
460API void
461lysp_module_free(struct lysp_module *module)
462{
Radek Krejci151a5b72018-10-19 14:21:44 +0200463 if (module) {
464 lysp_module_free_(module, 1);
465 }
466}
467
468static void
Radek Krejci478020e2018-10-30 16:02:14 +0100469lysc_ext_instance_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext, int dict)
470{
471 FREE_STRING(ctx, ext->argument, dict);
472 FREE_ARRAY(ctx, ext->exts, lysc_ext_instance_free);
473}
474
475static void
Radek Krejci151a5b72018-10-19 14:21:44 +0200476lysc_iffeature_free(struct ly_ctx *UNUSED(ctx), struct lysc_iffeature *iff, int UNUSED(dict))
477{
Radek Krejci2c4e7172018-10-19 15:56:26 +0200478 LY_ARRAY_FREE(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200479 free(iff->expr);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200480}
481
482static void
Radek Krejci478020e2018-10-30 16:02:14 +0100483lysc_import_free(struct ly_ctx *ctx, struct lysc_import *import, int dict)
484{
485 /* imported module is freed directly from the context's list */
486 FREE_STRING(ctx, import->prefix, dict);
487 FREE_ARRAY(ctx, import->exts, lysc_ext_instance_free);
488}
489
490static void
491lysc_ident_free(struct ly_ctx *ctx, struct lysc_ident *ident, int dict)
492{
493 FREE_STRING(ctx, ident->name, dict);
494 FREE_ARRAY(ctx, ident->iffeatures, lysc_iffeature_free);
495 LY_ARRAY_FREE(ident->derived);
496 FREE_ARRAY(ctx, ident->exts, lysc_ext_instance_free);
497}
498
499static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200500lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat, int dict)
501{
Radek Krejci151a5b72018-10-19 14:21:44 +0200502 FREE_STRING(ctx, feat->name, dict);
503 FREE_ARRAY(ctx, feat->iffeatures, lysc_iffeature_free);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200504 LY_ARRAY_FREE(feat->depfeatures);
Radek Krejci478020e2018-10-30 16:02:14 +0100505 FREE_ARRAY(ctx, feat->exts, lysc_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200506}
507
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100508static void lysc_node_free(struct ly_ctx *ctx, struct lysc_node *node, int dict);
509
510static void
511lysc_node_container_free(struct ly_ctx *ctx, struct lysc_node_container *node, int dict)
512{
513 struct lysc_node *child, *child_next;
514
515 LY_LIST_FOR_SAFE(node->child, child_next, child) {
516 lysc_node_free(ctx, child, dict);
517 }
518}
519
520static void
521lysc_node_free(struct ly_ctx *ctx, struct lysc_node *node, int dict)
522{
523 /* common part */
524 FREE_STRING(ctx, node->name, dict);
525
526 /* nodetype-specific part */
527 switch(node->nodetype) {
528 case LYS_CONTAINER:
529 lysc_node_container_free(ctx, (struct lysc_node_container*)node, dict);
530 break;
531 default:
532 LOGINT(ctx);
533 }
534
535 free(node);
536}
537
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200538static void
539lysc_module_free_(struct lysc_module *module, int dict)
540{
541 struct ly_ctx *ctx;
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100542 struct lysc_node *node, *node_next;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200543
544 LY_CHECK_ARG_RET(NULL, module,);
545 ctx = module->ctx;
546
Radek Krejci151a5b72018-10-19 14:21:44 +0200547 FREE_STRING(ctx, module->name, dict);
548 FREE_STRING(ctx, module->ns, dict);
549 FREE_STRING(ctx, module->prefix, dict);
Radek Krejcif8f882a2018-10-31 14:51:15 +0100550 FREE_STRING(ctx, module->revision, 1);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200551
Radek Krejci478020e2018-10-30 16:02:14 +0100552 FREE_ARRAY(ctx, module->imports, lysc_import_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200553 FREE_ARRAY(ctx, module->features, lysc_feature_free);
Radek Krejci478020e2018-10-30 16:02:14 +0100554 FREE_ARRAY(ctx, module->identities, lysc_ident_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200555
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100556 LY_LIST_FOR_SAFE(module->data, node_next, node) {
557 lysc_node_free(ctx, node, dict);
558 }
559
Radek Krejci478020e2018-10-30 16:02:14 +0100560 FREE_ARRAY(ctx, module->exts, lysc_ext_instance_free);
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200561
562 free(module);
563}
Radek Krejci70853c52018-10-15 14:46:16 +0200564
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200565API void
Radek Krejci86d106e2018-10-18 09:53:19 +0200566lysc_module_free(struct lysc_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200567{
Radek Krejci151a5b72018-10-19 14:21:44 +0200568 if (module) {
569 lysc_module_free_(module, 1);
570 }
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200571}
572
Radek Krejci86d106e2018-10-18 09:53:19 +0200573void
574lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejci70853c52018-10-15 14:46:16 +0200575{
Radek Krejci86d106e2018-10-18 09:53:19 +0200576 if (!module) {
577 return;
578 }
Radek Krejci70853c52018-10-15 14:46:16 +0200579
Radek Krejci86d106e2018-10-18 09:53:19 +0200580 lysc_module_free(module->compiled, private_destructor);
581 lysp_module_free(module->parsed);
582 free(module);
583}
584
Radek Krejci151a5b72018-10-19 14:21:44 +0200585struct iff_stack {
586 int size;
587 int index; /* first empty item */
588 uint8_t *stack;
589};
590
Radek Krejci86d106e2018-10-18 09:53:19 +0200591static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200592iff_stack_push(struct iff_stack *stack, uint8_t value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200593{
Radek Krejci151a5b72018-10-19 14:21:44 +0200594 if (stack->index == stack->size) {
595 stack->size += 4;
596 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
597 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
Radek Krejci70853c52018-10-15 14:46:16 +0200598 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200599 stack->stack[stack->index++] = value;
Radek Krejci70853c52018-10-15 14:46:16 +0200600 return LY_SUCCESS;
601}
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200602
Radek Krejci151a5b72018-10-19 14:21:44 +0200603static uint8_t
604iff_stack_pop(struct iff_stack *stack)
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200605{
Radek Krejci151a5b72018-10-19 14:21:44 +0200606 stack->index--;
607 return stack->stack[stack->index];
608}
609
610static void
611iff_stack_clean(struct iff_stack *stack)
612{
613 stack->size = 0;
614 free(stack->stack);
615}
616
617static void
618iff_setop(uint8_t *list, uint8_t op, int pos)
619{
620 uint8_t *item;
621 uint8_t mask = 3;
622
623 assert(pos >= 0);
624 assert(op <= 3); /* max 2 bits */
625
626 item = &list[pos / 4];
627 mask = mask << 2 * (pos % 4);
628 *item = (*item) & ~mask;
629 *item = (*item) | (op << 2 * (pos % 4));
630}
631
632static uint8_t
633iff_getop(uint8_t *list, int pos)
634{
635 uint8_t *item;
636 uint8_t mask = 3, result;
637
638 assert(pos >= 0);
639
640 item = &list[pos / 4];
641 result = (*item) & (mask << 2 * (pos % 4));
642 return result >> 2 * (pos % 4);
643}
644
645#define LYS_IFF_LP 0x04 /* ( */
646#define LYS_IFF_RP 0x08 /* ) */
647
648API int
649lysc_feature_value(const struct lysc_feature *feature)
650{
651 LY_CHECK_ARG_RET(NULL, feature, -1);
652 return feature->flags & LYS_FENABLED ? 1 : 0;
653}
654
655static struct lysc_feature *
656lysc_feature_find(struct lysc_module *mod, const char *name, size_t len)
657{
658 size_t i;
659 struct lysc_feature *f;
660
661 for (i = 0; i < len; ++i) {
662 if (name[i] == ':') {
663 /* we have a prefixed feature */
Radek Krejcibbe09a92018-11-08 09:36:54 +0100664 mod = lysc_module_find_prefix(mod, name, i);
Radek Krejci151a5b72018-10-19 14:21:44 +0200665 LY_CHECK_RET(!mod, NULL);
666
667 name = &name[i + 1];
668 len = len - i - 1;
669 }
670 }
671
672 /* we have the correct module, get the feature */
673 LY_ARRAY_FOR(mod->features, i) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200674 f = &mod->features[i];
Radek Krejci151a5b72018-10-19 14:21:44 +0200675 if (!strncmp(f->name, name, len) && f->name[len] == '\0') {
676 return f;
677 }
678 }
679
680 return NULL;
681}
682
683static int
684lysc_iffeature_value_(const struct lysc_iffeature *iff, int *index_e, int *index_f)
685{
686 uint8_t op;
687 int a, b;
688
689 op = iff_getop(iff->expr, *index_e);
690 (*index_e)++;
691
692 switch (op) {
693 case LYS_IFF_F:
694 /* resolve feature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200695 return lysc_feature_value(iff->features[(*index_f)++]);
Radek Krejci151a5b72018-10-19 14:21:44 +0200696 case LYS_IFF_NOT:
697 /* invert result */
698 return lysc_iffeature_value_(iff, index_e, index_f) ? 0 : 1;
699 case LYS_IFF_AND:
700 case LYS_IFF_OR:
701 a = lysc_iffeature_value_(iff, index_e, index_f);
702 b = lysc_iffeature_value_(iff, index_e, index_f);
703 if (op == LYS_IFF_AND) {
704 return a && b;
705 } else { /* LYS_IFF_OR */
706 return a || b;
707 }
708 }
709
710 return 0;
711}
712
713API int
714lysc_iffeature_value(const struct lysc_iffeature *iff)
715{
716 int index_e = 0, index_f = 0;
717
718 LY_CHECK_ARG_RET(NULL, iff, -1);
719
720 if (iff->expr) {
721 return lysc_iffeature_value_(iff, &index_e, &index_f);
722 }
723 return 0;
724}
725
726/*
727 * op: 1 - enable, 0 - disable
728 */
729/**
730 * @brief Enable/Disable the specified feature in the module.
731 *
732 * If the feature is already set to the desired value, LY_SUCCESS is returned.
733 * By changing the feature, also all the feature which depends on it via their
734 * if-feature statements are again evaluated (disabled if a if-feature statemen
735 * evaluates to false).
736 *
737 * @param[in] mod Compiled module where to set (search for) the feature.
738 * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
739 * set all the features in the module.
740 * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
741 * @return LY_ERR value.
742 */
743static LY_ERR
744lys_feature_change(const struct lysc_module *mod, const char *name, int value)
745{
746 int all = 0;
Radek Krejcica3db002018-11-01 10:31:01 +0100747 unsigned int u, changed_count, disabled_count;
Radek Krejci151a5b72018-10-19 14:21:44 +0200748 struct lysc_feature *f, **df;
749 struct lysc_iffeature *iff;
750 struct ly_set *changed;
751
752 if (!mod->features) {
753 LOGERR(mod->ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
754 return LY_EINVAL;
755 }
756
757 if (!strcmp(name, "*")) {
758 /* enable all */
759 all = 1;
760 }
761 changed = ly_set_new();
Radek Krejcica3db002018-11-01 10:31:01 +0100762 changed_count = 0;
Radek Krejci151a5b72018-10-19 14:21:44 +0200763
Radek Krejcica3db002018-11-01 10:31:01 +0100764run:
765 for (disabled_count = u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200766 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200767 if (all || !strcmp(f->name, name)) {
768 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
769 if (all) {
770 /* skip already set features */
771 continue;
772 } else {
773 /* feature already set correctly */
774 ly_set_free(changed, NULL);
775 return LY_SUCCESS;
776 }
777 }
778
779 if (value) { /* enable */
780 /* check referenced features if they are enabled */
781 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
782 if (!lysc_iffeature_value(iff)) {
783 if (all) {
Radek Krejcica3db002018-11-01 10:31:01 +0100784 ++disabled_count;
Radek Krejci151a5b72018-10-19 14:21:44 +0200785 goto next;
786 } else {
787 LOGERR(mod->ctx, LY_EDENIED,
788 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
789 f->name);
790 ly_set_free(changed, NULL);
791 return LY_EDENIED;
792 }
793 }
794 }
795 /* enable the feature */
796 f->flags |= LYS_FENABLED;
797 } else { /* disable */
798 /* disable the feature */
799 f->flags &= ~LYS_FENABLED;
800 }
801
802 /* remember the changed feature */
803 ly_set_add(changed, f, LY_SET_OPT_USEASLIST);
804
805 if (!all) {
806 /* stop in case changing a single feature */
807 break;
808 }
809 }
810next:
811 ;
812 }
813
814 if (!all && !changed->count) {
815 LOGERR(mod->ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
816 ly_set_free(changed, NULL);
817 return LY_EINVAL;
818 }
819
Radek Krejcica3db002018-11-01 10:31:01 +0100820 if (value && all && disabled_count) {
821 if (changed_count == changed->count) {
822 /* no change in last run -> not able to enable all ... */
823 /* ... print errors */
824 for (u = 0; disabled_count && u < LY_ARRAY_SIZE(mod->features); ++u) {
825 if (!(mod->features[u].flags & LYS_FENABLED)) {
826 LOGERR(mod->ctx, LY_EDENIED,
827 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
828 mod->features[u].name);
829 --disabled_count;
830 }
831 }
832 /* ... restore the original state */
833 for (u = 0; u < changed->count; ++u) {
834 f = changed->objs[u];
835 /* re-disable the feature */
836 f->flags &= ~LYS_FENABLED;
837 }
838
839 ly_set_free(changed, NULL);
840 return LY_EDENIED;
841 } else {
842 /* we did some change in last run, try it again */
843 changed_count = changed->count;
844 goto run;
845 }
846 }
847
Radek Krejci151a5b72018-10-19 14:21:44 +0200848 /* reflect change(s) in the dependent features */
849 for (u = 0; u < changed->count; ++u) {
850 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
851 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
852 * is not done - by default, features are disabled and must be explicitely enabled. */
853 f = changed->objs[u];
854 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature*, df) {
855 if (!((*df)->flags & LYS_FENABLED)) {
856 /* not enabled, nothing to do */
857 continue;
858 }
859 /* check the feature's if-features which could change by the previous change of our feature */
860 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
861 if (!lysc_iffeature_value(iff)) {
862 /* the feature must be disabled now */
863 (*df)->flags &= ~LYS_FENABLED;
864 /* add the feature into the list of changed features */
865 ly_set_add(changed, *df, LY_SET_OPT_USEASLIST);
866 break;
867 }
868 }
869 }
870 }
871
872 ly_set_free(changed, NULL);
873 return LY_SUCCESS;
874}
875
876API LY_ERR
877lys_feature_enable(struct lys_module *module, const char *feature)
878{
879 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
880
881 return lys_feature_change(module->compiled, feature, 1);
882}
883
884API LY_ERR
885lys_feature_disable(struct lys_module *module, const char *feature)
886{
887 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
888
889 return lys_feature_change(module->compiled, feature, 0);
890}
891
892API int
893lys_feature_value(const struct lys_module *module, const char *feature)
894{
895 struct lysc_feature *f;
896 struct lysc_module *mod;
897 unsigned int u;
898
899 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
900 mod = module->compiled;
901
902 /* search for the specified feature */
903 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200904 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200905 if (!strcmp(f->name, feature)) {
906 if (f->flags & LYS_FENABLED) {
907 return 1;
908 } else {
909 return 0;
910 }
911 }
912 }
913
914 /* feature definition not found */
915 return -1;
916}
917
918static LY_ERR
Radek Krejcice8c1592018-10-29 15:35:51 +0100919lys_compile_ext(struct lysc_ctx *ctx, struct lysp_ext_instance *ext_p, int options, struct lysc_ext_instance *ext)
Radek Krejci151a5b72018-10-19 14:21:44 +0200920{
Radek Krejcice8c1592018-10-29 15:35:51 +0100921 const char *name;
922 unsigned int u;
923 const struct lys_module *mod;
924 struct lysp_ext *edef;
925
926 if (options & LYSC_OPT_FREE_SP) {
927 /* just switch the pointers */
928 ext->argument = ext_p->argument;
929 } else {
930 /* keep refcounts correct for lysp_module_free() */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100931 ext->argument = lydict_insert(ctx->ctx, ext_p->argument, 0);
Radek Krejcice8c1592018-10-29 15:35:51 +0100932 }
933 ext->insubstmt = ext_p->insubstmt;
934 ext->insubstmt_index = ext_p->insubstmt_index;
935
936 /* get module where the extension definition should be placed */
937 for (u = 0; ext_p->name[u] != ':'; ++u);
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100938 mod = lys_module_find_prefix(ctx->mod, ext_p->name, u);
939 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejcice8c1592018-10-29 15:35:51 +0100940 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, ext_p->name),
941 LY_EVALID);
942 LY_CHECK_ERR_RET(!mod->parsed->extensions,
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100943 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejcice8c1592018-10-29 15:35:51 +0100944 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
945 ext_p->name, mod->parsed->name),
946 LY_EVALID);
947 name = &ext_p->name[u + 1];
948 /* find the extension definition there */
949 for (ext = NULL, u = 0; u < LY_ARRAY_SIZE(mod->parsed->extensions); ++u) {
950 if (!strcmp(name, mod->parsed->extensions[u].name)) {
951 edef = &mod->parsed->extensions[u];
952 break;
953 }
954 }
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100955 LY_CHECK_ERR_RET(!edef, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
Radek Krejcice8c1592018-10-29 15:35:51 +0100956 "Extension definition of extension instance \"%s\" not found.", ext_p->name),
957 LY_EVALID);
958 /* TODO plugins */
959
960 return LY_SUCCESS;
961}
962
963/**
964 * @param[in] parent Provided only in case the if-feature is inside
965 */
966static LY_ERR
967lys_compile_iffeature(struct lysc_ctx *ctx, const char **value, int UNUSED(options), struct lysc_iffeature *iff)
968{
969 const char *c = *value;
Radek Krejci151a5b72018-10-19 14:21:44 +0200970 int r, rc = EXIT_FAILURE;
971 int i, j, last_not, checkversion = 0;
972 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
973 uint8_t op;
974 struct iff_stack stack = {0, 0, NULL};
Radek Krejcice8c1592018-10-29 15:35:51 +0100975 struct lysc_feature *f;
Radek Krejci151a5b72018-10-19 14:21:44 +0200976
977 assert(c);
978
979 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
980 for (i = j = last_not = 0; c[i]; i++) {
981 if (c[i] == '(') {
982 j++;
983 checkversion = 1;
984 continue;
985 } else if (c[i] == ')') {
986 j--;
987 continue;
988 } else if (isspace(c[i])) {
989 checkversion = 1;
990 continue;
991 }
992
993 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
994 if (c[i + r] == '\0') {
Radek Krejcibd8d9ba2018-11-02 16:06:26 +0100995 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100996 "Invalid value \"%s\" of if-feature - unexpected end of expression.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200997 return LY_EVALID;
998 } else if (!isspace(c[i + r])) {
999 /* feature name starting with the not/and/or */
1000 last_not = 0;
1001 f_size++;
1002 } else if (c[i] == 'n') { /* not operation */
1003 if (last_not) {
1004 /* double not */
1005 expr_size = expr_size - 2;
1006 last_not = 0;
1007 } else {
1008 last_not = 1;
1009 }
1010 } else { /* and, or */
1011 f_exp++;
1012 /* not a not operation */
1013 last_not = 0;
1014 }
1015 i += r;
1016 } else {
1017 f_size++;
1018 last_not = 0;
1019 }
1020 expr_size++;
1021
1022 while (!isspace(c[i])) {
1023 if (!c[i] || c[i] == ')') {
1024 i--;
1025 break;
1026 }
1027 i++;
1028 }
1029 }
1030 if (j || f_exp != f_size) {
1031 /* not matching count of ( and ) */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001032 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001033 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001034 return LY_EVALID;
1035 }
1036
1037 if (checkversion || expr_size > 1) {
1038 /* check that we have 1.1 module */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001039 if (ctx->mod->compiled->version != LYS_VERSION_1_1) {
1040 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001041 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001042 return LY_EVALID;
1043 }
1044 }
1045
1046 /* allocate the memory */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001047 LY_ARRAY_CREATE_RET(ctx->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +02001048 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +02001049 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001050 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +02001051
Radek Krejci151a5b72018-10-19 14:21:44 +02001052 stack.size = expr_size;
1053 f_size--; expr_size--; /* used as indexes from now */
1054
1055 for (i--; i >= 0; i--) {
1056 if (c[i] == ')') {
1057 /* push it on stack */
1058 iff_stack_push(&stack, LYS_IFF_RP);
1059 continue;
1060 } else if (c[i] == '(') {
1061 /* pop from the stack into result all operators until ) */
1062 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1063 iff_setop(iff->expr, op, expr_size--);
1064 }
1065 continue;
1066 } else if (isspace(c[i])) {
1067 continue;
1068 }
1069
1070 /* end of operator or operand -> find beginning and get what is it */
1071 j = i + 1;
1072 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1073 i--;
1074 }
1075 i++; /* go back by one step */
1076
1077 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
1078 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1079 /* double not */
1080 iff_stack_pop(&stack);
1081 } else {
1082 /* not has the highest priority, so do not pop from the stack
1083 * as in case of AND and OR */
1084 iff_stack_push(&stack, LYS_IFF_NOT);
1085 }
1086 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
1087 /* as for OR - pop from the stack all operators with the same or higher
1088 * priority and store them to the result, then push the AND to the stack */
1089 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1090 op = iff_stack_pop(&stack);
1091 iff_setop(iff->expr, op, expr_size--);
1092 }
1093 iff_stack_push(&stack, LYS_IFF_AND);
1094 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
1095 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1096 op = iff_stack_pop(&stack);
1097 iff_setop(iff->expr, op, expr_size--);
1098 }
1099 iff_stack_push(&stack, LYS_IFF_OR);
1100 } else {
1101 /* feature name, length is j - i */
1102
1103 /* add it to the expression */
1104 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
1105
1106 /* now get the link to the feature definition */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001107 f = lysc_feature_find(ctx->mod->compiled, &c[i], j - i);
Radek Krejci151a5b72018-10-19 14:21:44 +02001108 LY_CHECK_ERR_GOTO(!f,
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001109 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001110 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
Radek Krejci87616bb2018-10-31 13:30:52 +01001111 rc = LY_EVALID,
Radek Krejci151a5b72018-10-19 14:21:44 +02001112 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +02001113 iff->features[f_size] = f;
1114 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +02001115 f_size--;
1116 }
1117 }
1118 while (stack.index) {
1119 op = iff_stack_pop(&stack);
1120 iff_setop(iff->expr, op, expr_size--);
1121 }
1122
1123 if (++expr_size || ++f_size) {
1124 /* not all expected operators and operands found */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001125 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001126 "Invalid value \"%s\" of if-feature - processing error.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001127 rc = LY_EINT;
1128 } else {
1129 rc = LY_SUCCESS;
1130 }
1131
1132error:
1133 /* cleanup */
1134 iff_stack_clean(&stack);
1135
1136 return rc;
1137}
1138
1139static LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001140lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
1141{
Radek Krejcice8c1592018-10-29 15:35:51 +01001142 unsigned int u;
Radek Krejcif8f882a2018-10-31 14:51:15 +01001143 struct lys_module *mod = NULL;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001144 struct lysc_module *comp;
Radek Krejcice8c1592018-10-29 15:35:51 +01001145 LY_ERR ret = LY_SUCCESS;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001146
1147 if (options & LYSC_OPT_FREE_SP) {
1148 /* just switch the pointers */
1149 imp->prefix = imp_p->prefix;
1150 } else {
1151 /* keep refcounts correct for lysp_module_free() */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001152 imp->prefix = lydict_insert(ctx->ctx, imp_p->prefix, 0);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001153 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001154 COMPILE_ARRAY_GOTO(ctx, imp_p->exts, imp->exts, options, u, lys_compile_ext, ret, done);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001155 imp->module = imp_p->module;
1156
1157 /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
1158 * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
1159 if (!imp->module->parsed) {
1160 comp = imp->module->compiled;
1161 /* try to get filepath from the compiled version */
1162 if (comp->filepath) {
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001163 mod = (struct lys_module*)lys_parse_path(ctx->ctx, comp->filepath,
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001164 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
1165 if (mod != imp->module) {
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001166 LOGERR(ctx->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001167 comp->filepath, comp->name);
1168 mod = NULL;
1169 }
1170 }
1171 if (!mod) {
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001172 if (lysp_load_module(ctx->ctx, comp->name, comp->revision, 0, 1, &mod)) {
1173 LOGERR(ctx->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
1174 comp->name, ctx->mod->compiled->name);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001175 return LY_ENOTFOUND;
1176 }
1177 }
1178 } else if (!imp->module->compiled) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001179 return lys_compile(imp->module, options);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001180 }
1181
Radek Krejcice8c1592018-10-29 15:35:51 +01001182done:
1183 return ret;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001184}
1185
1186static LY_ERR
Radek Krejci2a408df2018-10-29 16:32:26 +01001187lys_compile_identity(struct lysc_ctx *ctx, struct lysp_ident *ident_p, int options, struct lysc_ident *ident)
1188{
1189 unsigned int u;
1190 LY_ERR ret = LY_SUCCESS;
1191
1192 if (options & LYSC_OPT_FREE_SP) {
1193 /* just switch the pointers */
1194 ident->name = ident_p->name;
1195 } else {
1196 /* keep refcounts correct for lysp_module_free() */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001197 ident->name = lydict_insert(ctx->ctx, ident_p->name, 0);
Radek Krejci2a408df2018-10-29 16:32:26 +01001198 }
1199 COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, options, u, lys_compile_iffeature, ret, done);
1200 /* backlings (derived) can be added no sooner than when all the identities in the current module are present */
1201 COMPILE_ARRAY_GOTO(ctx, ident_p->exts, ident->exts, options, u, lys_compile_ext, ret, done);
1202 ident->flags = ident_p->flags;
1203
1204done:
1205 return ret;
1206}
1207
1208static LY_ERR
1209lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1210{
1211 unsigned int i, u, v;
1212 const char *s, *name;
1213 struct lysc_module *mod;
1214 struct lysc_ident **dident;
1215
1216 for (i = 0; i < LY_ARRAY_SIZE(idents_p); ++i) {
Radek Krejci478020e2018-10-30 16:02:14 +01001217 if (!idents_p[i].bases) {
1218 continue;
1219 }
Radek Krejci2a408df2018-10-29 16:32:26 +01001220 for (u = 0; u < LY_ARRAY_SIZE(idents_p[i].bases); ++u) {
1221 s = strchr(idents_p[i].bases[u], ':');
1222 if (s) {
1223 /* prefixed identity */
1224 name = &s[1];
Radek Krejcibbe09a92018-11-08 09:36:54 +01001225 mod = lysc_module_find_prefix(ctx->mod->compiled, idents_p[i].bases[u], s - idents_p[i].bases[u]);
Radek Krejci2a408df2018-10-29 16:32:26 +01001226 } else {
1227 name = idents_p[i].bases[u];
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001228 mod = ctx->mod->compiled;
Radek Krejci2a408df2018-10-29 16:32:26 +01001229 }
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001230 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejci2a408df2018-10-29 16:32:26 +01001231 "Invalid prefix used for base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1232 LY_EVALID);
1233 if (mod->identities) {
1234 for (v = 0; v < LY_ARRAY_SIZE(mod->identities); ++v) {
1235 if (!strcmp(name, mod->identities[v].name)) {
1236 /* we have match! store the backlink */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001237 LY_ARRAY_NEW_RET(ctx->ctx, mod->identities[v].derived, dident, LY_EMEM);
Radek Krejci2a408df2018-10-29 16:32:26 +01001238 *dident = &idents[i];
1239 break;
1240 }
1241 }
1242 }
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001243 LY_CHECK_ERR_RET(!dident, LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejci2a408df2018-10-29 16:32:26 +01001244 "Unable to find base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1245 LY_EVALID);
1246 }
1247 }
1248 return LY_SUCCESS;
1249}
1250
1251static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +02001252lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
1253{
Radek Krejcice8c1592018-10-29 15:35:51 +01001254 unsigned int u, v;
1255 LY_ERR ret = LY_SUCCESS;
1256 struct lysc_feature **df;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001257
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001258 if (options & LYSC_OPT_FREE_SP) {
1259 /* just switch the pointers */
1260 feature->name = feature_p->name;
1261 } else {
1262 /* keep refcounts correct for lysp_module_free() */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001263 feature->name = lydict_insert(ctx->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001264 }
1265 feature->flags = feature_p->flags;
1266
Radek Krejcice8c1592018-10-29 15:35:51 +01001267 COMPILE_ARRAY_GOTO(ctx, feature_p->exts, feature->exts, options, u, lys_compile_ext, ret, done);
1268 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, options, u, lys_compile_iffeature, ret, done);
1269 if (feature->iffeatures) {
1270 for (u = 0; u < LY_ARRAY_SIZE(feature->iffeatures); ++u) {
1271 if (feature->iffeatures[u].features) {
1272 for (v = 0; v < LY_ARRAY_SIZE(feature->iffeatures[u].features); ++v) {
1273 /* add itself into the dependants list */
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001274 LY_ARRAY_NEW_RET(ctx->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
Radek Krejcice8c1592018-10-29 15:35:51 +01001275 *df = feature;
1276 }
1277 /* TODO check for circular dependency */
1278 }
Radek Krejci151a5b72018-10-19 14:21:44 +02001279 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001280 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001281done:
1282 return ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001283}
1284
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001285static LY_ERR lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent);
1286
1287static LY_ERR
1288lys_compile_node_container(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *node)
1289{
1290 struct lysp_node_container *cont_p = (struct lysp_node_container*)node_p;
1291 //struct lysc_node_container *cont = (struct lysc_node_container*)node;
1292 struct lysp_node *child_p;
1293
1294 LY_LIST_FOR(cont_p->child, child_p) {
1295 LY_CHECK_RET(lys_compile_node(ctx, child_p, options, node));
1296 }
1297
1298 return LY_SUCCESS;
1299}
1300
1301static LY_ERR
1302lys_compile_node(struct lysc_ctx *ctx, struct lysp_node *node_p, int options, struct lysc_node *parent)
1303{
1304 LY_ERR ret = LY_EVALID;
1305 struct lysc_node *node;
1306 unsigned int u;
1307 LY_ERR (*node_compile_spec)(struct lysc_ctx*, struct lysp_node*, int, struct lysc_node*);
1308
1309 switch (node_p->nodetype) {
1310 case LYS_CONTAINER:
1311 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_container));
1312 node_compile_spec = lys_compile_node_container;
1313 break;
1314 case LYS_LEAF:
1315 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_leaf));
1316 break;
1317 case LYS_LIST:
1318 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_list));
1319 break;
1320 case LYS_LEAFLIST:
1321 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_leaflist));
1322 break;
1323 case LYS_CASE:
1324 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_case));
1325 break;
1326 case LYS_CHOICE:
1327 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_choice));
1328 break;
1329 case LYS_USES:
1330 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_uses));
1331 break;
1332 case LYS_ANYXML:
1333 case LYS_ANYDATA:
1334 node = (struct lysc_node*)calloc(1, sizeof(struct lysc_node_anydata));
1335 break;
1336 default:
1337 LOGINT(ctx->ctx);
1338 return LY_EINT;
1339 }
1340 LY_CHECK_ERR_RET(!node, LOGMEM(ctx->ctx), LY_EMEM);
1341 node->nodetype = node_p->nodetype;
1342 node->module = ctx->mod;
1343 node->prev = node;
1344 node->flags = node_p->flags;
1345
1346 /* config */
1347 if (!(node->flags & LYS_CONFIG_MASK)) {
1348 /* config not explicitely set, inherit it from parent */
1349 if (parent) {
1350 node->flags |= parent->flags & LYS_CONFIG_MASK;
1351 } else {
1352 /* default is config true */
1353 node->flags |= LYS_CONFIG_W;
1354 }
1355 }
1356
1357 /* status - it is not inherited by specification, but it does not make sense to have
1358 * current in deprecated or deprecated in obsolete, so we do print warning and inherit status */
1359 if (!(node->flags & LYS_STATUS_MASK)) {
1360 if (parent && (parent->flags & (LYS_STATUS_DEPRC | LYS_STATUS_OBSLT))) {
Radek Krejci98094b32018-11-02 16:21:47 +01001361 LOGWRN(ctx->ctx, "Missing explicit \"%s\" status that was already specified in parent, inheriting.",
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001362 (parent->flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
1363 node->flags |= parent->flags & LYS_STATUS_MASK;
1364 } else {
1365 node->flags |= LYS_STATUS_CURR;
1366 }
1367 } else if (parent) {
1368 /* check status compatibility with the parent */
1369 if ((parent->flags & LYS_STATUS_MASK) > (node->flags & LYS_STATUS_MASK)) {
1370 if (node->flags & LYS_STATUS_CURR) {
1371 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
1372 "A \"current\" status is in conflict with the parent's \"%s\" status.",
1373 (parent->flags & LYS_STATUS_DEPRC) ? "deprecated" : "obsolete");
1374 } else { /* LYS_STATUS_DEPRC */
1375 LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
1376 "A \"deprecated\" status is in conflict with the parent's \"obsolete\" status.");
1377 }
1378 goto error;
1379 }
1380 }
1381
1382 if (options & LYSC_OPT_FREE_SP) {
1383 /* just switch the pointers */
1384 node->name = node_p->name;
1385 } else {
1386 node->sp = node_p;
1387 /* keep refcounts correct for lysp_module_free() */
1388 node->name = lydict_insert(ctx->ctx, node_p->name, 0);
1389 }
1390 COMPILE_ARRAY_GOTO(ctx, node_p->exts, node->exts, options, u, lys_compile_ext, ret, error);
1391
1392 /* nodetype-specific part */
1393 LY_CHECK_GOTO(node_compile_spec(ctx, node_p, options, node), error);
1394
1395 /* insert into parent's children */
1396 if (parent) {
1397 if (!((struct lysc_node_case*)parent)->child) {
1398 /* first child */
1399 ((struct lysc_node_case*)parent)->child = node;
1400 } else {
1401 /* insert at the end of the parent's children list */
1402 ((struct lysc_node_case*)parent)->child->prev->next = node;
1403 node->prev = ((struct lysc_node_case*)parent)->child->prev;
1404 ((struct lysc_node_case*)parent)->child->prev = node;
1405 }
1406 } else {
1407 /* top-level element */
1408 if (!ctx->mod->compiled->data) {
1409 ctx->mod->compiled->data = node;
1410 } else {
1411 /* insert at the end of the module's top-level nodes list */
1412 ctx->mod->compiled->data->prev->next = node;
1413 node->prev = ctx->mod->compiled->data->prev;
1414 ctx->mod->compiled->data->prev = node;
1415 }
1416 }
1417
1418 return LY_SUCCESS;
1419
1420error:
1421 lysc_node_free(ctx->ctx, node, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
1422 return ret;
1423}
1424
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001425LY_ERR
Radek Krejcid14e9692018-11-01 11:00:37 +01001426lys_compile(struct lys_module *mod, int options)
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001427{
Radek Krejci86d106e2018-10-18 09:53:19 +02001428 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001429 struct lysc_module *mod_c;
Radek Krejcif8f882a2018-10-31 14:51:15 +01001430 struct lysp_module *sp;
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001431 struct lysp_node *node_p;
Radek Krejci151a5b72018-10-19 14:21:44 +02001432 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001433 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001434
Radek Krejcif8f882a2018-10-31 14:51:15 +01001435 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, mod->parsed->ctx, LY_EINVAL);
1436 sp = mod->parsed;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001437
1438 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001439 LOGERR(sp->ctx, LY_EINVAL, "Submodules (%s) are not supposed to be compiled, compile only the main modules.", sp->name);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001440 return LY_EINVAL;
1441 }
1442
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001443 ctx.ctx = sp->ctx;
1444 ctx.mod = mod;
1445
1446 mod->compiled = mod_c = calloc(1, sizeof *mod_c);
Radek Krejci86d106e2018-10-18 09:53:19 +02001447 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1448 mod_c->ctx = sp->ctx;
Radek Krejcid14e9692018-11-01 11:00:37 +01001449 mod_c->implemented = sp->implemented;
1450 mod_c->latest_revision = sp->latest_revision;
Radek Krejci86d106e2018-10-18 09:53:19 +02001451 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001452
1453 if (options & LYSC_OPT_FREE_SP) {
1454 /* just switch the pointers */
1455 mod_c->name = sp->name;
1456 mod_c->ns = sp->ns;
1457 mod_c->prefix = sp->prefix;
1458 } else {
1459 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001460 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1461 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1462 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001463 }
Radek Krejcif8f882a2018-10-31 14:51:15 +01001464 if (sp->revs) {
1465 mod_c->revision = lydict_insert(sp->ctx, sp->revs[0].date, 10);
1466 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001467 COMPILE_ARRAY_GOTO(&ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
1468 COMPILE_ARRAY_GOTO(&ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
Radek Krejci2a408df2018-10-29 16:32:26 +01001469 COMPILE_ARRAY_GOTO(&ctx, sp->identities, mod_c->identities, options, u, lys_compile_identity, ret, error);
1470 if (sp->identities) {
1471 LY_CHECK_RET(lys_compile_identities_derived(&ctx, sp->identities, mod_c->identities));
1472 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001473
1474 COMPILE_ARRAY_GOTO(&ctx, sp->exts, mod_c->exts, options, u, lys_compile_ext, ret, error);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001475
Radek Krejcibd8d9ba2018-11-02 16:06:26 +01001476 LY_LIST_FOR(sp->data, node_p) {
1477 ret = lys_compile_node(&ctx, node_p, options, NULL);
1478 LY_CHECK_GOTO(ret, error);
1479 }
1480
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001481 if (options & LYSC_OPT_FREE_SP) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001482 lysp_module_free_(mod->parsed, 0);
1483 ((struct lys_module*)mod)->parsed = NULL;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001484 }
1485
Radek Krejcif8f882a2018-10-31 14:51:15 +01001486 ((struct lys_module*)mod)->compiled = mod_c;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001487 return LY_SUCCESS;
1488
1489error:
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001490 lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
Radek Krejcif8f882a2018-10-31 14:51:15 +01001491 ((struct lys_module*)mod)->compiled = NULL;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001492 return ret;
1493}
Radek Krejci86d106e2018-10-18 09:53:19 +02001494
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001495static void
Radek Krejci086c7132018-10-26 15:29:04 +02001496lys_latest_switch(struct lys_module *old, struct lysp_module *new)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001497{
Radek Krejci086c7132018-10-26 15:29:04 +02001498 if (old->parsed) {
1499 new->latest_revision = old->parsed->latest_revision;
1500 old->parsed->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001501 }
Radek Krejci086c7132018-10-26 15:29:04 +02001502 if (old->compiled) {
1503 new->latest_revision = old->parsed->latest_revision;
1504 old->compiled->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001505 }
1506}
1507
Radek Krejcid33273d2018-10-25 14:55:52 +02001508struct lys_module *
Radek Krejci9ed7a192018-10-31 16:23:51 +01001509lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
1510 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
Radek Krejci86d106e2018-10-18 09:53:19 +02001511{
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001512 struct lys_module *mod = NULL, *latest, *mod_dup;
Radek Krejcid33273d2018-10-25 14:55:52 +02001513 struct lysp_module *latest_p;
Radek Krejci086c7132018-10-26 15:29:04 +02001514 struct lysp_import *imp;
1515 struct lysp_include *inc;
Radek Krejci9ed7a192018-10-31 16:23:51 +01001516 LY_ERR ret = LY_EINVAL;
Radek Krejci086c7132018-10-26 15:29:04 +02001517 unsigned int u, i;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001518 struct ly_parser_ctx context = {0};
Radek Krejci86d106e2018-10-18 09:53:19 +02001519
1520 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1521
Radek Krejcibbe09a92018-11-08 09:36:54 +01001522 context.ctx = ctx;
1523 context.line = 1;
1524
Radek Krejci86d106e2018-10-18 09:53:19 +02001525 mod = calloc(1, sizeof *mod);
1526 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1527
1528 switch (format) {
1529 case LYS_IN_YIN:
1530 /* TODO not yet supported
1531 mod = yin_read_module(ctx, data, revision, implement);
1532 */
1533 break;
1534 case LYS_IN_YANG:
Radek Krejcibbe09a92018-11-08 09:36:54 +01001535 ret = yang_parse(&context, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001536 break;
1537 default:
1538 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1539 break;
1540 }
Radek Krejcifaa1eac2018-10-30 14:34:55 +01001541 LY_CHECK_ERR_RET(ret, free(mod), NULL);
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001542
1543 /* make sure that the newest revision is at position 0 */
1544 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001545
1546 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001547 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001548 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1549 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
Radek Krejcibbe09a92018-11-08 09:36:54 +01001550 goto error;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001551 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001552 mod->parsed->implemented = 1;
1553 }
1554
Radek Krejci9ed7a192018-10-31 16:23:51 +01001555 if (custom_check) {
Radek Krejcibbe09a92018-11-08 09:36:54 +01001556 LY_CHECK_GOTO(custom_check(ctx, mod->parsed, check_data), error);
Radek Krejci86d106e2018-10-18 09:53:19 +02001557 }
1558
Radek Krejcid33273d2018-10-25 14:55:52 +02001559 if (mod->parsed->submodule) { /* submodule */
1560 /* decide the latest revision */
1561 latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
1562 if (latest_p) {
1563 if (mod->parsed->revs) {
1564 if (!latest_p->revs) {
1565 /* latest has no revision, so mod is anyway newer */
Radek Krejci9ed7a192018-10-31 16:23:51 +01001566 mod->parsed->latest_revision = latest_p->latest_revision;
Radek Krejcid33273d2018-10-25 14:55:52 +02001567 latest_p->latest_revision = 0;
1568 } else {
1569 if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
Radek Krejci9ed7a192018-10-31 16:23:51 +01001570 mod->parsed->latest_revision = latest_p->latest_revision;
Radek Krejcid33273d2018-10-25 14:55:52 +02001571 latest_p->latest_revision = 0;
1572 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001573 }
1574 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001575 } else {
Radek Krejci9ed7a192018-10-31 16:23:51 +01001576 mod->parsed->latest_revision = 1;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001577 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001578 } else { /* module */
1579 /* check for duplicity in the context */
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001580 mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
1581 if (mod_dup) {
1582 if (mod_dup->parsed) {
1583 /* error */
1584 if (mod->parsed->revs) {
1585 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1586 mod->parsed->name, mod->parsed->revs[0].date);
1587 } else {
1588 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1589 mod->parsed->name);
1590 }
Radek Krejcibbe09a92018-11-08 09:36:54 +01001591 goto error;
Radek Krejcid33273d2018-10-25 14:55:52 +02001592 } else {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001593 /* add the parsed data to the currently compiled-only module in the context */
1594 mod_dup->parsed = mod->parsed;
1595 free(mod);
1596 mod = mod_dup;
1597 goto finish_parsing;
Radek Krejcid33273d2018-10-25 14:55:52 +02001598 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001599 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001600
1601#if 0
1602 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1603 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1604 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1605 * the anotation definitions available in the internal schema structure. There is another hack in schema
1606 * printers to do not print this internally added annotation. */
1607 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1608 if (lyp_add_ietf_netconf_annotations(mod)) {
1609 lys_free(mod, NULL, 1, 1);
1610 return NULL;
1611 }
1612 }
1613#endif
1614
Radek Krejcid33273d2018-10-25 14:55:52 +02001615 /* decide the latest revision */
1616 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1617 if (latest) {
1618 if (mod->parsed->revs) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001619 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revision)) {
Radek Krejcid33273d2018-10-25 14:55:52 +02001620 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001621 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001622 } else {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001623 if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revision) > 0) {
Radek Krejci086c7132018-10-26 15:29:04 +02001624 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001625 }
1626 }
1627 }
1628 } else {
1629 mod->parsed->latest_revision = 1;
1630 }
1631
1632 /* add into context */
1633 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1634
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001635finish_parsing:
Radek Krejcibbe09a92018-11-08 09:36:54 +01001636 /* resolve imports */
Radek Krejci086c7132018-10-26 15:29:04 +02001637 mod->parsed->parsing = 1;
1638 LY_ARRAY_FOR(mod->parsed->imports, u) {
1639 imp = &mod->parsed->imports[u];
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001640 if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +01001641 goto error_ctx;
Radek Krejci086c7132018-10-26 15:29:04 +02001642 }
1643 /* check for importing the same module twice */
1644 for (i = 0; i < u; ++i) {
1645 if (imp->module == mod->parsed->imports[i].module) {
1646 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
Radek Krejcibbe09a92018-11-08 09:36:54 +01001647 goto error_ctx;
Radek Krejci086c7132018-10-26 15:29:04 +02001648 }
1649 }
1650 }
1651 LY_ARRAY_FOR(mod->parsed->includes, u) {
1652 inc = &mod->parsed->includes[u];
1653 if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
Radek Krejcibbe09a92018-11-08 09:36:54 +01001654 goto error_ctx;
Radek Krejci086c7132018-10-26 15:29:04 +02001655 }
1656 }
1657 mod->parsed->parsing = 0;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001658
1659 /* check name collisions - typedefs and groupings */
1660 LY_CHECK_GOTO(lysp_check_typedefs(&context), error_ctx);
Radek Krejcid33273d2018-10-25 14:55:52 +02001661 }
1662
Radek Krejci86d106e2018-10-18 09:53:19 +02001663 return mod;
Radek Krejcibbe09a92018-11-08 09:36:54 +01001664
1665error_ctx:
1666 ly_set_rm(&ctx->list, mod, NULL);
1667error:
1668 lys_module_free(mod, NULL);
1669 ly_set_erase(&context.tpdfs_nodes, NULL);
1670 return NULL;
Radek Krejci86d106e2018-10-18 09:53:19 +02001671}
1672
Radek Krejcid14e9692018-11-01 11:00:37 +01001673API struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001674lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1675{
Radek Krejcid33273d2018-10-25 14:55:52 +02001676 struct lys_module *result;
1677
Radek Krejci9ed7a192018-10-31 16:23:51 +01001678 result = lys_parse_mem_(ctx, data, format, 1, NULL, NULL);
Radek Krejcid33273d2018-10-25 14:55:52 +02001679 if (result && result->parsed->submodule) {
1680 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1681 result->parsed->name);
1682 lys_module_free(result, NULL);
1683 return NULL;
1684 }
1685 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001686}
1687
1688static void
1689lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1690{
1691#ifdef __APPLE__
1692 char path[MAXPATHLEN];
1693#else
1694 int len;
1695 char path[PATH_MAX], proc_path[32];
1696#endif
1697
1698#ifdef __APPLE__
1699 if (fcntl(fd, F_GETPATH, path) != -1) {
1700 *filename = lydict_insert(ctx, path, 0);
1701 }
1702#else
1703 /* get URI if there is /proc */
1704 sprintf(proc_path, "/proc/self/fd/%d", fd);
1705 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1706 *filename = lydict_insert(ctx, path, len);
1707 }
1708#endif
1709}
1710
Radek Krejcid33273d2018-10-25 14:55:52 +02001711struct lys_module *
Radek Krejci9ed7a192018-10-31 16:23:51 +01001712lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
1713 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
Radek Krejci86d106e2018-10-18 09:53:19 +02001714{
Radek Krejcid33273d2018-10-25 14:55:52 +02001715 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001716 size_t length;
1717 char *addr;
1718
1719 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1720 if (fd < 0) {
1721 LOGARG(ctx, fd);
1722 return NULL;
1723 }
1724
1725 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1726 if (!addr) {
1727 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1728 return NULL;
1729 }
1730
Radek Krejci9ed7a192018-10-31 16:23:51 +01001731 mod = lys_parse_mem_(ctx, addr, format, implement, custom_check, check_data);
Radek Krejci86d106e2018-10-18 09:53:19 +02001732 ly_munmap(addr, length);
1733
1734 if (mod && !mod->parsed->filepath) {
1735 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1736 }
1737
1738 return mod;
1739}
1740
Radek Krejcid14e9692018-11-01 11:00:37 +01001741API struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001742lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1743{
Radek Krejcid33273d2018-10-25 14:55:52 +02001744 struct lys_module *result;
1745
Radek Krejci9ed7a192018-10-31 16:23:51 +01001746 result = lys_parse_fd_(ctx, fd, format, 1, NULL, NULL);
Radek Krejcid33273d2018-10-25 14:55:52 +02001747 if (result && result->parsed->submodule) {
1748 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1749 result->parsed->name);
1750 lys_module_free(result, NULL);
1751 return NULL;
1752 }
1753 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001754}
1755
Radek Krejcid33273d2018-10-25 14:55:52 +02001756struct lys_module *
Radek Krejci9ed7a192018-10-31 16:23:51 +01001757lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
1758 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
Radek Krejci86d106e2018-10-18 09:53:19 +02001759{
1760 int fd;
Radek Krejcid33273d2018-10-25 14:55:52 +02001761 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001762 const char *rev, *dot, *filename;
1763 size_t len;
1764
1765 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1766
1767 fd = open(path, O_RDONLY);
1768 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1769
Radek Krejci9ed7a192018-10-31 16:23:51 +01001770 mod = lys_parse_fd_(ctx, fd, format, implement, custom_check, check_data);
Radek Krejci86d106e2018-10-18 09:53:19 +02001771 close(fd);
1772 LY_CHECK_RET(!mod, NULL);
1773
1774 /* check that name and revision match filename */
1775 filename = strrchr(path, '/');
1776 if (!filename) {
1777 filename = path;
1778 } else {
1779 filename++;
1780 }
1781 rev = strchr(filename, '@');
1782 dot = strrchr(filename, '.');
1783
1784 /* name */
1785 len = strlen(mod->parsed->name);
1786 if (strncmp(filename, mod->parsed->name, len) ||
1787 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1788 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1789 }
1790 if (rev) {
1791 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001792 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001793 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001794 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001795 }
1796 }
1797
1798 if (!mod->parsed->filepath) {
1799 /* store URI */
1800 char rpath[PATH_MAX];
1801 if (realpath(path, rpath) != NULL) {
1802 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1803 } else {
1804 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1805 }
1806 }
1807
1808 return mod;
1809}
1810
Radek Krejcid14e9692018-11-01 11:00:37 +01001811API struct lys_module *
Radek Krejcid33273d2018-10-25 14:55:52 +02001812lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1813{
1814 struct lys_module *result;
1815
Radek Krejci9ed7a192018-10-31 16:23:51 +01001816 result = lys_parse_path_(ctx, path, format, 1, NULL, NULL);
Radek Krejcid33273d2018-10-25 14:55:52 +02001817 if (result && result->parsed->submodule) {
1818 LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
1819 path, result->parsed->name);
1820 lys_module_free(result, NULL);
1821 return NULL;
1822 }
1823 return result;
1824}
1825
1826API LY_ERR
1827lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
1828 char **localfile, LYS_INFORMAT *format)
1829{
1830 size_t len, flen, match_len = 0, dir_len;
1831 int i, implicit_cwd = 0, ret = EXIT_FAILURE;
1832 char *wd, *wn = NULL;
1833 DIR *dir = NULL;
1834 struct dirent *file;
1835 char *match_name = NULL;
1836 LYS_INFORMAT format_aux, match_format = 0;
1837 struct ly_set *dirs;
1838 struct stat st;
1839
1840 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1841
1842 /* start to fill the dir fifo with the context's search path (if set)
1843 * and the current working directory */
1844 dirs = ly_set_new();
1845 if (!dirs) {
1846 LOGMEM(NULL);
1847 return EXIT_FAILURE;
1848 }
1849
1850 len = strlen(name);
1851 if (cwd) {
1852 wd = get_current_dir_name();
1853 if (!wd) {
1854 LOGMEM(NULL);
1855 goto cleanup;
1856 } else {
1857 /* add implicit current working directory (./) to be searched,
1858 * this directory is not searched recursively */
1859 if (ly_set_add(dirs, wd, 0) == -1) {
1860 goto cleanup;
1861 }
1862 implicit_cwd = 1;
1863 }
1864 }
1865 if (searchpaths) {
1866 for (i = 0; searchpaths[i]; i++) {
1867 /* check for duplicities with the implicit current working directory */
1868 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1869 implicit_cwd = 0;
1870 continue;
1871 }
1872 wd = strdup(searchpaths[i]);
1873 if (!wd) {
1874 LOGMEM(NULL);
1875 goto cleanup;
1876 } else if (ly_set_add(dirs, wd, 0) == -1) {
1877 goto cleanup;
1878 }
1879 }
1880 }
1881 wd = NULL;
1882
1883 /* start searching */
1884 while (dirs->count) {
1885 free(wd);
1886 free(wn); wn = NULL;
1887
1888 dirs->count--;
1889 wd = (char *)dirs->objs[dirs->count];
1890 dirs->objs[dirs->count] = NULL;
1891 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1892
1893 if (dir) {
1894 closedir(dir);
1895 }
1896 dir = opendir(wd);
1897 dir_len = strlen(wd);
1898 if (!dir) {
1899 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1900 } else {
1901 while ((file = readdir(dir))) {
1902 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1903 /* skip . and .. */
1904 continue;
1905 }
1906 free(wn);
1907 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1908 LOGMEM(NULL);
1909 goto cleanup;
1910 }
1911 if (stat(wn, &st) == -1) {
1912 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1913 file->d_name, wd, strerror(errno));
1914 continue;
1915 }
1916 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1917 /* we have another subdirectory in searchpath to explore,
1918 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1919 if (ly_set_add(dirs, wn, 0) == -1) {
1920 goto cleanup;
1921 }
1922 /* continue with the next item in current directory */
1923 wn = NULL;
1924 continue;
1925 } else if (!S_ISREG(st.st_mode)) {
1926 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1927 continue;
1928 }
1929
1930 /* here we know that the item is a file which can contain a module */
1931 if (strncmp(name, file->d_name, len) ||
1932 (file->d_name[len] != '.' && file->d_name[len] != '@')) {
1933 /* different filename than the module we search for */
1934 continue;
1935 }
1936
1937 /* get type according to filename suffix */
1938 flen = strlen(file->d_name);
1939 if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1940 format_aux = LYS_IN_YIN;
1941 } else if (!strcmp(&file->d_name[flen - 5], ".yang")) {
1942 format_aux = LYS_IN_YANG;
1943 } else {
1944 /* not supportde suffix/file format */
1945 continue;
1946 }
1947
1948 if (revision) {
1949 /* we look for the specific revision, try to get it from the filename */
1950 if (file->d_name[len] == '@') {
1951 /* check revision from the filename */
1952 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1953 /* another revision */
1954 continue;
1955 } else {
1956 /* exact revision */
1957 free(match_name);
1958 match_name = wn;
1959 wn = NULL;
1960 match_len = dir_len + 1 + len;
1961 match_format = format_aux;
1962 goto success;
1963 }
1964 } else {
1965 /* continue trying to find exact revision match, use this only if not found */
1966 free(match_name);
1967 match_name = wn;
1968 wn = NULL;
1969 match_len = dir_len + 1 +len;
1970 match_format = format_aux;
1971 continue;
1972 }
1973 } else {
1974 /* remember the revision and try to find the newest one */
1975 if (match_name) {
1976 if (file->d_name[len] != '@' ||
1977 lysp_check_date(NULL, &file->d_name[len + 1], flen - (format_aux == LYS_IN_YANG ? 5 : 4) - len - 1, NULL)) {
1978 continue;
1979 } else if (match_name[match_len] == '@' &&
1980 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1981 continue;
1982 }
1983 free(match_name);
1984 }
1985
1986 match_name = wn;
1987 wn = NULL;
1988 match_len = dir_len + 1 + len;
1989 match_format = format_aux;
1990 continue;
1991 }
1992 }
1993 }
1994 }
1995
1996success:
1997 (*localfile) = match_name;
1998 match_name = NULL;
1999 if (format) {
2000 (*format) = match_format;
2001 }
2002 ret = EXIT_SUCCESS;
2003
2004cleanup:
2005 free(wn);
2006 free(wd);
2007 if (dir) {
2008 closedir(dir);
2009 }
2010 free(match_name);
2011 ly_set_free(dirs, free);
2012
2013 return ret;
2014}
2015