Scaling an integer based on a suffix is something we plan on reusing
in several contexts: XML parsing, virsh CLI parsing, and possibly
elsewhere. Make it easy to reuse, as well as adding in support for
powers of 1000.
* src/util/util.h (virScaleInteger): New function.
* src/util/util.c (virScaleInteger): Implement it.
* src/libvirt_private.syms (util.h): Export it.
---
v2: new, but borrows ideas from memory v1 3/3
src/libvirt_private.syms | 1 +
src/util/util.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/util.h | 4 +++
3 files changed, 71 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index a104e70..a6d053b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1121,6 +1121,7 @@ virKillProcess;
virParseNumber;
virParseVersionString;
virPipeReadUntilEOF;
+virScaleInteger;
virSetBlocking;
virSetCloseExec;
virSetInherit;
diff --git a/src/util/util.c b/src/util/util.c
index 7c58c7b..1b71680 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -1632,6 +1632,72 @@ virHexToBin(unsigned char c)
}
}
+/* Scale an integer VALUE by an optional SUFFIX in-place, defaulting
+ * to SCALE if no suffix is present. Ensure that the result does not
+ * exceed LIMIT. Return 0 on success, -1 with error message raised on
+ * failure. */
+int
+virScaleInteger(unsigned long long *value, const char *suffix,
+ unsigned long long scale, unsigned long long limit)
+{
+ if (!suffix || !*suffix) {
+ if (!scale) {
+ virUtilError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid scale %llu"), scale);
+ return -1;
+ }
+ suffix = "";
+ } else if (STRCASEEQ(suffix, "b") || STRCASEEQ(suffix, "byte")
||
+ STRCASEEQ(suffix, "bytes")) {
+ scale = 1;
+ } else {
+ int base;
+
+ if (!suffix[1] || STRCASEEQ(suffix + 1, "iB")) {
+ base = 1024;
+ } else if (c_tolower(suffix[1]) == 'b' && !suffix[2]) {
+ base = 1000;
+ } else {
+ virUtilError(VIR_ERR_INVALID_ARG,
+ _("unknown suffix '%s'"), suffix);
+ return -1;
+ }
+ scale = 1;
+ switch (c_tolower(*suffix)) {
+ case 'e':
+ scale *= base;
+ /* fallthrough */
+ case 'p':
+ scale *= base;
+ /* fallthrough */
+ case 't':
+ scale *= base;
+ /* fallthrough */
+ case 'g':
+ scale *= base;
+ /* fallthrough */
+ case 'm':
+ scale *= base;
+ /* fallthrough */
+ case 'k':
+ scale *= base;
+ break;
+ default:
+ virUtilError(VIR_ERR_INVALID_ARG,
+ _("unknown suffix '%s'"), suffix);
+ return -1;
+ }
+ }
+
+ if (*value >= (limit / scale)) {
+ virUtilError(VIR_ERR_OVERFLOW, _("value too large: %llu%s"),
+ *value, suffix);
+ return -1;
+ }
+ *value *= scale;
+ return 0;
+}
+
/**
* virSkipSpaces:
* @str: pointer to the char pointer used
diff --git a/src/util/util.h b/src/util/util.h
index 5c945cc..85e8bd6 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -157,6 +157,10 @@ int virStrToDouble(char const *s,
char **end_ptr,
double *result);
+int virScaleInteger(unsigned long long *value, const char *suffix,
+ unsigned long long scale, unsigned long long limit)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
int virHexToBin(unsigned char c);
void virSkipSpaces(const char **str) ATTRIBUTE_NONNULL(1);
--
1.7.7.6