1 // Copyright (C) 2015 Thomas Voß <thomas.voss.bochum@gmail.com>
3 // This library is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU Lesser General Public License as published
5 // by the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <boost/algorithm/string.hpp>
23 namespace fs = boost::filesystem;
28 fs::path throw_if_not_absolute(const fs::path& p)
30 if (p.has_root_directory())
33 throw std::runtime_error{"Directores MUST be absolute."};
38 std::string get(const std::string& key, const std::string& default_value)
40 if (auto value = std::getenv(key.c_str()))
45 std::string get_or_throw(const std::string& key)
47 if (auto value = std::getenv(key.c_str()))
52 throw std::runtime_error{key + " not set in environment"};
55 constexpr const char* xdg_data_home{"XDG_DATA_HOME"};
56 constexpr const char* xdg_data_dirs{"XDG_DATA_DIRS"};
57 constexpr const char* xdg_config_home{"XDG_CONFIG_HOME"};
58 constexpr const char* xdg_config_dirs{"XDG_CONFIG_DIRS"};
59 constexpr const char* xdg_cache_home{"XDG_CACHE_HOME"};
64 class BaseDirSpecification : public xdg::BaseDirSpecification
67 static const BaseDirSpecification& instance()
69 static const BaseDirSpecification spec;
73 BaseDirSpecification()
77 const xdg::Data& data() const override
82 const xdg::Config& config() const override
87 const xdg::Cache& cache() const override
92 const xdg::Runtime& runtime() const override
101 xdg::Runtime runtime_;
106 fs::path xdg::Data::home() const
108 auto v = env::get(env::xdg_data_home, "");
110 return throw_if_not_absolute(fs::path{env::get_or_throw("HOME")} / ".local" / "share");
112 return throw_if_not_absolute(fs::path(v));
115 std::vector<fs::path> xdg::Data::dirs() const
117 auto v = env::get(env::xdg_data_dirs, "");
119 return {fs::path{"/usr/local/share"}, fs::path{"/usr/share"}};
121 std::vector<std::string> tokens;
122 tokens = boost::split(tokens, v, boost::is_any_of(":"));
123 std::vector<fs::path> result;
124 for (const auto& token : tokens)
126 result.push_back(throw_if_not_absolute(fs::path(token)));
131 fs::path xdg::Config::home() const
133 auto v = env::get(env::xdg_config_home, "");
135 return throw_if_not_absolute(fs::path{env::get_or_throw("HOME")} / ".config");
137 return throw_if_not_absolute(fs::path(v));
140 std::vector<fs::path> xdg::Config::dirs() const
142 auto v = env::get(env::xdg_config_dirs, "");
144 return {fs::path{"/etc/xdg"}};
146 std::vector<std::string> tokens;
147 tokens = boost::split(tokens, v, boost::is_any_of(":"));
148 std::vector<fs::path> result;
149 for (const auto& token : tokens)
152 result.push_back(throw_if_not_absolute(p));
157 fs::path xdg::Cache::home() const
159 auto v = env::get(env::xdg_cache_home, "");
161 return throw_if_not_absolute(fs::path{env::get_or_throw("HOME")} / ".cache");
163 return throw_if_not_absolute(fs::path(v));
166 fs::path xdg::Runtime::dir() const
168 auto v = env::get(env::xdg_config_home, "");
171 // We do not fall back gracefully and instead throw, dispatching to calling
172 // code for handling the case of a safe user-specfic runtime directory missing.
173 throw std::runtime_error{"Runtime directory not set"};
176 return throw_if_not_absolute(fs::path(v));
179 std::shared_ptr<xdg::BaseDirSpecification> xdg::BaseDirSpecification::create()
181 return std::make_shared<impl::BaseDirSpecification>();
184 const xdg::Data& xdg::data()
186 return impl::BaseDirSpecification::instance().data();
189 const xdg::Config& xdg::config()
191 return impl::BaseDirSpecification::instance().config();
194 const xdg::Cache& xdg::cache()
196 return impl::BaseDirSpecification::instance().cache();
199 const xdg::Runtime& xdg::runtime()
201 return impl::BaseDirSpecification::instance().runtime();