Add get command

Change-Id: Id06539070fb8d815786149e1479e93d75d4b70f1
diff --git a/src/ast_commands.hpp b/src/ast_commands.hpp
index 3a92e10..969515e 100644
--- a/src/ast_commands.hpp
+++ b/src/ast_commands.hpp
@@ -59,8 +59,12 @@
     bool operator==(const set_& b) const;
 };
 
+struct get_ : x3::position_tagged {
+    bool operator==(const get_& b) const;
+    boost::optional<path_> m_path;
+};
 
-using command_ = boost::variant<ls_, cd_, create_, delete_, set_, commit_>;
+using command_ = boost::variant<ls_, cd_, create_, delete_, set_, commit_, get_>;
 
 BOOST_FUSION_ADAPT_STRUCT(ls_, m_path)
 BOOST_FUSION_ADAPT_STRUCT(cd_, m_path)
@@ -69,3 +73,4 @@
 BOOST_FUSION_ADAPT_STRUCT(enum_, m_value)
 BOOST_FUSION_ADAPT_STRUCT(set_, m_path, m_data)
 BOOST_FUSION_ADAPT_STRUCT(commit_)
+BOOST_FUSION_ADAPT_STRUCT(get_, m_path)
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index bddc83e..686ae30 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -394,6 +394,8 @@
 
 struct commit_class;
 
+struct get_class;
+
 struct command_class {
     template <typename Iterator, typename Exception, typename Context>
     x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
diff --git a/src/ast_path.cpp b/src/ast_path.cpp
index 2621792..e943d0e 100644
--- a/src/ast_path.cpp
+++ b/src/ast_path.cpp
@@ -91,7 +91,7 @@
         res << node.m_name + "[";
         std::transform(node.m_keys.begin(), node.m_keys.end(),
                 std::experimental::make_ostream_joiner(res, ' '),
-                [] (const auto& it) { return it.first + "=" + it.second; });
+                [] (const auto& it) { return it.first + "=" + '\'' + it.second + '\''; });
         res << "]";
         return res.str();
     }
diff --git a/src/ast_path.hpp b/src/ast_path.hpp
index 8827a38..dab06ea 100644
--- a/src/ast_path.hpp
+++ b/src/ast_path.hpp
@@ -68,8 +68,7 @@
     bool operator==(const node_& b) const;
 };
 
-enum class Scope
-{
+enum class Scope {
     Absolute,
     Relative
 };
diff --git a/src/ast_values.hpp b/src/ast_values.hpp
index 121e760..369a73e 100644
--- a/src/ast_values.hpp
+++ b/src/ast_values.hpp
@@ -22,4 +22,3 @@
                                   int32_t,
                                   uint32_t,
                                   std::string>;
-
diff --git a/src/grammars.hpp b/src/grammars.hpp
index 6ad9b1b..5a3db0f 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -38,6 +38,7 @@
 x3::rule<ls_class, ls_> const ls = "ls";
 x3::rule<cd_class, cd_> const cd = "cd";
 x3::rule<set_class, set_> const set = "set";
+x3::rule<get_class, get_> const get = "get";
 x3::rule<create_class, create_> const create = "create";
 x3::rule<delete_class, delete_> const delete_rule = "delete_rule";
 x3::rule<commit_class, commit_> const commit = "commit";
@@ -145,6 +146,9 @@
 auto const delete_rule_def =
         lit("delete") >> space_separator > path;
 
+auto const get_def =
+        lit("get") >> -path;
+
 auto const set_def =
         lit("set") >> space_separator > leafPath > leaf_data;
 
@@ -152,7 +156,7 @@
         lit("commit") >> x3::attr(commit_());
 
 auto const command_def =
-        x3::expect[cd | create | delete_rule | set | commit | ls] >> x3::eoi;
+        x3::expect[cd | create | delete_rule | set | commit | get | ls] >> x3::eoi;
 
 #if __clang__
 #pragma GCC diagnostic pop
@@ -181,6 +185,7 @@
 BOOST_SPIRIT_DEFINE(leaf_data_string)
 BOOST_SPIRIT_DEFINE(set)
 BOOST_SPIRIT_DEFINE(commit)
+BOOST_SPIRIT_DEFINE(get)
 BOOST_SPIRIT_DEFINE(ls)
 BOOST_SPIRIT_DEFINE(cd)
 BOOST_SPIRIT_DEFINE(create)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index b919786..4e5d665 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -34,6 +34,14 @@
     m_datastore.setLeaf(absolutePathFromCommand(set), set.m_data);
 }
 
