blob: 9db0f7755f430594f558964c1a26a8fbde3828dc [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 Krejci87616bb2018-10-31 13:30:52 +010041 LY_ARRAY_INCREMENT(ARRAY_C); \
Radek Krejcice8c1592018-10-29 15:35:51 +010042 RET = FUNC(CTX, &(ARRAY_P)[ITER], OPTIONS, &(ARRAY_C)[ITER]); \
Radek Krejci6d6e4e42018-10-29 13:28:19 +010043 LY_CHECK_GOTO(RET != LY_SUCCESS, GOTO); \
Radek Krejci6d6e4e42018-10-29 13:28:19 +010044 } \
45 }
46
Radek Krejcidd4e8d42018-10-16 14:55:43 +020047static void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict);
48static void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020049
Radek 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 Krejcif8f882a2018-10-31 14:51:15 +0100102 dict = 1; /* includes not present in compiled tree, so the data are not reused there in anyway */
Radek Krejci086c7132018-10-26 15:29:04 +0200103 FREE_STRING(ctx, include->name, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200104 FREE_STRING(ctx, include->dsc, dict);
105 FREE_STRING(ctx, include->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200106 FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200107}
108
109static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200110lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200111{
Radek Krejci151a5b72018-10-19 14:21:44 +0200112 FREE_STRING(ctx, rev->dsc, dict);
113 FREE_STRING(ctx, rev->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200114 FREE_ARRAY(ctx, rev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200115}
116
117static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200118lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200119{
Radek Krejci151a5b72018-10-19 14:21:44 +0200120 FREE_STRING(ctx, ext->name, dict);
121 FREE_STRING(ctx, ext->argument, dict);
122 FREE_STRING(ctx, ext->dsc, dict);
123 FREE_STRING(ctx, ext->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200124 FREE_ARRAY(ctx, ext->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200125}
126
127static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200128lysp_feature_free(struct ly_ctx *ctx, struct lysp_feature *feat, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200129{
Radek Krejci151a5b72018-10-19 14:21:44 +0200130 FREE_STRING(ctx, feat->name, dict);
131 FREE_STRINGS(ctx, feat->iffeatures, 1);
132 FREE_STRING(ctx, feat->dsc, dict);
133 FREE_STRING(ctx, feat->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200134 FREE_ARRAY(ctx, feat->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200135}
136
137static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200138lysp_ident_free(struct ly_ctx *ctx, struct lysp_ident *ident, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200139{
Radek Krejci151a5b72018-10-19 14:21:44 +0200140 FREE_STRING(ctx, ident->name, dict);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200141 FREE_STRINGS(ctx, ident->iffeatures, 1);
Radek Krejci151a5b72018-10-19 14:21:44 +0200142 FREE_STRINGS(ctx, ident->bases, dict);
143 FREE_STRING(ctx, ident->dsc, dict);
144 FREE_STRING(ctx, ident->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200145 FREE_ARRAY(ctx, ident->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200146}
147
148static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200149lysp_restr_free(struct ly_ctx *ctx, struct lysp_restr *restr, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200150{
Radek Krejci151a5b72018-10-19 14:21:44 +0200151 FREE_STRING(ctx, restr->arg, dict);
152 FREE_STRING(ctx, restr->emsg, dict);
153 FREE_STRING(ctx, restr->eapptag, dict);
154 FREE_STRING(ctx, restr->dsc, dict);
155 FREE_STRING(ctx, restr->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200156 FREE_ARRAY(ctx, restr->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200157}
158
159static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200160lysp_type_enum_free(struct ly_ctx *ctx, struct lysp_type_enum *item, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200161{
Radek Krejci151a5b72018-10-19 14:21:44 +0200162 FREE_STRING(ctx, item->name, dict);
163 FREE_STRING(ctx, item->dsc, dict);
164 FREE_STRING(ctx, item->ref, dict);
165 FREE_STRINGS(ctx, item->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200166 FREE_ARRAY(ctx, item->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200167}
168
169static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200170lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200171{
Radek Krejci151a5b72018-10-19 14:21:44 +0200172 FREE_STRING(ctx, type->name, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200173 FREE_MEMBER(ctx, type->range, lysp_restr_free);
174 FREE_MEMBER(ctx, type->length, lysp_restr_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200175 FREE_ARRAY(ctx, type->patterns, lysp_restr_free);
176 FREE_ARRAY(ctx, type->enums, lysp_type_enum_free);
177 FREE_ARRAY(ctx, type->bits, lysp_type_enum_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200178 FREE_STRING(ctx, type->path, dict);
179 FREE_STRINGS(ctx, type->bases, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200180 FREE_ARRAY(ctx, type->types, lysp_type_free);
181 FREE_ARRAY(ctx, type->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200182}
183
184static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200185lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200186{
Radek Krejci151a5b72018-10-19 14:21:44 +0200187 FREE_STRING(ctx, tpdf->name, dict);
188 FREE_STRING(ctx, tpdf->units, dict);
189 FREE_STRING(ctx, tpdf->dflt, dict);
190 FREE_STRING(ctx, tpdf->dsc, dict);
191 FREE_STRING(ctx, tpdf->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200192 FREE_ARRAY(ctx, tpdf->exts, lysp_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200193 lysp_type_free(ctx, &tpdf->type, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200194}
195
196static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200197lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200198{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200199 struct lysp_node *node, *next;
200
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200201 FREE_ARRAY(ctx, inout->musts, lysp_restr_free);
202 FREE_ARRAY(ctx, inout->typedefs, lysp_tpdf_free);
203 FREE_ARRAY(ctx, inout->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200204 LY_LIST_FOR_SAFE(inout->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200205 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200206 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200207 FREE_ARRAY(ctx, inout->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200208
209}
210
211static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200212lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200213{
Radek Krejci151a5b72018-10-19 14:21:44 +0200214 FREE_STRING(ctx, action->name, dict);
215 FREE_STRING(ctx, action->dsc, dict);
216 FREE_STRING(ctx, action->ref, dict);
217 FREE_STRINGS(ctx, action->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200218 FREE_ARRAY(ctx, action->typedefs, lysp_tpdf_free);
219 FREE_ARRAY(ctx, action->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200220 FREE_MEMBER(ctx, action->input, lysp_action_inout_free);
221 FREE_MEMBER(ctx, action->output, lysp_action_inout_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200222 FREE_ARRAY(ctx, action->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200223}
224
225static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200226lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200227{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200228 struct lysp_node *node, *next;
229
Radek Krejci151a5b72018-10-19 14:21:44 +0200230 FREE_STRING(ctx, notif->name, dict);
231 FREE_STRING(ctx, notif->dsc, dict);
232 FREE_STRING(ctx, notif->ref, dict);
233 FREE_STRINGS(ctx, notif->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200234 FREE_ARRAY(ctx, notif->musts, lysp_restr_free);
235 FREE_ARRAY(ctx, notif->typedefs, lysp_tpdf_free);
236 FREE_ARRAY(ctx, notif->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200237 LY_LIST_FOR_SAFE(notif->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200238 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200239 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200240 FREE_ARRAY(ctx, notif->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200241}
242
243static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200244lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200245{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200246 struct lysp_node *node, *next;
247
Radek Krejci151a5b72018-10-19 14:21:44 +0200248 FREE_STRING(ctx, grp->name, dict);
249 FREE_STRING(ctx, grp->dsc, dict);
250 FREE_STRING(ctx, grp->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200251 FREE_ARRAY(ctx, grp->typedefs, lysp_tpdf_free);
252 FREE_ARRAY(ctx, grp->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200253 LY_LIST_FOR_SAFE(grp->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200254 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200255 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200256 FREE_ARRAY(ctx, grp->actions, lysp_action_free);
257 FREE_ARRAY(ctx, grp->notifs, lysp_notif_free);
258 FREE_ARRAY(ctx, grp->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200259}
260
261static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200262lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200263{
Radek Krejci151a5b72018-10-19 14:21:44 +0200264 FREE_STRING(ctx, when->cond, dict);
265 FREE_STRING(ctx, when->dsc, dict);
266 FREE_STRING(ctx, when->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200267 FREE_ARRAY(ctx, when->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200268}
269
270static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200271lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200272{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200273 struct lysp_node *node, *next;
274
Radek Krejci151a5b72018-10-19 14:21:44 +0200275 FREE_STRING(ctx, augment->nodeid, dict);
276 FREE_STRING(ctx, augment->dsc, dict);
277 FREE_STRING(ctx, augment->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200278 FREE_MEMBER(ctx, augment->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200279 FREE_STRINGS(ctx, augment->iffeatures, 1);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200280 LY_LIST_FOR_SAFE(augment->child, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200281 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200282 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200283 FREE_ARRAY(ctx, augment->actions, lysp_action_free);
284 FREE_ARRAY(ctx, augment->notifs, lysp_notif_free);
285 FREE_ARRAY(ctx, augment->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200286}
287
288static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200289lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200290{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200291 struct lysp_deviate_add *add = (struct lysp_deviate_add*)d;
292 struct lysp_deviate_rpl *rpl = (struct lysp_deviate_rpl*)d;
293
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200294 FREE_ARRAY(ctx, d->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200295 switch(d->mod) {
296 case LYS_DEV_NOT_SUPPORTED:
297 /* nothing to do */
298 break;
299 case LYS_DEV_ADD:
300 case LYS_DEV_DELETE: /* compatible for dynamically allocated data */
Radek Krejci151a5b72018-10-19 14:21:44 +0200301 FREE_STRING(ctx, add->units, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200302 FREE_ARRAY(ctx, add->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200303 FREE_STRINGS(ctx, add->uniques, dict);
304 FREE_STRINGS(ctx, add->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200305 break;
306 case LYS_DEV_REPLACE:
307 FREE_MEMBER(ctx, rpl->type, lysp_type_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200308 FREE_STRING(ctx, rpl->units, dict);
309 FREE_STRING(ctx, rpl->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200310 break;
311 default:
312 LOGINT(ctx);
313 break;
314 }
315}
316
317static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200318lysp_deviation_free(struct ly_ctx *ctx, struct lysp_deviation *dev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200319{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200320 struct lysp_deviate *next, *iter;
321
Radek Krejci151a5b72018-10-19 14:21:44 +0200322 FREE_STRING(ctx, dev->nodeid, dict);
323 FREE_STRING(ctx, dev->dsc, dict);
324 FREE_STRING(ctx, dev->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200325 LY_LIST_FOR_SAFE(dev->deviates, next, iter) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200326 lysp_deviate_free(ctx, iter, dict);
Michal Vasko8447f6a2018-10-15 10:56:16 +0200327 free(iter);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200328 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200329 FREE_ARRAY(ctx, dev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200330}
331
332static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200333lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200334{
Radek Krejci151a5b72018-10-19 14:21:44 +0200335 FREE_STRING(ctx, ref->nodeid, dict);
336 FREE_STRING(ctx, ref->dsc, dict);
337 FREE_STRING(ctx, ref->ref, dict);
338 FREE_STRINGS(ctx, ref->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200339 FREE_ARRAY(ctx, ref->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200340 FREE_STRING(ctx, ref->presence, dict);
341 FREE_STRINGS(ctx, ref->dflts, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200342 FREE_ARRAY(ctx, ref->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200343}
344
345static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200346lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200347{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200348 struct lysp_node *child, *next;
349
Radek Krejci151a5b72018-10-19 14:21:44 +0200350 FREE_STRING(ctx, node->name, dict);
351 FREE_STRING(ctx, node->dsc, dict);
352 FREE_STRING(ctx, node->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200353 FREE_MEMBER(ctx, node->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200354 FREE_STRINGS(ctx, node->iffeatures, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200355 FREE_ARRAY(ctx, node->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200356
357 switch(node->nodetype) {
358 case LYS_CONTAINER:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200359 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200360 FREE_STRING(ctx, ((struct lysp_node_container*)node)->presence, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200361 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->typedefs, lysp_tpdf_free);
362 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200363 LY_LIST_FOR_SAFE(((struct lysp_node_container*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200364 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200365 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200366 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->actions, lysp_action_free);
367 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->notifs, lysp_notif_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200368 break;
369 case LYS_LEAF:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200370 FREE_ARRAY(ctx, ((struct lysp_node_leaf*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200371 lysp_type_free(ctx, &((struct lysp_node_leaf*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200372 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->units, dict);
373 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200374 break;
375 case LYS_LEAFLIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200376 FREE_ARRAY(ctx, ((struct lysp_node_leaflist*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200377 lysp_type_free(ctx, &((struct lysp_node_leaflist*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200378 FREE_STRING(ctx, ((struct lysp_node_leaflist*)node)->units, dict);
379 FREE_STRINGS(ctx, ((struct lysp_node_leaflist*)node)->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200380 break;
381 case LYS_LIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200382 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200383 FREE_STRING(ctx, ((struct lysp_node_list*)node)->key, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200384 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->typedefs, lysp_tpdf_free);
385 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200386 LY_LIST_FOR_SAFE(((struct lysp_node_list*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200387 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200388 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200389 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->actions, lysp_action_free);
390 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->notifs, lysp_notif_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200391 FREE_STRINGS(ctx, ((struct lysp_node_list*)node)->uniques, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200392 break;
393 case LYS_CHOICE:
394 LY_LIST_FOR_SAFE(((struct lysp_node_choice*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200395 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200396 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200397 FREE_STRING(ctx, ((struct lysp_node_choice*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200398 break;
399 case LYS_CASE:
400 LY_LIST_FOR_SAFE(((struct lysp_node_case*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200401 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200402 }
403 break;
404 case LYS_ANYDATA:
405 case LYS_ANYXML:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200406 FREE_ARRAY(ctx, ((struct lysp_node_anydata*)node)->musts, lysp_restr_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200407 break;
408 case LYS_USES:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200409 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->refines, lysp_refine_free);
410 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->augments, lysp_augment_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200411 break;
412 default:
413 LOGINT(ctx);
414 }
415
416 free(node);
417}
418
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200419static void
420lysp_module_free_(struct lysp_module *module, int dict)
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200421{
422 struct ly_ctx *ctx;
Radek Krejci6f7feb62018-10-12 15:23:02 +0200423 struct lysp_node *node, *next;
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200424
425 LY_CHECK_ARG_RET(NULL, module,);
426 ctx = module->ctx;
427
Radek Krejci151a5b72018-10-19 14:21:44 +0200428 FREE_STRING(ctx, module->name, dict);
429 FREE_STRING(ctx, module->filepath, dict);
430 FREE_STRING(ctx, module->ns, dict); /* or belongs-to */
431 FREE_STRING(ctx, module->prefix, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200432
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200433 FREE_ARRAY(ctx, module->imports, lysp_import_free);
434 FREE_ARRAY(ctx, module->includes, lysp_include_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200435
Radek Krejci151a5b72018-10-19 14:21:44 +0200436 FREE_STRING(ctx, module->org, dict);
437 FREE_STRING(ctx, module->contact, dict);
438 FREE_STRING(ctx, module->dsc, dict);
439 FREE_STRING(ctx, module->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200440
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200441 FREE_ARRAY(ctx, module->revs, lysp_revision_free);
442 FREE_ARRAY(ctx, module->extensions, lysp_ext_free);
443 FREE_ARRAY(ctx, module->features, lysp_feature_free);
444 FREE_ARRAY(ctx, module->identities, lysp_ident_free);
445 FREE_ARRAY(ctx, module->typedefs, lysp_tpdf_free);
446 FREE_ARRAY(ctx, module->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200447 LY_LIST_FOR_SAFE(module->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200448 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200449 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200450 FREE_ARRAY(ctx, module->augments, lysp_augment_free);
451 FREE_ARRAY(ctx, module->rpcs, lysp_action_free);
452 FREE_ARRAY(ctx, module->notifs, lysp_notif_free);
453 FREE_ARRAY(ctx, module->deviations, lysp_deviation_free);
454 FREE_ARRAY(ctx, module->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200455
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200456 free(module);
457}
458
459API void
460lysp_module_free(struct lysp_module *module)
461{
Radek Krejci151a5b72018-10-19 14:21:44 +0200462 if (module) {
463 lysp_module_free_(module, 1);
464 }
465}
466
467static void
Radek Krejci478020e2018-10-30 16:02:14 +0100468lysc_ext_instance_free(struct ly_ctx *ctx, struct lysc_ext_instance *ext, int dict)
469{
470 FREE_STRING(ctx, ext->argument, dict);
471 FREE_ARRAY(ctx, ext->exts, lysc_ext_instance_free);
472}
473
474static void
Radek Krejci151a5b72018-10-19 14:21:44 +0200475lysc_iffeature_free(struct ly_ctx *UNUSED(ctx), struct lysc_iffeature *iff, int UNUSED(dict))
476{
Radek Krejci2c4e7172018-10-19 15:56:26 +0200477 LY_ARRAY_FREE(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200478 free(iff->expr);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200479}
480
481static void
Radek Krejci478020e2018-10-30 16:02:14 +0100482lysc_import_free(struct ly_ctx *ctx, struct lysc_import *import, int dict)
483{
484 /* imported module is freed directly from the context's list */
485 FREE_STRING(ctx, import->prefix, dict);
486 FREE_ARRAY(ctx, import->exts, lysc_ext_instance_free);
487}
488
489static void
490lysc_ident_free(struct ly_ctx *ctx, struct lysc_ident *ident, int dict)
491{
492 FREE_STRING(ctx, ident->name, dict);
493 FREE_ARRAY(ctx, ident->iffeatures, lysc_iffeature_free);
494 LY_ARRAY_FREE(ident->derived);
495 FREE_ARRAY(ctx, ident->exts, lysc_ext_instance_free);
496}
497
498static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200499lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat, int dict)
500{
Radek Krejci151a5b72018-10-19 14:21:44 +0200501 FREE_STRING(ctx, feat->name, dict);
502 FREE_ARRAY(ctx, feat->iffeatures, lysc_iffeature_free);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200503 LY_ARRAY_FREE(feat->depfeatures);
Radek Krejci478020e2018-10-30 16:02:14 +0100504 FREE_ARRAY(ctx, feat->exts, lysc_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200505}
506
507static void
508lysc_module_free_(struct lysc_module *module, int dict)
509{
510 struct ly_ctx *ctx;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200511
512 LY_CHECK_ARG_RET(NULL, module,);
513 ctx = module->ctx;
514
Radek Krejci151a5b72018-10-19 14:21:44 +0200515 FREE_STRING(ctx, module->name, dict);
516 FREE_STRING(ctx, module->ns, dict);
517 FREE_STRING(ctx, module->prefix, dict);
Radek Krejcif8f882a2018-10-31 14:51:15 +0100518 FREE_STRING(ctx, module->revision, 1);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200519
Radek Krejci478020e2018-10-30 16:02:14 +0100520 FREE_ARRAY(ctx, module->imports, lysc_import_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200521 FREE_ARRAY(ctx, module->features, lysc_feature_free);
Radek Krejci478020e2018-10-30 16:02:14 +0100522 FREE_ARRAY(ctx, module->identities, lysc_ident_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200523
Radek Krejci478020e2018-10-30 16:02:14 +0100524 FREE_ARRAY(ctx, module->exts, lysc_ext_instance_free);
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200525
526 free(module);
527}
Radek Krejci70853c52018-10-15 14:46:16 +0200528
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200529API void
Radek Krejci86d106e2018-10-18 09:53:19 +0200530lysc_module_free(struct lysc_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200531{
Radek Krejci151a5b72018-10-19 14:21:44 +0200532 if (module) {
533 lysc_module_free_(module, 1);
534 }
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200535}
536
Radek Krejci86d106e2018-10-18 09:53:19 +0200537void
538lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejci70853c52018-10-15 14:46:16 +0200539{
Radek Krejci86d106e2018-10-18 09:53:19 +0200540 if (!module) {
541 return;
542 }
Radek Krejci70853c52018-10-15 14:46:16 +0200543
Radek Krejci86d106e2018-10-18 09:53:19 +0200544 lysc_module_free(module->compiled, private_destructor);
545 lysp_module_free(module->parsed);
546 free(module);
547}
548
Radek Krejci151a5b72018-10-19 14:21:44 +0200549struct iff_stack {
550 int size;
551 int index; /* first empty item */
552 uint8_t *stack;
553};
554
Radek Krejci86d106e2018-10-18 09:53:19 +0200555static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200556iff_stack_push(struct iff_stack *stack, uint8_t value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200557{
Radek Krejci151a5b72018-10-19 14:21:44 +0200558 if (stack->index == stack->size) {
559 stack->size += 4;
560 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
561 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
Radek Krejci70853c52018-10-15 14:46:16 +0200562 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200563 stack->stack[stack->index++] = value;
Radek Krejci70853c52018-10-15 14:46:16 +0200564 return LY_SUCCESS;
565}
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200566
Radek Krejci151a5b72018-10-19 14:21:44 +0200567static uint8_t
568iff_stack_pop(struct iff_stack *stack)
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200569{
Radek Krejci151a5b72018-10-19 14:21:44 +0200570 stack->index--;
571 return stack->stack[stack->index];
572}
573
574static void
575iff_stack_clean(struct iff_stack *stack)
576{
577 stack->size = 0;
578 free(stack->stack);
579}
580
581static void
582iff_setop(uint8_t *list, uint8_t op, int pos)
583{
584 uint8_t *item;
585 uint8_t mask = 3;
586
587 assert(pos >= 0);
588 assert(op <= 3); /* max 2 bits */
589
590 item = &list[pos / 4];
591 mask = mask << 2 * (pos % 4);
592 *item = (*item) & ~mask;
593 *item = (*item) | (op << 2 * (pos % 4));
594}
595
596static uint8_t
597iff_getop(uint8_t *list, int pos)
598{
599 uint8_t *item;
600 uint8_t mask = 3, result;
601
602 assert(pos >= 0);
603
604 item = &list[pos / 4];
605 result = (*item) & (mask << 2 * (pos % 4));
606 return result >> 2 * (pos % 4);
607}
608
609#define LYS_IFF_LP 0x04 /* ( */
610#define LYS_IFF_RP 0x08 /* ) */
611
612API int
613lysc_feature_value(const struct lysc_feature *feature)
614{
615 LY_CHECK_ARG_RET(NULL, feature, -1);
616 return feature->flags & LYS_FENABLED ? 1 : 0;
617}
618
619static struct lysc_feature *
620lysc_feature_find(struct lysc_module *mod, const char *name, size_t len)
621{
622 size_t i;
623 struct lysc_feature *f;
624
625 for (i = 0; i < len; ++i) {
626 if (name[i] == ':') {
627 /* we have a prefixed feature */
Radek Krejcice8c1592018-10-29 15:35:51 +0100628 mod = lysc_module_find_prefix(mod, name, i)->compiled;
Radek Krejci151a5b72018-10-19 14:21:44 +0200629 LY_CHECK_RET(!mod, NULL);
630
631 name = &name[i + 1];
632 len = len - i - 1;
633 }
634 }
635
636 /* we have the correct module, get the feature */
637 LY_ARRAY_FOR(mod->features, i) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200638 f = &mod->features[i];
Radek Krejci151a5b72018-10-19 14:21:44 +0200639 if (!strncmp(f->name, name, len) && f->name[len] == '\0') {
640 return f;
641 }
642 }
643
644 return NULL;
645}
646
647static int
648lysc_iffeature_value_(const struct lysc_iffeature *iff, int *index_e, int *index_f)
649{
650 uint8_t op;
651 int a, b;
652
653 op = iff_getop(iff->expr, *index_e);
654 (*index_e)++;
655
656 switch (op) {
657 case LYS_IFF_F:
658 /* resolve feature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200659 return lysc_feature_value(iff->features[(*index_f)++]);
Radek Krejci151a5b72018-10-19 14:21:44 +0200660 case LYS_IFF_NOT:
661 /* invert result */
662 return lysc_iffeature_value_(iff, index_e, index_f) ? 0 : 1;
663 case LYS_IFF_AND:
664 case LYS_IFF_OR:
665 a = lysc_iffeature_value_(iff, index_e, index_f);
666 b = lysc_iffeature_value_(iff, index_e, index_f);
667 if (op == LYS_IFF_AND) {
668 return a && b;
669 } else { /* LYS_IFF_OR */
670 return a || b;
671 }
672 }
673
674 return 0;
675}
676
677API int
678lysc_iffeature_value(const struct lysc_iffeature *iff)
679{
680 int index_e = 0, index_f = 0;
681
682 LY_CHECK_ARG_RET(NULL, iff, -1);
683
684 if (iff->expr) {
685 return lysc_iffeature_value_(iff, &index_e, &index_f);
686 }
687 return 0;
688}
689
690/*
691 * op: 1 - enable, 0 - disable
692 */
693/**
694 * @brief Enable/Disable the specified feature in the module.
695 *
696 * If the feature is already set to the desired value, LY_SUCCESS is returned.
697 * By changing the feature, also all the feature which depends on it via their
698 * if-feature statements are again evaluated (disabled if a if-feature statemen
699 * evaluates to false).
700 *
701 * @param[in] mod Compiled module where to set (search for) the feature.
702 * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
703 * set all the features in the module.
704 * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
705 * @return LY_ERR value.
706 */
707static LY_ERR
708lys_feature_change(const struct lysc_module *mod, const char *name, int value)
709{
710 int all = 0;
711 unsigned int u;
712 struct lysc_feature *f, **df;
713 struct lysc_iffeature *iff;
714 struct ly_set *changed;
715
716 if (!mod->features) {
717 LOGERR(mod->ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
718 return LY_EINVAL;
719 }
720
721 if (!strcmp(name, "*")) {
722 /* enable all */
723 all = 1;
724 }
725 changed = ly_set_new();
726
727 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200728 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200729 if (all || !strcmp(f->name, name)) {
730 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
731 if (all) {
732 /* skip already set features */
733 continue;
734 } else {
735 /* feature already set correctly */
736 ly_set_free(changed, NULL);
737 return LY_SUCCESS;
738 }
739 }
740
741 if (value) { /* enable */
742 /* check referenced features if they are enabled */
743 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
744 if (!lysc_iffeature_value(iff)) {
745 if (all) {
746 LOGWRN(mod->ctx,
747 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
748 f->name);
749 goto next;
750 } else {
751 LOGERR(mod->ctx, LY_EDENIED,
752 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
753 f->name);
754 ly_set_free(changed, NULL);
755 return LY_EDENIED;
756 }
757 }
758 }
759 /* enable the feature */
760 f->flags |= LYS_FENABLED;
761 } else { /* disable */
762 /* disable the feature */
763 f->flags &= ~LYS_FENABLED;
764 }
765
766 /* remember the changed feature */
767 ly_set_add(changed, f, LY_SET_OPT_USEASLIST);
768
769 if (!all) {
770 /* stop in case changing a single feature */
771 break;
772 }
773 }
774next:
775 ;
776 }
777
778 if (!all && !changed->count) {
779 LOGERR(mod->ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
780 ly_set_free(changed, NULL);
781 return LY_EINVAL;
782 }
783
784 /* reflect change(s) in the dependent features */
785 for (u = 0; u < changed->count; ++u) {
786 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
787 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
788 * is not done - by default, features are disabled and must be explicitely enabled. */
789 f = changed->objs[u];
790 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature*, df) {
791 if (!((*df)->flags & LYS_FENABLED)) {
792 /* not enabled, nothing to do */
793 continue;
794 }
795 /* check the feature's if-features which could change by the previous change of our feature */
796 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
797 if (!lysc_iffeature_value(iff)) {
798 /* the feature must be disabled now */
799 (*df)->flags &= ~LYS_FENABLED;
800 /* add the feature into the list of changed features */
801 ly_set_add(changed, *df, LY_SET_OPT_USEASLIST);
802 break;
803 }
804 }
805 }
806 }
807
808 ly_set_free(changed, NULL);
809 return LY_SUCCESS;
810}
811
812API LY_ERR
813lys_feature_enable(struct lys_module *module, const char *feature)
814{
815 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
816
817 return lys_feature_change(module->compiled, feature, 1);
818}
819
820API LY_ERR
821lys_feature_disable(struct lys_module *module, const char *feature)
822{
823 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
824
825 return lys_feature_change(module->compiled, feature, 0);
826}
827
828API int
829lys_feature_value(const struct lys_module *module, const char *feature)
830{
831 struct lysc_feature *f;
832 struct lysc_module *mod;
833 unsigned int u;
834
835 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
836 mod = module->compiled;
837
838 /* search for the specified feature */
839 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200840 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200841 if (!strcmp(f->name, feature)) {
842 if (f->flags & LYS_FENABLED) {
843 return 1;
844 } else {
845 return 0;
846 }
847 }
848 }
849
850 /* feature definition not found */
851 return -1;
852}
853
854static LY_ERR
Radek Krejcice8c1592018-10-29 15:35:51 +0100855lys_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 +0200856{
Radek Krejcice8c1592018-10-29 15:35:51 +0100857 const char *name;
858 unsigned int u;
859 const struct lys_module *mod;
860 struct lysp_ext *edef;
861
862 if (options & LYSC_OPT_FREE_SP) {
863 /* just switch the pointers */
864 ext->argument = ext_p->argument;
865 } else {
866 /* keep refcounts correct for lysp_module_free() */
867 ext->argument = lydict_insert(ctx->mod->ctx, ext_p->argument, 0);
868 }
869 ext->insubstmt = ext_p->insubstmt;
870 ext->insubstmt_index = ext_p->insubstmt_index;
871
872 /* get module where the extension definition should be placed */
873 for (u = 0; ext_p->name[u] != ':'; ++u);
874 mod = lysc_module_find_prefix(ctx->mod, ext_p->name, u);
875 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
876 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, ext_p->name),
877 LY_EVALID);
878 LY_CHECK_ERR_RET(!mod->parsed->extensions,
879 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
880 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
881 ext_p->name, mod->parsed->name),
882 LY_EVALID);
883 name = &ext_p->name[u + 1];
884 /* find the extension definition there */
885 for (ext = NULL, u = 0; u < LY_ARRAY_SIZE(mod->parsed->extensions); ++u) {
886 if (!strcmp(name, mod->parsed->extensions[u].name)) {
887 edef = &mod->parsed->extensions[u];
888 break;
889 }
890 }
891 LY_CHECK_ERR_RET(!edef, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
892 "Extension definition of extension instance \"%s\" not found.", ext_p->name),
893 LY_EVALID);
894 /* TODO plugins */
895
896 return LY_SUCCESS;
897}
898
899/**
900 * @param[in] parent Provided only in case the if-feature is inside
901 */
902static LY_ERR
903lys_compile_iffeature(struct lysc_ctx *ctx, const char **value, int UNUSED(options), struct lysc_iffeature *iff)
904{
905 const char *c = *value;
Radek Krejci151a5b72018-10-19 14:21:44 +0200906 int r, rc = EXIT_FAILURE;
907 int i, j, last_not, checkversion = 0;
908 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
909 uint8_t op;
910 struct iff_stack stack = {0, 0, NULL};
Radek Krejcice8c1592018-10-29 15:35:51 +0100911 struct lysc_feature *f;
Radek Krejci151a5b72018-10-19 14:21:44 +0200912
913 assert(c);
914
915 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
916 for (i = j = last_not = 0; c[i]; i++) {
917 if (c[i] == '(') {
918 j++;
919 checkversion = 1;
920 continue;
921 } else if (c[i] == ')') {
922 j--;
923 continue;
924 } else if (isspace(c[i])) {
925 checkversion = 1;
926 continue;
927 }
928
929 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
930 if (c[i + r] == '\0') {
931 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100932 "Invalid value \"%s\" of if-feature - unexpected end of expression.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200933 return LY_EVALID;
934 } else if (!isspace(c[i + r])) {
935 /* feature name starting with the not/and/or */
936 last_not = 0;
937 f_size++;
938 } else if (c[i] == 'n') { /* not operation */
939 if (last_not) {
940 /* double not */
941 expr_size = expr_size - 2;
942 last_not = 0;
943 } else {
944 last_not = 1;
945 }
946 } else { /* and, or */
947 f_exp++;
948 /* not a not operation */
949 last_not = 0;
950 }
951 i += r;
952 } else {
953 f_size++;
954 last_not = 0;
955 }
956 expr_size++;
957
958 while (!isspace(c[i])) {
959 if (!c[i] || c[i] == ')') {
960 i--;
961 break;
962 }
963 i++;
964 }
965 }
966 if (j || f_exp != f_size) {
967 /* not matching count of ( and ) */
968 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100969 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200970 return LY_EVALID;
971 }
972
973 if (checkversion || expr_size > 1) {
974 /* check that we have 1.1 module */
975 if (ctx->mod->version != LYS_VERSION_1_1) {
976 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100977 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200978 return LY_EVALID;
979 }
980 }
981
982 /* allocate the memory */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200983 LY_ARRAY_CREATE_RET(ctx->mod->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200984 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +0200985 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200986 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->mod->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +0200987
Radek Krejci151a5b72018-10-19 14:21:44 +0200988 stack.size = expr_size;
989 f_size--; expr_size--; /* used as indexes from now */
990
991 for (i--; i >= 0; i--) {
992 if (c[i] == ')') {
993 /* push it on stack */
994 iff_stack_push(&stack, LYS_IFF_RP);
995 continue;
996 } else if (c[i] == '(') {
997 /* pop from the stack into result all operators until ) */
998 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
999 iff_setop(iff->expr, op, expr_size--);
1000 }
1001 continue;
1002 } else if (isspace(c[i])) {
1003 continue;
1004 }
1005
1006 /* end of operator or operand -> find beginning and get what is it */
1007 j = i + 1;
1008 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1009 i--;
1010 }
1011 i++; /* go back by one step */
1012
1013 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
1014 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1015 /* double not */
1016 iff_stack_pop(&stack);
1017 } else {
1018 /* not has the highest priority, so do not pop from the stack
1019 * as in case of AND and OR */
1020 iff_stack_push(&stack, LYS_IFF_NOT);
1021 }
1022 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
1023 /* as for OR - pop from the stack all operators with the same or higher
1024 * priority and store them to the result, then push the AND to the stack */
1025 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1026 op = iff_stack_pop(&stack);
1027 iff_setop(iff->expr, op, expr_size--);
1028 }
1029 iff_stack_push(&stack, LYS_IFF_AND);
1030 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
1031 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1032 op = iff_stack_pop(&stack);
1033 iff_setop(iff->expr, op, expr_size--);
1034 }
1035 iff_stack_push(&stack, LYS_IFF_OR);
1036 } else {
1037 /* feature name, length is j - i */
1038
1039 /* add it to the expression */
1040 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
1041
1042 /* now get the link to the feature definition */
1043 f = lysc_feature_find(ctx->mod, &c[i], j - i);
1044 LY_CHECK_ERR_GOTO(!f,
1045 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001046 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
Radek Krejci87616bb2018-10-31 13:30:52 +01001047 rc = LY_EVALID,
Radek Krejci151a5b72018-10-19 14:21:44 +02001048 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +02001049 iff->features[f_size] = f;
1050 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +02001051 f_size--;
1052 }
1053 }
1054 while (stack.index) {
1055 op = iff_stack_pop(&stack);
1056 iff_setop(iff->expr, op, expr_size--);
1057 }
1058
1059 if (++expr_size || ++f_size) {
1060 /* not all expected operators and operands found */
1061 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001062 "Invalid value \"%s\" of if-feature - processing error.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001063 rc = LY_EINT;
1064 } else {
1065 rc = LY_SUCCESS;
1066 }
1067
1068error:
1069 /* cleanup */
1070 iff_stack_clean(&stack);
1071
1072 return rc;
1073}
1074
1075static LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001076lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
1077{
Radek Krejcice8c1592018-10-29 15:35:51 +01001078 unsigned int u;
Radek Krejcif8f882a2018-10-31 14:51:15 +01001079 struct lys_module *mod = NULL;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001080 struct lysc_module *comp;
Radek Krejcice8c1592018-10-29 15:35:51 +01001081 LY_ERR ret = LY_SUCCESS;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001082
1083 if (options & LYSC_OPT_FREE_SP) {
1084 /* just switch the pointers */
1085 imp->prefix = imp_p->prefix;
1086 } else {
1087 /* keep refcounts correct for lysp_module_free() */
1088 imp->prefix = lydict_insert(ctx->mod->ctx, imp_p->prefix, 0);
1089 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001090 COMPILE_ARRAY_GOTO(ctx, imp_p->exts, imp->exts, options, u, lys_compile_ext, ret, done);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001091 imp->module = imp_p->module;
1092
1093 /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
1094 * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
1095 if (!imp->module->parsed) {
1096 comp = imp->module->compiled;
1097 /* try to get filepath from the compiled version */
1098 if (comp->filepath) {
1099 mod = (struct lys_module*)lys_parse_path(ctx->mod->ctx, comp->filepath,
1100 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
1101 if (mod != imp->module) {
1102 LOGERR(ctx->mod->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
1103 comp->filepath, comp->name);
1104 mod = NULL;
1105 }
1106 }
1107 if (!mod) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001108 if (lysp_load_module(ctx->mod->ctx, comp->name, comp->revision, 0, 1, &mod)) {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001109 LOGERR(ctx->mod->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
1110 comp->name, ctx->mod->name);
1111 return LY_ENOTFOUND;
1112 }
1113 }
1114 } else if (!imp->module->compiled) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001115 return lys_compile(imp->module, options);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001116 }
1117
Radek Krejcice8c1592018-10-29 15:35:51 +01001118done:
1119 return ret;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001120}
1121
1122static LY_ERR
Radek Krejci2a408df2018-10-29 16:32:26 +01001123lys_compile_identity(struct lysc_ctx *ctx, struct lysp_ident *ident_p, int options, struct lysc_ident *ident)
1124{
1125 unsigned int u;
1126 LY_ERR ret = LY_SUCCESS;
1127
1128 if (options & LYSC_OPT_FREE_SP) {
1129 /* just switch the pointers */
1130 ident->name = ident_p->name;
1131 } else {
1132 /* keep refcounts correct for lysp_module_free() */
1133 ident->name = lydict_insert(ctx->mod->ctx, ident_p->name, 0);
1134 }
1135 COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, options, u, lys_compile_iffeature, ret, done);
1136 /* backlings (derived) can be added no sooner than when all the identities in the current module are present */
1137 COMPILE_ARRAY_GOTO(ctx, ident_p->exts, ident->exts, options, u, lys_compile_ext, ret, done);
1138 ident->flags = ident_p->flags;
1139
1140done:
1141 return ret;
1142}
1143
1144static LY_ERR
1145lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1146{
1147 unsigned int i, u, v;
1148 const char *s, *name;
1149 struct lysc_module *mod;
1150 struct lysc_ident **dident;
1151
1152 for (i = 0; i < LY_ARRAY_SIZE(idents_p); ++i) {
Radek Krejci478020e2018-10-30 16:02:14 +01001153 if (!idents_p[i].bases) {
1154 continue;
1155 }
Radek Krejci2a408df2018-10-29 16:32:26 +01001156 for (u = 0; u < LY_ARRAY_SIZE(idents_p[i].bases); ++u) {
1157 s = strchr(idents_p[i].bases[u], ':');
1158 if (s) {
1159 /* prefixed identity */
1160 name = &s[1];
1161 mod = lysc_module_find_prefix(ctx->mod, idents_p[i].bases[u], s - idents_p[i].bases[u])->compiled;
1162 } else {
1163 name = idents_p[i].bases[u];
1164 mod = ctx->mod;
1165 }
1166 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1167 "Invalid prefix used for base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1168 LY_EVALID);
1169 if (mod->identities) {
1170 for (v = 0; v < LY_ARRAY_SIZE(mod->identities); ++v) {
1171 if (!strcmp(name, mod->identities[v].name)) {
1172 /* we have match! store the backlink */
1173 LY_ARRAY_NEW_RET(ctx->mod->ctx, mod->identities[v].derived, dident, LY_EMEM);
1174 *dident = &idents[i];
1175 break;
1176 }
1177 }
1178 }
1179 LY_CHECK_ERR_RET(!dident, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1180 "Unable to find base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1181 LY_EVALID);
1182 }
1183 }
1184 return LY_SUCCESS;
1185}
1186
1187static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +02001188lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
1189{
Radek Krejcice8c1592018-10-29 15:35:51 +01001190 unsigned int u, v;
1191 LY_ERR ret = LY_SUCCESS;
1192 struct lysc_feature **df;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001193
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001194 if (options & LYSC_OPT_FREE_SP) {
1195 /* just switch the pointers */
1196 feature->name = feature_p->name;
1197 } else {
1198 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001199 feature->name = lydict_insert(ctx->mod->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001200 }
1201 feature->flags = feature_p->flags;
1202
Radek Krejcice8c1592018-10-29 15:35:51 +01001203 COMPILE_ARRAY_GOTO(ctx, feature_p->exts, feature->exts, options, u, lys_compile_ext, ret, done);
1204 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, options, u, lys_compile_iffeature, ret, done);
1205 if (feature->iffeatures) {
1206 for (u = 0; u < LY_ARRAY_SIZE(feature->iffeatures); ++u) {
1207 if (feature->iffeatures[u].features) {
1208 for (v = 0; v < LY_ARRAY_SIZE(feature->iffeatures[u].features); ++v) {
1209 /* add itself into the dependants list */
1210 LY_ARRAY_NEW_RET(ctx->mod->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
1211 *df = feature;
1212 }
1213 /* TODO check for circular dependency */
1214 }
Radek Krejci151a5b72018-10-19 14:21:44 +02001215 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001216 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001217done:
1218 return ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001219}
1220
1221LY_ERR
Radek Krejcif8f882a2018-10-31 14:51:15 +01001222lys_compile(const struct lys_module *mod, int options)
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001223{
Radek Krejci86d106e2018-10-18 09:53:19 +02001224 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001225 struct lysc_module *mod_c;
Radek Krejcif8f882a2018-10-31 14:51:15 +01001226 struct lysp_module *sp;
Radek Krejci151a5b72018-10-19 14:21:44 +02001227 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001228 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001229
Radek Krejcif8f882a2018-10-31 14:51:15 +01001230 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, mod->parsed->ctx, LY_EINVAL);
1231 sp = mod->parsed;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001232
1233 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001234 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 +02001235 return LY_EINVAL;
1236 }
1237
Radek Krejcif8f882a2018-10-31 14:51:15 +01001238 ctx.mod = ((struct lys_module*)mod)->compiled = mod_c = calloc(1, sizeof *mod_c);
Radek Krejci86d106e2018-10-18 09:53:19 +02001239 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1240 mod_c->ctx = sp->ctx;
1241 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001242
1243 if (options & LYSC_OPT_FREE_SP) {
1244 /* just switch the pointers */
1245 mod_c->name = sp->name;
1246 mod_c->ns = sp->ns;
1247 mod_c->prefix = sp->prefix;
1248 } else {
1249 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001250 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1251 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1252 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001253 }
Radek Krejcif8f882a2018-10-31 14:51:15 +01001254 if (sp->revs) {
1255 mod_c->revision = lydict_insert(sp->ctx, sp->revs[0].date, 10);
1256 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001257 COMPILE_ARRAY_GOTO(&ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
1258 COMPILE_ARRAY_GOTO(&ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
Radek Krejci2a408df2018-10-29 16:32:26 +01001259 COMPILE_ARRAY_GOTO(&ctx, sp->identities, mod_c->identities, options, u, lys_compile_identity, ret, error);
1260 if (sp->identities) {
1261 LY_CHECK_RET(lys_compile_identities_derived(&ctx, sp->identities, mod_c->identities));
1262 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001263
1264 COMPILE_ARRAY_GOTO(&ctx, sp->exts, mod_c->exts, options, u, lys_compile_ext, ret, error);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001265
1266 if (options & LYSC_OPT_FREE_SP) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001267 lysp_module_free_(mod->parsed, 0);
1268 ((struct lys_module*)mod)->parsed = NULL;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001269 }
1270
Radek Krejcif8f882a2018-10-31 14:51:15 +01001271 ((struct lys_module*)mod)->compiled = mod_c;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001272 return LY_SUCCESS;
1273
1274error:
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001275 lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
Radek Krejcif8f882a2018-10-31 14:51:15 +01001276 ((struct lys_module*)mod)->compiled = NULL;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001277 return ret;
1278}
Radek Krejci86d106e2018-10-18 09:53:19 +02001279
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001280static void
Radek Krejci086c7132018-10-26 15:29:04 +02001281lys_latest_switch(struct lys_module *old, struct lysp_module *new)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001282{
Radek Krejci086c7132018-10-26 15:29:04 +02001283 if (old->parsed) {
1284 new->latest_revision = old->parsed->latest_revision;
1285 old->parsed->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001286 }
Radek Krejci086c7132018-10-26 15:29:04 +02001287 if (old->compiled) {
1288 new->latest_revision = old->parsed->latest_revision;
1289 old->compiled->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001290 }
1291}
1292
Radek Krejcid33273d2018-10-25 14:55:52 +02001293struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001294lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
1295{
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001296 struct lys_module *mod = NULL, *latest, *mod_dup;
Radek Krejcid33273d2018-10-25 14:55:52 +02001297 struct lysp_module *latest_p;
Radek Krejci086c7132018-10-26 15:29:04 +02001298 struct lysp_import *imp;
1299 struct lysp_include *inc;
Radek Krejci86d106e2018-10-18 09:53:19 +02001300 LY_ERR ret;
Radek Krejci086c7132018-10-26 15:29:04 +02001301 unsigned int u, i;
Radek Krejci86d106e2018-10-18 09:53:19 +02001302
1303 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1304
1305 mod = calloc(1, sizeof *mod);
1306 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1307
1308 switch (format) {
1309 case LYS_IN_YIN:
1310 /* TODO not yet supported
1311 mod = yin_read_module(ctx, data, revision, implement);
1312 */
1313 break;
1314 case LYS_IN_YANG:
1315 ret = yang_parse(ctx, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001316 break;
1317 default:
1318 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1319 break;
1320 }
Radek Krejcifaa1eac2018-10-30 14:34:55 +01001321 LY_CHECK_ERR_RET(ret, free(mod), NULL);
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001322
1323 /* make sure that the newest revision is at position 0 */
1324 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001325
1326 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001327 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001328 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1329 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
1330 lys_module_free(mod, NULL);
1331 return NULL;
1332 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001333 mod->parsed->implemented = 1;
1334 }
1335
1336 if (revision) {
1337 /* check revision of the parsed model */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001338 if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].date)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001339 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
Radek Krejcib7db73a2018-10-24 14:18:40 +02001340 mod->parsed->name, mod->parsed->revs[0].date, revision);
1341 lys_module_free(mod, NULL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001342 return NULL;
1343 }
1344 }
1345
Radek Krejcid33273d2018-10-25 14:55:52 +02001346 if (mod->parsed->submodule) { /* submodule */
1347 /* decide the latest revision */
1348 latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
1349 if (latest_p) {
1350 if (mod->parsed->revs) {
1351 if (!latest_p->revs) {
1352 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001353 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001354 latest_p->latest_revision = 0;
1355 } else {
1356 if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
Radek Krejci086c7132018-10-26 15:29:04 +02001357 mod->parsed->latest_revision = revision ? latest_p->latest_revision : 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001358 latest_p->latest_revision = 0;
1359 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001360 }
1361 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001362 } else {
Radek Krejci086c7132018-10-26 15:29:04 +02001363 mod->parsed->latest_revision = revision ? 1 : 2;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001364 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001365 } else { /* module */
1366 /* check for duplicity in the context */
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001367 mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
1368 if (mod_dup) {
1369 if (mod_dup->parsed) {
1370 /* error */
1371 if (mod->parsed->revs) {
1372 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1373 mod->parsed->name, mod->parsed->revs[0].date);
1374 } else {
1375 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1376 mod->parsed->name);
1377 }
1378 lys_module_free(mod, NULL);
1379 return NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +02001380 } else {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001381 /* add the parsed data to the currently compiled-only module in the context */
1382 mod_dup->parsed = mod->parsed;
1383 free(mod);
1384 mod = mod_dup;
1385 goto finish_parsing;
Radek Krejcid33273d2018-10-25 14:55:52 +02001386 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001387 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001388
1389#if 0
1390 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1391 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1392 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1393 * the anotation definitions available in the internal schema structure. There is another hack in schema
1394 * printers to do not print this internally added annotation. */
1395 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1396 if (lyp_add_ietf_netconf_annotations(mod)) {
1397 lys_free(mod, NULL, 1, 1);
1398 return NULL;
1399 }
1400 }
1401#endif
1402
Radek Krejcid33273d2018-10-25 14:55:52 +02001403 /* decide the latest revision */
1404 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1405 if (latest) {
1406 if (mod->parsed->revs) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001407 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revision)) {
Radek Krejcid33273d2018-10-25 14:55:52 +02001408 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001409 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001410 } else {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001411 if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revision) > 0) {
Radek Krejci086c7132018-10-26 15:29:04 +02001412 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001413 }
1414 }
1415 }
1416 } else {
1417 mod->parsed->latest_revision = 1;
1418 }
1419
1420 /* add into context */
1421 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1422
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001423finish_parsing:
Radek Krejci086c7132018-10-26 15:29:04 +02001424 /* resolve imports and includes */
1425 mod->parsed->parsing = 1;
1426 LY_ARRAY_FOR(mod->parsed->imports, u) {
1427 imp = &mod->parsed->imports[u];
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001428 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 +02001429 ly_set_rm(&ctx->list, mod, NULL);
1430 lys_module_free(mod, NULL);
1431 return NULL;
1432 }
1433 /* check for importing the same module twice */
1434 for (i = 0; i < u; ++i) {
1435 if (imp->module == mod->parsed->imports[i].module) {
1436 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
1437 ly_set_rm(&ctx->list, mod, NULL);
1438 lys_module_free(mod, NULL);
1439 return NULL;
1440 }
1441 }
1442 }
1443 LY_ARRAY_FOR(mod->parsed->includes, u) {
1444 inc = &mod->parsed->includes[u];
1445 if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
1446 ly_set_rm(&ctx->list, mod, NULL);
1447 lys_module_free(mod, NULL);
1448 return NULL;
1449 }
1450 }
1451 mod->parsed->parsing = 0;
Radek Krejcid33273d2018-10-25 14:55:52 +02001452 }
1453
Radek Krejci86d106e2018-10-18 09:53:19 +02001454 return mod;
1455}
1456
1457API const struct lys_module *
1458lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1459{
Radek Krejcid33273d2018-10-25 14:55:52 +02001460 struct lys_module *result;
1461
1462 result = lys_parse_mem_(ctx, data, format, NULL, 1);
1463 if (result && result->parsed->submodule) {
1464 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1465 result->parsed->name);
1466 lys_module_free(result, NULL);
1467 return NULL;
1468 }
1469 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001470}
1471
1472static void
1473lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1474{
1475#ifdef __APPLE__
1476 char path[MAXPATHLEN];
1477#else
1478 int len;
1479 char path[PATH_MAX], proc_path[32];
1480#endif
1481
1482#ifdef __APPLE__
1483 if (fcntl(fd, F_GETPATH, path) != -1) {
1484 *filename = lydict_insert(ctx, path, 0);
1485 }
1486#else
1487 /* get URI if there is /proc */
1488 sprintf(proc_path, "/proc/self/fd/%d", fd);
1489 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1490 *filename = lydict_insert(ctx, path, len);
1491 }
1492#endif
1493}
1494
Radek Krejcid33273d2018-10-25 14:55:52 +02001495struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001496lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const char *revision, int implement)
1497{
Radek Krejcid33273d2018-10-25 14:55:52 +02001498 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001499 size_t length;
1500 char *addr;
1501
1502 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1503 if (fd < 0) {
1504 LOGARG(ctx, fd);
1505 return NULL;
1506 }
1507
1508 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1509 if (!addr) {
1510 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1511 return NULL;
1512 }
1513
1514 mod = lys_parse_mem_(ctx, addr, format, revision, implement);
1515 ly_munmap(addr, length);
1516
1517 if (mod && !mod->parsed->filepath) {
1518 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1519 }
1520
1521 return mod;
1522}
1523
1524API const struct lys_module *
1525lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1526{
Radek Krejcid33273d2018-10-25 14:55:52 +02001527 struct lys_module *result;
1528
1529 result = lys_parse_fd_(ctx, fd, format, NULL, 1);
1530 if (result && result->parsed->submodule) {
1531 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1532 result->parsed->name);
1533 lys_module_free(result, NULL);
1534 return NULL;
1535 }
1536 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001537}
1538
Radek Krejcid33273d2018-10-25 14:55:52 +02001539struct lys_module *
1540lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const char *revision, int implement)
Radek Krejci86d106e2018-10-18 09:53:19 +02001541{
1542 int fd;
Radek Krejcid33273d2018-10-25 14:55:52 +02001543 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001544 const char *rev, *dot, *filename;
1545 size_t len;
1546
1547 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1548
1549 fd = open(path, O_RDONLY);
1550 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1551
Radek Krejcid33273d2018-10-25 14:55:52 +02001552 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
Radek Krejci86d106e2018-10-18 09:53:19 +02001553 close(fd);
1554 LY_CHECK_RET(!mod, NULL);
1555
1556 /* check that name and revision match filename */
1557 filename = strrchr(path, '/');
1558 if (!filename) {
1559 filename = path;
1560 } else {
1561 filename++;
1562 }
1563 rev = strchr(filename, '@');
1564 dot = strrchr(filename, '.');
1565
1566 /* name */
1567 len = strlen(mod->parsed->name);
1568 if (strncmp(filename, mod->parsed->name, len) ||
1569 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1570 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1571 }
1572 if (rev) {
1573 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001574 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001575 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001576 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001577 }
1578 }
1579
1580 if (!mod->parsed->filepath) {
1581 /* store URI */
1582 char rpath[PATH_MAX];
1583 if (realpath(path, rpath) != NULL) {
1584 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1585 } else {
1586 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1587 }
1588 }
1589
1590 return mod;
1591}
1592
Radek Krejcid33273d2018-10-25 14:55:52 +02001593API const struct lys_module *
1594lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1595{
1596 struct lys_module *result;
1597
1598 result = lys_parse_path_(ctx, path, format, NULL, 1);
1599 if (result && result->parsed->submodule) {
1600 LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
1601 path, result->parsed->name);
1602 lys_module_free(result, NULL);
1603 return NULL;
1604 }
1605 return result;
1606}
1607
1608API LY_ERR
1609lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
1610 char **localfile, LYS_INFORMAT *format)
1611{
1612 size_t len, flen, match_len = 0, dir_len;
1613 int i, implicit_cwd = 0, ret = EXIT_FAILURE;
1614 char *wd, *wn = NULL;
1615 DIR *dir = NULL;
1616 struct dirent *file;
1617 char *match_name = NULL;
1618 LYS_INFORMAT format_aux, match_format = 0;
1619 struct ly_set *dirs;
1620 struct stat st;
1621
1622 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1623
1624 /* start to fill the dir fifo with the context's search path (if set)
1625 * and the current working directory */
1626 dirs = ly_set_new();
1627 if (!dirs) {
1628 LOGMEM(NULL);
1629 return EXIT_FAILURE;
1630 }
1631
1632 len = strlen(name);
1633 if (cwd) {
1634 wd = get_current_dir_name();
1635 if (!wd) {
1636 LOGMEM(NULL);
1637 goto cleanup;
1638 } else {
1639 /* add implicit current working directory (./) to be searched,
1640 * this directory is not searched recursively */
1641 if (ly_set_add(dirs, wd, 0) == -1) {
1642 goto cleanup;
1643 }
1644 implicit_cwd = 1;
1645 }
1646 }
1647 if (searchpaths) {
1648 for (i = 0; searchpaths[i]; i++) {
1649 /* check for duplicities with the implicit current working directory */
1650 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1651 implicit_cwd = 0;
1652 continue;
1653 }
1654 wd = strdup(searchpaths[i]);
1655 if (!wd) {
1656 LOGMEM(NULL);
1657 goto cleanup;
1658 } else if (ly_set_add(dirs, wd, 0) == -1) {
1659 goto cleanup;
1660 }
1661 }
1662 }
1663 wd = NULL;
1664
1665 /* start searching */
1666 while (dirs->count) {
1667 free(wd);
1668 free(wn); wn = NULL;
1669
1670 dirs->count--;
1671 wd = (char *)dirs->objs[dirs->count];
1672 dirs->objs[dirs->count] = NULL;
1673 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1674
1675 if (dir) {
1676 closedir(dir);
1677 }
1678 dir = opendir(wd);
1679 dir_len = strlen(wd);
1680 if (!dir) {
1681 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1682 } else {
1683 while ((file = readdir(dir))) {
1684 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1685 /* skip . and .. */
1686 continue;
1687 }
1688 free(wn);
1689 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1690 LOGMEM(NULL);
1691 goto cleanup;
1692 }
1693 if (stat(wn, &st) == -1) {
1694 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1695 file->d_name, wd, strerror(errno));
1696 continue;
1697 }
1698 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1699 /* we have another subdirectory in searchpath to explore,
1700 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1701 if (ly_set_add(dirs, wn, 0) == -1) {
1702 goto cleanup;
1703 }
1704 /* continue with the next item in current directory */
1705 wn = NULL;
1706 continue;
1707 } else if (!S_ISREG(st.st_mode)) {
1708 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1709 continue;
1710 }
1711
1712 /* here we know that the item is a file which can contain a module */
1713 if (strncmp(name, file->d_name, len) ||
1714 (file->d_name[len] != '.' && file->d_name[len] != '@')) {
1715 /* different filename than the module we search for */
1716 continue;
1717 }
1718
1719 /* get type according to filename suffix */
1720 flen = strlen(file->d_name);
1721 if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1722 format_aux = LYS_IN_YIN;
1723 } else if (!strcmp(&file->d_name[flen - 5], ".yang")) {
1724 format_aux = LYS_IN_YANG;
1725 } else {
1726 /* not supportde suffix/file format */
1727 continue;
1728 }
1729
1730 if (revision) {
1731 /* we look for the specific revision, try to get it from the filename */
1732 if (file->d_name[len] == '@') {
1733 /* check revision from the filename */
1734 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1735 /* another revision */
1736 continue;
1737 } else {
1738 /* exact revision */
1739 free(match_name);
1740 match_name = wn;
1741 wn = NULL;
1742 match_len = dir_len + 1 + len;
1743 match_format = format_aux;
1744 goto success;
1745 }
1746 } else {
1747 /* continue trying to find exact revision match, use this only if not found */
1748 free(match_name);
1749 match_name = wn;
1750 wn = NULL;
1751 match_len = dir_len + 1 +len;
1752 match_format = format_aux;
1753 continue;
1754 }
1755 } else {
1756 /* remember the revision and try to find the newest one */
1757 if (match_name) {
1758 if (file->d_name[len] != '@' ||
1759 lysp_check_date(NULL, &file->d_name[len + 1], flen - (format_aux == LYS_IN_YANG ? 5 : 4) - len - 1, NULL)) {
1760 continue;
1761 } else if (match_name[match_len] == '@' &&
1762 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1763 continue;
1764 }
1765 free(match_name);
1766 }
1767
1768 match_name = wn;
1769 wn = NULL;
1770 match_len = dir_len + 1 + len;
1771 match_format = format_aux;
1772 continue;
1773 }
1774 }
1775 }
1776 }
1777
1778success:
1779 (*localfile) = match_name;
1780 match_name = NULL;
1781 if (format) {
1782 (*format) = match_format;
1783 }
1784 ret = EXIT_SUCCESS;
1785
1786cleanup:
1787 free(wn);
1788 free(wd);
1789 if (dir) {
1790 closedir(dir);
1791 }
1792 free(match_name);
1793 ly_set_free(dirs, free);
1794
1795 return ret;
1796}
1797
1798LY_ERR
1799lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement,
1800 struct lys_module **result)
1801{
1802 size_t len;
1803 int fd;
1804 char *filepath = NULL, *dot, *rev, *filename;
1805 LYS_INFORMAT format;
1806 struct lys_module *mod = NULL;
1807 LY_ERR ret = LY_SUCCESS;
1808
1809 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
1810 &filepath, &format));
1811 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
1812 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
1813
1814
1815 LOGVRB("Loading schema from \"%s\" file.", filepath);
1816
1817 /* open the file */
1818 fd = open(filepath, O_RDONLY);
1819 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
1820 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
1821
1822 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
1823 close(fd);
1824 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
1825
1826 /* check that name and revision match filename */
1827 filename = strrchr(filepath, '/');
1828 if (!filename) {
1829 filename = filepath;
1830 } else {
1831 filename++;
1832 }
1833 /* name */
1834 len = strlen(mod->parsed->name);
1835 rev = strchr(filename, '@');
1836 dot = strrchr(filepath, '.');
1837 if (strncmp(filename, mod->parsed->name, len) ||
1838 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1839 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1840 }
1841 /* revision */
1842 if (rev) {
1843 len = dot - ++rev;
1844 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
1845 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
1846 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
1847 }
1848 }
1849
1850 if (!mod->parsed->filepath) {
1851 char rpath[PATH_MAX];
1852 if (realpath(filepath, rpath) != NULL) {
1853 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1854 } else {
1855 mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
1856 }
1857 }
1858
1859 *result = mod;
1860
1861 /* success */
1862cleanup:
1863 free(filepath);
1864 return ret;
1865}