move cxx stuff into cxx directory
This commit is contained in:
parent
9316311a1d
commit
446e3e5e1e
|
@ -114,8 +114,13 @@ add_custom_command(
|
||||||
# mpw-shell-execute.cpp mpw-shell-builtins.cpp mpw-shell-read.cpp
|
# mpw-shell-execute.cpp mpw-shell-builtins.cpp mpw-shell-read.cpp
|
||||||
add_executable(mpw-shell mpw-shell.cpp mpw-shell-token.cpp mpw-shell-expand.cpp
|
add_executable(mpw-shell mpw-shell.cpp mpw-shell-token.cpp mpw-shell-expand.cpp
|
||||||
mpw-shell-parser.cpp value.cpp mpw-shell-quote.cpp
|
mpw-shell-parser.cpp value.cpp mpw-shell-quote.cpp
|
||||||
phase1.cpp phase2.cpp phase2-parser.cpp command.cpp environment.cpp builtins.cpp mapped_file.cpp
|
phase1.cpp phase2.cpp phase2-parser.cpp command.cpp environment.cpp builtins.cpp
|
||||||
pathnames.cpp)
|
pathnames.cpp
|
||||||
|
cxx/mapped_file.cpp
|
||||||
|
cxx/filesystem.cpp
|
||||||
|
cxx/path.cpp
|
||||||
|
cxx/directory_iterator.cpp
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(mpw-shell edit)
|
target_link_libraries(mpw-shell edit)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
#include "filesystem.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
|
||||||
|
namespace filesystem {
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - directory_entry
|
||||||
|
|
||||||
|
directory_entry::directory_entry(const class path& p, file_status st, file_status symlink_st) :
|
||||||
|
_path(p), _st(st), _lst(symlink_st)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void directory_entry::assign(const class path& p, file_status st, file_status symlink_st)
|
||||||
|
{
|
||||||
|
_path = p;
|
||||||
|
_st = st;
|
||||||
|
_lst = symlink_st;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void directory_entry::replace_filename(const path& p, file_status st, file_status symlink_st)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
file_status directory_entry::status() const {
|
||||||
|
|
||||||
|
if (!status_known(_st))
|
||||||
|
{
|
||||||
|
if (status_known(_lst) && ! is_symlink(_lst)) {
|
||||||
|
_st = _lst;
|
||||||
|
} else {
|
||||||
|
_st = filesystem::status(_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _st;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status directory_entry::status(error_code& ec) const noexcept {
|
||||||
|
|
||||||
|
if (!status_known(_st))
|
||||||
|
{
|
||||||
|
if (status_known(_lst) && ! is_symlink(_lst)) {
|
||||||
|
_st = _lst;
|
||||||
|
} else {
|
||||||
|
_st = filesystem::status(_path, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _st;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status directory_entry::symlink_status() const {
|
||||||
|
|
||||||
|
if (!status_known(_lst))
|
||||||
|
_lst = filesystem::symlink_status(_path);
|
||||||
|
|
||||||
|
return _lst;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status directory_entry::symlink_status(error_code& ec) const noexcept {
|
||||||
|
|
||||||
|
ec.clear();
|
||||||
|
|
||||||
|
if (!status_known(_lst))
|
||||||
|
_lst = filesystem::symlink_status(_path, ec);
|
||||||
|
|
||||||
|
return _lst;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool directory_entry::operator< (const directory_entry& rhs) const noexcept {
|
||||||
|
return _path < rhs._path;
|
||||||
|
}
|
||||||
|
bool directory_entry::operator==(const directory_entry& rhs) const noexcept {
|
||||||
|
return _path == rhs._path;
|
||||||
|
}
|
||||||
|
bool directory_entry::operator!=(const directory_entry& rhs) const noexcept {
|
||||||
|
return _path != rhs._path;
|
||||||
|
}
|
||||||
|
bool directory_entry::operator<=(const directory_entry& rhs) const noexcept {
|
||||||
|
return _path <= rhs._path;
|
||||||
|
}
|
||||||
|
bool directory_entry::operator> (const directory_entry& rhs) const noexcept {
|
||||||
|
return _path > rhs._path;
|
||||||
|
}
|
||||||
|
bool directory_entry::operator>=(const directory_entry& rhs) const noexcept {
|
||||||
|
return _path >= rhs._path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - directory_iterator
|
||||||
|
|
||||||
|
directory_iterator::directory_iterator(const path& p) {
|
||||||
|
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
open_dir(p, ec);
|
||||||
|
if (ec) throw filesystem_error("directory_iterator::directory_iterator", p, ec);
|
||||||
|
|
||||||
|
increment(ec);
|
||||||
|
if (ec) throw filesystem_error("directory_iterator::directory_iterator", p, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_iterator::directory_iterator(const path& p, error_code& ec) noexcept {
|
||||||
|
ec.clear();
|
||||||
|
|
||||||
|
open_dir(p, ec);
|
||||||
|
if (!ec) increment(ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void directory_iterator::open_dir(const path &p, error_code &ec) noexcept {
|
||||||
|
|
||||||
|
DIR *dp = opendir(p.c_str());
|
||||||
|
if (!dp)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, std::system_category());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_imp = std::make_shared<imp>(p, dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
directory_iterator& directory_iterator::operator++() {
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
increment(ec);
|
||||||
|
if (ec) throw filesystem_error("directory_iterator::operator++", ec);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_iterator& directory_iterator::increment(error_code& ec) noexcept {
|
||||||
|
|
||||||
|
ec.clear();
|
||||||
|
|
||||||
|
if (_imp) {
|
||||||
|
|
||||||
|
struct dirent entry;
|
||||||
|
struct dirent *result = nullptr;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
DIR *dp = _imp->_dp;
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
rv = readdir_r(dp, &entry, &result);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
ec = error_code(errno, std::system_category());
|
||||||
|
_imp.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
_imp.reset();
|
||||||
|
break; // end of directory.
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string s(entry.d_name);
|
||||||
|
if (s == ".") continue;
|
||||||
|
if (s == "..") continue;
|
||||||
|
|
||||||
|
|
||||||
|
path p = _imp->_path / s;
|
||||||
|
|
||||||
|
_imp->_entry.assign(p);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,289 @@
|
||||||
|
#include "filesystem.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
namespace filesystem {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
template<class FX, class... Args>
|
||||||
|
auto syscall(error_code &ec, FX fx, Args&&... args) -> decltype(fx(std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
auto rv = fx(std::forward<Args>(args)...);
|
||||||
|
if (rv < 0) {
|
||||||
|
ec = error_code(errno, std::system_category());
|
||||||
|
} else {
|
||||||
|
ec.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_stat(const path &p, struct stat *buf, error_code &ec) {
|
||||||
|
int rv = stat(p.c_str(), buf);
|
||||||
|
if (rv < 0) {
|
||||||
|
ec = error_code(errno, std::system_category());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ec.clear();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_lstat(const path &p, struct stat *buf, error_code &ec) {
|
||||||
|
int rv = lstat(p.c_str(), buf);
|
||||||
|
if (rv < 0) {
|
||||||
|
ec = error_code(errno, std::system_category());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ec.clear();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FX>
|
||||||
|
file_status status_common(FX fx, const path& p, error_code& ec) noexcept {
|
||||||
|
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
int rv = fx(p, &st, ec);
|
||||||
|
if (rv < 0)
|
||||||
|
{
|
||||||
|
switch (ec.value())
|
||||||
|
{
|
||||||
|
case ENOENT:
|
||||||
|
case ENOTDIR:
|
||||||
|
return file_status(file_type::not_found);
|
||||||
|
|
||||||
|
case EOVERFLOW:
|
||||||
|
return file_status(file_type::unknown);
|
||||||
|
|
||||||
|
//case ENAMETOOLONG: ???
|
||||||
|
// case ELOOP ?
|
||||||
|
|
||||||
|
default:
|
||||||
|
return file_status(file_type::none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ec.clear();
|
||||||
|
perms prms = static_cast<perms>(st.st_mode & perms::mask);
|
||||||
|
|
||||||
|
if (S_ISREG(st.st_mode))
|
||||||
|
return file_status(file_type::regular, prms);
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
return file_status(file_type::directory, prms);
|
||||||
|
|
||||||
|
if (S_ISBLK(st.st_mode))
|
||||||
|
return file_status(file_type::block, prms);
|
||||||
|
|
||||||
|
if (S_ISFIFO(st.st_mode))
|
||||||
|
return file_status(file_type::fifo, prms);
|
||||||
|
|
||||||
|
if (S_ISSOCK(st.st_mode))
|
||||||
|
return file_status(file_type::socket, prms);
|
||||||
|
|
||||||
|
return file_status(file_type::unknown, prms);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status status(const path& p) {
|
||||||
|
error_code ec;
|
||||||
|
file_status result = status(p, ec);
|
||||||
|
if (result.type() == file_type::none)
|
||||||
|
throw filesystem_error("filesystem::file_status", p, ec);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status status(const path& p, error_code& ec) noexcept {
|
||||||
|
|
||||||
|
return status_common(fs_stat, p, ec);
|
||||||
|
/*
|
||||||
|
struct stat st;
|
||||||
|
int rv = stat(p.c_str(), &st);
|
||||||
|
if (rv < 0) {
|
||||||
|
int e = errno;
|
||||||
|
ec = error_code(e, std::system_category());
|
||||||
|
|
||||||
|
switch(e){
|
||||||
|
case ENOENT:
|
||||||
|
case ENOTDIR:
|
||||||
|
return file_status(file_type::not_found);
|
||||||
|
|
||||||
|
case EOVERFLOW:
|
||||||
|
return file_status(file_type::unknown);
|
||||||
|
|
||||||
|
//case ENAMETOOLONG: ???
|
||||||
|
// case ELOOP ?
|
||||||
|
|
||||||
|
default:
|
||||||
|
return file_status(file_type::none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ec.clear();
|
||||||
|
perms prms = static_cast<perms>(st.st_mode & perms::mask);
|
||||||
|
|
||||||
|
if (S_ISREG(st.st_mode))
|
||||||
|
return file_status(file_type::regular, prms);
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
return file_status(file_type::directory, prms);
|
||||||
|
|
||||||
|
if (S_ISBLK(st.st_mode))
|
||||||
|
return file_status(file_type::block, prms);
|
||||||
|
|
||||||
|
if (S_ISFIFO(st.st_mode))
|
||||||
|
return file_status(file_type::fifo, prms);
|
||||||
|
|
||||||
|
if (S_ISSOCK(st.st_mode))
|
||||||
|
return file_status(file_type::socket, prms);
|
||||||
|
|
||||||
|
return file_status(file_type::unknown, prms);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status symlink_status(const path& p) {
|
||||||
|
error_code ec;
|
||||||
|
file_status result = symlink_status(p, ec);
|
||||||
|
if (result.type() == file_type::none)
|
||||||
|
throw filesystem_error("filesystem::symlink_status", p, ec);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status symlink_status(const path& p, error_code& ec) noexcept {
|
||||||
|
|
||||||
|
return status_common(fs_lstat, p, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uintmax_t file_size(const path& p) {
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
//if (fs_stat(p, &st, ec) < 0)
|
||||||
|
if (syscall(ec, ::stat, p.c_str(), &st) < 0)
|
||||||
|
throw filesystem_error("filesystem::file_size", p, ec);
|
||||||
|
|
||||||
|
return st.st_size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uintmax_t file_size(const path& p, error_code& ec) noexcept {
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
//if (fs_stat(p, &st, ec) < 0)
|
||||||
|
if (syscall(ec, ::stat, p.c_str(), &st) < 0)
|
||||||
|
return static_cast<uintmax_t>(-1);
|
||||||
|
|
||||||
|
return st.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool create_directory(const path& p) {
|
||||||
|
error_code ec;
|
||||||
|
bool rv = create_directory(p, ec);
|
||||||
|
if (ec)
|
||||||
|
throw filesystem_error("filesystem::create_directory", p, ec);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_directory(const path& p, error_code& ec) noexcept {
|
||||||
|
|
||||||
|
int rv = ::mkdir(p.c_str(), S_IRWXU|S_IRWXG|S_IRWXO);
|
||||||
|
if (rv == 0) {
|
||||||
|
ec.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int e = errno;
|
||||||
|
error_code tmp;
|
||||||
|
|
||||||
|
// special case -- not an error if the directory already exists.
|
||||||
|
|
||||||
|
if (e == EEXIST && is_directory(p, tmp)) {
|
||||||
|
ec.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec = error_code(e, std::system_category());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize_file(const path& p, uintmax_t new_size) {
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
if (syscall(ec, ::truncate, p.c_str(), new_size) < 0)
|
||||||
|
throw filesystem_error("filesystem::create_directory", p, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize_file(const path& p, uintmax_t new_size, error_code& ec) noexcept {
|
||||||
|
|
||||||
|
syscall(ec, ::truncate, p.c_str(), new_size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(const path& p) {
|
||||||
|
error_code ec;
|
||||||
|
|
||||||
|
if (syscall(ec, ::remove, p.c_str()) < 0)
|
||||||
|
{
|
||||||
|
throw filesystem_error("filesystem::remove", p, ec);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(const path& p, error_code& ec) noexcept {
|
||||||
|
if (syscall(ec, ::remove, p.c_str()) < 0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
path current_path() {
|
||||||
|
error_code ec;
|
||||||
|
path p = current_path(ec);
|
||||||
|
|
||||||
|
if (ec)
|
||||||
|
throw filesystem_error("filesystem::current_path", ec);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
path current_path(error_code& ec) {
|
||||||
|
|
||||||
|
char *cp;
|
||||||
|
char buffer[PATH_MAX];
|
||||||
|
|
||||||
|
ec.clear();
|
||||||
|
cp = ::getcwd(buffer, sizeof(buffer));
|
||||||
|
if (cp) return path(cp);
|
||||||
|
|
||||||
|
ec = error_code(errno, std::system_category());
|
||||||
|
return path();
|
||||||
|
}
|
||||||
|
|
||||||
|
void current_path(const path& p) {
|
||||||
|
error_code ec;
|
||||||
|
syscall(ec, ::chdir, p.c_str());
|
||||||
|
if (ec)
|
||||||
|
throw filesystem_error("filesystem::current_path", p, ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void current_path(const path& p, error_code& ec) noexcept {
|
||||||
|
|
||||||
|
syscall(ec, ::chdir, p.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,848 @@
|
||||||
|
#ifndef __filesystem_h__
|
||||||
|
#define __filesystem_h__
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <locale>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <system_error>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* light-weight implementation of n3803
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace filesystem {
|
||||||
|
|
||||||
|
class path;
|
||||||
|
class filesystem_error;
|
||||||
|
|
||||||
|
using std::error_code;
|
||||||
|
using std::system_error;
|
||||||
|
|
||||||
|
class path {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef char value_type;
|
||||||
|
typedef std::basic_string<value_type> string_type;
|
||||||
|
static constexpr value_type preferred_separator = '/';
|
||||||
|
|
||||||
|
|
||||||
|
// constructors and destructor
|
||||||
|
path() = default;
|
||||||
|
path(const path& p) = default;
|
||||||
|
path(path&& p) noexcept :
|
||||||
|
_path(std::move(p._path)) {
|
||||||
|
p.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Source>
|
||||||
|
path(Source const& source) :
|
||||||
|
_path(source) {}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
path(InputIterator begin, InputIterator end) :
|
||||||
|
_path(begin, end) {}
|
||||||
|
|
||||||
|
template <class Source>
|
||||||
|
path(Source const& source, const std::locale& loc);
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
path(InputIterator begin, InputIterator end, const std::locale& loc);
|
||||||
|
|
||||||
|
~path() = default;
|
||||||
|
|
||||||
|
// assignments
|
||||||
|
path& operator=(const path& p) {
|
||||||
|
if (this != &p) {
|
||||||
|
_path = p._path;
|
||||||
|
_info = p._info;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
path& operator=(path&& p) noexcept {
|
||||||
|
if (this != &p) {
|
||||||
|
_path = std::move(p._path);
|
||||||
|
_info = p._info;
|
||||||
|
p.invalidate();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Source>
|
||||||
|
path& operator=(Source const& source) {
|
||||||
|
invalidate();
|
||||||
|
_path = source;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
path& assign(const path &p) {
|
||||||
|
return (*this = p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Source>
|
||||||
|
path& assign(Source const& source) {
|
||||||
|
invalidate();
|
||||||
|
_path.assign(source);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
path& assign(InputIterator begin, InputIterator end) {
|
||||||
|
invalidate();
|
||||||
|
_path.assign(begin, end);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// appends
|
||||||
|
path& operator/=(const path& p) {
|
||||||
|
return append(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <class Source>
|
||||||
|
path& operator/=(Source const& source) {
|
||||||
|
return append(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// consider this a specialization of append.
|
||||||
|
path& append(const path &p);
|
||||||
|
|
||||||
|
path& append(const string_type &s);
|
||||||
|
|
||||||
|
|
||||||
|
template <class Source>
|
||||||
|
path& append(Source const& source) {
|
||||||
|
return append(path(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
path& append(InputIterator begin, InputIterator end) {
|
||||||
|
return append(path(begin, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// concatenation
|
||||||
|
path& operator+=(const path& x) {
|
||||||
|
invalidate();
|
||||||
|
_path += x._path;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
path& operator+=(const string_type& x) {
|
||||||
|
invalidate();
|
||||||
|
_path += x;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
path& operator+=(const value_type* x) {
|
||||||
|
invalidate();
|
||||||
|
_path += x;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
path& operator+=(value_type x) {
|
||||||
|
invalidate();
|
||||||
|
_path += x;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Source>
|
||||||
|
path& operator+=(Source const& x) {
|
||||||
|
invalidate();
|
||||||
|
_path += x;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class charT>
|
||||||
|
path& operator+=(charT x){
|
||||||
|
invalidate();
|
||||||
|
_path += x;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Source>
|
||||||
|
path& concat(Source const& x) {
|
||||||
|
invalidate();
|
||||||
|
_path += x;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
path& concat(InputIterator begin, InputIterator end) {
|
||||||
|
invalidate();
|
||||||
|
_path.append(begin, end);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// modifiers
|
||||||
|
void clear() noexcept {
|
||||||
|
invalidate();
|
||||||
|
_path.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
path& make_preferred() {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
path& remove_filename();
|
||||||
|
path& replace_filename(const path& replacement);
|
||||||
|
path& replace_extension(const path& replacement = path());
|
||||||
|
|
||||||
|
void swap(path& rhs) noexcept {
|
||||||
|
std::swap(_path, rhs._path);
|
||||||
|
std::swap(_info, rhs._info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// native format observers
|
||||||
|
const string_type& native() const noexcept {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_type* c_str() const noexcept {
|
||||||
|
return _path.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator string_type() const {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class charT, class traits = std::char_traits<charT>,
|
||||||
|
class Allocator = std::allocator<charT> >
|
||||||
|
std::basic_string<charT, traits, Allocator> string(const Allocator& a = Allocator()) const;
|
||||||
|
|
||||||
|
std::string string() const {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring wstring() const;
|
||||||
|
std::string u8string() const;
|
||||||
|
std::u16string u16string() const;
|
||||||
|
std::u32string u32string() const;
|
||||||
|
|
||||||
|
// generic format observers
|
||||||
|
template <class charT, class traits = std::char_traits<charT>,
|
||||||
|
class Allocator = std::allocator<charT> >
|
||||||
|
std::basic_string<charT, traits, Allocator>
|
||||||
|
generic_string(const Allocator& a = Allocator()) const;
|
||||||
|
std::string generic_string() const {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
std::wstring generic_wstring() const;
|
||||||
|
std::string generic_u8string() const;
|
||||||
|
std::u16string generic_u16string() const;
|
||||||
|
std::u32string generic_u32string() const;
|
||||||
|
|
||||||
|
// compare
|
||||||
|
int compare(const path& p) const noexcept;
|
||||||
|
int compare(const std::string& s) const;
|
||||||
|
int compare(const value_type* s) const;
|
||||||
|
|
||||||
|
// decomposition
|
||||||
|
path root_name() const;
|
||||||
|
path root_directory() const;
|
||||||
|
path root_path() const;
|
||||||
|
path relative_path() const;
|
||||||
|
path parent_path() const;
|
||||||
|
path filename() const;
|
||||||
|
path stem() const;
|
||||||
|
path extension() const;
|
||||||
|
|
||||||
|
// query
|
||||||
|
bool empty() const noexcept {
|
||||||
|
return _path.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_root_name() const;
|
||||||
|
bool has_root_directory() const;
|
||||||
|
bool has_root_path() const;
|
||||||
|
bool has_relative_path() const;
|
||||||
|
bool has_parent_path() const;
|
||||||
|
bool has_filename() const;
|
||||||
|
bool has_stem() const;
|
||||||
|
bool has_extension() const;
|
||||||
|
|
||||||
|
bool is_absolute() const {
|
||||||
|
return !empty() && _path[0] == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_relative() const {
|
||||||
|
return empty() || _path[0] != '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterators
|
||||||
|
class iterator;
|
||||||
|
typedef iterator const_iterator;
|
||||||
|
iterator begin() const;
|
||||||
|
iterator end() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void invalidate() const {
|
||||||
|
_info.valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void study() const;
|
||||||
|
path &append_common(const std::string &s);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string_type _path;
|
||||||
|
|
||||||
|
mutable struct {
|
||||||
|
bool valid = false;
|
||||||
|
value_type special;
|
||||||
|
int stem;
|
||||||
|
int extension;
|
||||||
|
} _info;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline void swap(path& lhs, path& rhs) noexcept {
|
||||||
|
lhs.swap(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// ugh, this is boost, not stl.
|
||||||
|
inline std::size_t hash_value(const path& p) noexcept {
|
||||||
|
return std::hash_value(p._path);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
inline bool operator==(const path& lhs, const path& rhs) noexcept {
|
||||||
|
return lhs.compare(rhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const path& lhs, const path& rhs) noexcept {
|
||||||
|
return lhs.compare(rhs) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator< (const path& lhs, const path& rhs) noexcept {
|
||||||
|
return lhs.compare(rhs) < 0;
|
||||||
|
}
|
||||||
|
inline bool operator<=(const path& lhs, const path& rhs) noexcept {
|
||||||
|
return lhs.compare(rhs) <= 0;
|
||||||
|
}
|
||||||
|
inline bool operator> (const path& lhs, const path& rhs) noexcept {
|
||||||
|
return lhs.compare(rhs) > 0;
|
||||||
|
}
|
||||||
|
inline bool operator>=(const path& lhs, const path& rhs) noexcept {
|
||||||
|
return lhs.compare(rhs) >= 0;
|
||||||
|
}
|
||||||
|
inline path operator/ (const path& lhs, const path& rhs) {
|
||||||
|
path tmp = lhs;
|
||||||
|
return tmp.append(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
//template <class charT, class traits>
|
||||||
|
//basic_ostream<charT, traits>&
|
||||||
|
//operator<<(basic_ostream<charT, traits>& os, const path& p);
|
||||||
|
//template <class charT, class traits>
|
||||||
|
//basic_istream<charT, traits>&
|
||||||
|
///operator>>(basic_istream<charT, traits>& is, path& p);
|
||||||
|
template <class Source>
|
||||||
|
path u8path(Source const& source);
|
||||||
|
template <class InputIterator>
|
||||||
|
path u8path(InputIterator begin, InputIterator end);
|
||||||
|
|
||||||
|
|
||||||
|
class filesystem_error : public system_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
filesystem_error(const std::string& what_arg, error_code ec) :
|
||||||
|
system_error(ec, what_arg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
filesystem_error(const std::string& what_arg, const path& p1, error_code ec) :
|
||||||
|
system_error(ec, what_arg), _p1(p1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
filesystem_error(const std::string& what_arg, const path& p1, const path& p2, error_code ec) :
|
||||||
|
system_error(ec, what_arg), _p1(p1), _p2(p2)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const path& path1() const noexcept {
|
||||||
|
return _p1;
|
||||||
|
}
|
||||||
|
const path& path2() const noexcept {
|
||||||
|
return _p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//const char* what() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
path _p1;
|
||||||
|
path _p2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum class file_type {
|
||||||
|
|
||||||
|
none = 0,
|
||||||
|
not_found = -1,
|
||||||
|
regular = 1,
|
||||||
|
directory = 2,
|
||||||
|
symlink = 3,
|
||||||
|
block = 4,
|
||||||
|
character = 5,
|
||||||
|
fifo = 6,
|
||||||
|
socket = 7,
|
||||||
|
unknown = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
enum perms {
|
||||||
|
|
||||||
|
none = 0,
|
||||||
|
owner_read = 0400,
|
||||||
|
owner_write = 0200,
|
||||||
|
owner_exec = 0100,
|
||||||
|
owner_all = 0700,
|
||||||
|
|
||||||
|
group_read = 040,
|
||||||
|
group_write = 020,
|
||||||
|
group_exec = 010,
|
||||||
|
group_all = 070,
|
||||||
|
|
||||||
|
others_read = 04,
|
||||||
|
others_write = 02,
|
||||||
|
others_exec = 01,
|
||||||
|
others_all = 07,
|
||||||
|
|
||||||
|
all = 0777,
|
||||||
|
set_uid = 04000,
|
||||||
|
set_gid = 02000,
|
||||||
|
sticky_bit = 01000,
|
||||||
|
mask = 07777,
|
||||||
|
|
||||||
|
unknown = 0xffff,
|
||||||
|
|
||||||
|
add_perms = 0x10000,
|
||||||
|
remove_perms = 0x20000,
|
||||||
|
resolve_symlinks = 0x40000,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class file_status
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// constructors
|
||||||
|
explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) noexcept:
|
||||||
|
_ft(ft), _prms(prms) {}
|
||||||
|
|
||||||
|
file_status(const file_status&) noexcept = default;
|
||||||
|
file_status(file_status&&) noexcept = default;
|
||||||
|
~file_status() = default;
|
||||||
|
|
||||||
|
file_status& operator=(const file_status&) noexcept = default;
|
||||||
|
file_status& operator=(file_status&&) noexcept = default;
|
||||||
|
|
||||||
|
// observers
|
||||||
|
file_type type() const noexcept {
|
||||||
|
return _ft;
|
||||||
|
}
|
||||||
|
|
||||||
|
perms permissions() const noexcept {
|
||||||
|
return _prms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// modifiers
|
||||||
|
void type(file_type ft) noexcept {
|
||||||
|
_ft = ft;
|
||||||
|
}
|
||||||
|
void permissions(perms prms) noexcept {
|
||||||
|
_prms = prms;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
file_type _ft = file_type::none;
|
||||||
|
perms _prms = perms::unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct space_info // returned by space function
|
||||||
|
{
|
||||||
|
uintmax_t capacity;
|
||||||
|
uintmax_t free;
|
||||||
|
uintmax_t available; // free space available to a non-privileged process
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class directory_options
|
||||||
|
{
|
||||||
|
none,
|
||||||
|
follow_directory_symlink,
|
||||||
|
skip_permission_denied
|
||||||
|
};
|
||||||
|
|
||||||
|
//typedef std::chrono::time_point<trivial-clock> file_time_type;
|
||||||
|
typedef std::chrono::time_point<std::chrono::system_clock> file_time_type;
|
||||||
|
|
||||||
|
enum class copy_options
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
skip_existing = 1,
|
||||||
|
overwrite_existing = 2,
|
||||||
|
update_existing = 4,
|
||||||
|
recurive = 8,
|
||||||
|
copy_symlinks = 16,
|
||||||
|
skip_symlinks = 32,
|
||||||
|
directories_only = 64,
|
||||||
|
create_symlinks = 128,
|
||||||
|
create_hard_links = 256
|
||||||
|
};
|
||||||
|
|
||||||
|
path current_path();
|
||||||
|
path current_path(error_code& ec);
|
||||||
|
void current_path(const path& p);
|
||||||
|
void current_path(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
path absolute(const path& p, const path& base=current_path());
|
||||||
|
|
||||||
|
path canonical(const path& p, const path& base = current_path());
|
||||||
|
path canonical(const path& p, error_code& ec);
|
||||||
|
path canonical(const path& p, const path& base, error_code& ec);
|
||||||
|
|
||||||
|
void copy(const path& from, const path& to);
|
||||||
|
void copy(const path& from, const path& to, error_code& ec) noexcept;
|
||||||
|
void copy(const path& from, const path& to, copy_options options);
|
||||||
|
void copy(const path& from, const path& to, copy_options options, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
bool copy_file(const path& from, const path& to);
|
||||||
|
bool copy_file(const path& from, const path& to, error_code& ec) noexcept;
|
||||||
|
bool copy_file(const path& from, const path& to, copy_options option);
|
||||||
|
bool copy_file(const path& from, const path& to, copy_options option, error_code& ec) noexcept;
|
||||||
|
void copy_symlink(const path& existing_symlink, const path& new_symlink);
|
||||||
|
|
||||||
|
void copy_symlink(const path& existing_symlink, const path& new_symlink, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
bool create_directories(const path& p);
|
||||||
|
bool create_directories(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
bool create_directory(const path& p);
|
||||||
|
bool create_directory(const path& p, error_code& ec) noexcept;
|
||||||
|
bool create_directory(const path& p, const path& attributes);
|
||||||
|
bool create_directory(const path& p, const path& attributes, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
void create_directory_symlink(const path& to, const path& new_symlink);
|
||||||
|
void create_directory_symlink(const path& to, const path& new_symlink, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
void create_hard_link(const path& to, const path& new_hard_link);
|
||||||
|
void create_hard_link(const path& to, const path& new_hard_link, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
void create_symlink(const path& to, const path& new_symlink);
|
||||||
|
void create_symlink(const path& to, const path& new_symlink, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
file_status status(const path& p);
|
||||||
|
file_status status(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
file_status symlink_status(const path& p);
|
||||||
|
file_status symlink_status(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
inline bool status_known(file_status s) noexcept {
|
||||||
|
return s.type() != file_type::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool exists(file_status s) noexcept {
|
||||||
|
return status_known(s) && s.type() != file_type::not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool exists(const path& p) {
|
||||||
|
return exists(status(p));
|
||||||
|
}
|
||||||
|
inline bool exists(const path& p, error_code& ec) noexcept {
|
||||||
|
return exists(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool equivalent(const path& p1, const path& p2);
|
||||||
|
bool equivalent(const path& p1, const path& p2, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
uintmax_t file_size(const path& p);
|
||||||
|
uintmax_t file_size(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
uintmax_t hard_link_count(const path& p);
|
||||||
|
uintmax_t hard_link_count(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
inline bool is_block_file(file_status s) noexcept {
|
||||||
|
return s.type() == file_type::block;
|
||||||
|
}
|
||||||
|
inline bool is_block_file(const path& p) {
|
||||||
|
return is_block_file(status(p));
|
||||||
|
}
|
||||||
|
inline bool is_block_file(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_block_file(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_character_file(file_status s) noexcept {
|
||||||
|
return s.type() == file_type::character;
|
||||||
|
}
|
||||||
|
inline bool is_character_file(const path& p) {
|
||||||
|
return is_character_file(status(p));
|
||||||
|
}
|
||||||
|
inline bool is_character_file(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_character_file(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_directory(file_status s) noexcept {
|
||||||
|
return s.type() == file_type::directory;
|
||||||
|
}
|
||||||
|
inline bool is_directory(const path& p) {
|
||||||
|
return is_directory(status(p));
|
||||||
|
}
|
||||||
|
inline bool is_directory(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_directory(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty(const path& p);
|
||||||
|
bool is_empty(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
inline bool is_fifo(file_status s) noexcept {
|
||||||
|
return s.type() == file_type::fifo;
|
||||||
|
}
|
||||||
|
inline bool is_fifo(const path& p) {
|
||||||
|
return is_fifo(status(p));
|
||||||
|
}
|
||||||
|
inline bool is_fifo(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_fifo(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_socket(file_status s) noexcept {
|
||||||
|
return s.type() == file_type::socket;
|
||||||
|
}
|
||||||
|
inline bool is_socket(const path& p) {
|
||||||
|
return is_socket(status(p));
|
||||||
|
}
|
||||||
|
inline bool is_socket(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_socket(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool is_symlink(file_status s) noexcept {
|
||||||
|
return s.type() == file_type::symlink;
|
||||||
|
}
|
||||||
|
inline bool is_symlink(const path& p) {
|
||||||
|
return is_symlink(status(p));
|
||||||
|
}
|
||||||
|
inline bool is_symlink(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_symlink(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool is_regular_file(file_status s) noexcept {
|
||||||
|
return s.type() == file_type::regular;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_regular_file(const path& p) {
|
||||||
|
return is_regular_file(status(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_regular_file(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_regular_file(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_other(file_status s) noexcept {
|
||||||
|
return exists(s) && !is_regular_file(s) && ! is_directory(s) && !is_symlink(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_other(const path& p) {
|
||||||
|
return is_other(status(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_other(const path& p, error_code& ec) noexcept {
|
||||||
|
return is_other(status(p, ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
file_time_type last_write_time(const path& p);
|
||||||
|
file_time_type last_write_time(const path& p, error_code& ec) noexcept;
|
||||||
|
void last_write_time(const path& p, file_time_type new_time);
|
||||||
|
void last_write_time(const path& p, file_time_type new_time, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
void permissions(const path& p, perms prms);
|
||||||
|
void permissions(const path& p, perms prms, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
path read_symlink(const path& p);
|
||||||
|
path read_symlink(const path& p, error_code& ec);
|
||||||
|
bool remove(const path& p);
|
||||||
|
bool remove(const path& p, error_code& ec) noexcept;
|
||||||
|
uintmax_t remove_all(const path& p);
|
||||||
|
uintmax_t remove_all(const path& p, error_code& ec) noexcept;
|
||||||
|
void rename(const path& from, const path& to);
|
||||||
|
void rename(const path& from, const path& to, error_code& ec) noexcept;
|
||||||
|
void resize_file(const path& p, uintmax_t size);
|
||||||
|
void resize_file(const path& p, uintmax_t size, error_code& ec) noexcept;
|
||||||
|
space_info space(const path& p);
|
||||||
|
space_info space(const path& p, error_code& ec) noexcept;
|
||||||
|
file_status status(const path& p);
|
||||||
|
file_status status(const path& p, error_code& ec) noexcept;
|
||||||
|
bool status_known(file_status s) noexcept;
|
||||||
|
file_status symlink_status(const path& p);
|
||||||
|
file_status symlink_status(const path& p, error_code& ec) noexcept;
|
||||||
|
path system_complete(const path& p);
|
||||||
|
path system_complete(const path& p, error_code& ec);
|
||||||
|
path temp_directory_path();
|
||||||
|
path temp_directory_path(error_code& ec);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class directory_entry {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// constructors and destructor
|
||||||
|
directory_entry() = default;
|
||||||
|
directory_entry(const directory_entry&) = default;
|
||||||
|
directory_entry(directory_entry&&) noexcept = default;
|
||||||
|
explicit directory_entry(const path& p, file_status st=file_status(), file_status symlink_st=file_status());
|
||||||
|
|
||||||
|
~directory_entry() = default;
|
||||||
|
|
||||||
|
// modifiers
|
||||||
|
directory_entry& operator=(const directory_entry&) = default;
|
||||||
|
directory_entry& operator=(directory_entry&&) noexcept = default;
|
||||||
|
void assign(const path& p, file_status st=file_status(),
|
||||||
|
file_status symlink_st=file_status());
|
||||||
|
void replace_filename(const path& p, file_status st=file_status(),
|
||||||
|
file_status symlink_st=file_status());
|
||||||
|
|
||||||
|
|
||||||
|
// observers
|
||||||
|
const filesystem::path& path() const noexcept {
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_status status() const;
|
||||||
|
file_status status(error_code& ec) const noexcept;
|
||||||
|
file_status symlink_status() const;
|
||||||
|
file_status symlink_status(error_code& ec) const noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
bool operator< (const directory_entry& rhs) const noexcept;
|
||||||
|
bool operator==(const directory_entry& rhs) const noexcept;
|
||||||
|
bool operator!=(const directory_entry& rhs) const noexcept;
|
||||||
|
bool operator<=(const directory_entry& rhs) const noexcept;
|
||||||
|
bool operator> (const directory_entry& rhs) const noexcept;
|
||||||
|
bool operator>=(const directory_entry& rhs) const noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
class path _path;
|
||||||
|
mutable file_status _st;
|
||||||
|
mutable file_status _lst;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class directory_iterator : public std::iterator<std::input_iterator_tag, directory_entry>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// member functions
|
||||||
|
directory_iterator() noexcept = default;
|
||||||
|
explicit directory_iterator(const path& p);
|
||||||
|
directory_iterator(const path& p, error_code& ec) noexcept;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
const directory_entry& operator*() const {
|
||||||
|
return _imp->_entry;
|
||||||
|
}
|
||||||
|
const directory_entry* operator->() const {
|
||||||
|
return &_imp->_entry;
|
||||||
|
}
|
||||||
|
directory_iterator& operator++();
|
||||||
|
directory_iterator& increment(error_code& ec) noexcept;
|
||||||
|
|
||||||
|
bool operator == (const directory_iterator &rhs) const noexcept {
|
||||||
|
return _imp == rhs._imp;
|
||||||
|
}
|
||||||
|
bool operator != (const directory_iterator &rhs) const noexcept {
|
||||||
|
return _imp != rhs._imp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// other members as required by
|
||||||
|
// C++ Std, 24.1.1 Input iterators [input.iterators]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void open_dir(const path &p, error_code &ec) noexcept;
|
||||||
|
|
||||||
|
struct imp {
|
||||||
|
path _path;
|
||||||
|
directory_entry _entry;
|
||||||
|
DIR *_dp = nullptr;
|
||||||
|
|
||||||
|
imp() = default;
|
||||||
|
imp(const path &p, DIR *dp) : _path(p), _dp(dp)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~imp() {
|
||||||
|
if (_dp) closedir(_dp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<imp> _imp;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
directory_iterator non-member functions
|
||||||
|
*/
|
||||||
|
inline const directory_iterator& begin(const directory_iterator& iter) noexcept {
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline directory_iterator end(const directory_iterator&) noexcept {
|
||||||
|
return directory_iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
inline void swap(filesystem::path& lhs, filesystem::path& rhs) noexcept {
|
||||||
|
lhs.swap(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<filesystem::path>
|
||||||
|
{
|
||||||
|
std::size_t operator()(const filesystem::path &p) const
|
||||||
|
{
|
||||||
|
std::hash<filesystem::path::string_type> hasher;
|
||||||
|
return hasher(p.native());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,285 @@
|
||||||
|
|
||||||
|
#include "filesystem.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace filesystem {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const path::value_type separator = '/';
|
||||||
|
|
||||||
|
// hmmm... these could be pre-studied since they're constant?
|
||||||
|
const path path_dot = ".";
|
||||||
|
const path path_dotdot = "..";
|
||||||
|
const path path_sep = "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
void path::study() const {
|
||||||
|
|
||||||
|
if (_info.valid) return;
|
||||||
|
int length = _path.length();
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
_info.valid = true;
|
||||||
|
_info.special = 0;
|
||||||
|
_info.stem = _info.extension = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto back = _path[length - 1];
|
||||||
|
|
||||||
|
// check for special cases (part 1)
|
||||||
|
// if the path is all /s, filename is /
|
||||||
|
// if the path ends with a / (but contains a non-/ char),
|
||||||
|
// the filename is .
|
||||||
|
|
||||||
|
if (back == separator) {
|
||||||
|
value_type special = '.';
|
||||||
|
if (_path.find_first_not_of(separator) == _path.npos)
|
||||||
|
special = separator;
|
||||||
|
|
||||||
|
_info.valid = true;
|
||||||
|
_info.extension = length;
|
||||||
|
_info.stem = length;
|
||||||
|
_info.special = special;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stem = 0;
|
||||||
|
int extension = length;
|
||||||
|
for (int i = length; i; ) {
|
||||||
|
auto c = _path[--i];
|
||||||
|
if (c == '.' && extension == length)
|
||||||
|
extension = i;
|
||||||
|
if (c == '/') {
|
||||||
|
stem = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check for special cases (part 2)
|
||||||
|
// ".." and "." are not extensions.
|
||||||
|
if (back == '.') {
|
||||||
|
int xlength = length - stem;
|
||||||
|
if (xlength == 1)
|
||||||
|
extension = length;
|
||||||
|
if (xlength == 2 && _path[stem] == '.')
|
||||||
|
extension = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
_info.valid = true;
|
||||||
|
_info.stem = stem;
|
||||||
|
_info.extension = extension;
|
||||||
|
_info.special = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
path::path(const path &rhs) :
|
||||||
|
_path(rhs._path), _info(rhs._info)
|
||||||
|
{}
|
||||||
|
|
||||||
|
path::path(path &&rhs) noexcept :
|
||||||
|
_path(std::move(rhs._path))
|
||||||
|
{
|
||||||
|
rhs.invalidate();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// private. neither this->_path nor s are empty.
|
||||||
|
path &path::append_common(const std::string &s)
|
||||||
|
{
|
||||||
|
invalidate();
|
||||||
|
if (_path.back() != separator && s.front() != separator)
|
||||||
|
_path.push_back(separator);
|
||||||
|
|
||||||
|
_path.append(s);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
path& path::append(const path& p)
|
||||||
|
{
|
||||||
|
if (p.empty()) return *this;
|
||||||
|
|
||||||
|
if (empty()) {
|
||||||
|
return (*this = p);
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
// check for something stupid like xx.append(xx);
|
||||||
|
if (&p == this) {
|
||||||
|
return append_common(string_type(p._path));
|
||||||
|
}
|
||||||
|
|
||||||
|
return append_common(p._path);
|
||||||
|
}
|
||||||
|
|
||||||
|
path& path::append(const string_type &s)
|
||||||
|
{
|
||||||
|
if (s.empty()) return *this;
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
if (empty()) {
|
||||||
|
_path = s;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (&s == &_path) {
|
||||||
|
string_type tmp(s);
|
||||||
|
if (_path.back() != separator && tmp[0] != separator)
|
||||||
|
_path.push_back(separator);
|
||||||
|
_path.append(tmp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_path.back() != separator && s[0] != separator)
|
||||||
|
_path.push_back(separator);
|
||||||
|
|
||||||
|
_path.append(s);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
path path::filename() const {
|
||||||
|
|
||||||
|
if (empty()) return *this;
|
||||||
|
if (!_info.valid) study();
|
||||||
|
|
||||||
|
if (_info.special == separator) return path_sep;
|
||||||
|
if (_info.special == '.') return path_dot;
|
||||||
|
|
||||||
|
if (_info.stem == 0) return *this;
|
||||||
|
return _path.substr(_info.stem);
|
||||||
|
}
|
||||||
|
|
||||||
|
path path::stem() const {
|
||||||
|
|
||||||
|
// filename without the extension.
|
||||||
|
|
||||||
|
if (empty()) return *this;
|
||||||
|
if (!_info.valid) study();
|
||||||
|
|
||||||
|
if (_info.special == separator) return path_sep;
|
||||||
|
if (_info.special == '.') return path_dot;
|
||||||
|
|
||||||
|
return _path.substr(_info.stem, _info.extension - _info.stem);
|
||||||
|
}
|
||||||
|
|
||||||
|
path path::extension() const {
|
||||||
|
|
||||||
|
if (empty()) return *this;
|
||||||
|
if (!_info.valid) study();
|
||||||
|
|
||||||
|
return _path.substr(_info.extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool path::has_parent_path() const
|
||||||
|
{
|
||||||
|
// if there is a /, it has a parent path.
|
||||||
|
// ... unless it's /.
|
||||||
|
|
||||||
|
if (empty()) return false;
|
||||||
|
|
||||||
|
if (!_info.valid) study();
|
||||||
|
|
||||||
|
if (_info.special == '/') return false;
|
||||||
|
|
||||||
|
return _path.find(separator) != _path.npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
path path::parent_path() const {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* special cases:
|
||||||
|
* /abc -> /
|
||||||
|
* /abc/ -> /abc
|
||||||
|
* all trailing /s are removed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
if (empty()) return *this;
|
||||||
|
|
||||||
|
if (!_info.valid) study();
|
||||||
|
|
||||||
|
// "/" is a file of "/" with a parent of ""
|
||||||
|
if (_info.special == separator) return path();
|
||||||
|
|
||||||
|
// stem starts at 0, eg "abc"
|
||||||
|
if (!_info.stem) return path();
|
||||||
|
|
||||||
|
|
||||||
|
auto tmp = _path.substr(0, _info.stem - 1);
|
||||||
|
|
||||||
|
// remove trailing slashes, but return "/" if nothing BUT /s.
|
||||||
|
while (!tmp.empty() && tmp.back() == separator) tmp.pop_back();
|
||||||
|
if (tmp.empty()) return path_sep;
|
||||||
|
|
||||||
|
return path(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
path path::root_directory() const {
|
||||||
|
// for unix, root directory is / or "".
|
||||||
|
if (empty()) return *this;
|
||||||
|
|
||||||
|
return _path.front() == '/' ? path_sep : path();
|
||||||
|
}
|
||||||
|
|
||||||
|
path path::root_name() const {
|
||||||
|
/*
|
||||||
|
* boost (unix) considers // or //component
|
||||||
|
* to be a root name (and only those cases).
|
||||||
|
*
|
||||||
|
* I do not.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return path();
|
||||||
|
}
|
||||||
|
|
||||||
|
path path::root_path() const {
|
||||||
|
// root_name + root_directory.
|
||||||
|
// since root_name is always empty...
|
||||||
|
|
||||||
|
return root_directory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
path path::relative_path() const {
|
||||||
|
// first pathname *after* the root path
|
||||||
|
// root_path is first / in this implementation.
|
||||||
|
|
||||||
|
if (is_relative()) return *this;
|
||||||
|
|
||||||
|
auto pos = _path.find_first_not_of(separator);
|
||||||
|
if (pos == _path.npos) return path();
|
||||||
|
|
||||||
|
return path(_path.substr(pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// compare
|
||||||
|
int path::compare(const path& p) const noexcept {
|
||||||
|
if (&p == this) return 0;
|
||||||
|
return _path.compare(p._path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int path::compare(const std::string& s) const {
|
||||||
|
if (&s == &_path) return 0;
|
||||||
|
return _path.compare(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int path::compare(const value_type* s) const {
|
||||||
|
return _path.compare(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef __string_splitter__
|
||||||
|
#define __string_splitter__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class string_splitter {
|
||||||
|
public:
|
||||||
|
string_splitter(const std::string &str, char sep) :
|
||||||
|
_parent(str), _sep(sep)
|
||||||
|
{
|
||||||
|
_begin = 0;
|
||||||
|
_end = _parent.find(_sep);
|
||||||
|
_str = _parent.substr(_begin, _end);
|
||||||
|
// _begin is 0, _end is either npos or offset from 0,
|
||||||
|
// so no need to calculate a count.
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const {
|
||||||
|
return _begin != npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
string_splitter &operator++() {
|
||||||
|
increment();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &operator *() const {
|
||||||
|
return _str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string *operator ->() const {
|
||||||
|
return &_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void increment() {
|
||||||
|
_str.clear();
|
||||||
|
if (_begin == npos) return;
|
||||||
|
if (_end == npos) { _begin = _end; return; }
|
||||||
|
|
||||||
|
_begin = _end + 1;
|
||||||
|
_end = _parent.find(_sep, _begin);
|
||||||
|
auto count = _end == npos ? _end : _end - _begin;
|
||||||
|
_str = _parent.substr(_begin, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
const static auto npos = std::string::npos;
|
||||||
|
std::string _str;
|
||||||
|
const std::string &_parent;
|
||||||
|
char _sep;
|
||||||
|
std::string::size_type _begin = 0;
|
||||||
|
std::string::size_type _end = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: %s sep string\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (strlen(argv[1]) != 1) {
|
||||||
|
fprintf(stderr, "Separator must be a single character\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
char sep = argv[1][0];
|
||||||
|
std::string str(argv[2]);
|
||||||
|
|
||||||
|
for (auto iter = string_splitter(str, sep); iter; ++iter) {
|
||||||
|
printf("%s\n", iter->c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,7 +17,7 @@
|
||||||
#include "phase2.h"
|
#include "phase2.h"
|
||||||
#include "command.h"
|
#include "command.h"
|
||||||
|
|
||||||
#include "mapped_file.h"
|
#include "cxx/mapped_file.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
|
||||||
//#include <histedit.h>
|
//#include <histedit.h>
|
||||||
|
|
Loading…
Reference in New Issue