blob: dce8f59d23ecfbf0b8025ae83ded3877ba3541a4 [file] [log] [blame]
Radek Krejcida04f4a2015-05-21 12:54:09 +02001/**
2 * @file context.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief context implementation for libyang
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 */
21
22#define _GNU_SOURCE
Radek Krejcida04f4a2015-05-21 12:54:09 +020023#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <errno.h>
29#include <fcntl.h>
30
31#include "common.h"
32#include "context.h"
33#include "dict.h"
Radek Krejcibc9cf932015-07-30 11:09:39 +020034#include "tree_internal.h"
Radek Krejcida04f4a2015-05-21 12:54:09 +020035
Michal Vasko8d054e42015-08-03 12:42:06 +020036#define IETF_YANG_TYPES_PATH "../models/ietf-yang-types@2013-07-15.h"
37#define IETF_INET_TYPES_PATH "../models/ietf-inet-types@2013-07-15.h"
38#define IETF_YANG_LIB_PATH "../models/ietf-yang-library@2015-07-03.h"
39
40#include IETF_YANG_TYPES_PATH
41#include IETF_INET_TYPES_PATH
42#include IETF_YANG_LIB_PATH
43
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020044API struct ly_ctx *
45ly_ctx_new(const char *search_dir)
Radek Krejcida04f4a2015-05-21 12:54:09 +020046{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020047 struct ly_ctx *ctx;
48 char *cwd;
Radek Krejcida04f4a2015-05-21 12:54:09 +020049
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020050 ctx = calloc(1, sizeof *ctx);
51 if (!ctx) {
52 LOGMEM;
53 return NULL;
54 }
Radek Krejcida04f4a2015-05-21 12:54:09 +020055
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020056 /* dictionary */
57 lydict_init(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +020058
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020059 /* models list */
60 ctx->models.list = calloc(16, sizeof *ctx->models.list);
61 ctx->models.used = 0;
62 ctx->models.size = 16;
63 if (search_dir) {
64 cwd = get_current_dir_name();
65 if (chdir(search_dir)) {
66 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
67 search_dir, strerror(errno));
68 free(cwd);
69 ly_ctx_destroy(ctx);
70 return NULL;
71 }
72 ctx->models.search_path = get_current_dir_name();
73 chdir(cwd);
74 free(cwd);
75 }
Michal Vasko8d054e42015-08-03 12:42:06 +020076 /* load ietf-inet-types */
77 ctx->models.list[0] = lys_parse(ctx, (char *)ietf_inet_types_2013_07_15_yin, LYS_IN_YIN);
78 if (!ctx->models.list[0]) {
79 ly_ctx_destroy(ctx);
80 return NULL;
81 }
82
83 /* load ietf-yang-types */
84 ctx->models.list[1] = lys_parse(ctx, (char *)ietf_yang_types_2013_07_15_yin, LYS_IN_YIN);
85 if (!ctx->models.list[1]) {
86 ly_ctx_destroy(ctx);
87 return NULL;
88 }
89
90 /* load ietf-yang-library */
91 ctx->models.list[2] = lys_parse(ctx, (char *)ietf_yang_library_2015_07_03_yin, LYS_IN_YIN);
92 if (!ctx->models.list[2]) {
93 ly_ctx_destroy(ctx);
94 return NULL;
95 }
Radek Krejcida04f4a2015-05-21 12:54:09 +020096
Radek Krejci6e4ffbb2015-06-16 10:34:41 +020097 return ctx;
Radek Krejcida04f4a2015-05-21 12:54:09 +020098}
99
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200100API void
Michal Vasko60ba9a62015-07-03 14:42:31 +0200101ly_ctx_set_searchdir(struct ly_ctx *ctx, const char *search_dir)
102{
103 char *cwd;
104
105 if (!ctx) {
106 return;
107 }
108
109 if (search_dir) {
110 cwd = get_current_dir_name();
111 if (chdir(search_dir)) {
112 LOGERR(LY_ESYS, "Unable to use search directory \"%s\" (%s)",
113 search_dir, strerror(errno));
114 free(cwd);
115 return;
116 }
117 ctx->models.search_path = get_current_dir_name();
118 chdir(cwd);
119 free(cwd);
120 } else {
121 free(ctx->models.search_path);
122 ctx->models.search_path = NULL;
123 }
124}
125
126API void
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200127ly_ctx_destroy(struct ly_ctx *ctx)
Radek Krejcida04f4a2015-05-21 12:54:09 +0200128{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200129 if (!ctx) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200130 return;
131 }
Radek Krejcida04f4a2015-05-21 12:54:09 +0200132
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200133 /* models list */
Radek Krejcidce51452015-06-16 15:20:08 +0200134 while (ctx->models.used) {
Radek Krejci912da452015-07-29 14:10:06 +0200135 lys_free(ctx->models.list[0]);
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200136 }
137 free(ctx->models.search_path);
138 free(ctx->models.list);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200139
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200140 /* dictionary */
141 lydict_clean(&ctx->dict);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200142
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200143 free(ctx);
Radek Krejcida04f4a2015-05-21 12:54:09 +0200144}
145
Michal Vaskoc425a6b2015-07-03 15:46:29 +0200146API struct ly_submodule *
Radek Krejci63a91a92015-07-29 13:31:04 +0200147ly_ctx_get_submodule(struct ly_module *module, const char *name, const char *revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200148{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200149 struct ly_submodule *result;
150 int i;
Radek Krejciefaeba32015-05-27 14:30:57 +0200151
Radek Krejci63a91a92015-07-29 13:31:04 +0200152 if (!module || !name) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200153 ly_errno = LY_EINVAL;
154 return NULL;
155 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200156
Radek Krejcie98bb4b2015-07-30 14:21:41 +0200157 /* TODO search also for submodules not directly available from the main module */
158
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200159 /* search in modules included by the main module */
160 if (module->type) {
161 module = ((struct ly_submodule *)module)->belongsto;
162 }
163 for (i = 0; i < module->inc_size; i++) {
164 result = module->inc[i].submodule;
165 if (strcmp(name, result->name)) {
166 continue;
167 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200168
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200169 if (!revision || (result->rev_size && !strcmp(revision, result->rev[0].date))) {
170 return result;
171 }
172 }
Radek Krejcice7fb782015-05-29 16:52:34 +0200173
Radek Krejci63a91a92015-07-29 13:31:04 +0200174 return NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200175}
176
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200177API struct ly_module *
Radek Krejci63a91a92015-07-29 13:31:04 +0200178ly_ctx_get_module(struct ly_ctx *ctx, const char *name, const char *revision)
Radek Krejciefaeba32015-05-27 14:30:57 +0200179{
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200180 int i;
181 struct ly_module *result = NULL;
Radek Krejciefaeba32015-05-27 14:30:57 +0200182
Radek Krejci63a91a92015-07-29 13:31:04 +0200183 if (!ctx || !name) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200184 ly_errno = LY_EINVAL;
185 return NULL;
186 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200187
Radek Krejcidce51452015-06-16 15:20:08 +0200188 for (i = 0; i < ctx->models.used; i++) {
Radek Krejcif647e612015-07-30 11:36:07 +0200189 if (!ctx->models.list[i] || strcmp(name, ctx->models.list[i]->name)) {
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200190 continue;
191 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200192
Radek Krejcif647e612015-07-30 11:36:07 +0200193 if (!revision) {
194 /* compare revisons and remember the newest one */
195 if (result) {
196 if (!ctx->models.list[i]->rev_size) {
197 /* the current have no revision, keep the previous with some revision */
198 continue;
199 }
200 if (result->rev_size && strcmp(ctx->models.list[i]->rev[0].date, result->rev[0].date) < 0) {
201 /* the previous found matching module has a newer revision */
202 continue;
203 }
204 }
205
206 /* remember the current match and search for newer version */
207 result = ctx->models.list[i];
208 } else {
209 if (ctx->models.list[i]->rev_size && !strcmp(revision, ctx->models.list[i]->rev[0].date)) {
210 /* matching revision */
211 return result;
212 }
Radek Krejci6e4ffbb2015-06-16 10:34:41 +0200213 }
214 }
Radek Krejciefaeba32015-05-27 14:30:57 +0200215
Radek Krejcif647e612015-07-30 11:36:07 +0200216 return result;
Radek Krejcida04f4a2015-05-21 12:54:09 +0200217}
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200218
Radek Krejci96a10da2015-07-30 11:00:14 +0200219API const char **
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200220ly_ctx_get_module_names(struct ly_ctx *ctx)
221{
222 int i;
Radek Krejci96a10da2015-07-30 11:00:14 +0200223 const char **result = NULL;
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200224
225 if (!ctx) {
226 ly_errno = LY_EINVAL;
227 return NULL;
228 }
229
Michal Vaskoe2ea44b2015-07-07 11:31:48 +0200230 result = malloc((ctx->models.used+1) * sizeof *result);
231
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200232 for (i = 0; i < ctx->models.used; i++) {
Radek Krejci96a10da2015-07-30 11:00:14 +0200233 result[i] = ctx->models.list[i]->name;
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200234 }
Michal Vaskoe2ea44b2015-07-07 11:31:48 +0200235 result[i] = NULL;
Michal Vasko3ec07dc2015-06-30 15:51:30 +0200236
237 return result;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200238}
239
Radek Krejci96a10da2015-07-30 11:00:14 +0200240API const char **
241ly_ctx_get_submodule_names(struct ly_ctx *ctx, const char *module_name)
Michal Vaskofa8c8282015-07-03 15:14:59 +0200242{
243 int i;
Radek Krejci96a10da2015-07-30 11:00:14 +0200244 const char **result = NULL;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200245 struct ly_module *mod;
246
247 if (!ctx) {
248 ly_errno = LY_EINVAL;
249 return NULL;
250 }
251
Radek Krejci96a10da2015-07-30 11:00:14 +0200252 mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vaskofa8c8282015-07-03 15:14:59 +0200253 if (!mod) {
Radek Krejci96a10da2015-07-30 11:00:14 +0200254 LOGERR(LY_EVALID, "Data model \"%s\" not loaded", module_name);
Michal Vaskofa8c8282015-07-03 15:14:59 +0200255 return NULL;
256 }
257
258 result = malloc((mod->inc_size+1) * sizeof *result);
259
260 for (i = 0; i < mod->inc_size; i++) {
Radek Krejci96a10da2015-07-30 11:00:14 +0200261 result[i] = mod->inc[i].submodule->name;
Michal Vaskofa8c8282015-07-03 15:14:59 +0200262 }
263 result[i] = NULL;
264
265 return result;
266}