Commit ec6a1afb authored by Dariusz Stojaczyk's avatar Dariusz Stojaczyk Committed by Jim Harris
Browse files

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: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/391670


Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent e0e8f53c
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -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
+26 −2
Original line number Diff line number Diff line
@@ -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) {
+41 −0
Original line number Diff line number Diff line
@@ -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;
}
+68 −1
Original line number Diff line number Diff line
@@ -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();
	}