diff --git a/CMakeLists.txt b/CMakeLists.txt index 49d9a4b..9cf5cf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,9 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.10) project(ghcfilesystem) set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) add_compile_options("$<$:/utf-8>") add_compile_options("$<$:/utf-8>") diff --git a/README.md b/README.md index b16e719..aaedc95 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ 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 +This is a helper class that currently checks for UTF-8 encoding on non-Windows platforms but on Windows it fetches the command line arguments als Unicode strings from the OS with ```cpp @@ -170,6 +170,10 @@ namespace fs = ghc::filesystem; int main(int argc, char* argv[]) { fs::u8arguments u8guard(argc, argv); + if(u8guard.valid()) { + std::cerr << "Bad encoding, needs UTF-8." << std::endl; + exit(EXIT_FAILURE); + } // now use argc/argv as usual, they have utf-8 enconding on windows // ... diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a49142c..66a95b1 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,17 +1,21 @@ add_executable(fs_dir dir.cpp ../filesystem.h) -target_compile_definitions(fs_dir PRIVATE _CRT_SECURE_NO_WARNINGS) +if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) + target_compile_definitions(fs_dir PRIVATE _CRT_SECURE_NO_WARNINGS) +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)) 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) diff --git a/examples/dir.cpp b/examples/dir.cpp index abb6eba..380f75c 100644 --- a/examples/dir.cpp +++ b/examples/dir.cpp @@ -31,6 +31,10 @@ int main(int argc, char* argv[]) { #ifdef GHC_FILESYSTEM_VERSION fs::u8arguments u8guard(argc, argv); + if(!u8guard.valid()) { + std::cerr << "Invalid character encoding, UTF-8 based encoding needed." << std::endl; + std::exit(EXIT_FAILURE); + } #endif if(argc > 2) { std::cerr << "USAGE: dir " << std::endl; diff --git a/filesystem.h b/filesystem.h index fc6e814..597781d 100644 --- a/filesystem.h +++ b/filesystem.h @@ -62,21 +62,22 @@ #error "Operating system currently not supported!" #endif -#ifndef GHC_OS_WINDOWS +#ifdef GHC_OS_WINDOWS +#include +#include +#include +#include +#include +#else #include #include +#include #include #include #include #include #include #include -#else -#include -#include -#include -#include -#include #endif #ifdef GHC_OS_MACOS #include @@ -917,11 +918,17 @@ public: _refargv = _argv; } + bool valid() const + { + return _isvalid; + } + private: int _argc; char** _argv; int& _refargc; char**& _refargv; + bool _isvalid; #ifdef GHC_OS_WINDOWS std::vector _args; std::vector _argp; @@ -1203,25 +1210,6 @@ 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) @@ -1667,6 +1655,34 @@ inline file_status status_ex(const path& p, std::error_code& ec, file_status* sl } // namespace detail + +inline u8arguments::u8arguments(int& argc, char**& argv) + : _argc(argc) + , _argv(argv) + , _refargc(argc) + , _refargv(argv) + , _isvalid(false) +{ +#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); + _isvalid = true; +#else + std::setlocale(LC_ALL, ""); + if(!detail::compare_no_case(::nl_langinfo(CODESET), "UTF-8")) { + _isvalid = true; + } +#endif +} + //----------------------------------------------------------------------------- // 30.10.8.4.1 constructors and destructor