From a99b72e4adbc4c28fadc08d29299d99405f72db9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 21 Jan 2018 00:41:34 +0100 Subject: Add FilePath class and remove use of glib path utilities --- ingen/Configuration.hpp | 15 +++--- ingen/FilePath.hpp | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ ingen/Node.hpp | 3 +- ingen/Parser.hpp | 11 +++-- ingen/URI.hpp | 6 +++ ingen/filesystem.hpp | 84 ++++++++++++++++++++++++++++++++ ingen/runtime_paths.hpp | 13 +++-- 7 files changed, 242 insertions(+), 16 deletions(-) create mode 100644 ingen/FilePath.hpp create mode 100644 ingen/filesystem.hpp (limited to 'ingen') diff --git a/ingen/Configuration.hpp b/ingen/Configuration.hpp index ae5e4909..67104422 100644 --- a/ingen/Configuration.hpp +++ b/ingen/Configuration.hpp @@ -30,6 +30,7 @@ namespace Ingen { +class FilePath; class Forge; class URIMap; @@ -81,7 +82,7 @@ public: void parse(int argc, char** argv) throw (OptionError); /** Load a specific file. */ - bool load(const std::string& path); + bool load(const FilePath& path); /** Save configuration to a file. * @@ -98,10 +99,10 @@ public: * * @return The absolute path of the saved configuration file. */ - std::string save(URIMap& uri_map, - const std::string& app, - const std::string& filename, - unsigned scopes) throw (FileError); + FilePath save(URIMap& uri_map, + const std::string& app, + const FilePath& filename, + unsigned scopes) throw (FileError); /** Load files from the standard configuration directories for the app. * @@ -109,8 +110,8 @@ public: * will be loaded before the user's, e.g. ~/.config/appname/filename, * so the user options will override the system options. */ - std::list load_default(const std::string& app, - const std::string& filename); + std::list load_default(const std::string& app, + const FilePath& filename); const Atom& option(const std::string& long_name) const; bool set(const std::string& long_name, const Atom& value); diff --git a/ingen/FilePath.hpp b/ingen/FilePath.hpp new file mode 100644 index 00000000..7ad341e0 --- /dev/null +++ b/ingen/FilePath.hpp @@ -0,0 +1,126 @@ +/* + This file is part of Ingen. + Copyright 2018 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_FILE_PATH_HPP +#define INGEN_FILE_PATH_HPP + +#include +#include +#include + +#include + +#if defined(_WIN32) && !defined(__CYGWIN__) +#define USE_WINDOWS_FILE_PATHS 1 +#endif + +namespace Ingen { + +/** A path to a file. + * + * This is a minimal subset of the std::filesystem::path interface in C++17. + * Support for Windows paths is only partial and there is no support for + * character encoding conversion at all. + */ +class FilePath +{ +public: +#ifdef USE_WINDOWS_FILE_PATHS + typedef wchar_t value_type; + static constexpr value_type preferred_separator = L'\\'; +#else + typedef char value_type; + static constexpr value_type preferred_separator = '/'; +#endif + + typedef std::basic_string string_type; + + FilePath() noexcept = default; + FilePath(const FilePath&) = default; + + FilePath(FilePath&& path) noexcept + : _str(std::move(path._str)) + { + path.clear(); + } + + FilePath(string_type&& str) : _str(std::move(str)) {} + FilePath(const string_type& str) : _str(str) {} + FilePath(const value_type* str) : _str(str) {} + FilePath(const boost::basic_string_view& sv) : _str(sv) {} + + ~FilePath() = default; + + FilePath& operator=(const FilePath& path) = default; + FilePath& operator=(FilePath&& path) noexcept; + FilePath& operator=(string_type&& str); + + FilePath& operator/=(const FilePath& path); + + FilePath& operator+=(const FilePath& path); + FilePath& operator+=(const string_type& str); + FilePath& operator+=(const value_type* str); + FilePath& operator+=(value_type chr); + FilePath& operator+=(boost::basic_string_view sv); + + void clear() noexcept { _str.clear(); } + + const string_type& native() const noexcept { return _str; } + const string_type& string() const noexcept { return _str; } + const value_type* c_str() const noexcept { return _str.c_str(); } + + operator string_type() const { return _str; } + + FilePath root_name() const; + FilePath root_directory() const; + FilePath root_path() const; + FilePath relative_path() const; + FilePath parent_path() const; + FilePath filename() const; + FilePath stem() const; + FilePath extension() const; + + bool empty() const noexcept { return _str.empty(); } + + bool is_absolute() const; + bool is_relative() const { return !is_absolute(); } + +private: + std::size_t find_first_sep() const; + std::size_t find_last_sep() const; + + string_type _str; +}; + +bool operator==(const FilePath& lhs, const FilePath& rhs) noexcept; +bool operator!=(const FilePath& lhs, const FilePath& rhs) noexcept; +bool operator<(const FilePath& lhs, const FilePath& rhs) noexcept; +bool operator<=(const FilePath& lhs, const FilePath& rhs) noexcept; +bool operator>(const FilePath& lhs, const FilePath& rhs) noexcept; +bool operator>=(const FilePath& lhs, const FilePath& rhs) noexcept; + +FilePath operator/(const FilePath& lhs, const FilePath& rhs); + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const FilePath& path) +{ + return os << path.string(); +} + +} // namespace Ingen + +#endif // INGEN_FILE_PATH_HPP diff --git a/ingen/Node.hpp b/ingen/Node.hpp index e023e9e2..ca78aa3d 100644 --- a/ingen/Node.hpp +++ b/ingen/Node.hpp @@ -36,6 +36,7 @@ class Symbol; namespace Ingen { class Arc; +class FilePath; class Store; class URIs; @@ -74,7 +75,7 @@ public: // Plugin blocks only virtual LilvInstance* instance() { return nullptr; } - virtual bool save_state(const std::string& dir) const { return false; } + virtual bool save_state(const FilePath& dir) const { return false; } // All objects virtual GraphType graph_type() const = 0; diff --git a/ingen/Parser.hpp b/ingen/Parser.hpp index ac9d8320..96e21c51 100644 --- a/ingen/Parser.hpp +++ b/ingen/Parser.hpp @@ -23,6 +23,7 @@ #include +#include "ingen/FilePath.hpp" #include "ingen/Properties.hpp" #include "ingen/URI.hpp" #include "ingen/ingen.h" @@ -50,7 +51,7 @@ public: /** Record of a resource listed in a bundle manifest. */ struct ResourceRecord { - inline ResourceRecord(URI u, std::string f) + inline ResourceRecord(URI u, FilePath f) : uri(std::move(u)), filename(std::move(f)) {} @@ -58,8 +59,8 @@ public: return uri < r.uri; } - URI uri; ///< URI of resource (e.g. a Graph) - std::string filename; ///< Path of describing file (seeAlso) + URI uri; ///< URI of resource (e.g. a Graph) + FilePath filename; ///< Path of describing file (seeAlso) }; /** Find all resources of a given type listed in a manifest file. */ @@ -79,7 +80,7 @@ public: virtual bool parse_file( World* world, Interface* target, - const std::string& path, + const FilePath& path, boost::optional parent = boost::optional(), boost::optional symbol = boost::optional(), boost::optional data = boost::optional()); @@ -88,7 +89,7 @@ public: World* world, Interface* target, const std::string& str, - const std::string& base_uri, + const URI& base_uri, boost::optional parent = boost::optional(), boost::optional symbol = boost::optional(), boost::optional data = boost::optional()); diff --git a/ingen/URI.hpp b/ingen/URI.hpp index 6b2adff4..30aeb7cc 100644 --- a/ingen/URI.hpp +++ b/ingen/URI.hpp @@ -22,6 +22,7 @@ #include +#include "ingen/FilePath.hpp" #include "ingen/ingen.h" #include "serd/serd.h" #include "sord/sordmm.hpp" @@ -38,6 +39,7 @@ public: explicit URI(const char* str); URI(const std::string& str, const URI& base); explicit URI(const Sord::Node& node); + explicit URI(const FilePath& path); URI(const URI& uri); URI& operator=(const URI& uri); @@ -53,6 +55,10 @@ public: size_t length() const { return _node.n_bytes; } const char* c_str() const { return (const char*)_node.buf; } + FilePath file_path() const { + return scheme() == "file" ? FilePath(path()) : FilePath(); + } + operator std::string() const { return string(); } const char* begin() const { return (const char*)_node.buf; } diff --git a/ingen/filesystem.hpp b/ingen/filesystem.hpp new file mode 100644 index 00000000..19fa74b2 --- /dev/null +++ b/ingen/filesystem.hpp @@ -0,0 +1,84 @@ +/* + This file is part of Ingen. + Copyright 2007-2017 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_FILESYSTEM_HPP +#define INGEN_FILESYSTEM_HPP + +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef _WIN32 +# include +# include +# define F_OK 0 +# define mkdir(path, flags) _mkdir(path) +#endif + +#include "ingen/FilePath.hpp" + +/* A minimal subset of the std::filesystem API from C++17. */ + +namespace Ingen { +namespace filesystem { + +inline bool exists(const FilePath& path) +{ + return !access(path.c_str(), F_OK); +} + +inline bool is_directory(const FilePath& path) +{ + struct stat info; + stat(path.c_str(), &info); + return S_ISDIR(info.st_mode); +} + +inline bool create_directories(const FilePath& path) +{ + std::vector paths; + for (FilePath p = path; p != path.root_directory(); p = p.parent_path()) { + paths.emplace_back(p); + } + + for (auto p = paths.rbegin(); p != paths.rend(); ++p) { + if (mkdir(p->c_str(), 0755) && errno != EEXIST) { + return false; + } + } + + return true; +} + +inline FilePath current_path() +{ + std::unique_ptr cpath(realpath(".", NULL)); + const FilePath path(cpath.get()); + return path; +} + +} // namespace filesystem +} // namespace Ingen + +#endif // INGEN_FILESYSTEM_HPP diff --git a/ingen/runtime_paths.hpp b/ingen/runtime_paths.hpp index 747bc9b7..1a8bc2c2 100644 --- a/ingen/runtime_paths.hpp +++ b/ingen/runtime_paths.hpp @@ -18,17 +18,24 @@ #define INGEN_RUNTIME_PATHS_HPP #include +#include #include "ingen/ingen.h" +#include "ingen/FilePath.hpp" namespace Ingen { +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 std::string bundle_file_path(const std::string& name); -INGEN_API std::string data_file_path(const std::string& name); -INGEN_API std::string module_path(const std::string& name, std::string dir=""); +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 std::vector system_config_dirs(); } // namespace Ingen -- cgit v1.2.1