blob: 2fd21d047cb10e6918693928290cb4b47db2a75d [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
Radek Krejci478020e2018-10-30 16:02:14 +0100467lysc_ext_instance_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext, int dict)
468{
469 FREE_STRING(ctx, ext->argument, dict);
470 FREE_ARRAY(ctx, ext->exts, lysc_ext_instance_free);
471}
472
473static void
Radek Krejci151a5b72018-10-19 14:21:44 +0200474lysc_iffeature_free(struct ly_ctx *UNUSED(ctx), struct lysc_iffeature *iff, int UNUSED(dict))
475{
Radek Krejci2c4e7172018-10-19 15:56:26 +0200476 LY_ARRAY_FREE(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200477 free(iff->expr);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200478}
479
480static void
Radek Krejci478020e2018-10-30 16:02:14 +0100481lysc_import_free(struct ly_ctx *ctx, struct lysc_import *import, int dict)
482{
483 /* imported module is freed directly from the context's list */
484 FREE_STRING(ctx, import->prefix, dict);
485 FREE_ARRAY(ctx, import->exts, lysc_ext_instance_free);
486}
487
488static void
489lysc_ident_free(struct ly_ctx *ctx, struct lysc_ident *ident, int dict)
490{
491 FREE_STRING(ctx, ident->name, dict);
492 FREE_ARRAY(ctx, ident->iffeatures, lysc_iffeature_free);
493 LY_ARRAY_FREE(ident->derived);
494 FREE_ARRAY(ctx, ident->exts, lysc_ext_instance_free);
495}
496
497static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200498lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat, int dict)
499{
Radek Krejci151a5b72018-10-19 14:21:44 +0200500 FREE_STRING(ctx, feat->name, dict);
501 FREE_ARRAY(ctx, feat->iffeatures, lysc_iffeature_free);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200502 LY_ARRAY_FREE(feat->depfeatures);
Radek Krejci478020e2018-10-30 16:02:14 +0100503 FREE_ARRAY(ctx, feat->exts, lysc_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200504}
505
506static void
507lysc_module_free_(struct lysc_module *module, int dict)
508{
509 struct ly_ctx *ctx;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200510
511 LY_CHECK_ARG_RET(NULL, module,);
512 ctx = module->ctx;
513
Radek Krejci151a5b72018-10-19 14:21:44 +0200514 FREE_STRING(ctx, module->name, dict);
515 FREE_STRING(ctx, module->ns, dict);
516 FREE_STRING(ctx, module->prefix, dict);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200517
Radek Krejci478020e2018-10-30 16:02:14 +0100518 FREE_ARRAY(ctx, module->imports, lysc_import_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200519 FREE_ARRAY(ctx, module->features, lysc_feature_free);
Radek Krejci478020e2018-10-30 16:02:14 +0100520 FREE_ARRAY(ctx, module->identities, lysc_ident_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200521
Radek Krejci478020e2018-10-30 16:02:14 +0100522 FREE_ARRAY(ctx, module->exts, lysc_ext_instance_free);
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200523
524 free(module);
525}
Radek Krejci70853c52018-10-15 14:46:16 +0200526
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200527API void
Radek Krejci86d106e2018-10-18 09:53:19 +0200528lysc_module_free(struct lysc_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200529{
Radek Krejci151a5b72018-10-19 14:21:44 +0200530 if (module) {
531 lysc_module_free_(module, 1);
532 }
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200533}
534
Radek Krejci86d106e2018-10-18 09:53:19 +0200535void
536lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejci70853c52018-10-15 14:46:16 +0200537{
Radek Krejci86d106e2018-10-18 09:53:19 +0200538 if (!module) {
539 return;
540 }
Radek Krejci70853c52018-10-15 14:46:16 +0200541
Radek Krejci86d106e2018-10-18 09:53:19 +0200542 lysc_module_free(module->compiled, private_destructor);
543 lysp_module_free(module->parsed);
544 free(module);
545}
546
Radek Krejci151a5b72018-10-19 14:21:44 +0200547struct iff_stack {
548 int size;
549 int index; /* first empty item */
550 uint8_t *stack;
551};
552
Radek Krejci86d106e2018-10-18 09:53:19 +0200553static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200554iff_stack_push(struct iff_stack *stack, uint8_t value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200555{
Radek Krejci151a5b72018-10-19 14:21:44 +0200556 if (stack->index == stack->size) {
557 stack->size += 4;
558 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
559 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
Radek Krejci70853c52018-10-15 14:46:16 +0200560 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200561 stack->stack[stack->index++] = value;
Radek Krejci70853c52018-10-15 14:46:16 +0200562 return LY_SUCCESS;
563}
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200564
Radek Krejci151a5b72018-10-19 14:21:44 +0200565static uint8_t
566iff_stack_pop(struct iff_stack *stack)
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200567{
Radek Krejci151a5b72018-10-19 14:21:44 +0200568 stack->index--;
569 return stack->stack[stack->index];
570}
571
572static void
573iff_stack_clean(struct iff_stack *stack)
574{
575 stack->size = 0;
576 free(stack->stack);
577}
578
579static void
580iff_setop(uint8_t *list, uint8_t op, int pos)
581{
582 uint8_t *item;
583 uint8_t mask = 3;
584
585 assert(pos >= 0);
586 assert(op <= 3); /* max 2 bits */
587
588 item = &list[pos / 4];
589 mask = mask << 2 * (pos % 4);
590 *item = (*item) & ~mask;
591 *item = (*item) | (op << 2 * (pos % 4));
592}
593
594static uint8_t
595iff_getop(uint8_t *list, int pos)
596{
597 uint8_t *item;
598 uint8_t mask = 3, result;
599
600 assert(pos >= 0);
601
602 item = &list[pos / 4];
603 result = (*item) & (mask << 2 * (pos % 4));
604 return result >> 2 * (pos % 4);
605}
606
607#define LYS_IFF_LP 0x04 /* ( */
608#define LYS_IFF_RP 0x08 /* ) */
609
610API int
611lysc_feature_value(const struct lysc_feature *feature)
612{
613 LY_CHECK_ARG_RET(NULL, feature, -1);
614 return feature->flags & LYS_FENABLED ? 1 : 0;
615}
616
617static struct lysc_feature *
618lysc_feature_find(struct lysc_module *mod, const char *name, size_t len)
619{
620 size_t i;
621 struct lysc_feature *f;
622
623 for (i = 0; i < len; ++i) {
624 if (name[i] == ':') {
625 /* we have a prefixed feature */
Radek Krejcice8c1592018-10-29 15:35:51 +0100626 mod = lysc_module_find_prefix(mod, name, i)->compiled;
Radek Krejci151a5b72018-10-19 14:21:44 +0200627 LY_CHECK_RET(!mod, NULL);
628
629 name = &name[i + 1];
630 len = len - i - 1;
631 }
632 }
633
634 /* we have the correct module, get the feature */
635 LY_ARRAY_FOR(mod->features, i) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200636 f = &mod->features[i];
Radek Krejci151a5b72018-10-19 14:21:44 +0200637 if (!strncmp(f->name, name, len) && f->name[len] == '\0') {
638 return f;
639 }
640 }
641
642 return NULL;
643}
644
645static int
646lysc_iffeature_value_(const struct lysc_iffeature *iff, int *index_e, int *index_f)
647{
648 uint8_t op;
649 int a, b;
650
651 op = iff_getop(iff->expr, *index_e);
652 (*index_e)++;
653
654 switch (op) {
655 case LYS_IFF_F:
656 /* resolve feature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200657 return lysc_feature_value(iff->features[(*index_f)++]);
Radek Krejci151a5b72018-10-19 14:21:44 +0200658 case LYS_IFF_NOT:
659 /* invert result */
660 return lysc_iffeature_value_(iff, index_e, index_f) ? 0 : 1;
661 case LYS_IFF_AND:
662 case LYS_IFF_OR:
663 a = lysc_iffeature_value_(iff, index_e, index_f);
664 b = lysc_iffeature_value_(iff, index_e, index_f);
665 if (op == LYS_IFF_AND) {
666 return a && b;
667 } else { /* LYS_IFF_OR */
668 return a || b;
669 }
670 }
671
672 return 0;
673}
674
675API int
676lysc_iffeature_value(const struct lysc_iffeature *iff)
677{
678 int index_e = 0, index_f = 0;
679
680 LY_CHECK_ARG_RET(NULL, iff, -1);
681
682 if (iff->expr) {
683 return lysc_iffeature_value_(iff, &index_e, &index_f);
684 }
685 return 0;
686}
687
688/*
689 * op: 1 - enable, 0 - disable
690 */
691/**
692 * @brief Enable/Disable the specified feature in the module.
693 *
694 * If the feature is already set to the desired value, LY_SUCCESS is returned.
695 * By changing the feature, also all the feature which depends on it via their
696 * if-feature statements are again evaluated (disabled if a if-feature statemen
697 * evaluates to false).
698 *
699 * @param[in] mod Compiled module where to set (search for) the feature.
700 * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
701 * set all the features in the module.
702 * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
703 * @return LY_ERR value.
704 */
705static LY_ERR
706lys_feature_change(const struct lysc_module *mod, const char *name, int value)
707{
708 int all = 0;
709 unsigned int u;
710 struct lysc_feature *f, **df;
711 struct lysc_iffeature *iff;
712 struct ly_set *changed;
713
714 if (!mod->features) {
715 LOGERR(mod->ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
716 return LY_EINVAL;
717 }
718
719 if (!strcmp(name, "*")) {
720 /* enable all */
721 all = 1;
722 }
723 changed = ly_set_new();
724
725 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200726 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200727 if (all || !strcmp(f->name, name)) {
728 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
729 if (all) {
730 /* skip already set features */
731 continue;
732 } else {
733 /* feature already set correctly */
734 ly_set_free(changed, NULL);
735 return LY_SUCCESS;
736 }
737 }
738
739 if (value) { /* enable */
740 /* check referenced features if they are enabled */
741 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
742 if (!lysc_iffeature_value(iff)) {
743 if (all) {
744 LOGWRN(mod->ctx,
745 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
746 f->name);
747 goto next;
748 } else {
749 LOGERR(mod->ctx, LY_EDENIED,
750 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
751 f->name);
752 ly_set_free(changed, NULL);
753 return LY_EDENIED;
754 }
755 }
756 }
757 /* enable the feature */
758 f->flags |= LYS_FENABLED;
759 } else { /* disable */
760 /* disable the feature */
761 f->flags &= ~LYS_FENABLED;
762 }
763
764 /* remember the changed feature */
765 ly_set_add(changed, f, LY_SET_OPT_USEASLIST);
766
767 if (!all) {
768 /* stop in case changing a single feature */
769 break;
770 }
771 }
772next:
773 ;
774 }
775
776 if (!all && !changed->count) {
777 LOGERR(mod->ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
778 ly_set_free(changed, NULL);
779 return LY_EINVAL;
780 }
781
782 /* reflect change(s) in the dependent features */
783 for (u = 0; u < changed->count; ++u) {
784 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
785 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
786 * is not done - by default, features are disabled and must be explicitely enabled. */
787 f = changed->objs[u];
788 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature*, df) {
789 if (!((*df)->flags & LYS_FENABLED)) {
790 /* not enabled, nothing to do */
791 continue;
792 }
793 /* check the feature's if-features which could change by the previous change of our feature */
794 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
795 if (!lysc_iffeature_value(iff)) {
796 /* the feature must be disabled now */
797 (*df)->flags &= ~LYS_FENABLED;
798 /* add the feature into the list of changed features */
799 ly_set_add(changed, *df, LY_SET_OPT_USEASLIST);
800 break;
801 }
802 }
803 }
804 }
805
806 ly_set_free(changed, NULL);
807 return LY_SUCCESS;
808}
809
810API LY_ERR
811lys_feature_enable(struct lys_module *module, const char *feature)
812{
813 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
814
815 return lys_feature_change(module->compiled, feature, 1);
816}
817
818API LY_ERR
819lys_feature_disable(struct lys_module *module, const char *feature)
820{
821 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
822
823 return lys_feature_change(module->compiled, feature, 0);
824}
825
826API int
827lys_feature_value(const struct lys_module *module, const char *feature)
828{
829 struct lysc_feature *f;
830 struct lysc_module *mod;
831 unsigned int u;
832
833 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
834 mod = module->compiled;
835
836 /* search for the specified feature */
837 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200838 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200839 if (!strcmp(f->name, feature)) {
840 if (f->flags & LYS_FENABLED) {
841 return 1;
842 } else {
843 return 0;
844 }
845 }
846 }
847
848 /* feature definition not found */
849 return -1;
850}
851
852static LY_ERR
Radek Krejcice8c1592018-10-29 15:35:51 +0100853lys_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 +0200854{
Radek Krejcice8c1592018-10-29 15:35:51 +0100855 const char *name;
856 unsigned int u;
857 const struct lys_module *mod;
858 struct lysp_ext *edef;
859
860 if (options & LYSC_OPT_FREE_SP) {
861 /* just switch the pointers */
862 ext->argument = ext_p->argument;
863 } else {
864 /* keep refcounts correct for lysp_module_free() */
865 ext->argument = lydict_insert(ctx->mod->ctx, ext_p->argument, 0);
866 }
867 ext->insubstmt = ext_p->insubstmt;
868 ext->insubstmt_index = ext_p->insubstmt_index;
869
870 /* get module where the extension definition should be placed */
871 for (u = 0; ext_p->name[u] != ':'; ++u);
872 mod = lysc_module_find_prefix(ctx->mod, ext_p->name, u);
873 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
874 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, ext_p->name),
875 LY_EVALID);
876 LY_CHECK_ERR_RET(!mod->parsed->extensions,
877 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
878 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
879 ext_p->name, mod->parsed->name),
880 LY_EVALID);
881 name = &ext_p->name[u + 1];
882 /* find the extension definition there */
883 for (ext = NULL, u = 0; u < LY_ARRAY_SIZE(mod->parsed->extensions); ++u) {
884 if (!strcmp(name, mod->parsed->extensions[u].name)) {
885 edef = &mod->parsed->extensions[u];
886 break;
887 }
888 }
889 LY_CHECK_ERR_RET(!edef, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
890 "Extension definition of extension instance \"%s\" not found.", ext_p->name),
891 LY_EVALID);
892 /* TODO plugins */
893
894 return LY_SUCCESS;
895}
896
897/**
898 * @param[in] parent Provided only in case the if-feature is inside
899 */
900static LY_ERR
901lys_compile_iffeature(struct lysc_ctx *ctx, const char **value, int UNUSED(options), struct lysc_iffeature *iff)
902{
903 const char *c = *value;
Radek Krejci151a5b72018-10-19 14:21:44 +0200904 int r, rc = EXIT_FAILURE;
905 int i, j, last_not, checkversion = 0;
906 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
907 uint8_t op;
908 struct iff_stack stack = {0, 0, NULL};
Radek Krejcice8c1592018-10-29 15:35:51 +0100909 struct lysc_feature *f;
Radek Krejci151a5b72018-10-19 14:21:44 +0200910
911 assert(c);
912
913 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
914 for (i = j = last_not = 0; c[i]; i++) {
915 if (c[i] == '(') {
916 j++;
917 checkversion = 1;
918 continue;
919 } else if (c[i] == ')') {
920 j--;
921 continue;
922 } else if (isspace(c[i])) {
923 checkversion = 1;
924 continue;
925 }
926
927 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
928 if (c[i + r] == '\0') {
929 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100930 "Invalid value \"%s\" of if-feature - unexpected end of expression.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200931 return LY_EVALID;
932 } else if (!isspace(c[i + r])) {
933 /* feature name starting with the not/and/or */
934 last_not = 0;
935 f_size++;
936 } else if (c[i] == 'n') { /* not operation */
937 if (last_not) {
938 /* double not */
939 expr_size = expr_size - 2;
940 last_not = 0;
941 } else {
942 last_not = 1;
943 }
944 } else { /* and, or */
945 f_exp++;
946 /* not a not operation */
947 last_not = 0;
948 }
949 i += r;
950 } else {
951 f_size++;
952 last_not = 0;
953 }
954 expr_size++;
955
956 while (!isspace(c[i])) {
957 if (!c[i] || c[i] == ')') {
958 i--;
959 break;
960 }
961 i++;
962 }
963 }
964 if (j || f_exp != f_size) {
965 /* not matching count of ( and ) */
966 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100967 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200968 return LY_EVALID;
969 }
970
971 if (checkversion || expr_size > 1) {
972 /* check that we have 1.1 module */
973 if (ctx->mod->version != LYS_VERSION_1_1) {
974 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100975 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200976 return LY_EVALID;
977 }
978 }
979
980 /* allocate the memory */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200981 LY_ARRAY_CREATE_RET(ctx->mod->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200982 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +0200983 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200984 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->mod->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +0200985
Radek Krejci151a5b72018-10-19 14:21:44 +0200986 stack.size = expr_size;
987 f_size--; expr_size--; /* used as indexes from now */
988
989 for (i--; i >= 0; i--) {
990 if (c[i] == ')') {
991 /* push it on stack */
992 iff_stack_push(&stack, LYS_IFF_RP);
993 continue;
994 } else if (c[i] == '(') {
995 /* pop from the stack into result all operators until ) */
996 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
997 iff_setop(iff->expr, op, expr_size--);
998 }
999 continue;
1000 } else if (isspace(c[i])) {
1001 continue;
1002 }
1003
1004 /* end of operator or operand -> find beginning and get what is it */
1005 j = i + 1;
1006 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1007 i--;
1008 }
1009 i++; /* go back by one step */
1010
1011 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
1012 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1013 /* double not */
1014 iff_stack_pop(&stack);
1015 } else {
1016 /* not has the highest priority, so do not pop from the stack
1017 * as in case of AND and OR */
1018 iff_stack_push(&stack, LYS_IFF_NOT);
1019 }
1020 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
1021 /* as for OR - pop from the stack all operators with the same or higher
1022 * priority and store them to the result, then push the AND to the stack */
1023 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1024 op = iff_stack_pop(&stack);
1025 iff_setop(iff->expr, op, expr_size--);
1026 }
1027 iff_stack_push(&stack, LYS_IFF_AND);
1028 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
1029 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1030 op = iff_stack_pop(&stack);
1031 iff_setop(iff->expr, op, expr_size--);
1032 }
1033 iff_stack_push(&stack, LYS_IFF_OR);
1034 } else {
1035 /* feature name, length is j - i */
1036
1037 /* add it to the expression */
1038 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
1039
1040 /* now get the link to the feature definition */
1041 f = lysc_feature_find(ctx->mod, &c[i], j - i);
1042 LY_CHECK_ERR_GOTO(!f,
1043 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001044 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
Radek Krejci151a5b72018-10-19 14:21:44 +02001045 rc = LY_EINVAL,
1046 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +02001047 iff->features[f_size] = f;
1048 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +02001049 f_size--;
1050 }
1051 }
1052 while (stack.index) {
1053 op = iff_stack_pop(&stack);
1054 iff_setop(iff->expr, op, expr_size--);
1055 }
1056
1057 if (++expr_size || ++f_size) {
1058 /* not all expected operators and operands found */
1059 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001060 "Invalid value \"%s\" of if-feature - processing error.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001061 rc = LY_EINT;
1062 } else {
1063 rc = LY_SUCCESS;
1064 }
1065
1066error:
1067 /* cleanup */
1068 iff_stack_clean(&stack);
1069
1070 return rc;
1071}
1072
1073static LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001074lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
1075{
Radek Krejcice8c1592018-10-29 15:35:51 +01001076 unsigned int u;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001077 struct lys_module *mod;
1078 struct lysc_module *comp;
Radek Krejcice8c1592018-10-29 15:35:51 +01001079 LY_ERR ret = LY_SUCCESS;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001080
1081 if (options & LYSC_OPT_FREE_SP) {
1082 /* just switch the pointers */
1083 imp->prefix = imp_p->prefix;
1084 } else {
1085 /* keep refcounts correct for lysp_module_free() */
1086 imp->prefix = lydict_insert(ctx->mod->ctx, imp_p->prefix, 0);
1087 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001088 COMPILE_ARRAY_GOTO(ctx, imp_p->exts, imp->exts, options, u, lys_compile_ext, ret, done);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001089 imp->module = imp_p->module;
1090
1091 /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
1092 * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
1093 if (!imp->module->parsed) {
1094 comp = imp->module->compiled;
1095 /* try to get filepath from the compiled version */
1096 if (comp->filepath) {
1097 mod = (struct lys_module*)lys_parse_path(ctx->mod->ctx, comp->filepath,
1098 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
1099 if (mod != imp->module) {
1100 LOGERR(ctx->mod->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
1101 comp->filepath, comp->name);
1102 mod = NULL;
1103 }
1104 }
1105 if (!mod) {
1106 if (lysp_load_module(ctx->mod->ctx, comp->name, comp->revs ? comp->revs[0].date : NULL, 0, 1, &mod)) {
1107 LOGERR(ctx->mod->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
1108 comp->name, ctx->mod->name);
1109 return LY_ENOTFOUND;
1110 }
1111 }
1112 } else if (!imp->module->compiled) {
1113 return lys_compile(imp->module->parsed, options, &imp->module->compiled);
1114 }
1115
Radek Krejcice8c1592018-10-29 15:35:51 +01001116done:
1117 return ret;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001118}
1119
1120static LY_ERR
Radek Krejci2a408df2018-10-29 16:32:26 +01001121lys_compile_identity(struct lysc_ctx *ctx, struct lysp_ident *ident_p, int options, struct lysc_ident *ident)
1122{
1123 unsigned int u;
1124 LY_ERR ret = LY_SUCCESS;
1125
1126 if (options & LYSC_OPT_FREE_SP) {
1127 /* just switch the pointers */
1128 ident->name = ident_p->name;
1129 } else {
1130 /* keep refcounts correct for lysp_module_free() */
1131 ident->name = lydict_insert(ctx->mod->ctx, ident_p->name, 0);
1132 }
1133 COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, options, u, lys_compile_iffeature, ret, done);
1134 /* backlings (derived) can be added no sooner than when all the identities in the current module are present */
1135 COMPILE_ARRAY_GOTO(ctx, ident_p->exts, ident->exts, options, u, lys_compile_ext, ret, done);
1136 ident->flags = ident_p->flags;
1137
1138done:
1139 return ret;
1140}
1141
1142static LY_ERR
1143lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1144{
1145 unsigned int i, u, v;
1146 const char *s, *name;
1147 struct lysc_module *mod;
1148 struct lysc_ident **dident;
1149
1150 for (i = 0; i < LY_ARRAY_SIZE(idents_p); ++i) {
Radek Krejci478020e2018-10-30 16:02:14 +01001151 if (!idents_p[i].bases) {
1152 continue;
1153 }
Radek Krejci2a408df2018-10-29 16:32:26 +01001154 for (u = 0; u < LY_ARRAY_SIZE(idents_p[i].bases); ++u) {
1155 s = strchr(idents_p[i].bases[u], ':');
1156 if (s) {
1157 /* prefixed identity */
1158 name = &s[1];
1159 mod = lysc_module_find_prefix(ctx->mod, idents_p[i].bases[u], s - idents_p[i].bases[u])->compiled;
1160 } else {
1161 name = idents_p[i].bases[u];
1162 mod = ctx->mod;
1163 }
1164 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1165 "Invalid prefix used for base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1166 LY_EVALID);
1167 if (mod->identities) {
1168 for (v = 0; v < LY_ARRAY_SIZE(mod->identities); ++v) {
1169 if (!strcmp(name, mod->identities[v].name)) {
1170 /* we have match! store the backlink */
1171 LY_ARRAY_NEW_RET(ctx->mod->ctx, mod->identities[v].derived, dident, LY_EMEM);
1172 *dident = &idents[i];
1173 break;
1174 }
1175 }
1176 }
1177 LY_CHECK_ERR_RET(!dident, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1178 "Unable to find base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1179 LY_EVALID);
1180 }
1181 }
1182 return LY_SUCCESS;
1183}
1184
1185static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +02001186lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
1187{
Radek Krejcice8c1592018-10-29 15:35:51 +01001188 unsigned int u, v;
1189 LY_ERR ret = LY_SUCCESS;
1190 struct lysc_feature **df;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001191
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001192 if (options & LYSC_OPT_FREE_SP) {
1193 /* just switch the pointers */
1194 feature->name = feature_p->name;
1195 } else {
1196 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001197 feature->name = lydict_insert(ctx->mod->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001198 }
1199 feature->flags = feature_p->flags;
1200
Radek Krejcice8c1592018-10-29 15:35:51 +01001201 COMPILE_ARRAY_GOTO(ctx, feature_p->exts, feature->exts, options, u, lys_compile_ext, ret, done);
1202 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, options, u, lys_compile_iffeature, ret, done);
1203 if (feature->iffeatures) {
1204 for (u = 0; u < LY_ARRAY_SIZE(feature->iffeatures); ++u) {
1205 if (feature->iffeatures[u].features) {
1206 for (v = 0; v < LY_ARRAY_SIZE(feature->iffeatures[u].features); ++v) {
1207 /* add itself into the dependants list */
1208 LY_ARRAY_NEW_RET(ctx->mod->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
1209 *df = feature;
1210 }
1211 /* TODO check for circular dependency */
1212 }
Radek Krejci151a5b72018-10-19 14:21:44 +02001213 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001214 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001215done:
1216 return ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001217}
1218
1219LY_ERR
1220lys_compile(struct lysp_module *sp, int options, struct lysc_module **sc)
1221{
Radek Krejci86d106e2018-10-18 09:53:19 +02001222 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001223 struct lysc_module *mod_c;
Radek Krejci151a5b72018-10-19 14:21:44 +02001224 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001225 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001226
1227 LY_CHECK_ARG_RET(NULL, sc, sp, sp->ctx, LY_EINVAL);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001228
1229 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001230 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 +02001231 return LY_EINVAL;
1232 }
1233
Radek Krejci478020e2018-10-30 16:02:14 +01001234 ctx.mod = *sc = mod_c = calloc(1, sizeof *mod_c);
Radek Krejci86d106e2018-10-18 09:53:19 +02001235 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1236 mod_c->ctx = sp->ctx;
1237 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001238
1239 if (options & LYSC_OPT_FREE_SP) {
1240 /* just switch the pointers */
1241 mod_c->name = sp->name;
1242 mod_c->ns = sp->ns;
1243 mod_c->prefix = sp->prefix;
1244 } else {
1245 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001246 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1247 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1248 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001249 }
1250
Radek Krejcice8c1592018-10-29 15:35:51 +01001251 COMPILE_ARRAY_GOTO(&ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
1252 COMPILE_ARRAY_GOTO(&ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
Radek Krejci2a408df2018-10-29 16:32:26 +01001253 COMPILE_ARRAY_GOTO(&ctx, sp->identities, mod_c->identities, options, u, lys_compile_identity, ret, error);
1254 if (sp->identities) {
1255 LY_CHECK_RET(lys_compile_identities_derived(&ctx, sp->identities, mod_c->identities));
1256 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001257
1258 COMPILE_ARRAY_GOTO(&ctx, sp->exts, mod_c->exts, options, u, lys_compile_ext, ret, error);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001259
1260 if (options & LYSC_OPT_FREE_SP) {
1261 lysp_module_free_(sp, 0);
1262 }
1263
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001264 return LY_SUCCESS;
1265
1266error:
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001267 lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001268
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001269 return ret;
1270}
Radek Krejci86d106e2018-10-18 09:53:19 +02001271
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001272static void
Radek Krejci086c7132018-10-26 15:29:04 +02001273lys_latest_switch(struct lys_module *old, struct lysp_module *new)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001274{
Radek Krejci086c7132018-10-26 15:29:04 +02001275 if (old->parsed) {
1276 new->latest_revision = old->parsed->latest_revision;
1277 old->parsed->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001278 }
Radek Krejci086c7132018-10-26 15:29:04 +02001279 if (old->compiled) {
1280 new->latest_revision = old->parsed->latest_revision;
1281 old->compiled->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001282 }
1283}
1284
Radek Krejcid33273d2018-10-25 14:55:52 +02001285struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001286lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
1287{
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001288 struct lys_module *mod = NULL, *latest, *mod_dup;
Radek Krejcid33273d2018-10-25 14:55:52 +02001289 struct lysp_module *latest_p;
Radek Krejci086c7132018-10-26 15:29:04 +02001290 struct lysp_import *imp;
1291 struct lysp_include *inc;
Radek Krejci86d106e2018-10-18 09:53:19 +02001292 LY_ERR ret;
Radek Krejci086c7132018-10-26 15:29:04 +02001293 unsigned int u, i;
Radek Krejci86d106e2018-10-18 09:53:19 +02001294
1295 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1296
1297 mod = calloc(1, sizeof *mod);
1298 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1299
1300 switch (format) {
1301 case LYS_IN_YIN:
1302 /* TODO not yet supported
1303 mod = yin_read_module(ctx, data, revision, implement);
1304 */
1305 break;
1306 case LYS_IN_YANG:
1307 ret = yang_parse(ctx, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001308 break;
1309 default:
1310 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1311 break;
1312 }
Radek Krejcifaa1eac2018-10-30 14:34:55 +01001313 LY_CHECK_ERR_RET(ret, free(mod), NULL);
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001314
1315 /* make sure that the newest revision is at position 0 */
1316 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001317
1318 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001319 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001320 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1321 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
1322 lys_module_free(mod, NULL);
1323 return NULL;
1324 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001325 mod->parsed->implemented = 1;
1326 }
1327
1328 if (revision) {
1329 /* check revision of the parsed model */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001330 if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].date)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001331 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
Radek Krejcib7db73a2018-10-24 14:18:40 +02001332 mod->parsed->name, mod->parsed->revs[0].date, revision);
1333 lys_module_free(mod, NULL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001334 return NULL;
1335 }
1336 }
1337
Radek Krejcid33273d2018-10-25 14:55:52 +02001338 if (mod->parsed->submodule) { /* submodule */
1339 /* decide the latest revision */
1340 latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
1341 if (latest_p) {
1342 if (mod->parsed->revs) {
1343 if (!latest_p->revs) {
1344 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001345 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001346 latest_p->latest_revision = 0;
1347 } else {
1348 if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
Radek Krejci086c7132018-10-26 15:29:04 +02001349 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001350 latest_p->latest_revision = 0;
1351 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001352 }
1353 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001354 } else {
Radek Krejci086c7132018-10-26 15:29:04 +02001355 mod->parsed->latest_revision = revision ? 1 : 2;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001356 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001357 } else { /* module */
1358 /* check for duplicity in the context */
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001359 mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
1360 if (mod_dup) {
1361 if (mod_dup->parsed) {
1362 /* error */
1363 if (mod->parsed->revs) {
1364 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1365 mod->parsed->name, mod->parsed->revs[0].date);
1366 } else {
1367 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1368 mod->parsed->name);
1369 }
1370 lys_module_free(mod, NULL);
1371 return NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +02001372 } else {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001373 /* add the parsed data to the currently compiled-only module in the context */
1374 mod_dup->parsed = mod->parsed;
1375 free(mod);
1376 mod = mod_dup;
1377 goto finish_parsing;
Radek Krejcid33273d2018-10-25 14:55:52 +02001378 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001379 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001380
1381#if 0
1382 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1383 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1384 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1385 * the anotation definitions available in the internal schema structure. There is another hack in schema
1386 * printers to do not print this internally added annotation. */
1387 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1388 if (lyp_add_ietf_netconf_annotations(mod)) {
1389 lys_free(mod, NULL, 1, 1);
1390 return NULL;
1391 }
1392 }
1393#endif
1394
Radek Krejcid33273d2018-10-25 14:55:52 +02001395 /* decide the latest revision */
1396 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1397 if (latest) {
1398 if (mod->parsed->revs) {
1399 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revs)) {
1400 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001401 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001402 } else {
1403 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 +02001404 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001405 }
1406 }
1407 }
1408 } else {
1409 mod->parsed->latest_revision = 1;
1410 }
1411
1412 /* add into context */
1413 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1414
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001415finish_parsing:
Radek Krejci086c7132018-10-26 15:29:04 +02001416 /* resolve imports and includes */
1417 mod->parsed->parsing = 1;
1418 LY_ARRAY_FOR(mod->parsed->imports, u) {
1419 imp = &mod->parsed->imports[u];
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001420 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 +02001421 ly_set_rm(&ctx->list, mod, NULL);
1422 lys_module_free(mod, NULL);
1423 return NULL;
1424 }
1425 /* check for importing the same module twice */
1426 for (i = 0; i < u; ++i) {
1427 if (imp->module == mod->parsed->imports[i].module) {
1428 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
1429 ly_set_rm(&ctx->list, mod, NULL);
1430 lys_module_free(mod, NULL);
1431 return NULL;
1432 }
1433 }
1434 }
1435 LY_ARRAY_FOR(mod->parsed->includes, u) {
1436 inc = &mod->parsed->includes[u];
1437 if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
1438 ly_set_rm(&ctx->list, mod, NULL);
1439 lys_module_free(mod, NULL);
1440 return NULL;
1441 }
1442 }
1443 mod->parsed->parsing = 0;
Radek Krejcid33273d2018-10-25 14:55:52 +02001444 }
1445
Radek Krejci86d106e2018-10-18 09:53:19 +02001446 return mod;
1447}
1448
1449API const struct lys_module *
1450lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1451{
Radek Krejcid33273d2018-10-25 14:55:52 +02001452 struct lys_module *result;
1453
1454 result = lys_parse_mem_(ctx, data, format, NULL, 1);
1455 if (result && result->parsed->submodule) {
1456 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1457 result->parsed->name);
1458 lys_module_free(result, NULL);
1459 return NULL;
1460 }
1461 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001462}
1463
1464static void
1465lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1466{
1467#ifdef __APPLE__
1468 char path[MAXPATHLEN];
1469#else
1470 int len;
1471 char path[PATH_MAX], proc_path[32];
1472#endif
1473
1474#ifdef __APPLE__
1475 if (fcntl(fd, F_GETPATH, path) != -1) {
1476 *filename = lydict_insert(ctx, path, 0);
1477 }
1478#else
1479 /* get URI if there is /proc */
1480 sprintf(proc_path, "/proc/self/fd/%d", fd);
1481 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1482 *filename = lydict_insert(ctx, path, len);
1483 }
1484#endif
1485}
1486
Radek Krejcid33273d2018-10-25 14:55:52 +02001487struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001488lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const char *revision, int implement)
1489{
Radek Krejcid33273d2018-10-25 14:55:52 +02001490 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001491 size_t length;
1492 char *addr;
1493
1494 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1495 if (fd < 0) {
1496 LOGARG(ctx, fd);
1497 return NULL;
1498 }
1499
1500 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1501 if (!addr) {
1502 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1503 return NULL;
1504 }
1505
1506 mod = lys_parse_mem_(ctx, addr, format, revision, implement);
1507 ly_munmap(addr, length);
1508
1509 if (mod && !mod->parsed->filepath) {
1510 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1511 }
1512
1513 return mod;
1514}
1515
1516API const struct lys_module *
1517lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1518{
Radek Krejcid33273d2018-10-25 14:55:52 +02001519 struct lys_module *result;
1520
1521 result = lys_parse_fd_(ctx, fd, format, NULL, 1);
1522 if (result && result->parsed->submodule) {
1523 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1524 result->parsed->name);
1525 lys_module_free(result, NULL);
1526 return NULL;
1527 }
1528 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001529}
1530
Radek Krejcid33273d2018-10-25 14:55:52 +02001531struct lys_module *
1532lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const char *revision, int implement)
Radek Krejci86d106e2018-10-18 09:53:19 +02001533{
1534 int fd;
Radek Krejcid33273d2018-10-25 14:55:52 +02001535 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001536 const char *rev, *dot, *filename;
1537 size_t len;
1538
1539 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1540
1541 fd = open(path, O_RDONLY);
1542 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1543
Radek Krejcid33273d2018-10-25 14:55:52 +02001544 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
Radek Krejci86d106e2018-10-18 09:53:19 +02001545 close(fd);
1546 LY_CHECK_RET(!mod, NULL);
1547
1548 /* check that name and revision match filename */
1549 filename = strrchr(path, '/');
1550 if (!filename) {
1551 filename = path;
1552 } else {
1553 filename++;
1554 }
1555 rev = strchr(filename, '@');
1556 dot = strrchr(filename, '.');
1557
1558 /* name */
1559 len = strlen(mod->parsed->name);
1560 if (strncmp(filename, mod->parsed->name, len) ||
1561 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1562 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1563 }
1564 if (rev) {
1565 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001566 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001567 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001568 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001569 }
1570 }
1571
1572 if (!mod->parsed->filepath) {
1573 /* store URI */
1574 char rpath[PATH_MAX];
1575 if (realpath(path, rpath) != NULL) {
1576 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1577 } else {
1578 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1579 }
1580 }
1581
1582 return mod;
1583}
1584
Radek Krejcid33273d2018-10-25 14:55:52 +02001585API const struct lys_module *
1586lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1587{
1588 struct lys_module *result;
1589
1590 result = lys_parse_path_(ctx, path, format, NULL, 1);
1591 if (result && result->parsed->submodule) {
1592 LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
1593 path, result->parsed->name);
1594 lys_module_free(result, NULL);
1595 return NULL;
1596 }
1597 return result;
1598}
1599
1600API LY_ERR
1601lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
1602 char **localfile, LYS_INFORMAT *format)
1603{
1604 size_t len, flen, match_len = 0, dir_len;
1605 int i, implicit_cwd = 0, ret = EXIT_FAILURE;
1606 char *wd, *wn = NULL;
1607 DIR *dir = NULL;
1608 struct dirent *file;
1609 char *match_name = NULL;
1610 LYS_INFORMAT format_aux, match_format = 0;
1611 struct ly_set *dirs;
1612 struct stat st;
1613
1614 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1615
1616 /* start to fill the dir fifo with the context's search path (if set)
1617 * and the current working directory */
1618 dirs = ly_set_new();
1619 if (!dirs) {
1620 LOGMEM(NULL);
1621 return EXIT_FAILURE;
1622 }
1623
1624 len = strlen(name);
1625 if (cwd) {
1626 wd = get_current_dir_name();
1627 if (!wd) {
1628 LOGMEM(NULL);
1629 goto cleanup;
1630 } else {
1631 /* add implicit current working directory (./) to be searched,
1632 * this directory is not searched recursively */
1633 if (ly_set_add(dirs, wd, 0) == -1) {
1634 goto cleanup;
1635 }
1636 implicit_cwd = 1;
1637 }
1638 }
1639 if (searchpaths) {
1640 for (i = 0; searchpaths[i]; i++) {
1641 /* check for duplicities with the implicit current working directory */
1642 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1643 implicit_cwd = 0;
1644 continue;
1645 }
1646 wd = strdup(searchpaths[i]);
1647 if (!wd) {
1648 LOGMEM(NULL);
1649 goto cleanup;
1650 } else if (ly_set_add(dirs, wd, 0) == -1) {
1651 goto cleanup;
1652 }
1653 }
1654 }
1655 wd = NULL;
1656
1657 /* start searching */
1658 while (dirs->count) {
1659 free(wd);
1660 free(wn); wn = NULL;
1661
1662 dirs->count--;
1663 wd = (char *)dirs->objs[dirs->count];
1664 dirs->objs[dirs->count] = NULL;
1665 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1666
1667 if (dir) {
1668 closedir(dir);
1669 }
1670 dir = opendir(wd);
1671 dir_len = strlen(wd);
1672 if (!dir) {
1673 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1674 } else {
1675 while ((file = readdir(dir))) {
1676 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1677 /* skip . and .. */
1678 continue;
1679 }
1680 free(wn);
1681 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1682 LOGMEM(NULL);
1683 goto cleanup;
1684 }
1685 if (stat(wn, &st) == -1) {
1686 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1687 file->d_name, wd, strerror(errno));
1688 continue;
1689 }
1690 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1691 /* we have another subdirectory in searchpath to explore,
1692 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1693 if (ly_set_add(dirs, wn, 0) == -1) {
1694 goto cleanup;
1695 }
1696 /* continue with the next item in current directory */
1697 wn = NULL;
1698 continue;
1699 } else if (!S_ISREG(st.st_mode)) {
1700 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1701 continue;
1702 }
1703
1704 /* here we know that the item is a file which can contain a module */
1705 if (strncmp(name, file->d_name, len) ||
1706 (file->d_name[len] != '.' && file->d_name[len] != '@')) {
1707 /* different filename than the module we search for */
1708 continue;
1709 }
1710
1711 /* get type according to filename suffix */
1712 flen = strlen(file->d_name);
1713 if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1714 format_aux = LYS_IN_YIN;
1715 } else if (!strcmp(&file->d_name[flen - 5], ".yang")) {
1716 format_aux = LYS_IN_YANG;
1717 } else {
1718 /* not supportde suffix/file format */
1719 continue;
1720 }
1721
1722 if (revision) {
1723 /* we look for the specific revision, try to get it from the filename */
1724 if (file->d_name[len] == '@') {
1725 /* check revision from the filename */
1726 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1727 /* another revision */
1728 continue;
1729 } else {
1730 /* exact revision */
1731 free(match_name);
1732 match_name = wn;
1733 wn = NULL;
1734 match_len = dir_len + 1 + len;
1735 match_format = format_aux;
1736 goto success;
1737 }
1738 } else {
1739 /* continue trying to find exact revision match, use this only if not found */
1740 free(match_name);
1741 match_name = wn;
1742 wn = NULL;
1743 match_len = dir_len + 1 +len;
1744 match_format = format_aux;
1745 continue;
1746 }
1747 } else {
1748 /* remember the revision and try to find the newest one */
1749 if (match_name) {
1750 if (file->d_name[len] != '@' ||
1751 lysp_check_date(NULL, &file->d_name[len + 1], flen - (format_aux == LYS_IN_YANG ? 5 : 4) - len - 1, NULL)) {
1752 continue;
1753 } else if (match_name[match_len] == '@' &&
1754 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1755 continue;
1756 }
1757 free(match_name);
1758 }
1759
1760 match_name = wn;
1761 wn = NULL;
1762 match_len = dir_len + 1 + len;
1763 match_format = format_aux;
1764 continue;
1765 }
1766 }
1767 }
1768 }
1769
1770success:
1771 (*localfile) = match_name;
1772 match_name = NULL;
1773 if (format) {
1774 (*format) = match_format;
1775 }
1776 ret = EXIT_SUCCESS;
1777
1778cleanup:
1779 free(wn);
1780 free(wd);
1781 if (dir) {
1782 closedir(dir);
1783 }
1784 free(match_name);
1785 ly_set_free(dirs, free);
1786
1787 return ret;
1788}
1789
1790LY_ERR
1791lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement,
1792 struct lys_module **result)
1793{
1794 size_t len;
1795 int fd;
1796 char *filepath = NULL, *dot, *rev, *filename;
1797 LYS_INFORMAT format;
1798 struct lys_module *mod = NULL;
1799 LY_ERR ret = LY_SUCCESS;
1800
1801 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
1802 &filepath, &format));
1803 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
1804 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
1805
1806
1807 LOGVRB("Loading schema from \"%s\" file.", filepath);
1808
1809 /* open the file */
1810 fd = open(filepath, O_RDONLY);
1811 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
1812 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
1813
1814 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
1815 close(fd);
1816 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
1817
1818 /* check that name and revision match filename */
1819 filename = strrchr(filepath, '/');
1820 if (!filename) {
1821 filename = filepath;
1822 } else {
1823 filename++;
1824 }
1825 /* name */
1826 len = strlen(mod->parsed->name);
1827 rev = strchr(filename, '@');
1828 dot = strrchr(filepath, '.');
1829 if (strncmp(filename, mod->parsed->name, len) ||
1830 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1831 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1832 }
1833 /* revision */
1834 if (rev) {
1835 len = dot - ++rev;
1836 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
1837 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
1838 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
1839 }
1840 }
1841
1842 if (!mod->parsed->filepath) {
1843 char rpath[PATH_MAX];
1844 if (realpath(filepath, rpath) != NULL) {
1845 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1846 } else {
1847 mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
1848 }
1849 }
1850
1851 *result = mod;
1852
1853 /* success */
1854cleanup:
1855 free(filepath);
1856 return ret;
1857}