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