move cxx stuff into cxx directory

This commit is contained in:
Kelvin Sherlock 2016-02-11 15:46:40 -05:00
parent 9316311a1d
commit 446e3e5e1e
10 changed files with 1704 additions and 3 deletions

View File

@ -114,8 +114,13 @@ add_custom_command(
# 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
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
pathnames.cpp)
phase1.cpp phase2.cpp phase2-parser.cpp command.cpp environment.cpp builtins.cpp
pathnames.cpp
cxx/mapped_file.cpp
cxx/filesystem.cpp
cxx/path.cpp
cxx/directory_iterator.cpp
)
target_link_libraries(mpw-shell edit)

193
cxx/directory_iterator.cpp Normal file
View File

@ -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;
}
}

289
cxx/filesystem.cpp Normal file
View File

@ -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());
}
}

848
cxx/filesystem.h Normal file
View File

@ -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

285
cxx/path.cpp Normal file
View File

@ -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);
}
}

81
cxx/string_splitter.h Normal file
View File

@ -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

View File

@ -17,7 +17,7 @@
#include "phase2.h"
#include "command.h"
#include "mapped_file.h"
#include "cxx/mapped_file.h"
#include "error.h"
//#include <histedit.h>