From 3ef9fddc7b643b2bbd85a3d5788083004c183533 Mon Sep 17 00:00:00 2001 From: jarro2783 Date: Sat, 3 Oct 2020 20:54:06 +1000 Subject: [PATCH 01/16] Fix passing a const array to parse (#258) Fixes #257. The input array is not modified, so we can declare this as `char const* const*`. --- include/cxxopts.hpp | 12 ++++++------ test/options.cpp | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 96881d6..cc43fa7 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1325,7 +1325,7 @@ namespace cxxopts } ParseResult - parse(int argc, const char** argv); + parse(int argc, const char* const* argv); bool consume_positional(const std::string& a, PositionalListIterator& next); @@ -1334,7 +1334,7 @@ namespace cxxopts checked_parse_arg ( int argc, - const char* argv[], + const char* const* argv, int& current, const std::shared_ptr& value, const std::string& name @@ -1412,7 +1412,7 @@ namespace cxxopts } ParseResult - parse(int argc, const char** argv); + parse(int argc, const char* const* argv); OptionAdder add_options(std::string group = ""); @@ -1772,7 +1772,7 @@ void OptionParser::checked_parse_arg ( int argc, - const char* argv[], + const char* const* argv, int& current, const std::shared_ptr& value, const std::string& name @@ -1865,7 +1865,7 @@ Options::parse_positional(std::initializer_list options) inline ParseResult -Options::parse(int argc, const char** argv) +Options::parse(int argc, const char* const* argv) { OptionParser parser(*m_options, m_positional, m_allow_unrecognised); @@ -1873,7 +1873,7 @@ Options::parse(int argc, const char** argv) } inline ParseResult -OptionParser::parse(int argc, const char** argv) +OptionParser::parse(int argc, const char* const* argv) { int current = 1; bool consume_remaining = false; diff --git a/test/options.cpp b/test/options.cpp index b98bade..61678a6 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -773,3 +773,9 @@ TEST_CASE("Option add with add_option(string, Option)", "[options]") { CHECK(result["aggregate"].as() == 4); CHECK(result["test"].as() == 5); } + +TEST_CASE("Const array", "[const]") { + const char* const option_list[] = {"empty", "options"}; + cxxopts::Options options("Empty options", " - test constness"); + auto result = options.parse(2, option_list); +} From 12e496da3d486b87fa9df43edea65232ed852510 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 6 Oct 2020 02:06:33 -0400 Subject: [PATCH 02/16] Making sure that the library can compile without warnings even when crazy pedantic flags are set (#238) Makes some fixes to satisfy various strict warnings. --- CMakeLists.txt | 2 +- include/cxxopts.hpp | 76 ++++++++++++++++++++++++++------------------- test/options.cpp | 2 +- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e9b862..3098445 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion") endif() add_library(cxxopts INTERFACE) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index cc43fa7..88e8a02 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -147,9 +147,9 @@ namespace cxxopts inline String& - stringAppend(String& s, int n, UChar32 c) + stringAppend(String& s, size_t n, UChar32 c) { - for (int i = 0; i != n; ++i) + for (size_t i = 0; i != n; ++i) { s.append(c); } @@ -285,6 +285,13 @@ namespace cxxopts #endif } // namespace +#if defined(__GNUC__) +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic push +// This will be ignored under other compilers like LLVM clang. +#endif class Value : public std::enable_shared_from_this { public: @@ -328,7 +335,9 @@ namespace cxxopts virtual bool is_boolean() const = 0; }; - +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif class OptionException : public std::exception { public: @@ -822,6 +831,8 @@ namespace cxxopts ~abstract_value() override = default; + abstract_value& operator=(const abstract_value&) = default; + abstract_value(const abstract_value& rhs) { if (rhs.m_result) @@ -922,14 +933,14 @@ namespace cxxopts } protected: - std::shared_ptr m_result; - T* m_store; + std::shared_ptr m_result{}; + T* m_store{}; bool m_default = false; bool m_implicit = false; - std::string m_default_value; - std::string m_implicit_value; + std::string m_default_value{}; + std::string m_implicit_value{}; }; template @@ -1067,13 +1078,13 @@ namespace cxxopts } private: - std::string m_short; - std::string m_long; - String m_desc; - std::shared_ptr m_value; + std::string m_short{}; + std::string m_long{}; + String m_desc{}; + std::shared_ptr m_value{}; int m_count; - size_t m_hash; + size_t m_hash{}; }; struct HelpOptionDetails @@ -1092,9 +1103,9 @@ namespace cxxopts struct HelpGroupDetails { - std::string name; - std::string description; - std::vector options; + std::string name{}; + std::string description{}; + std::vector options{}; }; class OptionValue @@ -1163,10 +1174,11 @@ namespace cxxopts } } + const std::string* m_long_name = nullptr; // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, // where the key has the string we point to. - std::shared_ptr m_value; + std::shared_ptr m_value{}; size_t m_count = 0; bool m_default = false; }; @@ -1282,10 +1294,10 @@ namespace cxxopts } private: - NameHashMap m_keys; - ParsedHashMap m_values; - std::vector m_sequential; - std::vector m_unmatched; + NameHashMap m_keys{}; + ParsedHashMap m_values{}; + std::vector m_sequential{}; + std::vector m_unmatched{}; }; struct Option @@ -1361,11 +1373,11 @@ namespace cxxopts const OptionMap& m_options; const PositionalList& m_positional; - std::vector m_sequential; + std::vector m_sequential{}; bool m_allow_unrecognised; - ParsedHashMap m_parsed; - NameHashMap m_keys; + ParsedHashMap m_parsed{}; + NameHashMap m_keys{}; }; class Options @@ -1489,22 +1501,22 @@ namespace cxxopts void generate_all_groups_help(String& result) const; - std::string m_program; - String m_help_string; - std::string m_custom_help; - std::string m_positional_help; + std::string m_program{}; + String m_help_string{}; + std::string m_custom_help{}; + std::string m_positional_help{}; bool m_show_positional; bool m_allow_unrecognised; std::shared_ptr m_options; - std::vector m_positional; - std::unordered_set m_positional_set; + std::vector m_positional{}; + std::unordered_set m_positional_set{}; //mapping from groups to help options - std::map m_help; + std::map m_help{}; - std::list m_option_list; - std::unordered_map m_option_map; + std::list m_option_list{}; + std::unordered_map m_option_map{}; }; class OptionAdder diff --git a/test/options.cpp b/test/options.cpp index 61678a6..8bc6f49 100644 --- a/test/options.cpp +++ b/test/options.cpp @@ -36,7 +36,7 @@ class Argv { private: - std::vector> m_args; + std::vector> m_args{}; std::unique_ptr m_argv; int m_argc; }; From 66b52e6cc9f3f2429dcb01ddb90b6c2f156ac67f Mon Sep 17 00:00:00 2001 From: fiesh Date: Wed, 21 Oct 2020 01:24:41 +0200 Subject: [PATCH 03/16] Add -Wsuggest-override (#264) We also add the suggested `override` keyword. --- CMakeLists.txt | 2 +- include/cxxopts.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3098445..feec2cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion -Wsuggest-override") endif() add_library(cxxopts INTERFACE) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 88e8a02..6ec7998 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -951,7 +951,7 @@ namespace cxxopts CXXOPTS_NODISCARD std::shared_ptr - clone() const + clone() const override { return std::make_shared>(*this); } From 2d8e17c4f88efce80e274cb03eeb902e055a91d3 Mon Sep 17 00:00:00 2001 From: Dan Ibanez Date: Mon, 14 Dec 2020 14:47:52 -0700 Subject: [PATCH 04/16] Add CMake option to not add warning flags (#267) Allow extra compiler warnings to be disabled. --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index feec2cd..7676638 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ enable_testing() option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ON) option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" ON) option(CXXOPTS_ENABLE_INSTALL "Generate the install target" ON) +option(CXXOPTS_ENABLE_WARNINGS "Add warnings to CMAKE_CXX_FLAGS" ON) # request c++11 without gnu extension for the whole project and enable more warnings if (CXXOPTS_CXX_STANDARD) @@ -47,11 +48,13 @@ endif() set(CMAKE_CXX_EXTENSIONS OFF) +if (CXXOPTS_ENABLE_WARNINGS) if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion -Wsuggest-override") endif() +endif() add_library(cxxopts INTERFACE) add_library(cxxopts::cxxopts ALIAS cxxopts) From c55726ee29dc41cb4d0b462c988041f536cd6e12 Mon Sep 17 00:00:00 2001 From: jpr89 <31327577+jpr89@users.noreply.github.com> Date: Sat, 16 Jan 2021 20:11:02 -0500 Subject: [PATCH 05/16] Cmake Revamp (#270) * Cmake Revamp I needed to do a variety of things to ensure cxxopts worked well in my own project. I created a new cmake module to abstract a lot of the logic in the main CMakelists.txt, I think it really assists in the readability of the project. Consequently a lot of logic is now written in functions. I made a lot of the project options off by default unless the project is being built standalone. As a frequent consumer of cmake libraries this is a huge issue. Since examples, tests, installation, etc. aren't things I expect/desired by default when using libraries. Co-authored-by: Juan Ramos --- CMakeLists.txt | 121 +++++++++++++++-------------------------- cmake/cxxopts.cmake | 112 ++++++++++++++++++++++++++++++++++++++ include/CMakeLists.txt | 23 ++++++++ src/CMakeLists.txt | 12 ++-- test/CMakeLists.txt | 82 +++++++++++++++++----------- 5 files changed, 233 insertions(+), 117 deletions(-) create mode 100644 cmake/cxxopts.cmake create mode 100644 include/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 7676638..5e5043d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,15 @@ # Copyright (c) 2014 Jarryd Beck -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -17,96 +17,61 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.1...3.19) -# parse the current version from the cxxopts header -file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/cxxopts.hpp" cxxopts_version_defines - REGEX "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH)") -foreach(ver ${cxxopts_version_defines}) - if(ver MATCHES "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") - set(CXXOPTS__VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") - endif() -endforeach() -set(VERSION ${CXXOPTS__VERSION_MAJOR}.${CXXOPTS__VERSION_MINOR}.${CXXOPTS__VERSION_PATCH}) -message(STATUS "cxxopts version ${VERSION}") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") +include(cxxopts) -project(cxxopts VERSION "${VERSION}" LANGUAGES CXX) +# Get the version of the library +cxxopts_getversion(VERSION) -enable_testing() +project(cxxopts + VERSION "${VERSION}" + LANGUAGES CXX +) -option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ON) -option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" ON) -option(CXXOPTS_ENABLE_INSTALL "Generate the install target" ON) -option(CXXOPTS_ENABLE_WARNINGS "Add warnings to CMAKE_CXX_FLAGS" ON) - -# request c++11 without gnu extension for the whole project and enable more warnings -if (CXXOPTS_CXX_STANDARD) - set(CMAKE_CXX_STANDARD ${CXXOPTS_CXX_STANDARD}) -else() - set(CMAKE_CXX_STANDARD 11) +# Determine whether this is a standalone project or included by other projects +set(CXXOPTS_STANDALONE_PROJECT OFF) +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(CXXOPTS_STANDALONE_PROJECT ON) endif() -set(CMAKE_CXX_EXTENSIONS OFF) +# Establish the project options +option(CXXOPTS_BUILD_EXAMPLES "Set to ON to build examples" ${CXXOPTS_STANDALONE_PROJECT}) +option(CXXOPTS_BUILD_TESTS "Set to ON to build tests" ${CXXOPTS_STANDALONE_PROJECT}) +option(CXXOPTS_ENABLE_INSTALL "Generate the install target" ${CXXOPTS_STANDALONE_PROJECT}) +option(CXXOPTS_ENABLE_WARNINGS "Add warnings to CMAKE_CXX_FLAGS" ${CXXOPTS_STANDALONE_PROJECT}) +option(CXXOPTS_USE_UNICODE_HELP "Use ICU Unicode library" OFF) + +if (CXXOPTS_STANDALONE_PROJECT) + cxxopts_set_cxx_standard() +endif() if (CXXOPTS_ENABLE_WARNINGS) -if(MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") -elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion -Wsuggest-override") -endif() + cxxopts_enable_warnings() endif() add_library(cxxopts INTERFACE) add_library(cxxopts::cxxopts ALIAS cxxopts) +add_subdirectory(include) -# optionally, enable unicode support using the ICU library -set(CXXOPTS_USE_UNICODE_HELP FALSE CACHE BOOL "Use ICU Unicode library") +# Link against the ICU library when requested if(CXXOPTS_USE_UNICODE_HELP) - find_package(PkgConfig) - pkg_check_modules(ICU REQUIRED icu-uc) - - target_link_libraries(cxxopts INTERFACE ${ICU_LDFLAGS}) - target_compile_options(cxxopts INTERFACE ${ICU_CFLAGS}) - target_compile_definitions(cxxopts INTERFACE CXXOPTS_USE_UNICODE) + cxxopts_use_unicode() endif() -target_include_directories(cxxopts INTERFACE - $ - $ - ) - -if(CXXOPTS_ENABLE_INSTALL) - include(GNUInstallDirs) - include(CMakePackageConfigHelpers) - set(CXXOPTS_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/cxxopts" CACHE STRING - "Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.") - set(version_config "${PROJECT_BINARY_DIR}/cxxopts-config-version.cmake") - set(project_config "${PROJECT_BINARY_DIR}/cxxopts-config.cmake") - set(targets_export_name cxxopts-targets) - - # Generate the version, config and target files into the build directory. - write_basic_package_version_file( - ${version_config} - VERSION ${VERSION} - COMPATIBILITY AnyNewerVersion) - configure_package_config_file( - ${PROJECT_SOURCE_DIR}/cxxopts-config.cmake.in - ${project_config} - INSTALL_DESTINATION ${CXXOPTS_CMAKE_DIR}) - export(TARGETS cxxopts NAMESPACE cxxopts:: - FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) - - # Install version, config and target files. - install( - FILES ${project_config} ${version_config} - DESTINATION ${CXXOPTS_CMAKE_DIR}) - install(EXPORT ${targets_export_name} DESTINATION ${CXXOPTS_CMAKE_DIR} - NAMESPACE cxxopts::) - - # Install the header file and export the target - install(TARGETS cxxopts EXPORT ${targets_export_name} DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(FILES ${PROJECT_SOURCE_DIR}/include/cxxopts.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +# Install cxxopts when requested by the user +if (CXXOPTS_ENABLE_INSTALL) + cxxopts_install_logic() endif() -add_subdirectory(src) -add_subdirectory(test) +# Build examples when requested by the user +if (CXXOPTS_BUILD_EXAMPLES) + add_subdirectory(src) +endif() + +# Enable testing when requested by the user +if (CXXOPTS_BUILD_TESTS) + enable_testing() + add_subdirectory(test) +endif() diff --git a/cmake/cxxopts.cmake b/cmake/cxxopts.cmake new file mode 100644 index 0000000..9ef6caa --- /dev/null +++ b/cmake/cxxopts.cmake @@ -0,0 +1,112 @@ +# Copyright (c) 2014 Jarryd Beck +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +if (CMAKE_VERSION VERSION_GREATER 3.10 OR CMAKE_VERSION VERSION_EQUAL 3.10) + # Use include_guard() added in cmake 3.10 + include_guard() +endif() + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +function(cxxopts_getversion version_arg) + # Parse the current version from the cxxopts header + file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/cxxopts.hpp" cxxopts_version_defines + REGEX "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH)") + foreach(ver ${cxxopts_version_defines}) + if(ver MATCHES "#define CXXOPTS__VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") + set(CXXOPTS__VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") + endif() + endforeach() + set(VERSION ${CXXOPTS__VERSION_MAJOR}.${CXXOPTS__VERSION_MINOR}.${CXXOPTS__VERSION_PATCH}) + + # Give feedback to the user. Prefer DEBUG when available since large projects tend to have a lot + # going on already + if (CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15) + message(DEBUG "cxxopts version ${VERSION}") + else() + message(STATUS "cxxopts version ${VERSION}") + endif() + + # Return the information to the caller + set(${version_arg} ${VERSION} PARENT_SCOPE) +endfunction() + +# Optionally, enable unicode support using the ICU library +function(cxxopts_use_unicode) + find_package(PkgConfig) + pkg_check_modules(ICU REQUIRED icu-uc) + + target_link_libraries(cxxopts INTERFACE ${ICU_LDFLAGS}) + target_compile_options(cxxopts INTERFACE ${ICU_CFLAGS}) + target_compile_definitions(cxxopts INTERFACE CXXOPTS_USE_UNICODE) +endfunction() + +# Request C++11 without gnu extension for the whole project and enable more warnings +macro(cxxopts_set_cxx_standard) + if (CXXOPTS_CXX_STANDARD) + set(CMAKE_CXX_STANDARD ${CXXOPTS_CXX_STANDARD}) + else() + set(CMAKE_CXX_STANDARD 11) + endif() + + set(CMAKE_CXX_EXTENSIONS OFF) +endmacro() + +# Helper function to enable warnings +function(cxxopts_enable_warnings) + if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion -Wsuggest-override") + endif() + + set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE) +endfunction() + +# Helper function to ecapsulate install logic +function(cxxopts_install_logic) + set(CXXOPTS_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/cxxopts" CACHE STRING "Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.") + set(version_config "${PROJECT_BINARY_DIR}/cxxopts-config-version.cmake") + set(project_config "${PROJECT_BINARY_DIR}/cxxopts-config.cmake") + set(targets_export_name cxxopts-targets) + + # Generate the version, config and target files into the build directory. + write_basic_package_version_file( + ${version_config} + VERSION ${VERSION} + COMPATIBILITY AnyNewerVersion) + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cxxopts-config.cmake.in + ${project_config} + INSTALL_DESTINATION ${CXXOPTS_CMAKE_DIR}) + export(TARGETS cxxopts NAMESPACE cxxopts:: + FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) + + # Install version, config and target files. + install( + FILES ${project_config} ${version_config} + DESTINATION ${CXXOPTS_CMAKE_DIR}) + install(EXPORT ${targets_export_name} DESTINATION ${CXXOPTS_CMAKE_DIR} + NAMESPACE cxxopts::) + + # Install the header file and export the target + install(TARGETS cxxopts EXPORT ${targets_export_name} DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(FILES ${PROJECT_SOURCE_DIR}/include/cxxopts.hpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endfunction() diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt new file mode 100644 index 0000000..1123c5a --- /dev/null +++ b/include/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 2014 Jarryd Beck +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +target_include_directories(cxxopts INTERFACE + $ + $ +) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eec97b7..451d778 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,15 +1,15 @@ # Copyright (c) 2014 Jarryd Beck -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. -# +# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -18,7 +18,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -if(CXXOPTS_BUILD_EXAMPLES) - add_executable(example example.cpp) - target_link_libraries(example cxxopts) -endif() +add_executable(example example.cpp) +target_link_libraries(example cxxopts) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1969545..d3467f3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,35 +1,53 @@ -if (CXXOPTS_BUILD_TESTS) - add_executable(options_test main.cpp options.cpp) - target_link_libraries(options_test cxxopts) - add_test(options options_test) +# Copyright (c) 2014 Jarryd Beck +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. - # test if the targets are findable from the build directory - add_test(find-package-test ${CMAKE_CTEST_COMMAND} - -C ${CMAKE_BUILD_TYPE} - --build-and-test - "${CMAKE_CURRENT_SOURCE_DIR}/find-package-test" - "${CMAKE_CURRENT_BINARY_DIR}/find-package-test" - --build-generator ${CMAKE_GENERATOR} - --build-makeprogram ${CMAKE_MAKE_PROGRAM} - --build-options - "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" - "-Dcxxopts_DIR=${PROJECT_BINARY_DIR}" - ) +add_executable(options_test main.cpp options.cpp) +target_link_libraries(options_test cxxopts) +add_test(options options_test) - # test if the targets are findable when add_subdirectory is used - add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND} - -C ${CMAKE_BUILD_TYPE} - --build-and-test - "${CMAKE_CURRENT_SOURCE_DIR}/add-subdirectory-test" - "${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test" - --build-generator ${CMAKE_GENERATOR} - --build-makeprogram ${CMAKE_MAKE_PROGRAM} - --build-options - "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" - ) +# test if the targets are findable from the build directory +add_test(find-package-test ${CMAKE_CTEST_COMMAND} + -C ${CMAKE_BUILD_TYPE} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/find-package-test" + "${CMAKE_CURRENT_BINARY_DIR}/find-package-test" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-options + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" + "-Dcxxopts_DIR=${PROJECT_BINARY_DIR}" +) - add_executable(link_test link_a.cpp link_b.cpp) - target_link_libraries(link_test cxxopts) -endif() +# test if the targets are findable when add_subdirectory is used +add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND} + -C ${CMAKE_BUILD_TYPE} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/add-subdirectory-test" + "${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-options + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" +) + +add_executable(link_test link_a.cpp link_b.cpp) +target_link_libraries(link_test cxxopts) From dc9a7728c0e395af0e987f315551213245cd11d1 Mon Sep 17 00:00:00 2001 From: jpr89 <31327577+jpr89@users.noreply.github.com> Date: Tue, 19 Jan 2021 00:55:23 -0500 Subject: [PATCH 06/16] Fixing cmake developer warning (#274) Here is the warning currently being produced: CMake Warning (dev) at C:/Program Files/CMake/share/cmake-3.19/Modules/GNUInstallDirs.cmake:223 (message): Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. Please enable at least one language before including GNUInstallDirs. Call Stack (most recent call first): I noted how I fixed the error. This is caused by GNUInstallDirs automatically executing code just by including it. I also added -Werror=dev to the CI to ensure this never happens again. Co-authored-by: Juan Ramos --- .travis.yml | 2 +- CMakeLists.txt | 3 +++ cmake/cxxopts.cmake | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 87c78a7..8d42327 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,7 +61,7 @@ matrix: - g++-5 sources: *sources script: > - cmake -DCXXOPTS_BUILD_TESTS=ON -DCMAKE_CXX_COMPILER=$COMPILER + cmake -Werror=dev -DCXXOPTS_BUILD_TESTS=ON -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_FLAGS=$CXXFLAGS $UNICODE_OPTIONS $CMAKE_OPTIONS . && make && make ARGS=--output-on-failure test diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e5043d..7db33e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,9 @@ project(cxxopts LANGUAGES CXX ) +# Must include after the project call due to GNUInstallDirs requiring a language be enabled (IE. CXX) +include(GNUInstallDirs) + # Determine whether this is a standalone project or included by other projects set(CXXOPTS_STANDALONE_PROJECT OFF) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) diff --git a/cmake/cxxopts.cmake b/cmake/cxxopts.cmake index 9ef6caa..ef975b8 100644 --- a/cmake/cxxopts.cmake +++ b/cmake/cxxopts.cmake @@ -22,7 +22,6 @@ if (CMAKE_VERSION VERSION_GREATER 3.10 OR CMAKE_VERSION VERSION_EQUAL 3.10) include_guard() endif() -include(GNUInstallDirs) include(CMakePackageConfigHelpers) function(cxxopts_getversion version_arg) From 834fb9999bc906693f1abaf257acbddbc57a6f48 Mon Sep 17 00:00:00 2001 From: Benjamin Sergeant Date: Mon, 18 Jan 2021 22:00:45 -0800 Subject: [PATCH 07/16] Ignore gcc-10 warning (#273) Workaround for GCC 10 null dereference warning. --- include/cxxopts.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 6ec7998..e491b2e 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1133,12 +1133,21 @@ namespace cxxopts m_value->parse(); } +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Werror=null-dereference" +#endif + CXXOPTS_NODISCARD size_t count() const noexcept { return m_count; } + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif // TODO: maybe default options should count towards the number of arguments CXXOPTS_NODISCARD From ed85f04a1b4e6a472f8973971c1f6c69b8afc02f Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 18 Jan 2021 22:05:09 -0800 Subject: [PATCH 08/16] clang-tidy stuff (#266) Several clang-tidy improvements. --- include/cxxopts.hpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index e491b2e..3cc57a5 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -82,7 +82,7 @@ namespace cxxopts namespace cxxopts { - typedef icu::UnicodeString String; + using String = icu::UnicodeString; inline String @@ -217,7 +217,7 @@ namespace std namespace cxxopts { - typedef std::string String; + using String = std::string; template T @@ -562,7 +562,7 @@ namespace cxxopts { template void - operator()(bool, U, const std::string&) {} + operator()(bool, U, const std::string&) const {} }; template @@ -1030,9 +1030,9 @@ namespace cxxopts OptionDetails(const OptionDetails& rhs) : m_desc(rhs.m_desc) + , m_value(rhs.m_value->clone()) , m_count(rhs.m_count) { - m_value = rhs.m_value->clone(); } OptionDetails(OptionDetails&& rhs) = default; @@ -1236,8 +1236,7 @@ namespace cxxopts { public: - ParseResult() {} - + ParseResult() = default; ParseResult(const ParseResult&) = default; ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector sequential, std::vector&& unmatched_args) @@ -1840,9 +1839,9 @@ OptionParser::consume_positional(const std::string& a, PositionalListIterator& n auto iter = m_options.find(*next); if (iter != m_options.end()) { - auto& result = m_parsed[iter->second->hash()]; if (!iter->second->value().is_container()) { + auto& result = m_parsed[iter->second->hash()]; if (result.count() == 0) { add_to_option(iter, *next, a); @@ -1898,7 +1897,7 @@ OptionParser::parse(int argc, const char* const* argv) { int current = 1; bool consume_remaining = false; - PositionalListIterator next_positional = m_positional.begin(); + auto next_positional = m_positional.begin(); std::vector unmatched; @@ -1932,7 +1931,7 @@ OptionParser::parse(int argc, const char* const* argv) } else { - unmatched.push_back(argv[current]); + unmatched.emplace_back(argv[current]); } //if we return from here then it was parsed successfully, so continue } @@ -1987,7 +1986,7 @@ OptionParser::parse(int argc, const char* const* argv) if (m_allow_unrecognised) { // keep unrecognised options in argument list, skip to next argument - unmatched.push_back(argv[current]); + unmatched.emplace_back(argv[current]); ++current; continue; } @@ -2040,7 +2039,7 @@ OptionParser::parse(int argc, const char* const* argv) //adjust argv for any that couldn't be swallowed while (current != argc) { - unmatched.push_back(argv[current]); + unmatched.emplace_back(argv[current]); ++current; } } @@ -2235,12 +2234,16 @@ void Options::generate_all_groups_help(String& result) const { std::vector all_groups; - all_groups.reserve(m_help.size()); - for (const auto& group : m_help) - { - all_groups.push_back(group.first); - } + std::transform( + m_help.begin(), + m_help.end(), + std::back_inserter(all_groups), + [] (const std::map::value_type& group) + { + return group.first; + } + ); generate_group_help(result, all_groups); } From e862445ef338d475edce152442cdc43d720d18ce Mon Sep 17 00:00:00 2001 From: Jarryd Beck Date: Sat, 23 Jan 2021 14:08:56 +1100 Subject: [PATCH 09/16] Fix null dereference warning error Fixes #276. Remove the fix for null dereference warning for GCC after 10.1.0 because this was removed in later versions. --- include/cxxopts.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 3cc57a5..01ce035 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1134,8 +1134,10 @@ namespace cxxopts } #if defined(__GNUC__) +#if __GNUC__ <= 10 && __GNUC_MINOR__ <= 1 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Werror=null-dereference" +#endif #endif CXXOPTS_NODISCARD @@ -1146,7 +1148,9 @@ namespace cxxopts } #if defined(__GNUC__) +#if __GNUC__ <= 10 && __GNUC_MINOR__ <= 1 #pragma GCC diagnostic pop +#endif #endif // TODO: maybe default options should count towards the number of arguments From d10a9b5678c7ea3b2f50e8a19be7594d525c5be9 Mon Sep 17 00:00:00 2001 From: Jarryd Beck Date: Mon, 8 Feb 2021 08:39:51 +1100 Subject: [PATCH 10/16] Upgrade GCC versions --- .travis.yml | 22 ++++++++++++++++++---- cmake/cxxopts.cmake | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d42327..b86f4ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,21 +6,35 @@ os: matrix: include: - os: linux - env: COMPILER=g++-4.9 + env: COMPILER=g++-6 addons: apt: packages: - - g++-4.9 + - g++-6 sources: &sources - llvm-toolchain-trusty-3.8 - llvm-toolchain-trusty-5.0 - ubuntu-toolchain-r-test - os: linux - env: COMPILER=g++-4.9 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes + env: COMPILER=g++-6 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes addons: apt: packages: - - g++-4.9 + - g++-6 + sources: *sources + - os: linux + env: COMPILER=g++-7 + addons: + apt: + packages: + - g++-7 + sources: *sources + - os: linux + env: COMPILER=g++-7 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes + addons: + apt: + packages: + - g++-7 sources: *sources - os: linux env: COMPILER=g++-5 diff --git a/cmake/cxxopts.cmake b/cmake/cxxopts.cmake index ef975b8..e7307f5 100644 --- a/cmake/cxxopts.cmake +++ b/cmake/cxxopts.cmake @@ -73,7 +73,7 @@ function(cxxopts_enable_warnings) if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion -Wsuggest-override") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion") endif() set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE) From f34d6038635f52dc9dd05f35a6bf95469b18abe0 Mon Sep 17 00:00:00 2001 From: Jarryd Beck Date: Mon, 8 Feb 2021 09:33:31 +1100 Subject: [PATCH 11/16] Fix missing override --- cmake/cxxopts.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/cxxopts.cmake b/cmake/cxxopts.cmake index e7307f5..8f9d61a 100644 --- a/cmake/cxxopts.cmake +++ b/cmake/cxxopts.cmake @@ -73,7 +73,11 @@ function(cxxopts_enable_warnings) if(MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion") + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(COMPILER_SPECIFIC_FLAGS "-Wsuggest-override") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion ${COMPILER_SPECIFIC_FLAGS}") endif() set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE) From 43ce03fdbd850385b0461c8873771dc47be5c9b3 Mon Sep 17 00:00:00 2001 From: Wolfgang Gahr Date: Thu, 11 Feb 2021 22:17:55 +0100 Subject: [PATCH 12/16] Improve formatting of help descriptions (#215) * Improve formatting of help descriptions (#213) * new function: cxxopts::Option::set_width(size_t width) Set the size of a helpline. * new function: cxxopts::Option::set_tab_expansion() Expand the tabs in descriptions. The tabsize 8 chars, base is start of description. The descriptions are not disturbed by adding additional options. * Allow newlines \n and tabs \t in descriptions. Other changes (last commit/new commit): * 1453/1471: size_t for OPTION_LONGEST and OPTION_DESC_GAP. This prevents the static cast in 2086/2140. * 2088/2142: in case of small width the value of "width - longest - OPTION_DEC_GAP" becomes negative. Because size_t is unsigned the result is a big number, and the width of the column of the descriptions is not shortened. * new 2143: When the given width is too small, it is set to longest + OPTION_DESC_GAP + 10 * new 1570: A long description is broken into multiple lines, and the iterator lastSpace remembers the begin of the last word. But when the iterator current reaches the end of line, the whole string from iterator is printed, which in soome cases is too long. Thats why one blank is added to the description to trigger the handling of lastSpace. Accordingly in 1574/1627 the line is shortened by one char. * repaired signed/unsigned issue * changes for unicode --- include/cxxopts.hpp | 135 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 105 insertions(+), 30 deletions(-) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 01ce035..b1efb4c 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1403,6 +1403,8 @@ namespace cxxopts , m_positional_help("positional parameters") , m_show_positional(false) , m_allow_unrecognised(false) + , m_width(76) + , m_tab_expansion(false) , m_options(std::make_shared()) { } @@ -1435,6 +1437,20 @@ namespace cxxopts return *this; } + Options& + set_width(size_t width) + { + m_width = width; + return *this; + } + + Options& + set_tab_expansion(bool expansion=true) + { + m_tab_expansion = expansion; + return *this; + } + ParseResult parse(int argc, const char* const* argv); @@ -1519,6 +1535,8 @@ namespace cxxopts std::string m_positional_help{}; bool m_show_positional; bool m_allow_unrecognised; + size_t m_width; + bool m_tab_expansion; std::shared_ptr m_options; std::vector m_positional{}; @@ -1557,8 +1575,8 @@ namespace cxxopts namespace { - constexpr int OPTION_LONGEST = 30; - constexpr int OPTION_DESC_GAP = 2; + constexpr size_t OPTION_LONGEST = 30; + constexpr size_t OPTION_DESC_GAP = 2; std::basic_regex option_matcher ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); @@ -1617,7 +1635,8 @@ namespace cxxopts ( const HelpOptionDetails& o, size_t start, - size_t width + size_t allowed, + bool m_tab_expansion ) { auto desc = o.desc; @@ -1636,54 +1655,107 @@ namespace cxxopts String result; + if (m_tab_expansion) + { + String desc2; + auto size = size_t{ 0 }; + for (auto c = std::begin(desc); c != std::end(desc); ++c) + { + if (*c == '\n') + { + desc2 += *c; + size = 0; + } + else if (*c == '\t') + { + auto skip = 8 - size % 8; + stringAppend(desc2, skip, ' '); + size += skip; + } + else + { + desc2 += *c; + ++size; + } + } + desc = desc2; + } + + desc += " "; + auto current = std::begin(desc); + auto previous = current; auto startLine = current; auto lastSpace = current; auto size = size_t{}; + bool appendNewLine; + bool onlyWhiteSpace = true; + while (current != std::end(desc)) { - if (*current == ' ') + appendNewLine = false; + + if (std::isblank(*previous)) { lastSpace = current; } - if (*current == '\n') + if (!std::isblank(*current)) { - startLine = current + 1; - lastSpace = startLine; + onlyWhiteSpace = false; } - else if (size > width) + + while (*current == '\n') { - if (lastSpace == startLine) + previous = current; + ++current; + appendNewLine = true; + } + + if (!appendNewLine && size >= allowed) + { + if (lastSpace != startLine) { - stringAppend(result, startLine, current + 1); - stringAppend(result, "\n"); - stringAppend(result, start, ' '); - startLine = current + 1; - lastSpace = startLine; + current = lastSpace; + previous = current; } - else + appendNewLine = true; + } + + if (appendNewLine) + { + stringAppend(result, startLine, current); + startLine = current; + lastSpace = current; + + if (*previous != '\n') { - stringAppend(result, startLine, lastSpace); stringAppend(result, "\n"); - stringAppend(result, start, ' '); - startLine = lastSpace + 1; - lastSpace = startLine; } + + stringAppend(result, start, ' '); + + if (*previous != '\n') + { + stringAppend(result, lastSpace, current); + } + + onlyWhiteSpace = true; size = 0; } - else - { - ++size; - } + previous = current; ++current; + ++size; } - //append whatever is left - stringAppend(result, startLine, current); + //append whatever is left but ignore whitespace + if (!onlyWhiteSpace) + { + stringAppend(result, startLine, previous); + } return result; } @@ -2172,11 +2244,14 @@ Options::help_one_group(const std::string& g) const longest = (std::max)(longest, stringLength(s)); format.push_back(std::make_pair(s, String())); } + longest = (std::min)(longest, OPTION_LONGEST); - longest = (std::min)(longest, static_cast(OPTION_LONGEST)); - - //widest allowed description - auto allowed = size_t{76} - longest - OPTION_DESC_GAP; + //widest allowed description -- min 10 chars for helptext/line + size_t allowed = 10; + if (m_width > allowed + longest + OPTION_DESC_GAP) + { + allowed = m_width - longest - OPTION_DESC_GAP; + } auto fiter = format.begin(); for (const auto& o : group->second.options) @@ -2187,7 +2262,7 @@ Options::help_one_group(const std::string& g) const continue; } - auto d = format_description(o, longest + OPTION_DESC_GAP, allowed); + auto d = format_description(o, longest + OPTION_DESC_GAP, allowed, m_tab_expansion); result += fiter->first; if (stringLength(fiter->first) > longest) From aaa5e790b6b5b4c9de0b1ca3346ed0c2e55e4e03 Mon Sep 17 00:00:00 2001 From: Jarryd Beck Date: Mon, 15 Feb 2021 08:33:56 +1100 Subject: [PATCH 13/16] Rename variable, add to example --- include/cxxopts.hpp | 4 ++-- src/example.cpp | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index b1efb4c..eee7ba0 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -1636,7 +1636,7 @@ namespace cxxopts const HelpOptionDetails& o, size_t start, size_t allowed, - bool m_tab_expansion + bool tab_expansion ) { auto desc = o.desc; @@ -1655,7 +1655,7 @@ namespace cxxopts String result; - if (m_tab_expansion) + if (tab_expansion) { String desc2; auto size = size_t{ 0 }; diff --git a/src/example.cpp b/src/example.cpp index 0efb3a4..c21bad6 100644 --- a/src/example.cpp +++ b/src/example.cpp @@ -39,6 +39,8 @@ parse(int argc, const char* argv[]) bool apple = false; options + .set_width(70) + .set_tab_expansion() .allow_unrecognised_options() .add_options() ("a,apple", "an apple", cxxopts::value(apple)) @@ -56,6 +58,7 @@ parse(int argc, const char* argv[]) ("long-description", "thisisareallylongwordthattakesupthewholelineandcannotbebrokenataspace") ("help", "Print help") + ("tab-expansion", "Tab\texpansion") ("int", "An integer", cxxopts::value(), "N") ("float", "A floating point number", cxxopts::value()) ("vector", "A list of doubles", cxxopts::value>()) From dd45a0801c99d62109aaa29f8c410ba8def2fbf2 Mon Sep 17 00:00:00 2001 From: jarro2783 Date: Sat, 20 Feb 2021 15:12:07 +1100 Subject: [PATCH 14/16] Rename BUILD to BUILD.bazel --- BUILD => BUILD.bazel | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename BUILD => BUILD.bazel (100%) diff --git a/BUILD b/BUILD.bazel similarity index 100% rename from BUILD rename to BUILD.bazel From 174510285a451d5e2ab2c4054bc88ce8b4ba933d Mon Sep 17 00:00:00 2001 From: RonxBulld <526677628@qq.com> Date: Wed, 21 Apr 2021 16:17:30 +0800 Subject: [PATCH 15/16] -Wsuggest-override is not supported by gcc before 5.0 (#283) * -Wsuggest-override is not supported by gcc before 5.0 * GCC prior to 5.0 should ignore not only -Wnon-virtual-dtor but also -Weffc++, otherwise non-virtual destructor problems will still be reported. * The `#pragma GCC diagnostic push' should be used before setting up the temporary environment. --- cmake/cxxopts.cmake | 4 +++- include/cxxopts.hpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmake/cxxopts.cmake b/cmake/cxxopts.cmake index 8f9d61a..e65c4b5 100644 --- a/cmake/cxxopts.cmake +++ b/cmake/cxxopts.cmake @@ -74,8 +74,10 @@ function(cxxopts_enable_warnings) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W2") elseif(CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if (${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 5.0) set(COMPILER_SPECIFIC_FLAGS "-Wsuggest-override") - endif() + endif() + endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wshadow -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion ${COMPILER_SPECIFIC_FLAGS}") endif() diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index eee7ba0..9776558 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -288,8 +288,9 @@ namespace cxxopts #if defined(__GNUC__) // GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: // warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" #pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Weffc++" // This will be ignored under other compilers like LLVM clang. #endif class Value : public std::enable_shared_from_this From c04f8a5bb9cabc552e690d8277d4939544813304 Mon Sep 17 00:00:00 2001 From: RonxBulld <526677628@qq.com> Date: Tue, 4 May 2021 15:35:45 +0800 Subject: [PATCH 16/16] Fully compatible with GCC4.8 compilation system. (#285) * -Wsuggest-override is not supported by gcc before 5.0 * GCC prior to 5.0 should ignore not only -Wnon-virtual-dtor but also -Weffc++, otherwise non-virtual destructor problems will still be reported. * The `#pragma GCC diagnostic push' should be used before setting up the temporary environment. * When using GCC4.8, use manual lexical analysis instead of regular expressions. * Add gcc4.8 stuff to travis file. --- .travis.yml | 14 ++ include/cxxopts.hpp | 375 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 318 insertions(+), 71 deletions(-) diff --git a/.travis.yml b/.travis.yml index b86f4ca..942f03f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,6 +50,20 @@ matrix: packages: - g++-5 sources: *sources + - os: linux + env: COMPILER=g++-4.8 + addons: + apt: + packages: + - g++-4.8 + sources: *sources + - os: linux + env: COMPILER=g++-4.8 UNICODE_OPTIONS=-DCXXOPTS_USE_UNICODE_HELP=Yes + addons: + apt: + packages: + - g++-4.8 + sources: *sources - os: linux env: COMPILER=clang++-3.8 CXXFLAGS=-stdlib=libc++ addons: diff --git a/include/cxxopts.hpp b/include/cxxopts.hpp index 9776558..58d5a3d 100644 --- a/include/cxxopts.hpp +++ b/include/cxxopts.hpp @@ -33,13 +33,23 @@ THE SOFTWARE. #include #include #include -#include #include #include #include #include #include #include +#include + +#if defined(__GNUC__) && !defined(__clang__) +# if (__GNUC__ * 10 + __GNUC_MINOR__) < 49 +# define CXXOPTS_NO_REGEX true +# endif +#endif + +#ifndef CXXOPTS_NO_REGEX +# include +#endif // CXXOPTS_NO_REGEX #ifdef __cpp_lib_optional #include @@ -91,6 +101,14 @@ namespace cxxopts return icu::UnicodeString::fromUTF8(std::move(s)); } +#if defined(__GNUC__) +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Weffc++" +// This will be ignored under other compilers like LLVM clang. +#endif class UnicodeStringIterator : public std::iterator { @@ -137,6 +155,9 @@ namespace cxxopts const icu::UnicodeString* s; int32_t i; }; +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif inline String& @@ -519,15 +540,257 @@ namespace cxxopts namespace values { - namespace + namespace parser_tool { - std::basic_regex integer_pattern - ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); - std::basic_regex truthy_pattern - ("(t|T)(rue)?|1"); - std::basic_regex falsy_pattern - ("(f|F)(alse)?|0"); - } // namespace + struct IntegerDesc + { + std::string negative = ""; + std::string base = ""; + std::string value = ""; + }; + struct ArguDesc { + std::string arg_name = ""; + bool grouping = false; + bool set_value = false; + std::string value = ""; + }; +#ifdef CXXOPTS_NO_REGEX + inline IntegerDesc SplitInteger(const std::string &text) + { + if (text.empty()) + { + throw_or_mimic(text); + } + IntegerDesc desc; + const char *pdata = text.c_str(); + if (*pdata == '-') + { + pdata += 1; + desc.negative = "-"; + } + if (strncmp(pdata, "0x", 2) == 0) + { + pdata += 2; + desc.base = "0x"; + } + if (*pdata != '\0') + { + desc.value = std::string(pdata); + } + else + { + throw_or_mimic(text); + } + return desc; + } + + inline bool IsTrueText(const std::string &text) + { + const char *pdata = text.c_str(); + if (*pdata == 't' || *pdata == 'T') + { + pdata += 1; + if (strncmp(pdata, "rue\0", 4) == 0) + { + return true; + } + } + else if (strncmp(pdata, "1\0", 2) == 0) + { + return true; + } + return false; + } + + inline bool IsFalseText(const std::string &text) + { + const char *pdata = text.c_str(); + if (*pdata == 'f' || *pdata == 'F') + { + pdata += 1; + if (strncmp(pdata, "alse\0", 5) == 0) + { + return true; + } + } + else if (strncmp(pdata, "0\0", 2) == 0) + { + return true; + } + return false; + } + + inline std::pair SplitSwitchDef(const std::string &text) + { + std::string short_sw, long_sw; + const char *pdata = text.c_str(); + if (isalnum(*pdata) && *(pdata + 1) == ',') { + short_sw = std::string(1, *pdata); + pdata += 2; + } + while (*pdata == ' ') { pdata += 1; } + if (isalnum(*pdata)) { + const char *store = pdata; + pdata += 1; + while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') { + pdata += 1; + } + if (*pdata == '\0') { + long_sw = std::string(store, pdata - store); + } else { + throw_or_mimic(text); + } + } + return std::pair(short_sw, long_sw); + } + + inline ArguDesc ParseArgument(const char *arg, bool &matched) + { + ArguDesc argu_desc; + const char *pdata = arg; + matched = false; + if (strncmp(pdata, "--", 2) == 0) + { + pdata += 2; + if (isalnum(*pdata)) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + if (argu_desc.arg_name.length() > 1) + { + if (*pdata == '=') + { + argu_desc.set_value = true; + pdata += 1; + if (*pdata != '\0') + { + argu_desc.value = std::string(pdata); + } + matched = true; + } + else if (*pdata == '\0') + { + matched = true; + } + } + } + } + else if (strncmp(pdata, "-", 1) == 0) + { + pdata += 1; + argu_desc.grouping = true; + while (isalnum(*pdata)) + { + argu_desc.arg_name.push_back(*pdata); + pdata += 1; + } + matched = !argu_desc.arg_name.empty() && *pdata == '\0'; + } + return argu_desc; + } + +#else // CXXOPTS_NO_REGEX + + namespace + { + + std::basic_regex integer_pattern + ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); + std::basic_regex truthy_pattern + ("(t|T)(rue)?|1"); + std::basic_regex falsy_pattern + ("(f|F)(alse)?|0"); + + std::basic_regex option_matcher + ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); + std::basic_regex option_specifier + ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); + + } // namespace + + inline IntegerDesc SplitInteger(const std::string &text) + { + std::smatch match; + std::regex_match(text, match, integer_pattern); + + if (match.length() == 0) + { + throw_or_mimic(text); + } + + IntegerDesc desc; + desc.negative = match[1]; + desc.base = match[2]; + desc.value = match[3]; + + if (match.length(4) > 0) + { + desc.base = match[5]; + desc.value = "0"; + return desc; + } + + return desc; + } + + inline bool IsTrueText(const std::string &text) + { + std::smatch result; + std::regex_match(text, result, truthy_pattern); + return !result.empty(); + } + + inline bool IsFalseText(const std::string &text) + { + std::smatch result; + std::regex_match(text, result, falsy_pattern); + return !result.empty(); + } + + inline std::pair SplitSwitchDef(const std::string &text) + { + std::match_results result; + std::regex_match(text.c_str(), result, option_specifier); + if (result.empty()) + { + throw_or_mimic(text); + } + + const std::string& short_sw = result[2]; + const std::string& long_sw = result[3]; + + return std::pair(short_sw, long_sw); + } + + inline ArguDesc ParseArgument(const char *arg, bool &matched) + { + std::match_results result; + std::regex_match(arg, result, option_matcher); + matched = !result.empty(); + + ArguDesc argu_desc; + if (matched) { + argu_desc.arg_name = result[1].str(); + argu_desc.set_value = result[2].length() > 0; + argu_desc.value = result[3].str(); + if (result[4].length() > 0) + { + argu_desc.grouping = true; + argu_desc.arg_name = result[4].str(); + } + } + + return argu_desc; + } + +#endif // CXXOPTS_NO_REGEX +#undef CXXOPTS_NO_REGEX + } namespace detail { @@ -595,45 +858,32 @@ namespace cxxopts void integer_parser(const std::string& text, T& value) { - std::smatch match; - std::regex_match(text, match, integer_pattern); - - if (match.length() == 0) - { - throw_or_mimic(text); - } - - if (match.length(4) > 0) - { - value = 0; - return; - } + parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text); using US = typename std::make_unsigned::type; - constexpr bool is_signed = std::numeric_limits::is_signed; - const bool negative = match.length(1) > 0; - const uint8_t base = match.length(2) > 0 ? 16 : 10; - auto value_match = match[3]; + const bool negative = int_desc.negative.length() > 0; + const uint8_t base = int_desc.base.length() > 0 ? 16 : 10; + const std::string & value_match = int_desc.value; US result = 0; - for (auto iter = value_match.first; iter != value_match.second; ++iter) + for (char ch : value_match) { US digit = 0; - if (*iter >= '0' && *iter <= '9') + if (ch >= '0' && ch <= '9') { - digit = static_cast(*iter - '0'); + digit = static_cast(ch - '0'); } - else if (base == 16 && *iter >= 'a' && *iter <= 'f') + else if (base == 16 && ch >= 'a' && ch <= 'f') { - digit = static_cast(*iter - 'a' + 10); + digit = static_cast(ch - 'a' + 10); } - else if (base == 16 && *iter >= 'A' && *iter <= 'F') + else if (base == 16 && ch >= 'A' && ch <= 'F') { - digit = static_cast(*iter - 'A' + 10); + digit = static_cast(ch - 'A' + 10); } else { @@ -731,17 +981,13 @@ namespace cxxopts void parse_value(const std::string& text, bool& value) { - std::smatch result; - std::regex_match(text, result, truthy_pattern); - - if (!result.empty()) + if (parser_tool::IsTrueText(text)) { value = true; return; } - std::regex_match(text, result, falsy_pattern); - if (!result.empty()) + if (parser_tool::IsFalseText(text)) { value = false; return; @@ -1579,12 +1825,6 @@ namespace cxxopts constexpr size_t OPTION_LONGEST = 30; constexpr size_t OPTION_DESC_GAP = 2; - std::basic_regex option_matcher - ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); - - std::basic_regex option_specifier - ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); - String format_option ( @@ -1794,37 +2034,30 @@ OptionAdder::operator() std::string arg_help ) { - std::match_results result; - std::regex_match(opts.c_str(), result, option_specifier); + std::string short_sw, long_sw; + std::tie(short_sw, long_sw) = values::parser_tool::SplitSwitchDef(opts); - if (result.empty()) + if (!short_sw.length() && !long_sw.length()) { throw_or_mimic(opts); } - - const auto& short_match = result[2]; - const auto& long_match = result[3]; - - if (!short_match.length() && !long_match.length()) - { - throw_or_mimic(opts); - } else if (long_match.length() == 1 && short_match.length()) + else if (long_sw.length() == 1 && short_sw.length()) { throw_or_mimic(opts); } auto option_names = [] ( - const std::sub_match& short_, - const std::sub_match& long_ + const std::string &short_, + const std::string &long_ ) { if (long_.length() == 1) { - return std::make_tuple(long_.str(), short_.str()); + return std::make_tuple(long_, short_); } - return std::make_tuple(short_.str(), long_.str()); - }(short_match, long_match); + return std::make_tuple(short_, long_); + }(short_sw, long_sw); m_options.add_option ( @@ -1986,11 +2219,11 @@ OptionParser::parse(int argc, const char* const* argv) ++current; break; } + bool matched = false; + values::parser_tool::ArguDesc argu_desc = + values::parser_tool::ParseArgument(argv[current], matched); - std::match_results result; - std::regex_match(argv[current], result, option_matcher); - - if (result.empty()) + if (!matched) { //not a flag @@ -2015,9 +2248,9 @@ OptionParser::parse(int argc, const char* const* argv) else { //short or long option? - if (result[4].length() != 0) + if (argu_desc.grouping) { - const std::string& s = result[4]; + const std::string& s = argu_desc.arg_name; for (std::size_t i = 0; i != s.size(); ++i) { @@ -2052,9 +2285,9 @@ OptionParser::parse(int argc, const char* const* argv) } } } - else if (result[1].length() != 0) + else if (argu_desc.arg_name.length() != 0) { - const std::string& name = result[1]; + const std::string& name = argu_desc.arg_name; auto iter = m_options.find(name); @@ -2074,11 +2307,11 @@ OptionParser::parse(int argc, const char* const* argv) auto opt = iter->second; //equals provided for long option? - if (result[2].length() != 0) + if (argu_desc.set_value) { //parse the option given - parse_option(opt, name, result[3]); + parse_option(opt, name, argu_desc.value); } else {