diff --git a/.travis.yml b/.travis.yml index 09209bba..82e8fd42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,7 @@ matrix: before_install: - cd .. - - git clone --depth=1 --branch=master https://github.com/qPCR4vir/nana-demo.git nana-demo + - git clone --depth=1 --branch=hotfix https://github.com/qPCR4vir/nana-demo.git nana-demo - export PATH="$HOME/bin:$PATH" - wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.12/cmake-3.12.0-rc3-Linux-x86_64.sh || true - chmod -R +x /tmp/tools diff --git a/CMakeLists.txt b/CMakeLists.txt index 69e1de1d..a7d0167a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ # cmake 3.12 have more better modern c++ support cmake_minimum_required(VERSION 3.12 FATAL_ERROR) -project(nana VERSION 1.7.1 +project(nana VERSION 1.7.2 DESCRIPTION "C++ GUI library" HOMEPAGE_URL http://nanapro.org LANGUAGES CXX ) @@ -116,7 +116,7 @@ option(NANA_CMAKE_ENABLE_MINGW_STD_THREADS_WITH_MEGANZ "replaced boost.thread wi ######## Nana options -target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ? +target_compile_definitions(nana PRIVATE NANA_IGNORE_CONF) # really ?? if(NANA_CMAKE_AUTOMATIC_GUI_TESTING) target_compile_definitions(nana PUBLIC NANA_AUTOMATIC_GUI_TESTING) # todo: enable_testing() # ?? diff --git a/build/cmake/select_filesystem.cmake b/build/cmake/select_filesystem.cmake index 7b2163de..a4729484 100644 --- a/build/cmake/select_filesystem.cmake +++ b/build/cmake/select_filesystem.cmake @@ -1,30 +1,36 @@ # The ISO C++ File System Technical Specification (ISO-TS, or STD) was optional. # http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf # It is part of c++17. -# The library may be not available or working correctly in the std library in use. As a workaround we may try +# The library may be not available or working correctly in the std library you use. As a workaround we may try # to "implement" it (ab)using Boost (almost compatible) # http://www.boost.org/doc/libs/1_60_0/libs/filesystem/doc/index.htm # or you can choose to use the (partial, but functional) implementation provided by nana. # If you include the file or -# the selected option will be set by nana into std::filesystem -# By default Nana will try to use the STD. If STD is not available and NANA_CMAKE_FIND_BOOST_FILESYSTEM -# is set to ON nana will try to use boost if available. Nana own implementation will be use if none of -# the previus were selected or available. +# the selected option will be inlined by nana into std::filesystem +# By default Nana will try to use the STD. If STD is not available Nana own implementation will be used. # You can change that default if you change one of the following # (please don't define more than one of the _XX_FORCE options): option(NANA_CMAKE_NANA_FILESYSTEM_FORCE "Force nana filesystem over ISO and boost?" OFF) option(NANA_CMAKE_STD_FILESYSTEM_FORCE "Use of STD filesystem?(a compilation error will ocurre if not available)" OFF) option(NANA_CMAKE_BOOST_FILESYSTEM_FORCE "Force use of Boost filesystem if available (over STD)?" OFF) -option(NANA_CMAKE_FIND_BOOST_FILESYSTEM "Search: Is Boost filesystem available?" OFF) +set (TEST_FS_LIB OFF) + if(NANA_CMAKE_NANA_FILESYSTEM_FORCE) + if(NANA_CMAKE_STD_FILESYSTEM_FORCE) + message (FATAL_ERROR "Defined NANA_CMAKE_NANA_FILESYSTEM_FORCE and NANA_CMAKE_STD_FILESYSTEM_FORCE") + endif() + if(NANA_CMAKE_BOOST_FILESYSTEM_FORCE) + message (FATAL_ERROR "Defined NANA_CMAKE_NANA_FILESYSTEM_FORCE and NANA_CMAKE_BOOST_FILESYSTEM_FORCE") + endif() + target_compile_definitions(nana PUBLIC NANA_FILESYSTEM_FORCE) -elseif(NANA_CMAKE_STD_FILESYSTEM_FORCE) - target_compile_definitions(nana PUBLIC STD_FILESYSTEM_FORCE) - target_link_libraries (nana PUBLIC stdc++fs) - elseif(NANA_CMAKE_BOOST_FILESYSTEM_FORCE) + if(NANA_CMAKE_STD_FILESYSTEM_FORCE) + message (FATAL_ERROR "Defined NANA_CMAKE_BOOST_FILESYSTEM_FORCE and NANA_CMAKE_STD_FILESYSTEM_FORCE") + endif() + target_compile_definitions(nana PUBLIC BOOST_FILESYSTEM_FORCE) # https://cmake.org/cmake/help/git-master/module/FindBoost.html # Implicit dependencies such as Boost::filesystem requiring Boost::system will be automatically detected and satisfied, @@ -43,14 +49,101 @@ elseif(NANA_CMAKE_BOOST_FILESYSTEM_FORCE) set(Boost_USE_STATIC_RUNTIME ON) else() - # todo test for std (for now just force nana or boost if there no std) - target_link_libraries (nana PUBLIC stdc++fs) - # todo if not test for boost - # if not add nana filesystem + if(NANA_CMAKE_STD_FILESYSTEM_FORCE) + target_compile_definitions(nana PUBLIC STD_FILESYSTEM_FORCE) + endif() + + check_include_file_cxx (filesystem NANA_HAVE_FILESYSTEM) + check_include_file_cxx (experimental/filesystem NANA_HAVE_EXP_FILESYSTEM) + + if (NANA_HAVE_FILESYSTEM) + message (STATUS "C++ Filesystem header: ") + set (TEST_FS_LIB ON) + set (CXXSTD_FS_TEST_SOURCE + "#include + int main() + { + std::filesystem::path p{\"\tmp/\"}; + throw std::filesystem::filesystem_error(\"Empty file name!\", std::make_error_code(std::errc::invalid_argument)); + }") + elseif (NANA_HAVE_EXP_FILESYSTEM) + message (STATUS "C++ Filesystem header: ") + set (TEST_FS_LIB ON) + set (CXXSTD_FS_TEST_SOURCE + "#include + int main() + { + std::experimental::filesystem::path p{\"/tmp/\"}; + throw std::experimental::filesystem::filesystem_error(\"Empty file name!\", std::make_error_code(std::errc::invalid_argument)); + }") + else () + message (WARNING "No std::filesystem include file found: nana::filesystem will be used. + Set NANA_CMAKE_NANA_FILESYSTEM_FORCE to ON to avoid this warning.") + target_compile_definitions(nana PUBLIC STD_FILESYSTEM_NOT_SUPPORTED) + set (TEST_FS_LIB OFF) + endif () + + if (TEST_FS_LIB) + include (FindPackageMessage) + include (CheckIncludeFileCXX) + include (CheckCXXSourceCompiles) + # CMAKE_REQUIRED_FLAGS = string of compile command line flags + # CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar) + # CMAKE_REQUIRED_INCLUDES = list of include directories + set (CMAKE_REQUIRED_INCLUDES ${CMAKE_INCLUDE_PATH}) + set (CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS}) + set (CMAKE_REQUIRED_FLAGS_ORIGINAL ${CMAKE_REQUIRED_FLAGS}) + + set (CXXSTD_TEST_SOURCE + "#if !defined (__cplusplus) || (__cplusplus < 201703L) + #error NOCXX17 + #endif + int main() {}") + + check_cxx_source_compiles ("${CXXSTD_TEST_SOURCE}" CXX17_BUILTIN) + + if (CXX17_BUILTIN) + message (STATUS "C++ Standard-17 support: builtin") + else () + set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_ORIGINAL} -std=c++17") + check_cxx_source_compiles ("${CXXSTD_TEST_SOURCE}" CXX17_FLAG) + if (CXX17_FLAG) + message (STATUS "C++ Standard-17 support: via -std=c++17") + else () + message (WARNING "nana requires C++17??, but your compiler does not support it.") + endif () + endif () + + set (CMAKE_REQUIRED_LIBRARIES_ORIGINAL ${CMAKE_REQUIRED_LIBRARIES}) + check_cxx_source_compiles ("${CXXSTD_TEST_SOURCE}" C++17FS_FLAG) + + if (C++17FS_FLAG) + message (STATUS "C++ Filesystem library: builtin") + else () + set (C++17FS_LIB "") + foreach (_LIB stdc++fs) + set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_ORIGINAL} ${_LIB}) + check_cxx_source_compiles ("${CXXSTD_FS_TEST_SOURCE}" C++17FS_LIB-l${_LIB}) + message (STATUS "C++ Filesystem library: testing -l${_LIB}") + if (C++17FS_LIB-l${_LIB}) + target_link_libraries (nana PUBLIC ${_LIB}) + message (STATUS "C++ Filesystem library: via -l${_LIB}") + set (C++17FS_LIB ${_LIB}) + break () + endif () + set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_ORIGINAL}) + endforeach () + + if (C++17FS_LIB) + message (STATUS "C++ Filesystem library: via -l${C++17FS_LIB}") + else () + message (WARNING "No std::filesystem library found: nana::filesystem will be used. + Set NANA_CMAKE_NANA_FILESYSTEM_FORCE to ON to avoid this warning.") + target_compile_definitions(nana PUBLIC STD_FILESYSTEM_NOT_SUPPORTED) + endif () + endif () + endif () endif() - - - diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 8aab0cea..4219e449 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -9,7 +9,7 @@ * * @file nana/filesystem/filesystem.hpp * @author Ariel Vina-Rodriguez, Jinhao - * @brief Mimic std::experimental::filesystem::v1 (boost v3) + * @brief Mimic std::filesystem * and need VC2015 or a C++11 compiler. With a few correction can be compiler by VC2013 */ @@ -34,32 +34,26 @@ //Filesystem Selection #include -#if defined(NANA_USING_NANA_FILESYSTEM) || defined(NANA_USING_STD_FILESYSTEM) || defined(NANA_USING_BOOST_FILESYSTEM) -#undef NANA_USING_NANA_FILESYSTEM -#undef NANA_USING_STD_FILESYSTEM -#undef NANA_USING_BOOST_FILESYSTEM -#endif - #define NANA_USING_NANA_FILESYSTEM 0 #define NANA_USING_STD_FILESYSTEM 0 #define NANA_USING_BOOST_FILESYSTEM 0 -#if (defined(NANA_FILESYSTEM_FORCE) || ( (defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(BOOST_FILESYSTEM_AVAILABLE)) && !(defined(BOOST_FILESYSTEM_FORCE) || defined(STD_FILESYSTEM_FORCE)) ) ) +//#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 #elif (defined(BOOST_FILESYSTEM_AVAILABLE) && ( defined(BOOST_FILESYSTEM_FORCE) || ( defined(STD_FILESYSTEM_NOT_SUPPORTED) && !defined(STD_FILESYSTEM_FORCE) ) )) - #undef NANA_USING_BOOST_FILESYSTEM #define NANA_USING_BOOST_FILESYSTEM 1 # include # include -// add boost::filesystem into std::experimental::filesystem +// inline boost::filesystem into std::filesystem namespace std { - namespace experimental { - namespace filesystem { + namespace filesystem { + inline namespace boost_filesystem { using namespace boost::filesystem; using file_time_type = std::chrono::time_point; @@ -75,43 +69,34 @@ namespace std { socket = boost::filesystem::file_type::socket_file, unknown = boost::filesystem::file_type::type_unknown, }; -// Boost dont include generic_u8string -// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp -// -// Boost versions: 1.67.0, 1.66.0, ... 1.56.0 enable directory_iterator C++11 range-base for -// http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp -// but travis come with an oooold version of boost -// 1.55.0 NOT enable directory_iterator C++11 range-base for -// http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp -#if BOOST_VERSION < 105600 - namespace boost - // enable directory_iterator C++11 range-base for statement use --------------------// + // Boost dont include generic_u8string + // http://www.boost.org/doc/libs/1_66_0/boost/filesystem/path.hpp + // + // Boost versions: 1.67.0, 1.66.0, ... 1.56.0 enable directory_iterator C++11 range-base for + // http://www.boost.org/doc/libs/1_66_0/boost/filesystem/operations.hpp + // but travis come with an oooold version of boost + // 1.55.0 NOT enable directory_iterator C++11 range-base for + // http://www.boost.org/doc/libs/1_54_0/boost/filesystem/operations.hpp + #if BOOST_VERSION < 105600 + namespace boost { // todo ?? + // enable directory_iterator C++11 range-base for statement use --------------------// - // begin() and end() are only used by a range-based for statement in the context of - // auto - thus the top-level const is stripped - so returning const is harmless and - // emphasizes begin() is just a pass through. - inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT - { - return iter; - } + // begin() and end() are only used by a range-based for statement in the context of + // auto - thus the top-level const is stripped - so returning const is harmless and + // emphasizes begin() is just a pass through. + inline const directory_iterator& begin(const directory_iterator& iter) BOOST_NOEXCEPT + { + return iter; + } - inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT - { - return directory_iterator(); - } -#endif - - } // filesystem - } // experimental - - namespace filesystem - { - using namespace experimental::filesystem; - } - -#ifndef __cpp_lib_experimental_filesystem -# define __cpp_lib_experimental_filesystem 201406 -#endif + inline directory_iterator end(const directory_iterator&) BOOST_NOEXCEPT + { + return directory_iterator(); + } + } + #endif + } // boost_filesystem + } // filesystem } // std #else @@ -148,426 +133,483 @@ namespace std { #include -namespace nana { namespace experimental { namespace filesystem -{ -#ifndef CXX_NO_INLINE_NAMESPACE - inline namespace v1 - { -#endif +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; - std::string string() const; - std::wstring wstring() const; - std::string u8string() const; - // std::u16string u16string() const; - // std::u32string u32string() const; + path relative_path() const; - std::string generic_string() const ; - std::wstring generic_wstring() const; - std::string generic_u8string() const; - // std::u16string generic_u16string() const; - // std::u32string generic_u32string() const; + path parent_path() const; - path lexically_normal() const; + path filename() const; - //appends - path& operator/=(const path& other); + path stem() const; - template - path& operator/=(const Source& source) - { - path other(source); - return this->operator/=(other); - } + path extension() const; - 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_; - }; + // query + bool empty() const noexcept; - 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); + 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; + + std::wstring wstring() const; + + // std::string u8string() const; + // std::u16string u16string() const; + // std::u32string u32string() const; + + std::string generic_string() const; + + std::wstring generic_wstring() const; + + // std::string generic_u8string() const; + // std::u16string generic_u16string() const; + // std::u32string generic_u32string() const; + + path lexically_normal() const; + + //appends + path &operator/=(const path &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_; + }; + + 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_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)); - } - // bool is_regular_file(const path& p, error_code& ec) noexcept; - // Returns: is_regular_file(status(p, ec)).Returns false if an error occurs. + inline bool is_directory(file_status s) noexcept + { return s.type() == file_type::directory; } - inline bool is_empty(const path& p) - { - auto fs = status(p); + bool is_directory(const path &p); - if (is_directory(fs)) - return (directory_iterator() == directory_iterator(p)); + bool is_directory(const path &p, std::error_code &ec) noexcept; - return (file_size(p) == 0); - } - // bool is_empty(const path& p, error_code& ec) noexcept; + 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)); + } + // 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); + + 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; - 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(); - return index ? path.substr(0, index + 1) : std::basic_string(); - } -#ifndef CXX_NO_INLINE_NAMESPACE -} //end namespace v1 -#endif -} //end namespace filesystem -} //end namespace experimental + for (--index; index > 0; --index) + { + auto c = str[index]; + if (c != '\\' && c != '/') + break; + } - //namespace filesystem = experimental::filesystem; + for (--index; index > 0; --index) + { + auto c = str[index]; + if (c == '\\' || c == '/') + break; + } + } + + return index ? path.substr(0, index + 1) : std::basic_string(); + } + + 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); + + bool exists( file_status s ) noexcept; + bool exists( const path& p ); + bool exists( const path& p, std::error_code& ec ) noexcept; + } //end namespace filesystem } //end namespace nana +namespace std +{ + namespace filesystem + { + inline namespace nana_filesystem + { + using namespace ::nana::filesystem; + } + } +} -namespace std { - namespace experimental { - namespace filesystem { -# ifdef CXX_NO_INLINE_NAMESPACE - using namespace nana::experimental::filesystem; -# else - using namespace nana::experimental::filesystem::v1; -# endif - - } // filesystem - } // experimental - - namespace filesystem { - using namespace std::experimental::filesystem; - -#if defined(NANA_FILESYSTEM_FORCE) || \ - (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_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/include/nana/filesystem/filesystem_ext.hpp b/include/nana/filesystem/filesystem_ext.hpp index 7bc69f0c..b31ff0e2 100644 --- a/include/nana/filesystem/filesystem_ext.hpp +++ b/include/nana/filesystem/filesystem_ext.hpp @@ -1,13 +1,13 @@ /** * Nana C++ Library(http://www.nanapro.org) -* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) +* Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * @file nana\filesystem\filesystem_ext.hpp -* @autor by Ariel Vina-Rodriguez: +* @autor Ariel Vina-Rodriguez: * @brief Some convenient extensions to the filesystem library. * */ @@ -35,16 +35,6 @@ namespace filesystem_ext std::filesystem::path path_user(); ///< extention ? - /// workaround Boost not having path.generic_u8string() - a good point for http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0251r0.pdf -inline std::string generic_u8string(const std::filesystem::path& p) -{ -#if NANA_USING_BOOST_FILESYSTEM - return nana::to_utf8(p.generic_wstring()); -#else - return p.generic_u8string(); -#endif -} - inline bool is_directory(const std::filesystem::directory_entry& dir) noexcept { return is_directory(dir.status()); @@ -57,10 +47,10 @@ class directory_only_iterator : public std::filesystem::directory_iterator directory_only_iterator& find_first() { - auto end = directory_only_iterator{}; + directory_only_iterator end{}; while (*this != end) { - if (is_directory((**this).status())) + if (is_directory((*(*this)).status())) return *this; this->directory_iterator::operator++(); } diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index bcd5957c..1c95f503 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -1,4 +1,4 @@ -/* +/** * A ISO C++ FileSystem Implementation * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * @@ -6,14 +6,15 @@ * (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 */ #include #include #include +#include #include #ifdef _nana_std_put_time @@ -150,43 +151,39 @@ namespace nana #if NANA_USING_NANA_FILESYSTEM -namespace nana_fs = nana::experimental::filesystem; +namespace nana_fs = nana::filesystem; +namespace nana +{ +namespace filesystem +{ + //class filesystem_error + filesystem_error::filesystem_error(const std::string& msg, std::error_code err) + : std::system_error(err, msg) + {} -namespace nana { namespace experimental { namespace filesystem - { -#ifndef CXX_NO_INLINE_NAMESPACE - inline namespace v1 { -#endif + filesystem_error::filesystem_error(const std::string& msg, const path& path1, std::error_code err) + : std::system_error(err, msg), + path1_(path1) + {} - //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, 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, std::error_code err) - : std::system_error(err, msg), - path1_(path1) - {} + const path& filesystem_error::path1() const noexcept + { + return 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) - {} + const path& filesystem_error::path2() const noexcept + { + return path2_; + } + //end class filesystem_error - const path& filesystem_error::path1() const noexcept - { - return path1_; - } - - 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 = '/'; @@ -512,10 +509,10 @@ namespace nana { namespace experimental { 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(); @@ -528,12 +525,12 @@ namespace nana { namespace experimental { 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 { @@ -667,7 +664,7 @@ namespace nana { namespace experimental { namespace filesystem } //class directory_entry - directory_entry::directory_entry(const nana_fs::path& p) + directory_entry::directory_entry(const filesystem::path& p) :path_{ p } {} @@ -713,112 +710,112 @@ namespace nana { namespace experimental { 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_) { @@ -978,7 +975,6 @@ namespace nana { namespace experimental { namespace filesystem #endif }//end namespace detail - file_status status(const path& p) { std::error_code err; @@ -1108,93 +1104,290 @@ namespace nana { namespace experimental { 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()) @@ -1379,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; @@ -1395,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))) @@ -1550,9 +1736,9 @@ namespace std { return weakly_canonical(p, &err); } -#endif } } +#endif #endif //NANA_USING_NANA_FILESYSTEM 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); } });