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
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list