blob: 29e418e665481cc8c2870ff75996a3c47e3e42ee [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 Krejci86d106e2018-10-18 09:53:19 +020018#include <errno.h>
19#include <fcntl.h>
20#include <linux/limits.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <unistd.h>
Radek Krejci3f5e3db2018-10-11 15:57:47 +020026
27#include "libyang.h"
Radek Krejci86d106e2018-10-18 09:53:19 +020028#include "context.h"
Radek Krejci70853c52018-10-15 14:46:16 +020029#include "tree_schema_internal.h"
Radek Krejci3f5e3db2018-10-11 15:57:47 +020030
Radek Krejci2c4e7172018-10-19 15:56:26 +020031#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 +020032#define FREE_MEMBER(CTX, MEMBER, FUNC) if (MEMBER) {FUNC(CTX, MEMBER, dict);free(MEMBER);}
Radek Krejci151a5b72018-10-19 14:21:44 +020033#define FREE_STRING(CTX, STRING, DICT) if (DICT && STRING) {lydict_remove(CTX, STRING);}
Radek Krejci2c4e7172018-10-19 15:56:26 +020034#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 +020035
Radek Krejcidd4e8d42018-10-16 14:55:43 +020036static void lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict);
37static void lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020038
Radek Krejci86d106e2018-10-18 09:53:19 +020039#define LYSC_CTX_BUFSIZE 4086
40struct lysc_ctx {
41 struct lysc_module *mod;
42 uint16_t path_len;
43 char path[LYSC_CTX_BUFSIZE];
44};
45
Radek Krejci6f7feb62018-10-12 15:23:02 +020046static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020047lysp_stmt_free(struct ly_ctx *ctx, struct lysp_stmt *stmt, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020048{
49 struct lysp_stmt *child, *next;
50
Radek Krejci151a5b72018-10-19 14:21:44 +020051 FREE_STRING(ctx, stmt->stmt, dict);
52 FREE_STRING(ctx, stmt->arg, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020053
54 LY_LIST_FOR_SAFE(stmt->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020055 lysp_stmt_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020056 }
57
58 free(stmt);
59}
60
61static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020062lysp_ext_instance_free(struct ly_ctx *ctx, struct lysp_ext_instance *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020063{
64 struct lysp_stmt *stmt, *next;
65
Radek Krejci151a5b72018-10-19 14:21:44 +020066 FREE_STRING(ctx, ext->name, dict);
67 FREE_STRING(ctx, ext->argument, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020068
69 LY_LIST_FOR_SAFE(ext->child, next, stmt) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +020070 lysp_stmt_free(ctx, stmt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +020071 }
72}
73
74static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020075lysp_import_free(struct ly_ctx *ctx, struct lysp_import *import, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020076{
Radek Krejci151a5b72018-10-19 14:21:44 +020077 FREE_STRING(ctx, import->name, dict);
78 FREE_STRING(ctx, import->prefix, dict);
79 FREE_STRING(ctx, import->dsc, dict);
80 FREE_STRING(ctx, import->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +020081 FREE_ARRAY(ctx, import->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +020082}
83
84static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020085lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020086{
Radek Krejci151a5b72018-10-19 14:21:44 +020087 FREE_STRING(ctx, include->name, dict);
88 FREE_STRING(ctx, include->dsc, dict);
89 FREE_STRING(ctx, include->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +020090 FREE_ARRAY(ctx, include->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +020091}
92
93static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +020094lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +020095{
Radek Krejci151a5b72018-10-19 14:21:44 +020096 FREE_STRING(ctx, rev->dsc, dict);
97 FREE_STRING(ctx, rev->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +020098 FREE_ARRAY(ctx, rev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +020099}
100
101static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200102lysp_ext_free(struct ly_ctx *ctx, struct lysp_ext *ext, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200103{
Radek Krejci151a5b72018-10-19 14:21:44 +0200104 FREE_STRING(ctx, ext->name, dict);
105 FREE_STRING(ctx, ext->argument, dict);
106 FREE_STRING(ctx, ext->dsc, dict);
107 FREE_STRING(ctx, ext->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200108 FREE_ARRAY(ctx, ext->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200109}
110
111static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200112lysp_feature_free(struct ly_ctx *ctx, struct lysp_feature *feat, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200113{
Radek Krejci151a5b72018-10-19 14:21:44 +0200114 FREE_STRING(ctx, feat->name, dict);
115 FREE_STRINGS(ctx, feat->iffeatures, 1);
116 FREE_STRING(ctx, feat->dsc, dict);
117 FREE_STRING(ctx, feat->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200118 FREE_ARRAY(ctx, feat->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200119}
120
121static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200122lysp_ident_free(struct ly_ctx *ctx, struct lysp_ident *ident, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200123{
Radek Krejci151a5b72018-10-19 14:21:44 +0200124 FREE_STRING(ctx, ident->name, dict);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200125 FREE_STRINGS(ctx, ident->iffeatures, 1);
Radek Krejci151a5b72018-10-19 14:21:44 +0200126 FREE_STRINGS(ctx, ident->bases, dict);
127 FREE_STRING(ctx, ident->dsc, dict);
128 FREE_STRING(ctx, ident->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200129 FREE_ARRAY(ctx, ident->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200130}
131
132static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200133lysp_restr_free(struct ly_ctx *ctx, struct lysp_restr *restr, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200134{
Radek Krejci151a5b72018-10-19 14:21:44 +0200135 FREE_STRING(ctx, restr->arg, dict);
136 FREE_STRING(ctx, restr->emsg, dict);
137 FREE_STRING(ctx, restr->eapptag, dict);
138 FREE_STRING(ctx, restr->dsc, dict);
139 FREE_STRING(ctx, restr->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200140 FREE_ARRAY(ctx, restr->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200141}
142
143static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200144lysp_type_enum_free(struct ly_ctx *ctx, struct lysp_type_enum *item, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200145{
Radek Krejci151a5b72018-10-19 14:21:44 +0200146 FREE_STRING(ctx, item->name, dict);
147 FREE_STRING(ctx, item->dsc, dict);
148 FREE_STRING(ctx, item->ref, dict);
149 FREE_STRINGS(ctx, item->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200150 FREE_ARRAY(ctx, item->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200151}
152
153static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200154lysp_type_free(struct ly_ctx *ctx, struct lysp_type *type, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200155{
Radek Krejci151a5b72018-10-19 14:21:44 +0200156 FREE_STRING(ctx, type->name, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200157 FREE_MEMBER(ctx, type->range, lysp_restr_free);
158 FREE_MEMBER(ctx, type->length, lysp_restr_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200159 FREE_ARRAY(ctx, type->patterns, lysp_restr_free);
160 FREE_ARRAY(ctx, type->enums, lysp_type_enum_free);
161 FREE_ARRAY(ctx, type->bits, lysp_type_enum_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200162 FREE_STRING(ctx, type->path, dict);
163 FREE_STRINGS(ctx, type->bases, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200164 FREE_ARRAY(ctx, type->types, lysp_type_free);
165 FREE_ARRAY(ctx, type->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200166}
167
168static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200169lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200170{
Radek Krejci151a5b72018-10-19 14:21:44 +0200171 FREE_STRING(ctx, tpdf->name, dict);
172 FREE_STRING(ctx, tpdf->units, dict);
173 FREE_STRING(ctx, tpdf->dflt, dict);
174 FREE_STRING(ctx, tpdf->dsc, dict);
175 FREE_STRING(ctx, tpdf->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200176 FREE_ARRAY(ctx, tpdf->exts, lysp_ext_instance_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200177 lysp_type_free(ctx, &tpdf->type, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200178}
179
180static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200181lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200182{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200183 struct lysp_node *node, *next;
184
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200185 FREE_ARRAY(ctx, inout->musts, lysp_restr_free);
186 FREE_ARRAY(ctx, inout->typedefs, lysp_tpdf_free);
187 FREE_ARRAY(ctx, inout->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200188 LY_LIST_FOR_SAFE(inout->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200189 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200190 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200191 FREE_ARRAY(ctx, inout->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200192
193}
194
195static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200196lysp_action_free(struct ly_ctx *ctx, struct lysp_action *action, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200197{
Radek Krejci151a5b72018-10-19 14:21:44 +0200198 FREE_STRING(ctx, action->name, dict);
199 FREE_STRING(ctx, action->dsc, dict);
200 FREE_STRING(ctx, action->ref, dict);
201 FREE_STRINGS(ctx, action->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200202 FREE_ARRAY(ctx, action->typedefs, lysp_tpdf_free);
203 FREE_ARRAY(ctx, action->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200204 FREE_MEMBER(ctx, action->input, lysp_action_inout_free);
205 FREE_MEMBER(ctx, action->output, lysp_action_inout_free);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200206 FREE_ARRAY(ctx, action->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200207}
208
209static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200210lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200211{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200212 struct lysp_node *node, *next;
213
Radek Krejci151a5b72018-10-19 14:21:44 +0200214 FREE_STRING(ctx, notif->name, dict);
215 FREE_STRING(ctx, notif->dsc, dict);
216 FREE_STRING(ctx, notif->ref, dict);
217 FREE_STRINGS(ctx, notif->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200218 FREE_ARRAY(ctx, notif->musts, lysp_restr_free);
219 FREE_ARRAY(ctx, notif->typedefs, lysp_tpdf_free);
220 FREE_ARRAY(ctx, notif->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200221 LY_LIST_FOR_SAFE(notif->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200222 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200223 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200224 FREE_ARRAY(ctx, notif->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200225}
226
227static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200228lysp_grp_free(struct ly_ctx *ctx, struct lysp_grp *grp, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200229{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200230 struct lysp_node *node, *next;
231
Radek Krejci151a5b72018-10-19 14:21:44 +0200232 FREE_STRING(ctx, grp->name, dict);
233 FREE_STRING(ctx, grp->dsc, dict);
234 FREE_STRING(ctx, grp->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200235 FREE_ARRAY(ctx, grp->typedefs, lysp_tpdf_free);
236 FREE_ARRAY(ctx, grp->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200237 LY_LIST_FOR_SAFE(grp->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, grp->actions, lysp_action_free);
241 FREE_ARRAY(ctx, grp->notifs, lysp_notif_free);
242 FREE_ARRAY(ctx, grp->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200243}
244
245static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200246lysp_when_free(struct ly_ctx *ctx, struct lysp_when *when, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200247{
Radek Krejci151a5b72018-10-19 14:21:44 +0200248 FREE_STRING(ctx, when->cond, dict);
249 FREE_STRING(ctx, when->dsc, dict);
250 FREE_STRING(ctx, when->ref, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200251 FREE_ARRAY(ctx, when->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200252}
253
254static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200255lysp_augment_free(struct ly_ctx *ctx, struct lysp_augment *augment, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200256{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200257 struct lysp_node *node, *next;
258
Radek Krejci151a5b72018-10-19 14:21:44 +0200259 FREE_STRING(ctx, augment->nodeid, dict);
260 FREE_STRING(ctx, augment->dsc, dict);
261 FREE_STRING(ctx, augment->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200262 FREE_MEMBER(ctx, augment->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200263 FREE_STRINGS(ctx, augment->iffeatures, 1);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200264 LY_LIST_FOR_SAFE(augment->child, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200265 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200266 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200267 FREE_ARRAY(ctx, augment->actions, lysp_action_free);
268 FREE_ARRAY(ctx, augment->notifs, lysp_notif_free);
269 FREE_ARRAY(ctx, augment->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200270}
271
272static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200273lysp_deviate_free(struct ly_ctx *ctx, struct lysp_deviate *d, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200274{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200275 struct lysp_deviate_add *add = (struct lysp_deviate_add*)d;
276 struct lysp_deviate_rpl *rpl = (struct lysp_deviate_rpl*)d;
277
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200278 FREE_ARRAY(ctx, d->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200279 switch(d->mod) {
280 case LYS_DEV_NOT_SUPPORTED:
281 /* nothing to do */
282 break;
283 case LYS_DEV_ADD:
284 case LYS_DEV_DELETE: /* compatible for dynamically allocated data */
Radek Krejci151a5b72018-10-19 14:21:44 +0200285 FREE_STRING(ctx, add->units, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200286 FREE_ARRAY(ctx, add->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200287 FREE_STRINGS(ctx, add->uniques, dict);
288 FREE_STRINGS(ctx, add->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200289 break;
290 case LYS_DEV_REPLACE:
291 FREE_MEMBER(ctx, rpl->type, lysp_type_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200292 FREE_STRING(ctx, rpl->units, dict);
293 FREE_STRING(ctx, rpl->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200294 break;
295 default:
296 LOGINT(ctx);
297 break;
298 }
299}
300
301static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200302lysp_deviation_free(struct ly_ctx *ctx, struct lysp_deviation *dev, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200303{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200304 struct lysp_deviate *next, *iter;
305
Radek Krejci151a5b72018-10-19 14:21:44 +0200306 FREE_STRING(ctx, dev->nodeid, dict);
307 FREE_STRING(ctx, dev->dsc, dict);
308 FREE_STRING(ctx, dev->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200309 LY_LIST_FOR_SAFE(dev->deviates, next, iter) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200310 lysp_deviate_free(ctx, iter, dict);
Michal Vasko8447f6a2018-10-15 10:56:16 +0200311 free(iter);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200312 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200313 FREE_ARRAY(ctx, dev->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200314}
315
316static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200317lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200318{
Radek Krejci151a5b72018-10-19 14:21:44 +0200319 FREE_STRING(ctx, ref->nodeid, dict);
320 FREE_STRING(ctx, ref->dsc, dict);
321 FREE_STRING(ctx, ref->ref, dict);
322 FREE_STRINGS(ctx, ref->iffeatures, 1);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200323 FREE_ARRAY(ctx, ref->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200324 FREE_STRING(ctx, ref->presence, dict);
325 FREE_STRINGS(ctx, ref->dflts, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200326 FREE_ARRAY(ctx, ref->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200327}
328
329static void
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200330lysp_node_free(struct ly_ctx *ctx, struct lysp_node *node, int dict)
Radek Krejci6f7feb62018-10-12 15:23:02 +0200331{
Radek Krejci6f7feb62018-10-12 15:23:02 +0200332 struct lysp_node *child, *next;
333
Radek Krejci151a5b72018-10-19 14:21:44 +0200334 FREE_STRING(ctx, node->name, dict);
335 FREE_STRING(ctx, node->dsc, dict);
336 FREE_STRING(ctx, node->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200337 FREE_MEMBER(ctx, node->when, lysp_when_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200338 FREE_STRINGS(ctx, node->iffeatures, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200339 FREE_ARRAY(ctx, node->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200340
341 switch(node->nodetype) {
342 case LYS_CONTAINER:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200343 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200344 FREE_STRING(ctx, ((struct lysp_node_container*)node)->presence, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200345 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->typedefs, lysp_tpdf_free);
346 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200347 LY_LIST_FOR_SAFE(((struct lysp_node_container*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200348 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200349 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200350 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->actions, lysp_action_free);
351 FREE_ARRAY(ctx, ((struct lysp_node_container*)node)->notifs, lysp_notif_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200352 break;
353 case LYS_LEAF:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200354 FREE_ARRAY(ctx, ((struct lysp_node_leaf*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200355 lysp_type_free(ctx, &((struct lysp_node_leaf*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200356 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->units, dict);
357 FREE_STRING(ctx, ((struct lysp_node_leaf*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200358 break;
359 case LYS_LEAFLIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200360 FREE_ARRAY(ctx, ((struct lysp_node_leaflist*)node)->musts, lysp_restr_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200361 lysp_type_free(ctx, &((struct lysp_node_leaflist*)node)->type, dict);
Radek Krejci151a5b72018-10-19 14:21:44 +0200362 FREE_STRING(ctx, ((struct lysp_node_leaflist*)node)->units, dict);
363 FREE_STRINGS(ctx, ((struct lysp_node_leaflist*)node)->dflts, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200364 break;
365 case LYS_LIST:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200366 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->musts, lysp_restr_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200367 FREE_STRING(ctx, ((struct lysp_node_list*)node)->key, dict);
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200368 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->typedefs, lysp_tpdf_free);
369 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200370 LY_LIST_FOR_SAFE(((struct lysp_node_list*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200371 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200372 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200373 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->actions, lysp_action_free);
374 FREE_ARRAY(ctx, ((struct lysp_node_list*)node)->notifs, lysp_notif_free);
Radek Krejci151a5b72018-10-19 14:21:44 +0200375 FREE_STRINGS(ctx, ((struct lysp_node_list*)node)->uniques, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200376 break;
377 case LYS_CHOICE:
378 LY_LIST_FOR_SAFE(((struct lysp_node_choice*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200379 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200380 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200381 FREE_STRING(ctx, ((struct lysp_node_choice*)node)->dflt, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200382 break;
383 case LYS_CASE:
384 LY_LIST_FOR_SAFE(((struct lysp_node_case*)node)->child, next, child) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200385 lysp_node_free(ctx, child, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200386 }
387 break;
388 case LYS_ANYDATA:
389 case LYS_ANYXML:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200390 FREE_ARRAY(ctx, ((struct lysp_node_anydata*)node)->musts, lysp_restr_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200391 break;
392 case LYS_USES:
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200393 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->refines, lysp_refine_free);
394 FREE_ARRAY(ctx, ((struct lysp_node_uses*)node)->augments, lysp_augment_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200395 break;
396 default:
397 LOGINT(ctx);
398 }
399
400 free(node);
401}
402
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200403static void
404lysp_module_free_(struct lysp_module *module, int dict)
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200405{
406 struct ly_ctx *ctx;
Radek Krejci6f7feb62018-10-12 15:23:02 +0200407 struct lysp_node *node, *next;
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200408
409 LY_CHECK_ARG_RET(NULL, module,);
410 ctx = module->ctx;
411
Radek Krejci151a5b72018-10-19 14:21:44 +0200412 FREE_STRING(ctx, module->name, dict);
413 FREE_STRING(ctx, module->filepath, dict);
414 FREE_STRING(ctx, module->ns, dict); /* or belongs-to */
415 FREE_STRING(ctx, module->prefix, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200416
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200417 FREE_ARRAY(ctx, module->imports, lysp_import_free);
418 FREE_ARRAY(ctx, module->includes, lysp_include_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200419
Radek Krejci151a5b72018-10-19 14:21:44 +0200420 FREE_STRING(ctx, module->org, dict);
421 FREE_STRING(ctx, module->contact, dict);
422 FREE_STRING(ctx, module->dsc, dict);
423 FREE_STRING(ctx, module->ref, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200424
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200425 FREE_ARRAY(ctx, module->revs, lysp_revision_free);
426 FREE_ARRAY(ctx, module->extensions, lysp_ext_free);
427 FREE_ARRAY(ctx, module->features, lysp_feature_free);
428 FREE_ARRAY(ctx, module->identities, lysp_ident_free);
429 FREE_ARRAY(ctx, module->typedefs, lysp_tpdf_free);
430 FREE_ARRAY(ctx, module->groupings, lysp_grp_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200431 LY_LIST_FOR_SAFE(module->data, next, node) {
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200432 lysp_node_free(ctx, node, dict);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200433 }
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200434 FREE_ARRAY(ctx, module->augments, lysp_augment_free);
435 FREE_ARRAY(ctx, module->rpcs, lysp_action_free);
436 FREE_ARRAY(ctx, module->notifs, lysp_notif_free);
437 FREE_ARRAY(ctx, module->deviations, lysp_deviation_free);
438 FREE_ARRAY(ctx, module->exts, lysp_ext_instance_free);
Radek Krejci6f7feb62018-10-12 15:23:02 +0200439
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200440 free(module);
441}
442
443API void
444lysp_module_free(struct lysp_module *module)
445{
Radek Krejci151a5b72018-10-19 14:21:44 +0200446 if (module) {
447 lysp_module_free_(module, 1);
448 }
449}
450
451static void
452lysc_iffeature_free(struct ly_ctx *UNUSED(ctx), struct lysc_iffeature *iff, int UNUSED(dict))
453{
Radek Krejci2c4e7172018-10-19 15:56:26 +0200454 LY_ARRAY_FREE(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200455 free(iff->expr);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200456}
457
458static void
459lysc_feature_free(struct ly_ctx *ctx, struct lysc_feature *feat, int dict)
460{
Radek Krejci151a5b72018-10-19 14:21:44 +0200461 FREE_STRING(ctx, feat->name, dict);
462 FREE_ARRAY(ctx, feat->iffeatures, lysc_iffeature_free);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200463 LY_ARRAY_FREE(feat->depfeatures);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200464}
465
466static void
467lysc_module_free_(struct lysc_module *module, int dict)
468{
469 struct ly_ctx *ctx;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200470
471 LY_CHECK_ARG_RET(NULL, module,);
472 ctx = module->ctx;
473
Radek Krejci151a5b72018-10-19 14:21:44 +0200474 FREE_STRING(ctx, module->name, dict);
475 FREE_STRING(ctx, module->ns, dict);
476 FREE_STRING(ctx, module->prefix, dict);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200477
478
Radek Krejcie53a8dc2018-10-17 12:52:40 +0200479 FREE_ARRAY(ctx, module->features, lysc_feature_free);
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200480
Radek Krejci3f5e3db2018-10-11 15:57:47 +0200481
482 free(module);
483}
Radek Krejci70853c52018-10-15 14:46:16 +0200484
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200485API void
Radek Krejci86d106e2018-10-18 09:53:19 +0200486lysc_module_free(struct lysc_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200487{
Radek Krejci151a5b72018-10-19 14:21:44 +0200488 if (module) {
489 lysc_module_free_(module, 1);
490 }
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200491}
492
Radek Krejci86d106e2018-10-18 09:53:19 +0200493void
494lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv))
Radek Krejci70853c52018-10-15 14:46:16 +0200495{
Radek Krejci86d106e2018-10-18 09:53:19 +0200496 if (!module) {
497 return;
498 }
Radek Krejci70853c52018-10-15 14:46:16 +0200499
Radek Krejci86d106e2018-10-18 09:53:19 +0200500 lysc_module_free(module->compiled, private_destructor);
501 lysp_module_free(module->parsed);
502 free(module);
503}
504
Radek Krejci151a5b72018-10-19 14:21:44 +0200505struct iff_stack {
506 int size;
507 int index; /* first empty item */
508 uint8_t *stack;
509};
510
Radek Krejci86d106e2018-10-18 09:53:19 +0200511static LY_ERR
Radek Krejci151a5b72018-10-19 14:21:44 +0200512iff_stack_push(struct iff_stack *stack, uint8_t value)
Radek Krejci86d106e2018-10-18 09:53:19 +0200513{
Radek Krejci151a5b72018-10-19 14:21:44 +0200514 if (stack->index == stack->size) {
515 stack->size += 4;
516 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
517 LY_CHECK_ERR_RET(!stack->stack, LOGMEM(NULL); stack->size = 0, LY_EMEM);
Radek Krejci70853c52018-10-15 14:46:16 +0200518 }
Radek Krejci151a5b72018-10-19 14:21:44 +0200519 stack->stack[stack->index++] = value;
Radek Krejci70853c52018-10-15 14:46:16 +0200520 return LY_SUCCESS;
521}
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200522
Radek Krejci151a5b72018-10-19 14:21:44 +0200523static uint8_t
524iff_stack_pop(struct iff_stack *stack)
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200525{
Radek Krejci151a5b72018-10-19 14:21:44 +0200526 stack->index--;
527 return stack->stack[stack->index];
528}
529
530static void
531iff_stack_clean(struct iff_stack *stack)
532{
533 stack->size = 0;
534 free(stack->stack);
535}
536
537static void
538iff_setop(uint8_t *list, uint8_t op, int pos)
539{
540 uint8_t *item;
541 uint8_t mask = 3;
542
543 assert(pos >= 0);
544 assert(op <= 3); /* max 2 bits */
545
546 item = &list[pos / 4];
547 mask = mask << 2 * (pos % 4);
548 *item = (*item) & ~mask;
549 *item = (*item) | (op << 2 * (pos % 4));
550}
551
552static uint8_t
553iff_getop(uint8_t *list, int pos)
554{
555 uint8_t *item;
556 uint8_t mask = 3, result;
557
558 assert(pos >= 0);
559
560 item = &list[pos / 4];
561 result = (*item) & (mask << 2 * (pos % 4));
562 return result >> 2 * (pos % 4);
563}
564
565#define LYS_IFF_LP 0x04 /* ( */
566#define LYS_IFF_RP 0x08 /* ) */
567
568API int
569lysc_feature_value(const struct lysc_feature *feature)
570{
571 LY_CHECK_ARG_RET(NULL, feature, -1);
572 return feature->flags & LYS_FENABLED ? 1 : 0;
573}
574
575static struct lysc_feature *
576lysc_feature_find(struct lysc_module *mod, const char *name, size_t len)
577{
578 size_t i;
579 struct lysc_feature *f;
580
581 for (i = 0; i < len; ++i) {
582 if (name[i] == ':') {
583 /* we have a prefixed feature */
584 mod = lysc_module_find_prefix(mod, name, i);
585 LY_CHECK_RET(!mod, NULL);
586
587 name = &name[i + 1];
588 len = len - i - 1;
589 }
590 }
591
592 /* we have the correct module, get the feature */
593 LY_ARRAY_FOR(mod->features, i) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200594 f = &mod->features[i];
Radek Krejci151a5b72018-10-19 14:21:44 +0200595 if (!strncmp(f->name, name, len) && f->name[len] == '\0') {
596 return f;
597 }
598 }
599
600 return NULL;
601}
602
603static int
604lysc_iffeature_value_(const struct lysc_iffeature *iff, int *index_e, int *index_f)
605{
606 uint8_t op;
607 int a, b;
608
609 op = iff_getop(iff->expr, *index_e);
610 (*index_e)++;
611
612 switch (op) {
613 case LYS_IFF_F:
614 /* resolve feature */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200615 return lysc_feature_value(iff->features[(*index_f)++]);
Radek Krejci151a5b72018-10-19 14:21:44 +0200616 case LYS_IFF_NOT:
617 /* invert result */
618 return lysc_iffeature_value_(iff, index_e, index_f) ? 0 : 1;
619 case LYS_IFF_AND:
620 case LYS_IFF_OR:
621 a = lysc_iffeature_value_(iff, index_e, index_f);
622 b = lysc_iffeature_value_(iff, index_e, index_f);
623 if (op == LYS_IFF_AND) {
624 return a && b;
625 } else { /* LYS_IFF_OR */
626 return a || b;
627 }
628 }
629
630 return 0;
631}
632
633API int
634lysc_iffeature_value(const struct lysc_iffeature *iff)
635{
636 int index_e = 0, index_f = 0;
637
638 LY_CHECK_ARG_RET(NULL, iff, -1);
639
640 if (iff->expr) {
641 return lysc_iffeature_value_(iff, &index_e, &index_f);
642 }
643 return 0;
644}
645
646/*
647 * op: 1 - enable, 0 - disable
648 */
649/**
650 * @brief Enable/Disable the specified feature in the module.
651 *
652 * If the feature is already set to the desired value, LY_SUCCESS is returned.
653 * By changing the feature, also all the feature which depends on it via their
654 * if-feature statements are again evaluated (disabled if a if-feature statemen
655 * evaluates to false).
656 *
657 * @param[in] mod Compiled module where to set (search for) the feature.
658 * @param[in] name Name of the feature to set. Asterisk ('*') can be used to
659 * set all the features in the module.
660 * @param[in] value Desired value of the feature: 1 (enable) or 0 (disable).
661 * @return LY_ERR value.
662 */
663static LY_ERR
664lys_feature_change(const struct lysc_module *mod, const char *name, int value)
665{
666 int all = 0;
667 unsigned int u;
668 struct lysc_feature *f, **df;
669 struct lysc_iffeature *iff;
670 struct ly_set *changed;
671
672 if (!mod->features) {
673 LOGERR(mod->ctx, LY_EINVAL, "Unable to switch feature since the module \"%s\" has no features.", mod->name);
674 return LY_EINVAL;
675 }
676
677 if (!strcmp(name, "*")) {
678 /* enable all */
679 all = 1;
680 }
681 changed = ly_set_new();
682
683 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200684 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200685 if (all || !strcmp(f->name, name)) {
686 if ((value && (f->flags & LYS_FENABLED)) || (!value && !(f->flags & LYS_FENABLED))) {
687 if (all) {
688 /* skip already set features */
689 continue;
690 } else {
691 /* feature already set correctly */
692 ly_set_free(changed, NULL);
693 return LY_SUCCESS;
694 }
695 }
696
697 if (value) { /* enable */
698 /* check referenced features if they are enabled */
699 LY_ARRAY_FOR(f->iffeatures, struct lysc_iffeature, iff) {
700 if (!lysc_iffeature_value(iff)) {
701 if (all) {
702 LOGWRN(mod->ctx,
703 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
704 f->name);
705 goto next;
706 } else {
707 LOGERR(mod->ctx, LY_EDENIED,
708 "Feature \"%s\" cannot be enabled since it is disabled by its if-feature condition(s).",
709 f->name);
710 ly_set_free(changed, NULL);
711 return LY_EDENIED;
712 }
713 }
714 }
715 /* enable the feature */
716 f->flags |= LYS_FENABLED;
717 } else { /* disable */
718 /* disable the feature */
719 f->flags &= ~LYS_FENABLED;
720 }
721
722 /* remember the changed feature */
723 ly_set_add(changed, f, LY_SET_OPT_USEASLIST);
724
725 if (!all) {
726 /* stop in case changing a single feature */
727 break;
728 }
729 }
730next:
731 ;
732 }
733
734 if (!all && !changed->count) {
735 LOGERR(mod->ctx, LY_EINVAL, "Feature \"%s\" not found in module \"%s\".", name, mod->name);
736 ly_set_free(changed, NULL);
737 return LY_EINVAL;
738 }
739
740 /* reflect change(s) in the dependent features */
741 for (u = 0; u < changed->count; ++u) {
742 /* If a dependent feature is enabled, it can be now changed by the change (to false) of the value of
743 * its if-feature statements. The reverse logic, automatically enable feature when its feature is enabled
744 * is not done - by default, features are disabled and must be explicitely enabled. */
745 f = changed->objs[u];
746 LY_ARRAY_FOR(f->depfeatures, struct lysc_feature*, df) {
747 if (!((*df)->flags & LYS_FENABLED)) {
748 /* not enabled, nothing to do */
749 continue;
750 }
751 /* check the feature's if-features which could change by the previous change of our feature */
752 LY_ARRAY_FOR((*df)->iffeatures, struct lysc_iffeature, iff) {
753 if (!lysc_iffeature_value(iff)) {
754 /* the feature must be disabled now */
755 (*df)->flags &= ~LYS_FENABLED;
756 /* add the feature into the list of changed features */
757 ly_set_add(changed, *df, LY_SET_OPT_USEASLIST);
758 break;
759 }
760 }
761 }
762 }
763
764 ly_set_free(changed, NULL);
765 return LY_SUCCESS;
766}
767
768API LY_ERR
769lys_feature_enable(struct lys_module *module, const char *feature)
770{
771 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
772
773 return lys_feature_change(module->compiled, feature, 1);
774}
775
776API LY_ERR
777lys_feature_disable(struct lys_module *module, const char *feature)
778{
779 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, LY_EINVAL);
780
781 return lys_feature_change(module->compiled, feature, 0);
782}
783
784API int
785lys_feature_value(const struct lys_module *module, const char *feature)
786{
787 struct lysc_feature *f;
788 struct lysc_module *mod;
789 unsigned int u;
790
791 LY_CHECK_ARG_RET(NULL, module, module->compiled, feature, -1);
792 mod = module->compiled;
793
794 /* search for the specified feature */
795 for (u = 0; u < LY_ARRAY_SIZE(mod->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +0200796 f = &mod->features[u];
Radek Krejci151a5b72018-10-19 14:21:44 +0200797 if (!strcmp(f->name, feature)) {
798 if (f->flags & LYS_FENABLED) {
799 return 1;
800 } else {
801 return 0;
802 }
803 }
804 }
805
806 /* feature definition not found */
807 return -1;
808}
809
810static LY_ERR
811lys_compile_iffeature(struct lysc_ctx *ctx, const char *value, int UNUSED(options), struct lysc_iffeature *iff, struct lysc_feature *parent)
812{
813 const char *c = value;
814 int r, rc = EXIT_FAILURE;
815 int i, j, last_not, checkversion = 0;
816 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
817 uint8_t op;
818 struct iff_stack stack = {0, 0, NULL};
819 struct lysc_feature *f, **df;
820
821 assert(c);
822
823 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
824 for (i = j = last_not = 0; c[i]; i++) {
825 if (c[i] == '(') {
826 j++;
827 checkversion = 1;
828 continue;
829 } else if (c[i] == ')') {
830 j--;
831 continue;
832 } else if (isspace(c[i])) {
833 checkversion = 1;
834 continue;
835 }
836
837 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
838 if (c[i + r] == '\0') {
839 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
840 "Invalid value \"%s\" of if-feature - unexpected end of expression.", value);
841 return LY_EVALID;
842 } else if (!isspace(c[i + r])) {
843 /* feature name starting with the not/and/or */
844 last_not = 0;
845 f_size++;
846 } else if (c[i] == 'n') { /* not operation */
847 if (last_not) {
848 /* double not */
849 expr_size = expr_size - 2;
850 last_not = 0;
851 } else {
852 last_not = 1;
853 }
854 } else { /* and, or */
855 f_exp++;
856 /* not a not operation */
857 last_not = 0;
858 }
859 i += r;
860 } else {
861 f_size++;
862 last_not = 0;
863 }
864 expr_size++;
865
866 while (!isspace(c[i])) {
867 if (!c[i] || c[i] == ')') {
868 i--;
869 break;
870 }
871 i++;
872 }
873 }
874 if (j || f_exp != f_size) {
875 /* not matching count of ( and ) */
876 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
877 "Invalid value \"%s\" of if-feature - non-matching opening and closing parentheses.", value);
878 return LY_EVALID;
879 }
880
881 if (checkversion || expr_size > 1) {
882 /* check that we have 1.1 module */
883 if (ctx->mod->version != LYS_VERSION_1_1) {
884 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
885 "Invalid value \"%s\" of if-feature - YANG 1.1 expression in YANG 1.0 module.", value);
886 return LY_EVALID;
887 }
888 }
889
890 /* allocate the memory */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200891 LY_ARRAY_CREATE_RET(ctx->mod->ctx, iff->features, f_size, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200892 iff->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iff->expr);
Radek Krejci151a5b72018-10-19 14:21:44 +0200893 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejci2c4e7172018-10-19 15:56:26 +0200894 LY_CHECK_ERR_GOTO(!stack.stack || !iff->expr, LOGMEM(ctx->mod->ctx), error);
Radek Krejci151a5b72018-10-19 14:21:44 +0200895
Radek Krejci151a5b72018-10-19 14:21:44 +0200896 stack.size = expr_size;
897 f_size--; expr_size--; /* used as indexes from now */
898
899 for (i--; i >= 0; i--) {
900 if (c[i] == ')') {
901 /* push it on stack */
902 iff_stack_push(&stack, LYS_IFF_RP);
903 continue;
904 } else if (c[i] == '(') {
905 /* pop from the stack into result all operators until ) */
906 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
907 iff_setop(iff->expr, op, expr_size--);
908 }
909 continue;
910 } else if (isspace(c[i])) {
911 continue;
912 }
913
914 /* end of operator or operand -> find beginning and get what is it */
915 j = i + 1;
916 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
917 i--;
918 }
919 i++; /* go back by one step */
920
921 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
922 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
923 /* double not */
924 iff_stack_pop(&stack);
925 } else {
926 /* not has the highest priority, so do not pop from the stack
927 * as in case of AND and OR */
928 iff_stack_push(&stack, LYS_IFF_NOT);
929 }
930 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
931 /* as for OR - pop from the stack all operators with the same or higher
932 * priority and store them to the result, then push the AND to the stack */
933 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
934 op = iff_stack_pop(&stack);
935 iff_setop(iff->expr, op, expr_size--);
936 }
937 iff_stack_push(&stack, LYS_IFF_AND);
938 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
939 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
940 op = iff_stack_pop(&stack);
941 iff_setop(iff->expr, op, expr_size--);
942 }
943 iff_stack_push(&stack, LYS_IFF_OR);
944 } else {
945 /* feature name, length is j - i */
946
947 /* add it to the expression */
948 iff_setop(iff->expr, LYS_IFF_F, expr_size--);
949
950 /* now get the link to the feature definition */
951 f = lysc_feature_find(ctx->mod, &c[i], j - i);
952 LY_CHECK_ERR_GOTO(!f,
953 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
954 "Invalid value \"%s\" of if-feature - unable to find feature \"%.*s\".", value, j - i, &c[i]);
955 rc = LY_EINVAL,
956 error)
Radek Krejci2c4e7172018-10-19 15:56:26 +0200957 iff->features[f_size] = f;
958 LY_ARRAY_INCREMENT(iff->features);
Radek Krejci151a5b72018-10-19 14:21:44 +0200959 if (parent) {
960 /* and add itself into the dependants list */
Radek Krejci2c4e7172018-10-19 15:56:26 +0200961 LY_ARRAY_NEW_RET(ctx->mod->ctx, f->depfeatures, df, LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +0200962 *df = parent;
963
964 /* TODO check for circular dependency */
965 }
966 f_size--;
967 }
968 }
969 while (stack.index) {
970 op = iff_stack_pop(&stack);
971 iff_setop(iff->expr, op, expr_size--);
972 }
973
974 if (++expr_size || ++f_size) {
975 /* not all expected operators and operands found */
976 LOGVAL(ctx->mod->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
977 "Invalid value \"%s\" of if-feature - processing error.", value);
978 rc = LY_EINT;
979 } else {
980 rc = LY_SUCCESS;
981 }
982
983error:
984 /* cleanup */
985 iff_stack_clean(&stack);
986
987 return rc;
988}
989
990static LY_ERR
991lys_compile_feature(struct lysc_ctx *ctx, struct lysp_feature *feature_p, int options, struct lysc_feature *feature)
992{
Radek Krejci86d106e2018-10-18 09:53:19 +0200993 unsigned int u;
994 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200995
Radek Krejcidd4e8d42018-10-16 14:55:43 +0200996 if (options & LYSC_OPT_FREE_SP) {
997 /* just switch the pointers */
998 feature->name = feature_p->name;
999 } else {
1000 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001001 feature->name = lydict_insert(ctx->mod->ctx, feature_p->name, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001002 }
1003 feature->flags = feature_p->flags;
1004
Radek Krejci151a5b72018-10-19 14:21:44 +02001005 if (feature_p->iffeatures) {
1006 /* allocate everything now */
Radek Krejci2c4e7172018-10-19 15:56:26 +02001007 LY_ARRAY_CREATE_RET(ctx->mod->ctx, feature->iffeatures, LY_ARRAY_SIZE(feature_p->iffeatures), LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +02001008
1009 for (u = 0; u < LY_ARRAY_SIZE(feature_p->iffeatures); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +02001010 ret = lys_compile_iffeature(ctx, feature_p->iffeatures[u], options, &feature->iffeatures[u], feature);
Radek Krejci151a5b72018-10-19 14:21:44 +02001011 LY_CHECK_RET(ret);
Radek Krejci2c4e7172018-10-19 15:56:26 +02001012 LY_ARRAY_INCREMENT(feature->iffeatures);
Radek Krejci151a5b72018-10-19 14:21:44 +02001013 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001014 }
1015
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001016 return LY_SUCCESS;
1017}
1018
1019LY_ERR
1020lys_compile(struct lysp_module *sp, int options, struct lysc_module **sc)
1021{
Radek Krejci86d106e2018-10-18 09:53:19 +02001022 struct lysc_ctx ctx = {0};
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001023 struct lysc_module *mod_c;
Radek Krejci151a5b72018-10-19 14:21:44 +02001024 unsigned int u;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001025 LY_ERR ret;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001026
1027 LY_CHECK_ARG_RET(NULL, sc, sp, sp->ctx, LY_EINVAL);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001028
1029 if (sp->submodule) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001030 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 +02001031 return LY_EINVAL;
1032 }
1033
Radek Krejci86d106e2018-10-18 09:53:19 +02001034 ctx.mod = mod_c = calloc(1, sizeof *mod_c);
1035 LY_CHECK_ERR_RET(!mod_c, LOGMEM(sp->ctx), LY_EMEM);
1036 mod_c->ctx = sp->ctx;
1037 mod_c->version = sp->version;
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001038
1039 if (options & LYSC_OPT_FREE_SP) {
1040 /* just switch the pointers */
1041 mod_c->name = sp->name;
1042 mod_c->ns = sp->ns;
1043 mod_c->prefix = sp->prefix;
1044 } else {
1045 /* keep refcounts correct for lysp_module_free() */
Radek Krejci86d106e2018-10-18 09:53:19 +02001046 mod_c->name = lydict_insert(sp->ctx, sp->name, 0);
1047 mod_c->ns = lydict_insert(sp->ctx, sp->ns, 0);
1048 mod_c->prefix = lydict_insert(sp->ctx, sp->prefix, 0);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001049 }
1050
1051 if (sp->features) {
Radek Krejci151a5b72018-10-19 14:21:44 +02001052 /* allocate everything now */
Radek Krejci2c4e7172018-10-19 15:56:26 +02001053 LY_ARRAY_CREATE_RET(ctx.mod->ctx, mod_c->features, LY_ARRAY_SIZE(sp->features), LY_EMEM);
Radek Krejci151a5b72018-10-19 14:21:44 +02001054
1055 for (u = 0; u < LY_ARRAY_SIZE(sp->features); ++u) {
Radek Krejci2c4e7172018-10-19 15:56:26 +02001056 ret = lys_compile_feature(&ctx, &sp->features[u], options, &mod_c->features[u]);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001057 LY_CHECK_GOTO(ret != LY_SUCCESS, error);
Radek Krejci2c4e7172018-10-19 15:56:26 +02001058 LY_ARRAY_INCREMENT(mod_c->features);
Radek Krejcidd4e8d42018-10-16 14:55:43 +02001059 }
1060 }
1061
1062 if (options & LYSC_OPT_FREE_SP) {
1063 lysp_module_free_(sp, 0);
1064 }
1065
1066 (*sc) = mod_c;
1067 return LY_SUCCESS;
1068
1069error:
1070
1071 if (options & LYSC_OPT_FREE_SP) {
1072 lysc_module_free_(mod_c, 0);
1073 } else {
1074 lysc_module_free_(mod_c, 1);
1075 }
1076 return ret;
1077}
Radek Krejci86d106e2018-10-18 09:53:19 +02001078
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001079static void
1080lys_latest_unset(struct lys_module *mod)
1081{
1082 if (mod->parsed) {
1083 mod->parsed->latest_revision = 0;
1084 }
1085 if (mod->compiled) {
1086 mod->compiled->latest_revision = 0;
1087 }
1088}
1089
Radek Krejcib7db73a2018-10-24 14:18:40 +02001090static const struct lys_module *
Radek Krejci86d106e2018-10-18 09:53:19 +02001091lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, const char *revision, int implement)
1092{
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001093 struct lys_module *mod = NULL, *latest;
Radek Krejci86d106e2018-10-18 09:53:19 +02001094 LY_ERR ret;
1095
1096 LY_CHECK_ARG_RET(ctx, ctx, data, NULL);
1097
1098 mod = calloc(1, sizeof *mod);
1099 LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
1100
1101 switch (format) {
1102 case LYS_IN_YIN:
1103 /* TODO not yet supported
1104 mod = yin_read_module(ctx, data, revision, implement);
1105 */
1106 break;
1107 case LYS_IN_YANG:
1108 ret = yang_parse(ctx, data, &mod->parsed);
Radek Krejci86d106e2018-10-18 09:53:19 +02001109 break;
1110 default:
1111 LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
1112 break;
1113 }
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001114 LY_CHECK_RET(ret, NULL);
1115
1116 /* make sure that the newest revision is at position 0 */
1117 lysp_sort_revisions(mod->parsed->revs);
Radek Krejci86d106e2018-10-18 09:53:19 +02001118
1119 if (implement) {
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001120 /* mark the loaded module implemented */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001121 if (ly_ctx_get_module_implemented(ctx, mod->parsed->name)) {
1122 LOGERR(ctx, LY_EDENIED, "Module \"%s\" is already implemented in the context.", mod->parsed->name);
1123 lys_module_free(mod, NULL);
1124 return NULL;
1125 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001126 mod->parsed->implemented = 1;
1127 }
1128
1129 if (revision) {
1130 /* check revision of the parsed model */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001131 if (!mod->parsed->revs || strcmp(revision, mod->parsed->revs[0].date)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001132 LOGERR(ctx, LY_EINVAL, "Module \"%s\" parsed with the wrong revision (\"%s\" instead \"%s\").",
Radek Krejcib7db73a2018-10-24 14:18:40 +02001133 mod->parsed->name, mod->parsed->revs[0].date, revision);
1134 lys_module_free(mod, NULL);
Radek Krejci86d106e2018-10-18 09:53:19 +02001135 return NULL;
1136 }
1137 }
1138
1139 /* check for duplicity in the context */
Radek Krejcib7db73a2018-10-24 14:18:40 +02001140 if (ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL)) {
1141 if (mod->parsed->revs) {
1142 LOGERR(ctx, LY_EEXIST, "Module \"%s\" of revision \"%s\" is already present in the context.",
1143 mod->parsed->name, mod->parsed->revs[0].date);
1144 } else {
1145 LOGERR(ctx, LY_EEXIST, "Module \"%s\" with no revision is already present in the context.",
1146 mod->parsed->name);
1147 }
1148 lys_module_free(mod, NULL);
1149 return NULL;
1150 }
Radek Krejci86d106e2018-10-18 09:53:19 +02001151
Radek Krejci9f5e6fb2018-10-25 09:26:12 +02001152 /* decide the latest revision */
1153 latest = (struct lys_module*)ly_ctx_get_module_latest(ctx, mod->parsed->name);
1154 if (latest) {
1155 if (mod->parsed->revs) {
1156 if ((latest->parsed && !latest->parsed->revs) || (!latest->parsed && !latest->compiled->revs)) {
1157 /* latest has no revision, so mod is anyway newer */
1158 mod->parsed->latest_revision = 1;
1159 lys_latest_unset(latest);
1160 } else {
1161 if (strcmp(mod->parsed->revs[0].date, latest->parsed ? latest->parsed->revs[0].date : latest->compiled->revs[0].date) > 0) {
1162 mod->parsed->latest_revision = 1;
1163 lys_latest_unset(latest);
1164 }
1165 }
1166 }
1167 } else {
1168 mod->parsed->latest_revision = 1;
1169 }
1170
Radek Krejci86d106e2018-10-18 09:53:19 +02001171 /* add into context */
1172 ly_set_add(&ctx->list, mod, LY_SET_OPT_USEASLIST);
1173
1174#if 0
1175 /* hack for NETCONF's edit-config's operation attribute. It is not defined in the schema, but since libyang
1176 * implements YANG metadata (annotations), we need its definition. Because the ietf-netconf schema is not the
1177 * internal part of libyang, we cannot add the annotation into the schema source, but we do it here to have
1178 * the anotation definitions available in the internal schema structure. There is another hack in schema
1179 * printers to do not print this internally added annotation. */
1180 if (mod && ly_strequal(mod->name, "ietf-netconf", 0)) {
1181 if (lyp_add_ietf_netconf_annotations(mod)) {
1182 lys_free(mod, NULL, 1, 1);
1183 return NULL;
1184 }
1185 }
1186#endif
1187
1188 return mod;
1189}
1190
1191API const struct lys_module *
1192lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
1193{
1194 return lys_parse_mem_(ctx, data, format, NULL, 1);
1195}
1196
1197static void
1198lys_parse_set_filename(struct ly_ctx *ctx, const char **filename, int fd)
1199{
1200#ifdef __APPLE__
1201 char path[MAXPATHLEN];
1202#else
1203 int len;
1204 char path[PATH_MAX], proc_path[32];
1205#endif
1206
1207#ifdef __APPLE__
1208 if (fcntl(fd, F_GETPATH, path) != -1) {
1209 *filename = lydict_insert(ctx, path, 0);
1210 }
1211#else
1212 /* get URI if there is /proc */
1213 sprintf(proc_path, "/proc/self/fd/%d", fd);
1214 if ((len = readlink(proc_path, path, PATH_MAX - 1)) > 0) {
1215 *filename = lydict_insert(ctx, path, len);
1216 }
1217#endif
1218}
1219
1220const struct lys_module *
1221lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, const char *revision, int implement)
1222{
1223 const struct lys_module *mod;
1224 size_t length;
1225 char *addr;
1226
1227 LY_CHECK_ARG_RET(ctx, ctx, NULL);
1228 if (fd < 0) {
1229 LOGARG(ctx, fd);
1230 return NULL;
1231 }
1232
1233 LY_CHECK_RET(ly_mmap(ctx, fd, &length, (void **)&addr), NULL);
1234 if (!addr) {
1235 LOGERR(ctx, LY_EINVAL, "Empty schema file.");
1236 return NULL;
1237 }
1238
1239 mod = lys_parse_mem_(ctx, addr, format, revision, implement);
1240 ly_munmap(addr, length);
1241
1242 if (mod && !mod->parsed->filepath) {
1243 lys_parse_set_filename(ctx, &mod->parsed->filepath, fd);
1244 }
1245
1246 return mod;
1247}
1248
1249API const struct lys_module *
1250lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
1251{
1252 return lys_parse_fd_(ctx, fd, format, NULL, 1);
1253}
1254
1255API const struct lys_module *
1256lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
1257{
1258 int fd;
1259 const struct lys_module *mod;
1260 const char *rev, *dot, *filename;
1261 size_t len;
1262
1263 LY_CHECK_ARG_RET(ctx, ctx, path, NULL);
1264
1265 fd = open(path, O_RDONLY);
1266 LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
1267
1268 mod = lys_parse_fd(ctx, fd, format);
1269 close(fd);
1270 LY_CHECK_RET(!mod, NULL);
1271
1272 /* check that name and revision match filename */
1273 filename = strrchr(path, '/');
1274 if (!filename) {
1275 filename = path;
1276 } else {
1277 filename++;
1278 }
1279 rev = strchr(filename, '@');
1280 dot = strrchr(filename, '.');
1281
1282 /* name */
1283 len = strlen(mod->parsed->name);
1284 if (strncmp(filename, mod->parsed->name, len) ||
1285 ((rev && rev != &filename[len]) || (!rev && dot != &filename[len]))) {
1286 LOGWRN(ctx, "File name \"%s\" does not match module name \"%s\".", filename, mod->parsed->name);
1287 }
1288 if (rev) {
1289 len = dot - ++rev;
Radek Krejcib7db73a2018-10-24 14:18:40 +02001290 if (!mod->parsed->revs || len != 10 || strncmp(mod->parsed->revs[0].date, rev, len)) {
Radek Krejci86d106e2018-10-18 09:53:19 +02001291 LOGWRN(ctx, "File name \"%s\" does not match module revision \"%s\".", filename,
Radek Krejcib7db73a2018-10-24 14:18:40 +02001292 mod->parsed->revs ? mod->parsed->revs[0].date : "none");
Radek Krejci86d106e2018-10-18 09:53:19 +02001293 }
1294 }
1295
1296 if (!mod->parsed->filepath) {
1297 /* store URI */
1298 char rpath[PATH_MAX];
1299 if (realpath(path, rpath) != NULL) {
1300 mod->parsed->filepath = lydict_insert(ctx, rpath, 0);
1301 } else {
1302 mod->parsed->filepath = lydict_insert(ctx, path, 0);
1303 }
1304 }
1305
1306 return mod;
1307}
1308