diff options
Diffstat (limited to 'src/FilePath.cpp')
-rw-r--r-- | src/FilePath.cpp | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/src/FilePath.cpp b/src/FilePath.cpp new file mode 100644 index 00000000..557fabc9 --- /dev/null +++ b/src/FilePath.cpp @@ -0,0 +1,242 @@ +/* + This file is part of Ingen. + Copyright 2018 David Robillard <http://drobilla.net/> + + 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 <http://www.gnu.org/licenses/>. +*/ + +#include "ingen/FilePath.hpp" + +namespace Ingen { + +template <typename Char> +static bool +is_sep(const Char chr) +{ +#ifdef USE_WINDOWS_FILE_PATHS + return chr == L'/' || chr == preferred_separator; +#else + return chr == '/'; +#endif +} + +FilePath& +FilePath::operator=(FilePath&& path) noexcept +{ + _str = std::move(path._str); + path.clear(); + return *this; +} + +FilePath& +FilePath::operator=(string_type&& str) +{ + return *this = FilePath(std::move(str)); +} + +FilePath& +FilePath::operator/=(const FilePath& path) +{ + const FilePath::string_type str = path.string(); + if (!_str.empty() && !is_sep(_str.back()) && !str.empty() && + !is_sep(str.front())) { + _str += preferred_separator; + } + + _str += str; + return *this; +} + +FilePath& +FilePath::operator+=(const FilePath& path) +{ + return operator+=(path.native()); +} + +FilePath& +FilePath::operator+=(const string_type& str) +{ + _str += str; + return *this; +} + +FilePath& +FilePath::operator+=(const value_type* str) +{ + _str += str; + return *this; +} + +FilePath& +FilePath::operator+=(value_type chr) +{ + _str += chr; + return *this; +} + +FilePath& +FilePath::operator+=(boost::basic_string_view<value_type> sv) +{ + _str.append(sv.data(), sv.size()); + return *this; +} + +FilePath +FilePath::root_name() const +{ +#ifdef USE_WINDOWS_FILE_PATHS + if (_str.length() >= 2 && _str[0] >= 'A' && _str[0] <= 'Z' && + _str[1] == ':') { + return FilePath(_str.substr(0, 2)); + } +#endif + + return FilePath(); +} + +FilePath +FilePath::root_directory() const +{ +#ifdef USE_WINDOWS_FILE_PATHS + const auto name = root_name().string(); + return name.empty() ? Path() : Path(name + preferred_separator); +#endif + + return _str[0] == '/' ? FilePath("/") : FilePath(); +} + +FilePath +FilePath::root_path() const +{ +#ifdef USE_WINDOWS_FILE_PATHS + const auto name = root_name(); + return name.empty() ? FilePath() : name / root_directory(); +#endif + return root_directory(); +} + +FilePath +FilePath::relative_path() const +{ + const auto root = root_path(); + return root.empty() ? FilePath() + : FilePath(_str.substr(root.string().length())); +} + +FilePath +FilePath::parent_path() const +{ + if (empty() || *this == root_path()) { + return *this; + } + + const auto first_sep = find_first_sep(); + const auto last_sep = find_last_sep(); + return ((last_sep == std::string::npos || last_sep == first_sep) + ? root_path() + : FilePath(_str.substr(0, last_sep))); +} + +FilePath +FilePath::filename() const +{ + return ((empty() || *this == root_path()) + ? FilePath() + : FilePath(_str.substr(find_last_sep() + 1))); +} + +FilePath +FilePath::stem() const +{ + const auto name = filename(); + const auto dot = name.string().find('.'); + return ((dot == std::string::npos) ? name + : FilePath(name.string().substr(0, dot))); +} + +FilePath +FilePath::extension() const +{ + const auto name = filename().string(); + const auto dot = name.find('.'); + return ((dot == std::string::npos) ? FilePath() + : FilePath(name.substr(dot, dot))); +} + +bool +FilePath::is_absolute() const +{ +#ifdef USE_WINDOWS_FILE_PATHS + return !root_name().empty(); +#else + return !root_directory().empty(); +#endif +} + +std::size_t +FilePath::find_first_sep() const +{ + const auto i = std::find_if(_str.begin(), _str.end(), is_sep<value_type>); + return i == _str.end() ? std::string::npos : (i - _str.begin()); +} + +std::size_t +FilePath::find_last_sep() const +{ + const auto i = std::find_if(_str.rbegin(), _str.rend(), is_sep<value_type>); + return (i == _str.rend() ? std::string::npos + : (_str.length() - 1 - (i - _str.rbegin()))); +} + +bool +operator==(const FilePath& lhs, const FilePath& rhs) noexcept +{ + return lhs.string() == rhs.string(); +} + +bool +operator!=(const FilePath& lhs, const FilePath& rhs) noexcept +{ + return !(lhs == rhs); +} + +bool +operator<(const FilePath& lhs, const FilePath& rhs) noexcept +{ + return lhs.string().compare(rhs.string()) < 0; +} + +bool +operator<=(const FilePath& lhs, const FilePath& rhs) noexcept +{ + return !(rhs < lhs); +} + +bool +operator>(const FilePath& lhs, const FilePath& rhs) noexcept +{ + return rhs < lhs; +} + +bool +operator>=(const FilePath& lhs, const FilePath& rhs) noexcept +{ + return !(lhs < rhs); +} + +FilePath +operator/(const FilePath& lhs, const FilePath& rhs) +{ + return FilePath(lhs) /= rhs; +} + +} // namespace Ingen |