$darkmode
xdg.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Robert Bosch GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * SPDX-License-Identifier: Apache-2.0
17  */
28 #ifndef CLOE_UTILITY_XDG_HPP_
29 #define CLOE_UTILITY_XDG_HPP_
30 
31 #include <functional> // for function
32 #include <string> // for string
33 #include <vector> // for vector<>
34 
35 #include <boost/filesystem/path.hpp> // for path, operator/
36 
37 namespace cloe {
38 namespace utility {
39 
43 enum class XdgError {
55  RELATIVE_XDG_PATH,
56 
61  HOME_UNSET,
62 
67  EMPTY_DEFAULT
68 };
69 
70 // The following xdg_* functions are implementation functions, and aren't meant
71 // to be used directly.
72 #ifdef __linux__
73 boost::filesystem::path xdg_temp_dir();
74 #endif
75 
76 boost::filesystem::path xdg_getenv_path(const std::string& env);
77 boost::filesystem::path xdg_path(const std::string& env,
78  const boost::filesystem::path& default_path);
79 std::vector<boost::filesystem::path> xdg_paths(const std::string& env,
80  const std::string& default_paths);
81 
82 /*
83  * Make sure to ask `is_empty()` on the result.
84  */
85 boost::filesystem::path xdg_find(const boost::filesystem::path& file,
86  const std::vector<boost::filesystem::path>& dirs);
87 
88 std::vector<boost::filesystem::path> xdg_findall(const boost::filesystem::path& file,
89  const std::vector<boost::filesystem::path>& dirs);
90 
91 void xdg_merge(const boost::filesystem::path& file,
92  const std::vector<boost::filesystem::path>& dirs, bool reverse,
93  std::function<bool(const boost::filesystem::path&)> mergefn);
94 
96 inline boost::filesystem::path config_home() {
97 #ifdef __linux__
98  return xdg_path("XDG_CONFIG_HOME", "~/.config");
99 #elif WIN32
100  return xdg_path("XDG_CONFIG_HOME", xdg_getenv_path("LOCALAPPDATA"));
101 #endif
102 }
103 
105 inline boost::filesystem::path data_home() {
106 #ifdef __linux__
107  return xdg_path("XDG_DATA_HOME", "~/.local/share");
108 #elif WIN32
109  return xdg_path("XDG_DATA_HOME", xdg_getenv_path("LOCALAPPDATA"));
110 #endif
111 }
112 
114 inline boost::filesystem::path cache_home() {
115 #ifdef __linux__
116  return xdg_path("XDG_CACHE_HOME", "~/.cache");
117 #elif WIN32
118  return xdg_path("XDG_CACHE_HOME", xdg_getenv_path("TEMP"));
119 #endif
120 }
121 
123 inline boost::filesystem::path runtime_dir() {
124 #ifdef __linux__
125  return xdg_path("XDG_RUNTIME_DIR", xdg_temp_dir());
126 #elif WIN32
127  return xdg_path("XDG_CACHE_HOME", xdg_getenv_path("TEMP"));
128 #endif
129 }
130 
132 inline std::vector<boost::filesystem::path> config_dirs() {
133 #ifdef __linux__
134  return xdg_paths("XDG_CONFIG_DIRS", "/etc/xdg");
135 #elif WIN32
136  return xdg_paths("XDG_CONFIG_DIRS", xdg_getenv_path("APPDATA").string());
137 #endif
138 }
139 
141 inline std::vector<boost::filesystem::path> data_dirs() {
142 #ifdef __linux__
143  return xdg_paths("XDG_DATA_DIRS", "/usr/local/share:/usr/share");
144 #elif WIN32
145  return xdg_paths("XDG_DATA_DIRS", xdg_getenv_path("APPDATA").string());
146 #endif
147 }
148 
150 inline std::vector<boost::filesystem::path> all_config_dirs() {
151  auto xs = config_dirs();
152  xs.insert(xs.begin(), config_home());
153  return xs;
154 }
155 
157 inline std::vector<boost::filesystem::path> all_data_dirs() {
158  auto xs = data_dirs();
159  xs.insert(xs.begin(), data_home());
160  return xs;
161 }
162 
163 /*
164  * The user_* functions return the correct path for the given suffix name.
165  *
166  * This is useful if you want to create a file.
167  */
168 inline boost::filesystem::path user_config(const boost::filesystem::path& file) {
169  return config_home() / file;
170 }
171 inline boost::filesystem::path user_data(const boost::filesystem::path& file) {
172  return data_home() / file;
173 }
174 inline boost::filesystem::path user_cache(const boost::filesystem::path& file) {
175  return cache_home() / file;
176 }
177 inline boost::filesystem::path user_runtime(const boost::filesystem::path& file) {
178  return runtime_dir() / file;
179 }
180 
181 /*
182  * The find_* functions return the most relevant path for the given suffix
183  * name that exists.
184  *
185  * This is useful if you want to read a file.
186  */
187 inline boost::filesystem::path find_config(const boost::filesystem::path& file) {
188  return xdg_find(file, all_config_dirs());
189 }
190 inline boost::filesystem::path find_data(const boost::filesystem::path& file) {
191  return xdg_find(file, all_data_dirs());
192 }
193 inline boost::filesystem::path find_cache(const boost::filesystem::path& file) {
194  return xdg_find(file, std::vector<boost::filesystem::path>{cache_home()});
195 }
196 inline boost::filesystem::path find_runtime(const boost::filesystem::path& file) {
197  return xdg_find(file, std::vector<boost::filesystem::path>{runtime_dir()});
198 }
199 
200 /*
201  * The find_all_config and find_all_data functions return for config and data
202  * all paths that contain the name suffix.
203  *
204  * This is useful if you can read multiple instances of the config or data.
205  */
206 inline std::vector<boost::filesystem::path> find_all_config(const boost::filesystem::path& file) {
207  return xdg_findall(file, all_config_dirs());
208 }
209 inline std::vector<boost::filesystem::path> find_all_data(const boost::filesystem::path& file) {
210  return xdg_findall(file, all_data_dirs());
211 }
212 
213 /*
214  * The merge_config and merge_data follow the same logic as the find_all_*
215  * functions, except that instead of returning the paths, they repeatedly
216  * apply the supplied function to the path.
217  *
218  * Because in merging, the most important file should be loaded last, there
219  * is a reverse option. If the function returns false, the merging is aborted.
220  */
221 inline void merge_config(const boost::filesystem::path& file,
222  std::function<bool(const boost::filesystem::path&)>
223  mergefn,
224  bool reverse = false) {
225  xdg_merge(file, all_config_dirs(), reverse, mergefn);
226 }
227 
228 inline void merge_data(const boost::filesystem::path& file,
229  std::function<bool(const boost::filesystem::path&)>
230  mergefn,
231  bool reverse = false) {
232  xdg_merge(file, all_data_dirs(), reverse, mergefn);
233 }
234 
235 } // namespace utility
236 } // namespace cloe
237 
238 #endif // CLOE_UTILITY_XDG_HPP_
XdgError
Definition: xdg.hpp:43
std::vector< boost::filesystem::path > all_data_dirs()
User and global data directories.
Definition: xdg.hpp:157
boost::filesystem::path config_home()
User configuration base directory, e.g., ~./config.
Definition: xdg.hpp:96
Definition: coordinator.hpp:36
std::vector< boost::filesystem::path > data_dirs()
Global data files directories, e.g., /usr/local/share.
Definition: xdg.hpp:141
std::vector< boost::filesystem::path > all_config_dirs()
User and global configuration directories.
Definition: xdg.hpp:150
boost::filesystem::path runtime_dir()
User runtime files base directory, e.g., /run/user/1000
Definition: xdg.hpp:123
boost::filesystem::path data_home()
User data files base directory, e.g., ~/.local/share.
Definition: xdg.hpp:105
std::vector< boost::filesystem::path > config_dirs()
Global configuration directories, e.g., /etc/xdg.
Definition: xdg.hpp:132
boost::filesystem::path cache_home()
User cache files base directory, e.g., ~/.cache.
Definition: xdg.hpp:114