Skip to content

Commit 79a1847

Browse files
authored
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
1 parent 3163630 commit 79a1847

File tree

5 files changed

+78
-9
lines changed

5 files changed

+78
-9
lines changed

CMakeLists.txt

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
22

3-
project(CLI11 LANGUAGES CXX)
3+
set(VERSION_REGEX "#define CLI11_VERSION[ \t]+\"(.+)\"")
44

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})
68

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
717
set(CLI_CXX_STD "11" CACHE STRING "The CMake standard to require")
818

919
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
@@ -70,6 +80,18 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/CLI DESTINATION include)
7080
# to Config.cmake (otherwise we'd have a custom config and would
7181
# import Targets.cmake
7282

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+
7395
# Make an export target
7496
install(TARGETS CLI11
7597
EXPORT CLI11Targets)
@@ -129,3 +151,24 @@ if(CLI_EXAMPLES)
129151
add_subdirectory(examples)
130152
endif()
131153

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ download_project(PROJ googletest
1515
)
1616

1717
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 "")
1821
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_SOURCE_DIR} EXCLUDE_FROM_ALL)
22+
unset(CMAKE_SUPPRESS_DEVELOPER_WARNINGS)
1923

2024
if (CMAKE_CONFIGURATION_TYPES)
2125
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}

conanfile.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
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
212

313
class HelloConan(ConanFile):
414
name = "CLI11"
5-
version = "1.3.0"
15+
version = get_version()
616
url = "https://github.com/CLIUtils/CLI11"
717
settings = "os", "compiler", "arch", "build_type"
818
license = "BSD 3 clause"
919
description = "Command Line Interface toolkit for C++11"
1020

11-
exports_sources = "LICENCE", "include/*", "cmake/*", "CMakeLists.txt", "tests/*"
21+
exports_sources = "LICENSE", "README.md", "include/*", "cmake/*", "CMakeLists.txt", "tests/*"
1222

1323
def build(self): # this is not building a library, just tests
1424
cmake = CMake(self)

include/CLI/TypeTools.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@ template <typename T,
7979
bool lexical_cast(std::string input, T &output) {
8080
try {
8181
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;
8485
} catch(const std::invalid_argument &) {
8586
return false;
8687
} catch(const std::out_of_range &) {
@@ -97,8 +98,9 @@ bool lexical_cast(std::string input, T &output) {
9798

9899
try {
99100
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;
102104
} catch(const std::invalid_argument &) {
103105
return false;
104106
} catch(const std::out_of_range &) {

tests/HelpersTest.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,16 @@ TEST(Types, TypeName) {
348348
EXPECT_EQ("TEXT", text2_name);
349349
}
350350

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+
351361
TEST(Types, LexicalCastInt) {
352362
std::string signed_input = "-912";
353363
int x_signed;
@@ -357,7 +367,7 @@ TEST(Types, LexicalCastInt) {
357367
std::string unsigned_input = "912";
358368
unsigned int x_unsigned;
359369
EXPECT_TRUE(CLI::detail::lexical_cast(unsigned_input, x_unsigned));
360-
EXPECT_EQ(912, x_unsigned);
370+
EXPECT_EQ((unsigned int)912, x_unsigned);
361371

362372
EXPECT_FALSE(CLI::detail::lexical_cast(signed_input, x_unsigned));
363373

0 commit comments

Comments
 (0)