From 69e559f657a34239dd039284cddf650b71b5b2d0 Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Sun, 11 Aug 2019 20:27:16 -0400 Subject: [PATCH 01/15] fixed a bug in trigger::dbl_click() impl_->set_expanded() was called unconditionally, even if the node had no children. This caused the node icon to change to the "expanded" icon if the node had an icon scheme, even when the node didn't have children. --- source/gui/widgets/treebox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index eb859353..c70c4330 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -1952,7 +1952,7 @@ namespace nana impl_->attr.tree_cont.for_each(shape.first, nl); auto const node = nl.node(); - if (!node) + if (!node || !node->child) return; switch (nl.what()) From b7a08744287270a1b0fb88152a4a6b7234b4d289 Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Tue, 20 Aug 2019 05:32:36 -0400 Subject: [PATCH 02/15] fixed bug: listbox::sort_col doesn't update view Calling listbox::sort_col to change the sort column doesn't update the viewport to reflect the change, forcing the user to call API::refresh_window or otherwise perform stupid tricks to force the listbox to refresh. --- source/gui/widgets/listbox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 2a984cf5..a62a80f8 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -5949,6 +5949,7 @@ namespace nana { internal_scope_guard lock; _m_ess().lister.sort_column(col, &reverse); + _m_ess().update(); } auto listbox::sort_col() const -> size_type From 35dadaeab63d634e9aa70aa9fa625277016eb93c Mon Sep 17 00:00:00 2001 From: Zaha Mihai <1395028+mihaizh@users.noreply.github.com> Date: Sun, 15 Sep 2019 23:32:58 +0300 Subject: [PATCH 03/15] Fix tabbar drawing not updated when tab is erased When a tab is deleted using `tabbar::erase`, `trigger::erase` is called. This function does not call `API::refresh_window` if the tab was erased successfully (unlike `trigger::tab_color`, `trigger::tab_image`, etc.), thus the tab is still visible until an interaction is made (like mouse click on `tabbar`). --- source/gui/widgets/tabbar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/tabbar.cpp b/source/gui/widgets/tabbar.cpp index 6a79c648..94ed54eb 100644 --- a/source/gui/widgets/tabbar.cpp +++ b/source/gui/widgets/tabbar.cpp @@ -1229,7 +1229,8 @@ namespace nana void trigger::erase(std::size_t pos) { - layouter_->erase(pos); + if (layouter_->erase(pos)) + API::refresh_window(layouter_->widget_handle()); } void trigger::tab_color(std::size_t i, bool is_bgcolor, const ::nana::color& clr) From e626f816b38c95cf61af189e4514ef102841549e Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Mon, 16 Sep 2019 06:07:04 -0400 Subject: [PATCH 04/15] nana::any bug fix - argument not forwarded A constructor and an overload of the assignment operator each have a forwarding reference as a parameter, but they don't actually forward the argument. --- include/nana/any.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nana/any.hpp b/include/nana/any.hpp index ed711146..9a90ca2f 100644 --- a/include/nana/any.hpp +++ b/include/nana/any.hpp @@ -74,7 +74,7 @@ namespace nana any(Value && value, typename std::enable_if::value>::type * = nullptr, typename std::enable_if::value>::type* = nullptr) - : content_(new holder::type>(static_cast(value))) + : content_(new holder::type>(std::forward(value))) { } @@ -87,7 +87,7 @@ namespace nana template any& operator=(Value&& other) { - any(other).swap(*this); + any(std::forward(other)).swap(*this); return *this; } From 59d3a684855d08bd78f50ab3137aa2c8478b6f13 Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Fri, 20 Sep 2019 23:38:09 -0400 Subject: [PATCH 05/15] item_proxy bug fix: postfix increment operator The behavior of the postfix increment operator is not consistent with the increment operator concept (currently just returns the next sibling node). --- source/gui/widgets/treebox.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index c70c4330..233099c6 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -1274,7 +1274,10 @@ namespace nana item_proxy item_proxy::operator++(int) { - return sibling(); + item_proxy ip(*this); + if(trigger_ && node_) + node_ = node_->next; + return ip; } item_proxy& item_proxy::operator*() From 6c547276ecd32ca58bb8d6f94c5f687dbd96e259 Mon Sep 17 00:00:00 2001 From: ErrorFlynn Date: Sat, 5 Oct 2019 11:19:42 -0400 Subject: [PATCH 06/15] bug fix: nana::drawerbase::listbox::essence::where This method incorrectly calculates the position of checkboxes in the listbox content area. It uses the formula `new_where.second * item_h + header_visible_px()` to calculate the number of pixels between the top of the viewport and a checkbox. The problem is that when the first visible item is only partially visible, `new_where.second * item_h` produces an excess of pixels equal to the vertical segment of the first visible item that is not in the viewport. This excess value produces a downward displacement of the calculated checkbox position, so it must be accounted for in the aforementioned formula. This problem occurs because at some point, the library switched from scrolling in item-sized increments to smooth scrolling (in older versions, it used to be that it was impossible for an item to be only partially visible). Relevant thread: http://nanapro.org/en-us/forum/index.php?u=/topic/1227/ggnana-listbox-with-a-check-box-for-each-list-item#post-3359 --- source/gui/widgets/listbox.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index a62a80f8..1fa6a29e 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2387,7 +2387,9 @@ namespace nana nana::rectangle r; if (rect_lister(r)) { - auto top = new_where.second * item_h + header_visible_px(); + //potential displacement due to partially visible first visible item + auto disp = origin.y - first_display().item * item_h; + auto top = new_where.second * item_h + header_visible_px() - disp; if (checkarea(item_xpos(r), static_cast(top)).is_hit(pos)) new_where.first = parts::checker; } From 25353e4325574cfe23e73379452173d42d84cf46 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 Nov 2019 19:23:50 +0100 Subject: [PATCH 07/15] reorganize priorities --- CMakeLists.txt | 4 ++-- build/cmake/select_filesystem.cmake | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) 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..3ae20e8f 100644 --- a/build/cmake/select_filesystem.cmake +++ b/build/cmake/select_filesystem.cmake @@ -1,15 +1,13 @@ # 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) @@ -18,13 +16,20 @@ option(NANA_CMAKE_BOOST_FILESYSTEM_FORCE "Force use of Boost filesystem if avail option(NANA_CMAKE_FIND_BOOST_FILESYSTEM "Search: Is Boost filesystem available?" 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, @@ -51,6 +56,3 @@ else() endif() - - - From babcdb477d12285b4148509c73e1716b1da27b15 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 Nov 2019 19:25:14 +0100 Subject: [PATCH 08/15] check_cxx_source_compiles FILESYSTEM --- build/cmake/select_filesystem.cmake | 101 ++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 5 deletions(-) diff --git a/build/cmake/select_filesystem.cmake b/build/cmake/select_filesystem.cmake index 3ae20e8f..69b8300b 100644 --- a/build/cmake/select_filesystem.cmake +++ b/build/cmake/select_filesystem.cmake @@ -13,7 +13,8 @@ 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) @@ -48,11 +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_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_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 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_BUILTIN) + + if (C++17FS_BUILTIN) + 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_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() From 597f6c05cdab9093c13f615414e52f8a3b3d2429 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 Nov 2019 19:29:30 +0100 Subject: [PATCH 09/15] inline boost::filesystem into std::filesystem --- include/nana/filesystem/filesystem.hpp | 76 ++++++++++---------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 8aab0cea..872bcb50 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,12 +34,6 @@ //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 @@ -50,16 +44,15 @@ #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 +68,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 From 3eee1f76b90124267b2e4129bc866e7164ed156f Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 Nov 2019 19:43:01 +0100 Subject: [PATCH 10/15] inline nana::filesystem --- include/nana/filesystem/filesystem.hpp | 109 ++++++++++----------- include/nana/filesystem/filesystem_ext.hpp | 18 +--- source/filesystem/filesystem.cpp | 18 ++-- 3 files changed, 66 insertions(+), 79 deletions(-) diff --git a/include/nana/filesystem/filesystem.hpp b/include/nana/filesystem/filesystem.hpp index 872bcb50..4a080b77 100644 --- a/include/nana/filesystem/filesystem.hpp +++ b/include/nana/filesystem/filesystem.hpp @@ -38,6 +38,8 @@ #define NANA_USING_STD_FILESYSTEM 0 #define NANA_USING_BOOST_FILESYSTEM 0 +#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 @@ -132,12 +134,8 @@ 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 { @@ -264,17 +262,21 @@ namespace nana { namespace experimental { namespace filesystem 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 string() 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; + 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; @@ -424,16 +426,17 @@ namespace nana { namespace experimental { namespace filesystem 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 - { - 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_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) { @@ -497,38 +500,34 @@ namespace nana { namespace experimental { namespace filesystem } } - 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 + return index ? path.substr(0, index + 1) : std::basic_string(); + } - //namespace filesystem = experimental::filesystem; + 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 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); +namespace std +{ + namespace filesystem + { + inline namespace nana_filesystem + { + using namespace ::nana::filesystem; + } + } +} path canonical(const path& p); path 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..2ef50604 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) * @@ -14,6 +14,7 @@ #include #include #include +#include #include #ifdef _nana_std_put_time @@ -150,14 +151,11 @@ namespace nana #if NANA_USING_NANA_FILESYSTEM -namespace nana_fs = nana::experimental::filesystem; - -namespace nana { namespace experimental { namespace filesystem - { -#ifndef CXX_NO_INLINE_NAMESPACE - inline namespace v1 { -#endif - +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) @@ -667,7 +665,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 } {} From a8b5e92947dcbc1e88ce3aedd09e78e745782006 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 Nov 2019 21:00:33 +0100 Subject: [PATCH 11/15] using nana filesystem --- include/nana/filesystem/filesystem.hpp | 629 ++++++++++++++----------- source/filesystem/filesystem.cpp | 568 ++++++++++++++-------- source/gui/filebox.cpp | 6 +- source/gui/msgbox.cpp | 2 +- 4 files changed, 726 insertions(+), 479 deletions(-) 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); } }); From bd702542230e9a4d543c9c4bb50a93632317d990 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 Nov 2019 21:08:28 +0100 Subject: [PATCH 12/15] using std filesystem --- source/filesystem/filesystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/filesystem/filesystem.cpp b/source/filesystem/filesystem.cpp index 544efe48..1c95f503 100644 --- a/source/filesystem/filesystem.cpp +++ b/source/filesystem/filesystem.cpp @@ -1736,9 +1736,9 @@ namespace std { return weakly_canonical(p, &err); } -#endif } } +#endif #endif //NANA_USING_NANA_FILESYSTEM From 5438b4ee2880ec86d087a6c67b4af5b848a8b760 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 5 Nov 2019 21:33:29 +0100 Subject: [PATCH 13/15] using nana-demo hotfix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 0e7261228c5e804b20a2481f5894a01fac9723e0 Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Wed, 6 Nov 2019 11:00:19 +0100 Subject: [PATCH 14/15] don't reuse variable! --- build/cmake/select_filesystem.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/cmake/select_filesystem.cmake b/build/cmake/select_filesystem.cmake index 69b8300b..a4729484 100644 --- a/build/cmake/select_filesystem.cmake +++ b/build/cmake/select_filesystem.cmake @@ -60,7 +60,7 @@ else() if (NANA_HAVE_FILESYSTEM) message (STATUS "C++ Filesystem header: ") set (TEST_FS_LIB ON) - set (CXXSTD_TEST_SOURCE + set (CXXSTD_FS_TEST_SOURCE "#include int main() { @@ -70,7 +70,7 @@ else() elseif (NANA_HAVE_EXP_FILESYSTEM) message (STATUS "C++ Filesystem header: ") set (TEST_FS_LIB ON) - set (CXXSTD_TEST_SOURCE + set (CXXSTD_FS_TEST_SOURCE "#include int main() { @@ -78,7 +78,7 @@ else() throw std::experimental::filesystem::filesystem_error(\"Empty file name!\", std::make_error_code(std::errc::invalid_argument)); }") else () - message (WARNING "No std::filesystem found: nana::filesystem will be used. + 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) @@ -116,15 +116,15 @@ else() endif () set (CMAKE_REQUIRED_LIBRARIES_ORIGINAL ${CMAKE_REQUIRED_LIBRARIES}) - check_cxx_source_compiles ("${CXXSTD_TEST_SOURCE}" C++17FS_BUILTIN) + check_cxx_source_compiles ("${CXXSTD_TEST_SOURCE}" C++17FS_FLAG) - if (C++17FS_BUILTIN) + 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_TEST_SOURCE}" C++17FS_LIB-l${_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}) From 948022e304778fafddccf43db262f5b0eee86ff8 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 17 Nov 2019 01:27:20 +0800 Subject: [PATCH 15/15] fix any forward inlude issue --- include/nana/any.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/nana/any.hpp b/include/nana/any.hpp index c9b3b33f..c949e376 100644 --- a/include/nana/any.hpp +++ b/include/nana/any.hpp @@ -16,6 +16,7 @@ #define NANA_ANY_HPP #include #include +#include #include "c++defines.hpp"