blob: e058755bc72f484a6c5c67586db490cc7eb0a710 [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 Krejcidd4e8d42018-10-16 14:55:43 +020037static void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict);
38static void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020039
Radek Krejci86d106e2018-10-18 09:53:19 +020040#define LYSC_CTX_BUFSIZE 4086
41struct lysc_ctx {
42 struct lysc_module *mod;
43 uint16_t path_len;
44 char path[LYSC_CTX_BUFSIZE];
45};
46
Radek Krejci6f7feb62018-10-12 15:23:02 +020047static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020048lysp_stmt_free(struct ly_ctx *ctx, struct lysp_stmt *stmt, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020049{
50 struct lysp_stmt *child, *next;
51
Radek Krejci151a5b72018-10-19 14:21:44 +020052 FREE_STRING(ctx, stmt->stmt, dict);
53 FREE_STRING(ctx, stmt->arg, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020054
55 LY_LIST_FOR_SAFE(stmt->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020056 lysp_stmt_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020057 }
58
59 free(stmt);
60}
61
62static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020063lysp_ext_instance_free(struct ly_ctx *ctx, struct lysp_ext_instance *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020064{
65 struct lysp_stmt *stmt, *next;
66
Radek Krejci151a5b72018-10-19 14:21:44 +020067 FREE_STRING(ctx, ext->name, dict);
68 FREE_STRING(ctx, ext->argument, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020069
70 LY_LIST_FOR_SAFE(ext->child, next, stmt) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020071 lysp_stmt_free(ctx, stmt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020072 }
73}
74
75static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020076lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020077{
Radek Krejci151a5b72018-10-19 14:21:44 +020078 FREE_STRING(ctx, import->name, dict);
79 FREE_STRING(ctx, import->prefix, dict);
80 FREE_STRING(ctx, import->dsc, dict);
81 FREE_STRING(ctx, import->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +020082 FREE_ARRAY(ctx, import->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +020083}
84
85static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020086lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020087{
Radek Krejcid33273d2018-10-25 14:55:52 +020088 if (include->submodule && !(--include->submodule->refcount)) {
89 lysp_module_free(include->submodule);
90 }
Radek Krejci151a5b72018-10-19 14:21:44 +020091 FREE_STRING(ctx, include->dsc, dict);
92 FREE_STRING(ctx, include->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +020093 FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +020094}
95
96static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020097lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020098{
Radek Krejci151a5b72018-10-19 14:21:44 +020099 FREE_STRING(ctx, rev->dsc, dict);
100 FREE_STRING(ctx, rev->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200101 FREE_ARRAY(ctx, rev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200102}
103
104static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200105lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200106{
Radek Krejci151a5b72018-10-19 14:21:44 +0200107 FREE_STRING(ctx, ext->name, dict);
108 FREE_STRING(ctx, ext->argument, dict);
109 FREE_STRING(ctx, ext->dsc, dict);
110 FREE_STRING(ctx, ext->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200111 FREE_ARRAY(ctx, ext->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200112}
113
114static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200115lysp_feature_free(struct ly_ctx *ctx, struct lysp_feature *feat, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200116{
Radek Krejci151a5b72018-10-19 14:21:44 +0200117 FREE_STRING(ctx, feat->name, dict);
118 FREE_STRINGS(ctx, feat->iffeatures, 1);
119 FREE_STRING(ctx, feat->dsc, dict);
120 FREE_STRING(ctx, feat->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200121 FREE_ARRAY(ctx, feat->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200122}
123
124static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200125lysp_ident_free(struct ly_ctx *ctx, struct lysp_ident *ident, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200126{
Radek Krejci151a5b72018-10-19 14:21:44 +0200127 FREE_STRING(ctx, ident->name, dict);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200128 FREE_STRINGS(ctx, ident->iffeatures, 1);
Radek Krejci151a5b72018-10-19 14:21:44 +0200129 FREE_STRINGS(ctx, ident->bases, dict);
130 FREE_STRING(ctx, ident->dsc, dict);
131 FREE_STRING(ctx, ident->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200132 FREE_ARRAY(ctx, ident->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200133}
134
135static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200136lysp_restr_free(struct ly_ctx *ctx, struct lysp_restr *restr, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200137{
Radek Krejci151a5b72018-10-19 14:21:44 +0200138 FREE_STRING(ctx, restr->arg, dict);
139 FREE_STRING(ctx, restr->emsg, dict);
140 FREE_STRING(ctx, restr->eapptag, dict);
141 FREE_STRING(ctx, restr->dsc, dict);
142 FREE_STRING(ctx, restr->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200143 FREE_ARRAY(ctx, restr->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200144}
145
146static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200147lysp_type_enum_free(struct ly_ctx *ctx, struct lysp_type_enum *item, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200148{
Radek Krejci151a5b72018-10-19 14:21:44 +0200149 FREE_STRING(ctx, item->name, dict);
150 FREE_STRING(ctx, item->dsc, dict);
151 FREE_STRING(ctx, item->ref, dict);
152 FREE_STRINGS(ctx, item->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200153 FREE_ARRAY(ctx, item->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200154}
155
156static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200157lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200158{
Radek Krejci151a5b72018-10-19 14:21:44 +0200159 FREE_STRING(ctx, type->name, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200160 FREE_MEMBER(ctx, type->range, lysp_restr_free);
161 FREE_MEMBER(ctx, type->length, lysp_restr_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200162 FREE_ARRAY(ctx, type->patterns, lysp_restr_free);
163 FREE_ARRAY(ctx, type->enums, lysp_type_enum_free);
164 FREE_ARRAY(ctx, type->bits, lysp_type_enum_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200165 FREE_STRING(ctx, type->path, dict);
166 FREE_STRINGS(ctx, type->bases, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200167 FREE_ARRAY(ctx, type->types, lysp_type_free);
168 FREE_ARRAY(ctx, type->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200169}
170
171static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200172lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200173{
Radek Krejci151a5b72018-10-19 14:21:44 +0200174 FREE_STRING(ctx, tpdf->name, dict);
175 FREE_STRING(ctx, tpdf->units, dict);
176 FREE_STRING(ctx, tpdf->dflt, dict);
177 FREE_STRING(ctx, tpdf->dsc, dict);
178 FREE_STRING(ctx, tpdf->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200179 FREE_ARRAY(ctx, tpdf->exts, lysp_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200180 lysp_type_free(ctx, &tpdf->type, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200181}
182
183static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200184lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200185{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200186 struct lysp_node *node, *next;
187
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200188 FREE_ARRAY(ctx, inout->musts, lysp_restr_free);
189 FREE_ARRAY(ctx, inout->typedefs, lysp_tpdf_free);
190 FREE_ARRAY(ctx, inout->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200191 LY_LIST_FOR_SAFE(inout->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200192 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200193 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200194 FREE_ARRAY(ctx, inout->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200195
196}
197
198static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200199lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200200{
Radek Krejci151a5b72018-10-19 14:21:44 +0200201 FREE_STRING(ctx, action->name, dict);
202 FREE_STRING(ctx, action->dsc, dict);
203 FREE_STRING(ctx, action->ref, dict);
204 FREE_STRINGS(ctx, action->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200205 FREE_ARRAY(ctx, action->typedefs, lysp_tpdf_free);
206 FREE_ARRAY(ctx, action->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200207 FREE_MEMBER(ctx, action->input, lysp_action_inout_free);
208 FREE_MEMBER(ctx, action->output, lysp_action_inout_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200209 FREE_ARRAY(ctx, action->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200210}
211
212static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200213lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200214{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200215 struct lysp_node *node, *next;
216
Radek Krejci151a5b72018-10-19 14:21:44 +0200217 FREE_STRING(ctx, notif->name, dict);
218 FREE_STRING(ctx, notif->dsc, dict);
219 FREE_STRING(ctx, notif->ref, dict);
220 FREE_STRINGS(ctx, notif->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200221 FREE_ARRAY(ctx, notif->musts, lysp_restr_free);
222 FREE_ARRAY(ctx, notif->typedefs, lysp_tpdf_free);
223 FREE_ARRAY(ctx, notif->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200224 LY_LIST_FOR_SAFE(notif->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200225 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200226 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200227 FREE_ARRAY(ctx, notif->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200228}
229
230static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200231lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200232{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200233 struct lysp_node *node, *next;
234
Radek Krejci151a5b72018-10-19 14:21:44 +0200235 FREE_STRING(ctx, grp->name, dict);
236 FREE_STRING(ctx, grp->dsc, dict);
237 FREE_STRING(ctx, grp->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200238 FREE_ARRAY(ctx, grp->typedefs, lysp_tpdf_free);
239 FREE_ARRAY(ctx, grp->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200240 LY_LIST_FOR_SAFE(grp->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200241 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200242 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200243 FREE_ARRAY(ctx, grp->actions, lysp_action_free);
244 FREE_ARRAY(ctx, grp->notifs, lysp_notif_free);
245 FREE_ARRAY(ctx, grp->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200246}
247
248static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200249lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200250{
Radek Krejci151a5b72018-10-19 14:21:44 +0200251 FREE_STRING(ctx, when->cond, dict);
252 FREE_STRING(ctx, when->dsc, dict);
253 FREE_STRING(ctx, when->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200254 FREE_ARRAY(ctx, when->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200255}
256
257static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200258lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200259{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200260 struct lysp_node *node, *next;
261
Radek Krejci151a5b72018-10-19 14:21:44 +0200262 FREE_STRING(ctx, augment->nodeid, dict);
263 FREE_STRING(ctx, augment->dsc, dict);
264 FREE_STRING(ctx, augment->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200265 FREE_MEMBER(ctx, augment->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200266 FREE_STRINGS(ctx, augment->iffeatures, 1);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200267 LY_LIST_FOR_SAFE(augment->child, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200268 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200269 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200270 FREE_ARRAY(ctx, augment->actions, lysp_action_free);
271 FREE_ARRAY(ctx, augment->notifs, lysp_notif_free);
272 FREE_ARRAY(ctx, augment->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200273}
274
275static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200276lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200277{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200278 struct lysp_deviate_add *add = (struct lysp_deviate_add*)d;
279 struct lysp_deviate_rpl *rpl = (struct lysp_deviate_rpl*)d;
280
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200281 FREE_ARRAY(ctx, d->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200282 switch(d->mod) {
283 case LYS_DEV_NOT_SUPPORTED:
284 /* nothing to do */
285 break;
286 case LYS_DEV_ADD:
287 case LYS_DEV_DELETE: /* compatible for dynamically allocated data */
Radek Krejci151a5b72018-10-19 14:21:44 +0200288 FREE_STRING(ctx, add->units, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200289 FREE_ARRAY(ctx, add->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200290 FREE_STRINGS(ctx, add->uniques, dict);
291 FREE_STRINGS(ctx, add->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200292 break;
293 case LYS_DEV_REPLACE:
294 FREE_MEMBER(ctx, rpl->type, lysp_type_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200295 FREE_STRING(ctx, rpl->units, dict);
296 FREE_STRING(ctx, rpl->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200297 break;
298 default:
299 LOGINT(ctx);
300 break;
301 }
302}
303
304static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200305lysp_deviation_free(struct ly_ctx *ctx, struct lysp_deviation *dev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200306{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200307 struct lysp_deviate *next, *iter;
308
Radek Krejci151a5b72018-10-19 14:21:44 +0200309 FREE_STRING(ctx, dev->nodeid, dict);
310 FREE_STRING(ctx, dev->dsc, dict);
311 FREE_STRING(ctx, dev->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200312 LY_LIST_FOR_SAFE(dev->deviates, next, iter) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200313 lysp_deviate_free(ctx, iter, dict);
Michal Vasko8447f6a2018-10-15 10:56:16 +0200314 free(iter);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200315 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200316 FREE_ARRAY(ctx, dev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200317}
318
319static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200320lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200321{
Radek Krejci151a5b72018-10-19 14:21:44 +0200322 FREE_STRING(ctx, ref->nodeid, dict);
323 FREE_STRING(ctx, ref->dsc, dict);
324 FREE_STRING(ctx, ref->ref, dict);
325 FREE_STRINGS(ctx, ref->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200326 FREE_ARRAY(ctx, ref->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200327 FREE_STRING(ctx, ref->presence, dict);
328 FREE_STRINGS(ctx, ref->dflts, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200329 FREE_ARRAY(ctx, ref->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200330}
331
332static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200333lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200334{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200335 struct lysp_node *child, *next;
336
Radek Krejci151a5b72018-10-19 14:21:44 +0200337 FREE_STRING(ctx, node->name, dict);
338 FREE_STRING(ctx, node->dsc, dict);
339 FREE_STRING(ctx, node->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200340 FREE_MEMBER(ctx, node->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200341 FREE_STRINGS(ctx, node->iffeatures, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200342 FREE_ARRAY(ctx, node->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200343
344 switch(node->nodetype) {
345 case LYS_CONTAINER:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200346 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200347 FREE_STRING(ctx, ((struct lysp_node_container*)node)->presence, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200348 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->typedefs, lysp_tpdf_free);
349 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200350 LY_LIST_FOR_SAFE(((struct lysp_node_container*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200351 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200352 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200353 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->actions, lysp_action_free);
354 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->notifs, lysp_notif_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200355 break;
356 case LYS_LEAF:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200357 FREE_ARRAY(ctx, ((struct lysp_node_leaf*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200358 lysp_type_free(ctx, &((struct lysp_node_leaf*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200359 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->units, dict);
360 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200361 break;
362 case LYS_LEAFLIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200363 FREE_ARRAY(ctx, ((struct lysp_node_leaflist*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200364 lysp_type_free(ctx, &((struct lysp_node_leaflist*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200365 FREE_STRING(ctx, ((struct lysp_node_leaflist*)node)->units, dict);
366 FREE_STRINGS(ctx, ((struct lysp_node_leaflist*)node)->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200367 break;
368 case LYS_LIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200369 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200370 FREE_STRING(ctx, ((struct lysp_node_list*)node)->key, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200371 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->typedefs, lysp_tpdf_free);
372 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200373 LY_LIST_FOR_SAFE(((struct lysp_node_list*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200374 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200375 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200376 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->actions, lysp_action_free);
377 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->notifs, lysp_notif_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200378 FREE_STRINGS(ctx, ((struct lysp_node_list*)node)->uniques, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200379 break;
380 case LYS_CHOICE:
381 LY_LIST_FOR_SAFE(((struct lysp_node_choice*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200382 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200383 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200384 FREE_STRING(ctx, ((struct lysp_node_choice*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200385 break;
386 case LYS_CASE:
387 LY_LIST_FOR_SAFE(((struct lysp_node_case*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200388 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200389 }
390 break;
391 case LYS_ANYDATA:
392 case LYS_ANYXML:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200393 FREE_ARRAY(ctx, ((struct lysp_node_anydata*)node)->musts, lysp_restr_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200394 break;
395 case LYS_USES:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200396 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->refines, lysp_refine_free);
397 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->augments, lysp_augment_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200398 break;
399 default:
400 LOGINT(ctx);
401 }
402
403 free(node);
404}
405
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200406static void
407lysp_module_free_(struct lysp_module *module, int dict)
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200408{
409 struct ly_ctx *ctx;
Radek Krejci6f7feb62018-10-12 15:23:02 +0200410 struct lysp_node *node, *next;
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200411
412 LY_CHECK_ARG_RET(NULL, module,);
413 ctx = module->ctx;
414
Radek Krejci151a5b72018-10-19 14:21:44 +0200415 FREE_STRING(ctx, module->name, dict);
416 FREE_STRING(ctx, module->filepath, dict);
417 FREE_STRING(ctx, module->ns, dict); /* or belongs-to */
418 FREE_STRING(ctx, module->prefix, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200419
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200420 FREE_ARRAY(ctx, module->imports, lysp_import_free);
421 FREE_ARRAY(ctx, module->includes, lysp_include_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200422
Radek Krejci151a5b72018-10-19 14:21:44 +0200423 FREE_STRING(ctx, module->org, dict);
424 FREE_STRING(ctx, module->contact, dict);
425 FREE_STRING(ctx, module->dsc, dict);
426 FREE_STRING(ctx, module->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200427
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200428 FREE_ARRAY(ctx, module->revs, lysp_revision_free);
429 FREE_ARRAY(ctx, module->extensions, lysp_ext_free);
430 FREE_ARRAY(ctx, module->features, lysp_feature_free);
431 FREE_ARRAY(ctx, module->identities, lysp_ident_free);
432 FREE_ARRAY(ctx, module->typedefs, lysp_tpdf_free);
433 FREE_ARRAY(ctx, module->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200434 LY_LIST_FOR_SAFE(module->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200435 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200436 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200437 FREE_ARRAY(ctx, module->augments, lysp_augment_free);
438 FREE_ARRAY(ctx, module->rpcs, lysp_action_free);
439 FREE_ARRAY(ctx, module->notifs, lysp_notif_free);
440 FREE_ARRAY(ctx, module->deviations, lysp_deviation_free);
441 FREE_ARRAY(ctx, module->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200442
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200443 free(module);
444}
445
446API void
447lysp_module_free(struct lysp_module *module)
448{
Radek Krejci151a5b72018-10-19 14:21:44 +0200449 if (module) {
450 lysp_module_free_(module, 1);
451 }
452}
453
454static void
455lysc_iffeature_free(struct ly_ctx *UNUSED(ctx), struct lysc_iffeature *iff, int UNUSED(dict))
456{
Radek Krejci2c4e7172018-10-19 15:56:26 +0200457 LY_ARRAY_FREE(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200458 free(iff->expr);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200459}
460
461static void
462lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat, int dict)
463{
Radek Krejci151a5b72018-10-19 14:21:44 +0200464 FREE_STRING(ctx, feat->name, dict);
465 FREE_ARRAY(ctx, feat->iffeatures, lysc_iffeature_free);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200466 LY_ARRAY_FREE(feat->depfeatures);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200467}
468
469static void
470lysc_module_free_(struct lysc_module *module, int dict)
471{
472 struct ly_ctx *ctx;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200473
474 LY_CHECK_ARG_RET(NULL, module,);
475 ctx = module->ctx;
476
Radek Krejci151a5b72018-10-19 14:21:44 +0200477 FREE_STRING(ctx, module->name, dict);
478 FREE_STRING(ctx, module->ns, dict);
479 FREE_STRING(ctx, module->prefix, dict);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200480
481
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200482 FREE_ARRAY(ctx, module->features, lysc_feature_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200483
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200484
485 free(module);
486}
Radek Krejci70853c52018-10-15 14:46:16 +0200487
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200488API void
Radek Krejci86d106e2018-10-18 09:53:19 +0200489lysc_module_free(struct lysc_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200490{
Radek Krejci151a5b72018-10-19 14:21:44 +0200491 if (module) {
492 lysc_module_free_(module, 1);
493 }
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200494}
495
Radek Krejci86d106e2018-10-18 09:53:19 +0200496void
497lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejci70853c52018-10-15 14:46:16 +0200498{
Radek Krejci86d106e2018-10-18 09:53:19 +0200499 if (!module) {
500 return;
501 }
Radek Krejci70853c52018-10-15 14:46:16 +0200502
Radek Krejci86d106e2018-10-18 09:53:19 +0200503 lysc_module_free(module->compiled, private_destructor);
504 lysp_module_free(module->parsed);
505 free(module);
506}
507
Radek Krejci151a5b72018-10-19 14:21:44 +0200508struct iff_stack {
509 int size;
510 int index; /* first empty item */
511 uint8_t *stack;
512};
513
Radek Krejci86d106e2018-10-18 09:53:19 +0200514static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200515iff_stack_push(struct iff_stack *stack, uint8_t value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200516{
Radek Krejci151a5b72018-10-19 14:21:44 +0200517 if (stack->index == stack->size) {
518 stack->size += 4;
519 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
520 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
Radek Krejci70853c52018-10-15 14:46:16 +0200521 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200522 stack->stack[stack->index++] = value;
Radek Krejci70853c52018-10-15 14:46:16 +0200523 return LY_SUCCESS;
524}
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200525
Radek Krejci151a5b72018-10-19 14:21:44 +0200526static uint8_t
527iff_stack_pop(struct iff_stack *stack)
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200528{
Radek Krejci151a5b72018-10-19 14:21:44 +0200529 stack->index--;
530 return stack->stack[stack->index];
531}
532
533static void
534iff_stack_clean(struct iff_stack *stack)
535{
536 stack->size = 0;
537 free(stack->stack);
538}
539
540static void
541iff_setop(uint8_t *list, uint8_t op, int pos)
542{
543 uint8_t *item;
544 uint8_t mask = 3;
545
546 assert(pos >= 0);
547 assert(op <= 3); /* max 2 bits */
548
549 item = &list[pos / 4];
550 mask = mask << 2 * (pos % 4);
551 *item = (*item) & ~mask;
552 *item = (*item) | (op << 2 * (pos % 4));
553}
554
555static uint8_t
556iff_getop(uint8_t *list, int pos)
557{
558 uint8_t *item;
559 uint8_t mask = 3, result;
560
561 assert(pos >= 0);
562
563 item = &list[pos / 4];
564 result = (*item) & (mask << 2 * (pos % 4));
565 return result >> 2 * (pos % 4);
566}
567
568#define LYS_IFF_LP 0x04 /* ( */
569#define LYS_IFF_RP 0x08 /* ) */
570
571API int
572lysc_feature_value(const struct lysc_feature *feature)
573{
574 LY_CHECK_ARG_RET(NULL, feature, -1);
575 return feature->flags & LYS_FENABLED ? 1 : 0;
576}
577
578static struct lysc_feature *
579lysc_feature_find(struct lysc_module *mod, const char *name, size_t len)
580{
581 size_t i;
582 struct lysc_feature *f;
583
584 for (i = 0; i < len; ++i) {
585 if (name[i] == ':') {
586 /* we have a prefixed feature */
587 mod = lysc_module_find_prefix(mod, name, i);
588 LY_CHECK_RET(!mod, NULL);
589
590 name = &name[i + 1];
591 len = len - i - 1;
592 }
593 }
594
595 /* we have the correct module, get the feature */
596 LY_ARRAY_FOR(mod->features, i) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200597 f = &mod->features[i];
Radek Krejci151a5b72018-10-19 14:21:44 +0200598 if (!strncmp(f->name, name, len) && f->name[len] == '\0') {
599 return f;
600 }
601 }
602
603 return NULL;
604}
605
606static int
607lysc_iffeature_value_(const struct lysc_iffeature *iff, int *index_e, int *index_f)
608{
609 uint8_t op;
610 int a, b;
611
612 op = iff_getop(iff->expr, *index_e);
613 (*index_e)++;
614
615 switch (op) {
616 case LYS_IFF_F:
617 /* resolve feature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200618 return lysc_feature_value(iff->features[(*index_f)++]);
Radek Krejci151a5b72018-10-19 14:21:44 +0200619 case LYS_IFF_NOT:
620 /* invert result */
621 return lysc_iffeature_value_(iff, index_e, index_f) ? 0 : 1;
622 case LYS_IFF_AND:
623 case LYS_IFF_OR:
624 a = lysc_iffeature_value_(iff, index_e, index_f);
625 b = lysc_iffeature_value_(iff, index_e, index_f);
626 if (op == LYS_IFF_AND) {
627 return a && b;
628 } else { /* LYS_IFF_OR */
629 return a || b;
630 }
631 }
632
633 return 0;
634}
635
636API int
637lysc_iffeature_value(const struct lysc_iffeature *iff)
638{
639 int index_e = 0, index_f = 0;
640
641 LY_CHECK_ARG_RET(NULL, iff, -1);
642
643 if (iff->expr) {
644 return lysc_iffeature_value_(iff, &index_e, &index_f);
645 }
646 return 0;
647}
648
649/*
650 * op: 1 - enable, 0 - disable
651 */
652/**
653 * @brief Enable/Disable the specified feature in the module.
654 *
655 * If the feature is already set to the desired value, LY_SUCCESS is returned.
656 * By changing the feature, also all the feature which depends on it via their
657 * if-feature statements are again evaluated (disabled if a if-feature statemen
658 * evaluates to false).
659 *
660 * @param[in] mod Compiled module where to set (search for) the feature.
661 * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
662 * set all the features in the module.
663 * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
664 * @return LY_ERR value.
665 */
666static LY_ERR
667lys_feature_change(const struct lysc_module *mod, const char *name, int value)
668{
669 int all = 0;
670 unsigned int u;
671 struct lysc_feature *f, **df;
672 struct lysc_iffeature *iff;
673 struct ly_set *changed;
674
675 if (!mod->features) {
676 LOGERR(mod->ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
677 return LY_EINVAL;
678 }
679
680 if (!strcmp(name, "*")) {
681 /* enable all */
682 all = 1;
683 }
684 changed = ly_set_new();
685
686 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200687 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200688 if (all || !strcmp(f->name, name)) {
689 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
690 if (all) {
691 /* skip already set features */
692 continue;
693 } else {
694 /* feature already set correctly */
695 ly_set_free(changed, NULL);
696 return LY_SUCCESS;
697 }
698 }
699
700 if (value) { /* enable */
701 /* check referenced features if they are enabled */
702 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
703 if (!lysc_iffeature_value(iff)) {
704 if (all) {
705 LOGWRN(mod->ctx,
706 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
707 f->name);
708 goto next;
709 } else {
710 LOGERR(mod->ctx, LY_EDENIED,
711 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
712 f->name);
713 ly_set_free(changed, NULL);
714 return LY_EDENIED;
715 }
716 }
717 }
718 /* enable the feature */
719 f->flags |= LYS_FENABLED;
720 } else { /* disable */
721 /* disable the feature */
722 f->flags &= ~LYS_FENABLED;
723 }
724
725 /* remember the changed feature */
726 ly_set_add(changed, f, LY_SET_OPT_USEASLIST);
727
728 if (!all) {
729 /* stop in case changing a single feature */
730 break;
731 }
732 }
733next:
734 ;
735 }
736
737 if (!all && !changed->count) {
738 LOGERR(mod->ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
739 ly_set_free(changed, NULL);
740 return LY_EINVAL;
741 }
742
743 /* reflect change(s) in the dependent features */
744 for (u = 0; u < changed->count; ++u) {
745 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
746 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
747 * is not done - by default, features are disabled and must be explicitely enabled. */
748 f = changed->objs[u];
749 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature*, df) {
750 if (!((*df)->flags & LYS_FENABLED)) {
751 /* not enabled, nothing to do */
752 continue;
753 }
754 /* check the feature's if-features which could change by the previous change of our feature */
755 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
756 if (!lysc_iffeature_value(iff)) {
757 /* the feature must be disabled now */
758 (*df)->flags &= ~LYS_FENABLED;
759 /* add the feature into the list of changed features */
760 ly_set_add(changed, *df, LY_SET_OPT_USEASLIST);
761 break;
762 }
763 }
764 }
765 }
766
767 ly_set_free(changed, NULL);
768 return LY_SUCCESS;
769}
770
771API LY_ERR
772lys_feature_enable(struct lys_module *module, const char *feature)
773{
774 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
775
776 return lys_feature_change(module->compiled, feature, 1);
777}
778
779API LY_ERR
780lys_feature_disable(struct lys_module *module, const char *feature)
781{
782 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
783
784 return lys_feature_change(module->compiled, feature, 0);
785}
786
787API int
788lys_feature_value(const struct lys_module *module, const char *feature)
789{
790 struct lysc_feature *f;
791 struct lysc_module *mod;
792 unsigned int u;
793
794 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
795 mod = module->compiled;
796
797 /* search for the specified feature */
798 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200799 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200800 if (!strcmp(f->name, feature)) {
801 if (f->flags & LYS_FENABLED) {
802 return 1;
803 } else {
804 return 0;
805 }
806 }
807 }
808
809 /* feature definition not found */
810 return -1;
811}
812
813static LY_ERR
814lys_compile_iffeature(struct lysc_ctx *ctx, const char *value, int UNUSED(options), struct lysc_iffeature *iff, struct lysc_feature *parent)
815{
816 const char *c = value;
817 int r, rc = EXIT_FAILURE;
818 int i, j, last_not, checkversion = 0;
819 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
820 uint8_t op;
821 struct iff_stack stack = {0, 0, NULL};
822 struct lysc_feature *f, **df;
823
824 assert(c);
825
826 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
827 for (i = j = last_not = 0; c[i]; i++) {
828 if (c[i] == '(') {
829 j++;
830 checkversion = 1;
831 continue;
832 } else if (c[i] == ')') {
833 j--;
834 continue;
835 } else if (isspace(c[i])) {
836 checkversion = 1;
837 continue;
838 }
839
840 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
841 if (c[i + r] == '\0') {
842 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
843 "Invalid value \"%s\" of if-feature - unexpected end of expression.", value);
844 return LY_EVALID;
845 } else if (!isspace(c[i + r])) {
846 /* feature name starting with the not/and/or */
847 last_not = 0;
848 f_size++;
849 } else if (c[i] == 'n') { /* not operation */
850 if (last_not) {
851 /* double not */
852 expr_size = expr_size - 2;
853 last_not = 0;
854 } else {
855 last_not = 1;
856 }
857 } else { /* and, or */
858 f_exp++;
859 /* not a not operation */
860 last_not = 0;
861 }
862 i += r;
863 } else {
864 f_size++;
865 last_not = 0;
866 }
867 expr_size++;
868
869 while (!isspace(c[i])) {
870 if (!c[i] || c[i] == ')') {
871 i--;
872 break;
873 }
874 i++;
875 }
876 }
877 if (j || f_exp != f_size) {
878 /* not matching count of ( and ) */
879 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
880 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", value);
881 return LY_EVALID;
882 }
883
884 if (checkversion || expr_size > 1) {
885 /* check that we have 1.1 module */
886 if (ctx->mod->version != LYS_VERSION_1_1) {
887 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
888 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", value);
889 return LY_EVALID;
890 }
891 }
892
893 /* allocate the memory */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200894 LY_ARRAY_CREATE_RET(ctx->mod->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200895 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +0200896 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200897 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->mod->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +0200898
Radek Krejci151a5b72018-10-19 14:21:44 +0200899 stack.size = expr_size;
900 f_size--; expr_size--; /* used as indexes from now */
901
902 for (i--; i >= 0; i--) {
903 if (c[i] == ')') {
904 /* push it on stack */
905 iff_stack_push(&stack, LYS_IFF_RP);
906 continue;
907 } else if (c[i] == '(') {
908 /* pop from the stack into result all operators until ) */
909 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
910 iff_setop(iff->expr, op, expr_size--);
911 }
912 continue;
913 } else if (isspace(c[i])) {
914 continue;
915 }
916
917 /* end of operator or operand -> find beginning and get what is it */
918 j = i + 1;
919 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
920 i--;
921 }
922 i++; /* go back by one step */
923
924 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
925 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
926 /* double not */
927 iff_stack_pop(&stack);
928 } else {
929 /* not has the highest priority, so do not pop from the stack
930 * as in case of AND and OR */
931 iff_stack_push(&stack, LYS_IFF_NOT);
932 }
933 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
934 /* as for OR - pop from the stack all operators with the same or higher
935 * priority and store them to the result, then push the AND to the stack */
936 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
937 op = iff_stack_pop(&stack);
938 iff_setop(iff->expr, op, expr_size--);
939 }
940 iff_stack_push(&stack, LYS_IFF_AND);
941 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
942 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
943 op = iff_stack_pop(&stack);
944 iff_setop(iff->expr, op, expr_size--);
945 }
946 iff_stack_push(&stack, LYS_IFF_OR);
947 } else {
948 /* feature name, length is j - i */
949
950 /* add it to the expression */
951 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
952
953 /* now get the link to the feature definition */
954 f = lysc_feature_find(ctx->mod, &c[i], j - i);
955 LY_CHECK_ERR_GOTO(!f,
956 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
957 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", value, j - i, &c[i]);
958 rc = LY_EINVAL,
959 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +0200960 iff->features[f_size] = f;
961 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200962 if (parent) {
963 /* and add itself into the dependants list */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200964 LY_ARRAY_NEW_RET(ctx->mod->ctx, f->depfeatures, df, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200965 *df = parent;
966
967 /* TODO check for circular dependency */
968 }
969 f_size--;
970 }
971 }
972 while (stack.index) {
973 op = iff_stack_pop(&stack);
974 iff_setop(iff->expr, op, expr_size--);
975 }
976
977 if (++expr_size || ++f_size) {
978 /* not all expected operators and operands found */
979 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
980 "Invalid value \"%s\" of if-feature - processing error.", value);
981 rc = LY_EINT;
982 } else {
983 rc = LY_SUCCESS;
984 }
985
986error:
987 /* cleanup */
988 iff_stack_clean(&stack);
989
990 return rc;
991}
992
993static LY_ERR
994lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
995{
Radek Krejci86d106e2018-10-18 09:53:19 +0200996 unsigned int u;
997 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200998
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200999 if (options & LYSC_OPT_FREE_SP) {
1000 /* just switch the pointers */
1001 feature->name = feature_p->name;
1002 } else {
1003 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001004 feature->name = lydict_insert(ctx->mod->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001005 }
1006 feature->flags = feature_p->flags;
1007
Radek Krejci151a5b72018-10-19 14:21:44 +02001008 if (feature_p->iffeatures) {
1009 /* allocate everything now */
Radek Krejci2c4e7172018-10-19 15:56:26 +02001010 LY_ARRAY_CREATE_RET(ctx->mod->ctx, feature->iffeatures, LY_ARRAY_SIZE(feature_p->iffeatures), LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +02001011
1012 for (u = 0; u < LY_ARRAY_SIZE(feature_p->iffeatures); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +02001013 ret = lys_compile_iffeature(ctx, feature_p->iffeatures[u], options, &feature->iffeatures[u], feature);
Radek Krejci151a5b72018-10-19 14:21:44 +02001014 LY_CHECK_RET(ret);
Radek Krejci2c4e7172018-10-19 15:56:26 +02001015 LY_ARRAY_INCREMENT(feature->iffeatures);
Radek Krejci151a5b72018-10-19 14:21:44 +02001016 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001017 }
1018
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001019 return LY_SUCCESS;
1020}
1021
1022LY_ERR
1023lys_compile(struct lysp_module *sp, int options, struct lysc_module **sc)
1024{
Radek Krejci86d106e2018-10-18 09:53:19 +02001025 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001026 struct lysc_module *mod_c;
Radek Krejci151a5b72018-10-19 14:21:44 +02001027 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001028 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001029
1030 LY_CHECK_ARG_RET(NULL, sc, sp, sp->ctx, LY_EINVAL);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001031
1032 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001033 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 +02001034 return LY_EINVAL;
1035 }
1036
Radek Krejci86d106e2018-10-18 09:53:19 +02001037 ctx.mod = mod_c = calloc(1, sizeof *mod_c);
1038 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1039 mod_c->ctx = sp->ctx;
1040 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001041
1042 if (options & LYSC_OPT_FREE_SP) {
1043 /* just switch the pointers */
1044 mod_c->name = sp->name;
1045 mod_c->ns = sp->ns;
1046 mod_c->prefix = sp->prefix;
1047 } else {
1048 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001049 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1050 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1051 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001052 }
1053
1054 if (sp->features) {
Radek Krejci151a5b72018-10-19 14:21:44 +02001055 /* allocate everything now */
Radek Krejci2c4e7172018-10-19 15:56:26 +02001056 LY_ARRAY_CREATE_RET(ctx.mod->ctx, mod_c->features, LY_ARRAY_SIZE(sp->features), LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +02001057
1058 for (u = 0; u < LY_ARRAY_SIZE(sp->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +02001059 ret = lys_compile_feature(&ctx, &sp->features[u], options, &mod_c->features[u]);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001060 LY_CHECK_GOTO(ret != LY_SUCCESS, error);
Radek Krejci2c4e7172018-10-19 15:56:26 +02001061 LY_ARRAY_INCREMENT(mod_c->features);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001062 }
1063 }
1064
1065 if (options & LYSC_OPT_FREE_SP) {
1066 lysp_module_free_(sp, 0);
1067 }
1068
1069 (*sc) = mod_c;
1070 return LY_SUCCESS;
1071
1072error:
1073
1074 if (options & LYSC_OPT_FREE_SP) {
1075 lysc_module_free_(mod_c, 0);
1076 } else {
1077 lysc_module_free_(mod_c, 1);
1078 }
1079 return ret;
1080}
Radek Krejci86d106e2018-10-18 09:53:19 +02001081
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001082static void
1083lys_latest_unset(struct lys_module *mod)
1084{
1085 if (mod->parsed) {
1086 mod->parsed->latest_revision = 0;
1087 }
1088 if (mod->compiled) {
1089 mod->compiled->latest_revision = 0;
1090 }
1091}
1092
Radek Krejcid33273d2018-10-25 14:55:52 +02001093struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001094lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
1095{
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001096 struct lys_module *mod = NULL, *latest;
Radek Krejcid33273d2018-10-25 14:55:52 +02001097 struct lysp_module *latest_p;
Radek Krejci86d106e2018-10-18 09:53:19 +02001098 LY_ERR ret;
1099
1100 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1101
1102 mod = calloc(1, sizeof *mod);
1103 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1104
1105 switch (format) {
1106 case LYS_IN_YIN:
1107 /* TODO not yet supported
1108 mod = yin_read_module(ctx, data, revision, implement);
1109 */
1110 break;
1111 case LYS_IN_YANG:
1112 ret = yang_parse(ctx, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001113 break;
1114 default:
1115 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1116 break;
1117 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001118 LY_CHECK_RET(ret, NULL);
1119
1120 /* make sure that the newest revision is at position 0 */
1121 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001122
1123 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001124 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001125 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1126 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
1127 lys_module_free(mod, NULL);
1128 return NULL;
1129 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001130 mod->parsed->implemented = 1;
1131 }
1132
1133 if (revision) {
1134 /* check revision of the parsed model */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001135 if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].date)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001136 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
Radek Krejcib7db73a2018-10-24 14:18:40 +02001137 mod->parsed->name, mod->parsed->revs[0].date, revision);
1138 lys_module_free(mod, NULL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001139 return NULL;
1140 }
1141 }
1142
Radek Krejcid33273d2018-10-25 14:55:52 +02001143 if (mod->parsed->submodule) { /* submodule */
1144 /* decide the latest revision */
1145 latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
1146 if (latest_p) {
1147 if (mod->parsed->revs) {
1148 if (!latest_p->revs) {
1149 /* latest has no revision, so mod is anyway newer */
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001150 mod->parsed->latest_revision = 1;
Radek Krejcid33273d2018-10-25 14:55:52 +02001151 latest_p->latest_revision = 0;
1152 } else {
1153 if (strcmp(mod->parsed->revs[0].date, latest_p->revs[0].date) > 0) {
1154 mod->parsed->latest_revision = 1;
1155 latest_p->latest_revision = 0;
1156 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001157 }
1158 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001159 } else {
1160 mod->parsed->latest_revision = 1;
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001161 }
Radek Krejcid33273d2018-10-25 14:55:52 +02001162 } else { /* module */
1163 /* check for duplicity in the context */
1164 if (ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL)) {
1165 if (mod->parsed->revs) {
1166 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1167 mod->parsed->name, mod->parsed->revs[0].date);
1168 } else {
1169 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1170 mod->parsed->name);
1171 }
1172 lys_module_free(mod, NULL);
1173 return NULL;
1174 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001175
1176#if 0
1177 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1178 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1179 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1180 * the anotation definitions available in the internal schema structure. There is another hack in schema
1181 * printers to do not print this internally added annotation. */
1182 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1183 if (lyp_add_ietf_netconf_annotations(mod)) {
1184 lys_free(mod, NULL, 1, 1);
1185 return NULL;
1186 }
1187 }
1188#endif
1189
Radek Krejcid33273d2018-10-25 14:55:52 +02001190 /* decide the latest revision */
1191 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1192 if (latest) {
1193 if (mod->parsed->revs) {
1194 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revs)) {
1195 /* latest has no revision, so mod is anyway newer */
1196 mod->parsed->latest_revision = 1;
1197 lys_latest_unset(latest);
1198 } else {
1199 if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revs[0].date) > 0) {
1200 mod->parsed->latest_revision = 1;
1201 lys_latest_unset(latest);
1202 }
1203 }
1204 }
1205 } else {
1206 mod->parsed->latest_revision = 1;
1207 }
1208
1209 /* add into context */
1210 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1211
1212 }
1213
Radek Krejci86d106e2018-10-18 09:53:19 +02001214 return mod;
1215}
1216
1217API const struct lys_module *
1218lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1219{
Radek Krejcid33273d2018-10-25 14:55:52 +02001220 struct lys_module *result;
1221
1222 result = lys_parse_mem_(ctx, data, format, NULL, 1);
1223 if (result && result->parsed->submodule) {
1224 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1225 result->parsed->name);
1226 lys_module_free(result, NULL);
1227 return NULL;
1228 }
1229 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001230}
1231
1232static void
1233lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1234{
1235#ifdef __APPLE__
1236 char path[MAXPATHLEN];
1237#else
1238 int len;
1239 char path[PATH_MAX], proc_path[32];
1240#endif
1241
1242#ifdef __APPLE__
1243 if (fcntl(fd, F_GETPATH, path) != -1) {
1244 *filename = lydict_insert(ctx, path, 0);
1245 }
1246#else
1247 /* get URI if there is /proc */
1248 sprintf(proc_path, "/proc/self/fd/%d", fd);
1249 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1250 *filename = lydict_insert(ctx, path, len);
1251 }
1252#endif
1253}
1254
Radek Krejcid33273d2018-10-25 14:55:52 +02001255struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001256lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const char *revision, int implement)
1257{
Radek Krejcid33273d2018-10-25 14:55:52 +02001258 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001259 size_t length;
1260 char *addr;
1261
1262 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1263 if (fd < 0) {
1264 LOGARG(ctx, fd);
1265 return NULL;
1266 }
1267
1268 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1269 if (!addr) {
1270 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1271 return NULL;
1272 }
1273
1274 mod = lys_parse_mem_(ctx, addr, format, revision, implement);
1275 ly_munmap(addr, length);
1276
1277 if (mod && !mod->parsed->filepath) {
1278 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1279 }
1280
1281 return mod;
1282}
1283
1284API const struct lys_module *
1285lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1286{
Radek Krejcid33273d2018-10-25 14:55:52 +02001287 struct lys_module *result;
1288
1289 result = lys_parse_fd_(ctx, fd, format, NULL, 1);
1290 if (result && result->parsed->submodule) {
1291 LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
1292 result->parsed->name);
1293 lys_module_free(result, NULL);
1294 return NULL;
1295 }
1296 return result;
Radek Krejci86d106e2018-10-18 09:53:19 +02001297}
1298
Radek Krejcid33273d2018-10-25 14:55:52 +02001299struct lys_module *
1300lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, const char *revision, int implement)
Radek Krejci86d106e2018-10-18 09:53:19 +02001301{
1302 int fd;
Radek Krejcid33273d2018-10-25 14:55:52 +02001303 struct lys_module *mod;
Radek Krejci86d106e2018-10-18 09:53:19 +02001304 const char *rev, *dot, *filename;
1305 size_t len;
1306
1307 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1308
1309 fd = open(path, O_RDONLY);
1310 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1311
Radek Krejcid33273d2018-10-25 14:55:52 +02001312 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
Radek Krejci86d106e2018-10-18 09:53:19 +02001313 close(fd);
1314 LY_CHECK_RET(!mod, NULL);
1315
1316 /* check that name and revision match filename */
1317 filename = strrchr(path, '/');
1318 if (!filename) {
1319 filename = path;
1320 } else {
1321 filename++;
1322 }
1323 rev = strchr(filename, '@');
1324 dot = strrchr(filename, '.');
1325
1326 /* name */
1327 len = strlen(mod->parsed->name);
1328 if (strncmp(filename, mod->parsed->name, len) ||
1329 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1330 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1331 }
1332 if (rev) {
1333 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001334 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001335 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001336 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001337 }
1338 }
1339
1340 if (!mod->parsed->filepath) {
1341 /* store URI */
1342 char rpath[PATH_MAX];
1343 if (realpath(path, rpath) != NULL) {
1344 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1345 } else {
1346 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1347 }
1348 }
1349
1350 return mod;
1351}
1352
Radek Krejcid33273d2018-10-25 14:55:52 +02001353API const struct lys_module *
1354lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1355{
1356 struct lys_module *result;
1357
1358 result = lys_parse_path_(ctx, path, format, NULL, 1);
1359 if (result && result->parsed->submodule) {
1360 LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
1361 path, result->parsed->name);
1362 lys_module_free(result, NULL);
1363 return NULL;
1364 }
1365 return result;
1366}
1367
1368API LY_ERR
1369lys_search_localfile(const char * const *searchpaths, int cwd, const char *name, const char *revision,
1370 char **localfile, LYS_INFORMAT *format)
1371{
1372 size_t len, flen, match_len = 0, dir_len;
1373 int i, implicit_cwd = 0, ret = EXIT_FAILURE;
1374 char *wd, *wn = NULL;
1375 DIR *dir = NULL;
1376 struct dirent *file;
1377 char *match_name = NULL;
1378 LYS_INFORMAT format_aux, match_format = 0;
1379 struct ly_set *dirs;
1380 struct stat st;
1381
1382 LY_CHECK_ARG_RET(NULL, localfile, LY_EINVAL);
1383
1384 /* start to fill the dir fifo with the context's search path (if set)
1385 * and the current working directory */
1386 dirs = ly_set_new();
1387 if (!dirs) {
1388 LOGMEM(NULL);
1389 return EXIT_FAILURE;
1390 }
1391
1392 len = strlen(name);
1393 if (cwd) {
1394 wd = get_current_dir_name();
1395 if (!wd) {
1396 LOGMEM(NULL);
1397 goto cleanup;
1398 } else {
1399 /* add implicit current working directory (./) to be searched,
1400 * this directory is not searched recursively */
1401 if (ly_set_add(dirs, wd, 0) == -1) {
1402 goto cleanup;
1403 }
1404 implicit_cwd = 1;
1405 }
1406 }
1407 if (searchpaths) {
1408 for (i = 0; searchpaths[i]; i++) {
1409 /* check for duplicities with the implicit current working directory */
1410 if (implicit_cwd && !strcmp(dirs->objs[0], searchpaths[i])) {
1411 implicit_cwd = 0;
1412 continue;
1413 }
1414 wd = strdup(searchpaths[i]);
1415 if (!wd) {
1416 LOGMEM(NULL);
1417 goto cleanup;
1418 } else if (ly_set_add(dirs, wd, 0) == -1) {
1419 goto cleanup;
1420 }
1421 }
1422 }
1423 wd = NULL;
1424
1425 /* start searching */
1426 while (dirs->count) {
1427 free(wd);
1428 free(wn); wn = NULL;
1429
1430 dirs->count--;
1431 wd = (char *)dirs->objs[dirs->count];
1432 dirs->objs[dirs->count] = NULL;
1433 LOGVRB("Searching for \"%s\" in %s.", name, wd);
1434
1435 if (dir) {
1436 closedir(dir);
1437 }
1438 dir = opendir(wd);
1439 dir_len = strlen(wd);
1440 if (!dir) {
1441 LOGWRN(NULL, "Unable to open directory \"%s\" for searching (sub)modules (%s).", wd, strerror(errno));
1442 } else {
1443 while ((file = readdir(dir))) {
1444 if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
1445 /* skip . and .. */
1446 continue;
1447 }
1448 free(wn);
1449 if (asprintf(&wn, "%s/%s", wd, file->d_name) == -1) {
1450 LOGMEM(NULL);
1451 goto cleanup;
1452 }
1453 if (stat(wn, &st) == -1) {
1454 LOGWRN(NULL, "Unable to get information about \"%s\" file in \"%s\" when searching for (sub)modules (%s)",
1455 file->d_name, wd, strerror(errno));
1456 continue;
1457 }
1458 if (S_ISDIR(st.st_mode) && (dirs->count || !implicit_cwd)) {
1459 /* we have another subdirectory in searchpath to explore,
1460 * subdirectories are not taken into account in current working dir (dirs->set.g[0]) */
1461 if (ly_set_add(dirs, wn, 0) == -1) {
1462 goto cleanup;
1463 }
1464 /* continue with the next item in current directory */
1465 wn = NULL;
1466 continue;
1467 } else if (!S_ISREG(st.st_mode)) {
1468 /* not a regular file (note that we see the target of symlinks instead of symlinks */
1469 continue;
1470 }
1471
1472 /* here we know that the item is a file which can contain a module */
1473 if (strncmp(name, file->d_name, len) ||
1474 (file->d_name[len] != '.' && file->d_name[len] != '@')) {
1475 /* different filename than the module we search for */
1476 continue;
1477 }
1478
1479 /* get type according to filename suffix */
1480 flen = strlen(file->d_name);
1481 if (!strcmp(&file->d_name[flen - 4], ".yin")) {
1482 format_aux = LYS_IN_YIN;
1483 } else if (!strcmp(&file->d_name[flen - 5], ".yang")) {
1484 format_aux = LYS_IN_YANG;
1485 } else {
1486 /* not supportde suffix/file format */
1487 continue;
1488 }
1489
1490 if (revision) {
1491 /* we look for the specific revision, try to get it from the filename */
1492 if (file->d_name[len] == '@') {
1493 /* check revision from the filename */
1494 if (strncmp(revision, &file->d_name[len + 1], strlen(revision))) {
1495 /* another revision */
1496 continue;
1497 } else {
1498 /* exact revision */
1499 free(match_name);
1500 match_name = wn;
1501 wn = NULL;
1502 match_len = dir_len + 1 + len;
1503 match_format = format_aux;
1504 goto success;
1505 }
1506 } else {
1507 /* continue trying to find exact revision match, use this only if not found */
1508 free(match_name);
1509 match_name = wn;
1510 wn = NULL;
1511 match_len = dir_len + 1 +len;
1512 match_format = format_aux;
1513 continue;
1514 }
1515 } else {
1516 /* remember the revision and try to find the newest one */
1517 if (match_name) {
1518 if (file->d_name[len] != '@' ||
1519 lysp_check_date(NULL, &file->d_name[len + 1], flen - (format_aux == LYS_IN_YANG ? 5 : 4) - len - 1, NULL)) {
1520 continue;
1521 } else if (match_name[match_len] == '@' &&
1522 (strncmp(&match_name[match_len + 1], &file->d_name[len + 1], LY_REV_SIZE - 1) >= 0)) {
1523 continue;
1524 }
1525 free(match_name);
1526 }
1527
1528 match_name = wn;
1529 wn = NULL;
1530 match_len = dir_len + 1 + len;
1531 match_format = format_aux;
1532 continue;
1533 }
1534 }
1535 }
1536 }
1537
1538success:
1539 (*localfile) = match_name;
1540 match_name = NULL;
1541 if (format) {
1542 (*format) = match_format;
1543 }
1544 ret = EXIT_SUCCESS;
1545
1546cleanup:
1547 free(wn);
1548 free(wd);
1549 if (dir) {
1550 closedir(dir);
1551 }
1552 free(match_name);
1553 ly_set_free(dirs, free);
1554
1555 return ret;
1556}
1557
1558LY_ERR
1559lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement,
1560 struct lys_module **result)
1561{
1562 size_t len;
1563 int fd;
1564 char *filepath = NULL, *dot, *rev, *filename;
1565 LYS_INFORMAT format;
1566 struct lys_module *mod = NULL;
1567 LY_ERR ret = LY_SUCCESS;
1568
1569 LY_CHECK_RET(lys_search_localfile(ly_ctx_get_searchdirs(ctx), !(ctx->flags & LY_CTX_DISABLE_SEARCHDIR_CWD), name, revision,
1570 &filepath, &format));
1571 LY_CHECK_ERR_RET(!filepath, LOGERR(ctx, LY_ENOTFOUND, "Data model \"%s%s%s\" not found in local searchdirs.",
1572 name, revision ? "@" : "", revision ? revision : ""), LY_ENOTFOUND);
1573
1574
1575 LOGVRB("Loading schema from \"%s\" file.", filepath);
1576
1577 /* open the file */
1578 fd = open(filepath, O_RDONLY);
1579 LY_CHECK_ERR_GOTO(fd < 0, LOGERR(ctx, LY_ESYS, "Unable to open data model file \"%s\" (%s).",
1580 filepath, strerror(errno)); ret = LY_ESYS, cleanup);
1581
1582 mod = lys_parse_fd_(ctx, fd, format, revision, implement);
1583 close(fd);
1584 LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
1585
1586 /* check that name and revision match filename */
1587 filename = strrchr(filepath, '/');
1588 if (!filename) {
1589 filename = filepath;
1590 } else {
1591 filename++;
1592 }
1593 /* name */
1594 len = strlen(mod->parsed->name);
1595 rev = strchr(filename, '@');
1596 dot = strrchr(filepath, '.');
1597 if (strncmp(filename, mod->parsed->name, len) ||
1598 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1599 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1600 }
1601 /* revision */
1602 if (rev) {
1603 len = dot - ++rev;
1604 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
1605 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
1606 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
1607 }
1608 }
1609
1610 if (!mod->parsed->filepath) {
1611 char rpath[PATH_MAX];
1612 if (realpath(filepath, rpath) != NULL) {
1613 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1614 } else {
1615 mod->parsed->filepath = lydict_insert(ctx, filepath, 0);
1616 }
1617 }
1618
1619 *result = mod;
1620
1621 /* success */
1622cleanup:
1623 free(filepath);
1624 return ret;
1625}