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