blob: 874ca015c3d8d5c5dc3f9089f68c380324a3da36 [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 Krejcice8c1592018-10-29 15:35:51 +010039 LY_ARRAY_CREATE_GOTO((CTX)->mod->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 Krejcice8c1592018-10-29 15:35:51 +010041 RET = FUNC(CTX, &(ARRAY_P)[ITER], OPTIONS, &(ARRAY_C)[ITER]); \
Radek Krejci6d6e4e42018-10-29 13:28:19 +010042 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 */
Radek Krejcice8c1592018-10-29 15:35:51 +0100599 mod = lysc_module_find_prefix(mod, name, i)->compiled;
Radek Krejci151a5b72018-10-19 14:21:44 +0200600 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
Radek Krejcice8c1592018-10-29 15:35:51 +0100826lys_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 +0200827{
Radek Krejcice8c1592018-10-29 15:35:51 +0100828 const char *name;
829 unsigned int u;
830 const struct lys_module *mod;
831 struct lysp_ext *edef;
832
833 if (options & LYSC_OPT_FREE_SP) {
834 /* just switch the pointers */
835 ext->argument = ext_p->argument;
836 } else {
837 /* keep refcounts correct for lysp_module_free() */
838 ext->argument = lydict_insert(ctx->mod->ctx, ext_p->argument, 0);
839 }
840 ext->insubstmt = ext_p->insubstmt;
841 ext->insubstmt_index = ext_p->insubstmt_index;
842
843 /* get module where the extension definition should be placed */
844 for (u = 0; ext_p->name[u] != ':'; ++u);
845 mod = lysc_module_find_prefix(ctx->mod, ext_p->name, u);
846 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
847 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, ext_p->name),
848 LY_EVALID);
849 LY_CHECK_ERR_RET(!mod->parsed->extensions,
850 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
851 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
852 ext_p->name, mod->parsed->name),
853 LY_EVALID);
854 name = &ext_p->name[u + 1];
855 /* find the extension definition there */
856 for (ext = NULL, u = 0; u < LY_ARRAY_SIZE(mod->parsed->extensions); ++u) {
857 if (!strcmp(name, mod->parsed->extensions[u].name)) {
858 edef = &mod->parsed->extensions[u];
859 break;
860 }
861 }
862 LY_CHECK_ERR_RET(!edef, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
863 "Extension definition of extension instance \"%s\" not found.", ext_p->name),
864 LY_EVALID);
865 /* TODO plugins */
866
867 return LY_SUCCESS;
868}
869
870/**
871 * @param[in] parent Provided only in case the if-feature is inside
872 */
873static LY_ERR
874lys_compile_iffeature(struct lysc_ctx *ctx, const char **value, int UNUSED(options), struct lysc_iffeature *iff)
875{
876 const char *c = *value;
Radek Krejci151a5b72018-10-19 14:21:44 +0200877 int r, rc = EXIT_FAILURE;
878 int i, j, last_not, checkversion = 0;
879 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
880 uint8_t op;
881 struct iff_stack stack = {0, 0, NULL};
Radek Krejcice8c1592018-10-29 15:35:51 +0100882 struct lysc_feature *f;
Radek Krejci151a5b72018-10-19 14:21:44 +0200883
884 assert(c);
885
886 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
887 for (i = j = last_not = 0; c[i]; i++) {
888 if (c[i] == '(') {
889 j++;
890 checkversion = 1;
891 continue;
892 } else if (c[i] == ')') {
893 j--;
894 continue;
895 } else if (isspace(c[i])) {
896 checkversion = 1;
897 continue;
898 }
899
900 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
901 if (c[i + r] == '\0') {
902 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100903 "Invalid value \"%s\" of if-feature - unexpected end of expression.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200904 return LY_EVALID;
905 } else if (!isspace(c[i + r])) {
906 /* feature name starting with the not/and/or */
907 last_not = 0;
908 f_size++;
909 } else if (c[i] == 'n') { /* not operation */
910 if (last_not) {
911 /* double not */
912 expr_size = expr_size - 2;
913 last_not = 0;
914 } else {
915 last_not = 1;
916 }
917 } else { /* and, or */
918 f_exp++;
919 /* not a not operation */
920 last_not = 0;
921 }
922 i += r;
923 } else {
924 f_size++;
925 last_not = 0;
926 }
927 expr_size++;
928
929 while (!isspace(c[i])) {
930 if (!c[i] || c[i] == ')') {
931 i--;
932 break;
933 }
934 i++;
935 }
936 }
937 if (j || f_exp != f_size) {
938 /* not matching count of ( and ) */
939 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100940 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200941 return LY_EVALID;
942 }
943
944 if (checkversion || expr_size > 1) {
945 /* check that we have 1.1 module */
946 if (ctx->mod->version != LYS_VERSION_1_1) {
947 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100948 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200949 return LY_EVALID;
950 }
951 }
952
953 /* allocate the memory */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200954 LY_ARRAY_CREATE_RET(ctx->mod->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200955 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +0200956 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200957 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->mod->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +0200958
Radek Krejci151a5b72018-10-19 14:21:44 +0200959 stack.size = expr_size;
960 f_size--; expr_size--; /* used as indexes from now */
961
962 for (i--; i >= 0; i--) {
963 if (c[i] == ')') {
964 /* push it on stack */
965 iff_stack_push(&stack, LYS_IFF_RP);
966 continue;
967 } else if (c[i] == '(') {
968 /* pop from the stack into result all operators until ) */
969 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
970 iff_setop(iff->expr, op, expr_size--);
971 }
972 continue;
973 } else if (isspace(c[i])) {
974 continue;
975 }
976
977 /* end of operator or operand -> find beginning and get what is it */
978 j = i + 1;
979 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
980 i--;
981 }
982 i++; /* go back by one step */
983
984 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
985 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
986 /* double not */
987 iff_stack_pop(&stack);
988 } else {
989 /* not has the highest priority, so do not pop from the stack
990 * as in case of AND and OR */
991 iff_stack_push(&stack, LYS_IFF_NOT);
992 }
993 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
994 /* as for OR - pop from the stack all operators with the same or higher
995 * priority and store them to the result, then push the AND to the stack */
996 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
997 op = iff_stack_pop(&stack);
998 iff_setop(iff->expr, op, expr_size--);
999 }
1000 iff_stack_push(&stack, LYS_IFF_AND);
1001 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
1002 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1003 op = iff_stack_pop(&stack);
1004 iff_setop(iff->expr, op, expr_size--);
1005 }
1006 iff_stack_push(&stack, LYS_IFF_OR);
1007 } else {
1008 /* feature name, length is j - i */
1009
1010 /* add it to the expression */
1011 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
1012
1013 /* now get the link to the feature definition */
1014 f = lysc_feature_find(ctx->mod, &c[i], j - i);
1015 LY_CHECK_ERR_GOTO(!f,
1016 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001017 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
Radek Krejci151a5b72018-10-19 14:21:44 +02001018 rc = LY_EINVAL,
1019 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +02001020 iff->features[f_size] = f;
1021 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +02001022 f_size--;
1023 }
1024 }
1025 while (stack.index) {
1026 op = iff_stack_pop(&stack);
1027 iff_setop(iff->expr, op, expr_size--);
1028 }
1029
1030 if (++expr_size || ++f_size) {
1031 /* not all expected operators and operands found */
1032 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001033 "Invalid value \"%s\" of if-feature - processing error.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001034 rc = LY_EINT;
1035 } else {
1036 rc = LY_SUCCESS;
1037 }
1038
1039error:
1040 /* cleanup */
1041 iff_stack_clean(&stack);
1042
1043 return rc;
1044}
1045
1046static LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001047lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
1048{
Radek Krejcice8c1592018-10-29 15:35:51 +01001049 unsigned int u;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001050 struct lys_module *mod;
1051 struct lysc_module *comp;
Radek Krejcice8c1592018-10-29 15:35:51 +01001052 LY_ERR ret = LY_SUCCESS;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001053
1054 if (options & LYSC_OPT_FREE_SP) {
1055 /* just switch the pointers */
1056 imp->prefix = imp_p->prefix;
1057 } else {
1058 /* keep refcounts correct for lysp_module_free() */
1059 imp->prefix = lydict_insert(ctx->mod->ctx, imp_p->prefix, 0);
1060 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001061 COMPILE_ARRAY_GOTO(ctx, imp_p->exts, imp->exts, options, u, lys_compile_ext, ret, done);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001062 imp->module = imp_p->module;
1063
1064 /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
1065 * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
1066 if (!imp->module->parsed) {
1067 comp = imp->module->compiled;
1068 /* try to get filepath from the compiled version */
1069 if (comp->filepath) {
1070 mod = (struct lys_module*)lys_parse_path(ctx->mod->ctx, comp->filepath,
1071 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
1072 if (mod != imp->module) {
1073 LOGERR(ctx->mod->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
1074 comp->filepath, comp->name);
1075 mod = NULL;
1076 }
1077 }
1078 if (!mod) {
1079 if (lysp_load_module(ctx->mod->ctx, comp->name, comp->revs ? comp->revs[0].date : NULL, 0, 1, &mod)) {
1080 LOGERR(ctx->mod->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
1081 comp->name, ctx->mod->name);
1082 return LY_ENOTFOUND;
1083 }
1084 }
1085 } else if (!imp->module->compiled) {
1086 return lys_compile(imp->module->parsed, options, &imp->module->compiled);
1087 }
1088
Radek Krejcice8c1592018-10-29 15:35:51 +01001089done:
1090 return ret;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001091}
1092
1093static LY_ERR
Radek Krejci2a408df2018-10-29 16:32:26 +01001094lys_compile_identity(struct lysc_ctx *ctx, struct lysp_ident *ident_p, int options, struct lysc_ident *ident)
1095{
1096 unsigned int u;
1097 LY_ERR ret = LY_SUCCESS;
1098
1099 if (options & LYSC_OPT_FREE_SP) {
1100 /* just switch the pointers */
1101 ident->name = ident_p->name;
1102 } else {
1103 /* keep refcounts correct for lysp_module_free() */
1104 ident->name = lydict_insert(ctx->mod->ctx, ident_p->name, 0);
1105 }
1106 COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, options, u, lys_compile_iffeature, ret, done);
1107 /* backlings (derived) can be added no sooner than when all the identities in the current module are present */
1108 COMPILE_ARRAY_GOTO(ctx, ident_p->exts, ident->exts, options, u, lys_compile_ext, ret, done);
1109 ident->flags = ident_p->flags;
1110
1111done:
1112 return ret;
1113}
1114
1115static LY_ERR
1116lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1117{
1118 unsigned int i, u, v;
1119 const char *s, *name;
1120 struct lysc_module *mod;
1121 struct lysc_ident **dident;
1122
1123 for (i = 0; i < LY_ARRAY_SIZE(idents_p); ++i) {
1124 for (u = 0; u < LY_ARRAY_SIZE(idents_p[i].bases); ++u) {
1125 s = strchr(idents_p[i].bases[u], ':');
1126 if (s) {
1127 /* prefixed identity */
1128 name = &s[1];
1129 mod = lysc_module_find_prefix(ctx->mod, idents_p[i].bases[u], s - idents_p[i].bases[u])->compiled;
1130 } else {
1131 name = idents_p[i].bases[u];
1132 mod = ctx->mod;
1133 }
1134 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1135 "Invalid prefix used for base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1136 LY_EVALID);
1137 if (mod->identities) {
1138 for (v = 0; v < LY_ARRAY_SIZE(mod->identities); ++v) {
1139 if (!strcmp(name, mod->identities[v].name)) {
1140 /* we have match! store the backlink */
1141 LY_ARRAY_NEW_RET(ctx->mod->ctx, mod->identities[v].derived, dident, LY_EMEM);
1142 *dident = &idents[i];
1143 break;
1144 }
1145 }
1146 }
1147 LY_CHECK_ERR_RET(!dident, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1148 "Unable to find base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1149 LY_EVALID);
1150 }
1151 }
1152 return LY_SUCCESS;
1153}
1154
1155static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +02001156lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
1157{
Radek Krejcice8c1592018-10-29 15:35:51 +01001158 unsigned int u, v;
1159 LY_ERR ret = LY_SUCCESS;
1160 struct lysc_feature **df;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001161
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001162 if (options & LYSC_OPT_FREE_SP) {
1163 /* just switch the pointers */
1164 feature->name = feature_p->name;
1165 } else {
1166 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001167 feature->name = lydict_insert(ctx->mod->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001168 }
1169 feature->flags = feature_p->flags;
1170
Radek Krejcice8c1592018-10-29 15:35:51 +01001171 COMPILE_ARRAY_GOTO(ctx, feature_p->exts, feature->exts, options, u, lys_compile_ext, ret, done);
1172 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, options, u, lys_compile_iffeature, ret, done);
1173 if (feature->iffeatures) {
1174 for (u = 0; u < LY_ARRAY_SIZE(feature->iffeatures); ++u) {
1175 if (feature->iffeatures[u].features) {
1176 for (v = 0; v < LY_ARRAY_SIZE(feature->iffeatures[u].features); ++v) {
1177 /* add itself into the dependants list */
1178 LY_ARRAY_NEW_RET(ctx->mod->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
1179 *df = feature;
1180 }
1181 /* TODO check for circular dependency */
1182 }
Radek Krejci151a5b72018-10-19 14:21:44 +02001183 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001184 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001185done:
1186 return ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001187}
1188
1189LY_ERR
1190lys_compile(struct lysp_module *sp, int options, struct lysc_module **sc)
1191{
Radek Krejci86d106e2018-10-18 09:53:19 +02001192 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001193 struct lysc_module *mod_c;
Radek Krejci151a5b72018-10-19 14:21:44 +02001194 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001195 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001196
1197 LY_CHECK_ARG_RET(NULL, sc, sp, sp->ctx, LY_EINVAL);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001198
1199 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001200 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 +02001201 return LY_EINVAL;
1202 }
1203
Radek Krejci86d106e2018-10-18 09:53:19 +02001204 ctx.mod = mod_c = calloc(1, sizeof *mod_c);
1205 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1206 mod_c->ctx = sp->ctx;
1207 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001208
1209 if (options & LYSC_OPT_FREE_SP) {
1210 /* just switch the pointers */
1211 mod_c->name = sp->name;
1212 mod_c->ns = sp->ns;
1213 mod_c->prefix = sp->prefix;
1214 } else {
1215 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001216 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1217 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1218 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001219 }
1220
Radek Krejcice8c1592018-10-29 15:35:51 +01001221 COMPILE_ARRAY_GOTO(&ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
1222 COMPILE_ARRAY_GOTO(&ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
Radek Krejci2a408df2018-10-29 16:32:26 +01001223 COMPILE_ARRAY_GOTO(&ctx, sp->identities, mod_c->identities, options, u, lys_compile_identity, ret, error);
1224 if (sp->identities) {
1225 LY_CHECK_RET(lys_compile_identities_derived(&ctx, sp->identities, mod_c->identities));
1226 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001227
1228 COMPILE_ARRAY_GOTO(&ctx, sp->exts, mod_c->exts, options, u, lys_compile_ext, ret, error);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001229
1230 if (options & LYSC_OPT_FREE_SP) {
1231 lysp_module_free_(sp, 0);
1232 }
1233
1234 (*sc) = mod_c;
1235 return LY_SUCCESS;
1236
1237error:
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001238 lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001239
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001240 return ret;
1241}
Radek Krejci86d106e2018-10-18 09:53:19 +02001242
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001243static void
Radek Krejci086c7132018-10-26 15:29:04 +02001244lys_latest_switch(struct lys_module *old, struct lysp_module *new)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001245{
Radek Krejci086c7132018-10-26 15:29:04 +02001246 if (old->parsed) {
1247 new->latest_revision = old->parsed->latest_revision;
1248 old->parsed->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001249 }
Radek Krejci086c7132018-10-26 15:29:04 +02001250 if (old->compiled) {
1251 new->latest_revision = old->parsed->latest_revision;
1252 old->compiled->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001253 }
1254}
1255
Radek Krejcid33273d2018-10-25 14:55:52 +02001256struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001257lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
1258{
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001259 struct lys_module *mod = NULL, *latest, *mod_dup;
Radek Krejcid33273d2018-10-25 14:55:52 +02001260 struct lysp_module *latest_p;
Radek Krejci086c7132018-10-26 15:29:04 +02001261 struct lysp_import *imp;
1262 struct lysp_include *inc;
Radek Krejci86d106e2018-10-18 09:53:19 +02001263 LY_ERR ret;
Radek Krejci086c7132018-10-26 15:29:04 +02001264 unsigned int u, i;
Radek Krejci86d106e2018-10-18 09:53:19 +02001265
1266 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1267
1268 mod = calloc(1, sizeof *mod);
1269 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1270
1271 switch (format) {
1272 case LYS_IN_YIN:
1273 /* TODO not yet supported
1274 mod = yin_read_module(ctx, data, revision, implement);
1275 */
1276 break;
1277 case LYS_IN_YANG:
1278 ret = yang_parse(ctx, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001279 break;
1280 default:
1281 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1282 break;
1283 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001284 LY_CHECK_RET(ret, NULL);
1285
1286 /* make sure that the newest revision is at position 0 */
1287 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001288
1289 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001290 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001291 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1292 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
1293 lys_module_free(mod, NULL);
1294 return NULL;
1295 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001296 mod->parsed->implemented = 1;
1297 }
1298
1299 if (revision) {
1300 /* check revision of the parsed model */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001301 if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].date)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001302 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
Radek Krejcib7db73a2018-10-24 14:18:40 +02001303 mod->parsed->name, mod->parsed->revs[0].date, revision);
1304 lys_module_free(mod, NULL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001305 return NULL;
1306 }
1307 }
1308
Radek Krejcid33273d2018-10-25 14:55:52 +02001309 if (mod->parsed->submodule) { /* submodule */
1310 /* decide the latest revision */
1311 latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
1312 if (latest_p) {
1313 if (mod->parsed->revs) {
1314 if (!latest_p->revs) {
1315 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001316 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001317 latest_p->latest_revision = 0;
1318 } else {
1319 if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
Radek Krejci086c7132018-10-26 15:29:04 +02001320 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001321 latest_p->latest_revision = 0;
1322 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001323 }
1324 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001325 } else {
Radek Krejci086c7132018-10-26 15:29:04 +02001326 mod->parsed->latest_revision = revision ? 1 : 2;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001327 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001328 } else { /* module */
1329 /* check for duplicity in the context */
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001330 mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
1331 if (mod_dup) {
1332 if (mod_dup->parsed) {
1333 /* error */
1334 if (mod->parsed->revs) {
1335 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1336 mod->parsed->name, mod->parsed->revs[0].date);
1337 } else {
1338 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1339 mod->parsed->name);
1340 }
1341 lys_module_free(mod, NULL);
1342 return NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +02001343 } else {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001344 /* add the parsed data to the currently compiled-only module in the context */
1345 mod_dup->parsed = mod->parsed;
1346 free(mod);
1347 mod = mod_dup;
1348 goto finish_parsing;
Radek Krejcid33273d2018-10-25 14:55:52 +02001349 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001350 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001351
1352#if 0
1353 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1354 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1355 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1356 * the anotation definitions available in the internal schema structure. There is another hack in schema
1357 * printers to do not print this internally added annotation. */
1358 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1359 if (lyp_add_ietf_netconf_annotations(mod)) {
1360 lys_free(mod, NULL, 1, 1);
1361 return NULL;
1362 }
1363 }
1364#endif
1365
Radek Krejcid33273d2018-10-25 14:55:52 +02001366 /* decide the latest revision */
1367 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1368 if (latest) {
1369 if (mod->parsed->revs) {
1370 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revs)) {
1371 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001372 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001373 } else {
1374 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 +02001375 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001376 }
1377 }
1378 }
1379 } else {
1380 mod->parsed->latest_revision = 1;
1381 }
1382
1383 /* add into context */
1384 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1385
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001386finish_parsing:
Radek Krejci086c7132018-10-26 15:29:04 +02001387 /* resolve imports and includes */
1388 mod->parsed->parsing = 1;
1389 LY_ARRAY_FOR(mod->parsed->imports, u) {
1390 imp = &mod->parsed->imports[u];
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001391 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 +02001392 ly_set_rm(&ctx->list, mod, NULL);
1393 lys_module_free(mod, NULL);
1394 return NULL;
1395 }
1396 /* check for importing the same module twice */
1397 for (i = 0; i < u; ++i) {
1398 if (imp->module == mod->parsed->imports[i].module) {
1399 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
1400 ly_set_rm(&ctx->list, mod, NULL);
1401 lys_module_free(mod, NULL);
1402 return NULL;
1403 }
1404 }
1405 }
1406 LY_ARRAY_FOR(mod->parsed->includes, u) {
1407 inc = &mod->parsed->includes[u];
1408 if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
1409 ly_set_rm(&ctx->list, mod, NULL);
1410 lys_module_free(mod, NULL);
1411 return NULL;
1412 }
1413 }
1414 mod->parsed->parsing = 0;
Radek Krejcid33273d2018-10-25 14:55:52 +02001415 }
1416
Radek Krejci86d106e2018-10-18 09:53:19 +02001417 return mod;
1418}
1419
1420API const struct lys_module *
1421lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1422{
Radek Krejcid33273d2018-10-25 14:55:52 +02001423 struct lys_module *result;
1424
1425 result = lys_parse_mem_(ctx, data, format, NULL, 1);
1426 if (result && result->parsed->submodule) {
1427 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1428 result->parsed->name);
1429 lys_module_free(result, NULL);
1430 return NULL;
1431 }
1432 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001433}
1434
1435static void
1436lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1437{
1438#ifdef __APPLE__
1439 char path[MAXPATHLEN];
1440#else
1441 int len;
1442 char path[PATH_MAX], proc_path[32];
1443#endif
1444
1445#ifdef __APPLE__
1446 if (fcntl(fd, F_GETPATH, path) != -1) {
1447 *filename = lydict_insert(ctx, path, 0);
1448 }
1449#else
1450 /* get URI if there is /proc */
1451 sprintf(proc_path, "/proc/self/fd/%d", fd);
1452 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1453 *filename = lydict_insert(ctx, path, len);
1454 }
1455#endif
1456}
1457
Radek Krejcid33273d2018-10-25 14:55:52 +02001458struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001459lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const char *revision, int implement)
1460{
Radek Krejcid33273d2018-10-25 14:55:52 +02001461 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001462 size_t length;
1463 char *addr;
1464
1465 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1466 if (fd < 0) {
1467 LOGARG(ctx, fd);
1468 return NULL;
1469 }
1470
1471 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1472 if (!addr) {
1473 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1474 return NULL;
1475 }
1476
1477 mod = lys_parse_mem_(ctx, addr, format, revision, implement);
1478 ly_munmap(addr, length);
1479
1480 if (mod && !mod->parsed->filepath) {
1481 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1482 }
1483
1484 return mod;
1485}
1486
1487API const struct lys_module *
1488lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1489{
Radek Krejcid33273d2018-10-25 14:55:52 +02001490 struct lys_module *result;
1491
1492 result = lys_parse_fd_(ctx, fd, format, NULL, 1);
1493 if (result && result->parsed->submodule) {
1494 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1495 result->parsed->name);
1496 lys_module_free(result, NULL);
1497 return NULL;
1498 }
1499 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001500}
1501
Radek Krejcid33273d2018-10-25 14:55:52 +02001502struct lys_module *
1503lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const char *revision, int implement)
Radek Krejci86d106e2018-10-18 09:53:19 +02001504{
1505 int fd;
Radek Krejcid33273d2018-10-25 14:55:52 +02001506 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001507 const char *rev, *dot, *filename;
1508 size_t len;
1509
1510 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1511
1512 fd = open(path, O_RDONLY);
1513 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1514
Radek Krejcid33273d2018-10-25 14:55:52 +02001515 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
Radek Krejci86d106e2018-10-18 09:53:19 +02001516 close(fd);
1517 LY_CHECK_RET(!mod, NULL);
1518
1519 /* check that name and revision match filename */
1520 filename = strrchr(path, '/');
1521 if (!filename) {
1522 filename = path;
1523 } else {
1524 filename++;
1525 }
1526 rev = strchr(filename, '@');
1527 dot = strrchr(filename, '.');
1528
1529 /* name */
1530 len = strlen(mod->parsed->name);
1531 if (strncmp(filename, mod->parsed->name, len) ||
1532 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1533 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1534 }
1535 if (rev) {
1536 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001537 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001538 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001539 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001540 }
1541 }
1542
1543 if (!mod->parsed->filepath) {
1544 /* store URI */
1545 char rpath[PATH_MAX];
1546 if (realpath(path, rpath) != NULL) {
1547 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1548 } else {
1549 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1550 }
1551 }
1552
1553 return mod;
1554}
1555
Radek Krejcid33273d2018-10-25 14:55:52 +02001556API const struct lys_module *
1557lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1558{
1559 struct lys_module *result;
1560
1561 result = lys_parse_path_(ctx, path, format, NULL, 1);
1562 if (result && result->parsed->submodule) {
1563 LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
1564 path, result->parsed->name);
1565 lys_module_free(result, NULL);
1566 return NULL;
1567 }
1568 return result;
1569}
1570
1571API LY_ERR
1572lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
1573 char **localfile, LYS_INFORMAT *format)
1574{
1575 size_t len, flen, match_len = 0, dir_len;
1576 int i, implicit_cwd = 0, ret = EXIT_FAILURE;
1577 char *wd, *wn = NULL;
1578 DIR *dir = NULL;
1579 struct dirent *file;
1580 char *match_name = NULL;
1581 LYS_INFORMAT format_aux, match_format = 0;
1582 struct ly_set *dirs;
1583 struct stat st;
1584
1585 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1586
1587 /* start to fill the dir fifo with the context's search path (if set)
1588 * and the current working directory */
1589 dirs = ly_set_new();
1590 if (!dirs) {
1591 LOGMEM(NULL);
1592 return EXIT_FAILURE;
1593 }
1594
1595 len = strlen(name);
1596 if (cwd) {
1597 wd = get_current_dir_name();
1598 if (!wd) {
1599 LOGMEM(NULL);
1600 goto cleanup;
1601 } else {
1602 /* add implicit current working directory (./) to be searched,
1603 * this directory is not searched recursively */
1604 if (ly_set_add(dirs, wd, 0) == -1) {
1605 goto cleanup;
1606 }
1607 implicit_cwd = 1;
1608 }
1609 }
1610 if (searchpaths) {
1611 for (i = 0; searchpaths[i]; i++) {
1612 /* check for duplicities with the implicit current working directory */
1613 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1614 implicit_cwd = 0;
1615 continue;
1616 }
1617 wd = strdup(searchpaths[i]);
1618 if (!wd) {
1619 LOGMEM(NULL);
1620 goto cleanup;
1621 } else if (ly_set_add(dirs, wd, 0) == -1) {
1622 goto cleanup;
1623 }
1624 }
1625 }
1626 wd = NULL;
1627
1628 /* start searching */
1629 while (dirs->count) {
1630 free(wd);
1631 free(wn); wn = NULL;
1632
1633 dirs->count--;
1634 wd = (char *)dirs->objs[dirs->count];
1635 dirs->objs[dirs->count] = NULL;
1636 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1637
1638 if (dir) {
1639 closedir(dir);
1640 }
1641 dir = opendir(wd);
1642 dir_len = strlen(wd);
1643 if (!dir) {
1644 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1645 } else {
1646 while ((file = readdir(dir))) {
1647 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1648 /* skip . and .. */
1649 continue;
1650 }
1651 free(wn);
1652 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1653 LOGMEM(NULL);
1654 goto cleanup;
1655 }
1656 if (stat(wn, &st) == -1) {
1657 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1658 file->d_name, wd, strerror(errno));
1659 continue;
1660 }
1661 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1662 /* we have another subdirectory in searchpath to explore,
1663 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1664 if (ly_set_add(dirs, wn, 0) == -1) {
1665 goto cleanup;
1666 }
1667 /* continue with the next item in current directory */
1668 wn = NULL;
1669 continue;
1670 } else if (!S_ISREG(st.st_mode)) {
1671 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1672 continue;
1673 }
1674
1675 /* here we know that the item is a file which can contain a module */
1676 if (strncmp(name, file->d_name, len) ||
1677 (file->d_name[len] != '.' && file->d_name[len] != '@')) {
1678 /* different filename than the module we search for */
1679 continue;
1680 }
1681
1682 /* get type according to filename suffix */
1683 flen = strlen(file->d_name);
1684 if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1685 format_aux = LYS_IN_YIN;
1686 } else if (!strcmp(&file->d_name[flen - 5], ".yang")) {
1687 format_aux = LYS_IN_YANG;
1688 } else {
1689 /* not supportde suffix/file format */
1690 continue;
1691 }
1692
1693 if (revision) {
1694 /* we look for the specific revision, try to get it from the filename */
1695 if (file->d_name[len] == '@') {
1696 /* check revision from the filename */
1697 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1698 /* another revision */
1699 continue;
1700 } else {
1701 /* exact revision */
1702 free(match_name);
1703 match_name = wn;
1704 wn = NULL;
1705 match_len = dir_len + 1 + len;
1706 match_format = format_aux;
1707 goto success;
1708 }
1709 } else {
1710 /* continue trying to find exact revision match, use this only if not found */
1711 free(match_name);
1712 match_name = wn;
1713 wn = NULL;
1714 match_len = dir_len + 1 +len;
1715 match_format = format_aux;
1716 continue;
1717 }
1718 } else {
1719 /* remember the revision and try to find the newest one */
1720 if (match_name) {
1721 if (file->d_name[len] != '@' ||
1722 lysp_check_date(NULL, &file->d_name[len + 1], flen - (format_aux == LYS_IN_YANG ? 5 : 4) - len - 1, NULL)) {
1723 continue;
1724 } else if (match_name[match_len] == '@' &&
1725 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1726 continue;
1727 }
1728 free(match_name);
1729 }
1730
1731 match_name = wn;
1732 wn = NULL;
1733 match_len = dir_len + 1 + len;
1734 match_format = format_aux;
1735 continue;
1736 }
1737 }
1738 }
1739 }
1740
1741success:
1742 (*localfile) = match_name;
1743 match_name = NULL;
1744 if (format) {
1745 (*format) = match_format;
1746 }
1747 ret = EXIT_SUCCESS;
1748
1749cleanup:
1750 free(wn);
1751 free(wd);
1752 if (dir) {
1753 closedir(dir);
1754 }
1755 free(match_name);
1756 ly_set_free(dirs, free);
1757
1758 return ret;
1759}
1760
1761LY_ERR
1762lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement,
1763 struct lys_module **result)
1764{
1765 size_t len;
1766 int fd;
1767 char *filepath = NULL, *dot, *rev, *filename;
1768 LYS_INFORMAT format;
1769 struct lys_module *mod = NULL;
1770 LY_ERR ret = LY_SUCCESS;
1771
1772 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
1773 &filepath, &format));
1774 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
1775 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
1776
1777
1778 LOGVRB("Loading schema from \"%s\" file.", filepath);
1779
1780 /* open the file */
1781 fd = open(filepath, O_RDONLY);
1782 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
1783 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
1784
1785 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
1786 close(fd);
1787 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
1788
1789 /* check that name and revision match filename */
1790 filename = strrchr(filepath, '/');
1791 if (!filename) {
1792 filename = filepath;
1793 } else {
1794 filename++;
1795 }
1796 /* name */
1797 len = strlen(mod->parsed->name);
1798 rev = strchr(filename, '@');
1799 dot = strrchr(filepath, '.');
1800 if (strncmp(filename, mod->parsed->name, len) ||
1801 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1802 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1803 }
1804 /* revision */
1805 if (rev) {
1806 len = dot - ++rev;
1807 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
1808 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
1809 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
1810 }
1811 }
1812
1813 if (!mod->parsed->filepath) {
1814 char rpath[PATH_MAX];
1815 if (realpath(filepath, rpath) != NULL) {
1816 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1817 } else {
1818 mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
1819 }
1820 }
1821
1822 *result = mod;
1823
1824 /* success */
1825cleanup:
1826 free(filepath);
1827 return ret;
1828}