| #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); |
| } |
| } |
| } |