From 9f9b17a4f0865286391e4d3a0a735230122a2289 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Thu, 21 Oct 2010 17:15:46 +0200 Subject: Introduce strtosz() library function to convert a string to a byte count. strtosz() returns -1 on error. It now supports human unit formats in eg. 1.0G, with better error handling. The following suffixes are supported: B/b = bytes K/k = KB M/m = MB G/g = GB T/t = TB This patch changes -numa and -m input to use strtosz(). Signed-off-by: Jes Sorensen Signed-off-by: Anthony Liguori --- cutils.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) (limited to 'cutils.c') diff --git a/cutils.c b/cutils.c index 588373774..28089aa3e 100644 --- a/cutils.c +++ b/cutils.c @@ -23,6 +23,7 @@ */ #include "qemu-common.h" #include "host-utils.h" +#include void pstrcpy(char *buf, int buf_size, const char *str) { @@ -283,3 +284,90 @@ int fcntl_setfl(int fd, int flag) } #endif +/* + * Convert string to bytes, allowing either B/b for bytes, K/k for KB, + * M/m for MB, G/g for GB or T/t for TB. Default without any postfix + * is MB. End pointer will be returned in *end, if not NULL. A valid + * value must be terminated by whitespace, ',' or '\0'. Return -1 on + * error. + */ +ssize_t strtosz(const char *nptr, char **end) +{ + ssize_t retval = -1; + char *endptr, c; + int mul_required = 0; + double val, mul, integral, fraction; + + errno = 0; + val = strtod(nptr, &endptr); + if (isnan(val) || endptr == nptr || errno != 0) { + goto fail; + } + integral = modf(val, &fraction); + if (integral != 0) { + mul_required = 1; + } + /* + * Any whitespace character is fine for terminating the number, + * in addition we accept ',' to handle strings where the size is + * part of a multi token argument. + */ + c = *endptr; + if (isspace(c) || c == '\0' || c == ',') { + c = 0; + } + switch (c) { + case 'B': + case 'b': + mul = 1; + if (mul_required) { + goto fail; + } + break; + case 'K': + case 'k': + mul = 1 << 10; + break; + case 0: + if (mul_required) { + goto fail; + } + case 'M': + case 'm': + mul = 1ULL << 20; + break; + case 'G': + case 'g': + mul = 1ULL << 30; + break; + case 'T': + case 't': + mul = 1ULL << 40; + break; + default: + goto fail; + } + /* + * If not terminated by whitespace, ',', or \0, increment endptr + * to point to next character, then check that we are terminated + * by an appropriate separating character, ie. whitespace, ',', or + * \0. If not, we are seeing trailing garbage, thus fail. + */ + if (c != 0) { + endptr++; + if (!isspace(*endptr) && *endptr != ',' && *endptr != 0) { + goto fail; + } + } + if ((val * mul >= ~(size_t)0) || val < 0) { + goto fail; + } + retval = val * mul; + +fail: + if (end) { + *end = endptr; + } + + return retval; +} -- cgit v1.2.3