/*
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 .
*/
#include "ingen/FilePath.hpp"
#include
#include
#include
namespace ingen {
template
static bool
is_sep(const Char chr)
{
#if 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)
{
_str = std::move(str);
return *this;
}
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 sv)
{
_str.append(sv.data(), sv.size());
return *this;
}
FilePath
FilePath::root_name()
{
#if 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
{
#if 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
{
#if 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
{
#if 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);
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);
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