$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 #pragma once
29 
30 #include <functional> // for function
31 #include <string> // for string
32 #include <vector> // for vector<>
33 
34 #include <boost/filesystem/path.hpp> // for path, operator/
35 
36 namespace cloe {
37 namespace utility {
38 
42 enum class XdgError {
55 
60  HOME_UNSET,
61 
67 };
68 
69 // The following xdg_* functions are implementation functions, and aren't meant
70 // to be used directly.
71 #ifdef __linux__
72 boost::filesystem::path xdg_temp_dir();
73 #endif
74 
75 boost::filesystem::path xdg_getenv_path(const std::string& env);
76 boost::filesystem::path xdg_path(const std::string& env,
77  const boost::filesystem::path& default_path);
78 std::vector<boost::filesystem::path> xdg_paths(const std::string& env,
79  const std::string& default_paths);
80 
81 /*
82  * Make sure to ask `is_empty()` on the result.
83  */
84 boost::filesystem::path xdg_find(const boost::filesystem::path& file,
85  const std::vector<boost::filesystem::path>& dirs);
86 
87 std::vector<boost::filesystem::path> xdg_findall(const boost::filesystem::path& file,
88  const std::vector<boost::filesystem::path>& dirs);
89 
90 void xdg_merge(const boost::filesystem::path& file,
91  const std::vector<boost::filesystem::path>& dirs, bool reverse,
92  std::function<bool(const boost::filesystem::path&)> mergefn);
93 
95 inline boost::filesystem::path config_home() {
96 #ifdef __linux__
97  return xdg_path("XDG_CONFIG_HOME", "~/.config");
98 #elif WIN32
99  return xdg_path("XDG_CONFIG_HOME", xdg_getenv_path("LOCALAPPDATA"));
100 #endif
101 }
102 
104 inline boost::filesystem::path data_home() {
105 #ifdef __linux__
106  return xdg_path("XDG_DATA_HOME", "~/.local/share");
107 #elif WIN32
108  return xdg_path("XDG_DATA_HOME", xdg_getenv_path("LOCALAPPDATA"));
109 #endif
110 }
111 
113 inline boost::filesystem::path cache_home() {
114 #ifdef __linux__
115  return xdg_path("XDG_CACHE_HOME", "~/.cache");
116 #elif WIN32
117  return xdg_path("XDG_CACHE_HOME", xdg_getenv_path("TEMP"));
118 #endif
119 }
120 
122 inline boost::filesystem::path runtime_dir() {
123 #ifdef __linux__
124  return xdg_path("XDG_RUNTIME_DIR", xdg_temp_dir());
125 #elif WIN32
126  return xdg_path("XDG_CACHE_HOME", xdg_getenv_path("TEMP"));
127 #endif
128 }
129 
131 inline std::vector<boost::filesystem::path> config_dirs() {
132 #ifdef __linux__
133  return xdg_paths("XDG_CONFIG_DIRS", "/etc/xdg");
134 #elif WIN32
135  return xdg_paths("XDG_CONFIG_DIRS", xdg_getenv_path("APPDATA").string());
136 #endif
137 }
138 
140 inline std::vector<boost::filesystem::path> data_dirs() {
141 #ifdef __linux__
142  return xdg_paths("XDG_DATA_DIRS", "/usr/local/share:/usr/share");
143 #elif WIN32
144  return xdg_paths("XDG_DATA_DIRS", xdg_getenv_path("APPDATA").string());
145 #endif
146 }
147 
149 inline std::vector<boost::filesystem::path> all_config_dirs() {
150  auto xs = config_dirs();
151  xs.insert(xs.begin(), config_home());
152  return xs;
153 }
154 
156 inline std::vector<boost::filesystem::path> all_data_dirs() {
157  auto xs = data_dirs();
158  xs.insert(xs.begin(), data_home());
159  return xs;
160 }
161 
162 /*
163  * The user_* functions return the correct path for the given suffix name.
164  *
165  * This is useful if you want to create a file.
166  */
167 inline boost::filesystem::path user_config(const boost::filesystem::path& file) {
168  return config_home() / file;
169 }
170 inline boost::filesystem::path user_data(const boost::filesystem::path& file) {
171  return data_home() / file;
172 }
173 inline boost::filesystem::path user_cache(const boost::filesystem::path& file) {
174  return cache_home() / file;
175 }
176 inline boost::filesystem::path user_runtime(const boost::filesystem::path& file) {
177  return runtime_dir() / file;
178 }
179 
180 /*
181  * The find_* functions return the most relevant path for the given suffix
182  * name that exists.
183  *
184  * This is useful if you want to read a file.
185  */
186 inline boost::filesystem::path find_config(const boost::filesystem::path& file) {
187  return xdg_find(file, all_config_dirs());
188 }
189 inline boost::filesystem::path find_data(const boost::filesystem::path& file) {
190  return xdg_find(file, all_data_dirs());
191 }
192 inline boost::filesystem::path find_cache(const boost::filesystem::path& file) {
193  return xdg_find(file, std::vector<boost::filesystem::path>{cache_home()});
194 }
195 inline boost::filesystem::path find_runtime(const boost::filesystem::path& file) {
196  return xdg_find(file, std::vector<boost::filesystem::path>{runtime_dir()});
197 }
198 
199 /*
200  * The find_all_config and find_all_data functions return for config and data
201  * all paths that contain the name suffix.
202  *
203  * This is useful if you can read multiple instances of the config or data.
204  */
205 inline std::vector<boost::filesystem::path> find_all_config(const boost::filesystem::path& file) {
206  return xdg_findall(file, all_config_dirs());
207 }
208 inline std::vector<boost::filesystem::path> find_all_data(const boost::filesystem::path& file) {
209  return xdg_findall(file, all_data_dirs());
210 }
211 
212 /*
213  * The merge_config and merge_data follow the same logic as the find_all_*
214  * functions, except that instead of returning the paths, they repeatedly
215  * apply the supplied function to the path.
216  *
217  * Because in merging, the most important file should be loaded last, there
218  * is a reverse option. If the function returns false, the merging is aborted.
219  */
220 inline void merge_config(const boost::filesystem::path& file,
221  std::function<bool(const boost::filesystem::path&)>
222  mergefn,
223  bool reverse = false) {
224  xdg_merge(file, all_config_dirs(), reverse, mergefn);
225 }
226 
227 inline void merge_data(const boost::filesystem::path& file,
228  std::function<bool(const boost::filesystem::path&)>
229  mergefn,
230  bool reverse = false) {
231  xdg_merge(file, all_data_dirs(), reverse, mergefn);
232 }
233 
234 } // namespace utility
235 } // namespace cloe
boost::filesystem::path cache_home()
User cache files base directory, e.g., ~/.cache.
Definition: xdg.hpp:113
std::vector< boost::filesystem::path > config_dirs()
Global configuration directories, e.g., /etc/xdg.
Definition: xdg.hpp:131
std::vector< boost::filesystem::path > all_data_dirs()
User and global data directories.
Definition: xdg.hpp:156
boost::filesystem::path config_home()
User configuration base directory, e.g., ~./config.
Definition: xdg.hpp:95
std::vector< boost::filesystem::path > data_dirs()
Global data files directories, e.g., /usr/local/share.
Definition: xdg.hpp:140
XdgError
Definition: xdg.hpp:42
std::vector< boost::filesystem::path > all_config_dirs()
User and global configuration directories.
Definition: xdg.hpp:149
boost::filesystem::path data_home()
User data files base directory, e.g., ~/.local/share.
Definition: xdg.hpp:104
boost::filesystem::path runtime_dir()
User runtime files base directory, e.g., /run/user/1000
Definition: xdg.hpp:122