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