xref: /dpdk/lib/argparse/rte_argparse.c (revision 31ed9f9f43bb03129aa9c5134e8e4fd20a4ce762)
1e3e579f5SChengwen Feng /* SPDX-License-Identifier: BSD-3-Clause
2e3e579f5SChengwen Feng  * Copyright(c) 2024 HiSilicon Limited
3e3e579f5SChengwen Feng  */
4e3e579f5SChengwen Feng 
56c5c6571SChengwen Feng #include <errno.h>
66c5c6571SChengwen Feng #include <stdlib.h>
76c5c6571SChengwen Feng #include <string.h>
86c5c6571SChengwen Feng 
96c5c6571SChengwen Feng #include <rte_log.h>
106c5c6571SChengwen Feng 
11e3e579f5SChengwen Feng #include "rte_argparse.h"
12e3e579f5SChengwen Feng 
136c5c6571SChengwen Feng RTE_LOG_REGISTER_DEFAULT(rte_argparse_logtype, INFO);
146c5c6571SChengwen Feng #define RTE_LOGTYPE_ARGPARSE rte_argparse_logtype
156c5c6571SChengwen Feng #define ARGPARSE_LOG(level, ...) \
166c5c6571SChengwen Feng 	RTE_LOG_LINE(level, ARGPARSE, "" __VA_ARGS__)
176c5c6571SChengwen Feng 
186c5c6571SChengwen Feng #define ARG_ATTR_HAS_VAL_MASK		RTE_GENMASK64(1, 0)
196c5c6571SChengwen Feng #define ARG_ATTR_VAL_TYPE_MASK		RTE_GENMASK64(9, 2)
206c5c6571SChengwen Feng #define ARG_ATTR_SUPPORT_MULTI_MASK	RTE_BIT64(10)
216c5c6571SChengwen Feng #define ARG_ATTR_FLAG_PARSED_MASK	RTE_BIT64(63)
226c5c6571SChengwen Feng 
236c5c6571SChengwen Feng static inline bool
246c5c6571SChengwen Feng is_arg_optional(const struct rte_argparse_arg *arg)
256c5c6571SChengwen Feng {
266c5c6571SChengwen Feng 	return arg->name_long[0] == '-';
276c5c6571SChengwen Feng }
286c5c6571SChengwen Feng 
296c5c6571SChengwen Feng static inline bool
306c5c6571SChengwen Feng is_arg_positional(const struct rte_argparse_arg *arg)
316c5c6571SChengwen Feng {
326c5c6571SChengwen Feng 	return arg->name_long[0] != '-';
336c5c6571SChengwen Feng }
346c5c6571SChengwen Feng 
356c5c6571SChengwen Feng static inline uint32_t
366c5c6571SChengwen Feng arg_attr_has_val(const struct rte_argparse_arg *arg)
376c5c6571SChengwen Feng {
386c5c6571SChengwen Feng 	return RTE_FIELD_GET64(ARG_ATTR_HAS_VAL_MASK, arg->flags);
396c5c6571SChengwen Feng }
406c5c6571SChengwen Feng 
416c5c6571SChengwen Feng static inline uint32_t
426c5c6571SChengwen Feng arg_attr_val_type(const struct rte_argparse_arg *arg)
436c5c6571SChengwen Feng {
446c5c6571SChengwen Feng 	return RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, arg->flags);
456c5c6571SChengwen Feng }
466c5c6571SChengwen Feng 
47*31ed9f9fSChengwen Feng static inline bool
48*31ed9f9fSChengwen Feng arg_attr_flag_multi(const struct rte_argparse_arg *arg)
49*31ed9f9fSChengwen Feng {
50*31ed9f9fSChengwen Feng 	return RTE_FIELD_GET64(ARG_ATTR_SUPPORT_MULTI_MASK, arg->flags);
51*31ed9f9fSChengwen Feng }
52*31ed9f9fSChengwen Feng 
536c5c6571SChengwen Feng static inline uint32_t
546c5c6571SChengwen Feng arg_attr_unused_bits(const struct rte_argparse_arg *arg)
556c5c6571SChengwen Feng {
566c5c6571SChengwen Feng #define USED_BIT_MASK	(ARG_ATTR_HAS_VAL_MASK | ARG_ATTR_VAL_TYPE_MASK | \
576c5c6571SChengwen Feng 			 ARG_ATTR_SUPPORT_MULTI_MASK)
586c5c6571SChengwen Feng 	return arg->flags & ~USED_BIT_MASK;
596c5c6571SChengwen Feng }
606c5c6571SChengwen Feng 
616c5c6571SChengwen Feng static int
626c5c6571SChengwen Feng verify_arg_name(const struct rte_argparse_arg *arg)
636c5c6571SChengwen Feng {
646c5c6571SChengwen Feng 	if (is_arg_optional(arg)) {
656c5c6571SChengwen Feng 		if (strlen(arg->name_long) <= 3) {
666c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long);
676c5c6571SChengwen Feng 			return -EINVAL;
686c5c6571SChengwen Feng 		}
696c5c6571SChengwen Feng 		if (arg->name_long[1] != '-') {
706c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "optional long name %s must only start with '--'",
716c5c6571SChengwen Feng 				     arg->name_long);
726c5c6571SChengwen Feng 			return -EINVAL;
736c5c6571SChengwen Feng 		}
746c5c6571SChengwen Feng 		if (arg->name_long[2] == '-') {
756c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'",
766c5c6571SChengwen Feng 				     arg->name_long);
776c5c6571SChengwen Feng 			return -EINVAL;
786c5c6571SChengwen Feng 		}
796c5c6571SChengwen Feng 	}
806c5c6571SChengwen Feng 
816c5c6571SChengwen Feng 	if (arg->name_short == NULL)
826c5c6571SChengwen Feng 		return 0;
836c5c6571SChengwen Feng 
846c5c6571SChengwen Feng 	if (!is_arg_optional(arg)) {
856c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!",
866c5c6571SChengwen Feng 			     arg->name_short);
876c5c6571SChengwen Feng 		return -EINVAL;
886c5c6571SChengwen Feng 	}
896c5c6571SChengwen Feng 
906c5c6571SChengwen Feng 	if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' ||
916c5c6571SChengwen Feng 		arg->name_short[1] == '-') {
926c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter",
936c5c6571SChengwen Feng 			     arg->name_short);
946c5c6571SChengwen Feng 		return -EINVAL;
956c5c6571SChengwen Feng 	}
966c5c6571SChengwen Feng 
976c5c6571SChengwen Feng 	return 0;
986c5c6571SChengwen Feng }
996c5c6571SChengwen Feng 
1006c5c6571SChengwen Feng static int
1016c5c6571SChengwen Feng verify_arg_help(const struct rte_argparse_arg *arg)
1026c5c6571SChengwen Feng {
1036c5c6571SChengwen Feng 	if (arg->help == NULL) {
1046c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s must have help info!", arg->name_long);
1056c5c6571SChengwen Feng 		return -EINVAL;
1066c5c6571SChengwen Feng 	}
1076c5c6571SChengwen Feng 
1086c5c6571SChengwen Feng 	return 0;
1096c5c6571SChengwen Feng }
1106c5c6571SChengwen Feng 
1116c5c6571SChengwen Feng static int
1126c5c6571SChengwen Feng verify_arg_has_val(const struct rte_argparse_arg *arg)
1136c5c6571SChengwen Feng {
1146c5c6571SChengwen Feng 	uint32_t has_val = arg_attr_has_val(arg);
1156c5c6571SChengwen Feng 
1166c5c6571SChengwen Feng 	if (is_arg_positional(arg)) {
1176c5c6571SChengwen Feng 		if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE)
1186c5c6571SChengwen Feng 			return 0;
1196c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s is positional, should has zero or required-val!",
1206c5c6571SChengwen Feng 			     arg->name_long);
1216c5c6571SChengwen Feng 		return -EINVAL;
1226c5c6571SChengwen Feng 	}
1236c5c6571SChengwen Feng 
1246c5c6571SChengwen Feng 	if (has_val == 0) {
1256c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s is optional, has-val config wrong!",
1266c5c6571SChengwen Feng 			     arg->name_long);
1276c5c6571SChengwen Feng 		return -EINVAL;
1286c5c6571SChengwen Feng 	}
1296c5c6571SChengwen Feng 
1306c5c6571SChengwen Feng 	return 0;
1316c5c6571SChengwen Feng }
1326c5c6571SChengwen Feng 
1336c5c6571SChengwen Feng static int
1346c5c6571SChengwen Feng verify_arg_saver(const struct rte_argparse *obj, uint32_t index)
1356c5c6571SChengwen Feng {
1366c5c6571SChengwen Feng 	uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX);
1376c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &obj->args[index];
1386c5c6571SChengwen Feng 	uint32_t val_type = arg_attr_val_type(arg);
1396c5c6571SChengwen Feng 	uint32_t has_val = arg_attr_has_val(arg);
1406c5c6571SChengwen Feng 
1416c5c6571SChengwen Feng 	if (arg->val_saver == NULL) {
1426c5c6571SChengwen Feng 		if (val_type != 0) {
1436c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s parse by callback, val-type must be zero!",
1446c5c6571SChengwen Feng 				     arg->name_long);
1456c5c6571SChengwen Feng 			return -EINVAL;
1466c5c6571SChengwen Feng 		}
1476c5c6571SChengwen Feng 
1486c5c6571SChengwen Feng 		if (obj->callback == NULL) {
1496c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s parse by callback, but callback is NULL!",
1506c5c6571SChengwen Feng 				     arg->name_long);
1516c5c6571SChengwen Feng 			return -EINVAL;
1526c5c6571SChengwen Feng 		}
1536c5c6571SChengwen Feng 
1546c5c6571SChengwen Feng 		return 0;
1556c5c6571SChengwen Feng 	}
1566c5c6571SChengwen Feng 
1576c5c6571SChengwen Feng 	if (val_type == 0 || val_type >= cmp_max) {
1586c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s val-type config wrong!", arg->name_long);
1596c5c6571SChengwen Feng 		return -EINVAL;
1606c5c6571SChengwen Feng 	}
1616c5c6571SChengwen Feng 
1626c5c6571SChengwen Feng 	if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE && arg->val_set != NULL) {
1636c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s has required value, val-set should be NULL!",
1646c5c6571SChengwen Feng 			     arg->name_long);
1656c5c6571SChengwen Feng 		return -EINVAL;
1666c5c6571SChengwen Feng 	}
1676c5c6571SChengwen Feng 
1686c5c6571SChengwen Feng 	return 0;
1696c5c6571SChengwen Feng }
1706c5c6571SChengwen Feng 
1716c5c6571SChengwen Feng static int
1726c5c6571SChengwen Feng verify_arg_flags(const struct rte_argparse *obj, uint32_t index)
1736c5c6571SChengwen Feng {
1746c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &obj->args[index];
1756c5c6571SChengwen Feng 	uint32_t unused_bits = arg_attr_unused_bits(arg);
1766c5c6571SChengwen Feng 
1776c5c6571SChengwen Feng 	if (unused_bits != 0) {
1786c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s flags set wrong!", arg->name_long);
1796c5c6571SChengwen Feng 		return -EINVAL;
1806c5c6571SChengwen Feng 	}
1816c5c6571SChengwen Feng 
1826c5c6571SChengwen Feng 	if (!(arg->flags & RTE_ARGPARSE_ARG_SUPPORT_MULTI))
1836c5c6571SChengwen Feng 		return 0;
1846c5c6571SChengwen Feng 
1856c5c6571SChengwen Feng 	if (is_arg_positional(arg)) {
1866c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!",
1876c5c6571SChengwen Feng 			     arg->name_long);
1886c5c6571SChengwen Feng 		return -EINVAL;
1896c5c6571SChengwen Feng 	}
1906c5c6571SChengwen Feng 
1916c5c6571SChengwen Feng 	if (arg->val_saver != NULL) {
1926c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s could occur multiple times, should use callback to parse!",
1936c5c6571SChengwen Feng 			     arg->name_long);
1946c5c6571SChengwen Feng 		return -EINVAL;
1956c5c6571SChengwen Feng 	}
1966c5c6571SChengwen Feng 
1976c5c6571SChengwen Feng 	if (obj->callback == NULL) {
1986c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s should use callback to parse, but callback is NULL!",
1996c5c6571SChengwen Feng 			     arg->name_long);
2006c5c6571SChengwen Feng 		return -EINVAL;
2016c5c6571SChengwen Feng 	}
2026c5c6571SChengwen Feng 
2036c5c6571SChengwen Feng 	return 0;
2046c5c6571SChengwen Feng }
2056c5c6571SChengwen Feng 
2066c5c6571SChengwen Feng static int
2076c5c6571SChengwen Feng verify_arg_repeat(const struct rte_argparse *self, uint32_t index)
2086c5c6571SChengwen Feng {
2096c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &self->args[index];
2106c5c6571SChengwen Feng 	uint32_t i;
2116c5c6571SChengwen Feng 
2126c5c6571SChengwen Feng 	for (i = 0; i < index; i++) {
2136c5c6571SChengwen Feng 		if (!strcmp(arg->name_long, self->args[i].name_long)) {
2146c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long);
2156c5c6571SChengwen Feng 			return -EINVAL;
2166c5c6571SChengwen Feng 		}
2176c5c6571SChengwen Feng 	}
2186c5c6571SChengwen Feng 
2196c5c6571SChengwen Feng 	if (arg->name_short == NULL)
2206c5c6571SChengwen Feng 		return 0;
2216c5c6571SChengwen Feng 
2226c5c6571SChengwen Feng 	for (i = 0; i < index; i++) {
2236c5c6571SChengwen Feng 		if (self->args[i].name_short == NULL)
2246c5c6571SChengwen Feng 			continue;
2256c5c6571SChengwen Feng 		if (!strcmp(arg->name_short, self->args[i].name_short)) {
2266c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short);
2276c5c6571SChengwen Feng 			return -EINVAL;
2286c5c6571SChengwen Feng 		}
2296c5c6571SChengwen Feng 	}
2306c5c6571SChengwen Feng 
2316c5c6571SChengwen Feng 	return 0;
2326c5c6571SChengwen Feng }
2336c5c6571SChengwen Feng 
2346c5c6571SChengwen Feng static int
2356c5c6571SChengwen Feng verify_argparse_arg(const struct rte_argparse *obj, uint32_t index)
2366c5c6571SChengwen Feng {
2376c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &obj->args[index];
2386c5c6571SChengwen Feng 	int ret;
2396c5c6571SChengwen Feng 
2406c5c6571SChengwen Feng 	ret = verify_arg_name(arg);
2416c5c6571SChengwen Feng 	if (ret != 0)
2426c5c6571SChengwen Feng 		return ret;
2436c5c6571SChengwen Feng 
2446c5c6571SChengwen Feng 	ret = verify_arg_help(arg);
2456c5c6571SChengwen Feng 	if (ret != 0)
2466c5c6571SChengwen Feng 		return ret;
2476c5c6571SChengwen Feng 
2486c5c6571SChengwen Feng 	ret = verify_arg_has_val(arg);
2496c5c6571SChengwen Feng 	if (ret != 0)
2506c5c6571SChengwen Feng 		return ret;
2516c5c6571SChengwen Feng 
2526c5c6571SChengwen Feng 	ret = verify_arg_saver(obj, index);
2536c5c6571SChengwen Feng 	if (ret != 0)
2546c5c6571SChengwen Feng 		return ret;
2556c5c6571SChengwen Feng 
2566c5c6571SChengwen Feng 	ret = verify_arg_flags(obj, index);
2576c5c6571SChengwen Feng 	if (ret != 0)
2586c5c6571SChengwen Feng 		return ret;
2596c5c6571SChengwen Feng 
2606c5c6571SChengwen Feng 	ret = verify_arg_repeat(obj, index);
2616c5c6571SChengwen Feng 	if (ret != 0)
2626c5c6571SChengwen Feng 		return ret;
2636c5c6571SChengwen Feng 
2646c5c6571SChengwen Feng 	return 0;
2656c5c6571SChengwen Feng }
2666c5c6571SChengwen Feng 
2676c5c6571SChengwen Feng static int
2686c5c6571SChengwen Feng verify_argparse(const struct rte_argparse *obj)
2696c5c6571SChengwen Feng {
2706c5c6571SChengwen Feng 	uint32_t idx;
2716c5c6571SChengwen Feng 	int ret;
2726c5c6571SChengwen Feng 
2736c5c6571SChengwen Feng 	if (obj->prog_name == NULL) {
2746c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "program name is NULL!");
2756c5c6571SChengwen Feng 		return -EINVAL;
2766c5c6571SChengwen Feng 	}
2776c5c6571SChengwen Feng 
2786c5c6571SChengwen Feng 	if (obj->usage == NULL) {
2796c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "usage is NULL!");
2806c5c6571SChengwen Feng 		return -EINVAL;
2816c5c6571SChengwen Feng 	}
2826c5c6571SChengwen Feng 
2836c5c6571SChengwen Feng 	for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) {
2846c5c6571SChengwen Feng 		if (obj->reserved[idx] != 0) {
2856c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "reserved field must be zero!");
2866c5c6571SChengwen Feng 			return -EINVAL;
2876c5c6571SChengwen Feng 		}
2886c5c6571SChengwen Feng 	}
2896c5c6571SChengwen Feng 
2906c5c6571SChengwen Feng 	idx = 0;
2916c5c6571SChengwen Feng 	while (obj->args[idx].name_long != NULL) {
2926c5c6571SChengwen Feng 		ret = verify_argparse_arg(obj, idx);
2936c5c6571SChengwen Feng 		if (ret != 0)
2946c5c6571SChengwen Feng 			return ret;
2956c5c6571SChengwen Feng 		idx++;
2966c5c6571SChengwen Feng 	}
2976c5c6571SChengwen Feng 
2986c5c6571SChengwen Feng 	return 0;
2996c5c6571SChengwen Feng }
3006c5c6571SChengwen Feng 
301*31ed9f9fSChengwen Feng static uint32_t
302*31ed9f9fSChengwen Feng calc_position_count(const struct rte_argparse *obj)
303*31ed9f9fSChengwen Feng {
304*31ed9f9fSChengwen Feng 	const struct rte_argparse_arg *arg;
305*31ed9f9fSChengwen Feng 	uint32_t count = 0;
306*31ed9f9fSChengwen Feng 	uint32_t i;
307*31ed9f9fSChengwen Feng 
308*31ed9f9fSChengwen Feng 	for (i = 0; /* NULL */; i++) {
309*31ed9f9fSChengwen Feng 		arg = &obj->args[i];
310*31ed9f9fSChengwen Feng 		if (obj->args[i].name_long == NULL)
311*31ed9f9fSChengwen Feng 			break;
312*31ed9f9fSChengwen Feng 		if (is_arg_positional(arg))
313*31ed9f9fSChengwen Feng 			count++;
314*31ed9f9fSChengwen Feng 	}
315*31ed9f9fSChengwen Feng 
316*31ed9f9fSChengwen Feng 	return count;
317*31ed9f9fSChengwen Feng }
318*31ed9f9fSChengwen Feng 
319*31ed9f9fSChengwen Feng static struct rte_argparse_arg *
320*31ed9f9fSChengwen Feng find_position_arg(struct rte_argparse *obj, uint32_t index)
321*31ed9f9fSChengwen Feng {
322*31ed9f9fSChengwen Feng 	struct rte_argparse_arg *arg;
323*31ed9f9fSChengwen Feng 	uint32_t count = 0;
324*31ed9f9fSChengwen Feng 	uint32_t i;
325*31ed9f9fSChengwen Feng 
326*31ed9f9fSChengwen Feng 	for (i = 0; /* NULL */; i++) {
327*31ed9f9fSChengwen Feng 		arg = &obj->args[i];
328*31ed9f9fSChengwen Feng 		if (arg->name_long == NULL)
329*31ed9f9fSChengwen Feng 			break;
330*31ed9f9fSChengwen Feng 		if (!is_arg_positional(arg))
331*31ed9f9fSChengwen Feng 			continue;
332*31ed9f9fSChengwen Feng 		count++;
333*31ed9f9fSChengwen Feng 		if (count == index)
334*31ed9f9fSChengwen Feng 			return arg;
335*31ed9f9fSChengwen Feng 	}
336*31ed9f9fSChengwen Feng 
337*31ed9f9fSChengwen Feng 	return NULL;
338*31ed9f9fSChengwen Feng }
339*31ed9f9fSChengwen Feng 
340*31ed9f9fSChengwen Feng static bool
341*31ed9f9fSChengwen Feng is_arg_match(struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len)
342*31ed9f9fSChengwen Feng {
343*31ed9f9fSChengwen Feng 	if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0)
344*31ed9f9fSChengwen Feng 		return true;
345*31ed9f9fSChengwen Feng 
346*31ed9f9fSChengwen Feng 	if (arg->name_short == NULL)
347*31ed9f9fSChengwen Feng 		return false;
348*31ed9f9fSChengwen Feng 
349*31ed9f9fSChengwen Feng 	if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0)
350*31ed9f9fSChengwen Feng 		return true;
351*31ed9f9fSChengwen Feng 
352*31ed9f9fSChengwen Feng 	return false;
353*31ed9f9fSChengwen Feng }
354*31ed9f9fSChengwen Feng 
355*31ed9f9fSChengwen Feng static struct rte_argparse_arg *
356*31ed9f9fSChengwen Feng find_option_arg(struct rte_argparse *obj, const char *curr_argv, const char *has_equal,
357*31ed9f9fSChengwen Feng 		const char **arg_name)
358*31ed9f9fSChengwen Feng {
359*31ed9f9fSChengwen Feng 	uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0);
360*31ed9f9fSChengwen Feng 	struct rte_argparse_arg *arg;
361*31ed9f9fSChengwen Feng 	uint32_t i;
362*31ed9f9fSChengwen Feng 	bool match;
363*31ed9f9fSChengwen Feng 
364*31ed9f9fSChengwen Feng 	for (i = 0; /* nothing */; i++) {
365*31ed9f9fSChengwen Feng 		arg = &obj->args[i];
366*31ed9f9fSChengwen Feng 		if (arg->name_long == NULL)
367*31ed9f9fSChengwen Feng 			break;
368*31ed9f9fSChengwen Feng 		match = is_arg_match(arg, curr_argv, len);
369*31ed9f9fSChengwen Feng 		if (match) {
370*31ed9f9fSChengwen Feng 			/* Obtains the exact matching name (long or short). */
371*31ed9f9fSChengwen Feng 			*arg_name = len > 2 ? arg->name_long : arg->name_short;
372*31ed9f9fSChengwen Feng 			return arg;
373*31ed9f9fSChengwen Feng 		}
374*31ed9f9fSChengwen Feng 	}
375*31ed9f9fSChengwen Feng 
376*31ed9f9fSChengwen Feng 	return NULL;
377*31ed9f9fSChengwen Feng }
378*31ed9f9fSChengwen Feng 
379*31ed9f9fSChengwen Feng static int
380*31ed9f9fSChengwen Feng parse_arg_int(struct rte_argparse_arg *arg, const char *value)
381*31ed9f9fSChengwen Feng {
382*31ed9f9fSChengwen Feng 	char *s = NULL;
383*31ed9f9fSChengwen Feng 
384*31ed9f9fSChengwen Feng 	if (value == NULL) {
385*31ed9f9fSChengwen Feng 		*(int *)arg->val_saver = (int)(intptr_t)arg->val_set;
386*31ed9f9fSChengwen Feng 		return 0;
387*31ed9f9fSChengwen Feng 	}
388*31ed9f9fSChengwen Feng 
389*31ed9f9fSChengwen Feng 	errno = 0;
390*31ed9f9fSChengwen Feng 	*(int *)arg->val_saver = strtol(value, &s, 0);
391*31ed9f9fSChengwen Feng 	if (errno == ERANGE) {
392*31ed9f9fSChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
393*31ed9f9fSChengwen Feng 		return -EINVAL;
394*31ed9f9fSChengwen Feng 	}
395*31ed9f9fSChengwen Feng 
396*31ed9f9fSChengwen Feng 	if (s[0] != '\0') {
397*31ed9f9fSChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long);
398*31ed9f9fSChengwen Feng 		return -EINVAL;
399*31ed9f9fSChengwen Feng 	}
400*31ed9f9fSChengwen Feng 
401*31ed9f9fSChengwen Feng 	return 0;
402*31ed9f9fSChengwen Feng }
403*31ed9f9fSChengwen Feng 
404*31ed9f9fSChengwen Feng static int
405*31ed9f9fSChengwen Feng parse_arg_autosave(struct rte_argparse_arg *arg, const char *value)
406*31ed9f9fSChengwen Feng {
407*31ed9f9fSChengwen Feng 	static struct {
408*31ed9f9fSChengwen Feng 		int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value);
409*31ed9f9fSChengwen Feng 	} map[] = {
410*31ed9f9fSChengwen Feng 		/* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */
411*31ed9f9fSChengwen Feng 		{ NULL          },
412*31ed9f9fSChengwen Feng 		{ parse_arg_int },
413*31ed9f9fSChengwen Feng 	};
414*31ed9f9fSChengwen Feng 	uint32_t index = arg_attr_val_type(arg);
415*31ed9f9fSChengwen Feng 	int ret = -EINVAL;
416*31ed9f9fSChengwen Feng 
417*31ed9f9fSChengwen Feng 	if (index > 0 && index < RTE_DIM(map))
418*31ed9f9fSChengwen Feng 		ret = map[index].f_parse_type(arg, value);
419*31ed9f9fSChengwen Feng 
420*31ed9f9fSChengwen Feng 	return ret;
421*31ed9f9fSChengwen Feng }
422*31ed9f9fSChengwen Feng 
423*31ed9f9fSChengwen Feng static int
424*31ed9f9fSChengwen Feng parse_arg_val(struct rte_argparse *obj, struct rte_argparse_arg *arg, char *value)
425e3e579f5SChengwen Feng {
4266c5c6571SChengwen Feng 	int ret;
4276c5c6571SChengwen Feng 
428*31ed9f9fSChengwen Feng 	if (arg->val_saver == NULL)
429*31ed9f9fSChengwen Feng 		ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque);
430*31ed9f9fSChengwen Feng 	else
431*31ed9f9fSChengwen Feng 		ret = parse_arg_autosave(arg, value);
432*31ed9f9fSChengwen Feng 	if (ret != 0) {
433*31ed9f9fSChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg->name_long);
434*31ed9f9fSChengwen Feng 		return ret;
435*31ed9f9fSChengwen Feng 	}
436*31ed9f9fSChengwen Feng 
437*31ed9f9fSChengwen Feng 	return 0;
438*31ed9f9fSChengwen Feng }
439*31ed9f9fSChengwen Feng 
440*31ed9f9fSChengwen Feng static bool
441*31ed9f9fSChengwen Feng is_help(const char *curr_argv)
442*31ed9f9fSChengwen Feng {
443*31ed9f9fSChengwen Feng 	return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0;
444*31ed9f9fSChengwen Feng }
445*31ed9f9fSChengwen Feng 
446*31ed9f9fSChengwen Feng static int
447*31ed9f9fSChengwen Feng parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help)
448*31ed9f9fSChengwen Feng {
449*31ed9f9fSChengwen Feng 	uint32_t position_count = calc_position_count(obj);
450*31ed9f9fSChengwen Feng 	struct rte_argparse_arg *arg;
451*31ed9f9fSChengwen Feng 	uint32_t position_index = 0;
452*31ed9f9fSChengwen Feng 	const char *arg_name;
453*31ed9f9fSChengwen Feng 	char *curr_argv;
454*31ed9f9fSChengwen Feng 	char *has_equal;
455*31ed9f9fSChengwen Feng 	char *value;
456*31ed9f9fSChengwen Feng 	int ret;
457*31ed9f9fSChengwen Feng 	int i;
458*31ed9f9fSChengwen Feng 
459*31ed9f9fSChengwen Feng 	for (i = 1; i < argc; i++) {
460*31ed9f9fSChengwen Feng 		curr_argv = argv[i];
461*31ed9f9fSChengwen Feng 		if (curr_argv[0] != '-') {
462*31ed9f9fSChengwen Feng 			/* process positional parameters. */
463*31ed9f9fSChengwen Feng 			position_index++;
464*31ed9f9fSChengwen Feng 			if (position_index > position_count) {
465*31ed9f9fSChengwen Feng 				ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv);
466*31ed9f9fSChengwen Feng 				return -EINVAL;
467*31ed9f9fSChengwen Feng 			}
468*31ed9f9fSChengwen Feng 			arg = find_position_arg(obj, position_index);
469*31ed9f9fSChengwen Feng 			ret = parse_arg_val(obj, arg, curr_argv);
470*31ed9f9fSChengwen Feng 			if (ret != 0)
471*31ed9f9fSChengwen Feng 				return ret;
472*31ed9f9fSChengwen Feng 			continue;
473*31ed9f9fSChengwen Feng 		}
474*31ed9f9fSChengwen Feng 
475*31ed9f9fSChengwen Feng 		/* process optional parameters. */
476*31ed9f9fSChengwen Feng 		if (is_help(curr_argv)) {
477*31ed9f9fSChengwen Feng 			*show_help = true;
478*31ed9f9fSChengwen Feng 			continue;
479*31ed9f9fSChengwen Feng 		}
480*31ed9f9fSChengwen Feng 
481*31ed9f9fSChengwen Feng 		has_equal = strchr(curr_argv, '=');
482*31ed9f9fSChengwen Feng 		arg_name = NULL;
483*31ed9f9fSChengwen Feng 		arg = find_option_arg(obj, curr_argv, has_equal, &arg_name);
484*31ed9f9fSChengwen Feng 		if (arg == NULL || arg_name == NULL) {
485*31ed9f9fSChengwen Feng 			ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv);
486*31ed9f9fSChengwen Feng 			return -EINVAL;
487*31ed9f9fSChengwen Feng 		}
488*31ed9f9fSChengwen Feng 
489*31ed9f9fSChengwen Feng 		if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) {
490*31ed9f9fSChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s should not occur multiple!",
491*31ed9f9fSChengwen Feng 				     arg_name);
492*31ed9f9fSChengwen Feng 			return -EINVAL;
493*31ed9f9fSChengwen Feng 		}
494*31ed9f9fSChengwen Feng 
495*31ed9f9fSChengwen Feng 		value = (has_equal != NULL ? has_equal + 1 : NULL);
496*31ed9f9fSChengwen Feng 		if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) {
497*31ed9f9fSChengwen Feng 			if (value != NULL) {
498*31ed9f9fSChengwen Feng 				ARGPARSE_LOG(ERR, "argument %s should not take value!",
499*31ed9f9fSChengwen Feng 					     arg_name);
500*31ed9f9fSChengwen Feng 				return -EINVAL;
501*31ed9f9fSChengwen Feng 			}
502*31ed9f9fSChengwen Feng 		} else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) {
503*31ed9f9fSChengwen Feng 			if (value == NULL) {
504*31ed9f9fSChengwen Feng 				if (i >= argc - 1) {
505*31ed9f9fSChengwen Feng 					ARGPARSE_LOG(ERR, "argument %s doesn't have value!",
506*31ed9f9fSChengwen Feng 						     arg_name);
507*31ed9f9fSChengwen Feng 					return -EINVAL;
508*31ed9f9fSChengwen Feng 				}
509*31ed9f9fSChengwen Feng 				/* Set value and make i move next. */
510*31ed9f9fSChengwen Feng 				value = argv[++i];
511*31ed9f9fSChengwen Feng 			}
512*31ed9f9fSChengwen Feng 		} else {
513*31ed9f9fSChengwen Feng 			/* Do nothing, because it's optional value, only support arg=val or arg. */
514*31ed9f9fSChengwen Feng 		}
515*31ed9f9fSChengwen Feng 
516*31ed9f9fSChengwen Feng 		ret = parse_arg_val(obj, arg, value);
517*31ed9f9fSChengwen Feng 		if (ret != 0)
518*31ed9f9fSChengwen Feng 			return ret;
519*31ed9f9fSChengwen Feng 
520*31ed9f9fSChengwen Feng 		/* This argument parsed success! then mark it parsed. */
521*31ed9f9fSChengwen Feng 		arg->flags |= ARG_ATTR_FLAG_PARSED_MASK;
522*31ed9f9fSChengwen Feng 	}
523*31ed9f9fSChengwen Feng 
524*31ed9f9fSChengwen Feng 	return 0;
525*31ed9f9fSChengwen Feng }
526*31ed9f9fSChengwen Feng 
527*31ed9f9fSChengwen Feng static void
528*31ed9f9fSChengwen Feng show_args_pos_help(const struct rte_argparse *obj)
529*31ed9f9fSChengwen Feng {
530*31ed9f9fSChengwen Feng 	uint32_t position_count = calc_position_count(obj);
531*31ed9f9fSChengwen Feng 	const struct rte_argparse_arg *arg;
532*31ed9f9fSChengwen Feng 	uint32_t i;
533*31ed9f9fSChengwen Feng 
534*31ed9f9fSChengwen Feng 	if (position_count == 0)
535*31ed9f9fSChengwen Feng 		return;
536*31ed9f9fSChengwen Feng 
537*31ed9f9fSChengwen Feng 	printf("\npositional arguments:\n");
538*31ed9f9fSChengwen Feng 	for (i = 0; /* NULL */; i++) {
539*31ed9f9fSChengwen Feng 		arg = &obj->args[i];
540*31ed9f9fSChengwen Feng 		if (arg->name_long == NULL)
541*31ed9f9fSChengwen Feng 			break;
542*31ed9f9fSChengwen Feng 		if (!is_arg_positional(arg))
543*31ed9f9fSChengwen Feng 			continue;
544*31ed9f9fSChengwen Feng 		printf(" %s: %s\n", arg->name_long, arg->help);
545*31ed9f9fSChengwen Feng 	}
546*31ed9f9fSChengwen Feng }
547*31ed9f9fSChengwen Feng 
548*31ed9f9fSChengwen Feng static void
549*31ed9f9fSChengwen Feng show_args_opt_help(const struct rte_argparse *obj)
550*31ed9f9fSChengwen Feng {
551*31ed9f9fSChengwen Feng 	const struct rte_argparse_arg *arg;
552*31ed9f9fSChengwen Feng 	uint32_t i;
553*31ed9f9fSChengwen Feng 
554*31ed9f9fSChengwen Feng 	printf("\noptions:\n"
555*31ed9f9fSChengwen Feng 	       " -h, --help: show this help message and exit.\n");
556*31ed9f9fSChengwen Feng 	for (i = 0; /* NULL */; i++) {
557*31ed9f9fSChengwen Feng 		arg = &obj->args[i];
558*31ed9f9fSChengwen Feng 		if (arg->name_long == NULL)
559*31ed9f9fSChengwen Feng 			break;
560*31ed9f9fSChengwen Feng 		if (!is_arg_optional(arg))
561*31ed9f9fSChengwen Feng 			continue;
562*31ed9f9fSChengwen Feng 		if (arg->name_short != NULL)
563*31ed9f9fSChengwen Feng 			printf(" %s, %s: %s\n", arg->name_short, arg->name_long, arg->help);
564*31ed9f9fSChengwen Feng 		else
565*31ed9f9fSChengwen Feng 			printf(" %s: %s\n", arg->name_long, arg->help);
566*31ed9f9fSChengwen Feng 	}
567*31ed9f9fSChengwen Feng }
568*31ed9f9fSChengwen Feng 
569*31ed9f9fSChengwen Feng static void
570*31ed9f9fSChengwen Feng show_args_help(const struct rte_argparse *obj)
571*31ed9f9fSChengwen Feng {
572*31ed9f9fSChengwen Feng 	printf("usage: %s %s\n", obj->prog_name, obj->usage);
573*31ed9f9fSChengwen Feng 	if (obj->descriptor != NULL)
574*31ed9f9fSChengwen Feng 		printf("\ndescriptor: %s\n", obj->descriptor);
575*31ed9f9fSChengwen Feng 
576*31ed9f9fSChengwen Feng 	show_args_pos_help(obj);
577*31ed9f9fSChengwen Feng 	show_args_opt_help(obj);
578*31ed9f9fSChengwen Feng 
579*31ed9f9fSChengwen Feng 	if (obj->epilog != NULL)
580*31ed9f9fSChengwen Feng 		printf("\n%s\n", obj->epilog);
581*31ed9f9fSChengwen Feng }
582*31ed9f9fSChengwen Feng 
583*31ed9f9fSChengwen Feng int
584*31ed9f9fSChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv)
585*31ed9f9fSChengwen Feng {
586*31ed9f9fSChengwen Feng 	bool show_help = false;
587*31ed9f9fSChengwen Feng 	int ret;
5886c5c6571SChengwen Feng 
5896c5c6571SChengwen Feng 	ret = verify_argparse(obj);
5906c5c6571SChengwen Feng 	if (ret != 0)
5916c5c6571SChengwen Feng 		goto error;
5926c5c6571SChengwen Feng 
593*31ed9f9fSChengwen Feng 	ret = parse_args(obj, argc, argv, &show_help);
594*31ed9f9fSChengwen Feng 	if (ret != 0)
595*31ed9f9fSChengwen Feng 		goto error;
596*31ed9f9fSChengwen Feng 
597*31ed9f9fSChengwen Feng 	if (show_help) {
598*31ed9f9fSChengwen Feng 		show_args_help(obj);
599*31ed9f9fSChengwen Feng 		exit(0);
600*31ed9f9fSChengwen Feng 	}
601*31ed9f9fSChengwen Feng 
602e3e579f5SChengwen Feng 	return 0;
6036c5c6571SChengwen Feng 
6046c5c6571SChengwen Feng error:
6056c5c6571SChengwen Feng 	if (obj->exit_on_error)
6066c5c6571SChengwen Feng 		exit(ret);
6076c5c6571SChengwen Feng 	return ret;
608e3e579f5SChengwen Feng }
609