diff --git a/build.sh b/build.sh index f0ae867..1c6a9e2 100755 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ ASM_SOURCES="jump_all_gas make_all_gas ontop_all_gas" # c++ sources CXX_SOURCE_DIR="src" -CXX_SOURCES="context_stack io filesystem" +CXX_SOURCES="context_stack io" # output lib OSTD_LIB="libostd" @@ -208,7 +208,7 @@ call_as() { # call_ld output file1 file2 ... call_ld() { echoq "LD: $1" - evalv "${CXX} ${OSTD_CPPFLAGS} ${OSTD_CXXFLAGS} ${OSTD_LDFLAGS} -o $@" + evalv "${CXX} ${OSTD_CPPFLAGS} ${OSTD_CXXFLAGS} -o $@ ${OSTD_LDFLAGS}" if [ "$BUILD_CFG" = "release" ]; then echoq "STRIP: $1" evalv "$STRIP \"$1\"" diff --git a/examples/listdir.cc b/examples/listdir.cc index aeefc63..402bf6c 100644 --- a/examples/listdir.cc +++ b/examples/listdir.cc @@ -4,16 +4,16 @@ using namespace ostd; -void list_dirs(string_range path, int off = 0) { - directory_stream ds{path}; - /* iterate all items in directory */ - for (auto v: iter(ds)) { - if (v.type() != file_type::DIRECTORY) { +void list_dirs(filesystem::path const &path, int off = 0) { + filesystem::directory_iterator ds{path}; + for (auto &v: ds) { + auto p = filesystem::path{v}; + if (!filesystem::is_directory(p)) { continue; } for_each(range(off), [](int) { write(' '); }); - writeln(v.filename()); - list_dirs(v.path(), off + 1); + writeln(p.filename()); + list_dirs(p, off + 1); } } diff --git a/ostd/filesystem.hh b/ostd/filesystem.hh index 8af202e..bea7039 100644 --- a/ostd/filesystem.hh +++ b/ostd/filesystem.hh @@ -6,525 +6,53 @@ #ifndef OSTD_FILESYSTEM_HH #define OSTD_FILESYSTEM_HH -#include "ostd/platform.hh" -#include "ostd/internal/win32.hh" - -#ifdef OSTD_PLATFORM_POSIX -#include -#include -#include +#if __has_include() +# include +namespace ostd { + namespace filesystem = std::filesystem; +} +#elif __has_include() +# include +namespace ostd { + namespace filesystem = std::experimental::filesystem; +} #else -#include +# error "Unsupported platform" #endif -#include - -#include "ostd/types.hh" #include "ostd/range.hh" -#include "ostd/vector.hh" -#include "ostd/string.hh" -#include "ostd/algorithm.hh" +#include "ostd/format.hh" namespace ostd { -enum class file_type { - UNKNOWN, REGULAR, FIFO, CHARACTER, DIRECTORY, BLOCK, SYMLINK, SOCKET +template<> +struct ranged_traits { + using range = iterator_range; + + static range iter(filesystem::directory_iterator const &r) { + return range{filesystem::begin(r), filesystem::end(r)}; + } }; -struct file_info; +template<> +struct ranged_traits { + using range = iterator_range; -#ifdef OSTD_PLATFORM_WIN32 -static constexpr char PATH_SEPARATOR = '\\'; -#else -static constexpr char PATH_SEPARATOR = '/'; -#endif - -inline void path_normalize(char_range) { - /* TODO */ -} - -struct OSTD_EXPORT file_info { - file_info() {} - - file_info(file_info const &i): - p_slash(i.p_slash), p_dot(i.p_dot), p_type(i.p_type), - p_path(i.p_path), p_atime(i.p_atime), p_mtime(i.p_mtime), - p_ctime(i.p_ctime) - {} - - file_info(file_info &&i): - p_slash(i.p_slash), p_dot(i.p_dot), p_type(i.p_type), - p_path(std::move(i.p_path)), p_atime(i.p_atime), p_mtime(i.p_mtime), - p_ctime(i.p_ctime) - { - i.p_slash = i.p_dot = std::string::npos; - i.p_type = file_type::UNKNOWN; - i.p_atime = i.p_ctime = i.p_mtime = 0; + static range iter(filesystem::recursive_directory_iterator const &r) { + return range{filesystem::begin(r), filesystem::end(r)}; } - - file_info(string_range path) { - init_from_str(path); - } - - file_info &operator=(file_info const &i) { - p_slash = i.p_slash; - p_dot = i.p_dot; - p_type = i.p_type; - p_path = i.p_path; - p_atime = i.p_atime; - p_mtime = i.p_mtime; - p_ctime = i.p_ctime; - return *this; - } - - file_info &operator=(file_info &&i) { - swap(i); - return *this; - } - - string_range path() const { return ostd::iter(p_path); } - - string_range filename() const { - return path().slice( - (p_slash == std::string::npos) ? 0 : (p_slash + 1), p_path.size() - ); - } - - string_range stem() const { - return path().slice( - (p_slash == std::string::npos) ? 0 : (p_slash + 1), - (p_dot == std::string::npos) ? p_path.size() : p_dot - ); - } - - string_range extension() const { - return (p_dot == std::string::npos) - ? string_range() - : path().slice(p_dot, p_path.size()); - } - - file_type type() const { return p_type; } - - void normalize() { - path_normalize(ostd::iter(p_path)); - init_from_str(ostd::iter(p_path)); - } - - time_t atime() const { return p_atime; } - time_t mtime() const { return p_mtime; } - time_t ctime() const { return p_ctime; } - - void swap(file_info &i) { - using std::swap; - swap(i.p_slash, p_slash); - swap(i.p_dot, p_dot); - swap(i.p_type, p_type); - swap(i.p_path, p_path); - swap(i.p_atime, p_atime); - swap(i.p_mtime, p_mtime); - swap(i.p_ctime, p_ctime); - } - -private: - void init_from_str(string_range path); - - size_t p_slash = std::string::npos, p_dot = std::string::npos; - file_type p_type = file_type::UNKNOWN; - std::string p_path; - - time_t p_atime = 0, p_mtime = 0, p_ctime = 0; }; -inline void swap(file_info &a, file_info &b) { - a.swap(b); -} - -struct directory_range; - -#ifndef OSTD_PLATFORM_WIN32 -struct directory_stream { - friend struct directory_range; - - directory_stream(): p_d(), p_de(), p_path() {} - directory_stream(directory_stream const &) = delete; - directory_stream(directory_stream &&s): - p_d(s.p_d), p_de(s.p_de), p_path(std::move(s.p_path)) - { - s.p_d = nullptr; - s.p_de = nullptr; +template<> +struct format_traits { + template + static void to_format( + filesystem::path const &p, R &writer, format_spec const &fs + ) { + fs.format_value(writer, p.string()); } - - directory_stream(string_range path): directory_stream() { - open(path); - } - - ~directory_stream() { close(); } - - directory_stream &operator=(directory_stream const &) = delete; - directory_stream &operator=(directory_stream &&s) { - close(); - swap(s); - return *this; - } - - bool open(string_range path) { - if (p_d || (path.size() > FILENAME_MAX)) { - return false; - } - char buf[FILENAME_MAX + 1]; - memcpy(buf, &path[0], path.size()); - buf[path.size()] = '\0'; - p_d = opendir(buf); - if (!pop_front()) { - close(); - return false; - } - p_path = path; - return true; - } - - bool is_open() const { return p_d != nullptr; } - - void close() { - if (p_d) closedir(p_d); - p_d = nullptr; - p_de = nullptr; - } - - long size() const { - if (!p_d) { - return -1; - } - DIR *td = opendir(p_path.data()); - if (!td) { - return -1; - } - long ret = 0; - struct dirent *rd; - while (pop_front(td, &rd)) { - ret += strcmp(rd->d_name, ".") && strcmp(rd->d_name, ".."); - } - closedir(td); - return ret; - } - - bool rewind() { - if (!p_d) { - return false; - } - rewinddir(p_d); - if (!pop_front()) { - close(); - return false; - } - return true; - } - - bool empty() const { - return !p_de; - } - - file_info read() { - if (!pop_front()) { - return file_info(); - } - return front(); - } - - void swap(directory_stream &s) { - using std::swap; - swap(p_d, s.p_d); - swap(p_de, s.p_de); - swap(p_path, s.p_path); - } - - directory_range iter(); - -private: - static bool pop_front(DIR *d, struct dirent **de) { - if (!d) return false; - if (!(*de = readdir(d))) - return false; - /* order of . and .. in the stream is not guaranteed, apparently... - * gotta check every time because of that - */ - while (*de && ( - !strcmp((*de)->d_name, ".") || !strcmp((*de)->d_name, "..") - )) { - if (!(*de = readdir(d))) { - return false; - } - } - return !!*de; - } - - bool pop_front() { - return pop_front(p_d, &p_de); - } - - file_info front() const { - if (!p_de) { - return file_info(); - } - std::string ap = p_path; - ap += PATH_SEPARATOR; - ap += static_cast(p_de->d_name); - return file_info(ap); - } - - DIR *p_d; - struct dirent *p_de; - std::string p_path; }; -#else /* OSTD_PLATFORM_WIN32 */ - -struct directory_stream { - friend struct directory_range; - - directory_stream(): p_handle(INVALID_HANDLE_VALUE), p_data(), p_path() {} - directory_stream(directory_stream const &) = delete; - directory_stream(directory_stream &&s): - p_handle(s.p_handle), p_data(s.p_data), p_path(std::move(s.p_path)) - { - s.p_handle = INVALID_HANDLE_VALUE; - memset(&s.p_data, 0, sizeof(s.p_data)); - } - - directory_stream(string_range path): directory_stream() { - open(path); - } - - ~directory_stream() { close(); } - - directory_stream &operator=(directory_stream const &) = delete; - directory_stream &operator=(directory_stream &&s) { - close(); - swap(s); - return *this; - } - - bool open(string_range path) { - if (p_handle != INVALID_HANDLE_VALUE) { - return false; - } - if ((path.size() >= 1024) || !path.size()) { - return false; - } - char buf[1026]; - memcpy(buf, &path[0], path.size()); - char *bptr = &buf[path.size()]; - /* if path ends with a slash, replace it */ - bptr -= ((*(bptr - 1) == '\\') || (*(bptr - 1) == '/')); - /* include trailing zero */ - memcpy(bptr, "\\*", 3); - p_handle = FindFirstFile(buf, &p_data); - if (p_handle == INVALID_HANDLE_VALUE) { - return false; - } - while ( - !strcmp(p_data.cFileName, ".") || !strcmp(p_data.cFileName, "..") - ) { - if (!FindNextFile(p_handle, &p_data)) { - FindClose(p_handle); - p_handle = INVALID_HANDLE_VALUE; - p_data.cFileName[0] = '\0'; - return false; - } - } - p_path = path; - return true; - } - - bool is_open() const { return p_handle != INVALID_HANDLE_VALUE; } - - void close() { - if (p_handle != INVALID_HANDLE_VALUE) { - FindClose(p_handle); - } - p_handle = INVALID_HANDLE_VALUE; - p_data.cFileName[0] = '\0'; - } - - long size() const { - if (p_handle == INVALID_HANDLE_VALUE) { - return -1; - } - WIN32_FIND_DATA wfd; - HANDLE td = FindFirstFile(p_path.data(), &wfd); - if (td == INVALID_HANDLE_VALUE) { - return -1; - } - while (!strcmp(wfd.cFileName, ".") && !strcmp(wfd.cFileName, "..")) { - if (!FindNextFile(td, &wfd)) { - FindClose(td); - return 0; - } - } - long ret = 1; - while (FindNextFile(td, &wfd)) { - ++ret; - } - FindClose(td); - return ret; - } - - bool rewind() { - if (p_handle != INVALID_HANDLE_VALUE) { - FindClose(p_handle); - } - p_handle = FindFirstFile(p_path.data(), &p_data); - if (p_handle == INVALID_HANDLE_VALUE) { - p_data.cFileName[0] = '\0'; - return false; - } - while ( - !strcmp(p_data.cFileName, ".") || !strcmp(p_data.cFileName, "..") - ) { - if (!FindNextFile(p_handle, &p_data)) { - FindClose(p_handle); - p_handle = INVALID_HANDLE_VALUE; - p_data.cFileName[0] = '\0'; - return false; - } - } - return true; - } - - bool empty() const { - return p_data.cFileName[0] == '\0'; - } - - file_info read() { - if (!pop_front()) { - return file_info(); - } - return front(); - } - - void swap(directory_stream &s) { - using std::swap; - swap(p_handle, s.p_handle); - swap(p_data, s.p_data); - swap(p_path, s.p_path); - } - - directory_range iter(); - -private: - bool pop_front() { - if (!is_open()) { - return false; - } - if (!FindNextFile(p_handle, &p_data)) { - p_data.cFileName[0] = '\0'; - return false; - } - return true; - } - - file_info front() const { - if (empty()) { - return file_info(); - } - std::string ap = p_path; - ap += PATH_SEPARATOR; - ap += static_cast(p_data.cFileName); - return file_info(ap); - } - - HANDLE p_handle; - WIN32_FIND_DATA p_data; - std::string p_path; -}; -#endif /* OSTD_PLATFORM_WIN32 */ - -inline void swap(directory_stream &a, directory_stream &b) { - a.swap(b); -} - -struct directory_range: input_range { - using range_category = input_range_tag; - using value_type = file_info; - using reference = file_info; - using size_type = size_t; - using difference_type = long; - - directory_range() = delete; - directory_range(directory_stream &s): p_stream(&s) {} - directory_range(directory_range const &r): p_stream(r.p_stream) {} - - directory_range &operator=(directory_range const &r) { - p_stream = r.p_stream; - return *this; - } - - bool empty() const { - return p_stream->empty(); - } - - void pop_front() { - p_stream->pop_front(); - } - - file_info front() const { - return p_stream->front(); - } - - bool equals_front(directory_range const &s) const { - return p_stream == s.p_stream; - } - -private: - directory_stream *p_stream; -}; - -inline directory_range directory_stream::iter() { - return directory_range(*this); -} - -namespace detail { - template - struct path_join { - template - static void join(std::string &s, T const &a, A const &...b) { - s += a; - s += PATH_SEPARATOR; - path_join::join(s, b...); - } - }; - - template<> - struct path_join<1> { - template - static void join(std::string &s, T const &a) { - s += a; - } - }; -} - -template -inline file_info path_join(A const &...args) { - std::string path; - detail::path_join::join(path, args...); - path_normalize(ostd::iter(path)); - return file_info(path); -} - -inline bool directory_change(string_range path) { - char buf[1024]; - if (path.size() >= 1024) { - return false; - } - memcpy(buf, path.data(), path.size()); - buf[path.size()] = '\0'; -#ifndef OSTD_PLATFORM_WIN32 - return !chdir(buf); -#else - return !_chdir(buf); -#endif -} - } /* namespace ostd */ #endif diff --git a/ostd/format.hh b/ostd/format.hh index 53a2239..bac99d9 100644 --- a/ostd/format.hh +++ b/ostd/format.hh @@ -282,13 +282,13 @@ struct format_spec { bool is_nested() const { return p_is_nested; } template - inline R &&format(R &&writer, A const &...args) { + R &&format(R &&writer, A const &...args) { write_fmt(writer, args...); return std::forward(writer); } template - inline R &&format_value(R &&writer, T const &val) { + R &&format_value(R &&writer, T const &val) const { write_arg(writer, 0, val); return std::forward(writer); } diff --git a/src/filesystem.cc b/src/filesystem.cc deleted file mode 100644 index af37d52..0000000 --- a/src/filesystem.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* Filesystem implementation bits. - * - * This file is part of OctaSTD. See COPYING.md for futher information. - */ - -#include "ostd/filesystem.hh" -#include "ostd/io.hh" - -namespace ostd { - -#ifdef OSTD_PLATFORM_WIN32 -static inline time_t filetime_to_time_t(FILETIME const &ft) { - ULARGE_INTEGER ul; - ul.LowPart = ft.dwLowDateTime; - ul.HighPart = ft.dwHighDateTime; - return static_cast((ul.QuadPart / 10000000ULL) - 11644473600ULL); -} -#endif - -void file_info::init_from_str(string_range path) { - /* TODO: implement a version that will follow symbolic links */ - p_path = path; -#ifdef OSTD_PLATFORM_WIN32 - WIN32_FILE_ATTRIBUTE_DATA attr; - if (!GetFileAttributesEx(p_path.data(), GetFileExInfoStandard, &attr) || - attr.dwFileAttributes == INVALID_FILE_ATTRIBUTES) -#else - struct stat st; - if (lstat(p_path.data(), &st) < 0) -#endif - { - p_slash = p_dot = std::string::npos; - p_type = file_type::UNKNOWN; - p_path.clear(); - p_atime = p_mtime = p_ctime = 0; - return; - } - string_range r = p_path; - - string_range found = find_last(r, PATH_SEPARATOR); - if (found.empty()) { - p_slash = std::string::npos; - } else { - p_slash = r.distance_front(found); - } - - found = find(filename(), '.'); - if (found.empty()) { - p_dot = std::string::npos; - } else { - p_dot = r.distance_front(found); - } - -#ifdef OSTD_PLATFORM_WIN32 - if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - p_type = file_type::DIRECTORY; - } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - p_type = file_type::SYMLINK; - } else if (attr.dwFileAttributes & ( - FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_COMPRESSED | - FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL | - FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_TEMPORARY - )) { - p_type = file_type::REGULAR; - } else { - p_type = file_type::UNKNOWN; - } - - p_atime = filetime_to_time_t(attr.ftLastAccessTime); - p_mtime = filetime_to_time_t(attr.ftLastWriteTime); - p_ctime = filetime_to_time_t(attr.ftCreationTime); -#else - if (S_ISREG(st.st_mode)) { - p_type = file_type::REGULAR; - } else if (S_ISDIR(st.st_mode)) { - p_type = file_type::DIRECTORY; - } else if (S_ISCHR(st.st_mode)) { - p_type = file_type::CHARACTER; - } else if (S_ISBLK(st.st_mode)) { - p_type = file_type::BLOCK; - } else if (S_ISFIFO(st.st_mode)) { - p_type = file_type::FIFO; - } else if (S_ISLNK(st.st_mode)) { - p_type = file_type::SYMLINK; - } else if (S_ISSOCK(st.st_mode)) { - p_type = file_type::SOCKET; - } else { - p_type = file_type::UNKNOWN; - } - - p_atime = st.st_atime; - p_mtime = st.st_mtime; - p_ctime = st.st_ctime; -#endif -} - -} /* namespace ostd */ diff --git a/test_runner.cc b/test_runner.cc index f37a16c..f7c0de6 100644 --- a/test_runner.cc +++ b/test_runner.cc @@ -35,7 +35,7 @@ int main() { /* do not change past this point */ int nsuccess = 0, nfailed = 0; - string_range modname = nullptr; + std::string modname = nullptr; auto print_result = [&](string_range fmsg = nullptr) { write(modname, "...\t"); @@ -48,23 +48,31 @@ int main() { } }; - directory_stream ds{testdir}; - for (auto v: iter(ds)) { - if ((v.type() != file_type::REGULAR) || (v.extension() != srcext)) + filesystem::directory_iterator ds{testdir}; + for (auto &v: ds) { + auto p = filesystem::path{v}; + if ( + (!filesystem::is_regular_file(p)) || + (p.extension().string() != srcext) + ) { continue; + } - modname = v.stem(); + modname = p.stem().string(); std::string exepath = testdir; - exepath += PATH_SEPARATOR; + exepath += char(filesystem::path::preferred_separator); exepath += modname; #ifdef OSTD_PLATFORM_WIN32 exepath += ".exe"; #endif auto cxxcmd = appender(); - format(cxxcmd, "%s %s%s%s -o %s %s", compiler, testdir, PATH_SEPARATOR, - v.filename(), exepath, cxxflags); + format( + cxxcmd, "%s %s%s%s -o %s %s", compiler, testdir, + char(filesystem::path::preferred_separator), + p.filename(), exepath, cxxflags + ); if (!userflags.empty()) { cxxcmd.get() += ' '; cxxcmd.get() += userflags;