From 82f190f8822c34137b8e0fcc6a7ca5efbc41d53d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 19 Nov 2024 09:15:19 +0100 Subject: [PATCH] MINOR: tools: make parse_size_err() support 32/64 bits parse_size_err() currently is a function working only on an uint. It's not convenient for certain elements such as rings on large machines. This commit addresses this by having one function for uints and one for ullong, and making parse_size_err() a macro that automatically calls one or the other. It also has the benefit of automatically supporting compatible types (long, size_t etc). --- include/haproxy/tools.h | 21 +++++++++++- src/tools.c | 73 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 2 deletions(-) diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index aa9fd777c..72bb5325e 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -642,7 +642,26 @@ extern time_t my_timegm(const struct tm *tm); * is left untouched. */ extern const char *parse_time_err(const char *text, unsigned *ret, unsigned unit_flags); -extern const char *parse_size_err(const char *text, unsigned *ret); +extern const char *parse_size_ui(const char *text, unsigned *ret); +extern const char *parse_size_ull(const char *text, ullong *ret); + +/* Parse a size from <_test> into <_ret> which must be compatible with a + * uint or ullong. The return value is a pointer to the first unparsable + * character (if any) or NULL if everything's OK. + */ +#define parse_size_err(_text, _ret) ({ \ + const char *_err; \ + if (sizeof(*(_ret)) > sizeof(int)) { \ + unsigned long long _tmp; \ + _err = parse_size_ull(_text, &_tmp); \ + *_ret = _tmp; \ + } else { \ + unsigned int _tmp; \ + _err = parse_size_ui(_text, &_tmp); \ + *_ret = _tmp; \ + } \ + _err; \ +}) /* * Parse binary string written in hexadecimal (source) and store the decoded diff --git a/src/tools.c b/src/tools.c index d2decb69b..224c5df97 100644 --- a/src/tools.c +++ b/src/tools.c @@ -2780,7 +2780,8 @@ const char *parse_time_err(const char *text, unsigned *ret, unsigned unit_flags) * stored in . If an error is detected, the pointer to the unexpected * character is returned. If the conversion is successful, NULL is returned. */ -const char *parse_size_err(const char *text, unsigned *ret) { +const char *parse_size_ui(const char *text, unsigned *ret) +{ unsigned value = 0; if (!isdigit((unsigned char)*text)) @@ -2833,6 +2834,76 @@ const char *parse_size_err(const char *text, unsigned *ret) { return NULL; } +/* this function converts the string starting at to an ullong stored in + * . If an error is detected, the pointer to the unexpected character is + * returned. If the conversion is successful, NULL is returned. + */ +const char *parse_size_ull(const char *text, ullong *ret) +{ + ullong value = 0; + + if (!isdigit((unsigned char)*text)) + return text; + + while (1) { + unsigned int j; + + j = *text - '0'; + if (j > 9) + break; + if (value > ~0ULL / 10) + return text; + value *= 10; + if (value > (value + j)) + return text; + value += j; + text++; + } + + switch (*text) { + case '\0': + break; + case 'K': + case 'k': + if (value > ~0ULL >> 10) + return text; + value = value << 10; + break; + case 'M': + case 'm': + if (value > ~0ULL >> 20) + return text; + value = value << 20; + break; + case 'G': + case 'g': + if (value > ~0ULL >> 30) + return text; + value = value << 30; + break; + case 'T': + case 't': + if (value > ~0ULL >> 40) + return text; + value = value << 40; + break; + case 'P': + case 'p': + if (value > ~0ULL >> 50) + return text; + value = value << 50; + break; + default: + return text; + } + + if (*text != '\0' && *++text != '\0') + return text; + + *ret = value; + return NULL; +} + /* * Parse binary string written in hexadecimal (source) and store the decoded * result into binstr and set binstrlen to the length of binstr. Memory for