xref: /dpdk/lib/argparse/rte_argparse.c (revision 9b8df29bf15575f2f0570e6f1e68294a399f6917)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2024 HiSilicon Limited
3  */
4 
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <rte_log.h>
10 
11 #include "rte_argparse.h"
12 
13 RTE_LOG_REGISTER_DEFAULT(rte_argparse_logtype, INFO);
14 #define RTE_LOGTYPE_ARGPARSE rte_argparse_logtype
15 #define ARGPARSE_LOG(level, ...) \
16 	RTE_LOG_LINE(level, ARGPARSE, "" __VA_ARGS__)
17 
18 #define ARG_ATTR_HAS_VAL_MASK		RTE_GENMASK64(1, 0)
19 #define ARG_ATTR_VAL_TYPE_MASK		RTE_GENMASK64(9, 2)
20 #define ARG_ATTR_SUPPORT_MULTI_MASK	RTE_BIT64(10)
21 #define ARG_ATTR_FLAG_PARSED_MASK	RTE_BIT64(63)
22 
23 static inline bool
24 is_arg_optional(const struct rte_argparse_arg *arg)
25 {
26 	return arg->name_long[0] == '-';
27 }
28 
29 static inline bool
30 is_arg_positional(const struct rte_argparse_arg *arg)
31 {
32 	return arg->name_long[0] != '-';
33 }
34 
35 static inline uint32_t
36 arg_attr_has_val(const struct rte_argparse_arg *arg)
37 {
38 	return RTE_FIELD_GET64(ARG_ATTR_HAS_VAL_MASK, arg->flags);
39 }
40 
41 static inline uint32_t
42 arg_attr_val_type(const struct rte_argparse_arg *arg)
43 {
44 	return RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, arg->flags);
45 }
46 
47 static inline bool
48 arg_attr_flag_multi(const struct rte_argparse_arg *arg)
49 {
50 	return RTE_FIELD_GET64(ARG_ATTR_SUPPORT_MULTI_MASK, arg->flags);
51 }
52 
53 static inline uint32_t
54 arg_attr_unused_bits(const struct rte_argparse_arg *arg)
55 {
56 #define USED_BIT_MASK	(ARG_ATTR_HAS_VAL_MASK | ARG_ATTR_VAL_TYPE_MASK | \
57 			 ARG_ATTR_SUPPORT_MULTI_MASK)
58 	return arg->flags & ~USED_BIT_MASK;
59 }
60 
61 static int
62 verify_arg_name(const struct rte_argparse_arg *arg)
63 {
64 	if (is_arg_optional(arg)) {
65 		if (strlen(arg->name_long) <= 3) {
66 			ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long);
67 			return -EINVAL;
68 		}
69 		if (arg->name_long[1] != '-') {
70 			ARGPARSE_LOG(ERR, "optional long name %s doesn't start with '--'",
71 				     arg->name_long);
72 			return -EINVAL;
73 		}
74 		if (arg->name_long[2] == '-') {
75 			ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'",
76 				     arg->name_long);
77 			return -EINVAL;
78 		}
79 	}
80 
81 	if (arg->name_short == NULL)
82 		return 0;
83 
84 	if (!is_arg_optional(arg)) {
85 		ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!",
86 			     arg->name_short);
87 		return -EINVAL;
88 	}
89 
90 	if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' ||
91 		arg->name_short[1] == '-') {
92 		ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter",
93 			     arg->name_short);
94 		return -EINVAL;
95 	}
96 
97 	return 0;
98 }
99 
100 static int
101 verify_arg_help(const struct rte_argparse_arg *arg)
102 {
103 	if (arg->help == NULL) {
104 		ARGPARSE_LOG(ERR, "argument %s doesn't have help info!", arg->name_long);
105 		return -EINVAL;
106 	}
107 
108 	return 0;
109 }
110 
111 static int
112 verify_arg_has_val(const struct rte_argparse_arg *arg)
113 {
114 	uint32_t has_val = arg_attr_has_val(arg);
115 
116 	if (is_arg_positional(arg)) {
117 		if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE)
118 			return 0;
119 		ARGPARSE_LOG(ERR, "argument %s is positional, must config required-val!",
120 			     arg->name_long);
121 		return -EINVAL;
122 	}
123 
124 	if (has_val == 0) {
125 		ARGPARSE_LOG(ERR, "argument %s is optional, has-value config wrong!",
126 			     arg->name_long);
127 		return -EINVAL;
128 	}
129 
130 	return 0;
131 }
132 
133 static int
134 verify_arg_saver(const struct rte_argparse *obj, uint32_t index)
135 {
136 	uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX);
137 	const struct rte_argparse_arg *arg = &obj->args[index];
138 	uint32_t val_type = arg_attr_val_type(arg);
139 	uint32_t has_val = arg_attr_has_val(arg);
140 
141 	if (arg->val_saver == NULL) {
142 		if (val_type != 0) {
143 			ARGPARSE_LOG(ERR, "argument %s parsed by callback, value-type should not be set!",
144 				     arg->name_long);
145 			return -EINVAL;
146 		}
147 
148 		if (obj->callback == NULL) {
149 			ARGPARSE_LOG(ERR, "argument %s parsed by callback, but callback is NULL!",
150 				     arg->name_long);
151 			return -EINVAL;
152 		}
153 
154 		return 0;
155 	}
156 
157 	if (val_type == 0 || val_type >= cmp_max) {
158 		ARGPARSE_LOG(ERR, "argument %s value-type config wrong!", arg->name_long);
159 		return -EINVAL;
160 	}
161 
162 	if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE && arg->val_set != NULL) {
163 		ARGPARSE_LOG(ERR, "argument %s has required value, value-set should be NULL!",
164 			     arg->name_long);
165 		return -EINVAL;
166 	}
167 
168 	return 0;
169 }
170 
171 static int
172 verify_arg_flags(const struct rte_argparse *obj, uint32_t index)
173 {
174 	const struct rte_argparse_arg *arg = &obj->args[index];
175 	uint32_t unused_bits = arg_attr_unused_bits(arg);
176 
177 	if (unused_bits != 0) {
178 		ARGPARSE_LOG(ERR, "argument %s flags unused bits should not be set!",
179 			     arg->name_long);
180 		return -EINVAL;
181 	}
182 
183 	if (!(arg->flags & RTE_ARGPARSE_ARG_SUPPORT_MULTI))
184 		return 0;
185 
186 	if (is_arg_positional(arg)) {
187 		ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!",
188 			     arg->name_long);
189 		return -EINVAL;
190 	}
191 
192 	if (arg->val_saver != NULL) {
193 		ARGPARSE_LOG(ERR, "argument %s supports multiple times, should use callback to parse!",
194 			     arg->name_long);
195 		return -EINVAL;
196 	}
197 
198 	if (obj->callback == NULL) {
199 		ARGPARSE_LOG(ERR, "argument %s should use callback to parse, but callback is NULL!",
200 			     arg->name_long);
201 		return -EINVAL;
202 	}
203 
204 	return 0;
205 }
206 
207 static int
208 verify_arg_repeat(const struct rte_argparse *self, uint32_t index)
209 {
210 	const struct rte_argparse_arg *arg = &self->args[index];
211 	uint32_t i;
212 
213 	for (i = 0; i < index; i++) {
214 		if (!strcmp(arg->name_long, self->args[i].name_long)) {
215 			ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long);
216 			return -EINVAL;
217 		}
218 	}
219 
220 	if (arg->name_short == NULL)
221 		return 0;
222 
223 	for (i = 0; i < index; i++) {
224 		if (self->args[i].name_short == NULL)
225 			continue;
226 		if (!strcmp(arg->name_short, self->args[i].name_short)) {
227 			ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short);
228 			return -EINVAL;
229 		}
230 	}
231 
232 	return 0;
233 }
234 
235 static int
236 verify_argparse_arg(const struct rte_argparse *obj, uint32_t index)
237 {
238 	const struct rte_argparse_arg *arg = &obj->args[index];
239 	int ret;
240 
241 	ret = verify_arg_name(arg);
242 	if (ret != 0)
243 		return ret;
244 
245 	ret = verify_arg_help(arg);
246 	if (ret != 0)
247 		return ret;
248 
249 	ret = verify_arg_has_val(arg);
250 	if (ret != 0)
251 		return ret;
252 
253 	ret = verify_arg_saver(obj, index);
254 	if (ret != 0)
255 		return ret;
256 
257 	ret = verify_arg_flags(obj, index);
258 	if (ret != 0)
259 		return ret;
260 
261 	ret = verify_arg_repeat(obj, index);
262 	if (ret != 0)
263 		return ret;
264 
265 	return 0;
266 }
267 
268 static int
269 verify_argparse(const struct rte_argparse *obj)
270 {
271 	uint32_t idx;
272 	int ret;
273 
274 	if (obj->prog_name == NULL) {
275 		ARGPARSE_LOG(ERR, "program name is NULL!");
276 		return -EINVAL;
277 	}
278 
279 	if (obj->usage == NULL) {
280 		ARGPARSE_LOG(ERR, "usage is NULL!");
281 		return -EINVAL;
282 	}
283 
284 	for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) {
285 		if (obj->reserved[idx] != 0) {
286 			ARGPARSE_LOG(ERR, "reserved field must be zero!");
287 			return -EINVAL;
288 		}
289 	}
290 
291 	idx = 0;
292 	while (obj->args[idx].name_long != NULL) {
293 		ret = verify_argparse_arg(obj, idx);
294 		if (ret != 0)
295 			return ret;
296 		idx++;
297 	}
298 
299 	return 0;
300 }
301 
302 static uint32_t
303 calc_position_count(const struct rte_argparse *obj)
304 {
305 	const struct rte_argparse_arg *arg;
306 	uint32_t count = 0;
307 	uint32_t i;
308 
309 	for (i = 0; /* NULL */; i++) {
310 		arg = &obj->args[i];
311 		if (obj->args[i].name_long == NULL)
312 			break;
313 		if (is_arg_positional(arg))
314 			count++;
315 	}
316 
317 	return count;
318 }
319 
320 static struct rte_argparse_arg *
321 find_position_arg(struct rte_argparse *obj, uint32_t index)
322 {
323 	struct rte_argparse_arg *arg;
324 	uint32_t count = 0;
325 	uint32_t i;
326 
327 	for (i = 0; /* NULL */; i++) {
328 		arg = &obj->args[i];
329 		if (arg->name_long == NULL)
330 			break;
331 		if (!is_arg_positional(arg))
332 			continue;
333 		count++;
334 		if (count == index)
335 			return arg;
336 	}
337 
338 	return NULL;
339 }
340 
341 static bool
342 is_arg_match(struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len)
343 {
344 	if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0)
345 		return true;
346 
347 	if (arg->name_short == NULL)
348 		return false;
349 
350 	if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0)
351 		return true;
352 
353 	return false;
354 }
355 
356 static struct rte_argparse_arg *
357 find_option_arg(struct rte_argparse *obj, const char *curr_argv, const char *has_equal,
358 		const char **arg_name)
359 {
360 	uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0);
361 	struct rte_argparse_arg *arg;
362 	uint32_t i;
363 	bool match;
364 
365 	for (i = 0; /* nothing */; i++) {
366 		arg = &obj->args[i];
367 		if (arg->name_long == NULL)
368 			break;
369 		match = is_arg_match(arg, curr_argv, len);
370 		if (match) {
371 			/* Obtains the exact matching name (long or short). */
372 			*arg_name = len > 2 ? arg->name_long : arg->name_short;
373 			return arg;
374 		}
375 	}
376 
377 	return NULL;
378 }
379 
380 static int
381 parse_arg_int(struct rte_argparse_arg *arg, const char *value)
382 {
383 	char *s = NULL;
384 
385 	if (value == NULL) {
386 		*(int *)arg->val_saver = (int)(intptr_t)arg->val_set;
387 		return 0;
388 	}
389 
390 	errno = 0;
391 	*(int *)arg->val_saver = strtol(value, &s, 0);
392 	if (errno == ERANGE) {
393 		ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
394 		return -EINVAL;
395 	}
396 
397 	if (s[0] != '\0') {
398 		ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long);
399 		return -EINVAL;
400 	}
401 
402 	return 0;
403 }
404 
405 static int
406 parse_arg_u8(struct rte_argparse_arg *arg, const char *value)
407 {
408 	unsigned long val;
409 	char *s = NULL;
410 
411 	if (value == NULL) {
412 		*(uint8_t *)arg->val_saver = (uint8_t)(intptr_t)arg->val_set;
413 		return 0;
414 	}
415 
416 	errno = 0;
417 	val = strtoul(value, &s, 0);
418 	if (errno == ERANGE || val > UINT8_MAX) {
419 		ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
420 		return -EINVAL;
421 	}
422 
423 	if (s[0] != '\0') {
424 		ARGPARSE_LOG(ERR, "argument %s expect an uint8 value!", arg->name_long);
425 		return -EINVAL;
426 	}
427 
428 	*(uint8_t *)arg->val_saver = val;
429 
430 	return 0;
431 }
432 
433 static int
434 parse_arg_u16(struct rte_argparse_arg *arg, const char *value)
435 {
436 	unsigned long val;
437 	char *s = NULL;
438 
439 	if (value == NULL) {
440 		*(uint16_t *)arg->val_saver = (uint16_t)(intptr_t)arg->val_set;
441 		return 0;
442 	}
443 
444 	errno = 0;
445 	val = strtoul(value, &s, 0);
446 	if (errno == ERANGE || val > UINT16_MAX) {
447 		ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
448 		return -EINVAL;
449 	}
450 
451 	if (s[0] != '\0') {
452 		ARGPARSE_LOG(ERR, "argument %s expect an uint16 value!", arg->name_long);
453 		return -EINVAL;
454 	}
455 
456 	*(uint16_t *)arg->val_saver = val;
457 
458 	return 0;
459 }
460 
461 static int
462 parse_arg_u32(struct rte_argparse_arg *arg, const char *value)
463 {
464 	unsigned long val;
465 	char *s = NULL;
466 
467 	if (value == NULL) {
468 		*(uint32_t *)arg->val_saver = (uint32_t)(intptr_t)arg->val_set;
469 		return 0;
470 	}
471 
472 	errno = 0;
473 	val = strtoul(value, &s, 0);
474 	if (errno == ERANGE || val > UINT32_MAX) {
475 		ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
476 		return -EINVAL;
477 	}
478 
479 	if (s[0] != '\0') {
480 		ARGPARSE_LOG(ERR, "argument %s expect an uint32 value!", arg->name_long);
481 		return -EINVAL;
482 	}
483 
484 	*(uint32_t *)arg->val_saver = val;
485 
486 	return 0;
487 }
488 
489 static int
490 parse_arg_u64(struct rte_argparse_arg *arg, const char *value)
491 {
492 	unsigned long val;
493 	char *s = NULL;
494 
495 	if (value == NULL) {
496 		*(uint64_t *)arg->val_saver = (uint64_t)(intptr_t)arg->val_set;
497 		return 0;
498 	}
499 
500 	errno = 0;
501 	val = strtoull(value, &s, 0);
502 	if (errno == ERANGE) {
503 		ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
504 		return -EINVAL;
505 	}
506 
507 	if (s[0] != '\0') {
508 		ARGPARSE_LOG(ERR, "argument %s expect an uint64 value!", arg->name_long);
509 		return -EINVAL;
510 	}
511 
512 	*(uint64_t *)arg->val_saver = val;
513 
514 	return 0;
515 }
516 
517 static int
518 parse_arg_autosave(struct rte_argparse_arg *arg, const char *value)
519 {
520 	static struct {
521 		int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value);
522 	} map[] = {
523 		/* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */
524 		{ NULL          },
525 		{ parse_arg_int },
526 		{ parse_arg_u8  },
527 		{ parse_arg_u16 },
528 		{ parse_arg_u32 },
529 		{ parse_arg_u64 },
530 	};
531 	uint32_t index = arg_attr_val_type(arg);
532 	int ret = -EINVAL;
533 
534 	if (index > 0 && index < RTE_DIM(map))
535 		ret = map[index].f_parse_type(arg, value);
536 
537 	return ret;
538 }
539 
540 /* arg_parse indicates the name entered by the user, which can be long-name or short-name. */
541 static int
542 parse_arg_val(struct rte_argparse *obj, const char *arg_name,
543 	      struct rte_argparse_arg *arg, char *value)
544 {
545 	int ret;
546 
547 	if (arg->val_saver == NULL)
548 		ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque);
549 	else
550 		ret = parse_arg_autosave(arg, value);
551 	if (ret != 0) {
552 		ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg_name);
553 		return ret;
554 	}
555 
556 	return 0;
557 }
558 
559 static bool
560 is_help(const char *curr_argv)
561 {
562 	return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0;
563 }
564 
565 static int
566 parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help)
567 {
568 	uint32_t position_count = calc_position_count(obj);
569 	struct rte_argparse_arg *arg;
570 	uint32_t position_index = 0;
571 	const char *arg_name;
572 	char *curr_argv;
573 	char *has_equal;
574 	char *value;
575 	int ret;
576 	int i;
577 
578 	for (i = 1; i < argc; i++) {
579 		curr_argv = argv[i];
580 		if (curr_argv[0] != '-') {
581 			/* process positional parameters. */
582 			position_index++;
583 			if (position_index > position_count) {
584 				ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv);
585 				return -EINVAL;
586 			}
587 			arg = find_position_arg(obj, position_index);
588 			ret = parse_arg_val(obj, arg->name_long, arg, curr_argv);
589 			if (ret != 0)
590 				return ret;
591 			continue;
592 		}
593 
594 		/* process optional parameters. */
595 		if (is_help(curr_argv)) {
596 			*show_help = true;
597 			continue;
598 		}
599 
600 		has_equal = strchr(curr_argv, '=');
601 		arg_name = NULL;
602 		arg = find_option_arg(obj, curr_argv, has_equal, &arg_name);
603 		if (arg == NULL || arg_name == NULL) {
604 			ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv);
605 			return -EINVAL;
606 		}
607 
608 		if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) {
609 			ARGPARSE_LOG(ERR, "argument %s should not occur multiple!",
610 				     arg_name);
611 			return -EINVAL;
612 		}
613 
614 		value = (has_equal != NULL ? has_equal + 1 : NULL);
615 		if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) {
616 			if (value != NULL) {
617 				ARGPARSE_LOG(ERR, "argument %s should not take value!",
618 					     arg_name);
619 				return -EINVAL;
620 			}
621 		} else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) {
622 			if (value == NULL) {
623 				if (i >= argc - 1) {
624 					ARGPARSE_LOG(ERR, "argument %s doesn't have value!",
625 						     arg_name);
626 					return -EINVAL;
627 				}
628 				/* Set value and make i move next. */
629 				value = argv[++i];
630 			}
631 		} else {
632 			/* Do nothing, because it's optional value, only support arg=val or arg. */
633 		}
634 
635 		ret = parse_arg_val(obj, arg_name, arg, value);
636 		if (ret != 0)
637 			return ret;
638 
639 		/* This argument parsed success! then mark it parsed. */
640 		arg->flags |= ARG_ATTR_FLAG_PARSED_MASK;
641 	}
642 
643 	return 0;
644 }
645 
646 static uint32_t
647 calc_help_align(const struct rte_argparse *obj)
648 {
649 	const struct rte_argparse_arg *arg;
650 	uint32_t width = 12; /* Default "-h, --help  " len. */
651 	uint32_t len;
652 	uint32_t i;
653 
654 	for (i = 0; /* NULL */; i++) {
655 		arg = &obj->args[i];
656 		if (arg->name_long == NULL)
657 			break;
658 		len = strlen(arg->name_long);
659 		if (is_arg_optional(arg) && arg->name_short != NULL) {
660 			len += strlen(", ");
661 			len += strlen(arg->name_short);
662 		}
663 		width = RTE_MAX(width, 1 + len + 2); /* start with 1 & end with 2 space. */
664 	}
665 
666 	return width;
667 }
668 
669 static void
670 show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width)
671 {
672 	uint32_t len = 0;
673 	uint32_t i;
674 
675 	if (arg->name_short != NULL)
676 		len = printf(" %s,", arg->name_short);
677 	len += printf(" %s", arg->name_long);
678 
679 	for (i = len; i < width; i++)
680 		printf(" ");
681 
682 	printf("%s\n", arg->help);
683 }
684 
685 static void
686 show_args_pos_help(const struct rte_argparse *obj, uint32_t align)
687 {
688 	uint32_t position_count = calc_position_count(obj);
689 	const struct rte_argparse_arg *arg;
690 	uint32_t i;
691 
692 	if (position_count == 0)
693 		return;
694 
695 	printf("\npositional arguments:\n");
696 	for (i = 0; /* NULL */; i++) {
697 		arg = &obj->args[i];
698 		if (arg->name_long == NULL)
699 			break;
700 		if (!is_arg_positional(arg))
701 			continue;
702 		show_oneline_help(arg, align);
703 	}
704 }
705 
706 static void
707 show_args_opt_help(const struct rte_argparse *obj, uint32_t align)
708 {
709 	static const struct rte_argparse_arg help = {
710 		.name_long = "--help",
711 		.name_short = "-h",
712 		.help = "show this help message and exit.",
713 	};
714 	const struct rte_argparse_arg *arg;
715 	uint32_t i;
716 
717 	printf("\noptions:\n");
718 	show_oneline_help(&help, align);
719 	for (i = 0; /* NULL */; i++) {
720 		arg = &obj->args[i];
721 		if (arg->name_long == NULL)
722 			break;
723 		if (!is_arg_optional(arg))
724 			continue;
725 		show_oneline_help(arg, align);
726 	}
727 }
728 
729 static void
730 show_args_help(const struct rte_argparse *obj)
731 {
732 	uint32_t align = calc_help_align(obj);
733 
734 	printf("usage: %s %s\n", obj->prog_name, obj->usage);
735 	if (obj->descriptor != NULL)
736 		printf("\ndescriptor: %s\n", obj->descriptor);
737 
738 	show_args_pos_help(obj, align);
739 	show_args_opt_help(obj, align);
740 
741 	if (obj->epilog != NULL)
742 		printf("\n%s\n", obj->epilog);
743 	else
744 		printf("\n");
745 }
746 
747 int
748 rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv)
749 {
750 	bool show_help = false;
751 	int ret;
752 
753 	ret = verify_argparse(obj);
754 	if (ret != 0)
755 		goto error;
756 
757 	ret = parse_args(obj, argc, argv, &show_help);
758 	if (ret != 0)
759 		goto error;
760 
761 	if (show_help) {
762 		show_args_help(obj);
763 		exit(0);
764 	}
765 
766 	return 0;
767 
768 error:
769 	if (obj->exit_on_error)
770 		exit(ret);
771 	return ret;
772 }
773 
774 int
775 rte_argparse_parse_type(const char *str, uint64_t val_type, void *val)
776 {
777 	uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX);
778 	struct rte_argparse_arg arg = {
779 		.name_long = str,
780 		.name_short = NULL,
781 		.val_saver = val,
782 		.val_set = NULL,
783 		.flags = val_type,
784 	};
785 	uint32_t value_type = arg_attr_val_type(&arg);
786 
787 	if (value_type == 0 || value_type >= cmp_max)
788 		return -EINVAL;
789 
790 	return parse_arg_autosave(&arg, str);
791 }
792