blob: 1f0c372324c068bf781f2a10645e56d3c47cde24 [file] [log] [blame]
Václav Kubernátdaf40312020-06-19 11:34:55 +02001#include <boost/algorithm/string/predicate.hpp>
Jan Kundrátbd3169c2020-02-03 19:31:34 +01002#include <cmath>
Václav Kubernát3c8fe022020-06-04 01:35:03 +02003#include "datastore_access.hpp"
4#include "libyang_utils.hpp"
5#include "utils.hpp"
Václav Kubernát02a71152020-01-21 14:52:51 +01006
Václav Kubernát2e4cafe2020-11-05 01:53:21 +01007leaf_data_ leafValueFromNode(libyang::S_Data_Node_Leaf_List node)
Václav Kubernát02a71152020-01-21 14:52:51 +01008{
Václav Kubernátb4e5b182020-11-16 19:55:09 +01009 std::function<leaf_data_(libyang::S_Data_Node_Leaf_List)> impl = [&impl](libyang::S_Data_Node_Leaf_List node) -> leaf_data_ {
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010010 // value_type() is what's ACTUALLY stored inside `node`
11 // Leafrefs sometimes don't hold a reference to another, but they have the actual pointed-to value.
12 switch (node->value_type()) {
13 case LY_TYPE_ENUM:
14 return enum_{node->value()->enm()->name()};
15 case LY_TYPE_UINT8:
16 return node->value()->uint8();
17 case LY_TYPE_UINT16:
18 return node->value()->uint16();
19 case LY_TYPE_UINT32:
20 return node->value()->uint32();
21 case LY_TYPE_UINT64:
22 return node->value()->uint64();
23 case LY_TYPE_INT8:
24 return node->value()->int8();
25 case LY_TYPE_INT16:
26 return node->value()->int16();
27 case LY_TYPE_INT32:
28 return node->value()->int32();
29 case LY_TYPE_INT64:
30 return node->value()->int64();
Václav Kubernátb4e5b182020-11-16 19:55:09 +010031 case LY_TYPE_DEC64: {
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010032 auto v = node->value()->dec64();
33 return v.value * std::pow(10, -v.digits);
34 }
35 case LY_TYPE_BOOL:
36 return node->value()->bln();
37 case LY_TYPE_STRING:
38 return std::string{node->value()->string()};
39 case LY_TYPE_BINARY:
40 return binary_{node->value()->binary()};
41 case LY_TYPE_IDENT:
42 return identityRef_{node->value()->ident()->module()->name(), node->value()->ident()->name()};
43 case LY_TYPE_EMPTY:
44 return empty_{};
Václav Kubernátb4e5b182020-11-16 19:55:09 +010045 case LY_TYPE_LEAFREF: {
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010046 auto refsTo = node->value()->leafref();
47 assert(refsTo);
48 return impl(std::make_shared<libyang::Data_Node_Leaf_List>(node->value()->leafref()));
49 }
Václav Kubernátb4e5b182020-11-16 19:55:09 +010050 case LY_TYPE_BITS: {
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010051 auto bits = node->value()->bit();
52 std::vector<libyang::S_Type_Bit> filterNull;
Václav Kubernátb4e5b182020-11-16 19:55:09 +010053 std::copy_if(bits.begin(), bits.end(), std::back_inserter(filterNull), [](auto bit) { return bit; });
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010054 bits_ res;
Václav Kubernátb4e5b182020-11-16 19:55:09 +010055 std::transform(filterNull.begin(), filterNull.end(), std::inserter(res.m_bits, res.m_bits.end()), [](const auto& bit) { return bit->name(); });
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010056 return bits_{res};
57 }
58 default:
59 return std::string{"(can't print)"};
Václav Kubernátb4e5b182020-11-16 19:55:09 +010060 }
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010061 };
62 return impl(node);
Václav Kubernát02a71152020-01-21 14:52:51 +010063}
Václav Kubernát3c8fe022020-06-04 01:35:03 +020064
Václav Kubernátdaf40312020-06-19 11:34:55 +020065namespace {
66void impl_lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix)
Václav Kubernát3c8fe022020-06-04 01:35:03 +020067{
Václav Kubernátb4e5b182020-11-16 19:55:09 +010068 auto stripXPathPrefix = [&ignoredXPathPrefix](auto path) {
Václav Kubernáta8789602020-07-20 15:18:19 +020069 return ignoredXPathPrefix && path.find(*ignoredXPathPrefix) != std::string::npos ? path.substr(ignoredXPathPrefix->size()) : path;
Václav Kubernát3c8fe022020-06-04 01:35:03 +020070 };
71
72 for (const auto& it : items) {
Václav Kubernát3c8fe022020-06-04 01:35:03 +020073 if (it->schema()->nodetype() == LYS_CONTAINER) {
74 if (libyang::Schema_Node_Container{it->schema()}.presence()) {
75 // The fact that the container is included in the data tree
76 // means that it is present and I don't need to check any
77 // value.
78 res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::PresenceContainer});
79 }
80 }
81 if (it->schema()->nodetype() == LYS_LIST) {
Václav Kubernátfaacd022020-07-08 16:44:38 +020082 res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::List});
Václav Kubernát3c8fe022020-06-04 01:35:03 +020083 }
84 if (it->schema()->nodetype() == LYS_LEAF || it->schema()->nodetype() == LYS_LEAFLIST) {
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010085 auto leaf = std::make_shared<libyang::Data_Node_Leaf_List>(it);
86 auto value = leafValueFromNode(leaf);
Václav Kubernát3c8fe022020-06-04 01:35:03 +020087 res.emplace_back(stripXPathPrefix(it->path()), value);
88 }
89 }
90}
Václav Kubernátdaf40312020-06-19 11:34:55 +020091}
92
93// This is very similar to the fillMap lambda in SysrepoAccess, however,
94// Sysrepo returns a weird array-like structure, while libnetconf
95// returns libyang::Data_Node
96void lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix)
97{
98 for (auto it = items.begin(); it < items.end(); it++) {
99 if ((*it)->schema()->nodetype() == LYS_LEAFLIST) {
100 auto leafListPath = stripLeafListValueFromPath((*it)->path());
101 res.emplace_back(leafListPath, special_{SpecialValue::LeafList});
102 while (it != items.end() && boost::starts_with((*it)->path(), leafListPath)) {
103 impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
104 it++;
105 }
106 } else {
107 impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
108 }
109 }
110}