1
0
mirror of https://github.com/CLIUtils/CLI11.git synced 2025-04-29 12:13:52 +00:00

Allow trailing spaces on strings for conversions (#1115)

Allow trailing spaces on strings for conversions to floating point and
integers.

There was a potential confusing error that could occur if strings with
trailing spaces were converted to integer or floating point values. This
PR allows trailing spaces in the strings that would otherwise be
convertible to the appropriate numerical type.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Philip Top 2025-01-27 19:14:18 -08:00 committed by GitHub
parent 10ac3e59a4
commit 92adf2c8c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 24 additions and 1 deletions

View File

@ -968,6 +968,9 @@ bool integral_conversion(const std::string &input, T &output) noexcept {
nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end());
return integral_conversion(nstring, output);
}
if(std::isspace(static_cast<unsigned char>(input.back()))) {
return integral_conversion(trim_copy(input), output);
}
if(input.compare(0, 2, "0o") == 0 || input.compare(0, 2, "0O") == 0) {
val = nullptr;
errno = 0;
@ -1016,13 +1019,16 @@ bool integral_conversion(const std::string &input, T &output) noexcept {
output = static_cast<T>(1);
return true;
}
// remove separators
// remove separators and trailing spaces
if(input.find_first_of("_'") != std::string::npos) {
std::string nstring = input;
nstring.erase(std::remove(nstring.begin(), nstring.end(), '_'), nstring.end());
nstring.erase(std::remove(nstring.begin(), nstring.end(), '\''), nstring.end());
return integral_conversion(nstring, output);
}
if(std::isspace(static_cast<unsigned char>(input.back()))) {
return integral_conversion(trim_copy(input), output);
}
if(input.compare(0, 2, "0o") == 0 || input.compare(0, 2, "0O") == 0) {
val = nullptr;
errno = 0;
@ -1147,6 +1153,13 @@ bool lexical_cast(const std::string &input, T &output) {
if(val == (input.c_str() + input.size())) {
return true;
}
while(std::isspace(static_cast<unsigned char>(*val))) {
++val;
if(val == (input.c_str() + input.size())) {
return true;
}
}
// remove separators
if(input.find_first_of("_'") != std::string::npos) {
std::string nstring = input;

View File

@ -227,9 +227,13 @@ TEST_CASE_METHOD(TApp, "atomic_int_option", "[optiontype]") {
static const std::map<std::string, double> testValuesDouble{
{"3.14159", 3.14159},
{"-3.14159", -3.14159},
{"-3.14159\t", -3.14159},
{"-3.14159 ", -3.14159},
{"+1.0", 1.0},
{"-0.01", -0.01},
{"5e22", 5e22},
{" 5e22", 5e22},
{" 5e22 ", 5e22},
{"-2E-2", -2e-2},
{"5e+22", 5e22},
{"1e06", 1e6},
@ -268,6 +272,7 @@ static const std::map<std::string, std::int64_t> testValuesInt{
{"+99", 99},
{"99", 99},
{"-99", -99},
{"-99 ", -99},
{"0xDEADBEEF", 0xDEADBEEF},
{"0xdeadbeef", 0xDEADBEEF},
{"0XDEADBEEF", 0xDEADBEEF},
@ -280,6 +285,7 @@ static const std::map<std::string, std::int64_t> testValuesInt{
{"995862_262", 995862262},
{"995862262", 995862262},
{"-995862275", -995862275},
{"\t-995862275\t", -995862275},
{"-995'862'275", -995862275},
{"0b11010110", 0xD6},
{"0b1101'0110", 0xD6},
@ -323,6 +329,7 @@ TEST_CASE_METHOD(TApp, "intConversionsErange", "[optiontype]") {
static const std::map<std::string, std::uint64_t> testValuesUInt{
{"+99", 99},
{"99", 99},
{" 99 ", 99},
{"0xDEADBEEF", 0xDEADBEEF},
{"0xdeadbeef", 0xDEADBEEF},
{"0XDEADBEEF", 0xDEADBEEF},
@ -331,13 +338,16 @@ static const std::map<std::string, std::uint64_t> testValuesUInt{
{"0xdead'beef", 0xDEADBEEF},
{"0o01234567", 001234567},
{"0o755", 0755},
{"0o755\t", 0755},
{"0755", 0755},
{"995862_262", 995862262},
{"995862262", 995862262},
{"+995862275", +995862275},
{"+995862275 \n\t", +995862275},
{"995'862'275", 995862275},
{"0b11010110", 0xD6},
{"0b1101'0110", 0xD6},
{"0b1101'0110 ", 0xD6},
{"0B11010110", 0xD6},
{"0B1101'0110", 0xD6},
{"1_2_3_4_5", 12345},