blob: d64768e5d6831bb1eaf944478f4e03a470de7d6c [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;
Radek Krejcica3db002018-11-01 10:31:01 +0100711 unsigned int u, changed_count, disabled_count;
Radek Krejci151a5b72018-10-19 14:21:44 +0200712 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();
Radek Krejcica3db002018-11-01 10:31:01 +0100726 changed_count = 0;
Radek Krejci151a5b72018-10-19 14:21:44 +0200727
Radek Krejcica3db002018-11-01 10:31:01 +0100728run:
729 for (disabled_count = u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200730 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200731 if (all || !strcmp(f->name, name)) {
732 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
733 if (all) {
734 /* skip already set features */
735 continue;
736 } else {
737 /* feature already set correctly */
738 ly_set_free(changed, NULL);
739 return LY_SUCCESS;
740 }
741 }
742
743 if (value) { /* enable */
744 /* check referenced features if they are enabled */
745 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
746 if (!lysc_iffeature_value(iff)) {
747 if (all) {
Radek Krejcica3db002018-11-01 10:31:01 +0100748 ++disabled_count;
Radek Krejci151a5b72018-10-19 14:21:44 +0200749 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
Radek Krejcica3db002018-11-01 10:31:01 +0100784 if (value && all && disabled_count) {
785 if (changed_count == changed->count) {
786 /* no change in last run -> not able to enable all ... */
787 /* ... print errors */
788 for (u = 0; disabled_count && u < LY_ARRAY_SIZE(mod->features); ++u) {
789 if (!(mod->features[u].flags & LYS_FENABLED)) {
790 LOGERR(mod->ctx, LY_EDENIED,
791 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
792 mod->features[u].name);
793 --disabled_count;
794 }
795 }
796 /* ... restore the original state */
797 for (u = 0; u < changed->count; ++u) {
798 f = changed->objs[u];
799 /* re-disable the feature */
800 f->flags &= ~LYS_FENABLED;
801 }
802
803 ly_set_free(changed, NULL);
804 return LY_EDENIED;
805 } else {
806 /* we did some change in last run, try it again */
807 changed_count = changed->count;
808 goto run;
809 }
810 }
811
Radek Krejci151a5b72018-10-19 14:21:44 +0200812 /* reflect change(s) in the dependent features */
813 for (u = 0; u < changed->count; ++u) {
814 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
815 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
816 * is not done - by default, features are disabled and must be explicitely enabled. */
817 f = changed->objs[u];
818 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature*, df) {
819 if (!((*df)->flags & LYS_FENABLED)) {
820 /* not enabled, nothing to do */
821 continue;
822 }
823 /* check the feature's if-features which could change by the previous change of our feature */
824 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
825 if (!lysc_iffeature_value(iff)) {
826 /* the feature must be disabled now */
827 (*df)->flags &= ~LYS_FENABLED;
828 /* add the feature into the list of changed features */
829 ly_set_add(changed, *df, LY_SET_OPT_USEASLIST);
830 break;
831 }
832 }
833 }
834 }
835
836 ly_set_free(changed, NULL);
837 return LY_SUCCESS;
838}
839
840API LY_ERR
841lys_feature_enable(struct lys_module *module, const char *feature)
842{
843 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
844
845 return lys_feature_change(module->compiled, feature, 1);
846}
847
848API LY_ERR
849lys_feature_disable(struct lys_module *module, const char *feature)
850{
851 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
852
853 return lys_feature_change(module->compiled, feature, 0);
854}
855
856API int
857lys_feature_value(const struct lys_module *module, const char *feature)
858{
859 struct lysc_feature *f;
860 struct lysc_module *mod;
861 unsigned int u;
862
863 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
864 mod = module->compiled;
865
866 /* search for the specified feature */
867 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200868 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200869 if (!strcmp(f->name, feature)) {
870 if (f->flags & LYS_FENABLED) {
871 return 1;
872 } else {
873 return 0;
874 }
875 }
876 }
877
878 /* feature definition not found */
879 return -1;
880}
881
882static LY_ERR
Radek Krejcice8c1592018-10-29 15:35:51 +0100883lys_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 +0200884{
Radek Krejcice8c1592018-10-29 15:35:51 +0100885 const char *name;
886 unsigned int u;
887 const struct lys_module *mod;
888 struct lysp_ext *edef;
889
890 if (options & LYSC_OPT_FREE_SP) {
891 /* just switch the pointers */
892 ext->argument = ext_p->argument;
893 } else {
894 /* keep refcounts correct for lysp_module_free() */
895 ext->argument = lydict_insert(ctx->mod->ctx, ext_p->argument, 0);
896 }
897 ext->insubstmt = ext_p->insubstmt;
898 ext->insubstmt_index = ext_p->insubstmt_index;
899
900 /* get module where the extension definition should be placed */
901 for (u = 0; ext_p->name[u] != ':'; ++u);
902 mod = lysc_module_find_prefix(ctx->mod, ext_p->name, u);
903 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
904 "Invalid prefix \"%.*s\" used for extension instance identifier.", u, ext_p->name),
905 LY_EVALID);
906 LY_CHECK_ERR_RET(!mod->parsed->extensions,
907 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
908 "Extension instance \"%s\" refers \"%s\" module that does not contain extension definitions.",
909 ext_p->name, mod->parsed->name),
910 LY_EVALID);
911 name = &ext_p->name[u + 1];
912 /* find the extension definition there */
913 for (ext = NULL, u = 0; u < LY_ARRAY_SIZE(mod->parsed->extensions); ++u) {
914 if (!strcmp(name, mod->parsed->extensions[u].name)) {
915 edef = &mod->parsed->extensions[u];
916 break;
917 }
918 }
919 LY_CHECK_ERR_RET(!edef, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
920 "Extension definition of extension instance \"%s\" not found.", ext_p->name),
921 LY_EVALID);
922 /* TODO plugins */
923
924 return LY_SUCCESS;
925}
926
927/**
928 * @param[in] parent Provided only in case the if-feature is inside
929 */
930static LY_ERR
931lys_compile_iffeature(struct lysc_ctx *ctx, const char **value, int UNUSED(options), struct lysc_iffeature *iff)
932{
933 const char *c = *value;
Radek Krejci151a5b72018-10-19 14:21:44 +0200934 int r, rc = EXIT_FAILURE;
935 int i, j, last_not, checkversion = 0;
936 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
937 uint8_t op;
938 struct iff_stack stack = {0, 0, NULL};
Radek Krejcice8c1592018-10-29 15:35:51 +0100939 struct lysc_feature *f;
Radek Krejci151a5b72018-10-19 14:21:44 +0200940
941 assert(c);
942
943 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
944 for (i = j = last_not = 0; c[i]; i++) {
945 if (c[i] == '(') {
946 j++;
947 checkversion = 1;
948 continue;
949 } else if (c[i] == ')') {
950 j--;
951 continue;
952 } else if (isspace(c[i])) {
953 checkversion = 1;
954 continue;
955 }
956
957 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
958 if (c[i + r] == '\0') {
959 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100960 "Invalid value \"%s\" of if-feature - unexpected end of expression.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200961 return LY_EVALID;
962 } else if (!isspace(c[i + r])) {
963 /* feature name starting with the not/and/or */
964 last_not = 0;
965 f_size++;
966 } else if (c[i] == 'n') { /* not operation */
967 if (last_not) {
968 /* double not */
969 expr_size = expr_size - 2;
970 last_not = 0;
971 } else {
972 last_not = 1;
973 }
974 } else { /* and, or */
975 f_exp++;
976 /* not a not operation */
977 last_not = 0;
978 }
979 i += r;
980 } else {
981 f_size++;
982 last_not = 0;
983 }
984 expr_size++;
985
986 while (!isspace(c[i])) {
987 if (!c[i] || c[i] == ')') {
988 i--;
989 break;
990 }
991 i++;
992 }
993 }
994 if (j || f_exp != f_size) {
995 /* not matching count of ( and ) */
996 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +0100997 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +0200998 return LY_EVALID;
999 }
1000
1001 if (checkversion || expr_size > 1) {
1002 /* check that we have 1.1 module */
1003 if (ctx->mod->version != LYS_VERSION_1_1) {
1004 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001005 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001006 return LY_EVALID;
1007 }
1008 }
1009
1010 /* allocate the memory */
Radek Krejci2c4e7172018-10-19 15:56:26 +02001011 LY_ARRAY_CREATE_RET(ctx->mod->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +02001012 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +02001013 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci2c4e7172018-10-19 15:56:26 +02001014 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->mod->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +02001015
Radek Krejci151a5b72018-10-19 14:21:44 +02001016 stack.size = expr_size;
1017 f_size--; expr_size--; /* used as indexes from now */
1018
1019 for (i--; i >= 0; i--) {
1020 if (c[i] == ')') {
1021 /* push it on stack */
1022 iff_stack_push(&stack, LYS_IFF_RP);
1023 continue;
1024 } else if (c[i] == '(') {
1025 /* pop from the stack into result all operators until ) */
1026 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1027 iff_setop(iff->expr, op, expr_size--);
1028 }
1029 continue;
1030 } else if (isspace(c[i])) {
1031 continue;
1032 }
1033
1034 /* end of operator or operand -> find beginning and get what is it */
1035 j = i + 1;
1036 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1037 i--;
1038 }
1039 i++; /* go back by one step */
1040
1041 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
1042 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1043 /* double not */
1044 iff_stack_pop(&stack);
1045 } else {
1046 /* not has the highest priority, so do not pop from the stack
1047 * as in case of AND and OR */
1048 iff_stack_push(&stack, LYS_IFF_NOT);
1049 }
1050 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
1051 /* as for OR - pop from the stack all operators with the same or higher
1052 * priority and store them to the result, then push the AND to the stack */
1053 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1054 op = iff_stack_pop(&stack);
1055 iff_setop(iff->expr, op, expr_size--);
1056 }
1057 iff_stack_push(&stack, LYS_IFF_AND);
1058 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
1059 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1060 op = iff_stack_pop(&stack);
1061 iff_setop(iff->expr, op, expr_size--);
1062 }
1063 iff_stack_push(&stack, LYS_IFF_OR);
1064 } else {
1065 /* feature name, length is j - i */
1066
1067 /* add it to the expression */
1068 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
1069
1070 /* now get the link to the feature definition */
1071 f = lysc_feature_find(ctx->mod, &c[i], j - i);
1072 LY_CHECK_ERR_GOTO(!f,
1073 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001074 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", *value, j - i, &c[i]);
Radek Krejci87616bb2018-10-31 13:30:52 +01001075 rc = LY_EVALID,
Radek Krejci151a5b72018-10-19 14:21:44 +02001076 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +02001077 iff->features[f_size] = f;
1078 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +02001079 f_size--;
1080 }
1081 }
1082 while (stack.index) {
1083 op = iff_stack_pop(&stack);
1084 iff_setop(iff->expr, op, expr_size--);
1085 }
1086
1087 if (++expr_size || ++f_size) {
1088 /* not all expected operators and operands found */
1089 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
Radek Krejcice8c1592018-10-29 15:35:51 +01001090 "Invalid value \"%s\" of if-feature - processing error.", *value);
Radek Krejci151a5b72018-10-19 14:21:44 +02001091 rc = LY_EINT;
1092 } else {
1093 rc = LY_SUCCESS;
1094 }
1095
1096error:
1097 /* cleanup */
1098 iff_stack_clean(&stack);
1099
1100 return rc;
1101}
1102
1103static LY_ERR
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001104lys_compile_import(struct lysc_ctx *ctx, struct lysp_import *imp_p, int options, struct lysc_import *imp)
1105{
Radek Krejcice8c1592018-10-29 15:35:51 +01001106 unsigned int u;
Radek Krejcif8f882a2018-10-31 14:51:15 +01001107 struct lys_module *mod = NULL;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001108 struct lysc_module *comp;
Radek Krejcice8c1592018-10-29 15:35:51 +01001109 LY_ERR ret = LY_SUCCESS;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001110
1111 if (options & LYSC_OPT_FREE_SP) {
1112 /* just switch the pointers */
1113 imp->prefix = imp_p->prefix;
1114 } else {
1115 /* keep refcounts correct for lysp_module_free() */
1116 imp->prefix = lydict_insert(ctx->mod->ctx, imp_p->prefix, 0);
1117 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001118 COMPILE_ARRAY_GOTO(ctx, imp_p->exts, imp->exts, options, u, lys_compile_ext, ret, done);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001119 imp->module = imp_p->module;
1120
1121 /* make sure that we have both versions (lysp_ and lysc_) of the imported module. To import groupings or
1122 * typedefs, the lysp_ is needed. To augment or deviate imported module, we need the lysc_ structure */
1123 if (!imp->module->parsed) {
1124 comp = imp->module->compiled;
1125 /* try to get filepath from the compiled version */
1126 if (comp->filepath) {
1127 mod = (struct lys_module*)lys_parse_path(ctx->mod->ctx, comp->filepath,
1128 !strcmp(&comp->filepath[strlen(comp->filepath - 4)], ".yin") ? LYS_IN_YIN : LYS_IN_YANG);
1129 if (mod != imp->module) {
1130 LOGERR(ctx->mod->ctx, LY_EINT, "Filepath \"%s\" of the module \"%s\" does not match.",
1131 comp->filepath, comp->name);
1132 mod = NULL;
1133 }
1134 }
1135 if (!mod) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001136 if (lysp_load_module(ctx->mod->ctx, comp->name, comp->revision, 0, 1, &mod)) {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001137 LOGERR(ctx->mod->ctx, LY_ENOTFOUND, "Unable to reload \"%s\" module to import it into \"%s\", source data not found.",
1138 comp->name, ctx->mod->name);
1139 return LY_ENOTFOUND;
1140 }
1141 }
1142 } else if (!imp->module->compiled) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001143 return lys_compile(imp->module, options);
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001144 }
1145
Radek Krejcice8c1592018-10-29 15:35:51 +01001146done:
1147 return ret;
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001148}
1149
1150static LY_ERR
Radek Krejci2a408df2018-10-29 16:32:26 +01001151lys_compile_identity(struct lysc_ctx *ctx, struct lysp_ident *ident_p, int options, struct lysc_ident *ident)
1152{
1153 unsigned int u;
1154 LY_ERR ret = LY_SUCCESS;
1155
1156 if (options & LYSC_OPT_FREE_SP) {
1157 /* just switch the pointers */
1158 ident->name = ident_p->name;
1159 } else {
1160 /* keep refcounts correct for lysp_module_free() */
1161 ident->name = lydict_insert(ctx->mod->ctx, ident_p->name, 0);
1162 }
1163 COMPILE_ARRAY_GOTO(ctx, ident_p->iffeatures, ident->iffeatures, options, u, lys_compile_iffeature, ret, done);
1164 /* backlings (derived) can be added no sooner than when all the identities in the current module are present */
1165 COMPILE_ARRAY_GOTO(ctx, ident_p->exts, ident->exts, options, u, lys_compile_ext, ret, done);
1166 ident->flags = ident_p->flags;
1167
1168done:
1169 return ret;
1170}
1171
1172static LY_ERR
1173lys_compile_identities_derived(struct lysc_ctx *ctx, struct lysp_ident *idents_p, struct lysc_ident *idents)
1174{
1175 unsigned int i, u, v;
1176 const char *s, *name;
1177 struct lysc_module *mod;
1178 struct lysc_ident **dident;
1179
1180 for (i = 0; i < LY_ARRAY_SIZE(idents_p); ++i) {
Radek Krejci478020e2018-10-30 16:02:14 +01001181 if (!idents_p[i].bases) {
1182 continue;
1183 }
Radek Krejci2a408df2018-10-29 16:32:26 +01001184 for (u = 0; u < LY_ARRAY_SIZE(idents_p[i].bases); ++u) {
1185 s = strchr(idents_p[i].bases[u], ':');
1186 if (s) {
1187 /* prefixed identity */
1188 name = &s[1];
1189 mod = lysc_module_find_prefix(ctx->mod, idents_p[i].bases[u], s - idents_p[i].bases[u])->compiled;
1190 } else {
1191 name = idents_p[i].bases[u];
1192 mod = ctx->mod;
1193 }
1194 LY_CHECK_ERR_RET(!mod, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1195 "Invalid prefix used for base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1196 LY_EVALID);
1197 if (mod->identities) {
1198 for (v = 0; v < LY_ARRAY_SIZE(mod->identities); ++v) {
1199 if (!strcmp(name, mod->identities[v].name)) {
1200 /* we have match! store the backlink */
1201 LY_ARRAY_NEW_RET(ctx->mod->ctx, mod->identities[v].derived, dident, LY_EMEM);
1202 *dident = &idents[i];
1203 break;
1204 }
1205 }
1206 }
1207 LY_CHECK_ERR_RET(!dident, LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
1208 "Unable to find base (%s) of identity \"%s\".", idents_p[i].bases[u], idents[i].name),
1209 LY_EVALID);
1210 }
1211 }
1212 return LY_SUCCESS;
1213}
1214
1215static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +02001216lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
1217{
Radek Krejcice8c1592018-10-29 15:35:51 +01001218 unsigned int u, v;
1219 LY_ERR ret = LY_SUCCESS;
1220 struct lysc_feature **df;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001221
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001222 if (options & LYSC_OPT_FREE_SP) {
1223 /* just switch the pointers */
1224 feature->name = feature_p->name;
1225 } else {
1226 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001227 feature->name = lydict_insert(ctx->mod->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001228 }
1229 feature->flags = feature_p->flags;
1230
Radek Krejcice8c1592018-10-29 15:35:51 +01001231 COMPILE_ARRAY_GOTO(ctx, feature_p->exts, feature->exts, options, u, lys_compile_ext, ret, done);
1232 COMPILE_ARRAY_GOTO(ctx, feature_p->iffeatures, feature->iffeatures, options, u, lys_compile_iffeature, ret, done);
1233 if (feature->iffeatures) {
1234 for (u = 0; u < LY_ARRAY_SIZE(feature->iffeatures); ++u) {
1235 if (feature->iffeatures[u].features) {
1236 for (v = 0; v < LY_ARRAY_SIZE(feature->iffeatures[u].features); ++v) {
1237 /* add itself into the dependants list */
1238 LY_ARRAY_NEW_RET(ctx->mod->ctx, feature->iffeatures[u].features[v]->depfeatures, df, LY_EMEM);
1239 *df = feature;
1240 }
1241 /* TODO check for circular dependency */
1242 }
Radek Krejci151a5b72018-10-19 14:21:44 +02001243 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001244 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001245done:
1246 return ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001247}
1248
1249LY_ERR
Radek Krejcid14e9692018-11-01 11:00:37 +01001250lys_compile(struct lys_module *mod, int options)
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001251{
Radek Krejci86d106e2018-10-18 09:53:19 +02001252 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001253 struct lysc_module *mod_c;
Radek Krejcif8f882a2018-10-31 14:51:15 +01001254 struct lysp_module *sp;
Radek Krejci151a5b72018-10-19 14:21:44 +02001255 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001256 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001257
Radek Krejcif8f882a2018-10-31 14:51:15 +01001258 LY_CHECK_ARG_RET(NULL, mod, mod->parsed, mod->parsed->ctx, LY_EINVAL);
1259 sp = mod->parsed;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001260
1261 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001262 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 +02001263 return LY_EINVAL;
1264 }
1265
Radek Krejcif8f882a2018-10-31 14:51:15 +01001266 ctx.mod = ((struct lys_module*)mod)->compiled = mod_c = calloc(1, sizeof *mod_c);
Radek Krejci86d106e2018-10-18 09:53:19 +02001267 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1268 mod_c->ctx = sp->ctx;
Radek Krejcid14e9692018-11-01 11:00:37 +01001269 mod_c->implemented = sp->implemented;
1270 mod_c->latest_revision = sp->latest_revision;
Radek Krejci86d106e2018-10-18 09:53:19 +02001271 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001272
1273 if (options & LYSC_OPT_FREE_SP) {
1274 /* just switch the pointers */
1275 mod_c->name = sp->name;
1276 mod_c->ns = sp->ns;
1277 mod_c->prefix = sp->prefix;
1278 } else {
1279 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001280 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1281 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1282 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001283 }
Radek Krejcif8f882a2018-10-31 14:51:15 +01001284 if (sp->revs) {
1285 mod_c->revision = lydict_insert(sp->ctx, sp->revs[0].date, 10);
1286 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001287 COMPILE_ARRAY_GOTO(&ctx, sp->imports, mod_c->imports, options, u, lys_compile_import, ret, error);
1288 COMPILE_ARRAY_GOTO(&ctx, sp->features, mod_c->features, options, u, lys_compile_feature, ret, error);
Radek Krejci2a408df2018-10-29 16:32:26 +01001289 COMPILE_ARRAY_GOTO(&ctx, sp->identities, mod_c->identities, options, u, lys_compile_identity, ret, error);
1290 if (sp->identities) {
1291 LY_CHECK_RET(lys_compile_identities_derived(&ctx, sp->identities, mod_c->identities));
1292 }
Radek Krejcice8c1592018-10-29 15:35:51 +01001293
1294 COMPILE_ARRAY_GOTO(&ctx, sp->exts, mod_c->exts, options, u, lys_compile_ext, ret, error);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001295
1296 if (options & LYSC_OPT_FREE_SP) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001297 lysp_module_free_(mod->parsed, 0);
1298 ((struct lys_module*)mod)->parsed = NULL;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001299 }
1300
Radek Krejcif8f882a2018-10-31 14:51:15 +01001301 ((struct lys_module*)mod)->compiled = mod_c;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001302 return LY_SUCCESS;
1303
1304error:
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001305 lysc_module_free_(mod_c, (options & LYSC_OPT_FREE_SP) ? 0 : 1);
Radek Krejcif8f882a2018-10-31 14:51:15 +01001306 ((struct lys_module*)mod)->compiled = NULL;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001307 return ret;
1308}
Radek Krejci86d106e2018-10-18 09:53:19 +02001309
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001310static void
Radek Krejci086c7132018-10-26 15:29:04 +02001311lys_latest_switch(struct lys_module *old, struct lysp_module *new)
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001312{
Radek Krejci086c7132018-10-26 15:29:04 +02001313 if (old->parsed) {
1314 new->latest_revision = old->parsed->latest_revision;
1315 old->parsed->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001316 }
Radek Krejci086c7132018-10-26 15:29:04 +02001317 if (old->compiled) {
1318 new->latest_revision = old->parsed->latest_revision;
1319 old->compiled->latest_revision = 0;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001320 }
1321}
1322
Radek Krejcid33273d2018-10-25 14:55:52 +02001323struct lys_module *
Radek Krejci9ed7a192018-10-31 16:23:51 +01001324lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
1325 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
Radek Krejci86d106e2018-10-18 09:53:19 +02001326{
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001327 struct lys_module *mod = NULL, *latest, *mod_dup;
Radek Krejcid33273d2018-10-25 14:55:52 +02001328 struct lysp_module *latest_p;
Radek Krejci086c7132018-10-26 15:29:04 +02001329 struct lysp_import *imp;
1330 struct lysp_include *inc;
Radek Krejci9ed7a192018-10-31 16:23:51 +01001331 LY_ERR ret = LY_EINVAL;
Radek Krejci086c7132018-10-26 15:29:04 +02001332 unsigned int u, i;
Radek Krejci86d106e2018-10-18 09:53:19 +02001333
1334 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1335
1336 mod = calloc(1, sizeof *mod);
1337 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1338
1339 switch (format) {
1340 case LYS_IN_YIN:
1341 /* TODO not yet supported
1342 mod = yin_read_module(ctx, data, revision, implement);
1343 */
1344 break;
1345 case LYS_IN_YANG:
1346 ret = yang_parse(ctx, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001347 break;
1348 default:
1349 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1350 break;
1351 }
Radek Krejcifaa1eac2018-10-30 14:34:55 +01001352 LY_CHECK_ERR_RET(ret, free(mod), NULL);
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001353
1354 /* make sure that the newest revision is at position 0 */
1355 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001356
1357 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001358 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001359 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1360 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
1361 lys_module_free(mod, NULL);
1362 return NULL;
1363 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001364 mod->parsed->implemented = 1;
1365 }
1366
Radek Krejci9ed7a192018-10-31 16:23:51 +01001367 if (custom_check) {
1368 LY_CHECK_ERR_RET(custom_check(ctx, mod->parsed, check_data), lys_module_free(mod, NULL), NULL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001369 }
1370
Radek Krejcid33273d2018-10-25 14:55:52 +02001371 if (mod->parsed->submodule) { /* submodule */
1372 /* decide the latest revision */
1373 latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
1374 if (latest_p) {
1375 if (mod->parsed->revs) {
1376 if (!latest_p->revs) {
1377 /* latest has no revision, so mod is anyway newer */
Radek Krejci9ed7a192018-10-31 16:23:51 +01001378 mod->parsed->latest_revision = latest_p->latest_revision;
Radek Krejcid33273d2018-10-25 14:55:52 +02001379 latest_p->latest_revision = 0;
1380 } else {
1381 if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
Radek Krejci9ed7a192018-10-31 16:23:51 +01001382 mod->parsed->latest_revision = latest_p->latest_revision;
Radek Krejcid33273d2018-10-25 14:55:52 +02001383 latest_p->latest_revision = 0;
1384 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001385 }
1386 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001387 } else {
Radek Krejci9ed7a192018-10-31 16:23:51 +01001388 mod->parsed->latest_revision = 1;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001389 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001390 } else { /* module */
1391 /* check for duplicity in the context */
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001392 mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
1393 if (mod_dup) {
1394 if (mod_dup->parsed) {
1395 /* error */
1396 if (mod->parsed->revs) {
1397 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1398 mod->parsed->name, mod->parsed->revs[0].date);
1399 } else {
1400 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1401 mod->parsed->name);
1402 }
1403 lys_module_free(mod, NULL);
1404 return NULL;
Radek Krejcid33273d2018-10-25 14:55:52 +02001405 } else {
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001406 /* add the parsed data to the currently compiled-only module in the context */
1407 mod_dup->parsed = mod->parsed;
1408 free(mod);
1409 mod = mod_dup;
1410 goto finish_parsing;
Radek Krejcid33273d2018-10-25 14:55:52 +02001411 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001412 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001413
1414#if 0
1415 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1416 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1417 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1418 * the anotation definitions available in the internal schema structure. There is another hack in schema
1419 * printers to do not print this internally added annotation. */
1420 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1421 if (lyp_add_ietf_netconf_annotations(mod)) {
1422 lys_free(mod, NULL, 1, 1);
1423 return NULL;
1424 }
1425 }
1426#endif
1427
Radek Krejcid33273d2018-10-25 14:55:52 +02001428 /* decide the latest revision */
1429 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1430 if (latest) {
1431 if (mod->parsed->revs) {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001432 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revision)) {
Radek Krejcid33273d2018-10-25 14:55:52 +02001433 /* latest has no revision, so mod is anyway newer */
Radek Krejci086c7132018-10-26 15:29:04 +02001434 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001435 } else {
Radek Krejcif8f882a2018-10-31 14:51:15 +01001436 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 +02001437 lys_latest_switch(latest, mod->parsed);
Radek Krejcid33273d2018-10-25 14:55:52 +02001438 }
1439 }
1440 }
1441 } else {
1442 mod->parsed->latest_revision = 1;
1443 }
1444
1445 /* add into context */
1446 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1447
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001448finish_parsing:
Radek Krejci086c7132018-10-26 15:29:04 +02001449 /* resolve imports and includes */
1450 mod->parsed->parsing = 1;
1451 LY_ARRAY_FOR(mod->parsed->imports, u) {
1452 imp = &mod->parsed->imports[u];
Radek Krejci6d6e4e42018-10-29 13:28:19 +01001453 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 +02001454 ly_set_rm(&ctx->list, mod, NULL);
1455 lys_module_free(mod, NULL);
1456 return NULL;
1457 }
1458 /* check for importing the same module twice */
1459 for (i = 0; i < u; ++i) {
1460 if (imp->module == mod->parsed->imports[i].module) {
1461 LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Single revision of the module \"%s\" referred twice.", imp->name);
1462 ly_set_rm(&ctx->list, mod, NULL);
1463 lys_module_free(mod, NULL);
1464 return NULL;
1465 }
1466 }
1467 }
1468 LY_ARRAY_FOR(mod->parsed->includes, u) {
1469 inc = &mod->parsed->includes[u];
1470 if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
1471 ly_set_rm(&ctx->list, mod, NULL);
1472 lys_module_free(mod, NULL);
1473 return NULL;
1474 }
1475 }
1476 mod->parsed->parsing = 0;
Radek Krejcid33273d2018-10-25 14:55:52 +02001477 }
1478
Radek Krejci86d106e2018-10-18 09:53:19 +02001479 return mod;
1480}
1481
Radek Krejcid14e9692018-11-01 11:00:37 +01001482API struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001483lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1484{
Radek Krejcid33273d2018-10-25 14:55:52 +02001485 struct lys_module *result;
1486
Radek Krejci9ed7a192018-10-31 16:23:51 +01001487 result = lys_parse_mem_(ctx, data, format, 1, NULL, NULL);
Radek Krejcid33273d2018-10-25 14:55:52 +02001488 if (result && result->parsed->submodule) {
1489 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1490 result->parsed->name);
1491 lys_module_free(result, NULL);
1492 return NULL;
1493 }
1494 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001495}
1496
1497static void
1498lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1499{
1500#ifdef __APPLE__
1501 char path[MAXPATHLEN];
1502#else
1503 int len;
1504 char path[PATH_MAX], proc_path[32];
1505#endif
1506
1507#ifdef __APPLE__
1508 if (fcntl(fd, F_GETPATH, path) != -1) {
1509 *filename = lydict_insert(ctx, path, 0);
1510 }
1511#else
1512 /* get URI if there is /proc */
1513 sprintf(proc_path, "/proc/self/fd/%d", fd);
1514 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1515 *filename = lydict_insert(ctx, path, len);
1516 }
1517#endif
1518}
1519
Radek Krejcid33273d2018-10-25 14:55:52 +02001520struct lys_module *
Radek Krejci9ed7a192018-10-31 16:23:51 +01001521lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
1522 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
Radek Krejci86d106e2018-10-18 09:53:19 +02001523{
Radek Krejcid33273d2018-10-25 14:55:52 +02001524 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001525 size_t length;
1526 char *addr;
1527
1528 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1529 if (fd < 0) {
1530 LOGARG(ctx, fd);
1531 return NULL;
1532 }
1533
1534 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1535 if (!addr) {
1536 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1537 return NULL;
1538 }
1539
Radek Krejci9ed7a192018-10-31 16:23:51 +01001540 mod = lys_parse_mem_(ctx, addr, format, implement, custom_check, check_data);
Radek Krejci86d106e2018-10-18 09:53:19 +02001541 ly_munmap(addr, length);
1542
1543 if (mod && !mod->parsed->filepath) {
1544 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1545 }
1546
1547 return mod;
1548}
1549
Radek Krejcid14e9692018-11-01 11:00:37 +01001550API struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001551lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1552{
Radek Krejcid33273d2018-10-25 14:55:52 +02001553 struct lys_module *result;
1554
Radek Krejci9ed7a192018-10-31 16:23:51 +01001555 result = lys_parse_fd_(ctx, fd, format, 1, NULL, NULL);
Radek Krejcid33273d2018-10-25 14:55:52 +02001556 if (result && result->parsed->submodule) {
1557 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1558 result->parsed->name);
1559 lys_module_free(result, NULL);
1560 return NULL;
1561 }
1562 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001563}
1564
Radek Krejcid33273d2018-10-25 14:55:52 +02001565struct lys_module *
Radek Krejci9ed7a192018-10-31 16:23:51 +01001566lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
1567 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
Radek Krejci86d106e2018-10-18 09:53:19 +02001568{
1569 int fd;
Radek Krejcid33273d2018-10-25 14:55:52 +02001570 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001571 const char *rev, *dot, *filename;
1572 size_t len;
1573
1574 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1575
1576 fd = open(path, O_RDONLY);
1577 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1578
Radek Krejci9ed7a192018-10-31 16:23:51 +01001579 mod = lys_parse_fd_(ctx, fd, format, implement, custom_check, check_data);
Radek Krejci86d106e2018-10-18 09:53:19 +02001580 close(fd);
1581 LY_CHECK_RET(!mod, NULL);
1582
1583 /* check that name and revision match filename */
1584 filename = strrchr(path, '/');
1585 if (!filename) {
1586 filename = path;
1587 } else {
1588 filename++;
1589 }
1590 rev = strchr(filename, '@');
1591 dot = strrchr(filename, '.');
1592
1593 /* name */
1594 len = strlen(mod->parsed->name);
1595 if (strncmp(filename, mod->parsed->name, len) ||
1596 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1597 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1598 }
1599 if (rev) {
1600 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001601 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001602 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001603 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001604 }
1605 }
1606
1607 if (!mod->parsed->filepath) {
1608 /* store URI */
1609 char rpath[PATH_MAX];
1610 if (realpath(path, rpath) != NULL) {
1611 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1612 } else {
1613 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1614 }
1615 }
1616
1617 return mod;
1618}
1619
Radek Krejcid14e9692018-11-01 11:00:37 +01001620API struct lys_module *
Radek Krejcid33273d2018-10-25 14:55:52 +02001621lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1622{
1623 struct lys_module *result;
1624
Radek Krejci9ed7a192018-10-31 16:23:51 +01001625 result = lys_parse_path_(ctx, path, format, 1, NULL, NULL);
Radek Krejcid33273d2018-10-25 14:55:52 +02001626 if (result && result->parsed->submodule) {
1627 LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
1628 path, result->parsed->name);
1629 lys_module_free(result, NULL);
1630 return NULL;
1631 }
1632 return result;
1633}
1634
1635API LY_ERR
1636lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
1637 char **localfile, LYS_INFORMAT *format)
1638{
1639 size_t len, flen, match_len = 0, dir_len;
1640 int i, implicit_cwd = 0, ret = EXIT_FAILURE;
1641 char *wd, *wn = NULL;
1642 DIR *dir = NULL;
1643 struct dirent *file;
1644 char *match_name = NULL;
1645 LYS_INFORMAT format_aux, match_format = 0;
1646 struct ly_set *dirs;
1647 struct stat st;
1648
1649 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1650
1651 /* start to fill the dir fifo with the context's search path (if set)
1652 * and the current working directory */
1653 dirs = ly_set_new();
1654 if (!dirs) {
1655 LOGMEM(NULL);
1656 return EXIT_FAILURE;
1657 }
1658
1659 len = strlen(name);
1660 if (cwd) {
1661 wd = get_current_dir_name();
1662 if (!wd) {
1663 LOGMEM(NULL);
1664 goto cleanup;
1665 } else {
1666 /* add implicit current working directory (./) to be searched,
1667 * this directory is not searched recursively */
1668 if (ly_set_add(dirs, wd, 0) == -1) {
1669 goto cleanup;
1670 }
1671 implicit_cwd = 1;
1672 }
1673 }
1674 if (searchpaths) {
1675 for (i = 0; searchpaths[i]; i++) {
1676 /* check for duplicities with the implicit current working directory */
1677 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1678 implicit_cwd = 0;
1679 continue;
1680 }
1681 wd = strdup(searchpaths[i]);
1682 if (!wd) {
1683 LOGMEM(NULL);
1684 goto cleanup;
1685 } else if (ly_set_add(dirs, wd, 0) == -1) {
1686 goto cleanup;
1687 }
1688 }
1689 }
1690 wd = NULL;
1691
1692 /* start searching */
1693 while (dirs->count) {
1694 free(wd);
1695 free(wn); wn = NULL;
1696
1697 dirs->count--;
1698 wd = (char *)dirs->objs[dirs->count];
1699 dirs->objs[dirs->count] = NULL;
1700 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1701
1702 if (dir) {
1703 closedir(dir);
1704 }
1705 dir = opendir(wd);
1706 dir_len = strlen(wd);
1707 if (!dir) {
1708 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1709 } else {
1710 while ((file = readdir(dir))) {
1711 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1712 /* skip . and .. */
1713 continue;
1714 }
1715 free(wn);
1716 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1717 LOGMEM(NULL);
1718 goto cleanup;
1719 }
1720 if (stat(wn, &st) == -1) {
1721 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1722 file->d_name, wd, strerror(errno));
1723 continue;
1724 }
1725 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1726 /* we have another subdirectory in searchpath to explore,
1727 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1728 if (ly_set_add(dirs, wn, 0) == -1) {
1729 goto cleanup;
1730 }
1731 /* continue with the next item in current directory */
1732 wn = NULL;
1733 continue;
1734 } else if (!S_ISREG(st.st_mode)) {
1735 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1736 continue;
1737 }
1738
1739 /* here we know that the item is a file which can contain a module */
1740 if (strncmp(name, file->d_name, len) ||
1741 (file->d_name[len] != '.' && file->d_name[len] != '@')) {
1742 /* different filename than the module we search for */
1743 continue;
1744 }
1745
1746 /* get type according to filename suffix */
1747 flen = strlen(file->d_name);
1748 if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1749 format_aux = LYS_IN_YIN;
1750 } else if (!strcmp(&file->d_name[flen - 5], ".yang")) {
1751 format_aux = LYS_IN_YANG;
1752 } else {
1753 /* not supportde suffix/file format */
1754 continue;
1755 }
1756
1757 if (revision) {
1758 /* we look for the specific revision, try to get it from the filename */
1759 if (file->d_name[len] == '@') {
1760 /* check revision from the filename */
1761 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1762 /* another revision */
1763 continue;
1764 } else {
1765 /* exact revision */
1766 free(match_name);
1767 match_name = wn;
1768 wn = NULL;
1769 match_len = dir_len + 1 + len;
1770 match_format = format_aux;
1771 goto success;
1772 }
1773 } else {
1774 /* continue trying to find exact revision match, use this only if not found */
1775 free(match_name);
1776 match_name = wn;
1777 wn = NULL;
1778 match_len = dir_len + 1 +len;
1779 match_format = format_aux;
1780 continue;
1781 }
1782 } else {
1783 /* remember the revision and try to find the newest one */
1784 if (match_name) {
1785 if (file->d_name[len] != '@' ||
1786 lysp_check_date(NULL, &file->d_name[len + 1], flen - (format_aux == LYS_IN_YANG ? 5 : 4) - len - 1, NULL)) {
1787 continue;
1788 } else if (match_name[match_len] == '@' &&
1789 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1790 continue;
1791 }
1792 free(match_name);
1793 }
1794
1795 match_name = wn;
1796 wn = NULL;
1797 match_len = dir_len + 1 + len;
1798 match_format = format_aux;
1799 continue;
1800 }
1801 }
1802 }
1803 }
1804
1805success:
1806 (*localfile) = match_name;
1807 match_name = NULL;
1808 if (format) {
1809 (*format) = match_format;
1810 }
1811 ret = EXIT_SUCCESS;
1812
1813cleanup:
1814 free(wn);
1815 free(wd);
1816 if (dir) {
1817 closedir(dir);
1818 }
1819 free(match_name);
1820 ly_set_free(dirs, free);
1821
1822 return ret;
1823}
1824