udev: String substitutions can be done in ENV, too
[systemd_ALT.git] / src / basic / percent-util.c
blobcab9d0eaeac055e889adb75441b95c4aed8e2606
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "percent-util.h"
4 #include "string-util.h"
5 #include "parse-util.h"
7 static int parse_parts_value_whole(const char *p, const char *symbol) {
8 const char *pc, *n;
9 int r, v;
11 pc = endswith(p, symbol);
12 if (!pc)
13 return -EINVAL;
15 n = strndupa_safe(p, pc - p);
16 r = safe_atoi(n, &v);
17 if (r < 0)
18 return r;
19 if (v < 0)
20 return -ERANGE;
22 return v;
25 static int parse_parts_value_with_tenths_place(const char *p, const char *symbol) {
26 const char *pc, *dot, *n;
27 int r, q, v;
29 pc = endswith(p, symbol);
30 if (!pc)
31 return -EINVAL;
33 dot = memchr(p, '.', pc - p);
34 if (dot) {
35 if (dot + 2 != pc)
36 return -EINVAL;
37 if (dot[1] < '0' || dot[1] > '9')
38 return -EINVAL;
39 q = dot[1] - '0';
40 n = strndupa_safe(p, dot - p);
41 } else {
42 q = 0;
43 n = strndupa_safe(p, pc - p);
45 r = safe_atoi(n, &v);
46 if (r < 0)
47 return r;
48 if (v < 0)
49 return -ERANGE;
50 if (v > (INT_MAX - q) / 10)
51 return -ERANGE;
53 v = v * 10 + q;
54 return v;
57 static int parse_parts_value_with_hundredths_place(const char *p, const char *symbol) {
58 const char *pc, *dot, *n;
59 int r, q, v;
61 pc = endswith(p, symbol);
62 if (!pc)
63 return -EINVAL;
65 dot = memchr(p, '.', pc - p);
66 if (dot) {
67 if (dot + 3 == pc) {
68 /* Support two places after the dot */
70 if (dot[1] < '0' || dot[1] > '9' || dot[2] < '0' || dot[2] > '9')
71 return -EINVAL;
72 q = (dot[1] - '0') * 10 + (dot[2] - '0');
74 } else if (dot + 2 == pc) {
75 /* Support one place after the dot */
77 if (dot[1] < '0' || dot[1] > '9')
78 return -EINVAL;
79 q = (dot[1] - '0') * 10;
80 } else
81 /* We do not support zero or more than two places */
82 return -EINVAL;
84 n = strndupa_safe(p, dot - p);
85 } else {
86 q = 0;
87 n = strndupa_safe(p, pc - p);
89 r = safe_atoi(n, &v);
90 if (r < 0)
91 return r;
92 if (v < 0)
93 return -ERANGE;
94 if (v > (INT_MAX - q) / 100)
95 return -ERANGE;
97 v = v * 100 + q;
98 return v;
101 int parse_percent_unbounded(const char *p) {
102 return parse_parts_value_whole(p, "%");
105 int parse_percent(const char *p) {
106 int v;
108 v = parse_percent_unbounded(p);
109 if (v > 100)
110 return -ERANGE;
112 return v;
115 int parse_permille_unbounded(const char *p) {
116 const char *pm;
118 pm = endswith(p, "‰");
119 if (pm)
120 return parse_parts_value_whole(p, "‰");
122 return parse_parts_value_with_tenths_place(p, "%");
125 int parse_permille(const char *p) {
126 int v;
128 v = parse_permille_unbounded(p);
129 if (v > 1000)
130 return -ERANGE;
132 return v;
135 int parse_permyriad_unbounded(const char *p) {
136 const char *pm;
138 pm = endswith(p, "‱");
139 if (pm)
140 return parse_parts_value_whole(p, "‱");
142 pm = endswith(p, "‰");
143 if (pm)
144 return parse_parts_value_with_tenths_place(p, "‰");
146 return parse_parts_value_with_hundredths_place(p, "%");
149 int parse_permyriad(const char *p) {
150 int v;
152 v = parse_permyriad_unbounded(p);
153 if (v > 10000)
154 return -ERANGE;
156 return v;