diff --git a/mx_util.c b/mx_util.c index 1e92deb..199bcd5 100644 --- a/mx_util.c +++ b/mx_util.c @@ -79,6 +79,72 @@ inline int mx_stribeginswithany(char *str, char **starts, char **endptr) return _mx_strbeginswithany(str, starts, endptr, 1); } +inline int mx_strtobytes(char *str, unsigned long long int *bytes) +{ + unsigned long long int s = 0; + unsigned long long int t; + + char *end; + + if (!str || !*str) + return -(errno=EINVAL); + + if (strchr(str, '-')) + return -(errno=ERANGE); + + do { + errno = 0; + t = strtoull(str, &end, 10); + + if (errno) + return -errno; + + if (str == end) + return -(errno=EINVAL); + + for (;*end && *end == ' '; end++) + /* empty */; + + switch (*end) { + + case 'T': /* tebi */ + t *= 1024; + + case 'G': /* gibi */ + t *= 1024; + + case 'M': /* mebi */ + t *= 1024; + + case 'k': /* kibi */ + case 'K': + t *= 1024; + + case 'B': /* bytes */ + end++; + break; + + default: + return -(errno=EINVAL); + } + + if (s+t < s) + return -(errno=ERANGE); + + s += t; + + for (;*end && *end == ' '; end++) + /* empty */; + + str = end; + + } while (*str); + + *bytes = s; + + return 0; +} + inline int mx_strtoseconds(char *str, unsigned long long int *seconds) { unsigned long long int s = 0; diff --git a/mx_util.h b/mx_util.h index aad1aff..d805aef 100644 --- a/mx_util.h +++ b/mx_util.h @@ -67,6 +67,8 @@ int mx_strbeginswithany(char *str, char **starts, char **endptr); char *mx_strskipwhitespaces(char *str); +int mx_strtobytes(char *str, unsigned long long int *bytes); + int mx_strtoseconds(char *str, unsigned long long int *seconds); int mx_strtominutes(char *str, unsigned long long int *minutes); diff --git a/test_mx_util.c b/test_mx_util.c index d4ba5db..66dd776 100644 --- a/test_mx_util.c +++ b/test_mx_util.c @@ -244,6 +244,33 @@ static void test_mx_strtominutes(void) assert(mx_strtominutes("test", &l) == -EINVAL); } +static void test_mx_strtobytes(void) +{ + unsigned long long int l; + + assert(mx_strtobytes("123B", &l) == 0); + assert(l == 123); + + assert(mx_strtobytes("2M", &l) == 0); + assert(l == 2*1024*1024); + + assert(mx_strtobytes("1M1024k", &l) == 0); + assert(l == 2*1024*1024); + + assert(mx_strtobytes("1024k1024K", &l) == 0); + assert(l == 2*1024*1024); + + assert(mx_strtobytes("-1", &l) == -ERANGE); + assert(mx_strtobytes(" -1", &l) == -ERANGE); + + assert(mx_strtobytes("2.5M", &l) == -EINVAL); + assert(mx_strtobytes("123", &l) == -EINVAL); + assert(mx_strtobytes("0123", &l) == -EINVAL); + assert(mx_strtobytes("1.2", &l) == -EINVAL); + assert(mx_strtobytes("1,2", &l) == -EINVAL); + assert(mx_strtobytes("test", &l) == -EINVAL); +} + int main(int argc, char *argv[]) { test_mx_strskipwhitespaces(); @@ -256,5 +283,6 @@ int main(int argc, char *argv[]) test_mx_strbeginswithany(); test_mx_strtoseconds(); test_mx_strtominutes(); + test_mx_strtobytes(); return 0; }