1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
14 #include <ecoli_log.h>
15 #include <ecoli_malloc.h>
16 #include <ecoli_strvec.h>
17 #include <ecoli_node.h>
18 #include <ecoli_parsed.h>
19 #include <ecoli_completed.h>
20 #include <ecoli_node_int.h>
21 #include <ecoli_test.h>
23 EC_LOG_TYPE_REGISTER(node_int);
25 /* common to int and uint */
26 struct ec_node_int_uint {
42 static int parse_llint(struct ec_node_int_uint *node, const char *str,
48 *val = strtoll(str, &endptr, node->base);
50 if ((errno == ERANGE && (*val == LLONG_MAX || *val == LLONG_MIN)) ||
51 (errno != 0 && *val == 0))
54 if (node->check_min && *val < node->min)
57 if (node->check_max && *val > node->max)
66 static int parse_ullint(struct ec_node_int_uint *node, const char *str,
71 /* since a negative input is silently converted to a positive
72 * one by strtoull(), first check that it is positive */
77 *val = strtoull(str, &endptr, node->base);
79 if ((errno == ERANGE && *val == ULLONG_MAX) ||
80 (errno != 0 && *val == 0))
83 if (node->check_min && *val < node->umin)
86 if (node->check_max && *val > node->umax)
95 static int ec_node_int_uint_parse(const struct ec_node *gen_node,
96 struct ec_parsed *state,
97 const struct ec_strvec *strvec)
99 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
106 if (ec_strvec_len(strvec) == 0)
107 return EC_PARSED_NOMATCH;
109 str = ec_strvec_val(strvec, 0);
110 if (node->is_signed) {
111 if (parse_llint(node, str, &i64) < 0)
112 return EC_PARSED_NOMATCH;
114 if (parse_ullint(node, str, &u64) < 0)
115 return EC_PARSED_NOMATCH;
121 ec_node_uint_init_priv(struct ec_node *gen_node)
123 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
125 node->is_signed = true;
130 static struct ec_node_type ec_node_int_type = {
132 .parse = ec_node_int_uint_parse,
133 .complete = ec_node_default_complete,
134 .size = sizeof(struct ec_node_int_uint),
135 .init_priv = ec_node_uint_init_priv,
138 EC_NODE_TYPE_REGISTER(ec_node_int_type);
140 struct ec_node *ec_node_int(const char *id, int64_t min,
141 int64_t max, unsigned int base)
143 struct ec_node *gen_node = NULL;
145 gen_node = __ec_node(&ec_node_int_type, id);
146 if (gen_node == NULL)
149 if (ec_node_int_set_limits(gen_node, min, max) < 0)
151 if (ec_node_int_set_base(gen_node, base) < 0)
157 ec_node_free(gen_node);
161 static struct ec_node_type ec_node_uint_type = {
163 .parse = ec_node_int_uint_parse,
164 .complete = ec_node_default_complete,
165 .size = sizeof(struct ec_node_int_uint),
168 EC_NODE_TYPE_REGISTER(ec_node_uint_type);
170 struct ec_node *ec_node_uint(const char *id, uint64_t min,
171 uint64_t max, unsigned int base)
173 struct ec_node *gen_node = NULL;
175 gen_node = __ec_node(&ec_node_uint_type, id);
176 if (gen_node == NULL)
179 if (ec_node_uint_set_limits(gen_node, min, max) < 0)
181 if (ec_node_uint_set_base(gen_node, base) < 0)
187 ec_node_free(gen_node);
191 int ec_node_int_disable_limits(struct ec_node *gen_node)
193 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
196 ret = ec_node_check_type(gen_node, &ec_node_int_type);
200 node->check_min = false;
201 node->check_max = false;
206 int ec_node_int_set_limits(struct ec_node *gen_node, int64_t min,
209 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
212 ret = ec_node_check_type(gen_node, &ec_node_int_type);
221 node->check_min = true;
223 node->check_max = true;
229 int ec_node_int_set_base(struct ec_node *gen_node, unsigned int base)
231 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
234 ret = ec_node_check_type(gen_node, &ec_node_int_type);
244 int ec_node_uint_disable_limits(struct ec_node *gen_node)
246 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
249 ret = ec_node_check_type(gen_node, &ec_node_uint_type);
253 node->check_min = false;
254 node->check_max = false;
259 int ec_node_uint_set_limits(struct ec_node *gen_node, uint64_t min,
262 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
265 ret = ec_node_check_type(gen_node, &ec_node_uint_type);
274 node->check_min = true;
276 node->check_max = true;
282 int ec_node_uint_set_base(struct ec_node *gen_node, unsigned int base)
284 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
287 ret = ec_node_check_type(gen_node, &ec_node_uint_type);
296 int ec_node_int_getval(const struct ec_node *gen_node, const char *str,
299 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
302 ret = ec_node_check_type(gen_node, &ec_node_int_type);
306 if (parse_llint(node, str, result) < 0)
312 int ec_node_uint_getval(const struct ec_node *gen_node, const char *str,
315 struct ec_node_int_uint *node = (struct ec_node_int_uint *)gen_node;
318 ret = ec_node_check_type(gen_node, &ec_node_uint_type);
322 if (parse_ullint(node, str, result) < 0)
328 /* LCOV_EXCL_START */
329 static int ec_node_int_testcase(void)
332 struct ec_node *node;
334 int testres = 0, ret;
338 node = ec_node_uint(EC_NO_ID, 1, 256, 0);
340 EC_LOG(EC_LOG_ERR, "cannot create node\n");
343 testres |= EC_TEST_CHECK_PARSE(node, -1, "");
344 testres |= EC_TEST_CHECK_PARSE(node, -1, "0");
345 testres |= EC_TEST_CHECK_PARSE(node, 1, "1");
346 testres |= EC_TEST_CHECK_PARSE(node, 1, "256", "foo");
347 testres |= EC_TEST_CHECK_PARSE(node, 1, "0x100");
348 testres |= EC_TEST_CHECK_PARSE(node, 1, " 1");
349 testres |= EC_TEST_CHECK_PARSE(node, -1, "-1");
350 testres |= EC_TEST_CHECK_PARSE(node, -1, "0x101");
351 testres |= EC_TEST_CHECK_PARSE(node, -1, "zzz");
352 testres |= EC_TEST_CHECK_PARSE(node, -1, "0x100000000000000000");
353 testres |= EC_TEST_CHECK_PARSE(node, -1, "4r");
354 ret = ec_node_uint_disable_limits(node);
355 testres |= EC_TEST_CHECK(ret == 0, "cannot disable limits");
356 testres |= EC_TEST_CHECK_PARSE(node, 1, "0");
358 p = ec_node_parse(node, "1");
359 s = ec_strvec_val(ec_parsed_strvec(p), 0);
360 testres |= EC_TEST_CHECK(s != NULL &&
361 ec_node_uint_getval(node, s, &u64) == 0 &&
362 u64 == 1, "bad integer value");
365 p = ec_node_parse(node, "10");
366 s = ec_strvec_val(ec_parsed_strvec(p), 0);
367 testres |= EC_TEST_CHECK(s != NULL &&
368 ec_node_uint_getval(node, s, &u64) == 0 &&
369 u64 == 10, "bad integer value");
373 node = ec_node_int(EC_NO_ID, -1, LLONG_MAX, 16);
375 EC_LOG(EC_LOG_ERR, "cannot create node\n");
378 testres |= EC_TEST_CHECK_PARSE(node, 1, "0");
379 testres |= EC_TEST_CHECK_PARSE(node, 1, "-1");
380 testres |= EC_TEST_CHECK_PARSE(node, 1, "7fffffffffffffff");
381 testres |= EC_TEST_CHECK_PARSE(node, 1, "0x7fffffffffffffff");
382 testres |= EC_TEST_CHECK_PARSE(node, -1, "0x8000000000000000");
383 testres |= EC_TEST_CHECK_PARSE(node, -1, "-2");
384 testres |= EC_TEST_CHECK_PARSE(node, -1, "zzz");
385 testres |= EC_TEST_CHECK_PARSE(node, -1, "4r");
386 ret = ec_node_int_disable_limits(node);
387 testres |= EC_TEST_CHECK(ret == 0, "cannot disable limits");
388 testres |= EC_TEST_CHECK_PARSE(node, 1, "-2");
390 p = ec_node_parse(node, "10");
391 s = ec_strvec_val(ec_parsed_strvec(p), 0);
392 testres |= EC_TEST_CHECK(s != NULL &&
393 ec_node_int_getval(node, s, &i64) == 0 &&
394 i64 == 16, "bad integer value");
398 node = ec_node_int(EC_NO_ID, LLONG_MIN, 0, 10);
400 EC_LOG(EC_LOG_ERR, "cannot create node\n");
403 testres |= EC_TEST_CHECK_PARSE(node, 1, "0");
404 testres |= EC_TEST_CHECK_PARSE(node, 1, "-1");
405 testres |= EC_TEST_CHECK_PARSE(node, 1, "-9223372036854775808");
406 testres |= EC_TEST_CHECK_PARSE(node, -1, "0x0");
407 testres |= EC_TEST_CHECK_PARSE(node, -1, "1");
410 /* test completion */
411 node = ec_node_int(EC_NO_ID, 0, 10, 0);
413 EC_LOG(EC_LOG_ERR, "cannot create node\n");
416 testres |= EC_TEST_CHECK_COMPLETE(node,
419 testres |= EC_TEST_CHECK_COMPLETE(node,
420 "x", EC_NODE_ENDLIST,
422 testres |= EC_TEST_CHECK_COMPLETE(node,
423 "1", EC_NODE_ENDLIST,
431 static struct ec_test ec_node_int_test = {
433 .test = ec_node_int_testcase,
436 EC_TEST_REGISTER(ec_node_int_test);