]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
util: new function for scaling numbers
authorEric Blake <eblake@redhat.com>
Mon, 5 Mar 2012 16:28:59 +0000 (09:28 -0700)
committerEric Blake <eblake@redhat.com>
Thu, 8 Mar 2012 01:24:43 +0000 (18:24 -0700)
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.

src/libvirt_private.syms
src/util/util.c
src/util/util.h

index c44c61732ccc3d3ef1641b78a8acaf930052665d..1439d3b5a968f260cd82105b1419e27361aecef6 100644 (file)
@@ -1134,6 +1134,7 @@ virKillProcess;
 virParseNumber;
 virParseVersionString;
 virPipeReadUntilEOF;
+virScaleInteger;
 virSetBlocking;
 virSetCloseExec;
 virSetInherit;
index 7c58c7b05df1a3acc164449c9f26677f4e7e602a..548ed1cbea9bc3a9a222cf89a50fdc09850150d8 100644 (file)
@@ -1632,6 +1632,76 @@ virHexToBin(unsigned char c)
     }
 }
 
+/* Scale an integer VALUE in-place by an optional case-insensitive
+ * SUFFIX, defaulting to SCALE if suffix is NULL or empty (scale is
+ * typically 1 or 1024).  Recognized suffixes include 'b' or 'bytes',
+ * as well as power-of-two scaling via binary abbreviations ('KiB',
+ * 'MiB', ...) or their one-letter counterpart ('k', 'M', ...), and
+ * power-of-ten scaling via SI abbreviations ('KB', 'MB', ...).
+ * 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 && *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
index 5c945cc265cd43173bfbc7f2c92f753a07ca0c9f..85e8bd66fd73bb2d3477b8008e537bb78e6266ca 100644 (file)
@@ -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);