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 | 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 | 17 | set(CLI_CXX_STD "11" CACHE STRING "The CMake standard to require") |
| 8 | 18 | |
| 9 | 19 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) |
| ... | ... | @@ -70,6 +80,18 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include) |
| 70 | 80 | # to Config.cmake (otherwise we'd have a custom config and would |
| 71 | 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 | 95 | # Make an export target |
| 74 | 96 | install(TARGETS CLI11 |
| 75 | 97 | EXPORT CLI11Targets) |
| ... | ... | @@ -129,3 +151,24 @@ if(CLI_EXAMPLES) |
| 129 | 151 | add_subdirectory(examples) |
| 130 | 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 | 15 | ) |
| 16 | 16 | |
| 17 | 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 | 21 | add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL) |
| 22 | +unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS) | |
| 19 | 23 | |
| 20 | 24 | if (CMAKE_CONFIGURATION_TYPES) |
| 21 | 25 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} | ... | ... |
conanfile.py
| 1 | 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 | 13 | class HelloConan(ConanFile): |
| 4 | 14 | name = "CLI11" |
| 5 | - version = "1.3.0" | |
| 15 | + version = get_version() | |
| 6 | 16 | url = "https://github.com/CLIUtils/CLI11" |
| 7 | 17 | settings = "os", "compiler", "arch", "build_type" |
| 8 | 18 | license = "BSD 3 clause" |
| 9 | 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 | 23 | def build(self): # this is not building a library, just tests |
| 14 | 24 | cmake = CMake(self) | ... | ... |
include/CLI/TypeTools.hpp
| ... | ... | @@ -79,8 +79,9 @@ template <typename T, |
| 79 | 79 | bool lexical_cast(std::string input, T &output) { |
| 80 | 80 | try { |
| 81 | 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 | 85 | } catch(const std::invalid_argument &) { |
| 85 | 86 | return false; |
| 86 | 87 | } catch(const std::out_of_range &) { |
| ... | ... | @@ -97,8 +98,9 @@ bool lexical_cast(std::string input, T &output) { |
| 97 | 98 | |
| 98 | 99 | try { |
| 99 | 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 | 104 | } catch(const std::invalid_argument &) { |
| 103 | 105 | return false; |
| 104 | 106 | } catch(const std::out_of_range &) { | ... | ... |
tests/HelpersTest.cpp
| ... | ... | @@ -348,6 +348,16 @@ TEST(Types, TypeName) { |
| 348 | 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 | 361 | TEST(Types, LexicalCastInt) { |
| 352 | 362 | std::string signed_input = "-912"; |
| 353 | 363 | int x_signed; |
| ... | ... | @@ -357,7 +367,7 @@ TEST(Types, LexicalCastInt) { |
| 357 | 367 | std::string unsigned_input = "912"; |
| 358 | 368 | unsigned int x_unsigned; |
| 359 | 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 | 372 | EXPECT_FALSE(CLI::detail::lexical_cast(signed_input, x_unsigned)); |
| 363 | 373 | ... | ... |