From: Jan Fajerski Date: Tue, 30 Jan 2018 08:50:25 +0000 (+0100) Subject: common/strtol: add string_view interface and use string_view internally X-Git-Tag: v13.1.0~258^2~3 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=143c776ba30f42df85f2d83184f179fee2104063;p=ceph.git common/strtol: add string_view interface and use string_view internally Signed-off-by: Jan Fajerski --- diff --git a/src/common/strtol.cc b/src/common/strtol.cc index 43a7de011faa5..b2a90963dff13 100644 --- a/src/common/strtol.cc +++ b/src/common/strtol.cc @@ -18,81 +18,81 @@ #include #include #include +#include using std::ostringstream; -long long strict_strtoll(const char *str, int base, std::string *err) +long long strict_strtoll(const std::string_view str, int base, std::string *err) { + ostringstream errStr; + if (auto invalid = str.find_first_not_of("0123456789-+"); + invalid != std::string_view::npos || + invalid == 0) { + errStr << "The option value '" << str << "' contains invalid digits"; + *err = errStr.str(); + return 0; + } char *endptr; - std::string errStr; errno = 0; /* To distinguish success/failure after call (see man page) */ - long long ret = strtoll(str, &endptr, base); + long long ret = strtoll(str.data(), &endptr, base); - if (endptr == str) { - errStr = "Expected option value to be integer, got '"; - errStr.append(str); - errStr.append("'"); - *err = errStr; + if (endptr == str.data()) { + errStr << "Expected option value to be integer, got '" << str << "'"; + *err = errStr.str(); return 0; } if ((errno == ERANGE && (ret == LLONG_MAX || ret == LLONG_MIN)) || (errno != 0 && ret == 0)) { - errStr = "The option value '"; - errStr.append(str); - errStr.append("'"); - errStr.append(" seems to be invalid"); - *err = errStr; - return 0; - } - if (*endptr != '\0') { - errStr = "The option value '"; - errStr.append(str); - errStr.append("'"); - errStr.append(" contains invalid digits"); - *err = errStr; + errStr << "The option value '" << str << "' seems to be invalid"; + *err = errStr.str(); return 0; } *err = ""; return ret; } -int strict_strtol(const char *str, int base, std::string *err) +long long strict_strtoll(const char *str, int base, std::string *err) { - std::string errStr; + return strict_strtoll(std::string_view(str), base, err); +} + +int strict_strtol(const std::string_view str, int base, std::string *err) +{ + ostringstream errStr; long long ret = strict_strtoll(str, base, err); if (!err->empty()) return 0; if ((ret < INT_MIN) || (ret > INT_MAX)) { - errStr = "The option value '"; - errStr.append(str); - errStr.append("'"); - errStr.append(" seems to be invalid"); - *err = errStr; + errStr << "The option value '" << str << "' seems to be invalid"; + *err = errStr.str(); return 0; } return static_cast(ret); } -double strict_strtod(const char *str, std::string *err) +int strict_strtol(const char *str, int base, std::string *err) +{ + return strict_strtol(std::string_view(str), base, err); +} + +double strict_strtod(const std::string_view str, std::string *err) { char *endptr; + ostringstream oss; errno = 0; /* To distinguish success/failure after call (see man page) */ - double ret = strtod(str, &endptr); + double ret = strtod(str.data(), &endptr); if (errno == ERANGE) { - ostringstream oss; oss << "strict_strtod: floating point overflow or underflow parsing '" << str << "'"; *err = oss.str(); return 0.0; } if (endptr == str) { - ostringstream oss; oss << "strict_strtod: expected double, got: '" << str << "'"; *err = oss.str(); return 0; } if (*endptr != '\0') { - ostringstream oss; oss << "strict_strtod: garbage at end of string. got: '" << str << "'"; *err = oss.str(); return 0; @@ -101,26 +101,29 @@ double strict_strtod(const char *str, std::string *err) return ret; } -float strict_strtof(const char *str, std::string *err) +double strict_strtod(const char *str, std::string *err) +{ + return strict_strtod(std::string_view(str), err); +} + +float strict_strtof(const std::string_view str, std::string *err) { char *endptr; + ostringstream oss; errno = 0; /* To distinguish success/failure after call (see man page) */ - float ret = strtof(str, &endptr); + float ret = strtof(str.data(), &endptr); if (errno == ERANGE) { - ostringstream oss; oss << "strict_strtof: floating point overflow or underflow parsing '" << str << "'"; *err = oss.str(); return 0.0; } if (endptr == str) { - ostringstream oss; oss << "strict_strtof: expected float, got: '" << str << "'"; *err = oss.str(); return 0; } if (*endptr != '\0') { - ostringstream oss; oss << "strict_strtof: garbage at end of string. got: '" << str << "'"; *err = oss.str(); return 0; @@ -129,55 +132,74 @@ float strict_strtof(const char *str, std::string *err) return ret; } +float strict_strtof(const char *str, std::string *err) +{ + return strict_strtof(std::string_view(str), err); +} + template -T strict_iec_cast(const char *str, std::string *err) +T strict_iec_cast(const std::string_view str, std::string *err) { - std::string s(str); - if (s.empty()) { + if (str.empty()) { *err = "strict_iecstrtoll: value not specified"; return 0; } - char &u = s.back(); - // consume 'i' if present, fail if "Bi" is passed - if ( u == 'i') { - s.pop_back(); - u = s.back(); - if (u == 'B') { - *err = "strict_iecstrtoll: illegal prefix \"Bi\""; + // get a view of the unit and of the value + std::string_view unit; + std::string_view n = str; + size_t u = str.find_first_not_of("0123456789-+"); + int m = 0; + // deal with unit prefix is there is one + if (u != std::string_view::npos) { + n = str.substr(0, u); + unit = str.substr(u, str.length() - u); + // we accept both old si prefixes as well as the proper iec prefixes + // i.e. K, M, ... and Ki, Mi, ... + if (unit.back() == 'i') { + if (unit.front() == 'B') { + *err = "strict_iecstrtoll: illegal prefix \"Bi\""; + return 0; + } + } + if (unit.length() > 2) { + *err = "strict_iecstrtoll: illegal prefix (length > 2)"; return 0; } + switch(unit.front()) { + case 'K': + m = 10; + break; + case 'M': + m = 20; + break; + case 'G': + m = 30; + break; + case 'T': + m = 40; + break; + case 'P': + m = 50; + break; + case 'E': + m = 60; + break; + case 'B': + break; + default: + *err = "strict_iecstrtoll: unit prefix not recognized"; + return 0; + } } - int m = 0; - if (u == 'B') - m = 0; - else if (u == 'K') - m = 10; - else if (u == 'M') - m = 20; - else if (u == 'G') - m = 30; - else if (u == 'T') - m = 40; - else if (u == 'P') - m = 50; - else if (u == 'E') - m = 60; - else - m = -1; - - if (m >= 0) - s.pop_back(); - else - m = 0; - long long ll = strict_strtoll(s.c_str(), 10, err); + long long ll = strict_strtoll(n, 10, err); if (ll < 0 && !std::numeric_limits::is_signed) { *err = "strict_iecstrtoll: value should not be negative"; return 0; } if (static_cast(m) >= sizeof(T) * CHAR_BIT) { *err = ("strict_iecstrtoll: the IEC prefix is too large for the designated " - "type"); + "type"); return 0; } using promoted_t = typename std::common_type::type; @@ -194,44 +216,68 @@ T strict_iec_cast(const char *str, std::string *err) return (ll << m); } +template int strict_iec_cast(const std::string_view str, std::string *err); +template long strict_iec_cast(const std::string_view str, std::string *err); +template long long strict_iec_cast(const std::string_view str, std::string *err); +template uint64_t strict_iec_cast(const std::string_view str, std::string *err); +template uint32_t strict_iec_cast(const std::string_view str, std::string *err); + +uint64_t strict_iecstrtoll(const std::string_view str, std::string *err) +{ + return strict_iec_cast(str, err); +} + +uint64_t strict_iecstrtoll(const char *str, std::string *err) +{ + return strict_iec_cast(std::string_view(str), err); +} + +template +T strict_iec_cast(const char *str, std::string *err) +{ + return strict_iec_cast(std::string_view(str), err); +} + template int strict_iec_cast(const char *str, std::string *err); template long strict_iec_cast(const char *str, std::string *err); template long long strict_iec_cast(const char *str, std::string *err); template uint64_t strict_iec_cast(const char *str, std::string *err); template uint32_t strict_iec_cast(const char *str, std::string *err); -uint64_t strict_iecstrtoll(const char *str, std::string *err) -{ - return strict_iec_cast(str, err); -} - template -T strict_si_cast(const char *str, std::string *err) +T strict_si_cast(const std::string_view str, std::string *err) { - std::string s(str); - if (s.empty()) { + if (str.empty()) { *err = "strict_sistrtoll: value not specified"; return 0; } - char &u = s.back(); + std::string_view n = str; int m = 0; - if (u == 'K') - m = 3; - else if (u == 'M') - m = 6; - else if (u == 'G') - m = 9; - else if (u == 'T') - m = 12; - else if (u == 'P') - m = 15; - else if (u == 'E') - m = 18; + // deal with unit prefix is there is one + if (str.find_first_not_of("0123456789+-") != std::string_view::npos) { + const char &u = str.back(); + if (u == 'K') + m = 3; + else if (u == 'M') + m = 6; + else if (u == 'G') + m = 9; + else if (u == 'T') + m = 12; + else if (u == 'P') + m = 15; + else if (u == 'E') + m = 18; + else if (u != 'B') { + *err = "strict_si_cast: unit prefix not recognized"; + return 0; + } - if (m >= 3) - s.pop_back(); + if (m >= 3) + n = str.substr(0, str.length() -1); + } - long long ll = strict_strtoll(s.c_str(), 10, err); + long long ll = strict_strtoll(n, 10, err); if (ll < 0 && !std::numeric_limits::is_signed) { *err = "strict_sistrtoll: value should not be negative"; return 0; @@ -250,13 +296,30 @@ T strict_si_cast(const char *str, std::string *err) return (ll * pow (10, m)); } -template int strict_si_cast(const char *str, std::string *err); -template long strict_si_cast(const char *str, std::string *err); -template long long strict_si_cast(const char *str, std::string *err); -template uint64_t strict_si_cast(const char *str, std::string *err); -template uint32_t strict_si_cast(const char *str, std::string *err); +template int strict_si_cast(const std::string_view str, std::string *err); +template long strict_si_cast(const std::string_view str, std::string *err); +template long long strict_si_cast(const std::string_view str, std::string *err); +template uint64_t strict_si_cast(const std::string_view str, std::string *err); +template uint32_t strict_si_cast(const std::string_view str, std::string *err); + +uint64_t strict_sistrtoll(const std::string_view str, std::string *err) +{ + return strict_si_cast(str, err); +} uint64_t strict_sistrtoll(const char *str, std::string *err) { return strict_si_cast(str, err); } + +template +T strict_si_cast(const char *str, std::string *err) +{ + return strict_si_cast(std::string_view(str), err); +} + +template int strict_si_cast(const char *str, std::string *err); +template long strict_si_cast(const char *str, std::string *err); +template long long strict_si_cast(const char *str, std::string *err); +template uint64_t strict_si_cast(const char *str, std::string *err); +template uint32_t strict_si_cast(const char *str, std::string *err); diff --git a/src/test/cli/monmaptool/feature-set-unset-list.t b/src/test/cli/monmaptool/feature-set-unset-list.t index 33e069be22748..306a495cb6db5 100644 --- a/src/test/cli/monmaptool/feature-set-unset-list.t +++ b/src/test/cli/monmaptool/feature-set-unset-list.t @@ -28,7 +28,7 @@ available:persistent:[kraken(1),luminous(2),mimic(4)] $ monmaptool --feature-set foo /tmp/test.monmap.1234 - unknown features name 'foo' or unable to parse value: Expected option value to be integer, got 'foo' + unknown features name 'foo' or unable to parse value: The option value 'foo' contains invalid digits usage: [--print] [--create [--clobber][--fsid uuid]] [--generate] [--set-initial-members] [--add name 1.2.3.4:567] [--rm name] diff --git a/src/test/strtol.cc b/src/test/strtol.cc index a7ef3e51d1db7..69d1a70871e0a 100644 --- a/src/test/strtol.cc +++ b/src/test/strtol.cc @@ -127,9 +127,11 @@ TEST(StrToL, Error1) { test_strict_strtoll_err("604462909807314587353088"); // overflow test_strict_strtoll_err("aw shucks"); // invalid test_strict_strtoll_err("343245 aw shucks"); // invalid chars at end + test_strict_strtoll_err("-"); // invalid test_strict_strtol_err("35 aw shucks"); // invalid chars at end test_strict_strtol_err("--0"); + test_strict_strtol_err("-"); test_strict_strtod_err("345345.0-"); test_strict_strtod_err("34.0 garbo");