blob: 8c117f12b2636bf6773626d6dcb8e966ec4c278a [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) { \
39 LY_ARRAY_CREATE_GOTO((CTX).mod->ctx, ARRAY_C, LY_ARRAY_SIZE(ARRAY_P), RET, GOTO); \
40 for (ITER = 0; ITER < LY_ARRAY_SIZE(ARRAY_P); ++ITER) { \
41 RET = FUNC(&(CTX), &(ARRAY_P)[ITER], OPTIONS, &(ARRAY_C)[ITER]); \
42 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
43 LY_ARRAY_INCREMENT(ARRAY_C); \
44 } \
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 Krejci86d106e2018-10-18 09:53:19 +020050#define LYSC_CTX_BUFSIZE 4086
51struct lysc_ctx {
52 struct lysc_module *mod;
53 uint16_t path_len;
54 char path[LYSC_CTX_BUFSIZE];
55};
56
Radek Krejci6f7feb62018-10-12 15:23:02 +020057static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020058lysp_stmt_free(struct ly_ctx *ctx, struct lysp_stmt *stmt, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020059{
60 struct lysp_stmt *child, *next;
61
Radek Krejci151a5b72018-10-19 14:21:44 +020062 FREE_STRING(ctx, stmt->stmt, dict);
63 FREE_STRING(ctx, stmt->arg, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020064
65 LY_LIST_FOR_SAFE(stmt->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020066 lysp_stmt_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020067 }
68
69 free(stmt);
70}
71
72static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020073lysp_ext_instance_free(struct ly_ctx *ctx, struct lysp_ext_instance *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020074{
75 struct lysp_stmt *stmt, *next;
76
Radek Krejci151a5b72018-10-19 14:21:44 +020077 FREE_STRING(ctx, ext->name, dict);
78 FREE_STRING(ctx, ext->argument, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020079
80 LY_LIST_FOR_SAFE(ext->child, next, stmt) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020081 lysp_stmt_free(ctx, stmt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020082 }
83}
84
85static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020086lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020087{
Radek Krejci086c7132018-10-26 15:29:04 +020088 /* imported module is freed directly from the context's list */
Radek Krejci151a5b72018-10-19 14:21:44 +020089 FREE_STRING(ctx, import->name, dict);
90 FREE_STRING(ctx, import->prefix, dict);
91 FREE_STRING(ctx, import->dsc, dict);
92 FREE_STRING(ctx, import->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +020093 FREE_ARRAY(ctx, import->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +020094}
95
96static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020097lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020098{
Radek Krejcid33273d2018-10-25 14:55:52 +020099 if (include->submodule && !(--include->submodule->refcount)) {
100 lysp_module_free(include->submodule);
101 }
Radek Krejci086c7132018-10-26 15:29:04 +0200102 FREE_STRING(ctx, include->name, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200103 FREE_STRING(ctx, include->dsc, dict);
104 FREE_STRING(ctx, include->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200105 FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200106}
107
108static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200109lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200110{
Radek Krejci151a5b72018-10-19 14:21:44 +0200111 FREE_STRING(ctx, rev->dsc, dict);
112 FREE_STRING(ctx, rev->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200113 FREE_ARRAY(ctx, rev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200114}
115
116static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200117lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200118{
Radek Krejci151a5b72018-10-19 14:21:44 +0200119 FREE_STRING(ctx, ext->name, dict);
120 FREE_STRING(ctx, ext->argument, dict);
121 FREE_STRING(ctx, ext->dsc, dict);
122 FREE_STRING(ctx, ext->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200123 FREE_ARRAY(ctx, ext->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200124}
125
126static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200127lysp_feature_free(struct ly_ctx *ctx, struct lysp_feature *feat, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200128{
Radek Krejci151a5b72018-10-19 14:21:44 +0200129 FREE_STRING(ctx, feat->name, dict);
130 FREE_STRINGS(ctx, feat->iffeatures, 1);
131 FREE_STRING(ctx, feat->dsc, dict);
132 FREE_STRING(ctx, feat->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200133 FREE_ARRAY(ctx, feat->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200134}
135
136static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200137lysp_ident_free(struct ly_ctx *ctx, struct lysp_ident *ident, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200138{
Radek Krejci151a5b72018-10-19 14:21:44 +0200139 FREE_STRING(ctx, ident->name, dict);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200140 FREE_STRINGS(ctx, ident->iffeatures, 1);
Radek Krejci151a5b72018-10-19 14:21:44 +0200141 FREE_STRINGS(ctx, ident->bases, dict);
142 FREE_STRING(ctx, ident->dsc, dict);
143 FREE_STRING(ctx, ident->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200144 FREE_ARRAY(ctx, ident->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200145}
146
147static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200148lysp_restr_free(struct ly_ctx *ctx, struct lysp_restr *restr, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200149{
Radek Krejci151a5b72018-10-19 14:21:44 +0200150 FREE_STRING(ctx, restr->arg, dict);
151 FREE_STRING(ctx, restr->emsg, dict);
152 FREE_STRING(ctx, restr->eapptag, dict);
153 FREE_STRING(ctx, restr->dsc, dict);
154 FREE_STRING(ctx, restr->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200155 FREE_ARRAY(ctx, restr->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200156}
157
158static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200159lysp_type_enum_free(struct ly_ctx *ctx, struct lysp_type_enum *item, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200160{
Radek Krejci151a5b72018-10-19 14:21:44 +0200161 FREE_STRING(ctx, item->name, dict);
162 FREE_STRING(ctx, item->dsc, dict);
163 FREE_STRING(ctx, item->ref, dict);
164 FREE_STRINGS(ctx, item->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200165 FREE_ARRAY(ctx, item->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200166}
167
168static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200169lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200170{
Radek Krejci151a5b72018-10-19 14:21:44 +0200171 FREE_STRING(ctx, type->name, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200172 FREE_MEMBER(ctx, type->range, lysp_restr_free);
173 FREE_MEMBER(ctx, type->length, lysp_restr_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200174 FREE_ARRAY(ctx, type->patterns, lysp_restr_free);
175 FREE_ARRAY(ctx, type->enums, lysp_type_enum_free);
176 FREE_ARRAY(ctx, type->bits, lysp_type_enum_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200177 FREE_STRING(ctx, type->path, dict);
178 FREE_STRINGS(ctx, type->bases, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200179 FREE_ARRAY(ctx, type->types, lysp_type_free);
180 FREE_ARRAY(ctx, type->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200181}
182
183static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200184lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200185{
Radek Krejci151a5b72018-10-19 14:21:44 +0200186 FREE_STRING(ctx, tpdf->name, dict);
187 FREE_STRING(ctx, tpdf->units, dict);
188 FREE_STRING(ctx, tpdf->dflt, dict);
189 FREE_STRING(ctx, tpdf->dsc, dict);
190 FREE_STRING(ctx, tpdf->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200191 FREE_ARRAY(ctx, tpdf->exts, lysp_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200192 lysp_type_free(ctx, &tpdf->type, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200193}
194
195static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200196lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200197{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200198 struct lysp_node *node, *next;
199
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200200 FREE_ARRAY(ctx, inout->musts, lysp_restr_free);
201 FREE_ARRAY(ctx, inout->typedefs, lysp_tpdf_free);
202 FREE_ARRAY(ctx, inout->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200203 LY_LIST_FOR_SAFE(inout->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200204 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200205 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200206 FREE_ARRAY(ctx, inout->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200207
208}
209
210static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200211lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200212{
Radek Krejci151a5b72018-10-19 14:21:44 +0200213 FREE_STRING(ctx, action->name, dict);
214 FREE_STRING(ctx, action->dsc, dict);
215 FREE_STRING(ctx, action->ref, dict);
216 FREE_STRINGS(ctx, action->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200217 FREE_ARRAY(ctx, action->typedefs, lysp_tpdf_free);
218 FREE_ARRAY(ctx, action->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200219 FREE_MEMBER(ctx, action->input, lysp_action_inout_free);
220 FREE_MEMBER(ctx, action->output, lysp_action_inout_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200221 FREE_ARRAY(ctx, action->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200222}
223
224static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200225lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200226{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200227 struct lysp_node *node, *next;
228
Radek Krejci151a5b72018-10-19 14:21:44 +0200229 FREE_STRING(ctx, notif->name, dict);
230 FREE_STRING(ctx, notif->dsc, dict);
231 FREE_STRING(ctx, notif->ref, dict);
232 FREE_STRINGS(ctx, notif->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200233 FREE_ARRAY(ctx, notif->musts, lysp_restr_free);
234 FREE_ARRAY(ctx, notif->typedefs, lysp_tpdf_free);
235 FREE_ARRAY(ctx, notif->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200236 LY_LIST_FOR_SAFE(notif->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200237 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200238 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200239 FREE_ARRAY(ctx, notif->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200240}
241
242static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200243lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200244{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200245 struct lysp_node *node, *next;
246
Radek Krejci151a5b72018-10-19 14:21:44 +0200247 FREE_STRING(ctx, grp->name, dict);
248 FREE_STRING(ctx, grp->dsc, dict);
249 FREE_STRING(ctx, grp->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200250 FREE_ARRAY(ctx, grp->typedefs, lysp_tpdf_free);
251 FREE_ARRAY(ctx, grp->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200252 LY_LIST_FOR_SAFE(grp->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200253 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200254 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200255 FREE_ARRAY(ctx, grp->actions, lysp_action_free);
256 FREE_ARRAY(ctx, grp->notifs, lysp_notif_free);
257 FREE_ARRAY(ctx, grp->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200258}
259
260static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200261lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200262{
Radek Krejci151a5b72018-10-19 14:21:44 +0200263 FREE_STRING(ctx, when->cond, dict);
264 FREE_STRING(ctx, when->dsc, dict);
265 FREE_STRING(ctx, when->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200266 FREE_ARRAY(ctx, when->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200267}
268
269static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200270lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200271{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200272 struct lysp_node *node, *next;
273
Radek Krejci151a5b72018-10-19 14:21:44 +0200274 FREE_STRING(ctx, augment->nodeid, dict);
275 FREE_STRING(ctx, augment->dsc, dict);
276 FREE_STRING(ctx, augment->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200277 FREE_MEMBER(ctx, augment->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200278 FREE_STRINGS(ctx, augment->iffeatures, 1);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200279 LY_LIST_FOR_SAFE(augment->child, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200280 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200281 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200282 FREE_ARRAY(ctx, augment->actions, lysp_action_free);
283 FREE_ARRAY(ctx, augment->notifs, lysp_notif_free);
284 FREE_ARRAY(ctx, augment->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200285}
286
287static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200288lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200289{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200290 struct lysp_deviate_add *add = (struct lysp_deviate_add*)d;
291 struct lysp_deviate_rpl *rpl = (struct lysp_deviate_rpl*)d;
292
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200293 FREE_ARRAY(ctx, d->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200294 switch(d->mod) {
295 case LYS_DEV_NOT_SUPPORTED:
296 /* nothing to do */
297 break;
298 case LYS_DEV_ADD:
299 case LYS_DEV_DELETE: /* compatible for dynamically allocated data */
Radek Krejci151a5b72018-10-19 14:21:44 +0200300 FREE_STRING(ctx, add->units, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200301 FREE_ARRAY(ctx, add->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200302 FREE_STRINGS(ctx, add->uniques, dict);
303 FREE_STRINGS(ctx, add->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200304 break;
305 case LYS_DEV_REPLACE:
306 FREE_MEMBER(ctx, rpl->type, lysp_type_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200307 FREE_STRING(ctx, rpl->units, dict);
308 FREE_STRING(ctx, rpl->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200309 break;
310 default:
311 LOGINT(ctx);
312 break;
313 }
314}
315
316static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200317lysp_deviation_free(struct ly_ctx *ctx, struct lysp_deviation *dev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200318{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200319 struct lysp_deviate *next, *iter;
320
Radek Krejci151a5b72018-10-19 14:21:44 +0200321 FREE_STRING(ctx, dev->nodeid, dict);
322 FREE_STRING(ctx, dev->dsc, dict);
323 FREE_STRING(ctx, dev->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200324 LY_LIST_FOR_SAFE(dev->deviates, next, iter) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200325 lysp_deviate_free(ctx, iter, dict);
Michal Vasko8447f6a2018-10-15 10:56:16 +0200326 free(iter);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200327 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200328 FREE_ARRAY(ctx, dev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200329}
330
331static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200332lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200333{
Radek Krejci151a5b72018-10-19 14:21:44 +0200334 FREE_STRING(ctx, ref->nodeid, dict);
335 FREE_STRING(ctx, ref->dsc, dict);
336 FREE_STRING(ctx, ref->ref, dict);
337 FREE_STRINGS(ctx, ref->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200338 FREE_ARRAY(ctx, ref->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200339 FREE_STRING(ctx, ref->presence, dict);
340 FREE_STRINGS(ctx, ref->dflts, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200341 FREE_ARRAY(ctx, ref->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200342}
343
344static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200345lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200346{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200347 struct lysp_node *child, *next;
348
Radek Krejci151a5b72018-10-19 14:21:44 +0200349 FREE_STRING(ctx, node->name, dict);
350 FREE_STRING(ctx, node->dsc, dict);
351 FREE_STRING(ctx, node->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200352 FREE_MEMBER(ctx, node->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200353 FREE_STRINGS(ctx, node->iffeatures, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200354 FREE_ARRAY(ctx, node->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200355
356 switch(node->nodetype) {
357 case LYS_CONTAINER:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200358 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200359 FREE_STRING(ctx, ((struct lysp_node_container*)node)->presence, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200360 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->typedefs, lysp_tpdf_free);
361 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200362 LY_LIST_FOR_SAFE(((struct lysp_node_container*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200363 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200364 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200365 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->actions, lysp_action_free);
366 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->notifs, lysp_notif_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200367 break;
368 case LYS_LEAF:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200369 FREE_ARRAY(ctx, ((struct lysp_node_leaf*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200370 lysp_type_free(ctx, &((struct lysp_node_leaf*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200371 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->units, dict);
372 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200373 break;
374 case LYS_LEAFLIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200375 FREE_ARRAY(ctx, ((struct lysp_node_leaflist*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200376 lysp_type_free(ctx, &((struct lysp_node_leaflist*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200377 FREE_STRING(ctx, ((struct lysp_node_leaflist*)node)->units, dict);
378 FREE_STRINGS(ctx, ((struct lysp_node_leaflist*)node)->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200379 break;
380 case LYS_LIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200381 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200382 FREE_STRING(ctx, ((struct lysp_node_list*)node)->key, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200383 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->typedefs, lysp_tpdf_free);
384 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200385 LY_LIST_FOR_SAFE(((struct lysp_node_list*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200386 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200387 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200388 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->actions, lysp_action_free);
389 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->notifs, lysp_notif_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200390 FREE_STRINGS(ctx, ((struct lysp_node_list*)node)->uniques, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200391 break;
392 case LYS_CHOICE:
393 LY_LIST_FOR_SAFE(((struct lysp_node_choice*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200394 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200395 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200396 FREE_STRING(ctx, ((struct lysp_node_choice*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200397 break;
398 case LYS_CASE:
399 LY_LIST_FOR_SAFE(((struct lysp_node_case*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200400 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200401 }
402 break;
403 case LYS_ANYDATA:
404 case LYS_ANYXML:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200405 FREE_ARRAY(ctx, ((struct lysp_node_anydata*)node)->musts, lysp_restr_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200406 break;
407 case LYS_USES:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200408 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->refines, lysp_refine_free);
409 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->augments, lysp_augment_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200410 break;
411 default:
412 LOGINT(ctx);
413 }
414
415 free(node);
416}
417
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200418static void
419lysp_module_free_(struct lysp_module *module, int dict)
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200420{
421 struct ly_ctx *ctx;
Radek Krejci6f7feb62018-10-12 15:23:02 +0200422 struct lysp_node *node, *next;
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200423
424 LY_CHECK_ARG_RET(NULL, module,);
425 ctx = module->ctx;
426
Radek Krejci151a5b72018-10-19 14:21:44 +0200427 FREE_STRING(ctx, module->name, dict);
428 FREE_STRING(ctx, module->filepath, dict);
429 FREE_STRING(ctx, module->ns, dict); /* or belongs-to */
430 FREE_STRING(ctx, module->prefix, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200431
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200432 FREE_ARRAY(ctx, module->imports, lysp_import_free);
433 FREE_ARRAY(ctx, module->includes, lysp_include_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200434
Radek Krejci151a5b72018-10-19 14:21:44 +0200435 FREE_STRING(ctx, module->org, dict);
436 FREE_STRING(ctx, module->contact, dict);
437 FREE_STRING(ctx, module->dsc, dict);
438 FREE_STRING(ctx, module->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200439
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200440 FREE_ARRAY(ctx, module->revs, lysp_revision_free);
441 FREE_ARRAY(ctx, module->extensions, lysp_ext_free);
442 FREE_ARRAY(ctx, module->features, lysp_feature_free);
443 FREE_ARRAY(ctx, module->identities, lysp_ident_free);
444 FREE_ARRAY(ctx, module->typedefs, lysp_tpdf_free);
445 FREE_ARRAY(ctx, module->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200446 LY_LIST_FOR_SAFE(module->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200447 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200448 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200449 FREE_ARRAY(ctx, module->augments, lysp_augment_free);
450 FREE_ARRAY(ctx, module->rpcs, lysp_action_free);
451 FREE_ARRAY(ctx, module->notifs, lysp_notif_free);
452 FREE_ARRAY(ctx, module->deviations, lysp_deviation_free);
453 FREE_ARRAY(ctx, module->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200454
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200455 free(module);
456}
457
458API void
459lysp_module_free(struct lysp_module *module)
460{
Radek Krejci151a5b72018-10-19 14:21:44 +0200461 if (module) {
462 lysp_module_free_(module, 1);
463 }
464}
465
466static void
467lysc_iffeature_free(struct ly_ctx *UNUSED(ctx), struct lysc_iffeature *iff, int UNUSED(dict))
468{
Radek Krejci2c4e7172018-10-19 15:56:26 +0200469 LY_ARRAY_FREE(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200470 free(iff->expr);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200471}
472
473static void
474lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat, int dict)
475{
Radek Krejci151a5b72018-10-19 14:21:44 +0200476 FREE_STRING(ctx, feat->name, dict);
477 FREE_ARRAY(ctx, feat->iffeatures, lysc_iffeature_free);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200478 LY_ARRAY_FREE(feat->depfeatures);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200479}
480
481static void
482lysc_module_free_(struct lysc_module *module, int dict)
483{
484 struct ly_ctx *ctx;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200485
486 LY_CHECK_ARG_RET(NULL, module,);
487 ctx = module->ctx;
488
Radek Krejci151a5b72018-10-19 14:21:44 +0200489 FREE_STRING(ctx, module->name, dict);
490 FREE_STRING(ctx, module->ns, dict);
491 FREE_STRING(ctx, module->prefix, dict);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200492
493
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200494 FREE_ARRAY(ctx, module->features, lysc_feature_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200495
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200496
497 free(module);
498}
Radek Krejci70853c52018-10-15 14:46:16 +0200499
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200500API void
Radek Krejci86d106e2018-10-18 09:53:19 +0200501lysc_module_free(struct lysc_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200502{
Radek Krejci151a5b72018-10-19 14:21:44 +0200503 if (module) {
504 lysc_module_free_(module, 1);
505 }
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200506}
507
Radek Krejci86d106e2018-10-18 09:53:19 +0200508void
509lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejci70853c52018-10-15 14:46:16 +0200510{
Radek Krejci86d106e2018-10-18 09:53:19 +0200511 if (!module) {
512 return;
513 }
Radek Krejci70853c52018-10-15 14:46:16 +0200514
Radek Krejci86d106e2018-10-18 09:53:19 +0200515 lysc_module_free(module->compiled, private_destructor);
516 lysp_module_free(module->parsed);
517 free(module);
518}
519
Radek Krejci151a5b72018-10-19 14:21:44 +0200520struct iff_stack {
521 int size;
522 int index; /* first empty item */
523 uint8_t *stack;
524};
525
Radek Krejci86d106e2018-10-18 09:53:19 +0200526static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200527iff_stack_push(struct iff_stack *stack, uint8_t value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200528{
Radek Krejci151a5b72018-10-19 14:21:44 +0200529 if (stack->index == stack->size) {
530 stack->size += 4;
531 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
532 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
Radek Krejci70853c52018-10-15 14:46:16 +0200533 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200534 stack->stack[stack->index++] = value;
Radek Krejci70853c52018-10-15 14:46:16 +0200535 return LY_SUCCESS;
536}
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200537
Radek Krejci151a5b72018-10-19 14:21:44 +0200538static uint8_t
539iff_stack_pop(struct iff_stack *stack)
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200540{
Radek Krejci151a5b72018-10-19 14:21:44 +0200541 stack->index--;
542 return stack->stack[stack->index];
543}
544
545static void
546iff_stack_clean(struct iff_stack *stack)
547{
548 stack->size = 0;
549 free(stack->stack);
550}
551
552static void
553iff_setop(uint8_t *list, uint8_t op, int pos)
554{
555 uint8_t *item;
556 uint8_t mask = 3;
557
558 assert(pos >= 0);
559 assert(op <= 3); /* max 2 bits */
560
561 item = &list[pos / 4];
562 mask = mask << 2 * (pos % 4);
563 *item = (*item) & ~mask;
564 *item = (*item) | (op << 2 * (pos % 4));
565}
566
567static uint8_t
568iff_getop(uint8_t *list, int pos)
569{
570 uint8_t *item;
571 uint8_t mask = 3, result;
572
573 assert(pos >= 0);
574
575 item = &list[pos / 4];
576 result = (*item) & (mask << 2 * (pos % 4));
577 return result >> 2 * (pos % 4);
578}
579
580#define LYS_IFF_LP 0x04 /* ( */
581#define LYS_IFF_RP 0x08 /* ) */
582
583API int
584lysc_feature_value(const struct lysc_feature *feature)
585{
586 LY_CHECK_ARG_RET(NULL, feature, -1);
587 return feature->flags & LYS_FENABLED ? 1 : 0;
588}
589
590static struct lysc_feature *
591lysc_feature_find(struct lysc_module *mod, const char *name, size_t len)
592{
593 size_t i;
594 struct lysc_feature *f;
595
596 for (i = 0; i < len; ++i) {
597 if (name[i] == ':') {
598 /* we have a prefixed feature */
599 mod = lysc_module_find_prefix(mod, name, i);
600 LY_CHECK_RET(!mod, NULL);
601
602 name = &name[i + 1];
603 len = len - i - 1;
604 }
605 }
606
607 /* we have the correct module, get the feature */
608 LY_ARRAY_FOR(mod->features, i) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200609 f = &mod->features[i];
Radek Krejci151a5b72018-10-19 14:21:44 +0200610 if (!strncmp(f->name, name, len) && f->name[len] == '\0') {
611 return f;
612 }
613 }
614
615 return NULL;
616}
617
618static int
619lysc_iffeature_value_(const struct lysc_iffeature *iff, int *index_e, int *index_f)
620{
621 uint8_t op;
622 int a, b;
623
624 op = iff_getop(iff->expr, *index_e);
625 (*index_e)++;
626
627 switch (op) {
628 case LYS_IFF_F:
629 /* resolve feature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200630 return lysc_feature_value(iff->features[(*index_f)++]);
Radek Krejci151a5b72018-10-19 14:21:44 +0200631 case LYS_IFF_NOT:
632 /* invert result */
633 return lysc_iffeature_value_(iff, index_e, index_f) ? 0 : 1;
634 case LYS_IFF_AND:
635 case LYS_IFF_OR:
636 a = lysc_iffeature_value_(iff, index_e, index_f);
637 b = lysc_iffeature_value_(iff, index_e, index_f);
638 if (op == LYS_IFF_AND) {
639 return a && b;
640 } else { /* LYS_IFF_OR */
641 return a || b;
642 }
643 }
644
645 return 0;
646}
647
648API int
649lysc_iffeature_value(const struct lysc_iffeature *iff)
650{
651 int index_e = 0, index_f = 0;
652
653 LY_CHECK_ARG_RET(NULL, iff, -1);
654
655 if (iff->expr) {
656 return lysc_iffeature_value_(iff, &index_e, &index_f);
657 }
658 return 0;
659}
660
661/*
662 * op: 1 - enable, 0 - disable
663 */
664/**
665 * @brief Enable/Disable the specified feature in the module.
666 *
667 * If the feature is already set to the desired value, LY_SUCCESS is returned.
668 * By changing the feature, also all the feature which depends on it via their
669 * if-feature statements are again evaluated (disabled if a if-feature statemen
670 * evaluates to false).
671 *
672 * @param[in] mod Compiled module where to set (search for) the feature.
673 * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
674 * set all the features in the module.
675 * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
676 * @return LY_ERR value.
677 */
678static LY_ERR
679lys_feature_change(const struct lysc_module *mod, const char *name, int value)
680{
681 int all = 0;
682 unsigned int u;
683 struct lysc_feature *f, **df;
684 struct lysc_iffeature *iff;
685 struct ly_set *changed;
686
687 if (!mod->features) {
688 LOGERR(mod->ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
689 return LY_EINVAL;
690 }
691
692 if (!strcmp(name, "*")) {
693 /* enable all */
694 all = 1;
695 }
696 changed = ly_set_new();
697
698 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200699 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200700 if (all || !strcmp(f->name, name)) {
701 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
702 if (all) {
703 /* skip already set features */
704 continue;
705 } else {
706 /* feature already set correctly */
707 ly_set_free(changed, NULL);
708 return LY_SUCCESS;
709 }
710 }
711
712 if (value) { /* enable */
713 /* check referenced features if they are enabled */
714 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
715 if (!lysc_iffeature_value(iff)) {
716 if (all) {
717 LOGWRN(mod->ctx,
718 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
719 f->name);
720 goto next;
721 } else {
722 LOGERR(mod->ctx, LY_EDENIED,
723 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
724 f->name);
725 ly_set_free(changed, NULL);
726 return LY_EDENIED;
727 }
728 }
729 }
730 /* enable the feature */
731 f->flags |= LYS_FENABLED;
732 } else { /* disable */
733 /* disable the feature */
734 f->flags &= ~LYS_FENABLED;
735 }
736
737 /* remember the changed feature */
738 ly_set_add(changed, f, LY_SET_OPT_USEASLIST);
739
740 if (!all) {
741 /* stop in case changing a single feature */
742 break;
743 }
744 }
745next:
746 ;
747 }
748
749 if (!all && !changed->count) {
750 LOGERR(mod->ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
751 ly_set_free(changed, NULL);
752 return LY_EINVAL;
753 }
754
755 /* reflect change(s) in the dependent features */
756 for (u = 0; u < changed->count; ++u) {
757 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
758 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
759 * is not done - by default, features are disabled and must be explicitely enabled. */
760 f = changed->objs[u];
761 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature*, df) {
762 if (!((*df)->flags & LYS_FENABLED)) {
763 /* not enabled, nothing to do */
764 continue;
765 }
766 /* check the feature's if-features which could change by the previous change of our feature */
767 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
768 if (!lysc_iffeature_value(iff)) {
769 /* the feature must be disabled now */
770 (*df)->flags &= ~LYS_FENABLED;
771 /* add the feature into the list of changed features */
772 ly_set_add(changed, *df, LY_SET_OPT_USEASLIST);
773 break;
774 }
775 }
776 }
777 }
778
779 ly_set_free(changed, NULL);
780 return LY_SUCCESS;
781}
782
783API LY_ERR
784lys_feature_enable(struct lys_module *module, const char *feature)
785{
786 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
787
788 return lys_feature_change(module->compiled, feature, 1);
789}
790
791API LY_ERR
792lys_feature_disable(struct lys_module *module, const char *feature)
793{
794 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
795
796 return lys_feature_change(module->compiled, feature, 0);
797}
798
799API int
800lys_feature_value(const struct lys_module *module, const char *feature)
801{
802 struct lysc_feature *f;
803 struct lysc_module *mod;
804 unsigned int u;
805
806 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
807 mod = module->compiled;
808
809 /* search for the specified feature */
810 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200811 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200812 if (!strcmp(f->name, feature)) {
813 if (f->flags & LYS_FENABLED) {
814 return 1;
815 } else {
816 return 0;
817 }
818 }
819 }
820
821 /* feature definition not found */
822 return -1;
823}
824
825static LY_ERR
826lys_compile_iffeature(struct lysc_ctx *ctx, const char *value, int UNUSED(options), struct lysc_iffeature *iff, struct lysc_feature *parent)
827{
828 const char *c = value;
829 int r, rc = EXIT_FAILURE;
830 int i, j, last_not, checkversion = 0;
831 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
832 uint8_t op;
833 struct iff_stack stack = {0, 0, NULL};
834 struct lysc_feature *f, **df;
835
836 assert(c);
837
838 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
839 for (i = j = last_not = 0; c[i]; i++) {
840 if (c[i] == '(') {
841 j++;
842 checkversion = 1;
843 continue;
844 } else if (c[i] == ')') {
845 j--;
846 continue;
847 } else if (isspace(c[i])) {
848 checkversion = 1;
849 continue;
850 }
851
852 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
853 if (c[i + r] == '\0') {
854 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
855 "Invalid value \"%s\" of if-feature - unexpected end of expression.", value);
856 return LY_EVALID;
857 } else if (!isspace(c[i + r])) {
858 /* feature name starting with the not/and/or */
859 last_not = 0;
860 f_size++;
861 } else if (c[i] == 'n') { /* not operation */
862 if (last_not) {
863 /* double not */
864 expr_size = expr_size - 2;
865 last_not = 0;
866 } else {
867 last_not = 1;
868 }
869 } else { /* and, or */
870 f_exp++;
871 /* not a not operation */
872 last_not = 0;
873 }
874 i += r;
875 } else {
876 f_size++;
877 last_not = 0;
878 }
879 expr_size++;
880
881 while (!isspace(c[i])) {
882 if (!c[i] || c[i] == ')') {
883 i--;
884 break;
885 }
886 i++;
887 }
888 }
889 if (j || f_exp != f_size) {
890 /* not matching count of ( and ) */
891 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
892 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", value);
893 return LY_EVALID;
894 }
895
896 if (checkversion || expr_size > 1) {
897 /* check that we have 1.1 module */
898 if (ctx->mod->version != LYS_VERSION_1_1) {
899 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
900 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", value);
901 return LY_EVALID;
902 }
903 }
904
905 /* allocate the memory */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200906 LY_ARRAY_CREATE_RET(ctx->mod->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200907 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +0200908 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200909 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->mod->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +0200910
Radek Krejci151a5b72018-10-19 14:21:44 +0200911 stack.size = expr_size;
912 f_size--; expr_size--; /* used as indexes from now */
913
914 for (i--; i >= 0; i--) {
915 if (c[i] == ')') {
916 /* push it on stack */
917 iff_stack_push(&stack, LYS_IFF_RP);
918 continue;
919 } else if (c[i] == '(') {
920 /* pop from the stack into result all operators until ) */
921 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
922 iff_setop(iff->expr, op, expr_size--);
923 }
924 continue;
925 } else if (isspace(c[i])) {
926 continue;
927 }
928
929 /* end of operator or operand -> find beginning and get what is it */
930 j = i + 1;
931 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
932 i--;
933 }
934 i++; /* go back by one step */
935
936 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
937 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
938 /* double not */
939 iff_stack_pop(&stack);
940 } else {
941 /* not has the highest priority, so do not pop from the stack
942 * as in case of AND and OR */
943 iff_stack_push(&stack, LYS_IFF_NOT);
944 }
945 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
946 /* as for OR - pop from the stack all operators with the same or higher
947 * priority and store them to the result, then push the AND to the stack */
948 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
949 op = iff_stack_pop(&stack);
950 iff_setop(iff->expr, op, expr_size--);
951 }
952 iff_stack_push(&stack, LYS_IFF_AND);
953 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
954 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
955 op = iff_stack_pop(&stack);
956 iff_setop(iff->expr, op, expr_size--);
957 }
958 iff_stack_push(&stack, LYS_IFF_OR);
959 } else {
960 /* feature name, length is j - i */
961
962 /* add it to the expression */
963 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
964
965 /* now get the link to the feature definition */
966 f = lysc_feature_find(ctx->mod, &c[i], j - i);
967 LY_CHECK_ERR_GOTO(!f,
968 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
969 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", value, j - i, &c[i]);
970 rc = LY_EINVAL,
971 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +0200972 iff->features[f_size] = f;
973 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200974 if (parent) {
975 /* and add itself into the dependants list */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200976 LY_ARRAY_NEW_RET(ctx->mod->ctx, f->depfeatures, df, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200977 *df = parent;
978
979 /* TODO check for circular dependency */
980 }
981 f_size--;
982 }
983 }
984 while (stack.index) {
985 op = iff_stack_pop(&stack);
986 iff_setop(iff->expr, op, expr_size--);
987 }
988
989 if (++expr_size || ++f_size) {
990 /* not all expected operators and operands found */
991 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
992 "Invalid value \"%s\" of if-feature - processing error.", value);
993 rc = LY_EINT;
994 } else {
995 rc = LY_SUCCESS;
996 }
997
998error:
999 /* cleanup */
1000 iff_stack_clean(&stack);
1001
1002 return rc;
1003}
1004
1005static LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001006lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
1007{
1008 struct lys_module *mod;
1009 struct lysc_module *comp;
1010
1011 if (options & LYSC_OPT_FREE_SP) {
1012 /* just switch the pointers */
1013 imp->prefix = imp_p->prefix;
1014 } else {
1015 /* keep refcounts correct for lysp_module_free() */
1016 imp->prefix = lydict_insert(ctx->mod->ctx, imp_p->prefix, 0);
1017 }
1018 imp->module = imp_p->module;
1019
1020 /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
1021 * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
1022 if (!imp->module->parsed) {
1023 comp = imp->module->compiled;
1024 /* try to get filepath from the compiled version */
1025 if (comp->filepath) {
1026 mod = (struct lys_module*)lys_parse_path(ctx->mod->ctx, comp->filepath,
1027 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
1028 if (mod != imp->module) {
1029 LOGERR(ctx->mod->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
1030 comp->filepath, comp->name);
1031 mod = NULL;
1032 }
1033 }
1034 if (!mod) {
1035 if (lysp_load_module(ctx->mod->ctx, comp->name, comp->revs ? comp->revs[0].date : NULL, 0, 1, &mod)) {
1036 LOGERR(ctx->mod->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
1037 comp->name, ctx->mod->name);
1038 return LY_ENOTFOUND;
1039 }
1040 }
1041 } else if (!imp->module->compiled) {
1042 return lys_compile(imp->module->parsed, options, &imp->module->compiled);
1043 }
1044
1045 return LY_SUCCESS;
1046}
1047
1048static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +02001049lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
1050{
Radek Krejci86d106e2018-10-18 09:53:19 +02001051 unsigned int u;
1052 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001053
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001054 if (options & LYSC_OPT_FREE_SP) {
1055 /* just switch the pointers */
1056 feature->name = feature_p->name;
1057 } else {
1058 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001059 feature->name = lydict_insert(ctx->mod->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001060 }
1061 feature->flags = feature_p->flags;
1062
Radek Krejci151a5b72018-10-19 14:21:44 +02001063 if (feature_p->iffeatures) {
1064 /* allocate everything now */
Radek Krejci2c4e7172018-10-19 15:56:26 +02001065 LY_ARRAY_CREATE_RET(ctx->mod->ctx, feature->iffeatures, LY_ARRAY_SIZE(feature_p->iffeatures), LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +02001066
1067 for (u = 0; u < LY_ARRAY_SIZE(feature_p->iffeatures); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +02001068 ret = lys_compile_iffeature(ctx, feature_p->iffeatures[u], options, &feature->iffeatures[u], feature);
Radek Krejci151a5b72018-10-19 14:21:44 +02001069 LY_CHECK_RET(ret);
Radek Krejci2c4e7172018-10-19 15:56:26 +02001070 LY_ARRAY_INCREMENT(feature->iffeatures);
Radek Krejci151a5b72018-10-19 14:21:44 +02001071 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001072 }
1073
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001074 return LY_SUCCESS;
1075}
1076
1077LY_ERR
1078lys_compile(struct lysp_module *sp, int options, struct lysc_module **sc)
1079{
Radek Krejci86d106e2018-10-18 09:53:19 +02001080 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001081 struct lysc_module *mod_c;
Radek Krejci151a5b72018-10-19 14:21:44 +02001082 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001083 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001084
1085 LY_CHECK_ARG_RET(NULL, sc, sp, sp->ctx, LY_EINVAL);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001086
1087 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001088 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 +02001089 return LY_EINVAL;
1090 }
1091
Radek Krejci86d106e2018-10-18 09:53:19 +02001092 ctx.mod = mod_c = calloc(1, sizeof *mod_c);
1093 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1094 mod_c->ctx = sp->ctx;
1095 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001096
1097 if (options & LYSC_OPT_FREE_SP) {
1098 /* just switch the pointers */
1099 mod_c->name = sp->name;
1100 mod_c->ns = sp->ns;
1101 mod_c->prefix = sp->prefix;
1102 } else {
1103 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001104 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1105 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1106 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001107 }
1108
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001109 COMPILE_ARRAY_GOTO(ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
1110 COMPILE_ARRAY_GOTO(ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001111
1112 if (options & LYSC_OPT_FREE_SP) {
1113 lysp_module_free_(sp, 0);
1114 }
1115
1116 (*sc) = mod_c;
1117 return LY_SUCCESS;
1118
1119error:
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001120 lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001121
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001122 return ret;
1123}
Radek Krejci86d106e2018-10-18 09:53:19 +02001124
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001125static void
Radek Krejci086c7132018-10-26 15:29:04 +02001126lys_latest_switch(struct lys_module *old, struct lysp_module *new)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001127{
Radek Krejci086c7132018-10-26 15:29:04 +02001128 if (old->parsed) {
1129 new->latest_revision = old->parsed->latest_revision;
1130 old->parsed->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001131 }
Radek Krejci086c7132018-10-26 15:29:04 +02001132 if (old->compiled) {
1133 new->latest_revision = old->parsed->latest_revision;
1134 old->compiled->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001135 }
1136}
1137
Radek Krejcid33273d2018-10-25 14:55:52 +02001138struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001139lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
1140{
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001141 struct lys_module *mod = NULL, *latest, *mod_dup;
Radek Krejcid33273d2018-10-25 14:55:52 +02001142 struct lysp_module *latest_p;
Radek Krejci086c7132018-10-26 15:29:04 +02001143 struct lysp_import *imp;
1144 struct lysp_include *inc;
Radek Krejci86d106e2018-10-18 09:53:19 +02001145 LY_ERR ret;
Radek Krejci086c7132018-10-26 15:29:04 +02001146 unsigned int u, i;
Radek Krejci86d106e2018-10-18 09:53:19 +02001147
1148 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1149
1150 mod = calloc(1, sizeof *mod);
1151 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1152
1153 switch (format) {
1154 case LYS_IN_YIN:
1155 /* TODO not yet supported
1156 mod = yin_read_module(ctx, data, revision, implement);
1157 */
1158 break;
1159 case LYS_IN_YANG:
1160 ret = yang_parse(ctx, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001161 break;
1162 default:
1163 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1164 break;
1165 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001166 LY_CHECK_RET(ret, NULL);
1167
1168 /* make sure that the newest revision is at position 0 */
1169 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001170
1171 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001172 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001173 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1174 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
1175 lys_module_free(mod, NULL);
1176 return NULL;
1177 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001178 mod->parsed->implemented = 1;
1179 }
1180
1181 if (revision) {
1182 /* check revision of the parsed model */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001183 if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].date)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001184 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
Radek Krejcib7db73a2018-10-24 14:18:40 +02001185 mod->parsed->name, mod->parsed->revs[0].date, revision);
1186 lys_module_free(mod, NULL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001187 return NULL;
1188 }
1189 }
1190
Radek Krejcid33273d2018-10-25 14:55:52 +02001191 if (mod->parsed->submodule) { /* submodule */
1192 /* decide the latest revision */
1193 latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
1194 if (latest_p) {
1195 if (mod->parsed->revs) {
1196 if (!latest_p->revs) {
1197 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001198 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001199 latest_p->latest_revision = 0;
1200 } else {
1201 if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
Radek Krejci086c7132018-10-26 15:29:04 +02001202 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001203 latest_p->latest_revision = 0;
1204 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001205 }
1206 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001207 } else {
Radek Krejci086c7132018-10-26 15:29:04 +02001208 mod->parsed->latest_revision = revision ? 1 : 2;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001209 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001210 } else { /* module */
1211 /* check for duplicity in the context */
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001212 mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
1213 if (mod_dup) {
1214 if (mod_dup->parsed) {
1215 /* error */
1216 if (mod->parsed->revs) {
1217 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1218 mod->parsed->name, mod->parsed->revs[0].date);
1219 } else {
1220 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1221 mod->parsed->name);
1222 }
1223 lys_module_free(mod, NULL);
1224 return NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +02001225 } else {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001226 /* add the parsed data to the currently compiled-only module in the context */
1227 mod_dup->parsed = mod->parsed;
1228 free(mod);
1229 mod = mod_dup;
1230 goto finish_parsing;
Radek Krejcid33273d2018-10-25 14:55:52 +02001231 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001232 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001233
1234#if 0
1235 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1236 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1237 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1238 * the anotation definitions available in the internal schema structure. There is another hack in schema
1239 * printers to do not print this internally added annotation. */
1240 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1241 if (lyp_add_ietf_netconf_annotations(mod)) {
1242 lys_free(mod, NULL, 1, 1);
1243 return NULL;
1244 }
1245 }
1246#endif
1247
Radek Krejcid33273d2018-10-25 14:55:52 +02001248 /* decide the latest revision */
1249 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1250 if (latest) {
1251 if (mod->parsed->revs) {
1252 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revs)) {
1253 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001254 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001255 } else {
1256 if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revs[0].date) > 0) {
Radek Krejci086c7132018-10-26 15:29:04 +02001257 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001258 }
1259 }
1260 }
1261 } else {
1262 mod->parsed->latest_revision = 1;
1263 }
1264
1265 /* add into context */
1266 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1267
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001268finish_parsing:
Radek Krejci086c7132018-10-26 15:29:04 +02001269 /* resolve imports and includes */
1270 mod->parsed->parsing = 1;
1271 LY_ARRAY_FOR(mod->parsed->imports, u) {
1272 imp = &mod->parsed->imports[u];
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001273 if (!imp->module && lysp_load_module(ctx, imp->name, imp->rev[0] ? imp->rev : NULL, 0, 0, &imp->module)) {
Radek Krejci086c7132018-10-26 15:29:04 +02001274 ly_set_rm(&ctx->list, mod, NULL);
1275 lys_module_free(mod, NULL);
1276 return NULL;
1277 }
1278 /* check for importing the same module twice */
1279 for (i = 0; i < u; ++i) {
1280 if (imp->module == mod->parsed->imports[i].module) {
1281 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
1282 ly_set_rm(&ctx->list, mod, NULL);
1283 lys_module_free(mod, NULL);
1284 return NULL;
1285 }
1286 }
1287 }
1288 LY_ARRAY_FOR(mod->parsed->includes, u) {
1289 inc = &mod->parsed->includes[u];
1290 if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
1291 ly_set_rm(&ctx->list, mod, NULL);
1292 lys_module_free(mod, NULL);
1293 return NULL;
1294 }
1295 }
1296 mod->parsed->parsing = 0;
Radek Krejcid33273d2018-10-25 14:55:52 +02001297 }
1298
Radek Krejci86d106e2018-10-18 09:53:19 +02001299 return mod;
1300}
1301
1302API const struct lys_module *
1303lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1304{
Radek Krejcid33273d2018-10-25 14:55:52 +02001305 struct lys_module *result;
1306
1307 result = lys_parse_mem_(ctx, data, format, NULL, 1);
1308 if (result && result->parsed->submodule) {
1309 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1310 result->parsed->name);
1311 lys_module_free(result, NULL);
1312 return NULL;
1313 }
1314 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001315}
1316
1317static void
1318lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1319{
1320#ifdef __APPLE__
1321 char path[MAXPATHLEN];
1322#else
1323 int len;
1324 char path[PATH_MAX], proc_path[32];
1325#endif
1326
1327#ifdef __APPLE__
1328 if (fcntl(fd, F_GETPATH, path) != -1) {
1329 *filename = lydict_insert(ctx, path, 0);
1330 }
1331#else
1332 /* get URI if there is /proc */
1333 sprintf(proc_path, "/proc/self/fd/%d", fd);
1334 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1335 *filename = lydict_insert(ctx, path, len);
1336 }
1337#endif
1338}
1339
Radek Krejcid33273d2018-10-25 14:55:52 +02001340struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001341lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const char *revision, int implement)
1342{
Radek Krejcid33273d2018-10-25 14:55:52 +02001343 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001344 size_t length;
1345 char *addr;
1346
1347 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1348 if (fd < 0) {
1349 LOGARG(ctx, fd);
1350 return NULL;
1351 }
1352
1353 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1354 if (!addr) {
1355 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1356 return NULL;
1357 }
1358
1359 mod = lys_parse_mem_(ctx, addr, format, revision, implement);
1360 ly_munmap(addr, length);
1361
1362 if (mod && !mod->parsed->filepath) {
1363 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1364 }
1365
1366 return mod;
1367}
1368
1369API const struct lys_module *
1370lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1371{
Radek Krejcid33273d2018-10-25 14:55:52 +02001372 struct lys_module *result;
1373
1374 result = lys_parse_fd_(ctx, fd, format, NULL, 1);
1375 if (result && result->parsed->submodule) {
1376 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1377 result->parsed->name);
1378 lys_module_free(result, NULL);
1379 return NULL;
1380 }
1381 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001382}
1383
Radek Krejcid33273d2018-10-25 14:55:52 +02001384struct lys_module *
1385lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const char *revision, int implement)
Radek Krejci86d106e2018-10-18 09:53:19 +02001386{
1387 int fd;
Radek Krejcid33273d2018-10-25 14:55:52 +02001388 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001389 const char *rev, *dot, *filename;
1390 size_t len;
1391
1392 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1393
1394 fd = open(path, O_RDONLY);
1395 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1396
Radek Krejcid33273d2018-10-25 14:55:52 +02001397 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
Radek Krejci86d106e2018-10-18 09:53:19 +02001398 close(fd);
1399 LY_CHECK_RET(!mod, NULL);
1400
1401 /* check that name and revision match filename */
1402 filename = strrchr(path, '/');
1403 if (!filename) {
1404 filename = path;
1405 } else {
1406 filename++;
1407 }
1408 rev = strchr(filename, '@');
1409 dot = strrchr(filename, '.');
1410
1411 /* name */
1412 len = strlen(mod->parsed->name);
1413 if (strncmp(filename, mod->parsed->name, len) ||
1414 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1415 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1416 }
1417 if (rev) {
1418 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001419 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001420 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001421 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001422 }
1423 }
1424
1425 if (!mod->parsed->filepath) {
1426 /* store URI */
1427 char rpath[PATH_MAX];
1428 if (realpath(path, rpath) != NULL) {
1429 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1430 } else {
1431 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1432 }
1433 }
1434
1435 return mod;
1436}
1437
Radek Krejcid33273d2018-10-25 14:55:52 +02001438API const struct lys_module *
1439lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1440{
1441 struct lys_module *result;
1442
1443 result = lys_parse_path_(ctx, path, format, NULL, 1);
1444 if (result && result->parsed->submodule) {
1445 LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
1446 path, result->parsed->name);
1447 lys_module_free(result, NULL);
1448 return NULL;
1449 }
1450 return result;
1451}
1452
1453API LY_ERR
1454lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
1455 char **localfile, LYS_INFORMAT *format)
1456{
1457 size_t len, flen, match_len = 0, dir_len;
1458 int i, implicit_cwd = 0, ret = EXIT_FAILURE;
1459 char *wd, *wn = NULL;
1460 DIR *dir = NULL;
1461 struct dirent *file;
1462 char *match_name = NULL;
1463 LYS_INFORMAT format_aux, match_format = 0;
1464 struct ly_set *dirs;
1465 struct stat st;
1466
1467 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1468
1469 /* start to fill the dir fifo with the context's search path (if set)
1470 * and the current working directory */
1471 dirs = ly_set_new();
1472 if (!dirs) {
1473 LOGMEM(NULL);
1474 return EXIT_FAILURE;
1475 }
1476
1477 len = strlen(name);
1478 if (cwd) {
1479 wd = get_current_dir_name();
1480 if (!wd) {
1481 LOGMEM(NULL);
1482 goto cleanup;
1483 } else {
1484 /* add implicit current working directory (./) to be searched,
1485 * this directory is not searched recursively */
1486 if (ly_set_add(dirs, wd, 0) == -1) {
1487 goto cleanup;
1488 }
1489 implicit_cwd = 1;
1490 }
1491 }
1492 if (searchpaths) {
1493 for (i = 0; searchpaths[i]; i++) {
1494 /* check for duplicities with the implicit current working directory */
1495 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1496 implicit_cwd = 0;
1497 continue;
1498 }
1499 wd = strdup(searchpaths[i]);
1500 if (!wd) {
1501 LOGMEM(NULL);
1502 goto cleanup;
1503 } else if (ly_set_add(dirs, wd, 0) == -1) {
1504 goto cleanup;
1505 }
1506 }
1507 }
1508 wd = NULL;
1509
1510 /* start searching */
1511 while (dirs->count) {
1512 free(wd);
1513 free(wn); wn = NULL;
1514
1515 dirs->count--;
1516 wd = (char *)dirs->objs[dirs->count];
1517 dirs->objs[dirs->count] = NULL;
1518 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1519
1520 if (dir) {
1521 closedir(dir);
1522 }
1523 dir = opendir(wd);
1524 dir_len = strlen(wd);
1525 if (!dir) {
1526 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1527 } else {
1528 while ((file = readdir(dir))) {
1529 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1530 /* skip . and .. */
1531 continue;
1532 }
1533 free(wn);
1534 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1535 LOGMEM(NULL);
1536 goto cleanup;
1537 }
1538 if (stat(wn, &st) == -1) {
1539 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1540 file->d_name, wd, strerror(errno));
1541 continue;
1542 }
1543 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1544 /* we have another subdirectory in searchpath to explore,
1545 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1546 if (ly_set_add(dirs, wn, 0) == -1) {
1547 goto cleanup;
1548 }
1549 /* continue with the next item in current directory */
1550 wn = NULL;
1551 continue;
1552 } else if (!S_ISREG(st.st_mode)) {
1553 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1554 continue;
1555 }
1556
1557 /* here we know that the item is a file which can contain a module */
1558 if (strncmp(name, file->d_name, len) ||
1559 (file->d_name[len] != '.' && file->d_name[len] != '@')) {
1560 /* different filename than the module we search for */
1561 continue;
1562 }
1563
1564 /* get type according to filename suffix */
1565 flen = strlen(file->d_name);
1566 if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1567 format_aux = LYS_IN_YIN;
1568 } else if (!strcmp(&file->d_name[flen - 5], ".yang")) {
1569 format_aux = LYS_IN_YANG;
1570 } else {
1571 /* not supportde suffix/file format */
1572 continue;
1573 }
1574
1575 if (revision) {
1576 /* we look for the specific revision, try to get it from the filename */
1577 if (file->d_name[len] == '@') {
1578 /* check revision from the filename */
1579 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1580 /* another revision */
1581 continue;
1582 } else {
1583 /* exact revision */
1584 free(match_name);
1585 match_name = wn;
1586 wn = NULL;
1587 match_len = dir_len + 1 + len;
1588 match_format = format_aux;
1589 goto success;
1590 }
1591 } else {
1592 /* continue trying to find exact revision match, use this only if not found */
1593 free(match_name);
1594 match_name = wn;
1595 wn = NULL;
1596 match_len = dir_len + 1 +len;
1597 match_format = format_aux;
1598 continue;
1599 }
1600 } else {
1601 /* remember the revision and try to find the newest one */
1602 if (match_name) {
1603 if (file->d_name[len] != '@' ||
1604 lysp_check_date(NULL, &file->d_name[len + 1], flen - (format_aux == LYS_IN_YANG ? 5 : 4) - len - 1, NULL)) {
1605 continue;
1606 } else if (match_name[match_len] == '@' &&
1607 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1608 continue;
1609 }
1610 free(match_name);
1611 }
1612
1613 match_name = wn;
1614 wn = NULL;
1615 match_len = dir_len + 1 + len;
1616 match_format = format_aux;
1617 continue;
1618 }
1619 }
1620 }
1621 }
1622
1623success:
1624 (*localfile) = match_name;
1625 match_name = NULL;
1626 if (format) {
1627 (*format) = match_format;
1628 }
1629 ret = EXIT_SUCCESS;
1630
1631cleanup:
1632 free(wn);
1633 free(wd);
1634 if (dir) {
1635 closedir(dir);
1636 }
1637 free(match_name);
1638 ly_set_free(dirs, free);
1639
1640 return ret;
1641}
1642
1643LY_ERR
1644lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement,
1645 struct lys_module **result)
1646{
1647 size_t len;
1648 int fd;
1649 char *filepath = NULL, *dot, *rev, *filename;
1650 LYS_INFORMAT format;
1651 struct lys_module *mod = NULL;
1652 LY_ERR ret = LY_SUCCESS;
1653
1654 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
1655 &filepath, &format));
1656 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
1657 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
1658
1659
1660 LOGVRB("Loading schema from \"%s\" file.", filepath);
1661
1662 /* open the file */
1663 fd = open(filepath, O_RDONLY);
1664 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
1665 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
1666
1667 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
1668 close(fd);
1669 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
1670
1671 /* check that name and revision match filename */
1672 filename = strrchr(filepath, '/');
1673 if (!filename) {
1674 filename = filepath;
1675 } else {
1676 filename++;
1677 }
1678 /* name */
1679 len = strlen(mod->parsed->name);
1680 rev = strchr(filename, '@');
1681 dot = strrchr(filepath, '.');
1682 if (strncmp(filename, mod->parsed->name, len) ||
1683 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1684 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1685 }
1686 /* revision */
1687 if (rev) {
1688 len = dot - ++rev;
1689 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
1690 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
1691 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
1692 }
1693 }
1694
1695 if (!mod->parsed->filepath) {
1696 char rpath[PATH_MAX];
1697 if (realpath(filepath, rpath) != NULL) {
1698 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1699 } else {
1700 mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
1701 }
1702 }
1703
1704 *result = mod;
1705
1706 /* success */
1707cleanup:
1708 free(filepath);
1709 return ret;
1710}