diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/string.cpp | 42 | ||||
-rw-r--r-- | src/util/string.hpp | 5 |
2 files changed, 47 insertions, 0 deletions
diff --git a/src/util/string.cpp b/src/util/string.cpp index 914f1f74..4ad3decd 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -114,6 +114,48 @@ parse_signed(std::string_view value, } } +nonstd::expected<uint64_t, std::string> +parse_size(const std::string& value) +{ + errno = 0; + + char* p; + double result = strtod(value.c_str(), &p); + if (errno != 0 || result < 0 || p == value.c_str() || value.empty()) { + return nonstd::make_unexpected(FMT("invalid size: \"{}\"", value)); + } + + while (isspace(*p)) { + ++p; + } + + if (*p != '\0') { + unsigned multiplier = *(p + 1) == 'i' ? 1024 : 1000; + switch (*p) { + case 'T': + result *= multiplier; + [[fallthrough]]; + case 'G': + result *= multiplier; + [[fallthrough]]; + case 'M': + result *= multiplier; + [[fallthrough]]; + case 'K': + case 'k': + result *= multiplier; + break; + default: + return nonstd::make_unexpected(FMT("invalid size: \"{}\"", value)); + } + } else { + // Default suffix: G. + result *= 1000 * 1000 * 1000; + } + + return static_cast<uint64_t>(result); +} + nonstd::expected<mode_t, std::string> parse_umask(std::string_view value) { diff --git a/src/util/string.hpp b/src/util/string.hpp index 5154915d..7df40aad 100644 --- a/src/util/string.hpp +++ b/src/util/string.hpp @@ -77,6 +77,11 @@ parse_signed(std::string_view value, std::optional<int64_t> max_value = std::nullopt, std::string_view description = "integer"); +// Parse a "size value", i.e. a string that can end in k, M, G, T (10-based +// suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility, K +// is also recognized as a synonym of k. +nonstd::expected<uint64_t, std::string> parse_size(const std::string& value); + // Parse `value` (an octal integer). nonstd::expected<mode_t, std::string> parse_umask(std::string_view value); |