chiark / gitweb /
parse-util: add permille parser + tests
authorMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 5 Jun 2018 13:15:33 +0000 (15:15 +0200)
committerSven Eden <yamakuzure@gmx.net>
Fri, 24 Aug 2018 14:47:08 +0000 (16:47 +0200)
src/basic/parse-util.c
src/basic/parse-util.h
src/test/test-parse-util.c

index e9bd8ade1918e8760a5832a2757239ac144d3a94..53e030efc3b007f81c142ba9d92c2d69e556faa3 100644 (file)
@@ -637,6 +637,58 @@ int parse_percent(const char *p) {
         return v;
 }
 
+int parse_permille_unbounded(const char *p) {
+        const char *pc, *pm, *dot, *n;
+        int r, q, v;
+
+        pm = endswith(p, "‰");
+        if (pm) {
+                n = strndupa(p, pm - p);
+                r = safe_atoi(n, &v);
+                if (r < 0)
+                        return r;
+        } 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 > ((INT_MAX - q) / 10))
+                        return -ERANGE;
+
+                v = v * 10 + q;
+        }
+
+        if (v < 0)
+                return -ERANGE;
+
+        return v;
+}
+
+int parse_permille(const char *p) {
+        int v;
+
+        v = parse_permille_unbounded(p);
+        if (v > 1000)
+                return -ERANGE;
+
+        return v;
+}
+
 #if 0 /// UNNEEDED by elogind
 int parse_nice(const char *p, int *ret) {
         int n, r;
index f0f785a884649f8802fb95078033b05629d32913..fc52d1f221d6d6b949fea9f80802a7a255a4d1a5 100644 (file)
@@ -117,6 +117,9 @@ int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
 int parse_percent_unbounded(const char *p);
 int parse_percent(const char *p);
 
+int parse_permille_unbounded(const char *p);
+int parse_permille(const char *p);
+
 #if 0 /// UNNEEDED by elogind
 int parse_nice(const char *p, int *ret);
 
index 8f3cf671f31bf02d0381e7ab7ae18c1ba15b641d..5a6af9ba82fb6693ed64af2e8f5d1533f571bda0 100644 (file)
@@ -653,6 +653,54 @@ static void test_parse_percent_unbounded(void) {
         assert_se(parse_percent_unbounded("400%") == 400);
 }
 
+static void test_parse_permille(void) {
+        assert_se(parse_permille("") == -EINVAL);
+        assert_se(parse_permille("foo") == -EINVAL);
+        assert_se(parse_permille("0") == -EINVAL);
+        assert_se(parse_permille("50") == -EINVAL);
+        assert_se(parse_permille("100") == -EINVAL);
+        assert_se(parse_permille("-1") == -EINVAL);
+
+        assert_se(parse_permille("0‰") == 0);
+        assert_se(parse_permille("555‰") == 555);
+        assert_se(parse_permille("1000‰") == 1000);
+        assert_se(parse_permille("-7‰") == -ERANGE);
+        assert_se(parse_permille("1007‰") == -ERANGE);
+        assert_se(parse_permille("‰") == -EINVAL);
+        assert_se(parse_permille("‰‰") == -EINVAL);
+        assert_se(parse_permille("‰1") == -EINVAL);
+        assert_se(parse_permille("1‰‰") == -EINVAL);
+        assert_se(parse_permille("3.2‰") == -EINVAL);
+
+        assert_se(parse_permille("0%") == 0);
+        assert_se(parse_permille("55%") == 550);
+        assert_se(parse_permille("55.5%") == 555);
+        assert_se(parse_permille("100%") == 1000);
+        assert_se(parse_permille("-7%") == -ERANGE);
+        assert_se(parse_permille("107%") == -ERANGE);
+        assert_se(parse_permille("%") == -EINVAL);
+        assert_se(parse_permille("%%") == -EINVAL);
+        assert_se(parse_permille("%1") == -EINVAL);
+        assert_se(parse_permille("1%%") == -EINVAL);
+        assert_se(parse_permille("3.21%") == -EINVAL);
+}
+
+static void test_parse_permille_unbounded(void) {
+        assert_se(parse_permille_unbounded("1001‰") == 1001);
+        assert_se(parse_permille_unbounded("4000‰") == 4000);
+        assert_se(parse_permille_unbounded("2147483647‰") == 2147483647);
+        assert_se(parse_permille_unbounded("2147483648‰") == -ERANGE);
+        assert_se(parse_permille_unbounded("4294967295‰") == -ERANGE);
+        assert_se(parse_permille_unbounded("4294967296‰") == -ERANGE);
+
+        assert_se(parse_permille_unbounded("101%") == 1010);
+        assert_se(parse_permille_unbounded("400%") == 4000);
+        assert_se(parse_permille_unbounded("214748364.7%") == 2147483647);
+        assert_se(parse_permille_unbounded("214748364.8%") == -ERANGE);
+        assert_se(parse_permille_unbounded("429496729.5%") == -ERANGE);
+        assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE);
+}
+
 #if 0 /// UNNEEDED by elogind
 static void test_parse_nice(void) {
         int n;
@@ -806,6 +854,8 @@ int main(int argc, char *argv[]) {
         test_safe_atod();
         test_parse_percent();
         test_parse_percent_unbounded();
+        test_parse_permille();
+        test_parse_permille_unbounded();
 #if 0 /// UNNEEDED by elogind
         test_parse_nice();
 #endif // 0