blob: 1f5fce30674e7f15af617dc17dd911d499368440 [file] [log] [blame]
/**
* @file yang_library.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Static YANG ietf-yang-library implementation
*
* Copyright (c) 2015 CESNET, z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of the Company nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "libyang.h"
#include "common.h"
#include "context.h"
#include "parser.h"
static struct lys_node *
ylib_get_next_sibling_recursive(struct lys_node *siblings, struct lys_node *prev, int *found)
{
struct lys_node *sibling, *node;
LY_TREE_FOR(siblings, sibling) {
if (sibling->nodetype == LYS_GROUPING) {
continue;
}
if (sibling->nodetype == LYS_USES) {
node = ylib_get_next_sibling_recursive(sibling->child, (*found ? NULL : prev), found);
if (node) {
return node;
}
continue;
}
if (*found || !prev) {
return sibling;
}
if (prev == sibling) {
*found = 1;
}
}
return NULL;
}
static struct lys_node *
ylib_get_next_sibling(struct lys_node *siblings, struct lys_node *prev)
{
int found = 0;
return ylib_get_next_sibling_recursive(siblings, prev, &found);
}
static void
ylib_append_children(struct lyd_node *parent, struct lyd_node *child)
{
struct lyd_node *parent_last_child;
if (!parent || !child) {
return;
}
if (!parent->child) {
parent->child = child;
return;
}
parent_last_child = parent->child->prev;
parent->child->prev = child->prev;
parent_last_child->next = child;
child->prev = parent_last_child;
}
static void
ylib_append_list(struct lyd_node_list *sibling, struct lyd_node_list *list)
{
struct lyd_node *sibling_last;
struct lyd_node_list *sibling_last_list;
if (!sibling || !list) {
return;
}
sibling_last = sibling->prev;
sibling->prev = list->prev;
sibling_last->next = (struct lyd_node *)list;
list->prev = sibling_last->next;
sibling_last_list = sibling->lprev;
sibling->lprev = list->lprev;
sibling_last_list->lnext = list;
list->lprev = sibling_last_list->lnext;
}
static void
ylib_append_llist(struct lyd_node_leaflist *sibling, struct lyd_node_leaflist *llist)
{
struct lyd_node *sibling_last;
struct lyd_node_leaflist *sibling_last_llist;
if (!sibling || !llist) {
return;
}
sibling_last = sibling->prev;
sibling->prev = llist->prev;
sibling_last->next = (struct lyd_node *)llist;
llist->prev = sibling_last->next;
sibling_last_llist = sibling->lprev;
sibling->lprev = llist->lprev;
sibling_last_llist->lnext = llist;
llist->lprev = sibling_last_llist->lnext;
}
static struct lyd_node *
ylib_name_space(struct ly_ctx *ctx, struct lys_node *name_node, const char *name)
{
struct lyd_node_leaf *dleaf;
dleaf = calloc(1, sizeof *dleaf);
dleaf->prev = (struct lyd_node *)dleaf;
dleaf->schema = name_node;
dleaf->value_str = lydict_insert(ctx, name, 0);
dleaf->value.string = dleaf->value_str;
dleaf->value_type = LY_TYPE_STRING;
return (struct lyd_node *)dleaf;
}
static struct lyd_node *
ylib_revision(struct ly_ctx *ctx, struct lys_node *revision_node, struct lys_revision *rev, uint8_t rev_size)
{
int i, max = 0;
struct lyd_node_leaf *dleaf;
dleaf = calloc(1, sizeof *dleaf);
dleaf->prev = (struct lyd_node *)dleaf;
dleaf->schema = revision_node;
if (rev_size) {
for (i = 1; i < rev_size; ++i) {
if (strcmp(rev[i].date, rev[max].date) > 0) {
max = i;
}
}
dleaf->value_str = lydict_insert(ctx, rev[max].date, 0);
} else {
dleaf->value_str = lydict_insert(ctx, "", 0);
}
dleaf->value.string = dleaf->value_str;
dleaf->value_type = LY_TYPE_STRING;
return (struct lyd_node *)dleaf;
}
static struct lyd_node *
ylib_schema(struct ly_ctx *ctx, struct lys_node *schema_node, const char *uri)
{
struct lyd_node_leaf *dleaf;
if (!uri) {
return NULL;
}
dleaf = calloc(1, sizeof *dleaf);
dleaf->prev = (struct lyd_node *)dleaf;
dleaf->schema = schema_node;
dleaf->value_str = lydict_insert(ctx, uri, 0);
dleaf->value.string = dleaf->value_str;
dleaf->value_type = LY_TYPE_STRING;
return (struct lyd_node *)dleaf;
}
static struct lyd_node *
ylib_feature(struct ly_ctx *ctx, struct lys_node *feature_node, struct lys_module *mod)
{
int i, j;
struct lyd_node_leaflist *dllist, *ret = NULL;
/* module features */
for (i = 0; i < mod->features_size; ++i) {
if (!(mod->features[i].flags & LYS_FENABLED)) {
continue;
}
dllist = calloc(1, sizeof *dllist);
dllist->prev = (struct lyd_node *)dllist;
dllist->lprev = dllist;
dllist->schema = feature_node;
dllist->value_str = lydict_insert(ctx, mod->features[i].name, 0);
dllist->value.string = dllist->value_str;
dllist->value_type = LY_TYPE_STRING;
if (ret) {
ylib_append_llist(ret, dllist);
} else {
ret = dllist;
}
}
/* submodule features */
for (i = 0; i < mod->inc_size; ++i) {
for (j = 0; j < mod->inc[i].submodule->features_size; ++j) {
if (!(mod->inc[i].submodule->features[j].flags & LYS_FENABLED)) {
continue;
}
dllist = calloc(1, sizeof *dllist);
dllist->schema = feature_node;
dllist->prev = (struct lyd_node *)dllist;
dllist->lprev = dllist;
dllist->value_str = lydict_insert(ctx, mod->inc[i].submodule->features[j].name, 0);
dllist->value.string = dllist->value_str;
dllist->value_type = LY_TYPE_STRING;
if (ret) {
ylib_append_llist(ret, dllist);
} else {
ret = dllist;
}
}
}
return (struct lyd_node *)ret;
}
static struct lyd_node *
ylib_deviation(struct ly_ctx *ctx, struct lys_node *deviation_node, struct lys_module *mod, struct lys_module **modules, int mod_count)
{
int i, j, k;
struct lys_module *target_module;
struct lyd_node *dnode;
struct lyd_node_list *ret = NULL, *dlist;
struct lys_node *deviation_child;
for (i = 0; i < mod_count; ++i) {
for (k = 0; k < modules[i]->deviation_size; ++k) {
if (modules[i]->deviation[k].target->module->type) {
target_module = ((struct lys_submodule *)modules[i]->deviation[k].target->module)->belongsto;
} else {
target_module = modules[i]->deviation[k].target->module;
}
/* we found a module deviating our module */
if (target_module == mod) {
dlist = calloc(1, sizeof *dlist);
dlist->prev = (struct lyd_node *)dlist;
dlist->lprev = dlist;
dlist->schema = deviation_node;
deviation_child = NULL;
while ((deviation_child = ylib_get_next_sibling(deviation_node->child, deviation_child))) {
dnode = NULL;
if (!strcmp(deviation_child->name, "name")) {
dnode = ylib_name_space(ctx, deviation_child, modules[i]->name);
} else if (!strcmp(deviation_child->name, "revision")) {
dnode = ylib_revision(ctx, deviation_child, modules[i]->rev, modules[i]->rev_size);
}
if (dnode) {
ylib_append_children((struct lyd_node *)dlist, dnode);
}
}
if (ret) {
ylib_append_list(ret, dlist);
} else {
ret = dlist;
}
}
}
for (j = 0; j < modules[i]->inc_size; ++j) {
for (k = 0; k < modules[i]->inc[j].submodule->deviation_size; ++k) {
if (modules[i]->inc[j].submodule->deviation[k].target->module->type) {
target_module = ((struct lys_submodule *)
modules[i]->inc[j].submodule->deviation[k].target->module)->belongsto;
} else {
target_module = modules[i]->inc[j].submodule->deviation[k].target->module;
}
/* we found a submodule deviating our module */
if (target_module == mod) {
dlist = calloc(1, sizeof *dlist);
dlist->prev = (struct lyd_node *)dlist;
dlist->lprev = dlist;
dlist->schema = deviation_node;
deviation_child = NULL;
while ((deviation_child = ylib_get_next_sibling(deviation_node->child, deviation_child))) {
dnode = NULL;
if (!strcmp(deviation_child->name, "name")) {
dnode = ylib_name_space(ctx, deviation_child, modules[i]->inc[j].submodule->name);
} else if (!strcmp(deviation_child->name, "revision")) {
dnode = ylib_revision(ctx, deviation_child, modules[i]->inc[j].submodule->rev,
modules[i]->inc[j].submodule->rev_size);
}
if (dnode) {
ylib_append_children((struct lyd_node *)dlist, dnode);
}
}
if (ret) {
ylib_append_list(ret, dlist);
} else {
ret = dlist;
}
}
}
}
}
return (struct lyd_node *)ret;
}
static struct lyd_node *
ylib_conformance(struct ly_ctx *ctx, struct lys_node *conformance_node, int implemented)
{
struct lyd_node_leaf *dleaf;
dleaf = calloc(1, sizeof *dleaf);
dleaf->prev = (struct lyd_node *)dleaf;
dleaf->schema = conformance_node;
if (implemented) {
dleaf->value_str = lydict_insert(ctx, "implement", 0);
} else {
dleaf->value_str = lydict_insert(ctx, "import", 0);
}
dleaf->value.string = dleaf->value_str;
dleaf->value_type = LY_TYPE_STRING;
return (struct lyd_node *)dleaf;
}
static struct lyd_node *
ylib_submodules(struct ly_ctx *ctx, struct lys_node *submodules_node, struct lys_include *inc, uint8_t inc_size)
{
int i;
struct lys_node *submodule_node, *submodule_child;
struct lyd_node *ret = NULL, *dnode;
struct lyd_node_list *dsubmodule = NULL, *dlist;
ret = calloc(1, sizeof *ret);
ret->prev = ret;
ret->schema = submodules_node;
submodule_node = NULL;
while ((submodule_node = ylib_get_next_sibling(submodules_node->child, submodule_node))) {
if (!strcmp(submodule_node->name, "submodule")) {
for (i = 0; i < inc_size; ++i) {
dlist = calloc(1, sizeof *dlist);
dlist->prev = (struct lyd_node *)dlist;
dlist->lprev = dlist;
dlist->schema = submodule_node;
submodule_child = NULL;
while ((submodule_child = ylib_get_next_sibling(submodule_node->child, submodule_child))) {
dnode = NULL;
if (!strcmp(submodule_child->name, "name")) {
dnode = ylib_name_space(ctx, submodule_child, inc[i].submodule->name);
} else if (!strcmp(submodule_child->name, "revision")) {
dnode = ylib_revision(ctx, submodule_child, inc[i].submodule->rev, inc[i].submodule->rev_size);
} else if (!strcmp(submodule_child->name, "schema")) {
dnode = ylib_schema(ctx, submodule_child, inc[i].submodule->uri);
}
if (dnode) {
ylib_append_children((struct lyd_node *)dlist, dnode);
}
}
if (dsubmodule) {
ylib_append_list(dsubmodule, dlist);
} else {
dsubmodule = dlist;
}
}
}
}
ret->child = (struct lyd_node *)dsubmodule;
return ret;
}
static struct lyd_node *
ylib_module_set_id(struct ly_ctx *ctx, struct lys_node *modules_set_id_node)
{
struct lyd_node_leaf *dleaf;
char id[8];
dleaf = calloc(1, sizeof *dleaf);
dleaf->prev = (struct lyd_node *)dleaf;
dleaf->schema = modules_set_id_node;
sprintf(id, "%u", ctx->models.module_set_id);
dleaf->value_str = lydict_insert(ctx, id, 0);
dleaf->value.string = dleaf->value_str;
dleaf->value_type = LY_TYPE_STRING;
return (struct lyd_node *)dleaf;
}
API struct lyd_node *
ly_ctx_info(struct ly_ctx *ctx)
{
int i;
struct lys_module *mod;
struct lys_node *modules_child, *module_child;
struct lyd_node *root, *dnode;
struct lyd_node_list *dlist, *dmodule = NULL;
mod = ly_ctx_get_module(ctx, "ietf-yang-library", NULL);
if (!mod) {
mod = lyp_search_file(ctx, NULL, "ietf-yang-library", NULL);
}
if (!mod || !mod->data || strcmp(mod->data->next->name, "modules")) {
return NULL;
}
root = calloc(1, sizeof *root);
if (!root) {
return NULL;
}
root->prev = root;
root->schema = mod->data;
modules_child = NULL;
while ((modules_child = ylib_get_next_sibling(mod->data->next->child, modules_child))) {
if (!strcmp(modules_child->name, "module")) {
for (i = 0; i < ctx->models.used; ++i) {
dlist = calloc(1, sizeof *dlist);
dlist->prev = (struct lyd_node *)dlist;
dlist->lprev = dlist;
dlist->schema = modules_child;
module_child = NULL;
while ((module_child = ylib_get_next_sibling(modules_child->child, module_child))) {
dnode = NULL;
if (!strcmp(module_child->name, "name")) {
dnode = ylib_name_space(ctx, module_child, ctx->models.list[i]->name);
} else if (!strcmp(module_child->name, "revision")) {
dnode = ylib_revision(ctx, module_child, ctx->models.list[i]->rev, ctx->models.list[i]->rev_size);
} else if (!strcmp(module_child->name, "schema")) {
dnode = ylib_schema(ctx, module_child, ctx->models.list[i]->uri);
} else if (!strcmp(module_child->name, "namespace")) {
dnode = ylib_name_space(ctx, module_child, ctx->models.list[i]->ns);
} else if (!strcmp(module_child->name, "feature")) {
dnode = ylib_feature(ctx, module_child, ctx->models.list[i]);
} else if (!strcmp(module_child->name, "deviation")) {
if (ctx->models.list[i]->deviated) {
dnode = ylib_deviation(ctx, module_child, ctx->models.list[i], ctx->models.list, ctx->models.used);
}
} else if (!strcmp(module_child->name, "conformance")) {
dnode = ylib_conformance(ctx, module_child, ctx->models.list[i]->implemented);
} else if (!strcmp(module_child->name, "submodules")) {
if (ctx->models.list[i]->inc_size) {
dnode = ylib_submodules(ctx, module_child, ctx->models.list[i]->inc, ctx->models.list[i]->inc_size);
}
}
if (dnode) {
ylib_append_children((struct lyd_node *)dlist, dnode);
}
}
if (dmodule) {
ylib_append_list(dmodule, dlist);
} else {
dmodule = dlist;
}
}
}
}
assert(dmodule);
ylib_append_children(root, (struct lyd_node *)dmodule);
dnode = NULL;
modules_child = NULL;
while ((modules_child = ylib_get_next_sibling(mod->data->next->child, modules_child))) {
if (!strcmp(modules_child->name, "module-set-id")) {
dnode = ylib_module_set_id(ctx, modules_child);
}
}
assert(dnode);
ylib_append_children(root, dnode);
return root;
}