Remove filesystem compatibility implementation
Keep <experimental/filesystem> support for now, so we still need to use a compatibility header to alias the namespace.pull/1273/head
parent
e6a7b32fee
commit
e4ea8e0df4
|
@ -353,17 +353,13 @@ include(CheckSymbolExists)
|
|||
check_symbol_exists(wordexp wordexp.h HAVE_WORDEXP)
|
||||
check_include_files(byteswap.h HAVE_BYTESWAP_H)
|
||||
|
||||
find_package(Filesystem)
|
||||
if(Filesystem_FOUND)
|
||||
if(CXX_FILESYSTEM_IS_EXPERIMENTAL)
|
||||
set(HAVE_EXPERIMENTAL_FILESYSTEM ON)
|
||||
else()
|
||||
set(HAVE_FILESYSTEM ON)
|
||||
endif()
|
||||
link_libraries(std::filesystem)
|
||||
find_package(Filesystem REQUIRED COMPONENTS Final Experimental)
|
||||
if(CXX_FILESYSTEM_IS_EXPERIMENTAL)
|
||||
message(WARNING "C++ lacks header <filesystem>, using <experimental/filesystem> instead.")
|
||||
else()
|
||||
message(WARNING "C++ experimental filesystem library is unusable!\nWill use own implementation.")
|
||||
set(HAVE_STD_FILESYSTEM ON)
|
||||
endif()
|
||||
link_libraries(std::filesystem)
|
||||
|
||||
try_compile(HAVE_CHARCONV ${CMAKE_BINARY_DIR} "${CMAKE_SOURCE_DIR}/checks/cxxccint.cpp")
|
||||
if(HAVE_CHARCONV)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#cmakedefine HAVE_BYTESWAP_H
|
||||
#cmakedefine HAVE_CHARCONV
|
||||
#cmakedefine HAVE_FLOAT_CHARCONV
|
||||
#cmakedefine HAVE_FILESYSTEM
|
||||
#cmakedefine HAVE_EXPERIMENTAL_FILESYSTEM
|
||||
#cmakedefine HAVE_STD_FILESYSTEM
|
||||
#cmakedefine HAVE_WORDEXP
|
||||
#cmakedefine WORDS_BIGENDIAN
|
||||
|
|
|
@ -5,13 +5,6 @@ set(CELCOMPAT_SOURCES
|
|||
)
|
||||
endif()
|
||||
|
||||
if ((NOT HAVE_EXPERIMENTAL_FILESYSTEM) AND (NOT HAVE_FILESYSTEM))
|
||||
set(CELCOMPAT_SOURCES ${CELCOMPAT_SOURCES}
|
||||
fs.cpp
|
||||
fs.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CELCOMPAT_SOURCES)
|
||||
add_library(celcompat OBJECT ${CELCOMPAT_SOURCES})
|
||||
endif()
|
||||
|
|
|
@ -2,13 +2,10 @@
|
|||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_FILESYSTEM
|
||||
#ifdef HAVE_STD_FILESYSTEM
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#elif defined(HAVE_EXPERIMENTAL_FILESYSTEM)
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#else
|
||||
#include "fs.h"
|
||||
namespace fs = celestia::filesystem;
|
||||
#endif
|
||||
|
|
|
@ -1,655 +0,0 @@
|
|||
#include "fs.h"
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#include <celutil/winutil.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// M$VC++ build without C++ exceptions are not supported yet
|
||||
#ifndef __cpp_exceptions
|
||||
#define __cpp_exceptions 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ! __cpp_exceptions
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define W(s) L##s
|
||||
#else
|
||||
#define W(s) s
|
||||
#endif
|
||||
|
||||
namespace celestia
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
|
||||
// we should skip "." and ".."
|
||||
template<typename CharT> static bool is_special_dir(const CharT s[])
|
||||
{
|
||||
return s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'));
|
||||
}
|
||||
|
||||
path operator/(const path& lhs, const path& rhs)
|
||||
{
|
||||
return path(lhs) /= rhs;
|
||||
}
|
||||
|
||||
path u8path(const std::string& source)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return UTF8ToWide(source);
|
||||
#else
|
||||
return source; // FIXME
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void path::fixup_separators()
|
||||
{
|
||||
if (m_fmt == native_format)
|
||||
return;
|
||||
|
||||
string_type::size_type pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
pos = m_path.find(L'/', pos);
|
||||
if (pos == path::string_type::npos)
|
||||
break;
|
||||
m_path[pos] = preferred_separator;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
path path::filename() const
|
||||
{
|
||||
auto pos = m_path.rfind(preferred_separator);
|
||||
if (pos == string_type::npos)
|
||||
pos = 0;
|
||||
else
|
||||
pos++;
|
||||
|
||||
auto fn = m_path.substr(pos);
|
||||
if (is_special_dir(fn.c_str()))
|
||||
return path();
|
||||
|
||||
path p(fn);
|
||||
return p;
|
||||
}
|
||||
|
||||
path path::stem() const
|
||||
{
|
||||
auto fn = filename().native();
|
||||
auto pos = fn.rfind(W('.'));
|
||||
|
||||
if (pos == 0 || pos == string_type::npos)
|
||||
return fn;
|
||||
|
||||
return fn.substr(0, pos);
|
||||
}
|
||||
|
||||
path path::extension() const
|
||||
{
|
||||
auto fn = filename().native();
|
||||
auto pos = fn.rfind(W('.'));
|
||||
|
||||
if (pos == 0 || pos == string_type::npos)
|
||||
return path();
|
||||
|
||||
return fn.substr(pos);
|
||||
}
|
||||
|
||||
path path::parent_path() const
|
||||
{
|
||||
auto pos = m_path.rfind(preferred_separator);
|
||||
if (pos == 0)
|
||||
return path(m_path.substr(0, 1));
|
||||
|
||||
if (pos == string_type::npos)
|
||||
return path();
|
||||
|
||||
return path(m_path.substr(0, pos));
|
||||
}
|
||||
|
||||
path& path::replace_extension(const path& replacement)
|
||||
{
|
||||
auto pos = m_path.rfind(W('.'));
|
||||
|
||||
if (pos != (m_path.length() - 1))
|
||||
{
|
||||
if (pos != 0 && pos != string_type::npos)
|
||||
m_path.resize(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// special case for "/dir/" or "/dir/."
|
||||
path basename = filename();
|
||||
if (!(basename.empty() || basename == W(".")))
|
||||
m_path.resize(pos);
|
||||
}
|
||||
|
||||
if (replacement.empty())
|
||||
return *this;
|
||||
|
||||
if (replacement.m_path[0] != W('.'))
|
||||
m_path += W('.');
|
||||
|
||||
m_path += replacement.m_path;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool path::is_absolute() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return m_path[0] == preferred_separator || m_path[1] == L':';
|
||||
#else
|
||||
return m_path[0] == preferred_separator;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct directory_iterator::SearchImpl
|
||||
{
|
||||
path m_path {};
|
||||
directory_options m_options { directory_options::none };
|
||||
#ifdef _WIN32
|
||||
HANDLE m_handle { INVALID_HANDLE_VALUE };
|
||||
#else
|
||||
DIR *m_dir { nullptr };
|
||||
#endif
|
||||
explicit SearchImpl(const path& p, directory_options options) :
|
||||
m_options(options),
|
||||
m_path(p)
|
||||
{
|
||||
};
|
||||
~SearchImpl();
|
||||
|
||||
bool advance(directory_entry&, std::error_code*);
|
||||
};
|
||||
|
||||
directory_iterator::SearchImpl::~SearchImpl()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(m_handle);
|
||||
m_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
if (m_dir != nullptr)
|
||||
{
|
||||
closedir(m_dir);
|
||||
m_dir = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool directory_iterator::SearchImpl::advance(directory_entry& entry, std::error_code* ec)
|
||||
{
|
||||
if (ec != nullptr)
|
||||
ec->clear();
|
||||
|
||||
#ifdef _WIN32
|
||||
WIN32_FIND_DATAW findData;
|
||||
|
||||
if (m_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
m_handle = FindFirstFileW((m_path / L"*").c_str(), &findData);
|
||||
if (m_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::error_code m_ec = std::error_code(GetLastError(), std::system_category());
|
||||
m_ec = std::error_code(GetLastError(), std::system_category());
|
||||
if (m_ec.value() == ERROR_ACCESS_DENIED && bool(m_options & directory_options::skip_permission_denied))
|
||||
m_ec.clear();
|
||||
if (m_ec)
|
||||
{
|
||||
if (ec != nullptr)
|
||||
*ec = m_ec;
|
||||
else
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(m_ec, "celfs::directory_iterator::SearchImpl::advance error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FindNextFileW(m_handle, &findData))
|
||||
return false;
|
||||
}
|
||||
|
||||
while (is_special_dir(findData.cFileName))
|
||||
{
|
||||
if (!FindNextFileW(m_handle, &findData))
|
||||
return false;
|
||||
}
|
||||
|
||||
entry = directory_entry(std::move(m_path / findData.cFileName));
|
||||
return true;
|
||||
#else
|
||||
if (m_dir == nullptr)
|
||||
{
|
||||
m_dir = opendir(m_path.c_str());
|
||||
if (m_dir == nullptr)
|
||||
{
|
||||
std::error_code m_ec = std::error_code(errno, std::system_category());
|
||||
if (m_ec.value() == EACCES && bool(m_options & directory_options::skip_permission_denied))
|
||||
m_ec.clear();
|
||||
if (m_ec)
|
||||
{
|
||||
if (ec != nullptr)
|
||||
*ec = m_ec;
|
||||
else
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(m_ec, "celfs::directory_iterator::SearchImpl::advance error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct dirent* ent = nullptr;
|
||||
do
|
||||
{
|
||||
ent = readdir(m_dir);
|
||||
if (ent == nullptr)
|
||||
return false;
|
||||
}
|
||||
while (is_special_dir(ent->d_name));
|
||||
|
||||
entry = directory_entry(std::move(m_path / ent->d_name));
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
directory_iterator::directory_iterator(const path& p) :
|
||||
directory_iterator::directory_iterator(p, directory_options::none, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
directory_iterator::directory_iterator(const path& p, directory_options options) :
|
||||
directory_iterator::directory_iterator(p, options, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
directory_iterator::directory_iterator(const path& p, std::error_code& ec) :
|
||||
directory_iterator::directory_iterator(p, directory_options::none, &ec)
|
||||
{
|
||||
}
|
||||
|
||||
directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) :
|
||||
directory_iterator::directory_iterator(p, directory_options::none, &ec)
|
||||
{
|
||||
}
|
||||
|
||||
directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code* ec, bool advance) :
|
||||
m_path(p),
|
||||
m_search(new SearchImpl(p, options))
|
||||
{
|
||||
if (advance)
|
||||
__increment(ec);
|
||||
else
|
||||
m_entry = directory_entry(p);
|
||||
}
|
||||
|
||||
void directory_iterator::reset()
|
||||
{
|
||||
*this = directory_iterator();
|
||||
}
|
||||
|
||||
bool directory_iterator::operator==(const directory_iterator& other) const noexcept
|
||||
{
|
||||
return m_search == other.m_search && m_entry == other.m_entry;
|
||||
}
|
||||
|
||||
directory_iterator& directory_iterator::operator++()
|
||||
{
|
||||
return __increment();
|
||||
}
|
||||
|
||||
directory_iterator& directory_iterator::increment(std::error_code &ec)
|
||||
{
|
||||
return __increment(&ec);
|
||||
}
|
||||
|
||||
directory_iterator& directory_iterator::__increment(std::error_code *ec)
|
||||
{
|
||||
if (m_search != nullptr && !m_search->advance(m_entry, ec))
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
struct recursive_directory_iterator::DirStack
|
||||
{
|
||||
std::vector<directory_iterator> m_dirIters;
|
||||
};
|
||||
|
||||
|
||||
recursive_directory_iterator::recursive_directory_iterator(const path& p) : recursive_directory_iterator(p, directory_options::none, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options) : recursive_directory_iterator(p, options, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) : recursive_directory_iterator(p, directory_options::none, &ec)
|
||||
{
|
||||
}
|
||||
|
||||
recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) : recursive_directory_iterator(p, options, &ec)
|
||||
{
|
||||
}
|
||||
|
||||
recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code* ec)
|
||||
{
|
||||
m_options = options;
|
||||
|
||||
if (m_dirs == nullptr)
|
||||
m_dirs = std::shared_ptr<DirStack>(new DirStack);
|
||||
|
||||
m_iter = directory_iterator(p, options, ec, false);
|
||||
__increment(ec); // advance to the first element
|
||||
|
||||
if (m_iter == end(m_iter))
|
||||
reset();
|
||||
}
|
||||
|
||||
bool recursive_directory_iterator::operator==(const recursive_directory_iterator& other) const noexcept
|
||||
{
|
||||
return m_depth == other.m_depth &&
|
||||
m_pending == other.m_pending &&
|
||||
m_dirs == other.m_dirs &&
|
||||
m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
|
||||
recursive_directory_iterator& recursive_directory_iterator::operator++()
|
||||
{
|
||||
return __increment();
|
||||
}
|
||||
|
||||
recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code &ec)
|
||||
{
|
||||
return __increment(&ec);
|
||||
}
|
||||
|
||||
recursive_directory_iterator& recursive_directory_iterator::__increment(std::error_code *ec)
|
||||
{
|
||||
if (m_dirs == nullptr)
|
||||
return *this;
|
||||
|
||||
m_iter.__increment(ec);
|
||||
|
||||
while (m_iter == end(m_iter))
|
||||
{
|
||||
if (m_dirs->m_dirIters.empty())
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
m_iter = std::move(m_dirs->m_dirIters.back());
|
||||
m_iter.__increment(ec);
|
||||
m_dirs->m_dirIters.pop_back();
|
||||
}
|
||||
|
||||
auto path = m_iter->path();
|
||||
if (m_pending && (path.empty() || is_directory(path)))
|
||||
{
|
||||
m_dirs->m_dirIters.emplace_back(m_iter);
|
||||
m_iter = directory_iterator(path, m_options, ec, false);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void recursive_directory_iterator::pop()
|
||||
{
|
||||
std::error_code ec;
|
||||
pop(ec);
|
||||
}
|
||||
|
||||
void recursive_directory_iterator::pop(std::error_code& ec)
|
||||
{
|
||||
if (m_dirs->m_dirIters.empty())
|
||||
ec = std::error_code(errno, std::system_category()); // filesystem_error
|
||||
else
|
||||
m_dirs->m_dirIters.pop_back();
|
||||
}
|
||||
|
||||
void recursive_directory_iterator::reset()
|
||||
{
|
||||
*this = recursive_directory_iterator();
|
||||
}
|
||||
|
||||
|
||||
uintmax_t file_size(const path& p, std::error_code& ec) noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WIN32_FILE_ATTRIBUTE_DATA attr;
|
||||
LARGE_INTEGER fileSize = { 0 };
|
||||
if (GetFileAttributesExW(p.c_str(), GetFileExInfoStandard, &attr))
|
||||
{
|
||||
fileSize.LowPart = attr.nFileSizeLow;
|
||||
fileSize.HighPart = attr.nFileSizeHigh;
|
||||
return static_cast<uintmax_t>(fileSize.QuadPart);
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return static_cast<uintmax_t>(-1);
|
||||
}
|
||||
#else
|
||||
struct stat stat_buf;
|
||||
int rc = stat(p.c_str(), &stat_buf);
|
||||
if (rc == -1)
|
||||
{
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return static_cast<uintmax_t>(-1);
|
||||
}
|
||||
|
||||
return static_cast<uintmax_t>(stat_buf.st_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
uintmax_t file_size(const path& p)
|
||||
{
|
||||
std::error_code ec;
|
||||
uintmax_t s = file_size(p, ec);
|
||||
if (ec)
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(ec, "celfs::file_size error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
bool exists(const path& p, std::error_code& ec) noexcept
|
||||
{
|
||||
ec.clear();
|
||||
#ifdef _WIN32
|
||||
DWORD attr = GetFileAttributesW(&p.native()[0]);
|
||||
if (attr != INVALID_FILE_ATTRIBUTES)
|
||||
return true;
|
||||
|
||||
switch (GetLastError())
|
||||
{
|
||||
// behave like boost::filesystem
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
case ERROR_INVALID_NAME:
|
||||
case ERROR_INVALID_DRIVE:
|
||||
case ERROR_NOT_READY:
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
case ERROR_BAD_PATHNAME:
|
||||
case ERROR_BAD_NETPATH:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
struct stat buf;
|
||||
if (stat(p.c_str(), &buf) == 0)
|
||||
return true;
|
||||
|
||||
if (errno == ENOENT)
|
||||
return false;
|
||||
#endif
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool exists(const path& p)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool r = exists(p, ec);
|
||||
if (ec)
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(ec, "celfs::exists error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
bool is_directory(const path& p, std::error_code& ec) noexcept
|
||||
{
|
||||
ec.clear();
|
||||
#ifdef _WIN32
|
||||
DWORD attr = GetFileAttributesW(&p.native()[0]);
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return false;
|
||||
}
|
||||
|
||||
return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
#else
|
||||
struct stat buf;
|
||||
if (stat(p.c_str(), &buf) != 0)
|
||||
{
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return false;
|
||||
}
|
||||
return S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_directory(const path& p)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool r = is_directory(p, ec);
|
||||
if (ec)
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(ec, "celfs::is_directory error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
bool create_directory(const path& p, std::error_code& ec) noexcept
|
||||
{
|
||||
bool r;
|
||||
#ifdef _WIN32
|
||||
r = _wmkdir(p.c_str()) == 0;
|
||||
#else
|
||||
r = mkdir(p.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
|
||||
#endif
|
||||
if (!r)
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return r;
|
||||
}
|
||||
|
||||
bool create_directory(const path& p)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool r = create_directory(p, ec);
|
||||
if (ec)
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(ec, "celfs::create_directory error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
path current_path()
|
||||
{
|
||||
std::error_code ec;
|
||||
path p = current_path(ec);
|
||||
|
||||
if (ec)
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(ec, "celfs::current_path error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
path current_path(std::error_code& ec)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::wstring buffer(MAX_PATH + 1, 0);
|
||||
DWORD r = GetModuleFileNameW(nullptr, &buffer[0], MAX_PATH);
|
||||
if (r == 0)
|
||||
{
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return path();
|
||||
}
|
||||
auto pos = buffer.find_last_of(L"\\/");
|
||||
return buffer.substr(0, pos);
|
||||
#else
|
||||
std::string buffer(256, 0);
|
||||
char *r = getcwd(&buffer[0], buffer.size());
|
||||
if (r == nullptr)
|
||||
{
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
return path();
|
||||
}
|
||||
return buffer;
|
||||
#endif
|
||||
}
|
||||
|
||||
void current_path(const path& p)
|
||||
{
|
||||
std::error_code ec;
|
||||
current_path(p, ec);
|
||||
if (ec)
|
||||
#if __cpp_exceptions
|
||||
throw filesystem_error(ec, "celfs::current_path error");
|
||||
#else
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void current_path(const path& p, std::error_code& ec) noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
BOOL ret = SetCurrentDirectoryW(p.c_str());
|
||||
if (!ret)
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
#else
|
||||
int ret = chdir(p.c_str());
|
||||
if (ret != 0)
|
||||
ec = std::error_code(errno, std::system_category());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,490 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
#ifdef _WIN32
|
||||
#include <celutil/winutil.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace celestia
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
class filesystem_error : public std::system_error
|
||||
{
|
||||
public:
|
||||
filesystem_error(std::error_code ec, const char* msg) :
|
||||
std::system_error(ec, msg)
|
||||
{
|
||||
}
|
||||
}; // filesystem_error
|
||||
|
||||
|
||||
class path
|
||||
{
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
using string_type = std::wstring;
|
||||
#else
|
||||
using string_type = std::string;
|
||||
#endif
|
||||
using value_type = string_type::value_type;
|
||||
|
||||
#ifdef _WIN32
|
||||
static constexpr value_type preferred_separator = L'\\';
|
||||
#else
|
||||
static constexpr value_type preferred_separator = '/';
|
||||
#endif
|
||||
|
||||
enum format
|
||||
{
|
||||
native_format,
|
||||
generic_format,
|
||||
auto_format
|
||||
};
|
||||
|
||||
path() noexcept
|
||||
{
|
||||
}
|
||||
path(const path&) = default;
|
||||
path(path&& p) noexcept :
|
||||
m_path(std::move(p.m_path)),
|
||||
m_fmt(p.m_fmt)
|
||||
{
|
||||
}
|
||||
path(string_type&& p, format fmt = auto_format) :
|
||||
m_path(std::move(p)),
|
||||
m_fmt(fmt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
fixup_separators();
|
||||
#endif
|
||||
}
|
||||
template<typename T> path(const T& p, format fmt = auto_format ) :
|
||||
m_path(encconv(p)),
|
||||
m_fmt(fmt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
fixup_separators();
|
||||
#endif
|
||||
}
|
||||
~path() = default;
|
||||
path& operator=(const path& p) = default;
|
||||
path& operator=(path&&) = default;
|
||||
|
||||
template<typename T> path& append(const T& p)
|
||||
{
|
||||
if (empty())
|
||||
m_path = p;
|
||||
else
|
||||
m_path.append(1, preferred_separator).append(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> path& operator/=(const T& p)
|
||||
{
|
||||
return append(p);
|
||||
}
|
||||
|
||||
template<typename T> path& concat(const T& p)
|
||||
{
|
||||
m_path += p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T> path& operator+=(const T& p)
|
||||
{
|
||||
return concat(p);
|
||||
}
|
||||
|
||||
bool operator==(const path& other) const noexcept
|
||||
{
|
||||
return m_path == other.m_path && m_fmt == other.m_fmt;
|
||||
}
|
||||
|
||||
bool operator!=(const path& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool operator<(const path& other) const noexcept
|
||||
{
|
||||
return m_path < other.m_path;
|
||||
}
|
||||
|
||||
bool operator>(const path& other) const noexcept
|
||||
{
|
||||
return m_path > other.m_path;
|
||||
}
|
||||
|
||||
bool operator<=(const path& other) const noexcept
|
||||
{
|
||||
return m_path <= other.m_path;
|
||||
}
|
||||
|
||||
bool operator>=(const path& other) const noexcept
|
||||
{
|
||||
return m_path >= other.m_path;
|
||||
}
|
||||
|
||||
std::string string() const noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return WideToCurrentCP(m_path);
|
||||
#else
|
||||
return m_path;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::wstring wstring() const noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return m_path;
|
||||
#else
|
||||
return L""; // FIXME
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string u8string() const noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return WideToUTF8(m_path);
|
||||
#else
|
||||
return m_path; // FIXME
|
||||
#endif
|
||||
}
|
||||
|
||||
const value_type* c_str() const noexcept
|
||||
{
|
||||
return m_path.c_str();
|
||||
}
|
||||
|
||||
const string_type& native() const noexcept
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
operator string_type() const noexcept
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return m_path.empty();
|
||||
}
|
||||
|
||||
path filename() const;
|
||||
path stem() const;
|
||||
path extension() const;
|
||||
path parent_path() const;
|
||||
|
||||
path& replace_extension(const path& replacement = path());
|
||||
|
||||
bool is_relative() const
|
||||
{
|
||||
return !is_absolute();
|
||||
}
|
||||
bool is_absolute() const;
|
||||
|
||||
private:
|
||||
inline string_type encconv(const std::string& p) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return CurrentCPToWide(p);
|
||||
#else
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
inline string_type encconv(const std::wstring& p) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return p;
|
||||
#else
|
||||
(void)p;
|
||||
return ""; // FIXME
|
||||
#endif
|
||||
}
|
||||
#ifdef _WIN32
|
||||
void fixup_separators();
|
||||
#endif
|
||||
|
||||
string_type m_path;
|
||||
format m_fmt { auto_format };
|
||||
|
||||
template<class CharT, class Traits>
|
||||
friend std::basic_ostream<CharT,Traits>&
|
||||
operator<<(std::basic_ostream<CharT,Traits>& os, const path& p);
|
||||
}; // path
|
||||
|
||||
path operator/(const path& lhs, const path& rhs);
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT,Traits>&
|
||||
operator<<(std::basic_ostream<CharT,Traits>& os, const path& p)
|
||||
{
|
||||
os << std::quoted(p.string());
|
||||
return os;
|
||||
}
|
||||
|
||||
path u8path(const std::string& source);
|
||||
|
||||
enum class directory_options : unsigned char {
|
||||
none = 0,
|
||||
follow_directory_symlink = 1, // Not implemented
|
||||
skip_permission_denied = 2
|
||||
};
|
||||
|
||||
inline constexpr directory_options operator&(directory_options _LHS,
|
||||
directory_options _RHS) {
|
||||
return static_cast<directory_options>(static_cast<unsigned char>(_LHS) &
|
||||
static_cast<unsigned char>(_RHS));
|
||||
}
|
||||
|
||||
inline constexpr directory_options operator|(directory_options _LHS,
|
||||
directory_options _RHS) {
|
||||
return static_cast<directory_options>(static_cast<unsigned char>(_LHS) |
|
||||
static_cast<unsigned char>(_RHS));
|
||||
}
|
||||
|
||||
inline constexpr directory_options operator^(directory_options _LHS,
|
||||
directory_options _RHS) {
|
||||
return static_cast<directory_options>(static_cast<unsigned char>(_LHS) ^
|
||||
static_cast<unsigned char>(_RHS));
|
||||
}
|
||||
|
||||
inline constexpr directory_options operator~(directory_options _LHS) {
|
||||
return static_cast<directory_options>(~static_cast<unsigned char>(_LHS));
|
||||
}
|
||||
|
||||
inline directory_options& operator&=(directory_options& _LHS,
|
||||
directory_options _RHS) {
|
||||
return _LHS = _LHS & _RHS;
|
||||
}
|
||||
|
||||
inline directory_options& operator|=(directory_options& _LHS,
|
||||
directory_options _RHS) {
|
||||
return _LHS = _LHS | _RHS;
|
||||
}
|
||||
|
||||
inline directory_options& operator^=(directory_options& _LHS,
|
||||
directory_options _RHS) {
|
||||
return _LHS = _LHS ^ _RHS;
|
||||
}
|
||||
|
||||
class directory_iterator;
|
||||
class recursive_directory_iterator;
|
||||
class directory_entry
|
||||
{
|
||||
public:
|
||||
directory_entry() = default;
|
||||
directory_entry(const directory_entry&) = default;
|
||||
directory_entry(directory_entry&&) = default;
|
||||
explicit directory_entry(const path& p) :
|
||||
m_path(p)
|
||||
{
|
||||
};
|
||||
directory_entry& operator=(const directory_entry&) = default;
|
||||
directory_entry& operator=(directory_entry&&) = default;
|
||||
|
||||
const class path& path() const noexcept
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
operator const class path& () const noexcept
|
||||
{
|
||||
return m_path;
|
||||
};
|
||||
|
||||
bool operator==(const directory_entry& other) const noexcept
|
||||
{
|
||||
return m_path == other.m_path;
|
||||
}
|
||||
bool operator!=(const directory_entry& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class directory_iterator;
|
||||
friend class recursive_directory_iterator;
|
||||
|
||||
class path m_path;
|
||||
}; // directory_entry
|
||||
|
||||
|
||||
class directory_iterator
|
||||
{
|
||||
public:
|
||||
using value_type = directory_entry;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const directory_entry*;
|
||||
using reference = const directory_entry&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
directory_iterator() = default;
|
||||
explicit directory_iterator(const path& p);
|
||||
directory_iterator(const path& p, directory_options options);
|
||||
directory_iterator(const path& p, std::error_code& ec);
|
||||
directory_iterator(const path& p, directory_options options, std::error_code& ec);
|
||||
|
||||
directory_iterator(const directory_iterator&) = default;
|
||||
directory_iterator(directory_iterator&&) = default;
|
||||
~directory_iterator() = default;
|
||||
|
||||
directory_iterator& operator=(const directory_iterator&) = default;
|
||||
directory_iterator& operator=(directory_iterator&&) = default;
|
||||
|
||||
directory_iterator& operator++();
|
||||
directory_iterator& increment(std::error_code&);
|
||||
|
||||
const directory_entry& operator*() const noexcept
|
||||
{
|
||||
return m_entry;
|
||||
}
|
||||
|
||||
const directory_entry* operator->() const noexcept
|
||||
{
|
||||
return &m_entry;
|
||||
}
|
||||
|
||||
bool operator==(const directory_iterator& other) const noexcept;
|
||||
bool operator!=(const directory_iterator& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class recursive_directory_iterator;
|
||||
|
||||
directory_iterator(const path& p, directory_options options, std::error_code* ec, bool advance = true);
|
||||
|
||||
directory_iterator& __increment(std::error_code* ec = nullptr);
|
||||
|
||||
struct SearchImpl;
|
||||
void reset();
|
||||
|
||||
path m_path {};
|
||||
directory_entry m_entry {};
|
||||
std::shared_ptr<SearchImpl> m_search { nullptr };
|
||||
}; // directory_iterator
|
||||
|
||||
inline directory_iterator begin(directory_iterator iter) noexcept
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
|
||||
inline directory_iterator end(directory_iterator) noexcept
|
||||
{
|
||||
return directory_iterator();
|
||||
}
|
||||
|
||||
|
||||
class recursive_directory_iterator
|
||||
{
|
||||
public:
|
||||
using value_type = directory_entry;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const directory_entry*;
|
||||
using reference = const directory_entry&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
recursive_directory_iterator() = default;
|
||||
recursive_directory_iterator(const recursive_directory_iterator&) = default;
|
||||
recursive_directory_iterator(recursive_directory_iterator&&) noexcept = default;
|
||||
explicit recursive_directory_iterator(const path& p);
|
||||
recursive_directory_iterator(const path& p, directory_options options);
|
||||
recursive_directory_iterator(const path& p, std::error_code& ec);
|
||||
recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec);
|
||||
~recursive_directory_iterator() = default;
|
||||
|
||||
recursive_directory_iterator& operator=(const recursive_directory_iterator&) = default;
|
||||
recursive_directory_iterator& operator=(recursive_directory_iterator&&) = default;
|
||||
|
||||
bool recursion_pending() const
|
||||
{
|
||||
return m_pending;
|
||||
};
|
||||
|
||||
void disable_recursion_pending()
|
||||
{
|
||||
m_pending = false;
|
||||
};
|
||||
|
||||
void pop();
|
||||
void pop(std::error_code& ec);
|
||||
|
||||
recursive_directory_iterator& operator++();
|
||||
recursive_directory_iterator& increment(std::error_code&);
|
||||
|
||||
const directory_entry& operator*() const noexcept
|
||||
{
|
||||
return *m_iter;
|
||||
}
|
||||
|
||||
const directory_entry* operator->() const noexcept
|
||||
{
|
||||
return &*m_iter;
|
||||
}
|
||||
|
||||
bool operator==(const recursive_directory_iterator& other) const noexcept;
|
||||
bool operator!=(const recursive_directory_iterator& other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
recursive_directory_iterator(const path& p, directory_options options, std::error_code* ec);
|
||||
|
||||
recursive_directory_iterator& __increment(std::error_code* ec = nullptr);
|
||||
|
||||
void reset();
|
||||
|
||||
directory_options m_options { directory_options::none };
|
||||
std::error_code m_ec {};
|
||||
int m_depth { 0 };
|
||||
bool m_pending { true };
|
||||
|
||||
struct DirStack;
|
||||
std::shared_ptr<DirStack> m_dirs { nullptr };
|
||||
directory_iterator m_iter {};
|
||||
}; // recursive_directory_iterator
|
||||
|
||||
inline recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
|
||||
inline recursive_directory_iterator end(recursive_directory_iterator) noexcept
|
||||
{
|
||||
return recursive_directory_iterator();
|
||||
}
|
||||
|
||||
|
||||
uintmax_t file_size(const path& p, std::error_code& ec) noexcept;
|
||||
uintmax_t file_size(const path& p);
|
||||
|
||||
bool exists(const path& p);
|
||||
bool exists(const path& p, std::error_code& ec) noexcept;
|
||||
|
||||
bool is_directory(const path& p);
|
||||
bool is_directory(const path& p, std::error_code& ec) noexcept;
|
||||
|
||||
bool create_directory(const path& p);
|
||||
bool create_directory(const path& p, std::error_code& ec) noexcept;
|
||||
|
||||
path current_path();
|
||||
path current_path(std::error_code& ec);
|
||||
void current_path(const path& p);
|
||||
void current_path(const path& p, std::error_code& ec) noexcept;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#include <iostream>
|
||||
#include "fs.h"
|
||||
namespace fs = celestia::filesystem;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << fs::path("/foo/bar.txt").extension() << '\n'
|
||||
<< fs::path("/foo/bar.").extension() << '\n'
|
||||
<< fs::path("/foo/bar").extension() << '\n'
|
||||
<< fs::path("/foo/bar.txt/bar.cc").extension() << '\n'
|
||||
<< fs::path("/foo/bar.txt/bar.").extension() << '\n'
|
||||
<< fs::path("/foo/bar.txt/bar").extension() << '\n'
|
||||
<< fs::path("/foo/.").extension() << '\n'
|
||||
<< fs::path("/foo/..").extension() << '\n'
|
||||
<< fs::path("/foo/.hidden").extension() << '\n'
|
||||
<< fs::path("/foo/..bar").extension() << '\n';
|
||||
|
||||
std::cout << "----------\n";
|
||||
std::cout << fs::path("/foo/bar.txt").stem() << '\n'
|
||||
<< fs::path("/foo/.bar").stem() << '\n';
|
||||
|
||||
for (fs::path p = "foo.bar.baz.tar"; !p.extension().empty(); p = p.stem())
|
||||
std::cout << p.extension() << '\n';
|
||||
|
||||
std::cout << "----------\n";
|
||||
std::cout << fs::path("/foo/bar.txt") << '\n';
|
||||
std::cout << fs::path("baz/foo/bar.txt") << '\n';
|
||||
std::cout << fs::path("c:\\foo\\bar.txt") << '\n';
|
||||
std::cout << fs::path(L"c:\\foo\\bar.txt") << '\n';
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
test_case(charconv_compat)
|
||||
test_case(hash)
|
||||
if ((NOT HAVE_EXPERIMENTAL_FILESYSTEM) AND (NOT HAVE_FILESYSTEM))
|
||||
test_case(fs)
|
||||
endif()
|
||||
test_case(logger)
|
||||
test_case(stellarclass)
|
||||
test_case(tokenizer)
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
#if 1
|
||||
#include <celcompat/fs.h>
|
||||
namespace fs = celestia::filesystem;
|
||||
#else
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("filesystem", "[filesystem]")
|
||||
{
|
||||
SECTION("fs::path::extension()")
|
||||
{
|
||||
REQUIRE(fs::path("/foo/bar.txt").extension() == ".txt");
|
||||
REQUIRE(fs::path("/foo/bar.").extension() == ".");
|
||||
REQUIRE(fs::path("/foo/bar").extension().empty() == true);
|
||||
REQUIRE(fs::path("/foo/bar.txt/bar.cc").extension() == ".cc");
|
||||
REQUIRE(fs::path("/foo/bar.txt/bar.").extension() == ".");
|
||||
REQUIRE(fs::path("/foo/bar.txt/bar").extension().empty() == true);
|
||||
REQUIRE(fs::path("/foo/.").extension().empty() == true);
|
||||
REQUIRE(fs::path("/foo/..").extension().empty() == true);
|
||||
REQUIRE(fs::path("/foo/.hidden").extension().empty() == true);
|
||||
REQUIRE(fs::path("/foo/..bar").extension() == ".bar");
|
||||
REQUIRE(fs::path("/foo/bar.txt").stem() == "bar");
|
||||
REQUIRE(fs::path("/foo/.bar").stem() == ".bar");
|
||||
}
|
||||
|
||||
SECTION("fs::path::stem()")
|
||||
{
|
||||
fs::path p = "foo.bar.baz.tar";
|
||||
REQUIRE(p.extension() == ".tar");
|
||||
p = p.stem();
|
||||
REQUIRE(p.extension() == ".baz");
|
||||
REQUIRE(p == "foo.bar.baz");
|
||||
p = p.stem();
|
||||
REQUIRE(p.extension() == ".bar");
|
||||
REQUIRE(p == "foo.bar");
|
||||
p = p.stem();
|
||||
REQUIRE(p.extension().empty() == true);
|
||||
REQUIRE(p == "foo");
|
||||
}
|
||||
|
||||
SECTION("path separators")
|
||||
{
|
||||
REQUIRE(fs::path("/foo/bar.txt") == "/foo/bar.txt");
|
||||
REQUIRE(fs::path("baz/foo/bar.txt") == "baz/foo/bar.txt");
|
||||
// These two fail on Unix/GCC both with C++11 fs and our own.
|
||||
// But they are successful with MinGW.
|
||||
#ifdef _WIN32
|
||||
REQUIRE(fs::path("c:\\foo\\bar.txt") == "c:/foo/bar.txt");
|
||||
REQUIRE(fs::path(L"c:\\foo\\bar.txt") == "c:/foo/bar.txt");
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("fs::path::replace_extension()")
|
||||
{
|
||||
REQUIRE(fs::path("/foo/bar.jpg").replace_extension(".png") == "/foo/bar.png");
|
||||
REQUIRE(fs::path("/foo/bar.jpg").replace_extension("png") == "/foo/bar.png");
|
||||
REQUIRE(fs::path("/foo/bar.jpg").replace_extension(".") == "/foo/bar.");
|
||||
REQUIRE(fs::path("/foo/bar.jpg").replace_extension("") == "/foo/bar");
|
||||
|
||||
REQUIRE(fs::path("/foo/bar.").replace_extension("png") == "/foo/bar.png");
|
||||
|
||||
REQUIRE(fs::path("/foo/bar").replace_extension(".png") == "/foo/bar.png");
|
||||
REQUIRE(fs::path("/foo/bar").replace_extension("png") == "/foo/bar.png");
|
||||
REQUIRE(fs::path("/foo/bar").replace_extension(".") == "/foo/bar.");
|
||||
REQUIRE(fs::path("/foo/bar").replace_extension("") == "/foo/bar");
|
||||
|
||||
REQUIRE(fs::path("/foo/.").replace_extension(".png") == "/foo/..png");
|
||||
REQUIRE(fs::path("/foo/.").replace_extension("png") == "/foo/..png");
|
||||
REQUIRE(fs::path("/foo/.").replace_extension(".") == "/foo/..");
|
||||
REQUIRE(fs::path("/foo/.").replace_extension("") == "/foo/.");
|
||||
|
||||
REQUIRE(fs::path("/foo/").replace_extension(".png") == "/foo/.png");
|
||||
REQUIRE(fs::path("/foo/").replace_extension("png") == "/foo/.png");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue