xref: /dpdk/lib/argparse/rte_argparse.c (revision 6c5c6571601c527815a105cf878101911b4aa53d)
1e3e579f5SChengwen Feng /* SPDX-License-Identifier: BSD-3-Clause
2e3e579f5SChengwen Feng  * Copyright(c) 2024 HiSilicon Limited
3e3e579f5SChengwen Feng  */
4e3e579f5SChengwen Feng 
5*6c5c6571SChengwen Feng #include <errno.h>
6*6c5c6571SChengwen Feng #include <stdlib.h>
7*6c5c6571SChengwen Feng #include <string.h>
8*6c5c6571SChengwen Feng 
9*6c5c6571SChengwen Feng #include <rte_log.h>
10*6c5c6571SChengwen Feng 
11e3e579f5SChengwen Feng #include "rte_argparse.h"
12e3e579f5SChengwen Feng 
13*6c5c6571SChengwen Feng RTE_LOG_REGISTER_DEFAULT(rte_argparse_logtype, INFO);
14*6c5c6571SChengwen Feng #define RTE_LOGTYPE_ARGPARSE rte_argparse_logtype
15*6c5c6571SChengwen Feng #define ARGPARSE_LOG(level, ...) \
16*6c5c6571SChengwen Feng 	RTE_LOG_LINE(level, ARGPARSE, "" __VA_ARGS__)
17*6c5c6571SChengwen Feng 
18*6c5c6571SChengwen Feng #define ARG_ATTR_HAS_VAL_MASK		RTE_GENMASK64(1, 0)
19*6c5c6571SChengwen Feng #define ARG_ATTR_VAL_TYPE_MASK		RTE_GENMASK64(9, 2)
20*6c5c6571SChengwen Feng #define ARG_ATTR_SUPPORT_MULTI_MASK	RTE_BIT64(10)
21*6c5c6571SChengwen Feng #define ARG_ATTR_FLAG_PARSED_MASK	RTE_BIT64(63)
22*6c5c6571SChengwen Feng 
23*6c5c6571SChengwen Feng static inline bool
24*6c5c6571SChengwen Feng is_arg_optional(const struct rte_argparse_arg *arg)
25*6c5c6571SChengwen Feng {
26*6c5c6571SChengwen Feng 	return arg->name_long[0] == '-';
27*6c5c6571SChengwen Feng }
28*6c5c6571SChengwen Feng 
29*6c5c6571SChengwen Feng static inline bool
30*6c5c6571SChengwen Feng is_arg_positional(const struct rte_argparse_arg *arg)
31*6c5c6571SChengwen Feng {
32*6c5c6571SChengwen Feng 	return arg->name_long[0] != '-';
33*6c5c6571SChengwen Feng }
34*6c5c6571SChengwen Feng 
35*6c5c6571SChengwen Feng static inline uint32_t
36*6c5c6571SChengwen Feng arg_attr_has_val(const struct rte_argparse_arg *arg)
37*6c5c6571SChengwen Feng {
38*6c5c6571SChengwen Feng 	return RTE_FIELD_GET64(ARG_ATTR_HAS_VAL_MASK, arg->flags);
39*6c5c6571SChengwen Feng }
40*6c5c6571SChengwen Feng 
41*6c5c6571SChengwen Feng static inline uint32_t
42*6c5c6571SChengwen Feng arg_attr_val_type(const struct rte_argparse_arg *arg)
43*6c5c6571SChengwen Feng {
44*6c5c6571SChengwen Feng 	return RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, arg->flags);
45*6c5c6571SChengwen Feng }
46*6c5c6571SChengwen Feng 
47*6c5c6571SChengwen Feng static inline uint32_t
48*6c5c6571SChengwen Feng arg_attr_unused_bits(const struct rte_argparse_arg *arg)
49*6c5c6571SChengwen Feng {
50*6c5c6571SChengwen Feng #define USED_BIT_MASK	(ARG_ATTR_HAS_VAL_MASK | ARG_ATTR_VAL_TYPE_MASK | \
51*6c5c6571SChengwen Feng 			 ARG_ATTR_SUPPORT_MULTI_MASK)
52*6c5c6571SChengwen Feng 	return arg->flags & ~USED_BIT_MASK;
53*6c5c6571SChengwen Feng }
54*6c5c6571SChengwen Feng 
55*6c5c6571SChengwen Feng static int
56*6c5c6571SChengwen Feng verify_arg_name(const struct rte_argparse_arg *arg)
57*6c5c6571SChengwen Feng {
58*6c5c6571SChengwen Feng 	if (is_arg_optional(arg)) {
59*6c5c6571SChengwen Feng 		if (strlen(arg->name_long) <= 3) {
60*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long);
61*6c5c6571SChengwen Feng 			return -EINVAL;
62*6c5c6571SChengwen Feng 		}
63*6c5c6571SChengwen Feng 		if (arg->name_long[1] != '-') {
64*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "optional long name %s must only start with '--'",
65*6c5c6571SChengwen Feng 				     arg->name_long);
66*6c5c6571SChengwen Feng 			return -EINVAL;
67*6c5c6571SChengwen Feng 		}
68*6c5c6571SChengwen Feng 		if (arg->name_long[2] == '-') {
69*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'",
70*6c5c6571SChengwen Feng 				     arg->name_long);
71*6c5c6571SChengwen Feng 			return -EINVAL;
72*6c5c6571SChengwen Feng 		}
73*6c5c6571SChengwen Feng 	}
74*6c5c6571SChengwen Feng 
75*6c5c6571SChengwen Feng 	if (arg->name_short == NULL)
76*6c5c6571SChengwen Feng 		return 0;
77*6c5c6571SChengwen Feng 
78*6c5c6571SChengwen Feng 	if (!is_arg_optional(arg)) {
79*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!",
80*6c5c6571SChengwen Feng 			     arg->name_short);
81*6c5c6571SChengwen Feng 		return -EINVAL;
82*6c5c6571SChengwen Feng 	}
83*6c5c6571SChengwen Feng 
84*6c5c6571SChengwen Feng 	if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' ||
85*6c5c6571SChengwen Feng 		arg->name_short[1] == '-') {
86*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter",
87*6c5c6571SChengwen Feng 			     arg->name_short);
88*6c5c6571SChengwen Feng 		return -EINVAL;
89*6c5c6571SChengwen Feng 	}
90*6c5c6571SChengwen Feng 
91*6c5c6571SChengwen Feng 	return 0;
92*6c5c6571SChengwen Feng }
93*6c5c6571SChengwen Feng 
94*6c5c6571SChengwen Feng static int
95*6c5c6571SChengwen Feng verify_arg_help(const struct rte_argparse_arg *arg)
96*6c5c6571SChengwen Feng {
97*6c5c6571SChengwen Feng 	if (arg->help == NULL) {
98*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s must have help info!", arg->name_long);
99*6c5c6571SChengwen Feng 		return -EINVAL;
100*6c5c6571SChengwen Feng 	}
101*6c5c6571SChengwen Feng 
102*6c5c6571SChengwen Feng 	return 0;
103*6c5c6571SChengwen Feng }
104*6c5c6571SChengwen Feng 
105*6c5c6571SChengwen Feng static int
106*6c5c6571SChengwen Feng verify_arg_has_val(const struct rte_argparse_arg *arg)
107*6c5c6571SChengwen Feng {
108*6c5c6571SChengwen Feng 	uint32_t has_val = arg_attr_has_val(arg);
109*6c5c6571SChengwen Feng 
110*6c5c6571SChengwen Feng 	if (is_arg_positional(arg)) {
111*6c5c6571SChengwen Feng 		if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE)
112*6c5c6571SChengwen Feng 			return 0;
113*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s is positional, should has zero or required-val!",
114*6c5c6571SChengwen Feng 			     arg->name_long);
115*6c5c6571SChengwen Feng 		return -EINVAL;
116*6c5c6571SChengwen Feng 	}
117*6c5c6571SChengwen Feng 
118*6c5c6571SChengwen Feng 	if (has_val == 0) {
119*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s is optional, has-val config wrong!",
120*6c5c6571SChengwen Feng 			     arg->name_long);
121*6c5c6571SChengwen Feng 		return -EINVAL;
122*6c5c6571SChengwen Feng 	}
123*6c5c6571SChengwen Feng 
124*6c5c6571SChengwen Feng 	return 0;
125*6c5c6571SChengwen Feng }
126*6c5c6571SChengwen Feng 
127*6c5c6571SChengwen Feng static int
128*6c5c6571SChengwen Feng verify_arg_saver(const struct rte_argparse *obj, uint32_t index)
129*6c5c6571SChengwen Feng {
130*6c5c6571SChengwen Feng 	uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX);
131*6c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &obj->args[index];
132*6c5c6571SChengwen Feng 	uint32_t val_type = arg_attr_val_type(arg);
133*6c5c6571SChengwen Feng 	uint32_t has_val = arg_attr_has_val(arg);
134*6c5c6571SChengwen Feng 
135*6c5c6571SChengwen Feng 	if (arg->val_saver == NULL) {
136*6c5c6571SChengwen Feng 		if (val_type != 0) {
137*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s parse by callback, val-type must be zero!",
138*6c5c6571SChengwen Feng 				     arg->name_long);
139*6c5c6571SChengwen Feng 			return -EINVAL;
140*6c5c6571SChengwen Feng 		}
141*6c5c6571SChengwen Feng 
142*6c5c6571SChengwen Feng 		if (obj->callback == NULL) {
143*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s parse by callback, but callback is NULL!",
144*6c5c6571SChengwen Feng 				     arg->name_long);
145*6c5c6571SChengwen Feng 			return -EINVAL;
146*6c5c6571SChengwen Feng 		}
147*6c5c6571SChengwen Feng 
148*6c5c6571SChengwen Feng 		return 0;
149*6c5c6571SChengwen Feng 	}
150*6c5c6571SChengwen Feng 
151*6c5c6571SChengwen Feng 	if (val_type == 0 || val_type >= cmp_max) {
152*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s val-type config wrong!", arg->name_long);
153*6c5c6571SChengwen Feng 		return -EINVAL;
154*6c5c6571SChengwen Feng 	}
155*6c5c6571SChengwen Feng 
156*6c5c6571SChengwen Feng 	if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE && arg->val_set != NULL) {
157*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s has required value, val-set should be NULL!",
158*6c5c6571SChengwen Feng 			     arg->name_long);
159*6c5c6571SChengwen Feng 		return -EINVAL;
160*6c5c6571SChengwen Feng 	}
161*6c5c6571SChengwen Feng 
162*6c5c6571SChengwen Feng 	return 0;
163*6c5c6571SChengwen Feng }
164*6c5c6571SChengwen Feng 
165*6c5c6571SChengwen Feng static int
166*6c5c6571SChengwen Feng verify_arg_flags(const struct rte_argparse *obj, uint32_t index)
167*6c5c6571SChengwen Feng {
168*6c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &obj->args[index];
169*6c5c6571SChengwen Feng 	uint32_t unused_bits = arg_attr_unused_bits(arg);
170*6c5c6571SChengwen Feng 
171*6c5c6571SChengwen Feng 	if (unused_bits != 0) {
172*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s flags set wrong!", arg->name_long);
173*6c5c6571SChengwen Feng 		return -EINVAL;
174*6c5c6571SChengwen Feng 	}
175*6c5c6571SChengwen Feng 
176*6c5c6571SChengwen Feng 	if (!(arg->flags & RTE_ARGPARSE_ARG_SUPPORT_MULTI))
177*6c5c6571SChengwen Feng 		return 0;
178*6c5c6571SChengwen Feng 
179*6c5c6571SChengwen Feng 	if (is_arg_positional(arg)) {
180*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!",
181*6c5c6571SChengwen Feng 			     arg->name_long);
182*6c5c6571SChengwen Feng 		return -EINVAL;
183*6c5c6571SChengwen Feng 	}
184*6c5c6571SChengwen Feng 
185*6c5c6571SChengwen Feng 	if (arg->val_saver != NULL) {
186*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s could occur multiple times, should use callback to parse!",
187*6c5c6571SChengwen Feng 			     arg->name_long);
188*6c5c6571SChengwen Feng 		return -EINVAL;
189*6c5c6571SChengwen Feng 	}
190*6c5c6571SChengwen Feng 
191*6c5c6571SChengwen Feng 	if (obj->callback == NULL) {
192*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "argument %s should use callback to parse, but callback is NULL!",
193*6c5c6571SChengwen Feng 			     arg->name_long);
194*6c5c6571SChengwen Feng 		return -EINVAL;
195*6c5c6571SChengwen Feng 	}
196*6c5c6571SChengwen Feng 
197*6c5c6571SChengwen Feng 	return 0;
198*6c5c6571SChengwen Feng }
199*6c5c6571SChengwen Feng 
200*6c5c6571SChengwen Feng static int
201*6c5c6571SChengwen Feng verify_arg_repeat(const struct rte_argparse *self, uint32_t index)
202*6c5c6571SChengwen Feng {
203*6c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &self->args[index];
204*6c5c6571SChengwen Feng 	uint32_t i;
205*6c5c6571SChengwen Feng 
206*6c5c6571SChengwen Feng 	for (i = 0; i < index; i++) {
207*6c5c6571SChengwen Feng 		if (!strcmp(arg->name_long, self->args[i].name_long)) {
208*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long);
209*6c5c6571SChengwen Feng 			return -EINVAL;
210*6c5c6571SChengwen Feng 		}
211*6c5c6571SChengwen Feng 	}
212*6c5c6571SChengwen Feng 
213*6c5c6571SChengwen Feng 	if (arg->name_short == NULL)
214*6c5c6571SChengwen Feng 		return 0;
215*6c5c6571SChengwen Feng 
216*6c5c6571SChengwen Feng 	for (i = 0; i < index; i++) {
217*6c5c6571SChengwen Feng 		if (self->args[i].name_short == NULL)
218*6c5c6571SChengwen Feng 			continue;
219*6c5c6571SChengwen Feng 		if (!strcmp(arg->name_short, self->args[i].name_short)) {
220*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short);
221*6c5c6571SChengwen Feng 			return -EINVAL;
222*6c5c6571SChengwen Feng 		}
223*6c5c6571SChengwen Feng 	}
224*6c5c6571SChengwen Feng 
225*6c5c6571SChengwen Feng 	return 0;
226*6c5c6571SChengwen Feng }
227*6c5c6571SChengwen Feng 
228*6c5c6571SChengwen Feng static int
229*6c5c6571SChengwen Feng verify_argparse_arg(const struct rte_argparse *obj, uint32_t index)
230*6c5c6571SChengwen Feng {
231*6c5c6571SChengwen Feng 	const struct rte_argparse_arg *arg = &obj->args[index];
232*6c5c6571SChengwen Feng 	int ret;
233*6c5c6571SChengwen Feng 
234*6c5c6571SChengwen Feng 	ret = verify_arg_name(arg);
235*6c5c6571SChengwen Feng 	if (ret != 0)
236*6c5c6571SChengwen Feng 		return ret;
237*6c5c6571SChengwen Feng 
238*6c5c6571SChengwen Feng 	ret = verify_arg_help(arg);
239*6c5c6571SChengwen Feng 	if (ret != 0)
240*6c5c6571SChengwen Feng 		return ret;
241*6c5c6571SChengwen Feng 
242*6c5c6571SChengwen Feng 	ret = verify_arg_has_val(arg);
243*6c5c6571SChengwen Feng 	if (ret != 0)
244*6c5c6571SChengwen Feng 		return ret;
245*6c5c6571SChengwen Feng 
246*6c5c6571SChengwen Feng 	ret = verify_arg_saver(obj, index);
247*6c5c6571SChengwen Feng 	if (ret != 0)
248*6c5c6571SChengwen Feng 		return ret;
249*6c5c6571SChengwen Feng 
250*6c5c6571SChengwen Feng 	ret = verify_arg_flags(obj, index);
251*6c5c6571SChengwen Feng 	if (ret != 0)
252*6c5c6571SChengwen Feng 		return ret;
253*6c5c6571SChengwen Feng 
254*6c5c6571SChengwen Feng 	ret = verify_arg_repeat(obj, index);
255*6c5c6571SChengwen Feng 	if (ret != 0)
256*6c5c6571SChengwen Feng 		return ret;
257*6c5c6571SChengwen Feng 
258*6c5c6571SChengwen Feng 	return 0;
259*6c5c6571SChengwen Feng }
260*6c5c6571SChengwen Feng 
261*6c5c6571SChengwen Feng static int
262*6c5c6571SChengwen Feng verify_argparse(const struct rte_argparse *obj)
263*6c5c6571SChengwen Feng {
264*6c5c6571SChengwen Feng 	uint32_t idx;
265*6c5c6571SChengwen Feng 	int ret;
266*6c5c6571SChengwen Feng 
267*6c5c6571SChengwen Feng 	if (obj->prog_name == NULL) {
268*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "program name is NULL!");
269*6c5c6571SChengwen Feng 		return -EINVAL;
270*6c5c6571SChengwen Feng 	}
271*6c5c6571SChengwen Feng 
272*6c5c6571SChengwen Feng 	if (obj->usage == NULL) {
273*6c5c6571SChengwen Feng 		ARGPARSE_LOG(ERR, "usage is NULL!");
274*6c5c6571SChengwen Feng 		return -EINVAL;
275*6c5c6571SChengwen Feng 	}
276*6c5c6571SChengwen Feng 
277*6c5c6571SChengwen Feng 	for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) {
278*6c5c6571SChengwen Feng 		if (obj->reserved[idx] != 0) {
279*6c5c6571SChengwen Feng 			ARGPARSE_LOG(ERR, "reserved field must be zero!");
280*6c5c6571SChengwen Feng 			return -EINVAL;
281*6c5c6571SChengwen Feng 		}
282*6c5c6571SChengwen Feng 	}
283*6c5c6571SChengwen Feng 
284*6c5c6571SChengwen Feng 	idx = 0;
285*6c5c6571SChengwen Feng 	while (obj->args[idx].name_long != NULL) {
286*6c5c6571SChengwen Feng 		ret = verify_argparse_arg(obj, idx);
287*6c5c6571SChengwen Feng 		if (ret != 0)
288*6c5c6571SChengwen Feng 			return ret;
289*6c5c6571SChengwen Feng 		idx++;
290*6c5c6571SChengwen Feng 	}
291*6c5c6571SChengwen Feng 
292*6c5c6571SChengwen Feng 	return 0;
293*6c5c6571SChengwen Feng }
294*6c5c6571SChengwen Feng 
295e3e579f5SChengwen Feng int
296e3e579f5SChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv)
297e3e579f5SChengwen Feng {
298*6c5c6571SChengwen Feng 	int ret;
299*6c5c6571SChengwen Feng 
300e3e579f5SChengwen Feng 	(void)argc;
301e3e579f5SChengwen Feng 	(void)argv;
302*6c5c6571SChengwen Feng 
303*6c5c6571SChengwen Feng 	ret = verify_argparse(obj);
304*6c5c6571SChengwen Feng 	if (ret != 0)
305*6c5c6571SChengwen Feng 		goto error;
306*6c5c6571SChengwen Feng 
307e3e579f5SChengwen Feng 	return 0;
308*6c5c6571SChengwen Feng 
309*6c5c6571SChengwen Feng error:
310*6c5c6571SChengwen Feng 	if (obj->exit_on_error)
311*6c5c6571SChengwen Feng 		exit(ret);
312*6c5c6571SChengwen Feng 	return ret;
313e3e579f5SChengwen Feng }
314