From 75dd033cb0be147653e3fb1d807a6c4fc6f49193 Mon Sep 17 00:00:00 2001 From: krcroft Date: Tue, 31 Mar 2020 10:31:08 -0700 Subject: [PATCH] Validate string to double using std::isfinite --- include/support.h | 25 +++++++++++++++++++++++-- src/dos/program_autotype.cpp | 6 +++--- src/misc/support.cpp | 11 ----------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/include/support.h b/include/support.h index a55fe9ff..646c4117 100644 --- a/include/support.h +++ b/include/support.h @@ -23,8 +23,11 @@ #include #include +#include #include #include +#include +#include #include #include @@ -35,8 +38,26 @@ #define strncasecmp(a, b, n) _strnicmp(a, b, n) #endif -// Convert a string to double, returning true or false depending on susccess -bool str_to_double(const std::string& input, double &value); +/* + * Converts a string to a finite number (such as float or double). + * Returns the number or quiet_NaN, if it could not be parsed. + * This function does not attemp to capture exceptions that may + * be thrown from std::stod(...) + */ +template +T to_finite(const std::string& input) { + T result = std::numeric_limits::quiet_NaN(); + size_t bytes_read = 0; + try { + const double interim = std::stod(input, &bytes_read); + if (!input.empty() && bytes_read == input.size()) + result = static_cast(interim); + } + // handle exceptions that stod may throw + catch (std::invalid_argument e) {} + catch (std::out_of_range e) {} + return result; +} // Returns the filename with the prior path stripped. // Works with both \ and / directory delimeters. diff --git a/src/dos/program_autotype.cpp b/src/dos/program_autotype.cpp index c6e1e797..b9755c07 100644 --- a/src/dos/program_autotype.cpp +++ b/src/dos/program_autotype.cpp @@ -83,15 +83,15 @@ bool AUTOTYPE::ReadDoubleArg(const std::string &name, std::string str_value; // Is the user trying to set this flag? if (cmd->FindString(flag, str_value, true)) { - double user_value; // Can the user's value be parsed? - if (str_to_double(str_value, user_value)) { + const double user_value = to_finite(str_value); + if (std::isfinite(user_value)) { result = true; // Clamp the user's value if needed value = clamp(user_value, min_value, max_value); - // If we had to clamp the users value, then inform them + // Inform them if we had to clamp their value if (std::fabs(user_value - value) > std::numeric_limits::epsilon()) WriteOut("AUTOTYPE: bounding %s value of %.2f to %.2f\n", name.c_str(), user_value, value); diff --git a/src/misc/support.cpp b/src/misc/support.cpp index 83e6116e..3edb1c27 100644 --- a/src/misc/support.cpp +++ b/src/misc/support.cpp @@ -35,17 +35,6 @@ #include "support.h" #include "video.h" -bool str_to_double(const std::string& input, double &value) { - bool result = false; - size_t bytes_read = 0; - try { - value = std::stod(input, &bytes_read); - if (bytes_read == input.size()) - result = true; - } catch (std::invalid_argument &) {} - return result; -} - std::string get_basename(const std::string& filename) { // Guard against corner cases: '', '/', '\', 'a' if (filename.length() <= 1)