Commit 79a184760591a82e0e68354246e476e3f0f25c71
Committed by
GitHub
1 parent
31636306
Overflow (#84)
* Overflowing an integer conversion now results in a conversion failure * CMake improvements for VERSION and inital packing support * Fix for recent addition of overflow check * Conan file now gets version from Version.hpp file too
Showing
5 changed files
with
78 additions
and
9 deletions
CMakeLists.txt
| 1 | cmake_minimum_required(VERSION 3.4 FATAL_ERROR) | 1 | cmake_minimum_required(VERSION 3.4 FATAL_ERROR) |
| 2 | 2 | ||
| 3 | -project(CLI11 LANGUAGES CXX) | 3 | +set(VERSION_REGEX "#define CLI11_VERSION[ \t]+\"(.+)\"") |
| 4 | 4 | ||
| 5 | -SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) | 5 | +# Read in the line containing the version |
| 6 | +file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/CLI/Version.hpp" | ||
| 7 | + VERSION_STRING REGEX ${VERSION_REGEX}) | ||
| 6 | 8 | ||
| 9 | +# Pick out just the version | ||
| 10 | +string(REGEX REPLACE ${VERSION_REGEX} "\\1" VERSION_STRING "${VERSION_STRING}") | ||
| 11 | + | ||
| 12 | +project(CLI11 LANGUAGES CXX VERSION ${VERSION_STRING}) | ||
| 13 | + | ||
| 14 | +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) | ||
| 15 | + | ||
| 16 | +# User settable | ||
| 7 | set(CLI_CXX_STD "11" CACHE STRING "The CMake standard to require") | 17 | set(CLI_CXX_STD "11" CACHE STRING "The CMake standard to require") |
| 8 | 18 | ||
| 9 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) | 19 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) |
| @@ -70,6 +80,18 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include) | @@ -70,6 +80,18 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include) | ||
| 70 | # to Config.cmake (otherwise we'd have a custom config and would | 80 | # to Config.cmake (otherwise we'd have a custom config and would |
| 71 | # import Targets.cmake | 81 | # import Targets.cmake |
| 72 | 82 | ||
| 83 | +# Add the version in a CMake readable way | ||
| 84 | +include(CMakePackageConfigHelpers) | ||
| 85 | +write_basic_package_version_file( | ||
| 86 | + CLI11ConfigVersion.cmake | ||
| 87 | + VERSION ${CLI11_VERSION} | ||
| 88 | + COMPATIBILITY AnyNewerVersion | ||
| 89 | + ) | ||
| 90 | + | ||
| 91 | +# Make version available in the install | ||
| 92 | +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/CLI11ConfigVersion.cmake" | ||
| 93 | + DESTINATION lib/cmake/CLI11) | ||
| 94 | + | ||
| 73 | # Make an export target | 95 | # Make an export target |
| 74 | install(TARGETS CLI11 | 96 | install(TARGETS CLI11 |
| 75 | EXPORT CLI11Targets) | 97 | EXPORT CLI11Targets) |
| @@ -129,3 +151,24 @@ if(CLI_EXAMPLES) | @@ -129,3 +151,24 @@ if(CLI_EXAMPLES) | ||
| 129 | add_subdirectory(examples) | 151 | add_subdirectory(examples) |
| 130 | endif() | 152 | endif() |
| 131 | 153 | ||
| 154 | +# Packaging support | ||
| 155 | +set(CPACK_PACKAGE_VENDOR "github.com/CLIUtils/CLI11") | ||
| 156 | +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Command line interface") | ||
| 157 | +set(CPACK_PACKAGE_VERSION_MAJOR ${CLI11_VERSION_MAJOR}) | ||
| 158 | +set(CPACK_PACKAGE_VERSION_MINOR ${CLI11_VERSION_MINOR}) | ||
| 159 | +set(CPACK_PACKAGE_VERSION_PATCH ${CLI11_VERSION_PATCH}) | ||
| 160 | +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") | ||
| 161 | +set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") | ||
| 162 | +set(CPACK_SOURCE_GENERATOR "TGZ;ZIP") | ||
| 163 | +# CPack collects *everything* except what's listed here. | ||
| 164 | +set(CPACK_SOURCE_IGNORE_FILES | ||
| 165 | + /.git | ||
| 166 | + /dist | ||
| 167 | + /.*build.* | ||
| 168 | + /\\\\.DS_Store | ||
| 169 | + /.*\\\\.egg-info | ||
| 170 | + /var | ||
| 171 | + /Pipfile.*$ | ||
| 172 | +) | ||
| 173 | +include(CPack) | ||
| 174 | + |
cmake/AddGoogletest.cmake
| @@ -15,7 +15,11 @@ download_project(PROJ googletest | @@ -15,7 +15,11 @@ download_project(PROJ googletest | ||
| 15 | ) | 15 | ) |
| 16 | 16 | ||
| 17 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) | 17 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) |
| 18 | + | ||
| 19 | +# CMake warning suppression will not be needed in version 1.9 | ||
| 20 | +set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE BOOL "") | ||
| 18 | add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL) | 21 | add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL) |
| 22 | +unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) | ||
| 19 | 23 | ||
| 20 | if (CMAKE_CONFIGURATION_TYPES) | 24 | if (CMAKE_CONFIGURATION_TYPES) |
| 21 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} | 25 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} |
conanfile.py
| 1 | from conans import ConanFile, CMake | 1 | from conans import ConanFile, CMake |
| 2 | +from conans.tools import load | ||
| 3 | +import re | ||
| 4 | + | ||
| 5 | +def get_version(): | ||
| 6 | + try: | ||
| 7 | + content = load("include/CLI/Version.hpp") | ||
| 8 | + version = re.search(r'#define CLI11_VERSION "(.*)"', content).group(1) | ||
| 9 | + return version | ||
| 10 | + except Exception: | ||
| 11 | + return None | ||
| 2 | 12 | ||
| 3 | class HelloConan(ConanFile): | 13 | class HelloConan(ConanFile): |
| 4 | name = "CLI11" | 14 | name = "CLI11" |
| 5 | - version = "1.3.0" | 15 | + version = get_version() |
| 6 | url = "https://github.com/CLIUtils/CLI11" | 16 | url = "https://github.com/CLIUtils/CLI11" |
| 7 | settings = "os", "compiler", "arch", "build_type" | 17 | settings = "os", "compiler", "arch", "build_type" |
| 8 | license = "BSD 3 clause" | 18 | license = "BSD 3 clause" |
| 9 | description = "Command Line Interface toolkit for C++11" | 19 | description = "Command Line Interface toolkit for C++11" |
| 10 | 20 | ||
| 11 | - exports_sources = "LICENCE", "include/*", "cmake/*", "CMakeLists.txt", "tests/*" | 21 | + exports_sources = "LICENSE", "README.md", "include/*", "cmake/*", "CMakeLists.txt", "tests/*" |
| 12 | 22 | ||
| 13 | def build(self): # this is not building a library, just tests | 23 | def build(self): # this is not building a library, just tests |
| 14 | cmake = CMake(self) | 24 | cmake = CMake(self) |
include/CLI/TypeTools.hpp
| @@ -79,8 +79,9 @@ template <typename T, | @@ -79,8 +79,9 @@ template <typename T, | ||
| 79 | bool lexical_cast(std::string input, T &output) { | 79 | bool lexical_cast(std::string input, T &output) { |
| 80 | try { | 80 | try { |
| 81 | size_t n = 0; | 81 | size_t n = 0; |
| 82 | - output = static_cast<T>(std::stoll(input, &n, 0)); | ||
| 83 | - return n == input.size(); | 82 | + long long output_ll = std::stoll(input, &n, 0); |
| 83 | + output = static_cast<T>(output_ll); | ||
| 84 | + return n == input.size() && static_cast<long long>(output) == output_ll; | ||
| 84 | } catch(const std::invalid_argument &) { | 85 | } catch(const std::invalid_argument &) { |
| 85 | return false; | 86 | return false; |
| 86 | } catch(const std::out_of_range &) { | 87 | } catch(const std::out_of_range &) { |
| @@ -97,8 +98,9 @@ bool lexical_cast(std::string input, T &output) { | @@ -97,8 +98,9 @@ bool lexical_cast(std::string input, T &output) { | ||
| 97 | 98 | ||
| 98 | try { | 99 | try { |
| 99 | size_t n = 0; | 100 | size_t n = 0; |
| 100 | - output = static_cast<T>(std::stoull(input, &n, 0)); | ||
| 101 | - return n == input.size(); | 101 | + unsigned long long output_ll = std::stoull(input, &n, 0); |
| 102 | + output = static_cast<T>(output_ll); | ||
| 103 | + return n == input.size() && static_cast<unsigned long long>(output) == output_ll; | ||
| 102 | } catch(const std::invalid_argument &) { | 104 | } catch(const std::invalid_argument &) { |
| 103 | return false; | 105 | return false; |
| 104 | } catch(const std::out_of_range &) { | 106 | } catch(const std::out_of_range &) { |
tests/HelpersTest.cpp
| @@ -348,6 +348,16 @@ TEST(Types, TypeName) { | @@ -348,6 +348,16 @@ TEST(Types, TypeName) { | ||
| 348 | EXPECT_EQ("TEXT", text2_name); | 348 | EXPECT_EQ("TEXT", text2_name); |
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | +TEST(Types, OverflowSmall) { | ||
| 352 | + char x; | ||
| 353 | + auto strmax = std::to_string(INT8_MAX + 1); | ||
| 354 | + EXPECT_FALSE(CLI::detail::lexical_cast(strmax, x)); | ||
| 355 | + | ||
| 356 | + unsigned char y; | ||
| 357 | + strmax = std::to_string(UINT8_MAX + 1); | ||
| 358 | + EXPECT_FALSE(CLI::detail::lexical_cast(strmax, y)); | ||
| 359 | +} | ||
| 360 | + | ||
| 351 | TEST(Types, LexicalCastInt) { | 361 | TEST(Types, LexicalCastInt) { |
| 352 | std::string signed_input = "-912"; | 362 | std::string signed_input = "-912"; |
| 353 | int x_signed; | 363 | int x_signed; |
| @@ -357,7 +367,7 @@ TEST(Types, LexicalCastInt) { | @@ -357,7 +367,7 @@ TEST(Types, LexicalCastInt) { | ||
| 357 | std::string unsigned_input = "912"; | 367 | std::string unsigned_input = "912"; |
| 358 | unsigned int x_unsigned; | 368 | unsigned int x_unsigned; |
| 359 | EXPECT_TRUE(CLI::detail::lexical_cast(unsigned_input, x_unsigned)); | 369 | EXPECT_TRUE(CLI::detail::lexical_cast(unsigned_input, x_unsigned)); |
| 360 | - EXPECT_EQ(912, x_unsigned); | 370 | + EXPECT_EQ((unsigned int)912, x_unsigned); |
| 361 | 371 | ||
| 362 | EXPECT_FALSE(CLI::detail::lexical_cast(signed_input, x_unsigned)); | 372 | EXPECT_FALSE(CLI::detail::lexical_cast(signed_input, x_unsigned)); |
| 363 | 373 |