summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2019-03-16 18:52:24 +0100
committerDavid Robillard <d@drobilla.net>2019-03-16 21:03:20 +0100
commitf7ace4ffc6dabd93a4d0abc6121dd8dd87ce7af1 (patch)
tree8f380c8cae3a3b9b61c5141b83b7262027d6e13f
parent2058c121a6224263368d584c1cdc05c1819b0721 (diff)
downloadingen-f7ace4ffc6dabd93a4d0abc6121dd8dd87ce7af1.tar.gz
ingen-f7ace4ffc6dabd93a4d0abc6121dd8dd87ce7af1.tar.bz2
ingen-f7ace4ffc6dabd93a4d0abc6121dd8dd87ce7af1.zip
Properly support XDG_DATA_HOME and XDG_DATA_DIRS
-rw-r--r--ingen/runtime_paths.hpp8
-rw-r--r--src/runtime_paths.cpp86
2 files changed, 78 insertions, 16 deletions
diff --git a/ingen/runtime_paths.hpp b/ingen/runtime_paths.hpp
index 2575efa1..fb697b14 100644
--- a/ingen/runtime_paths.hpp
+++ b/ingen/runtime_paths.hpp
@@ -30,12 +30,20 @@ extern const char search_path_separator;
INGEN_API void set_bundle_path(const char* path);
INGEN_API void set_bundle_path_from_code(void* function);
+INGEN_API FilePath
+find_in_search_path(const std::string& name,
+ const std::vector<FilePath>& search_path);
+
INGEN_API FilePath bundle_file_path(const std::string& name);
INGEN_API FilePath data_file_path(const std::string& name);
INGEN_API FilePath ingen_module_path(const std::string& name, FilePath dir={});
INGEN_API FilePath user_config_dir();
+INGEN_API FilePath user_data_dir();
INGEN_API std::vector<FilePath> system_config_dirs();
+INGEN_API std::vector<FilePath> system_data_dirs();
+INGEN_API std::vector<FilePath> config_dirs();
+INGEN_API std::vector<FilePath> data_dirs();
} // namespace ingen
diff --git a/src/runtime_paths.cpp b/src/runtime_paths.cpp
index 6e42381f..471e2ba2 100644
--- a/src/runtime_paths.cpp
+++ b/src/runtime_paths.cpp
@@ -17,6 +17,7 @@
#include "ingen/runtime_paths.hpp"
#include "ingen/FilePath.hpp"
+#include "ingen/filesystem.hpp"
#include "ingen_config.h"
#include <algorithm>
@@ -43,6 +44,22 @@ static const char* const library_prefix = "lib";
static const char* const library_suffix = ".so";
#endif
+static std::vector<FilePath>
+parse_search_path(const char* search_path, std::vector<FilePath> defaults)
+{
+ if (!search_path) {
+ return std::move(defaults);
+ }
+
+ std::vector<FilePath> paths;
+ std::istringstream ss{search_path};
+ std::string entry;
+ while (std::getline(ss, entry, search_path_separator)) {
+ paths.emplace_back(entry);
+ }
+ return paths;
+}
+
/** Must be called once at startup, and passed a pointer to a function
* that lives in the 'top level' of the bundle (e.g. the executable).
* Passing a function defined in a module etc. will not work!
@@ -69,6 +86,20 @@ set_bundle_path(const char* path)
bundle_path = FilePath(path);
}
+FilePath
+find_in_search_path(const std::string& name,
+ const std::vector<FilePath>& search_path)
+{
+ for (const auto& dir : search_path) {
+ FilePath path = dir / name;
+ if (filesystem::exists(path)) {
+ return path;
+ }
+ }
+
+ return FilePath{};
+}
+
/** Return the absolute path of a file in an Ingen LV2 bundle
*/
FilePath
@@ -85,7 +116,7 @@ data_file_path(const std::string& name)
#ifdef BUNDLE
return bundle_path / INGEN_DATA_DIR / name;
#else
- return FilePath(INGEN_DATA_DIR) / name;
+ return find_in_search_path(name, data_dirs());
#endif
}
@@ -110,34 +141,57 @@ ingen_module_path(const std::string& name, FilePath dir)
FilePath
user_config_dir()
{
- const char* const xdg_config_home = getenv("XDG_CONFIG_HOME");
- const char* const home = getenv("HOME");
-
- if (xdg_config_home) {
+ if (const char* xdg_config_home = getenv("XDG_CONFIG_HOME")) {
return FilePath(xdg_config_home);
- } else if (home) {
+ } else if (const char* home = getenv("HOME")) {
return FilePath(home) / ".config";
}
+ return FilePath();
+}
+FilePath
+user_data_dir()
+{
+ if (const char* xdg_data_home = getenv("XDG_DATA_HOME")) {
+ return FilePath(xdg_data_home);
+ } else if (const char* home = getenv("HOME")) {
+ return FilePath(home) / ".local/share";
+ }
return FilePath();
}
std::vector<FilePath>
system_config_dirs()
{
- const char* const xdg_config_dirs = getenv("XDG_CONFIG_DIRS");
+ return parse_search_path(getenv("XDG_CONFIG_DIRS"), {"/etc/xdg"});
+}
- std::vector<FilePath> paths;
- if (xdg_config_dirs) {
- std::istringstream ss(xdg_config_dirs);
- std::string entry;
- while (std::getline(ss, entry, search_path_separator)) {
- paths.emplace_back(entry);
- }
- } else {
- paths.emplace_back("/etc/xdg");
+std::vector<FilePath>
+config_dirs()
+{
+ std::vector<FilePath> paths = system_config_dirs();
+ const FilePath user_dir = user_config_dir();
+ if (!user_dir.empty()) {
+ paths.insert(paths.begin(), user_dir);
}
+ return paths;
+}
+
+std::vector<FilePath>
+system_data_dirs()
+{
+ return parse_search_path(getenv("XDG_DATA_DIRS"),
+ {"/usr/local/share", "/usr/share"});
+}
+std::vector<FilePath>
+data_dirs()
+{
+ std::vector<FilePath> paths = system_data_dirs();
+ const FilePath user_dir = user_data_dir();
+ if (!user_dir.empty()) {
+ paths.insert(paths.begin(), user_dir);
+ }
return paths;
}