summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/string.cpp42
-rw-r--r--src/util/string.hpp5
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);