blob: f1af868647f10895d1abfd9dbb9b9642b51875f9 [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át2e4cafe2020-11-05 01:53:21 +01009 std::function<leaf_data_(libyang::S_Data_Node_Leaf_List)> impl = [&impl] (libyang::S_Data_Node_Leaf_List node) -> leaf_data_ {
10 // 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();
31 case LY_TYPE_DEC64:
32 {
33 auto v = node->value()->dec64();
34 return v.value * std::pow(10, -v.digits);
35 }
36 case LY_TYPE_BOOL:
37 return node->value()->bln();
38 case LY_TYPE_STRING:
39 return std::string{node->value()->string()};
40 case LY_TYPE_BINARY:
41 return binary_{node->value()->binary()};
42 case LY_TYPE_IDENT:
43 return identityRef_{node->value()->ident()->module()->name(), node->value()->ident()->name()};
44 case LY_TYPE_EMPTY:
45 return empty_{};
46 case LY_TYPE_LEAFREF:
47 {
48 auto refsTo = node->value()->leafref();
49 assert(refsTo);
50 return impl(std::make_shared<libyang::Data_Node_Leaf_List>(node->value()->leafref()));
51 }
52 case LY_TYPE_BITS:
53 {
54 auto bits = node->value()->bit();
55 std::vector<libyang::S_Type_Bit> filterNull;
56 std::copy_if(bits.begin(), bits.end(), std::back_inserter(filterNull), [] (auto bit) { return bit; });
57 bits_ res;
58 std::transform(filterNull.begin(), filterNull.end(), std::inserter(res.m_bits, res.m_bits.end()), [] (const auto& bit) { return bit->name(); });
59 return bits_{res};
60 }
61 default:
62 return std::string{"(can't print)"};
Václav Kubernát19097f32020-10-05 10:08:29 +020063 }
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010064 };
65 return impl(node);
Václav Kubernát02a71152020-01-21 14:52:51 +010066}
Václav Kubernát3c8fe022020-06-04 01:35:03 +020067
Václav Kubernátdaf40312020-06-19 11:34:55 +020068namespace {
69void 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 +020070{
71 auto stripXPathPrefix = [&ignoredXPathPrefix] (auto path) {
Václav Kubernáta8789602020-07-20 15:18:19 +020072 return ignoredXPathPrefix && path.find(*ignoredXPathPrefix) != std::string::npos ? path.substr(ignoredXPathPrefix->size()) : path;
Václav Kubernát3c8fe022020-06-04 01:35:03 +020073 };
74
75 for (const auto& it : items) {
Václav Kubernát3c8fe022020-06-04 01:35:03 +020076 if (it->schema()->nodetype() == LYS_CONTAINER) {
77 if (libyang::Schema_Node_Container{it->schema()}.presence()) {
78 // The fact that the container is included in the data tree
79 // means that it is present and I don't need to check any
80 // value.
81 res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::PresenceContainer});
82 }
83 }
84 if (it->schema()->nodetype() == LYS_LIST) {
Václav Kubernátfaacd022020-07-08 16:44:38 +020085 res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::List});
Václav Kubernát3c8fe022020-06-04 01:35:03 +020086 }
87 if (it->schema()->nodetype() == LYS_LEAF || it->schema()->nodetype() == LYS_LEAFLIST) {
Václav Kubernát2e4cafe2020-11-05 01:53:21 +010088 auto leaf = std::make_shared<libyang::Data_Node_Leaf_List>(it);
89 auto value = leafValueFromNode(leaf);
Václav Kubernát3c8fe022020-06-04 01:35:03 +020090 res.emplace_back(stripXPathPrefix(it->path()), value);
91 }
92 }
93}
Václav Kubernátdaf40312020-06-19 11:34:55 +020094}
95
96// This is very similar to the fillMap lambda in SysrepoAccess, however,
97// Sysrepo returns a weird array-like structure, while libnetconf
98// returns libyang::Data_Node
99void lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix)
100{
101 for (auto it = items.begin(); it < items.end(); it++) {
102 if ((*it)->schema()->nodetype() == LYS_LEAFLIST) {
103 auto leafListPath = stripLeafListValueFromPath((*it)->path());
104 res.emplace_back(leafListPath, special_{SpecialValue::LeafList});
105 while (it != items.end() && boost::starts_with((*it)->path(), leafListPath)) {
106 impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
107 it++;
108 }
109 } else {
110 impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
111 }
112 }
113}