diff options
author | Anita Zhang <the.anitazha@gmail.com> | 2021-02-02 01:47:08 -0800 |
---|---|---|
committer | Anita Zhang <the.anitazha@gmail.com> | 2021-02-02 01:47:08 -0800 |
commit | 94a8e2d6db689b0349091829e809e751fff9b812 (patch) | |
tree | b61d961762471c79cf21b53ebb0c9cd5c724b1ef | |
parent | 77591e97327d6fc47f27599ba1937629afb6dd13 (diff) | |
download | systemd-94a8e2d6db689b0349091829e809e751fff9b812.tar.gz |
parse-util: add permyriad parsing
-rw-r--r-- | src/basic/parse-util.c | 137 | ||||
-rw-r--r-- | src/basic/parse-util.h | 3 | ||||
-rw-r--r-- | src/test/test-parse-util.c | 68 |
3 files changed, 169 insertions, 39 deletions
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 2a7280fc38..97d224f165 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -627,11 +627,11 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { return 0; } -int parse_percent_unbounded(const char *p) { +static int parse_parts_value_whole(const char *p, const char *symbol) { const char *pc, *n; int r, v; - pc = endswith(p, "%"); + pc = endswith(p, symbol); if (!pc) return -EINVAL; @@ -645,6 +645,74 @@ int parse_percent_unbounded(const char *p) { return v; } +static int parse_parts_value_with_tenths_place(const char *p, const char *symbol) { + const char *pc, *dot, *n; + int r, q, v; + + pc = endswith(p, symbol); + if (!pc) + return -EINVAL; + + dot = memchr(p, '.', pc - p); + if (dot) { + if (dot + 2 != pc) + return -EINVAL; + if (dot[1] < '0' || dot[1] > '9') + return -EINVAL; + q = dot[1] - '0'; + n = strndupa(p, dot - p); + } else { + q = 0; + n = strndupa(p, pc - p); + } + r = safe_atoi(n, &v); + if (r < 0) + return r; + if (v < 0) + return -ERANGE; + if (v > (INT_MAX - q) / 10) + return -ERANGE; + + v = v * 10 + q; + return v; +} + +static int parse_parts_value_with_hundredths_place(const char *p, const char *symbol) { + const char *pc, *dot, *n; + int r, q, v; + + pc = endswith(p, symbol); + if (!pc) + return -EINVAL; + + dot = memchr(p, '.', pc - p); + if (dot) { + if (dot + 3 != pc) + return -EINVAL; + if (dot[1] < '0' || dot[1] > '9' || dot[2] < '0' || dot[2] > '9') + return -EINVAL; + q = (dot[1] - '0') * 10 + (dot[2] - '0'); + n = strndupa(p, dot - p); + } else { + q = 0; + n = strndupa(p, pc - p); + } + r = safe_atoi(n, &v); + if (r < 0) + return r; + if (v < 0) + return -ERANGE; + if (v > (INT_MAX - q) / 100) + return -ERANGE; + + v = v * 100 + q; + return v; +} + +int parse_percent_unbounded(const char *p) { + return parse_parts_value_whole(p, "%"); +} + int parse_percent(const char *p) { int v; @@ -656,46 +724,13 @@ int parse_percent(const char *p) { } int parse_permille_unbounded(const char *p) { - const char *pc, *pm, *dot, *n; - int r, q, v; + const char *pm; pm = endswith(p, "‰"); - if (pm) { - n = strndupa(p, pm - p); - r = safe_atoi(n, &v); - if (r < 0) - return r; - if (v < 0) - return -ERANGE; - } else { - pc = endswith(p, "%"); - if (!pc) - return -EINVAL; - - dot = memchr(p, '.', pc - p); - if (dot) { - if (dot + 2 != pc) - return -EINVAL; - if (dot[1] < '0' || dot[1] > '9') - return -EINVAL; - q = dot[1] - '0'; - n = strndupa(p, dot - p); - } else { - q = 0; - n = strndupa(p, pc - p); - } - r = safe_atoi(n, &v); - if (r < 0) - return r; - if (v < 0) - return -ERANGE; - if (v > (INT_MAX - q) / 10) - return -ERANGE; + if (pm) + return parse_parts_value_whole(p, "‰"); - v = v * 10 + q; - } - - return v; + return parse_parts_value_with_tenths_place(p, "%"); } int parse_permille(const char *p) { @@ -708,6 +743,30 @@ int parse_permille(const char *p) { return v; } +int parse_permyriad_unbounded(const char *p) { + const char *pm; + + pm = endswith(p, "‱"); + if (pm) + return parse_parts_value_whole(p, "‱"); + + pm = endswith(p, "‰"); + if (pm) + return parse_parts_value_with_tenths_place(p, "‰"); + + return parse_parts_value_with_hundredths_place(p, "%"); +} + +int parse_permyriad(const char *p) { + int v; + + v = parse_permyriad_unbounded(p); + if (v > 10000) + return -ERANGE; + + return v; +} + int parse_nice(const char *p, int *ret) { int n, r; diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 1ff76ded44..29e04cf562 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -133,6 +133,9 @@ int parse_percent(const char *p); int parse_permille_unbounded(const char *p); int parse_permille(const char *p); +int parse_permyriad_unbounded(const char *p); +int parse_permyriad(const char *p); + int parse_nice(const char *p, int *ret); int parse_ip_port(const char *s, uint16_t *ret); diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index 1c969091ef..6e23efe134 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -790,6 +790,72 @@ static void test_parse_permille_unbounded(void) { assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE); } +static void test_parse_permyriad(void) { + assert_se(parse_permyriad("") == -EINVAL); + assert_se(parse_permyriad("foo") == -EINVAL); + assert_se(parse_permyriad("0") == -EINVAL); + assert_se(parse_permyriad("50") == -EINVAL); + assert_se(parse_permyriad("100") == -EINVAL); + assert_se(parse_permyriad("-1") == -EINVAL); + + assert_se(parse_permyriad("0‱") == 0); + assert_se(parse_permyriad("555‱") == 555); + assert_se(parse_permyriad("1000‱") == 1000); + assert_se(parse_permyriad("-7‱") == -ERANGE); + assert_se(parse_permyriad("10007‱") == -ERANGE); + assert_se(parse_permyriad("‱") == -EINVAL); + assert_se(parse_permyriad("‱‱") == -EINVAL); + assert_se(parse_permyriad("‱1") == -EINVAL); + assert_se(parse_permyriad("1‱‱") == -EINVAL); + assert_se(parse_permyriad("3.2‱") == -EINVAL); + + assert_se(parse_permyriad("0‰") == 0); + assert_se(parse_permyriad("555.5‰") == 5555); + assert_se(parse_permyriad("1000.0‰") == 10000); + assert_se(parse_permyriad("-7‰") == -ERANGE); + assert_se(parse_permyriad("1007‰") == -ERANGE); + assert_se(parse_permyriad("‰") == -EINVAL); + assert_se(parse_permyriad("‰‰") == -EINVAL); + assert_se(parse_permyriad("‰1") == -EINVAL); + assert_se(parse_permyriad("1‰‰") == -EINVAL); + assert_se(parse_permyriad("3.22‰") == -EINVAL); + + assert_se(parse_permyriad("0%") == 0); + assert_se(parse_permyriad("55%") == 5500); + assert_se(parse_permyriad("55.53%") == 5553); + assert_se(parse_permyriad("100%") == 10000); + assert_se(parse_permyriad("-7%") == -ERANGE); + assert_se(parse_permyriad("107%") == -ERANGE); + assert_se(parse_permyriad("%") == -EINVAL); + assert_se(parse_permyriad("%%") == -EINVAL); + assert_se(parse_permyriad("%1") == -EINVAL); + assert_se(parse_permyriad("1%%") == -EINVAL); + assert_se(parse_permyriad("3.212%") == -EINVAL); +} + +static void test_parse_permyriad_unbounded(void) { + assert_se(parse_permyriad_unbounded("1001‱") == 1001); + assert_se(parse_permyriad_unbounded("4000‱") == 4000); + assert_se(parse_permyriad_unbounded("2147483647‱") == 2147483647); + assert_se(parse_permyriad_unbounded("2147483648‱") == -ERANGE); + assert_se(parse_permyriad_unbounded("4294967295‱") == -ERANGE); + assert_se(parse_permyriad_unbounded("4294967296‱") == -ERANGE); + + assert_se(parse_permyriad_unbounded("101‰") == 1010); + assert_se(parse_permyriad_unbounded("400‰") == 4000); + assert_se(parse_permyriad_unbounded("214748364.7‰") == 2147483647); + assert_se(parse_permyriad_unbounded("214748364.8‰") == -ERANGE); + assert_se(parse_permyriad_unbounded("429496729.5‰") == -ERANGE); + assert_se(parse_permyriad_unbounded("429496729.6‰") == -ERANGE); + + assert_se(parse_permyriad_unbounded("99%") == 9900); + assert_se(parse_permyriad_unbounded("40%") == 4000); + assert_se(parse_permyriad_unbounded("21474836.47%") == 2147483647); + assert_se(parse_permyriad_unbounded("21474836.48%") == -ERANGE); + assert_se(parse_permyriad_unbounded("42949672.95%") == -ERANGE); + assert_se(parse_permyriad_unbounded("42949672.96%") == -ERANGE); +} + static void test_parse_nice(void) { int n; @@ -987,6 +1053,8 @@ int main(int argc, char *argv[]) { test_parse_percent_unbounded(); test_parse_permille(); test_parse_permille_unbounded(); + test_parse_permyriad(); + test_parse_permyriad_unbounded(); test_parse_nice(); test_parse_dev(); test_parse_errno(); |