diff --git a/src/env_fake.cpp b/src/env_fake.cpp
new file mode 100644
index 0000000..d859629
--- /dev/null
+++ b/src/env_fake.cpp
@@ -0,0 +1,129 @@
+/* Copyright 2020, Michele Santullo
+ * This file is part of user-gcc.
+ *
+ * User-gcc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * User-gcc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with user-gcc. If not, see .
+ */
+
+#include "env_fake.hpp"
+#include "to_var_map.hpp"
+#include "safe_print.hpp"
+#include "string_view_cat.hpp"
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace duck {
+namespace {
+ template <
+ typename M,
+ typename I,
+ typename F,
+ typename R=decltype(std::declval()(std::declval().find(std::declval()))&>())),
+ //not supposed to be altered by the caller
+ bool FIsNoex=noexcept(std::declval()(std::declval().find(std::declval()))&>())) and noexcept(R())
+ >
+ R run_if_found (M& map, const I& item, F func) noexcept(FIsNoex) {
+ typedef decltype(map.find(item)) iterator_type;
+
+ iterator_type it_found;
+ if constexpr (FIsNoex) {
+ try {
+ it_found = map.find(item);
+ }
+ catch (...) {
+ safe_print_error("Unexpected exception in run_if_found() will be ignored");
+ }
+ }
+ else {
+ it_found = map.find(item);
+ }
+
+ if constexpr (std::is_same::value) {
+ if (map.end() != it_found) {
+ func(it_found);
+ }
+ }
+ else {
+ if (map.end() != it_found) {
+ return func(it_found);
+ }
+ else {
+ return R{};
+ }
+ }
+ }
+} //unnamed namespace
+
+EnvFake::EnvFake (bool starts_empty) :
+ m_map_strong_cpy(),
+ m_map(starts_empty ? map_type() : to_var_map_ignore_ownership(environ))
+{
+}
+
+std::optional EnvFake::get (std::string_view name) const noexcept {
+ return run_if_found(m_map, name, [](auto& it)noexcept{return std::make_optional(it->second);});
+}
+
+std::string_view EnvFake::get (std::string_view name, std::string_view def) const noexcept {
+ bool ret_def{true};
+ std::string_view maybe_ret(run_if_found(m_map, name, [&ret_def](auto& it)noexcept{ret_def=false; return it->second;}));
+ if (ret_def)
+ return def;
+ else
+ return maybe_ret;
+}
+
+void EnvFake::set (std::string_view name, std::string_view value) {
+ assert(not name.empty());
+ if (name.empty())
+ return;
+
+ const std::size_t size = name.size() + value.size();
+ std::unique_ptr buff = std::make_unique(size);
+ std::copy(name.begin(), name.end(), buff.get());
+ std::copy(value.begin(), value.end(), buff.get() + name.size());
+
+ const std::string_view new_name(buff.get(), name.size());
+ assert(new_name == name);
+ const std::string_view new_value(buff.get() + name.size(), value.size());
+ assert(new_value == value);
+
+ m_map_strong_cpy.insert_or_assign(std::string_view(new_name), std::move(buff));
+ m_map.insert_or_assign(std::string_view(new_name), std::string_view(new_value));
+ assert(m_map.at(name) == value);
+ assert(m_map.find(name)->first.data() == new_name.data());
+}
+
+void EnvFake::unset (std::string_view name) noexcept {
+ run_if_found(m_map, name, [&](auto& it)noexcept{m_map.erase(it);});
+ run_if_found(m_map_strong_cpy, name, [&](auto& it)noexcept{m_map_strong_cpy.erase(it);});
+}
+
+bool EnvFake::is_set (std::string_view name) const noexcept {
+ return run_if_found(m_map, name, [](auto&)noexcept{return true;});
+}
+
+auto EnvFake::size() const noexcept -> size_type {
+ return m_map.size();
+}
+
+void EnvFake::clear() noexcept {
+ m_map.clear();
+ m_map_strong_cpy.clear();
+}
+
+} //namespace duck
diff --git a/src/env_fake.hpp b/src/env_fake.hpp
new file mode 100644
index 0000000..75fd1f8
--- /dev/null
+++ b/src/env_fake.hpp
@@ -0,0 +1,43 @@
+/* Copyright 2020, Michele Santullo
+ * This file is part of user-gcc.
+ *
+ * User-gcc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * User-gcc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with user-gcc. If not, see .
+ */
+
+#pragma once
+
+#include "env_base.hpp"
+#include
+#include
+
+namespace duck {
+ class EnvFake : public EnvBase {
+ typedef std::unordered_map map_type;
+ public:
+ explicit EnvFake (bool starts_empty=false);
+ ~EnvFake() noexcept = default;
+
+ virtual std::optional get (std::string_view name) const noexcept override;
+ virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override;
+ virtual void set (std::string_view name, std::string_view value) override;
+ virtual void unset (std::string_view name) noexcept override;
+ virtual bool is_set (std::string_view name) const noexcept override;
+ virtual size_type size() const noexcept override;
+ virtual void clear() noexcept override;
+
+ private:
+ std::unordered_map> m_map_strong_cpy;
+ map_type m_map;
+ };
+} //namespace duck
diff --git a/src/meson.build b/src/meson.build
index 8a762d8..2f547ed 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -21,6 +21,7 @@ executable(meson.project_name(),
'var_map.cpp',
'env_base.cpp',
'env_real.cpp',
+ 'env_fake.cpp',
'safe_print.cpp',
install: true,
dependencies: [fslib_dep],