parse-util: add permyriad parsing

This commit is contained in:
Anita Zhang
2021-02-02 01:47:08 -08:00
parent 77591e9732
commit 94a8e2d6db
3 changed files with 169 additions and 39 deletions
+98 -39
View File
@@ -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;
if (pm)
return parse_parts_value_whole(p, "‰");
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;
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;