From f7ace4ffc6dabd93a4d0abc6121dd8dd87ce7af1 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 16 Mar 2019 18:52:24 +0100 Subject: Properly support XDG_DATA_HOME and XDG_DATA_DIRS --- src/runtime_paths.cpp | 86 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 16 deletions(-) (limited to 'src') 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 @@ -43,6 +44,22 @@ static const char* const library_prefix = "lib"; static const char* const library_suffix = ".so"; #endif +static std::vector +parse_search_path(const char* search_path, std::vector defaults) +{ + if (!search_path) { + return std::move(defaults); + } + + std::vector 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& 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 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 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 +config_dirs() +{ + std::vector 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 +system_data_dirs() +{ + return parse_search_path(getenv("XDG_DATA_DIRS"), + {"/usr/local/share", "/usr/share"}); +} +std::vector +data_dirs() +{ + std::vector paths = system_data_dirs(); + const FilePath user_dir = user_data_dir(); + if (!user_dir.empty()) { + paths.insert(paths.begin(), user_dir); + } return paths; } -- cgit v1.2.1