diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 4a080b77..4219e449 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -38,10 +38,9 @@ #define NANA_USING_STD_FILESYSTEM 0 #define NANA_USING_BOOST_FILESYSTEM 0 -#define NANA_FILESYSTEM_FORCE 1 +//#define NANA_FILESYSTEM_FORCE 1 #if (defined(NANA_FILESYSTEM_FORCE) || ( (defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(BOOST_FILESYSTEM_AVAILABLE)) && !(defined(BOOST_FILESYSTEM_FORCE) || defined(STD_FILESYSTEM_FORCE)) ) ) - #undef NANA_USING_NANA_FILESYSTEM #define NANA_USING_NANA_FILESYSTEM 1 @@ -137,130 +136,157 @@ namespace std { namespace nana { namespace filesystem { - enum class file_type - { - none = 0, ///< has not been determined or an error occurred while trying to determine - not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error - regular = 1, - directory = 2 , - symlink =3, ///< Symbolic link file - block =4, ///< Block special file - character= 5 , ///< Character special file - fifo = 6 , ///< FIFO or pipe file - socket =7, - unknown= 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other - }; + enum class file_type + { + none = 0, ///< has not been determined or an error occurred while trying to determine + not_found = -1, ///< Pseudo-type: file was not found. Is not considered an error + regular = 1, + directory = 2, + symlink = 3, ///< Symbolic link file + block = 4, ///< Block special file + character = 5, ///< Character special file + fifo = 6, ///< FIFO or pipe file + socket = 7, + unknown = 8 ///< The file does exist, but is of an operating system dependent type not covered by any of the other + }; - enum class perms - { - none = 0, ///< There are no permissions set for the file. - all = 0x1FF, ///< owner_all | group_all | others_all - mask = 0xFFF, ///< all | set_uid | set_gid | sticky_bit. - unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions - }; - //enum class copy_options; + enum class perms + { + none = 0, ///< There are no permissions set for the file. + all = 0x1FF, ///< owner_all | group_all | others_all + mask = 0xFFF, ///< all | set_uid | set_gid | sticky_bit. + unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions + }; + //enum class copy_options; - enum class directory_options - { - none, - follow_directory_symlink, - skip_permission_denied - }; + enum class directory_options + { + none, + follow_directory_symlink, + skip_permission_denied + }; - struct space_info - { - uintmax_t capacity; - uintmax_t free; - uintmax_t available; - }; + struct space_info + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; + }; - using file_time_type = std::chrono::time_point; ///< trivial-clock> ; + using file_time_type = std::chrono::time_point; ///< trivial-clock> ; - class file_status - { - file_type m_ft = file_type::none; - perms m_prms = perms::unknown; + class file_status + { + file_type m_ft = file_type::none; + perms m_prms = perms::unknown; - public: - explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown); + public: + explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown); - // observers - file_type type() const; - perms permissions() const; + // observers + file_type type() const; - // modifiers - void type(file_type ft); - void permissions(perms prms); - private: - file_type value_; - perms perms_; - }; + perms permissions() const; - /// concerned only with lexical and syntactic aspects and does not necessarily exist in - /// external storage, and the pathname is not necessarily valid for the current operating system - /// or for a particular file system - /// A sequence of elements that identify the location of a file within a filesystem. - /// The elements are the: - /// rootname (opt), root-directory (opt), and an optional sequence of filenames. - /// The maximum number of elements in the sequence is operating system dependent. - class path - { - public: + // modifiers + void type(file_type ft); + + void permissions(perms prms); + + private: + file_type value_; + perms perms_; + }; + + /// concerned only with lexical and syntactic aspects and does not necessarily exist in + /// external storage, and the pathname is not necessarily valid for the current operating system + /// or for a particular file system + /// A sequence of elements that identify the location of a file within a filesystem. + /// The elements are the: + /// rootname (opt), root-directory (opt), and an optional sequence of filenames. + /// The maximum number of elements in the sequence is operating system dependent. + class path + { + public: #if defined(NANA_WINDOWS) - using value_type = wchar_t; - const static value_type preferred_separator = L'\\'; + using value_type = wchar_t; + const static value_type preferred_separator = L'\\'; #else - using value_type = char; - const static value_type preferred_separator = '/'; + using value_type = char; + const static value_type preferred_separator = '/'; #endif - using string_type = std::basic_string; + using string_type = std::basic_string; - path() = default; + path() = default; - template - path(const Source& source) - { - _m_assign(source); - } + template + path(const Source &source) + { + _m_assign(source); + } - // modifiers - void clear() noexcept; - path& make_preferred(); - path& remove_filename(); - //path& replace_filename(const path& replacement); - //path& replace_extension(const path& replacement = path()); - //void swap(path& rhs) noexcept; + // modifiers + void clear() noexcept; - // 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; + path &make_preferred(); - // query - bool empty() const noexcept; - bool has_root_name() const { return !root_name().empty(); } - bool has_root_directory() const { return !root_directory().empty(); } - bool has_root_path() const { return !root_path().empty(); } - bool has_relative_path() const { return !relative_path().empty(); } - bool has_parent_path() const { return !parent_path().empty(); }; // temp;; - bool has_filename() const { return !filename().empty(); }; // temp; - //bool has_stem() const; - bool has_extension() const { return !extension().empty(); }; // temp - bool is_absolute() const; - bool is_relative() const; + path &remove_filename(); + //path& replace_filename(const path& replacement); + //path& replace_extension(const path& replacement = path()); + //void swap(path& rhs) noexcept; - int compare(const path& other) const; + // decomposition + path root_name() const; - file_type what() const; + path root_directory() const; - const value_type*c_str() const; - const string_type& native() const; - operator string_type() 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; + + bool has_root_name() const + { return !root_name().empty(); } + + bool has_root_directory() const + { return !root_directory().empty(); } + + bool has_root_path() const + { return !root_path().empty(); } + + bool has_relative_path() const + { return !relative_path().empty(); } + + bool has_parent_path() const + { return !parent_path().empty(); }; // temp;; + bool has_filename() const + { return !filename().empty(); }; // temp; + //bool has_stem() const; + bool has_extension() const + { return !extension().empty(); }; // temp + bool is_absolute() const; + + bool is_relative() const; + + int compare(const path &other) const; + + file_type what() const; + + const value_type *c_str() const; + + const string_type &native() const; + + operator string_type() const; std::string string() const; @@ -278,153 +304,178 @@ namespace nana { // std::u16string generic_u16string() const; // std::u32string generic_u32string() const; - path lexically_normal() const; + path lexically_normal() const; - //appends - path& operator/=(const path& other); + //appends + path &operator/=(const path &other); - template - path& operator/=(const Source& source) - { - path other(source); - return this->operator/=(other); - } + template + path &operator/=(const Source &source) + { + path other(source); + return this->operator/=(other); + } - template - path& append(const Source& source) - { - path other(source); - return this->operator/=(other); - } - private: - void _m_assign(const std::string& source_utf8); - void _m_assign(const std::wstring& source); - private: - string_type pathstr_; - }; + template + path &append(const Source &source) + { + path other(source); + return this->operator/=(other); + } - bool operator==(const path& lhs, const path& rhs); - bool operator!=(const path& lhs, const path& rhs); - bool operator<(const path& lhs, const path& rhs); - bool operator>(const path& lhs, const path& rhs); - path operator/(const path& lhs, const path& rhs); + private: + void _m_assign(const std::string &source_utf8); + + void _m_assign(const std::wstring &source); + + private: + string_type pathstr_; + }; + + bool operator==(const path &lhs, const path &rhs); + + bool operator!=(const path &lhs, const path &rhs); + + bool operator<(const path &lhs, const path &rhs); + + bool operator>(const path &lhs, const path &rhs); + + path operator/(const path &lhs, const path &rhs); - class filesystem_error - : public std::system_error - { - public: - explicit filesystem_error(const std::string& msg, std::error_code); + class filesystem_error + : public std::system_error + { + public: + explicit filesystem_error(const std::string &msg, std::error_code); - filesystem_error(const std::string& msg, const path& path1, std::error_code err); - filesystem_error(const std::string& msg, const path& path1, const path& path2, std::error_code err); + filesystem_error(const std::string &msg, const path &path1, std::error_code err); - const path& path1() const noexcept; - const path& path2() const noexcept; - // const char* what() const noexcept; - private: - path path1_; - path path2_; - }; + filesystem_error(const std::string &msg, const path &path1, const path &path2, std::error_code err); + + const path &path1() const noexcept; + + const path &path2() const noexcept; + // const char* what() const noexcept; + private: + path path1_; + path path2_; + }; - class directory_entry - { - public: - directory_entry() = default; - explicit directory_entry(const ::nana::experimental::filesystem::path&); + class directory_entry + { + public: + directory_entry() = default; - //modifiers - void assign(const ::nana::experimental::filesystem::path&); - void replace_filename(const ::nana::experimental::filesystem::path&); + explicit directory_entry(const filesystem::path &); - //observers - file_status status() const; - operator const filesystem::path&() const { return path_; }; - const filesystem::path& path() const; - private: - ::nana::experimental::filesystem::path path_; - }; + //modifiers + void assign(const filesystem::path &); - /// InputIterator that iterate over the sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator - class directory_iterator :public std::iterator - { - using find_handle = void*; - public: + void replace_filename(const filesystem::path &); - directory_iterator() noexcept; - explicit directory_iterator(const path& p); - directory_iterator(const path& p, directory_options opt); + //observers + file_status status() const; - const value_type& operator*() const; - const value_type* operator->() const; + operator const filesystem::path &() const + { return path_; }; - directory_iterator& operator++(); - directory_iterator operator++(int); ///< extention + const filesystem::path &path() const; - bool equal(const directory_iterator& x) const; + private: + filesystem::path path_; + }; - private: - template - static bool _m_ignore(const Char * p) - { - while(*p == '.') - ++p; - return (*p == 0); - } + /// InputIterator that iterate over the sequence of directory_entry elements representing the files in a directory, not an recursive_directory_iterator + class directory_iterator : public std::iterator + { + using find_handle = void *; + public: - void _m_prepare(const path& file_path); - void _m_read(); - private: - bool end_{false}; - path::string_type path_; - directory_options option_{ directory_options::none }; + directory_iterator() noexcept; - std::shared_ptr find_ptr_; - find_handle handle_{nullptr}; - value_type value_; - }; - /// enable directory_iterator range-based for statements - inline directory_iterator begin( directory_iterator iter) noexcept - { - return iter; - } + explicit directory_iterator(const path &p); - inline directory_iterator end( const directory_iterator&) noexcept - { - return {}; - } + directory_iterator(const path &p, directory_options opt); + + const value_type &operator*() const; + + const value_type *operator->() const; + + directory_iterator &operator++(); + + directory_iterator operator++(int); ///< extention + + bool equal(const directory_iterator &x) const; + + private: + template + static bool _m_ignore(const Char *p) + { + while (*p == '.') + ++p; + return (*p == 0); + } + + void _m_prepare(const path &file_path); + + void _m_read(); + + private: + bool end_{false}; + path::string_type path_; + directory_options option_{directory_options::none}; + + std::shared_ptr find_ptr_; + find_handle handle_{nullptr}; + value_type value_; + }; + + /// enable directory_iterator range-based for statements + inline directory_iterator begin(directory_iterator iter) noexcept + { + return iter; + } + + inline directory_iterator end(const directory_iterator &) noexcept + { + return {}; + } - //class recursive_directory_iterator; - //// enable recursive_directory_iterator range-based for statements - //recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; - //recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; + //class recursive_directory_iterator; + //// enable recursive_directory_iterator range-based for statements + //recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; + //recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; - //template - inline bool operator==(const directory_iterator/**/ & x, const directory_iterator/**/ & y) - { - return x.equal(y); - } + //template + inline bool operator==(const directory_iterator/**/ &x, const directory_iterator/**/ &y) + { + return x.equal(y); + } - //template - inline bool operator!=(const directory_iterator/**/ & x, const directory_iterator/**/ & y) - { - return !x.equal(y); - } + //template + inline bool operator!=(const directory_iterator/**/ &x, const directory_iterator/**/ &y) + { + return !x.equal(y); + } - file_status status(const path& p); - file_status status(const path& p, std::error_code&); + file_status status(const path &p); - std::uintmax_t file_size(const path& p); - std::uintmax_t file_size(const path& p, std::error_code& ec) noexcept; + file_status status(const path &p, std::error_code &); - inline bool is_directory(file_status s) noexcept - { return s.type() == file_type::directory ;} + std::uintmax_t file_size(const path &p); - bool is_directory(const path& p); - bool is_directory(const path& p, std::error_code& ec) noexcept; + std::uintmax_t file_size(const path &p, std::error_code &ec) noexcept; + + inline bool is_directory(file_status s) noexcept + { return s.type() == file_type::directory; } + + bool is_directory(const path &p); + + bool is_directory(const path &p, std::error_code &ec) noexcept; inline bool is_regular_file(file_status s) noexcept { @@ -438,67 +489,71 @@ namespace nana { // bool is_regular_file(const path& p, error_code& ec) noexcept; // todo: // Returns: is_regular_file(status(p, ec)).Returns false if an error occurs. // todo: - inline bool is_empty(const path& p) - { - auto fs = status(p); + inline bool is_empty(const path &p) + { + auto fs = status(p); - if (is_directory(fs)) - return (directory_iterator() == directory_iterator(p)); + if (is_directory(fs)) + return (directory_iterator() == directory_iterator(p)); - return (file_size(p) == 0); - } - // bool is_empty(const path& p, error_code& ec) noexcept; + return (file_size(p) == 0); + } + // bool is_empty(const path& p, 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; + 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; - /// The time of last data modification of p, determined as if by the value of the POSIX - /// stat structure member st_mtime obtained as if by POSIX stat(). - file_time_type last_write_time(const path& p); - /// returns file_time_type::min() if an error occurs - //file_time_type last_write_time(const path& p, error_code& ec) noexcept; + /// The time of last data modification of p, determined as if by the value of the POSIX + /// stat structure member st_mtime obtained as if by POSIX stat(). + file_time_type last_write_time(const path &p); + /// returns file_time_type::min() if an error occurs + //file_time_type last_write_time(const path& p, error_code& ec) noexcept; - path current_path(); - //path current_path(error_code& ec); - void current_path(const path& p); ///< chdir - //void current_path(const path& p, error_code& ec) noexcept; + path current_path(); - bool remove(const path& p); - bool remove(const path& p, std::error_code& ec); // noexcept; + //path current_path(error_code& ec); + void current_path(const path &p); ///< chdir + //void current_path(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; + bool remove(const path &p); - template - std::basic_string parent_path(const std::basic_string& path) - { - auto index = path.size(); + bool remove(const path &p, std::error_code &ec); // noexcept; - if (index) - { - auto str = path.c_str(); + //uintmax_t remove_all(const path& p); + //uintmax_t remove_all(const path& p, error_code& ec) noexcept; - for (--index; index > 0; --index) - { - auto c = str[index]; - if (c != '\\' && c != '/') - break; - } + template + std::basic_string parent_path(const std::basic_string &path) + { + auto index = path.size(); - for (--index; index > 0; --index) - { - auto c = str[index]; - if (c == '\\' || c == '/') - break; - } - } + if (index) + { + auto str = path.c_str(); + + for (--index; index > 0; --index) + { + auto c = str[index]; + if (c != '\\' && c != '/') + break; + } + + for (--index; index > 0; --index) + { + auto c = str[index]; + if (c == '\\' || c == '/') + break; + } + } return index ? path.substr(0, index + 1) : std::basic_string(); } @@ -529,28 +584,32 @@ namespace std } } - path canonical(const path& p); - path canonical(const path& p, std::error_code& err); - path weakly_canonical(const path& p); - path weakly_canonical(const path& p, std::error_code& err); -#endif - -#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW) - bool exists( std::filesystem::file_status s ) noexcept; - bool exists( const std::filesystem::path& p ); - bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept; -#endif - } -} // std #else //#if NANA_USING_NANA_FILESYSTEM //Implements the missing functions for various version of experimental/filesystem namespace std { namespace filesystem { - //Visual Studio 2017 -#if (defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) && defined(_MSC_VER) && (_MSC_VER > 1912)) || \ +#if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)) + path absolute(const path& p); + path absolute(const path& p, std::error_code& err); + + path canonical(const path& p); + path canonical(const path& p, std::error_code& err); + + path weakly_canonical(const path& p); + path weakly_canonical(const path& p, std::error_code& err); +#endif + +#if defined(NANA_MINGW) // todo ?? + bool exists( std::filesystem::file_status s ) noexcept; + bool exists( const std::filesystem::path& p ); + bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept; +#endif + + //Visual Studio 2017 +#if (defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) && defined(_MSC_VER) && (_MSC_VER > 1912)) || \ (!defined(__clang__) && defined(__GNUC__) && (__cplusplus < 201603 || (__GNUC__* 100 + __GNUC_MINOR__ < 801))) path weakly_canonical(const path& p); path weakly_canonical(const path& p, std::error_code& err); diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 2ef50604..544efe48 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -6,8 +6,8 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/filesystem/filesystem.cpp - * @description: + * @file nana/filesystem/filesystem.cpp + * @description * provide some interface for file management */ @@ -156,35 +156,34 @@ namespace nana { namespace filesystem { - //class filesystem_error - filesystem_error::filesystem_error(const std::string& msg, std::error_code err) - : std::system_error(err, msg) - {} + //class filesystem_error + filesystem_error::filesystem_error(const std::string& msg, std::error_code err) + : std::system_error(err, msg) + {} - filesystem_error::filesystem_error(const std::string& msg, const path& path1, std::error_code err) - : std::system_error(err, msg), - path1_(path1) - {} + filesystem_error::filesystem_error(const std::string& msg, const path& path1, std::error_code err) + : std::system_error(err, msg), + path1_(path1) + {} - filesystem_error::filesystem_error(const std::string& msg, const path& path1, const path& path2, std::error_code err) - : std::system_error(err, msg), - path1_(path1), - path2_(path2) - {} + filesystem_error::filesystem_error(const std::string& msg, const path& path1, const path& path2, std::error_code err) + : std::system_error(err, msg), + path1_(path1), + path2_(path2) + {} - const path& filesystem_error::path1() const noexcept - { - return path1_; - } + const path& filesystem_error::path1() const noexcept + { + return path1_; + } - const path& filesystem_error::path2() const noexcept - { - return path2_; - } - //end class filesystem_error + const path& filesystem_error::path2() const noexcept + { + return path2_; + } + //end class filesystem_error - - //Because of No wide character version of POSIX + //Because of No wide character version of POSIX #if defined(NANA_POSIX) const char* separators = "/"; const char separator = '/'; @@ -510,10 +509,10 @@ namespace filesystem return to_wstring(pathstr_); } - std::string path::u8string() const + /*std::string path::u8string() const { return to_utf8(pathstr_); - } + }*/ std::string path::generic_string() const { auto str = string(); @@ -526,12 +525,12 @@ namespace filesystem std::replace(str.begin(), str.end(), L'\\', L'/'); return str; } - std::string path::generic_u8string() const // uppss ... + /*std::string path::generic_u8string() const // uppss ... { auto str = pathstr_; std::replace(str.begin(), str.end(), '\\', '/'); // uppss ... revise this !!!!! return to_utf8(str); - } + }*/ path path::lexically_normal() const { @@ -711,112 +710,112 @@ namespace filesystem } }; - directory_iterator::directory_iterator() noexcept - : end_(true), - handle_(nullptr) - {} + directory_iterator::directory_iterator() noexcept + : end_(true), + handle_(nullptr) + {} - directory_iterator::directory_iterator(const path& file_path) - { - _m_prepare(file_path); - } + directory_iterator::directory_iterator(const path& file_path) + { + _m_prepare(file_path); + } - directory_iterator::directory_iterator(const path& p, directory_options opt): - option_(opt) - { - _m_prepare(p); - } + directory_iterator::directory_iterator(const path& p, directory_options opt): + option_(opt) + { + _m_prepare(p); + } - const directory_iterator::value_type& directory_iterator::operator*() const { return value_; } + const directory_iterator::value_type& directory_iterator::operator*() const { return value_; } - const directory_iterator::value_type* - directory_iterator::operator->() const { return &(operator*()); } + const directory_iterator::value_type* + directory_iterator::operator->() const { return &(operator*()); } - directory_iterator& directory_iterator::operator++() - { - _m_read(); return *this; - } + directory_iterator& directory_iterator::operator++() + { + _m_read(); return *this; + } - directory_iterator directory_iterator::operator++(int) - { - directory_iterator tmp = *this; - _m_read(); - return tmp; - } + directory_iterator directory_iterator::operator++(int) + { + directory_iterator tmp = *this; + _m_read(); + return tmp; + } - bool directory_iterator::equal(const directory_iterator& x) const - { - if (end_ && (end_ == x.end_)) return true; - return (value_.path().filename() == x.value_.path().filename()); - } + bool directory_iterator::equal(const directory_iterator& x) const + { + if (end_ && (end_ == x.end_)) return true; + return (value_.path().filename() == x.value_.path().filename()); + } - void directory_iterator::_m_prepare(const path& file_path) - { - path_ = file_path.native(); + void directory_iterator::_m_prepare(const path& file_path) + { + path_ = file_path.native(); #if defined(NANA_WINDOWS) - if (!path_.empty() && (path_.back() != L'/' && path_.back() != L'\\')) - path_ += L'\\'; + if (!path_.empty() && (path_.back() != L'/' && path_.back() != L'\\')) + path_ += L'\\'; - auto pat = path_; - DWORD attr = ::GetFileAttributes(pat.data()); - if ((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY)) - pat += L"*"; + auto pat = path_; + DWORD attr = ::GetFileAttributes(pat.data()); + if ((attr != INVALID_FILE_ATTRIBUTES) && (attr & FILE_ATTRIBUTE_DIRECTORY)) + pat += L"*"; - WIN32_FIND_DATAW wfd; - ::HANDLE handle = ::FindFirstFile(pat.data(), &wfd); + WIN32_FIND_DATAW wfd; + ::HANDLE handle = ::FindFirstFile(pat.data(), &wfd); - if (handle == INVALID_HANDLE_VALUE) - { - end_ = true; - return; - } + if (handle == INVALID_HANDLE_VALUE) + { + end_ = true; + return; + } - while (_m_ignore(wfd.cFileName)) - { - if (::FindNextFile(handle, &wfd) == 0) - { - end_ = true; - ::FindClose(handle); - return; - } - } + while (_m_ignore(wfd.cFileName)) + { + if (::FindNextFile(handle, &wfd) == 0) + { + end_ = true; + ::FindClose(handle); + return; + } + } - value_ = value_type(path(path_ + wfd.cFileName)); + value_ = value_type(path(path_ + wfd.cFileName)); #elif defined(NANA_POSIX) - if (path_.size() && (path_.back() != '/')) - path_ += '/'; - auto handle = opendir(path_.c_str()); - end_ = true; - if (handle) - { - struct dirent * dnt = readdir(handle); - if (dnt) - { - while (_m_ignore(dnt->d_name)) - { - dnt = readdir(handle); - if (dnt == 0) - { - closedir(handle); - return; - } - } + if (path_.size() && (path_.back() != '/')) + path_ += '/'; + auto handle = opendir(path_.c_str()); + end_ = true; + if (handle) + { + struct dirent * dnt = readdir(handle); + if (dnt) + { + while (_m_ignore(dnt->d_name)) + { + dnt = readdir(handle); + if (dnt == 0) + { + closedir(handle); + return; + } + } - value_ = value_type(path_ + dnt->d_name); - end_ = false; - } - } + value_ = value_type(path_ + dnt->d_name); + end_ = false; + } + } #endif - if (false == end_) - { - find_ptr_ = std::shared_ptr(new find_handle(handle), inner_handle_deleter()); - handle_ = handle; - } - } + if (false == end_) + { + find_ptr_ = std::shared_ptr(new find_handle(handle), inner_handle_deleter()); + handle_ = handle; + } + } - void directory_iterator::_m_read() + void directory_iterator::_m_read() { if (handle_) { @@ -976,7 +975,6 @@ namespace filesystem #endif }//end namespace detail - file_status status(const path& p) { std::error_code err; @@ -1106,93 +1104,290 @@ namespace filesystem return dateTime; } - bool create_directory(const path& p) - { + bool create_directory(const path& p) + { #if defined(NANA_WINDOWS) - return (FALSE != ::CreateDirectoryW(p.c_str(), 0)); + return (FALSE != ::CreateDirectoryW(p.c_str(), 0)); #elif defined(NANA_POSIX) - return (0 == ::mkdir(p.c_str(), static_cast(perms::all))); + return (0 == ::mkdir(p.c_str(), static_cast(perms::all))); #endif - } + } - bool remove(const path& p) - { - auto stat = status(p); - if (stat.type() == file_type::directory) - return detail::rm_dir(p); + bool remove(const path& p) + { + auto stat = status(p); + if (stat.type() == file_type::directory) + return detail::rm_dir(p); - return detail::rm_file(p); - } + return detail::rm_file(p); + } - bool remove(const path& p, std::error_code & ec) - { - ec.clear(); - auto stat = status(p); - if (stat.type() == file_type::directory) - return detail::rm_dir(p); + bool remove(const path& p, std::error_code & ec) + { + ec.clear(); + auto stat = status(p); + if (stat.type() == file_type::directory) + return detail::rm_dir(p); - return detail::rm_file(p); - } + return detail::rm_file(p); + } - path current_path() - { + path current_path() + { #if defined(NANA_WINDOWS) - wchar_t buf[MAX_PATH]; - DWORD len = ::GetCurrentDirectoryW(MAX_PATH, buf); - if (len) - { - if (len > MAX_PATH) - { - wchar_t * p = new wchar_t[len + 1]; - ::GetCurrentDirectoryW(len + 1, p); - std::wstring s = p; - delete[] p; - return s; - } - return buf; - } + wchar_t buf[MAX_PATH]; + DWORD len = ::GetCurrentDirectoryW(MAX_PATH, buf); + if (len) + { + if (len > MAX_PATH) + { + wchar_t * p = new wchar_t[len + 1]; + ::GetCurrentDirectoryW(len + 1, p); + std::wstring s = p; + delete[] p; + return s; + } + return buf; + } #elif defined(NANA_POSIX) - char buf[260]; - auto pstr = ::getcwd(buf, 260); - if (pstr) - return pstr; + char buf[260]; + auto pstr = ::getcwd(buf, 260); + if (pstr) + return pstr; - int bytes = 260 + 260; - while (ERANGE == errno) - { - std::unique_ptr buf(new char[bytes]); - auto pstr = ::getcwd(buf.get(), bytes); - if (pstr) - return path(pstr); + int bytes = 260 + 260; + while (ERANGE == errno) + { + std::unique_ptr buf(new char[bytes]); + auto pstr = ::getcwd(buf.get(), bytes); + if (pstr) + return path(pstr); - bytes += 260; - } + bytes += 260; + } #endif - return path(); - } + return path(); + } - void current_path(const path& p) - { + void current_path(const path& p) + { #if defined(NANA_WINDOWS) - ::SetCurrentDirectoryW(p.c_str()); + ::SetCurrentDirectoryW(p.c_str()); #elif defined(NANA_POSIX) - ::chdir(p.c_str()); + ::chdir(p.c_str()); #endif - } + } -#ifndef CXX_NO_INLINE_NAMESPACE - } //end namespace v1 + path absolute(const path& p) + { + if (p.empty()) + return p; + + auto abs_base = current_path(); + + // store expensive to compute values that are needed multiple times + path p_root_name(p.root_name()); + path base_root_name(abs_base.root_name()); + path p_root_directory(p.root_directory()); + + if (!p_root_name.empty()) // p.has_root_name() + { + if (p_root_directory.empty()) // !p.has_root_directory() + return p_root_name / abs_base.root_directory() + / abs_base.relative_path() / p.relative_path(); + // p is absolute, so fall through to return p at end of block + } + else if (!p_root_directory.empty()) // p.has_root_directory() + { +#ifdef NANA_POSIX + // POSIX can have root name it it is a network path + if (base_root_name.empty()) // !abs_base.has_root_name() + return p; #endif - }//end namespace filesystem - } //end namespace experimental + return base_root_name / p; + } + else + return abs_base / p; + + return p; // p.is_absolute() is true + } + + path absolute(const path& p, std::error_code& /*err*/) + { + return absolute(p); + } + + path canonical(const path& p, std::error_code* err) + { + path source(p.is_absolute() ? p : absolute(p)); + path root(source.root_path()); + path result; + + std::error_code local_ec; + file_status stat(status(source, local_ec)); + + if (stat.type() == file_type::not_found) + { + if (nullptr == err) + throw (filesystem_error( + "nana::filesystem::canonical", source, + std::error_code(static_cast(std::errc::no_such_file_or_directory), std::generic_category()))); + err->assign(static_cast(std::errc::no_such_file_or_directory), std::generic_category()); + return result; + } + else if (local_ec) + { + if (nullptr == err) + throw (filesystem_error( + "nana::filesystem::canonical", source, local_ec)); + *err = local_ec; + return result; + } + + + auto tmp_p = source; + + std::vector source_elements; + while (tmp_p != root) + { + source_elements.emplace(source_elements.begin(), tmp_p.filename()); + tmp_p.remove_filename(); + } + + result = root; + + for(auto & e : source_elements) + { + auto str = e.string(); + if("." == str) + continue; + else if(".." == str) + { + if(result != root) + result.remove_filename(); + continue; + } + + result /= e; + } + + if (err) + err->clear(); + + return result; + } + + path canonical(const path& p) + { + return canonical(p, nullptr); + } + + path canonical(const path& p, std::error_code& err) + { + return canonical(p, &err); + } + + bool try_throw(int err_val, const path& p, std::error_code* ec, const char* message) + { + if (0 == err_val) + { + if (ec) ec->clear(); + } + else + { //error + if (nullptr == ec) + throw (filesystem_error( + message, p, + std::error_code(err_val, std::generic_category()))); + else + ec->assign(err_val, std::system_category()); + } + return err_val != 0; + } + + path weakly_canonical(const path& p, std::error_code* err) + { + path head{ p }; + + std::error_code tmp_err; + std::vector elements; + while (!head.empty()) + { + auto head_status = status(head, tmp_err); + + if (head_status.type() == file_type::unknown) + { + if (try_throw(static_cast(std::errc::invalid_argument), head, err, "nana::filesystem::weakly_canonical")) + return path{}; + } + if (head_status.type() != file_type::not_found) + break; + + elements.emplace_back(head.filename()); + head.remove_filename(); + } + + bool tail_has_dots = false; + path tail; + + for (auto & e : elements) + { + tail /= e; + // for a later optimization, track if any dot or dot-dot elements are present + if (e.native().size() <= 2 + && e.native()[0] == '.' + && (e.native().size() == 1 || e.native()[1] == '.')) + tail_has_dots = true; + } + + if (head.empty()) + return p.lexically_normal(); + head = canonical(head, tmp_err); + if (try_throw(tmp_err.value(), head, err, "nana::filesystem::weakly_canonical")) + return path(); + return tail.empty() + ? head + : (tail_has_dots // optimization: only normalize if tail had dot or dot-dot element + ? (head / tail).lexically_normal() + : head / tail); + } + + path weakly_canonical(const path& p) + { + return weakly_canonical(p, nullptr); + } + + path weakly_canonical(const path& p, std::error_code& err) + { + return weakly_canonical(p, &err); + } + + bool exists( std::filesystem::file_status s ) noexcept + { + return s.type() != file_type::not_found; + } + + bool exists( const std::filesystem::path& p ) + { + return exists(status(p)); + } + + bool exists( const std::filesystem::path& p, std::error_code& ec ) noexcept + { + return exists(status(p, ec)); + } + + + } //end namespace filesystem }//end namespace nana +#else namespace std { namespace filesystem { -#if defined(NANA_FILESYSTEM_FORCE) || \ - (defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703))) +#if defined(_MSC_VER) && ((!defined(_MSVC_LANG)) || (_MSVC_LANG < 201703)) + path absolute(const path& p) { if (p.empty()) @@ -1377,8 +1572,8 @@ namespace std return weakly_canonical(p, &err); } #endif - -#if defined(NANA_FILESYSTEM_FORCE) || defined(NANA_MINGW) +/* +#if defined(NANA_MINGW) bool exists( std::filesystem::file_status s ) noexcept { return s.type() != file_type::not_found; @@ -1393,17 +1588,10 @@ namespace std { return exists(status(p, ec)); } -#endif - }//end namespace filesystem +*/ + }//end namespace filesystem }//end namespace std -#else //else NANA_USING_NANA_FILESYSTEM - - //Defines the functions that are not provided by experimental/filesystem - namespace std - { - namespace filesystem - { #if (defined(NANA_USING_STD_EXPERIMENTAL_FILESYSTEM) && defined(_MSC_VER) && (_MSC_VER > 1912)) || \ (!defined(__clang__) && defined(__GNUC__) && (__cplusplus < 201603 || (__GNUC__* 100 + __GNUC_MINOR__ < 801))) diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index f2417087..63586abd 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -1522,7 +1522,7 @@ namespace nana if (!*str) { targets.emplace_back(parent_path); - impl_->path = parent_path.parent_path().u8string(); + impl_->path = parent_path.parent_path().string(); } else { @@ -1532,7 +1532,7 @@ namespace nana targets.emplace_back(parent_path / path_type{str}); str += (len + 1); } - impl_->path = parent_path.u8string(); + impl_->path = parent_path.string(); } } else @@ -1540,7 +1540,7 @@ namespace nana wfile.resize(std::wcslen(wfile.data())); targets.emplace_back(wfile); - impl_->path = targets.front().parent_path().u8string(); + impl_->path = targets.front().parent_path().string(); } #elif defined(NANA_POSIX) diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 4d4ffc36..60fbaf23 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -1267,7 +1267,7 @@ namespace nana auto files = impl->fbox.show(); if(!files.empty()) { - impl->value = files.front().u8string(); + impl->value = files.front().string(); impl->path_edit.caption(impl->value); } });