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_FLAG_PARSED_MASK RTE_BIT64(63) 196c5c6571SChengwen Feng 206c5c6571SChengwen Feng static inline bool 216c5c6571SChengwen Feng is_arg_optional(const struct rte_argparse_arg *arg) 226c5c6571SChengwen Feng { 236c5c6571SChengwen Feng return arg->name_long[0] == '-'; 246c5c6571SChengwen Feng } 256c5c6571SChengwen Feng 266c5c6571SChengwen Feng static inline bool 276c5c6571SChengwen Feng is_arg_positional(const struct rte_argparse_arg *arg) 286c5c6571SChengwen Feng { 296c5c6571SChengwen Feng return arg->name_long[0] != '-'; 306c5c6571SChengwen Feng } 316c5c6571SChengwen Feng 326c5c6571SChengwen Feng static inline uint32_t 336c5c6571SChengwen Feng arg_attr_has_val(const struct rte_argparse_arg *arg) 346c5c6571SChengwen Feng { 35*f48e4eedSChengwen Feng return RTE_FIELD_GET64(RTE_ARGPARSE_HAS_VAL_BITMASK, arg->flags); 366c5c6571SChengwen Feng } 376c5c6571SChengwen Feng 386c5c6571SChengwen Feng static inline uint32_t 396c5c6571SChengwen Feng arg_attr_val_type(const struct rte_argparse_arg *arg) 406c5c6571SChengwen Feng { 41*f48e4eedSChengwen Feng return RTE_FIELD_GET64(RTE_ARGPARSE_VAL_TYPE_BITMASK, arg->flags); 426c5c6571SChengwen Feng } 436c5c6571SChengwen Feng 4431ed9f9fSChengwen Feng static inline bool 4531ed9f9fSChengwen Feng arg_attr_flag_multi(const struct rte_argparse_arg *arg) 4631ed9f9fSChengwen Feng { 47*f48e4eedSChengwen Feng return RTE_FIELD_GET64(RTE_ARGPARSE_ARG_SUPPORT_MULTI, arg->flags); 4831ed9f9fSChengwen Feng } 4931ed9f9fSChengwen Feng 50*f48e4eedSChengwen Feng static inline uint64_t 516c5c6571SChengwen Feng arg_attr_unused_bits(const struct rte_argparse_arg *arg) 526c5c6571SChengwen Feng { 53*f48e4eedSChengwen Feng #define USED_BIT_MASK (RTE_ARGPARSE_HAS_VAL_BITMASK | \ 54*f48e4eedSChengwen Feng RTE_ARGPARSE_VAL_TYPE_BITMASK | \ 55*f48e4eedSChengwen Feng RTE_ARGPARSE_ARG_SUPPORT_MULTI) 566c5c6571SChengwen Feng return arg->flags & ~USED_BIT_MASK; 576c5c6571SChengwen Feng } 586c5c6571SChengwen Feng 596c5c6571SChengwen Feng static int 606c5c6571SChengwen Feng verify_arg_name(const struct rte_argparse_arg *arg) 616c5c6571SChengwen Feng { 626c5c6571SChengwen Feng if (is_arg_optional(arg)) { 636c5c6571SChengwen Feng if (strlen(arg->name_long) <= 3) { 646c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long); 656c5c6571SChengwen Feng return -EINVAL; 666c5c6571SChengwen Feng } 676c5c6571SChengwen Feng if (arg->name_long[1] != '-') { 689b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s doesn't start with '--'", 696c5c6571SChengwen Feng arg->name_long); 706c5c6571SChengwen Feng return -EINVAL; 716c5c6571SChengwen Feng } 726c5c6571SChengwen Feng if (arg->name_long[2] == '-') { 736c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'", 746c5c6571SChengwen Feng arg->name_long); 756c5c6571SChengwen Feng return -EINVAL; 766c5c6571SChengwen Feng } 776c5c6571SChengwen Feng } 786c5c6571SChengwen Feng 796c5c6571SChengwen Feng if (arg->name_short == NULL) 806c5c6571SChengwen Feng return 0; 816c5c6571SChengwen Feng 826c5c6571SChengwen Feng if (!is_arg_optional(arg)) { 836c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!", 846c5c6571SChengwen Feng arg->name_short); 856c5c6571SChengwen Feng return -EINVAL; 866c5c6571SChengwen Feng } 876c5c6571SChengwen Feng 886c5c6571SChengwen Feng if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' || 896c5c6571SChengwen Feng arg->name_short[1] == '-') { 906c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter", 916c5c6571SChengwen Feng arg->name_short); 926c5c6571SChengwen Feng return -EINVAL; 936c5c6571SChengwen Feng } 946c5c6571SChengwen Feng 956c5c6571SChengwen Feng return 0; 966c5c6571SChengwen Feng } 976c5c6571SChengwen Feng 986c5c6571SChengwen Feng static int 996c5c6571SChengwen Feng verify_arg_help(const struct rte_argparse_arg *arg) 1006c5c6571SChengwen Feng { 1016c5c6571SChengwen Feng if (arg->help == NULL) { 1029b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s doesn't have help info!", arg->name_long); 1036c5c6571SChengwen Feng return -EINVAL; 1046c5c6571SChengwen Feng } 1056c5c6571SChengwen Feng 1066c5c6571SChengwen Feng return 0; 1076c5c6571SChengwen Feng } 1086c5c6571SChengwen Feng 1096c5c6571SChengwen Feng static int 1106c5c6571SChengwen Feng verify_arg_has_val(const struct rte_argparse_arg *arg) 1116c5c6571SChengwen Feng { 1126c5c6571SChengwen Feng uint32_t has_val = arg_attr_has_val(arg); 1136c5c6571SChengwen Feng 1146c5c6571SChengwen Feng if (is_arg_positional(arg)) { 1156c5c6571SChengwen Feng if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE) 1166c5c6571SChengwen Feng return 0; 1179b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s is positional, must config required-val!", 1186c5c6571SChengwen Feng arg->name_long); 1196c5c6571SChengwen Feng return -EINVAL; 1206c5c6571SChengwen Feng } 1216c5c6571SChengwen Feng 1226c5c6571SChengwen Feng if (has_val == 0) { 1239b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s is optional, has-value config wrong!", 1246c5c6571SChengwen Feng arg->name_long); 1256c5c6571SChengwen Feng return -EINVAL; 1266c5c6571SChengwen Feng } 1276c5c6571SChengwen Feng 1286c5c6571SChengwen Feng return 0; 1296c5c6571SChengwen Feng } 1306c5c6571SChengwen Feng 1316c5c6571SChengwen Feng static int 1326c5c6571SChengwen Feng verify_arg_saver(const struct rte_argparse *obj, uint32_t index) 1336c5c6571SChengwen Feng { 134*f48e4eedSChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(RTE_ARGPARSE_VAL_TYPE_BITMASK, 135*f48e4eedSChengwen Feng RTE_ARGPARSE_ARG_VALUE_MAX); 1366c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 1376c5c6571SChengwen Feng uint32_t val_type = arg_attr_val_type(arg); 1386c5c6571SChengwen Feng uint32_t has_val = arg_attr_has_val(arg); 1396c5c6571SChengwen Feng 1406c5c6571SChengwen Feng if (arg->val_saver == NULL) { 1416c5c6571SChengwen Feng if (val_type != 0) { 1429b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parsed by callback, value-type should not be set!", 1436c5c6571SChengwen Feng arg->name_long); 1446c5c6571SChengwen Feng return -EINVAL; 1456c5c6571SChengwen Feng } 1466c5c6571SChengwen Feng 1476c5c6571SChengwen Feng if (obj->callback == NULL) { 1489b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parsed by callback, but callback is NULL!", 1496c5c6571SChengwen Feng arg->name_long); 1506c5c6571SChengwen Feng return -EINVAL; 1516c5c6571SChengwen Feng } 1526c5c6571SChengwen Feng 1536c5c6571SChengwen Feng return 0; 1546c5c6571SChengwen Feng } 1556c5c6571SChengwen Feng 1566c5c6571SChengwen Feng if (val_type == 0 || val_type >= cmp_max) { 1579b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s value-type config wrong!", arg->name_long); 1586c5c6571SChengwen Feng return -EINVAL; 1596c5c6571SChengwen Feng } 1606c5c6571SChengwen Feng 1616c5c6571SChengwen Feng if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE && arg->val_set != NULL) { 1629b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s has required value, value-set should be NULL!", 1636c5c6571SChengwen Feng arg->name_long); 1646c5c6571SChengwen Feng return -EINVAL; 1656c5c6571SChengwen Feng } 1666c5c6571SChengwen Feng 1676c5c6571SChengwen Feng return 0; 1686c5c6571SChengwen Feng } 1696c5c6571SChengwen Feng 1706c5c6571SChengwen Feng static int 1716c5c6571SChengwen Feng verify_arg_flags(const struct rte_argparse *obj, uint32_t index) 1726c5c6571SChengwen Feng { 1736c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 174*f48e4eedSChengwen Feng uint64_t unused_bits = arg_attr_unused_bits(arg); 1756c5c6571SChengwen Feng 1766c5c6571SChengwen Feng if (unused_bits != 0) { 1779b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s flags unused bits should not be set!", 1789b8df29bSChengwen Feng 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) { 1929b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s supports multiple times, should use callback to parse!", 1936c5c6571SChengwen Feng arg->name_long); 1946c5c6571SChengwen Feng return -EINVAL; 1956c5c6571SChengwen Feng } 1966c5c6571SChengwen Feng 1976c5c6571SChengwen Feng return 0; 1986c5c6571SChengwen Feng } 1996c5c6571SChengwen Feng 2006c5c6571SChengwen Feng static int 2016c5c6571SChengwen Feng verify_arg_repeat(const struct rte_argparse *self, uint32_t index) 2026c5c6571SChengwen Feng { 2036c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &self->args[index]; 2046c5c6571SChengwen Feng uint32_t i; 2056c5c6571SChengwen Feng 2066c5c6571SChengwen Feng for (i = 0; i < index; i++) { 2076c5c6571SChengwen Feng if (!strcmp(arg->name_long, self->args[i].name_long)) { 2086c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long); 2096c5c6571SChengwen Feng return -EINVAL; 2106c5c6571SChengwen Feng } 2116c5c6571SChengwen Feng } 2126c5c6571SChengwen Feng 2136c5c6571SChengwen Feng if (arg->name_short == NULL) 2146c5c6571SChengwen Feng return 0; 2156c5c6571SChengwen Feng 2166c5c6571SChengwen Feng for (i = 0; i < index; i++) { 2176c5c6571SChengwen Feng if (self->args[i].name_short == NULL) 2186c5c6571SChengwen Feng continue; 2196c5c6571SChengwen Feng if (!strcmp(arg->name_short, self->args[i].name_short)) { 2206c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short); 2216c5c6571SChengwen Feng return -EINVAL; 2226c5c6571SChengwen Feng } 2236c5c6571SChengwen Feng } 2246c5c6571SChengwen Feng 2256c5c6571SChengwen Feng return 0; 2266c5c6571SChengwen Feng } 2276c5c6571SChengwen Feng 2286c5c6571SChengwen Feng static int 2296c5c6571SChengwen Feng verify_argparse_arg(const struct rte_argparse *obj, uint32_t index) 2306c5c6571SChengwen Feng { 2316c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 2326c5c6571SChengwen Feng int ret; 2336c5c6571SChengwen Feng 2346c5c6571SChengwen Feng ret = verify_arg_name(arg); 2356c5c6571SChengwen Feng if (ret != 0) 2366c5c6571SChengwen Feng return ret; 2376c5c6571SChengwen Feng 2386c5c6571SChengwen Feng ret = verify_arg_help(arg); 2396c5c6571SChengwen Feng if (ret != 0) 2406c5c6571SChengwen Feng return ret; 2416c5c6571SChengwen Feng 2426c5c6571SChengwen Feng ret = verify_arg_has_val(arg); 2436c5c6571SChengwen Feng if (ret != 0) 2446c5c6571SChengwen Feng return ret; 2456c5c6571SChengwen Feng 2466c5c6571SChengwen Feng ret = verify_arg_saver(obj, index); 2476c5c6571SChengwen Feng if (ret != 0) 2486c5c6571SChengwen Feng return ret; 2496c5c6571SChengwen Feng 2506c5c6571SChengwen Feng ret = verify_arg_flags(obj, index); 2516c5c6571SChengwen Feng if (ret != 0) 2526c5c6571SChengwen Feng return ret; 2536c5c6571SChengwen Feng 2546c5c6571SChengwen Feng ret = verify_arg_repeat(obj, index); 2556c5c6571SChengwen Feng if (ret != 0) 2566c5c6571SChengwen Feng return ret; 2576c5c6571SChengwen Feng 2586c5c6571SChengwen Feng return 0; 2596c5c6571SChengwen Feng } 2606c5c6571SChengwen Feng 2616c5c6571SChengwen Feng static int 2626c5c6571SChengwen Feng verify_argparse(const struct rte_argparse *obj) 2636c5c6571SChengwen Feng { 2646c5c6571SChengwen Feng uint32_t idx; 2656c5c6571SChengwen Feng int ret; 2666c5c6571SChengwen Feng 2676c5c6571SChengwen Feng if (obj->prog_name == NULL) { 2686c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "program name is NULL!"); 2696c5c6571SChengwen Feng return -EINVAL; 2706c5c6571SChengwen Feng } 2716c5c6571SChengwen Feng 2726c5c6571SChengwen Feng if (obj->usage == NULL) { 2736c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "usage is NULL!"); 2746c5c6571SChengwen Feng return -EINVAL; 2756c5c6571SChengwen Feng } 2766c5c6571SChengwen Feng 2776c5c6571SChengwen Feng for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) { 2786c5c6571SChengwen Feng if (obj->reserved[idx] != 0) { 2796c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "reserved field must be zero!"); 2806c5c6571SChengwen Feng return -EINVAL; 2816c5c6571SChengwen Feng } 2826c5c6571SChengwen Feng } 2836c5c6571SChengwen Feng 2846c5c6571SChengwen Feng idx = 0; 2856c5c6571SChengwen Feng while (obj->args[idx].name_long != NULL) { 2866c5c6571SChengwen Feng ret = verify_argparse_arg(obj, idx); 2876c5c6571SChengwen Feng if (ret != 0) 2886c5c6571SChengwen Feng return ret; 2896c5c6571SChengwen Feng idx++; 2906c5c6571SChengwen Feng } 2916c5c6571SChengwen Feng 2926c5c6571SChengwen Feng return 0; 2936c5c6571SChengwen Feng } 2946c5c6571SChengwen Feng 29531ed9f9fSChengwen Feng static uint32_t 29631ed9f9fSChengwen Feng calc_position_count(const struct rte_argparse *obj) 29731ed9f9fSChengwen Feng { 29831ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 29931ed9f9fSChengwen Feng uint32_t count = 0; 30031ed9f9fSChengwen Feng uint32_t i; 30131ed9f9fSChengwen Feng 30231ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 30331ed9f9fSChengwen Feng arg = &obj->args[i]; 30431ed9f9fSChengwen Feng if (obj->args[i].name_long == NULL) 30531ed9f9fSChengwen Feng break; 30631ed9f9fSChengwen Feng if (is_arg_positional(arg)) 30731ed9f9fSChengwen Feng count++; 30831ed9f9fSChengwen Feng } 30931ed9f9fSChengwen Feng 31031ed9f9fSChengwen Feng return count; 31131ed9f9fSChengwen Feng } 31231ed9f9fSChengwen Feng 31331ed9f9fSChengwen Feng static struct rte_argparse_arg * 31431ed9f9fSChengwen Feng find_position_arg(struct rte_argparse *obj, uint32_t index) 31531ed9f9fSChengwen Feng { 31631ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 31731ed9f9fSChengwen Feng uint32_t count = 0; 31831ed9f9fSChengwen Feng uint32_t i; 31931ed9f9fSChengwen Feng 32031ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 32131ed9f9fSChengwen Feng arg = &obj->args[i]; 32231ed9f9fSChengwen Feng if (arg->name_long == NULL) 32331ed9f9fSChengwen Feng break; 32431ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 32531ed9f9fSChengwen Feng continue; 32631ed9f9fSChengwen Feng count++; 32731ed9f9fSChengwen Feng if (count == index) 32831ed9f9fSChengwen Feng return arg; 32931ed9f9fSChengwen Feng } 33031ed9f9fSChengwen Feng 33131ed9f9fSChengwen Feng return NULL; 33231ed9f9fSChengwen Feng } 33331ed9f9fSChengwen Feng 33431ed9f9fSChengwen Feng static bool 33531ed9f9fSChengwen Feng is_arg_match(struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len) 33631ed9f9fSChengwen Feng { 33731ed9f9fSChengwen Feng if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0) 33831ed9f9fSChengwen Feng return true; 33931ed9f9fSChengwen Feng 34031ed9f9fSChengwen Feng if (arg->name_short == NULL) 34131ed9f9fSChengwen Feng return false; 34231ed9f9fSChengwen Feng 34331ed9f9fSChengwen Feng if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0) 34431ed9f9fSChengwen Feng return true; 34531ed9f9fSChengwen Feng 34631ed9f9fSChengwen Feng return false; 34731ed9f9fSChengwen Feng } 34831ed9f9fSChengwen Feng 34931ed9f9fSChengwen Feng static struct rte_argparse_arg * 35031ed9f9fSChengwen Feng find_option_arg(struct rte_argparse *obj, const char *curr_argv, const char *has_equal, 35131ed9f9fSChengwen Feng const char **arg_name) 35231ed9f9fSChengwen Feng { 35331ed9f9fSChengwen Feng uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0); 35431ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 35531ed9f9fSChengwen Feng uint32_t i; 35631ed9f9fSChengwen Feng bool match; 35731ed9f9fSChengwen Feng 35831ed9f9fSChengwen Feng for (i = 0; /* nothing */; i++) { 35931ed9f9fSChengwen Feng arg = &obj->args[i]; 36031ed9f9fSChengwen Feng if (arg->name_long == NULL) 36131ed9f9fSChengwen Feng break; 36231ed9f9fSChengwen Feng match = is_arg_match(arg, curr_argv, len); 36331ed9f9fSChengwen Feng if (match) { 36431ed9f9fSChengwen Feng /* Obtains the exact matching name (long or short). */ 36531ed9f9fSChengwen Feng *arg_name = len > 2 ? arg->name_long : arg->name_short; 36631ed9f9fSChengwen Feng return arg; 36731ed9f9fSChengwen Feng } 36831ed9f9fSChengwen Feng } 36931ed9f9fSChengwen Feng 37031ed9f9fSChengwen Feng return NULL; 37131ed9f9fSChengwen Feng } 37231ed9f9fSChengwen Feng 37331ed9f9fSChengwen Feng static int 37431ed9f9fSChengwen Feng parse_arg_int(struct rte_argparse_arg *arg, const char *value) 37531ed9f9fSChengwen Feng { 37631ed9f9fSChengwen Feng char *s = NULL; 37731ed9f9fSChengwen Feng 37831ed9f9fSChengwen Feng if (value == NULL) { 37931ed9f9fSChengwen Feng *(int *)arg->val_saver = (int)(intptr_t)arg->val_set; 38031ed9f9fSChengwen Feng return 0; 38131ed9f9fSChengwen Feng } 38231ed9f9fSChengwen Feng 38331ed9f9fSChengwen Feng errno = 0; 38431ed9f9fSChengwen Feng *(int *)arg->val_saver = strtol(value, &s, 0); 38531ed9f9fSChengwen Feng if (errno == ERANGE) { 38631ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 38731ed9f9fSChengwen Feng return -EINVAL; 38831ed9f9fSChengwen Feng } 38931ed9f9fSChengwen Feng 39031ed9f9fSChengwen Feng if (s[0] != '\0') { 39131ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long); 39231ed9f9fSChengwen Feng return -EINVAL; 39331ed9f9fSChengwen Feng } 39431ed9f9fSChengwen Feng 39531ed9f9fSChengwen Feng return 0; 39631ed9f9fSChengwen Feng } 39731ed9f9fSChengwen Feng 39831ed9f9fSChengwen Feng static int 3995357c248SChengwen Feng parse_arg_u8(struct rte_argparse_arg *arg, const char *value) 4005357c248SChengwen Feng { 4015357c248SChengwen Feng unsigned long val; 4025357c248SChengwen Feng char *s = NULL; 4035357c248SChengwen Feng 4045357c248SChengwen Feng if (value == NULL) { 4055357c248SChengwen Feng *(uint8_t *)arg->val_saver = (uint8_t)(intptr_t)arg->val_set; 4065357c248SChengwen Feng return 0; 4075357c248SChengwen Feng } 4085357c248SChengwen Feng 4095357c248SChengwen Feng errno = 0; 4105357c248SChengwen Feng val = strtoul(value, &s, 0); 4115357c248SChengwen Feng if (errno == ERANGE || val > UINT8_MAX) { 4125357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4135357c248SChengwen Feng return -EINVAL; 4145357c248SChengwen Feng } 4155357c248SChengwen Feng 4165357c248SChengwen Feng if (s[0] != '\0') { 4175357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint8 value!", arg->name_long); 4185357c248SChengwen Feng return -EINVAL; 4195357c248SChengwen Feng } 4205357c248SChengwen Feng 4215357c248SChengwen Feng *(uint8_t *)arg->val_saver = val; 4225357c248SChengwen Feng 4235357c248SChengwen Feng return 0; 4245357c248SChengwen Feng } 4255357c248SChengwen Feng 4265357c248SChengwen Feng static int 4275357c248SChengwen Feng parse_arg_u16(struct rte_argparse_arg *arg, const char *value) 4285357c248SChengwen Feng { 4295357c248SChengwen Feng unsigned long val; 4305357c248SChengwen Feng char *s = NULL; 4315357c248SChengwen Feng 4325357c248SChengwen Feng if (value == NULL) { 4335357c248SChengwen Feng *(uint16_t *)arg->val_saver = (uint16_t)(intptr_t)arg->val_set; 4345357c248SChengwen Feng return 0; 4355357c248SChengwen Feng } 4365357c248SChengwen Feng 4375357c248SChengwen Feng errno = 0; 4385357c248SChengwen Feng val = strtoul(value, &s, 0); 4395357c248SChengwen Feng if (errno == ERANGE || val > UINT16_MAX) { 4405357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4415357c248SChengwen Feng return -EINVAL; 4425357c248SChengwen Feng } 4435357c248SChengwen Feng 4445357c248SChengwen Feng if (s[0] != '\0') { 4455357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint16 value!", arg->name_long); 4465357c248SChengwen Feng return -EINVAL; 4475357c248SChengwen Feng } 4485357c248SChengwen Feng 4495357c248SChengwen Feng *(uint16_t *)arg->val_saver = val; 4505357c248SChengwen Feng 4515357c248SChengwen Feng return 0; 4525357c248SChengwen Feng } 4535357c248SChengwen Feng 4545357c248SChengwen Feng static int 4555357c248SChengwen Feng parse_arg_u32(struct rte_argparse_arg *arg, const char *value) 4565357c248SChengwen Feng { 4575357c248SChengwen Feng unsigned long val; 4585357c248SChengwen Feng char *s = NULL; 4595357c248SChengwen Feng 4605357c248SChengwen Feng if (value == NULL) { 4615357c248SChengwen Feng *(uint32_t *)arg->val_saver = (uint32_t)(intptr_t)arg->val_set; 4625357c248SChengwen Feng return 0; 4635357c248SChengwen Feng } 4645357c248SChengwen Feng 4655357c248SChengwen Feng errno = 0; 4665357c248SChengwen Feng val = strtoul(value, &s, 0); 4675357c248SChengwen Feng if (errno == ERANGE || val > UINT32_MAX) { 4685357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4695357c248SChengwen Feng return -EINVAL; 4705357c248SChengwen Feng } 4715357c248SChengwen Feng 4725357c248SChengwen Feng if (s[0] != '\0') { 4735357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint32 value!", arg->name_long); 4745357c248SChengwen Feng return -EINVAL; 4755357c248SChengwen Feng } 4765357c248SChengwen Feng 4775357c248SChengwen Feng *(uint32_t *)arg->val_saver = val; 4785357c248SChengwen Feng 4795357c248SChengwen Feng return 0; 4805357c248SChengwen Feng } 4815357c248SChengwen Feng 4825357c248SChengwen Feng static int 4835357c248SChengwen Feng parse_arg_u64(struct rte_argparse_arg *arg, const char *value) 4845357c248SChengwen Feng { 4855357c248SChengwen Feng unsigned long val; 4865357c248SChengwen Feng char *s = NULL; 4875357c248SChengwen Feng 4885357c248SChengwen Feng if (value == NULL) { 4895357c248SChengwen Feng *(uint64_t *)arg->val_saver = (uint64_t)(intptr_t)arg->val_set; 4905357c248SChengwen Feng return 0; 4915357c248SChengwen Feng } 4925357c248SChengwen Feng 4935357c248SChengwen Feng errno = 0; 4945357c248SChengwen Feng val = strtoull(value, &s, 0); 4955357c248SChengwen Feng if (errno == ERANGE) { 4965357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4975357c248SChengwen Feng return -EINVAL; 4985357c248SChengwen Feng } 4995357c248SChengwen Feng 5005357c248SChengwen Feng if (s[0] != '\0') { 5015357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint64 value!", arg->name_long); 5025357c248SChengwen Feng return -EINVAL; 5035357c248SChengwen Feng } 5045357c248SChengwen Feng 5055357c248SChengwen Feng *(uint64_t *)arg->val_saver = val; 5065357c248SChengwen Feng 5075357c248SChengwen Feng return 0; 5085357c248SChengwen Feng } 5095357c248SChengwen Feng 5105357c248SChengwen Feng static int 51131ed9f9fSChengwen Feng parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) 51231ed9f9fSChengwen Feng { 51331ed9f9fSChengwen Feng static struct { 51431ed9f9fSChengwen Feng int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value); 51531ed9f9fSChengwen Feng } map[] = { 51631ed9f9fSChengwen Feng /* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */ 51731ed9f9fSChengwen Feng { NULL }, 51831ed9f9fSChengwen Feng { parse_arg_int }, 5195357c248SChengwen Feng { parse_arg_u8 }, 5205357c248SChengwen Feng { parse_arg_u16 }, 5215357c248SChengwen Feng { parse_arg_u32 }, 5225357c248SChengwen Feng { parse_arg_u64 }, 52331ed9f9fSChengwen Feng }; 52431ed9f9fSChengwen Feng uint32_t index = arg_attr_val_type(arg); 52531ed9f9fSChengwen Feng int ret = -EINVAL; 52631ed9f9fSChengwen Feng 52731ed9f9fSChengwen Feng if (index > 0 && index < RTE_DIM(map)) 52831ed9f9fSChengwen Feng ret = map[index].f_parse_type(arg, value); 52931ed9f9fSChengwen Feng 53031ed9f9fSChengwen Feng return ret; 53131ed9f9fSChengwen Feng } 53231ed9f9fSChengwen Feng 5339b8df29bSChengwen Feng /* arg_parse indicates the name entered by the user, which can be long-name or short-name. */ 53431ed9f9fSChengwen Feng static int 5359b8df29bSChengwen Feng parse_arg_val(struct rte_argparse *obj, const char *arg_name, 5369b8df29bSChengwen Feng struct rte_argparse_arg *arg, char *value) 537e3e579f5SChengwen Feng { 5386c5c6571SChengwen Feng int ret; 5396c5c6571SChengwen Feng 54031ed9f9fSChengwen Feng if (arg->val_saver == NULL) 54131ed9f9fSChengwen Feng ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque); 54231ed9f9fSChengwen Feng else 54331ed9f9fSChengwen Feng ret = parse_arg_autosave(arg, value); 54431ed9f9fSChengwen Feng if (ret != 0) { 5459b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg_name); 54631ed9f9fSChengwen Feng return ret; 54731ed9f9fSChengwen Feng } 54831ed9f9fSChengwen Feng 54931ed9f9fSChengwen Feng return 0; 55031ed9f9fSChengwen Feng } 55131ed9f9fSChengwen Feng 55231ed9f9fSChengwen Feng static bool 55331ed9f9fSChengwen Feng is_help(const char *curr_argv) 55431ed9f9fSChengwen Feng { 55531ed9f9fSChengwen Feng return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0; 55631ed9f9fSChengwen Feng } 55731ed9f9fSChengwen Feng 55831ed9f9fSChengwen Feng static int 55931ed9f9fSChengwen Feng parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help) 56031ed9f9fSChengwen Feng { 56131ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 56231ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 56331ed9f9fSChengwen Feng uint32_t position_index = 0; 56431ed9f9fSChengwen Feng const char *arg_name; 56531ed9f9fSChengwen Feng char *curr_argv; 56631ed9f9fSChengwen Feng char *has_equal; 56731ed9f9fSChengwen Feng char *value; 56831ed9f9fSChengwen Feng int ret; 56931ed9f9fSChengwen Feng int i; 57031ed9f9fSChengwen Feng 57131ed9f9fSChengwen Feng for (i = 1; i < argc; i++) { 57231ed9f9fSChengwen Feng curr_argv = argv[i]; 57331ed9f9fSChengwen Feng if (curr_argv[0] != '-') { 57431ed9f9fSChengwen Feng /* process positional parameters. */ 57531ed9f9fSChengwen Feng position_index++; 57631ed9f9fSChengwen Feng if (position_index > position_count) { 57731ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv); 57831ed9f9fSChengwen Feng return -EINVAL; 57931ed9f9fSChengwen Feng } 58031ed9f9fSChengwen Feng arg = find_position_arg(obj, position_index); 5819b8df29bSChengwen Feng ret = parse_arg_val(obj, arg->name_long, arg, curr_argv); 58231ed9f9fSChengwen Feng if (ret != 0) 58331ed9f9fSChengwen Feng return ret; 58431ed9f9fSChengwen Feng continue; 58531ed9f9fSChengwen Feng } 58631ed9f9fSChengwen Feng 58731ed9f9fSChengwen Feng /* process optional parameters. */ 58831ed9f9fSChengwen Feng if (is_help(curr_argv)) { 58931ed9f9fSChengwen Feng *show_help = true; 59031ed9f9fSChengwen Feng continue; 59131ed9f9fSChengwen Feng } 59231ed9f9fSChengwen Feng 59331ed9f9fSChengwen Feng has_equal = strchr(curr_argv, '='); 59431ed9f9fSChengwen Feng arg_name = NULL; 59531ed9f9fSChengwen Feng arg = find_option_arg(obj, curr_argv, has_equal, &arg_name); 59631ed9f9fSChengwen Feng if (arg == NULL || arg_name == NULL) { 59731ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv); 59831ed9f9fSChengwen Feng return -EINVAL; 59931ed9f9fSChengwen Feng } 60031ed9f9fSChengwen Feng 60131ed9f9fSChengwen Feng if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) { 60231ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not occur multiple!", 60331ed9f9fSChengwen Feng arg_name); 60431ed9f9fSChengwen Feng return -EINVAL; 60531ed9f9fSChengwen Feng } 60631ed9f9fSChengwen Feng 60731ed9f9fSChengwen Feng value = (has_equal != NULL ? has_equal + 1 : NULL); 60831ed9f9fSChengwen Feng if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) { 60931ed9f9fSChengwen Feng if (value != NULL) { 61031ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not take value!", 61131ed9f9fSChengwen Feng arg_name); 61231ed9f9fSChengwen Feng return -EINVAL; 61331ed9f9fSChengwen Feng } 61431ed9f9fSChengwen Feng } else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) { 61531ed9f9fSChengwen Feng if (value == NULL) { 61631ed9f9fSChengwen Feng if (i >= argc - 1) { 61731ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s doesn't have value!", 61831ed9f9fSChengwen Feng arg_name); 61931ed9f9fSChengwen Feng return -EINVAL; 62031ed9f9fSChengwen Feng } 62131ed9f9fSChengwen Feng /* Set value and make i move next. */ 62231ed9f9fSChengwen Feng value = argv[++i]; 62331ed9f9fSChengwen Feng } 62431ed9f9fSChengwen Feng } else { 62531ed9f9fSChengwen Feng /* Do nothing, because it's optional value, only support arg=val or arg. */ 62631ed9f9fSChengwen Feng } 62731ed9f9fSChengwen Feng 6289b8df29bSChengwen Feng ret = parse_arg_val(obj, arg_name, arg, value); 62931ed9f9fSChengwen Feng if (ret != 0) 63031ed9f9fSChengwen Feng return ret; 63131ed9f9fSChengwen Feng 63231ed9f9fSChengwen Feng /* This argument parsed success! then mark it parsed. */ 63331ed9f9fSChengwen Feng arg->flags |= ARG_ATTR_FLAG_PARSED_MASK; 63431ed9f9fSChengwen Feng } 63531ed9f9fSChengwen Feng 63631ed9f9fSChengwen Feng return 0; 63731ed9f9fSChengwen Feng } 63831ed9f9fSChengwen Feng 639676ca0d2SChengwen Feng static uint32_t 640676ca0d2SChengwen Feng calc_help_align(const struct rte_argparse *obj) 641676ca0d2SChengwen Feng { 642676ca0d2SChengwen Feng const struct rte_argparse_arg *arg; 643676ca0d2SChengwen Feng uint32_t width = 12; /* Default "-h, --help " len. */ 644676ca0d2SChengwen Feng uint32_t len; 645676ca0d2SChengwen Feng uint32_t i; 646676ca0d2SChengwen Feng 647676ca0d2SChengwen Feng for (i = 0; /* NULL */; i++) { 648676ca0d2SChengwen Feng arg = &obj->args[i]; 649676ca0d2SChengwen Feng if (arg->name_long == NULL) 650676ca0d2SChengwen Feng break; 651676ca0d2SChengwen Feng len = strlen(arg->name_long); 652676ca0d2SChengwen Feng if (is_arg_optional(arg) && arg->name_short != NULL) { 653676ca0d2SChengwen Feng len += strlen(", "); 654676ca0d2SChengwen Feng len += strlen(arg->name_short); 655676ca0d2SChengwen Feng } 656676ca0d2SChengwen Feng width = RTE_MAX(width, 1 + len + 2); /* start with 1 & end with 2 space. */ 657676ca0d2SChengwen Feng } 658676ca0d2SChengwen Feng 659676ca0d2SChengwen Feng return width; 660676ca0d2SChengwen Feng } 661676ca0d2SChengwen Feng 66231ed9f9fSChengwen Feng static void 663676ca0d2SChengwen Feng show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width) 664676ca0d2SChengwen Feng { 665676ca0d2SChengwen Feng uint32_t len = 0; 666676ca0d2SChengwen Feng uint32_t i; 667676ca0d2SChengwen Feng 668676ca0d2SChengwen Feng if (arg->name_short != NULL) 669676ca0d2SChengwen Feng len = printf(" %s,", arg->name_short); 670676ca0d2SChengwen Feng len += printf(" %s", arg->name_long); 671676ca0d2SChengwen Feng 672676ca0d2SChengwen Feng for (i = len; i < width; i++) 673676ca0d2SChengwen Feng printf(" "); 674676ca0d2SChengwen Feng 675676ca0d2SChengwen Feng printf("%s\n", arg->help); 676676ca0d2SChengwen Feng } 677676ca0d2SChengwen Feng 678676ca0d2SChengwen Feng static void 679676ca0d2SChengwen Feng show_args_pos_help(const struct rte_argparse *obj, uint32_t align) 68031ed9f9fSChengwen Feng { 68131ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 68231ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 68331ed9f9fSChengwen Feng uint32_t i; 68431ed9f9fSChengwen Feng 68531ed9f9fSChengwen Feng if (position_count == 0) 68631ed9f9fSChengwen Feng return; 68731ed9f9fSChengwen Feng 68831ed9f9fSChengwen Feng printf("\npositional arguments:\n"); 68931ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 69031ed9f9fSChengwen Feng arg = &obj->args[i]; 69131ed9f9fSChengwen Feng if (arg->name_long == NULL) 69231ed9f9fSChengwen Feng break; 69331ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 69431ed9f9fSChengwen Feng continue; 695676ca0d2SChengwen Feng show_oneline_help(arg, align); 69631ed9f9fSChengwen Feng } 69731ed9f9fSChengwen Feng } 69831ed9f9fSChengwen Feng 69931ed9f9fSChengwen Feng static void 700676ca0d2SChengwen Feng show_args_opt_help(const struct rte_argparse *obj, uint32_t align) 70131ed9f9fSChengwen Feng { 702676ca0d2SChengwen Feng static const struct rte_argparse_arg help = { 703676ca0d2SChengwen Feng .name_long = "--help", 704676ca0d2SChengwen Feng .name_short = "-h", 705676ca0d2SChengwen Feng .help = "show this help message and exit.", 706676ca0d2SChengwen Feng }; 70731ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 70831ed9f9fSChengwen Feng uint32_t i; 70931ed9f9fSChengwen Feng 710676ca0d2SChengwen Feng printf("\noptions:\n"); 711676ca0d2SChengwen Feng show_oneline_help(&help, align); 71231ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 71331ed9f9fSChengwen Feng arg = &obj->args[i]; 71431ed9f9fSChengwen Feng if (arg->name_long == NULL) 71531ed9f9fSChengwen Feng break; 71631ed9f9fSChengwen Feng if (!is_arg_optional(arg)) 71731ed9f9fSChengwen Feng continue; 718676ca0d2SChengwen Feng show_oneline_help(arg, align); 71931ed9f9fSChengwen Feng } 72031ed9f9fSChengwen Feng } 72131ed9f9fSChengwen Feng 72231ed9f9fSChengwen Feng static void 72331ed9f9fSChengwen Feng show_args_help(const struct rte_argparse *obj) 72431ed9f9fSChengwen Feng { 725676ca0d2SChengwen Feng uint32_t align = calc_help_align(obj); 726676ca0d2SChengwen Feng 72731ed9f9fSChengwen Feng printf("usage: %s %s\n", obj->prog_name, obj->usage); 72831ed9f9fSChengwen Feng if (obj->descriptor != NULL) 72931ed9f9fSChengwen Feng printf("\ndescriptor: %s\n", obj->descriptor); 73031ed9f9fSChengwen Feng 731676ca0d2SChengwen Feng show_args_pos_help(obj, align); 732676ca0d2SChengwen Feng show_args_opt_help(obj, align); 73331ed9f9fSChengwen Feng 73431ed9f9fSChengwen Feng if (obj->epilog != NULL) 73531ed9f9fSChengwen Feng printf("\n%s\n", obj->epilog); 736676ca0d2SChengwen Feng else 737676ca0d2SChengwen Feng printf("\n"); 73831ed9f9fSChengwen Feng } 73931ed9f9fSChengwen Feng 74031ed9f9fSChengwen Feng int 74131ed9f9fSChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) 74231ed9f9fSChengwen Feng { 74331ed9f9fSChengwen Feng bool show_help = false; 74431ed9f9fSChengwen Feng int ret; 7456c5c6571SChengwen Feng 7466c5c6571SChengwen Feng ret = verify_argparse(obj); 7476c5c6571SChengwen Feng if (ret != 0) 7486c5c6571SChengwen Feng goto error; 7496c5c6571SChengwen Feng 75031ed9f9fSChengwen Feng ret = parse_args(obj, argc, argv, &show_help); 75131ed9f9fSChengwen Feng if (ret != 0) 75231ed9f9fSChengwen Feng goto error; 75331ed9f9fSChengwen Feng 75431ed9f9fSChengwen Feng if (show_help) { 75531ed9f9fSChengwen Feng show_args_help(obj); 75631ed9f9fSChengwen Feng exit(0); 75731ed9f9fSChengwen Feng } 75831ed9f9fSChengwen Feng 759e3e579f5SChengwen Feng return 0; 7606c5c6571SChengwen Feng 7616c5c6571SChengwen Feng error: 7626c5c6571SChengwen Feng if (obj->exit_on_error) 7636c5c6571SChengwen Feng exit(ret); 7646c5c6571SChengwen Feng return ret; 765e3e579f5SChengwen Feng } 7669ccd7b27SChengwen Feng 7679ccd7b27SChengwen Feng int 7689ccd7b27SChengwen Feng rte_argparse_parse_type(const char *str, uint64_t val_type, void *val) 7699ccd7b27SChengwen Feng { 770*f48e4eedSChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(RTE_ARGPARSE_VAL_TYPE_BITMASK, 771*f48e4eedSChengwen Feng RTE_ARGPARSE_ARG_VALUE_MAX); 7729ccd7b27SChengwen Feng struct rte_argparse_arg arg = { 7739ccd7b27SChengwen Feng .name_long = str, 7749ccd7b27SChengwen Feng .name_short = NULL, 7759ccd7b27SChengwen Feng .val_saver = val, 7769ccd7b27SChengwen Feng .val_set = NULL, 7779ccd7b27SChengwen Feng .flags = val_type, 7789ccd7b27SChengwen Feng }; 7799ccd7b27SChengwen Feng uint32_t value_type = arg_attr_val_type(&arg); 7809ccd7b27SChengwen Feng 7819ccd7b27SChengwen Feng if (value_type == 0 || value_type >= cmp_max) 7829ccd7b27SChengwen Feng return -EINVAL; 7839ccd7b27SChengwen Feng 7849ccd7b27SChengwen Feng return parse_arg_autosave(&arg, str); 7859ccd7b27SChengwen Feng } 786