[libvirt] [PATCHv2 03/15] util: new function for scaling numbers

Eric Blake eblake at redhat.com
Tue Mar 6 00:34:18 UTC 2012


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




More information about the libvir-list mailing list