blob: f1af868647f10895d1abfd9dbb9b9642b51875f9 [file] [log] [blame]
#include <boost/algorithm/string/predicate.hpp>
#include <cmath>
#include "datastore_access.hpp"
#include "libyang_utils.hpp"
#include "utils.hpp"
leaf_data_ leafValueFromNode(libyang::S_Data_Node_Leaf_List node)
{
std::function<leaf_data_(libyang::S_Data_Node_Leaf_List)> impl = [&impl] (libyang::S_Data_Node_Leaf_List node) -> leaf_data_ {
// value_type() is what's ACTUALLY stored inside `node`
// Leafrefs sometimes don't hold a reference to another, but they have the actual pointed-to value.
switch (node->value_type()) {
case LY_TYPE_ENUM:
return enum_{node->value()->enm()->name()};
case LY_TYPE_UINT8:
return node->value()->uint8();
case LY_TYPE_UINT16:
return node->value()->uint16();
case LY_TYPE_UINT32:
return node->value()->uint32();
case LY_TYPE_UINT64:
return node->value()->uint64();
case LY_TYPE_INT8:
return node->value()->int8();
case LY_TYPE_INT16:
return node->value()->int16();
case LY_TYPE_INT32:
return node->value()->int32();
case LY_TYPE_INT64:
return node->value()->int64();
case LY_TYPE_DEC64:
{
auto v = node->value()->dec64();
return v.value * std::pow(10, -v.digits);
}
case LY_TYPE_BOOL:
return node->value()->bln();
case LY_TYPE_STRING:
return std::string{node->value()->string()};
case LY_TYPE_BINARY:
return binary_{node->value()->binary()};
case LY_TYPE_IDENT:
return identityRef_{node->value()->ident()->module()->name(), node->value()->ident()->name()};
case LY_TYPE_EMPTY:
return empty_{};
case LY_TYPE_LEAFREF:
{
auto refsTo = node->value()->leafref();
assert(refsTo);
return impl(std::make_shared<libyang::Data_Node_Leaf_List>(node->value()->leafref()));
}
case LY_TYPE_BITS:
{
auto bits = node->value()->bit();
std::vector<libyang::S_Type_Bit> filterNull;
std::copy_if(bits.begin(), bits.end(), std::back_inserter(filterNull), [] (auto bit) { return bit; });
bits_ res;
std::transform(filterNull.begin(), filterNull.end(), std::inserter(res.m_bits, res.m_bits.end()), [] (const auto& bit) { return bit->name(); });
return bits_{res};
}
default:
return std::string{"(can't print)"};
}
};
return impl(node);
}
namespace {
void impl_lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix)
{
auto stripXPathPrefix = [&ignoredXPathPrefix] (auto path) {
return ignoredXPathPrefix && path.find(*ignoredXPathPrefix) != std::string::npos ? path.substr(ignoredXPathPrefix->size()) : path;
};
for (const auto& it : items) {
if (it->schema()->nodetype() == LYS_CONTAINER) {
if (libyang::Schema_Node_Container{it->schema()}.presence()) {
// The fact that the container is included in the data tree
// means that it is present and I don't need to check any
// value.
res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::PresenceContainer});
}
}
if (it->schema()->nodetype() == LYS_LIST) {
res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::List});
}
if (it->schema()->nodetype() == LYS_LEAF || it->schema()->nodetype() == LYS_LEAFLIST) {
auto leaf = std::make_shared<libyang::Data_Node_Leaf_List>(it);
auto value = leafValueFromNode(leaf);
res.emplace_back(stripXPathPrefix(it->path()), value);
}
}
}
}
// This is very similar to the fillMap lambda in SysrepoAccess, however,
// Sysrepo returns a weird array-like structure, while libnetconf
// returns libyang::Data_Node
void lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix)
{
for (auto it = items.begin(); it < items.end(); it++) {
if ((*it)->schema()->nodetype() == LYS_LEAFLIST) {
auto leafListPath = stripLeafListValueFromPath((*it)->path());
res.emplace_back(leafListPath, special_{SpecialValue::LeafList});
while (it != items.end() && boost::starts_with((*it)->path(), leafListPath)) {
impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
it++;
}
} else {
impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
}
}
}