Add yang-cli

The original idea for this was that I would libyang C++ bindings for
this. Unfortunately, there have been problems with them as explained
here: https://github.com/CESNET/libyang/issues/1106. The easiest
solution to this was to just use the C api of libyang. After creating
some safe wrappers around pointers, it wasn't too difficult.

Change-Id: I0421cb64df66c640956501e56ffc4122eef0b9b7
diff --git a/src/yang_access.hpp b/src/yang_access.hpp
new file mode 100644
index 0000000..9f20b51
--- /dev/null
+++ b/src/yang_access.hpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Václav Kubernát <kubernat@cesnet.cz>
+ *
+*/
+
+#pragma once
+
+#include "datastore_access.hpp"
+
+/*! \class YangAccess
+ *     \brief Implementation of DatastoreAccess with a local libyang data node instance
+ */
+
+class YangSchema;
+
+struct ly_ctx;
+struct lyd_node;
+
+class YangAccess : public DatastoreAccess {
+public:
+    YangAccess();
+    ~YangAccess() override;
+    Tree getItems(const std::string& path) override;
+    void setLeaf(const std::string& path, leaf_data_ value) override;
+    void createItem(const std::string& path) override;
+    void deleteItem(const std::string& path) override;
+    void moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move) override;
+    void commitChanges() override;
+    void discardChanges() override;
+    Tree executeRpc(const std::string& path, const Tree& input) override;
+    void copyConfig(const Datastore source, const Datastore destination) override;
+
+    std::shared_ptr<Schema> schema() override;
+
+    void enableFeature(const std::string& module, const std::string& feature);
+    std::string dumpXML() const;
+    std::string dumpJSON() const;
+
+    void addSchemaFile(const std::string& path);
+    void addSchemaDir(const std::string& path);
+
+private:
+    std::vector<ListInstance> listInstances(const std::string& path) override;
+
+    [[noreturn]] void getErrorsAndThrow() const;
+    void impl_newPath(const std::string& path, const std::optional<std::string>& value = std::nullopt);
+    void impl_removeNode(const std::string& path);
+    void validate();
+
+    std::unique_ptr<ly_ctx, void(*)(ly_ctx*)> m_ctx;
+    std::unique_ptr<lyd_node, void(*)(lyd_node*)> m_datastore;
+    std::shared_ptr<YangSchema> m_schema;
+};