Commit 79a184760591a82e0e68354246e476e3f0f25c71

Authored by Henry Schreiner
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
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 &amp;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  
... ...