util: add a helper function for parsing capacities (1K, 128M, 2G)

Also used it in parsing `-m` SPDK app param,
meaning that it can now accept numbers
followed by a binary prefix - like 512M or 2G.

Change-Id: If458dc08429237f2cb3f3f661bcaf382468df0f0
Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/391670
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Dariusz Stojaczyk 2017-12-13 20:21:28 +01:00 committed by Jim Harris
parent e0e8f53cc0
commit ec6a1afbdb
4 changed files with 150 additions and 3 deletions

View File

@ -148,6 +148,21 @@ size_t spdk_strlen_pad(const void *str, size_t size, int pad);
*/
int spdk_parse_ip_addr(char *ip, char **host, char **port);
/**
* Parse a string representing a number possibly followed by a binary prefix.
* The string can contain a trailing "B" (KB,MB,GB) but it's not necessary.
* "128K" = 128 * 1024; "2G" = 2 * 1024 * 1024; "2GB" = 2 * 1024 * 1024;
* Additionally, lowercase "k", "m", "g" are parsed as well. They are processed
* the same as their uppercase equivalents.
*
* \param cap_str null terminated string
* \param cap pointer where the parsed capacity (in bytes) will be put
* \param has_prefix pointer to a flag that will be set to describe whether given
* string contains a binary prefix
* \returned 0 on success, negative errno otherwise
*/
int spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix);
#ifdef __cplusplus
}
#endif

View File

@ -538,9 +538,33 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
case 'r':
opts->rpc_addr = optarg;
break;
case 's':
opts->mem_size = atoi(optarg);
case 's': {
uint64_t mem_size_mb;
bool mem_size_has_prefix;
rc = spdk_parse_capacity(optarg, &mem_size_mb, &mem_size_has_prefix);
if (rc != 0) {
fprintf(stderr, "invalid memory pool size `-s %s`\n", optarg);
usage(argv[0], &default_opts, app_usage);
exit(EXIT_FAILURE);
}
if (mem_size_has_prefix) {
/* the mem size is in MB by default, so if a prefix was
* specified, we need to manually convert to MB.
*/
mem_size_mb /= 1024 * 1024;
}
if (mem_size_mb > INT_MAX) {
fprintf(stderr, "invalid memory pool size `-s %s`\n", optarg);
usage(argv[0], &default_opts, app_usage);
exit(EXIT_FAILURE);
}
opts->mem_size = (int) mem_size_mb;
break;
}
case 't':
rc = spdk_log_set_trace_flag(optarg);
if (rc < 0) {

View File

@ -342,3 +342,44 @@ spdk_strerror_r(int errnum, char *buf, size_t buflen)
return strerror_r(errnum, buf, buflen);
#endif
}
int
spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix)
{
int rc;
char bin_prefix;
rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix);
if (rc == 1) {
*has_prefix = false;
return 0;
} else if (rc == 0) {
if (errno == 0) {
/* No scanf matches - the string does not start with a digit */
return -EINVAL;
} else {
/* Parsing error */
return -errno;
}
}
*has_prefix = true;
switch (bin_prefix) {
case 'k':
case 'K':
*cap *= 1024;
break;
case 'm':
case 'M':
*cap *= 1024 * 1024;
break;
case 'g':
case 'G':
*cap *= 1024 * 1024 * 1024;
break;
default:
return -EINVAL;
}
return 0;
}

View File

@ -136,6 +136,72 @@ test_str_chomp(void)
CU_ASSERT(strcmp(s, "a") == 0);
}
static void
test_parse_capacity(void)
{
char str[128];
uint64_t cap;
int rc;
bool has_prefix;
rc = spdk_parse_capacity("472", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 472);
CU_ASSERT(has_prefix == false);
sprintf(str, "%"PRIu64, UINT64_MAX);
rc = spdk_parse_capacity(str, &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == UINT64_MAX);
CU_ASSERT(has_prefix == false);
rc = spdk_parse_capacity("12k", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 12 * 1024);
CU_ASSERT(has_prefix == true);
rc = spdk_parse_capacity("12K", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 12 * 1024);
CU_ASSERT(has_prefix == true);
rc = spdk_parse_capacity("12KB", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 12 * 1024);
CU_ASSERT(has_prefix == true);
rc = spdk_parse_capacity("100M", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 100 * 1024 * 1024);
CU_ASSERT(has_prefix == true);
rc = spdk_parse_capacity("128M", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 128 * 1024 * 1024);
CU_ASSERT(has_prefix == true);
rc = spdk_parse_capacity("4G", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 4ULL * 1024 * 1024 * 1024);
CU_ASSERT(has_prefix == true);
rc = spdk_parse_capacity("100M 512k", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 100ULL * 1024 * 1024);
rc = spdk_parse_capacity("12k8K", &cap, &has_prefix);
CU_ASSERT(rc == 0);
CU_ASSERT(cap == 12 * 1024);
CU_ASSERT(has_prefix == true);
/* Non-number */
rc = spdk_parse_capacity("G", &cap, &has_prefix);
CU_ASSERT(rc != 0);
rc = spdk_parse_capacity("darsto", &cap, &has_prefix);
CU_ASSERT(rc != 0);
}
int
main(int argc, char **argv)
{
@ -154,7 +220,8 @@ main(int argc, char **argv)
if (
CU_add_test(suite, "test_parse_ip_addr", test_parse_ip_addr) == NULL ||
CU_add_test(suite, "test_str_chomp", test_str_chomp) == NULL) {
CU_add_test(suite, "test_str_chomp", test_str_chomp) == NULL ||
CU_add_test(suite, "test_parse_capacity", test_parse_capacity) == NULL) {
CU_cleanup_registry();
return CU_get_error();
}