+void Interpreter::operator()(const get_& get) const
+{
+    auto items = m_datastore.getItems(absolutePathFromCommand(get));
+    for (auto it : items) {
+        std::cout << it.first << " = " << boost::apply_visitor(leafDataToString(), it.second) << std::endl;
+    }
+}
+
 void Interpreter::operator()(const cd_& cd) const
 {
     m_parser.changeNode(cd.m_path);
@@ -66,6 +74,17 @@
         return joinPaths(m_parser.currentNode(), pathToDataString(command.m_path));
 }
 
+std::string Interpreter::absolutePathFromCommand(const get_& get) const
+{
+    if (!get.m_path) {
+        return m_parser.currentNode();
+    } else if (get.m_path->m_scope == Scope::Absolute) {
+        return "/" + pathToDataString(*get.m_path);
+    } else {
+        return joinPaths(m_parser.currentNode(), pathToDataString(*get.m_path));
+    }
+}
+
 Interpreter::Interpreter(Parser& parser, DatastoreAccess& datastore)
     : m_parser(parser)
     , m_datastore(datastore)
diff --git a/src/interpreter.hpp b/src/interpreter.hpp
index fd14ffe..262b037 100644
--- a/src/interpreter.hpp
+++ b/src/interpreter.hpp
@@ -17,6 +17,7 @@
 
     void operator()(const commit_&) const;
     void operator()(const set_&) const;
+    void operator()(const get_&) const;
     void operator()(const cd_&) const;
     void operator()(const create_&) const;
     void operator()(const delete_&) const;
@@ -25,6 +26,7 @@
 private:
     template <typename T>
     std::string absolutePathFromCommand(const T& command) const;
+    std::string absolutePathFromCommand(const get_& command) const;
 
     Parser& m_parser;
     DatastoreAccess& m_datastore;
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index 54fa1fd..af553d9 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -11,21 +11,28 @@
 
 leaf_data_ leafValueFromVal(const S_Val& value)
 {
+    using namespace std::string_literals;
     switch (value->type()) {
-        case SR_INT32_T:
-            return value->data()->get_int32();
-        case SR_UINT32_T:
-            return value->data()->get_uint32();
-        case SR_BOOL_T:
-            return value->data()->get_bool();
-        case SR_STRING_T:
-            return std::string(value->data()->get_string());
-        case SR_ENUM_T:
-            return std::string(value->data()->get_enum());
-        case SR_DECIMAL64_T:
-            return value->data()->get_decimal64();
-        default: // TODO: implement all types
-            throw std::runtime_error("This type is not yet implemented");
+    case SR_INT32_T:
+        return value->data()->get_int32();
+    case SR_UINT32_T:
+        return value->data()->get_uint32();
+    case SR_BOOL_T:
+        return value->data()->get_bool();
+    case SR_STRING_T:
+        return std::string(value->data()->get_string());
+    case SR_ENUM_T:
+        return std::string(value->data()->get_enum());
+    case SR_DECIMAL64_T:
+        return value->data()->get_decimal64();
+    case SR_CONTAINER_T:
+        return "(container)"s;
+    case SR_CONTAINER_PRESENCE_T:
+        return "(presence container)"s;
+    case SR_LIST_T:
+        return "(list)"s;
+    default: // TODO: implement all types
+        return value->val_to_string();
     }
 }
 
@@ -71,14 +78,25 @@
 
 std::map<std::string, leaf_data_> SysrepoAccess::getItems(const std::string& path)
 {
+    using namespace std::string_literals;
     std::map<std::string, leaf_data_> res;
-    auto iterator = m_session->get_items_iter(path.c_str());
 
-    if (!iterator)
-        return res;
+    auto fillMap = [&res](auto items) {
+        if (!items)
+            return;
+        for (unsigned int i = 0; i < items->val_cnt(); i++) {
+            res.emplace(items->val(i)->xpath(), leafValueFromVal(items->val(i)));
+        }
+    };
 
-    while (auto value = m_session->get_item_next(iterator)) {
-        res.emplace(value->xpath(), leafValueFromVal(value));
+    if (path == "/") {
+        // Sysrepo doesn't have a root node ("/"), so we take all top-level nodes from all schemas
+        auto schemas = m_session->list_schemas();
+        for (unsigned int i = 0; i < schemas->schema_cnt(); i++) {
+            fillMap(m_session->get_items(("/"s + schemas->schema(i)->module_name() + ":*//.").c_str()));
+        }
+    } else {
+        fillMap(m_session->get_items((path + "//.").c_str()));
     }
 
     return res;