diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 864f9608..2acd5a46 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -55,25 +56,27 @@ namespace nana { namespace experimental { 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. - unknown = 0xFFFF ///< not known, such as when a file_status object is created without specifying the permissions - }; + 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; @@ -96,35 +99,28 @@ namespace filesystem uintmax_t free; uintmax_t available; }; - using file_time_type = std::chrono::time_point< std::chrono::system_clock>;// trivial-clock> ; - class file_status - { - file_type m_ft = file_type::none; - perms m_prms = perms::unknown; + using file_time_type = std::chrono::time_point< std::chrono::system_clock>;// trivial-clock> ; - public: - explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown) - :m_ft{ft}, m_prms{prms} - {} + class file_status + { + file_type m_ft = file_type::none; + perms m_prms = perms::unknown; - file_status(const file_status& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; - file_status(file_status&& fs) : m_ft{fs.m_ft}, m_prms{fs.m_prms}{} // = default; + public: + explicit file_status(file_type ft = file_type::none, perms prms = perms::unknown); - ~file_status(){}; - file_status& operator=(const file_status&) = default; - file_status& operator=(file_status&&fs) // = default; - { - m_ft=fs.m_ft; m_prms = fs.m_prms; - return *this; - } - // observers - file_type type() const { return m_ft;} - perms permissions() const { return m_prms;} - // modifiers - void type (file_type ft) { m_ft=ft ;} - void permissions(perms prms) { m_prms = prms; } - }; + // observers + file_type type() const; + perms permissions() const; + + // 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 @@ -418,11 +414,11 @@ namespace filesystem } - // file_status status(const path& p); + file_status status(const path& p); bool file_attrib(const nana::string& file, attribute&); inline bool is_directory(file_status s) { return s.type() == file_type::directory ;} - inline bool is_directory(const path& p) { return directory_iterator(p)->attr.directory; }//works?? + bool is_directory(const path& p); inline bool is_directory(const directory_entry& d) { return d.attr.directory; } //bool is_directory(const path& p, error_code& ec) noexcept; @@ -436,35 +432,34 @@ namespace filesystem } //bool is_empty(const path& p, error_code& ec) noexcept; - uintmax_t file_size(const nana::string& file); // deprecate? - inline uintmax_t file_size(const path& p){return file_size(p.filename());} - //uintmax_t file_size(const path& p, error_code& ec) noexcept; + std::uintmax_t file_size(const path& p); + //uintmax_t file_size(const path& p, error_code& ec) noexcept; //long long filesize(const nana::string& file); - 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_directory(const std::wstring& p, bool & if_exist); + 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_directory(const std::wstring& p, bool & if_exist); //deprecated inline bool create_directory(const path& p, bool & if_exist) { return create_directory(p.filename(), if_exist); - }; - - bool modified_file_time(const std::wstring& file, struct tm&); - - + } + */ + + bool modified_file_time(const std::wstring& file, struct tm&); path path_user(); - - 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; - //nana::string path_current(); + 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; + //nana::string path_current(); //bool remove(const path& p); diff --git a/include/nana/filesystem/fs_utility.hpp b/include/nana/filesystem/fs_utility.hpp index fa961dce..8723a5f4 100644 --- a/include/nana/filesystem/fs_utility.hpp +++ b/include/nana/filesystem/fs_utility.hpp @@ -25,9 +25,9 @@ namespace filesystem }; bool file_attrib(const ::std::string& file, attribute&); - long long filesize(const nana::string& file); + //long long filesize(const nana::string& file); //deprecated - bool mkdir(const ::std::string& dir, bool & if_exist); + //bool mkdir(const ::std::string& dir, bool & if_exist); //deprecated bool modified_file_time(const ::std::string& file, struct tm&); std::wstring path_user(); @@ -37,6 +37,7 @@ namespace filesystem bool rmdir(const char* dir, bool fails_if_not_empty); nana::string root(const nana::string& path); + /* class path { public: @@ -59,6 +60,7 @@ namespace filesystem std::string text_; #endif }; + */ }//end namespace filesystem }//end namespace nana diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 69270d73..5567fa07 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -36,160 +36,184 @@ #include #endif -namespace nana { - namespace experimental +namespace nana { namespace experimental { + namespace filesystem { - namespace filesystem - { - //Because of No wide character version of POSIX + //Because of No wide character version of POSIX #if defined(NANA_LINUX) || defined(NANA_MACOS) - const char* splstr = "/"; + const char* splstr = "/"; #else - const wchar_t* splstr = L"/\\"; + const wchar_t* splstr = L"/\\"; #endif - //class path - path::path() {} + //class file_status + file_status::file_status(file_type ft, perms prms) + : value_{ft}, perms_{prms} + {} - int path::compare(const path& p) const - { - return pathstr_.compare(p.pathstr_); - } + file_type file_status::type() const + { + return value_; + } - bool path::empty() const - { + void file_status::type(file_type ft) + { + value_ = ft; + } + + perms file_status::permissions() const + { + return perms_; + } + + void file_status::permissions(perms prms) + { + perms_ = prms; + } + //end filestatus + + //class path + path::path() {} + + int path::compare(const path& p) const + { + return pathstr_.compare(p.pathstr_); + } + + bool path::empty() const + { #if defined(NANA_WINDOWS) - return (::GetFileAttributes(pathstr_.c_str()) == INVALID_FILE_ATTRIBUTES); + return (::GetFileAttributes(pathstr_.c_str()) == INVALID_FILE_ATTRIBUTES); #elif defined(NANA_LINUX) || defined(NANA_MACOS) - struct stat sta; - return (::stat(pathstr_.c_str(), &sta) == -1); + struct stat sta; + return (::stat(pathstr_.c_str(), &sta) == -1); #endif - } + } - path path::extension() const - { + path path::extension() const + { #if defined(NANA_WINDOWS) - auto pos = pathstr_.find_last_of(L"\\/."); + auto pos = pathstr_.find_last_of(L"\\/."); #else - auto pos = pathstr_.find_last_of("\\/."); + auto pos = pathstr_.find_last_of("\\/."); #endif - if ((pos == pathstr_.npos) || (pathstr_[pos] != '.')) - return path(); + if ((pos == pathstr_.npos) || (pathstr_[pos] != '.')) + return path(); - if (pos + 1 == pathstr_.size()) - return path(); + if (pos + 1 == pathstr_.size()) + return path(); - return path(pathstr_.substr(pos)); - } + return path(pathstr_.substr(pos)); + } - path path::parent_path() const - { - return{filesystem::parent_path(pathstr_)}; - } + path path::parent_path() const + { + return{filesystem::parent_path(pathstr_)}; + } - file_type path::what() const - { + file_type path::what() const + { #if defined(NANA_WINDOWS) - unsigned long attr = ::GetFileAttributes(pathstr_.c_str()); - if (INVALID_FILE_ATTRIBUTES == attr) - return file_type::not_found; //?? + unsigned long attr = ::GetFileAttributes(pathstr_.c_str()); + if (INVALID_FILE_ATTRIBUTES == attr) + return file_type::not_found; //?? - if (FILE_ATTRIBUTE_DIRECTORY & attr) - return file_type::directory; + if (FILE_ATTRIBUTE_DIRECTORY & attr) + return file_type::directory; - return file_type::regular; + return file_type::regular; #elif defined(NANA_LINUX) || defined(NANA_MACOS) - struct stat sta; - if (-1 == ::stat(pathstr_.c_str(), &sta)) - return file_type::not_found; //?? + struct stat sta; + if (-1 == ::stat(pathstr_.c_str(), &sta)) + return file_type::not_found; //?? - if ((S_IFDIR & sta.st_mode) == S_IFDIR) - return file_type::directory; + if ((S_IFDIR & sta.st_mode) == S_IFDIR) + return file_type::directory; - if ((S_IFREG & sta.st_mode) == S_IFREG) - return file_type::regular; + if ((S_IFREG & sta.st_mode) == S_IFREG) + return file_type::regular; - return file_type::none; + return file_type::none; #endif - } + } - path path::filename() const + path path::filename() const + { + auto pos = pathstr_.find_last_of(splstr); + if (pos != pathstr_.npos) { - auto pos = pathstr_.find_last_of(splstr); - if (pos != pathstr_.npos) + if (pos + 1 == pathstr_.size()) { - if (pos + 1 == pathstr_.size()) - { - value_type tmp[2] = {preferred_separator, 0}; + value_type tmp[2] = {preferred_separator, 0}; - if (pathstr_.npos != pathstr_.find_last_not_of(splstr, pos)) - tmp[0] = '.'; + if (pathstr_.npos != pathstr_.find_last_not_of(splstr, pos)) + tmp[0] = '.'; - return{ tmp }; - } - return{ pathstr_.substr(pos + 1) }; + return{ tmp }; } - - return{ pathstr_ }; + return{ pathstr_.substr(pos + 1) }; } - const path::value_type* path::c_str() const - { - return native().c_str(); - } + return{ pathstr_ }; + } - const path::string_type& path::native() const - { - return pathstr_; - } + const path::value_type* path::c_str() const + { + return native().c_str(); + } + + const path::string_type& path::native() const + { + return pathstr_; + } - path::operator string_type() const - { - return native(); - } + path::operator string_type() const + { + return native(); + } - void path::_m_assign(const std::string& source_utf8) - { + void path::_m_assign(const std::string& source_utf8) + { #if defined(NANA_WINDOWS) - pathstr_ = utf8_cast(source_utf8); + pathstr_ = utf8_cast(source_utf8); #else - pathstr_ = source_utf8; + pathstr_ = source_utf8; #endif - } + } - void path::_m_assign(const std::wstring& source) - { + void path::_m_assign(const std::wstring& source) + { #if defined(NANA_WINDOWS) - pathstr_ = source; + pathstr_ = source; #else - pathstr_ = utf8_cast(source); + pathstr_ = utf8_cast(source); #endif - } - //end class path + } + //end class path - bool operator==(const path& lhs, const path& rhs) - { - return (lhs.compare(rhs) == 0); - } + bool operator==(const path& lhs, const path& rhs) + { + return (lhs.compare(rhs) == 0); + } - bool operator!=(const path& lhs, const path& rhs) - { - return (lhs.native() != rhs.native()); - } + bool operator!=(const path& lhs, const path& rhs) + { + return (lhs.native() != rhs.native()); + } - bool operator<(const path& lhs, const path& rhs) - { - return (lhs.compare(rhs) < 0); - } + bool operator<(const path& lhs, const path& rhs) + { + return (lhs.compare(rhs) < 0); + } - bool operator>(const path& lhs, const path& rhs) - { - return (rhs.compare(lhs) < 0); - } + bool operator>(const path& lhs, const path& rhs) + { + return (rhs.compare(lhs) < 0); + } - namespace detail - { + namespace detail + { //rm_dir_recursive //@brief: remove a directory, if it is not empty, recursively remove it's subfiles and sub directories template @@ -257,6 +281,51 @@ namespace nana { #endif }//end namespace detail + file_status status(const path& p) + { +#if defined(NANA_WINDOWS) + auto attr = ::GetFileAttributesW(p.c_str()); + if(INVALID_FILE_ATTRIBUTES == attr) + return file_status{file_type::unknown}; + + return file_status{(FILE_ATTRIBUTE_DIRECTORY & attr) ? file_type::directory : file_type::regular, perms::all}; +#elif defined(NANA_POSIX) + struct stat path_stat; + if(0 != ::stat(p.c_str(), &path_stat)) + { + if(errno == ENOENT || errno == ENOTDIR) + return file_status{file_type::not_found}; + + return file_status{file_type::unknown}; + } + + auto prms = static_cast(path_stat.st_mode & static_cast(perms::mask)); + + if(S_ISREG(path_stat.st_mode)) + return file_status{file_type::regular, prms}; + + if(S_ISDIR(path_stat.st_mode)) + return file_status{file_type::directory, prms}; + + if(S_ISLNK(path_stat.st_mode)) + return file_status{file_type::symlink, prms}; + + if(S_ISBLK(path_stat.st_mode)) + return file_status{file_type::block, prms}; + + if(S_ISCHR(path_stat.st_mode)) + return file_status{file_type::character, prms}; + + if(S_ISFIFO(path_stat.st_mode)) + return file_status{file_type::fifo, prms}; + + if(S_ISSOCK(path_stat.st_mode)) + return file_status{file_type::socket, prms}; + + return file_status{file_type::unknown}; +#endif + } + bool file_attrib(const nana::string& file, attribute& attr) { #if defined(NANA_WINDOWS) @@ -284,7 +353,12 @@ namespace nana { return false; } - uintmax_t file_size(const nana::string& file) + bool is_directory(const path& p) + { + return (status(p).type() == file_type::directory); + } + + std::uintmax_t file_size(const path& p) { #if defined(NANA_WINDOWS) //Some compilation environment may fail to link to GetFileSizeEx @@ -292,7 +366,7 @@ namespace nana { GetFileSizeEx_fptr_t get_file_size_ex = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("Kernel32.DLL"), "GetFileSizeEx")); if (get_file_size_ex) { - HANDLE handle = ::CreateFile(file.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + HANDLE handle = ::CreateFile(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (INVALID_HANDLE_VALUE != handle) { LARGE_INTEGER li; @@ -304,26 +378,21 @@ namespace nana { } } return 0; -#elif defined(NANA_LINUX) - FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); +#elif defined(NANA_POSIX) + FILE * stream = ::fopen(p.c_str(), "rb"); long long size = 0; if (stream) { +# if defined(NANA_LINUX) fseeko64(stream, 0, SEEK_END); size = ftello64(stream); - fclose(stream); - } - return size; -#elif defined(NANA_MACOS) - FILE * stream = ::fopen(static_cast(nana::charset(file)).c_str(), "rb"); - long long size = 0; - if (stream) - { +# elif defined(NANA_MACOS) fseeko(stream, 0, SEEK_END); size = ftello(stream); - fclose(stream); +# endif + ::fclose(stream); } - return size; + return size; #endif } @@ -361,7 +430,18 @@ namespace nana { return false; } - bool create_directory(const std::wstring& path, bool & if_exist) + + bool create_directory(const path& p) + { +#if defined(NANA_WINDOWS) + return (FALSE != ::CreateDirectoryW(p.c_str(), 0)); +#elif defined(NANA_POSIX) + return (0 == ::mkdir(p.c_str(), static_cast(perms::all))); +#endif + } + + /* + bool create_directory(const std::wstring& path, bool & if_exist) //deprecated { if_exist = false; if (path.size() == 0) return false; @@ -411,7 +491,7 @@ namespace nana { } return mkstat; } - + */ bool rmfile(const path& p) { diff --git a/source/filesystem/fs_utility.cpp b/source/filesystem/fs_utility.cpp index 885c9305..0af2c6d3 100644 --- a/source/filesystem/fs_utility.cpp +++ b/source/filesystem/fs_utility.cpp @@ -47,10 +47,11 @@ namespace filesystem typedef std::string string_t; const char* splstr = "/\\"; #else - typedef nana::string string_t; - const nana::char_t* splstr = L"/\\"; + typedef std::wstring string_t; + const wchar_t* splstr = L"/\\"; #endif + /* //class path path::path(){} @@ -122,7 +123,7 @@ namespace filesystem #endif } //end class path - + */ namespace detail { @@ -219,7 +220,8 @@ namespace filesystem return false; } - long long filesize(const std::string& file) + /* + long long filesize(const std::string& file) //deprecated { #if defined(NANA_WINDOWS) //Some compilation environment may fail to link to GetFileSizeEx @@ -256,6 +258,7 @@ namespace filesystem return size; #endif } + */ bool modified_file_time(const ::std::string& file, struct tm& t) { @@ -291,7 +294,8 @@ namespace filesystem return false; } - bool mkdir(const std::string& path, bool & if_exist) + /* + bool mkdir(const std::string& path, bool & if_exist) //deprecated { if_exist = false; if(path.size() == 0) return false; @@ -341,6 +345,7 @@ namespace filesystem } return mkstat; } + */ bool rmfile(const char* file) { diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index 22a322ae..a10e3fdc 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #if defined(NANA_WINDOWS) #include @@ -644,9 +645,30 @@ namespace nana mb(); return; } - + + using file_type = nana::experimental::filesystem::file_type; + + experimental::filesystem::path fspath(fb_.addr_.filesystem + path); + + auto fs = experimental::filesystem::status(fspath); + + if(fs.type() != file_type::not_found && fs.type() != file_type::none) + { + mb<