blob: afb291e0f77f32e5a8e9c4a0001cf325ac416c6c [file] [log] [blame]
/*
* Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
* Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
*
* Written by Václav Kubernát <kubervac@fit.cvut.cz>
*
*/
#include <experimental/iterator>
#include <sstream>
#include "completion.hpp"
#include "utils.hpp"
std::string joinPaths(const std::string& prefix, const std::string& suffix)
{
// These two if statements are essential for the algorithm:
// The first one solves joining nothing and a relative path - the algorithm
// down below adds a leading slash, turning it into an absolute path.
// The second one would always add a trailing slash to the path.
if (prefix.empty()) {
return suffix;
}
if (suffix.empty()) {
return prefix;
}
// Otherwise, strip slashes where the join is going to happen. This will
// also change "/" to "", but the return statement takes care of that and
// inserts the slash again.
auto prefixWithoutTrailingSlash = !prefix.empty() && prefix.back() == '/' ? prefix.substr(0, prefix.length() - 1) : prefix;
auto suffixWithoutLeadingSlash = !suffix.empty() && suffix.front() == '/' ? suffix.substr(1) : suffix;
// And join the result with a slash.
return prefixWithoutTrailingSlash + '/' + suffixWithoutLeadingSlash;
}
std::string stripLastNodeFromPath(const std::string& path)
{
std::string res = path;
auto pos = res.find_last_of('/');
if (pos == res.npos) { // path has no backslash - it's either empty, or is a relative path with one fragment
res.clear();
} else if (pos == 0) { // path has one backslash at the start - it's either "/" or "/one-path-fragment"
return "/";
} else {
res.erase(pos);
}
return res;
}
schemaPath_ pathWithoutLastNode(const schemaPath_& path)
{
return schemaPath_{path.m_scope, decltype(schemaPath_::m_nodes)(path.m_nodes.begin(), path.m_nodes.end() - 1)};
}
ModuleNodePair splitModuleNode(const std::string& input)
{
auto colonLocation = input.find_first_of(':');
if (colonLocation != std::string::npos) {
return ModuleNodePair{input.substr(0, colonLocation), input.substr(colonLocation + 1)};
}
throw std::logic_error("Internal error: got module-unqualified node name");
}
struct impl_leafDataTypeToString {
std::string operator()(const yang::String)
{
return "a string";
}
std::string operator()(const yang::Decimal)
{
return "a decimal";
}
std::string operator()(const yang::Bool)
{
return "a boolean";
}
std::string operator()(const yang::Int8)
{
return "an 8-bit integer";
}
std::string operator()(const yang::Uint8)
{
return "an 8-bit unsigned integer";
}
std::string operator()(const yang::Int16)
{
return "a 16-bit integer";
}
std::string operator()(const yang::Uint16)
{
return "a 16-bit unsigned integer";
}
std::string operator()(const yang::Int32)
{
return "a 32-bit integer";
}
std::string operator()(const yang::Uint32)
{
return "a 32-bit unsigned integer";
}
std::string operator()(const yang::Int64)
{
return "a 64-bit integer";
}
std::string operator()(const yang::Uint64)
{
return "a 64-bit unsigned integer";
}
std::string operator()(const yang::Binary)
{
return "a base64-encoded binary value";
}
std::string operator()(const yang::Enum&)
{
return "an enum";
}
std::string operator()(const yang::IdentityRef&)
{
return "an identity";
}
std::string operator()(const yang::LeafRef&)
{
return "a leafref";
}
std::string operator()(const yang::Empty&)
{
return "an empty leaf";
}
std::string operator()(const yang::Union& type)
{
std::ostringstream ss;
std::transform(type.m_unionTypes.begin(), type.m_unionTypes.end(), std::experimental::make_ostream_joiner(ss, ", "), [this](const auto& unionType) {
return std::visit(*this, unionType.m_type);
});
return ss.str();
}
std::string operator()(const yang::Bits& type)
{
std::ostringstream ss;
ss << "bits {";
std::copy(type.m_allowedValues.begin(), type.m_allowedValues.end(), std::experimental::make_ostream_joiner(ss, ", "));
ss << "}";
return ss.str();
}
};
std::string leafDataTypeToString(const yang::LeafDataType& type)
{
return std::visit(impl_leafDataTypeToString{}, type);
}
std::string fullNodeName(const schemaPath_& location, const ModuleNodePair& pair)
{
if (!pair.first) {
return location.m_nodes.at(0).m_prefix.value().m_name + ":" + pair.second;
} else {
return pair.first.value() + ":" + pair.second;
}
}
std::string fullNodeName(const dataPath_& location, const ModuleNodePair& pair)
{
return fullNodeName(dataPathToSchemaPath(location), pair);
}
struct leafDataToStringVisitor : boost::static_visitor<std::string> {
std::string operator()(const enum_& data) const
{
return data.m_value;
}
std::string operator()(const binary_& data) const
{
return data.m_value;
}
std::string operator()(const empty_) const
{
return "[empty]";
}
std::string operator()(const identityRef_& data) const
{
return data.m_prefix ? (data.m_prefix.value().m_name + ":" + data.m_value) : data.m_value;
}
std::string operator()(const special_& data) const
{
return specialValueToString(data);
}
std::string operator()(const std::string& data) const
{
return data;
}
std::string operator()(const bool& data) const
{
if (data) {
return "true";
} else {
return "false";
}
}
std::string operator()(const bits_& data) const
{
std::stringstream ss;
std::copy(data.m_bits.begin(), data.m_bits.end(), std::experimental::make_ostream_joiner(ss, " "));
return ss.str();
}
template <typename T>
std::string operator()(const T& data) const
{
return std::to_string(data);
}
};
std::string leafDataToString(const leaf_data_ value)
{
return boost::apply_visitor(leafDataToStringVisitor(), value);
}
struct getSchemaPathVisitor : boost::static_visitor<schemaPath_> {
schemaPath_ operator()(const dataPath_& path) const
{
return dataPathToSchemaPath(path);
}
schemaPath_ operator()(const schemaPath_& path) const
{
return path;
}
[[noreturn]] schemaPath_ operator()([[maybe_unused]] const module_& path) const
{
throw std::logic_error("getSchemaPathVisitor: Tried getting a schema path from a module");
}
};
schemaPath_ anyPathToSchemaPath(const boost::variant<dataPath_, schemaPath_, module_>& path)
{
return boost::apply_visitor(getSchemaPathVisitor(), path);
}
std::string stripLeafListValueFromPath(const std::string& path)
{
auto res = path;
res.erase(res.find_last_of('['));
return res;
}
std::string stripLastListInstanceFromPath(const std::string& path)
{
auto res = path;
res.erase(res.find_first_of('[', res.find_last_of('/')));
return res;
}
std::string instanceToString(const ListInstance& instance, const std::optional<std::string>& modName)
{
std::string instanceStr;
auto modulePrefix = modName ? *modName + ":" : "";
for (const auto& [key, value] : instance) {
using namespace std::string_literals;
instanceStr += "[" + modulePrefix + key + "=" + escapeListKeyString(leafDataToString(value)) + "]";
}
return instanceStr;
}