From 1da3ae7864696df92fdecd9d6d257bd2eeb4372a Mon Sep 17 00:00:00 2001 From: Steffen Schuemann Date: Sat, 29 Sep 2018 12:49:12 +0200 Subject: [PATCH] Restructured CMakeLists, added fs::u8arguments helper, added first example --- CMakeLists.txt | 28 ++-------------------- README.md | 48 ++++++++++++++++++++++++++++++++++++- examples/CMakeLists.txt | 17 +++++++++++++ examples/dir.cpp | 53 +++++++++++++++++++++++++++++++++++++++++ filesystem.h | 40 +++++++++++++++++++++++++++++++ test/CMakeLists.txt | 27 +++++++++++++++++++++ 6 files changed, 186 insertions(+), 27 deletions(-) create mode 100644 examples/CMakeLists.txt create mode 100644 examples/dir.cpp create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 757f8f7..49d9a4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,29 +6,5 @@ set(CMAKE_CXX_STANDARD 11) add_compile_options("$<$:/utf-8>") add_compile_options("$<$:/utf-8>") -add_executable(filesystem_test test/filesystem_test.cpp filesystem.h test/catch.hpp) -if(CMAKE_GENERATOR STREQUAL Xcode) - add_executable(filesystem_test_cov test/filesystem_test.cpp filesystem.h test/catch.hpp) - target_compile_options(filesystem_test_cov PRIVATE "$<$:--coverage>") - target_link_libraries(filesystem_test_cov PRIVATE --coverage) -endif() - -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)) - include_directories(/usr/local/opt/llvm/include) - link_directories(/usr/local/opt/llvm/lib) - add_executable(std_filesystem_test test/filesystem_test.cpp filesystem.h test/catch.hpp) - set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) - target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) - target_link_libraries(std_filesystem_test -lc++fs) -endif() -if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)) - add_executable(std_filesystem_test test/filesystem_test.cpp filesystem.h test/catch.hpp) - set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) - target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) - target_link_libraries(std_filesystem_test -lstdc++fs) -endif() -if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15)) - add_executable(std_filesystem_test test/filesystem_test.cpp filesystem.h test/catch.hpp) - set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) - target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) -endif() +add_subdirectory(test) +add_subdirectory(examples) diff --git a/README.md b/README.md index 4039dff..acdbbd5 100644 --- a/README.md +++ b/README.md @@ -132,11 +132,50 @@ It's the version as decimal number `(major * 10000 + minor * 100 + patch)`. ## Documentation -There is no documentation in this release, as any `std::filesystem` documentation +There is almost no documentation in this release, as any `std::filesystem` documentation would work, besides the few differences explained in the next section. So you might head over to https://en.cppreference.com/w/cpp/filesystem for a description of the components of this library. +The only additions to the standard are documented here: + + +### `ghc::filesystem::ifstream`, `ghc::filesystem::ofstream`, `ghc::filesystem::fstream` + +These are simple wrappers around `std::ifstream`, `std::ofstream` and `std::fstream`. +They simply add an `open()` method and a constuctor with an `ghc::filesystem::path` +argument as the `fstream` variants in C++17 have them. + +### `ghc::filesystem::u8arguments` + +This is a helper class that acts neutral on non-Windows platforms but on Windows it +fetches the command line arguments als Unicode strings from the OS with + +```cpp +::CommandLineToArgvW(::GetCommandLineW(), &argc) +``` + +and then converts them to UTF-8, and replaces `argc` and `argv`. It is a guard-like +class that reverts its changes when going out of scope. + +So basic usage is: + +```cpp +namespace fs = ghc::filesystem; + +int main(int argc, char* argv[]) +{ + fs::u8arguments u8guard(argc, argv); + + // now use argc/argv as usual, they have utf-8 enconding on windows + // ... + + return 0; +} +``` + +That way `argv` is UTF-8 encoded as long as the scope from `main` is valid. + ## Differences @@ -292,6 +331,13 @@ to the expected behavior. * Updated catch2 to v2.4.0. * Refactored `fs.op.permissions` test to work with all tested `std::filesystem` implementations (gcc, clang, msvc++). +* Added helper class `ghc::filesystem::u8arguments` as `argv` converter, to + help follow the UTF-8 path on windows. Simply instantiate it with `argc` and + `argv` and it will fetch the Unicode version of the command line and convert + it to UTF-8. The destructor reverts the change. +* Added `examples` folder with hopefully some usefull example usage. Examples are + tested (and build) with `ghc::filesystem` and C++17 `std::filesystem` when + available. ### [v1.0.1](https://github.com/gulrak/filesystem/tree/v1.0.1) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..e82671c --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,17 @@ + +add_executable(fs_dir dir.cpp ../filesystem.h) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)) + add_executable(std_fs_dir dir.cpp) + set_property(TARGET std_fs_dir PROPERTY CXX_STANDARD 17) + target_link_libraries(std_fs_dir -lc++fs) +endif() +if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)) + add_executable(std_fs_dir dir.cpp) + set_property(TARGET std_fs_dir PROPERTY CXX_STANDARD 17) + target_link_libraries(std_fs_dir -lstdc++fs) +endif() +if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15)) + add_executable(std_fs_dir dir.cpp) + set_property(TARGET std_fs_dir PROPERTY CXX_STANDARD 17) +endif() diff --git a/examples/dir.cpp b/examples/dir.cpp new file mode 100644 index 0000000..abb6eba --- /dev/null +++ b/examples/dir.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) && __has_include() +#include +namespace fs = std::filesystem; +#else +#include "../filesystem.h" +namespace fs = ghc::filesystem; +#endif + +template +std::time_t to_time_t(TP tp) +{ + // Based on trick from: Nico Josuttis, C++17 - The Complete Guide + return std::chrono::system_clock::to_time_t(std::chrono::system_clock::now() + (tp - TP::clock::now())); +} + +static std::string perm_to_str(fs::perms prms) +{ + std::string result; + result.reserve(6); + for(int i = 0; i < 9; ++i) { + result = ((static_cast(prms) & (1< 2) { + std::cerr << "USAGE: dir " << std::endl; + exit(1); + } + fs::path dir{"."}; + if(argc == 2) { + dir = fs::u8path(argv[1]); + } + for(auto de : fs::directory_iterator(dir)) { + auto ft = to_time_t(de.last_write_time()); + auto ftm = *std::localtime(&ft); + std::cout << (de.is_directory() ? "d" : "-") << perm_to_str(de.symlink_status().permissions()) << " " + << std::setw(8) << (de.is_directory() ? "-" : std::to_string(de.file_size())) << " " + << std::put_time(&ftm, "%Y-%m-%d %H:%M:%S") << " " + << de.path().filename().string() + << std::endl; + } + return 0; +} diff --git a/filesystem.h b/filesystem.h index 3e955cf..12f6991 100644 --- a/filesystem.h +++ b/filesystem.h @@ -900,6 +900,26 @@ typedef basic_ofstream ofstream; typedef basic_ofstream wofstream; typedef basic_fstream fstream; typedef basic_fstream wfstream; + +class u8arguments { +public: + u8arguments(int& argc, char**& argv); + ~u8arguments() + { + _refargc = _argc; + _refargv = _argv; + } +private: + int _argc; + char** _argv; + int& _refargc; + char**& _refargv; +#ifdef GHC_OS_WINDOWS + std::vector _args; + std::vector _argp; +#endif +}; + //------------------------------------------------------------------------------------------------- // Implementation @@ -1181,6 +1201,26 @@ inline void postprocess_path_with_format(path::string_type& p, path::format fmt) } // namespace detail +inline u8arguments::u8arguments(int& argc, char**& argv) +: _argc(argc) +, _argv(argv) +, _refargc(argc) +, _refargv(argv) +{ +#ifdef GHC_OS_WINDOWS + LPWSTR* p; + p = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + _args.reserve(argc); + _argp.reserve(argc); + for (size_t i = 0; i < argc; ++i) { + _args.push_back(detail::toUtf8(std::wstring(p[i]))); + _argp.push_back((char*)_args[i].data()); + } + argv = _argp.data(); + ::LocalFree(p); +#endif +} + template inline path::path(const Source& source, format fmt) : _path(source) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..9352c39 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,27 @@ + +add_executable(filesystem_test filesystem_test.cpp ../filesystem.h catch.hpp) +if(CMAKE_GENERATOR STREQUAL Xcode) + add_executable(filesystem_test_cov filesystem_test.cpp ../filesystem.h catch.hpp) + target_compile_options(filesystem_test_cov PRIVATE "$<$:--coverage>") + target_link_libraries(filesystem_test_cov PRIVATE --coverage) +endif() + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 7.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)) + include_directories(/usr/local/opt/llvm/include) + link_directories(/usr/local/opt/llvm/lib) + add_executable(std_filesystem_test filesystem_test.cpp ../filesystem.h catch.hpp) + set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) + target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) + target_link_libraries(std_filesystem_test -lc++fs) +endif() +if (CMAKE_COMPILER_IS_GNUCXX AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0)) + add_executable(std_filesystem_test filesystem_test.cpp ../filesystem.h catch.hpp) + set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) + target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) + target_link_libraries(std_filesystem_test -lstdc++fs) +endif() +if(CMAKE_CXX_COMPILER_ID MATCHES MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 19.15 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.15)) + add_executable(std_filesystem_test filesystem_test.cpp ../filesystem.h catch.hpp) + set_property(TARGET std_filesystem_test PROPERTY CXX_STANDARD 17) + target_compile_definitions(std_filesystem_test PRIVATE USE_STD_FS) +endif()