1e3e579f5SChengwen Feng /* SPDX-License-Identifier: BSD-3-Clause 2e3e579f5SChengwen Feng * Copyright(c) 2024 HiSilicon Limited 3e3e579f5SChengwen Feng */ 4e3e579f5SChengwen Feng 56c5c6571SChengwen Feng #include <errno.h> 66c5c6571SChengwen Feng #include <stdlib.h> 76c5c6571SChengwen Feng #include <string.h> 86c5c6571SChengwen Feng 96c5c6571SChengwen Feng #include <rte_log.h> 106c5c6571SChengwen Feng 11e3e579f5SChengwen Feng #include "rte_argparse.h" 12e3e579f5SChengwen Feng 136c5c6571SChengwen Feng RTE_LOG_REGISTER_DEFAULT(rte_argparse_logtype, INFO); 146c5c6571SChengwen Feng #define RTE_LOGTYPE_ARGPARSE rte_argparse_logtype 156c5c6571SChengwen Feng #define ARGPARSE_LOG(level, ...) \ 166c5c6571SChengwen Feng RTE_LOG_LINE(level, ARGPARSE, "" __VA_ARGS__) 176c5c6571SChengwen Feng 186c5c6571SChengwen Feng #define ARG_ATTR_HAS_VAL_MASK RTE_GENMASK64(1, 0) 196c5c6571SChengwen Feng #define ARG_ATTR_VAL_TYPE_MASK RTE_GENMASK64(9, 2) 206c5c6571SChengwen Feng #define ARG_ATTR_SUPPORT_MULTI_MASK RTE_BIT64(10) 216c5c6571SChengwen Feng #define ARG_ATTR_FLAG_PARSED_MASK RTE_BIT64(63) 226c5c6571SChengwen Feng 236c5c6571SChengwen Feng static inline bool 246c5c6571SChengwen Feng is_arg_optional(const struct rte_argparse_arg *arg) 256c5c6571SChengwen Feng { 266c5c6571SChengwen Feng return arg->name_long[0] == '-'; 276c5c6571SChengwen Feng } 286c5c6571SChengwen Feng 296c5c6571SChengwen Feng static inline bool 306c5c6571SChengwen Feng is_arg_positional(const struct rte_argparse_arg *arg) 316c5c6571SChengwen Feng { 326c5c6571SChengwen Feng return arg->name_long[0] != '-'; 336c5c6571SChengwen Feng } 346c5c6571SChengwen Feng 356c5c6571SChengwen Feng static inline uint32_t 366c5c6571SChengwen Feng arg_attr_has_val(const struct rte_argparse_arg *arg) 376c5c6571SChengwen Feng { 386c5c6571SChengwen Feng return RTE_FIELD_GET64(ARG_ATTR_HAS_VAL_MASK, arg->flags); 396c5c6571SChengwen Feng } 406c5c6571SChengwen Feng 416c5c6571SChengwen Feng static inline uint32_t 426c5c6571SChengwen Feng arg_attr_val_type(const struct rte_argparse_arg *arg) 436c5c6571SChengwen Feng { 446c5c6571SChengwen Feng return RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, arg->flags); 456c5c6571SChengwen Feng } 466c5c6571SChengwen Feng 4731ed9f9fSChengwen Feng static inline bool 4831ed9f9fSChengwen Feng arg_attr_flag_multi(const struct rte_argparse_arg *arg) 4931ed9f9fSChengwen Feng { 5031ed9f9fSChengwen Feng return RTE_FIELD_GET64(ARG_ATTR_SUPPORT_MULTI_MASK, arg->flags); 5131ed9f9fSChengwen Feng } 5231ed9f9fSChengwen Feng 536c5c6571SChengwen Feng static inline uint32_t 546c5c6571SChengwen Feng arg_attr_unused_bits(const struct rte_argparse_arg *arg) 556c5c6571SChengwen Feng { 566c5c6571SChengwen Feng #define USED_BIT_MASK (ARG_ATTR_HAS_VAL_MASK | ARG_ATTR_VAL_TYPE_MASK | \ 576c5c6571SChengwen Feng ARG_ATTR_SUPPORT_MULTI_MASK) 586c5c6571SChengwen Feng return arg->flags & ~USED_BIT_MASK; 596c5c6571SChengwen Feng } 606c5c6571SChengwen Feng 616c5c6571SChengwen Feng static int 626c5c6571SChengwen Feng verify_arg_name(const struct rte_argparse_arg *arg) 636c5c6571SChengwen Feng { 646c5c6571SChengwen Feng if (is_arg_optional(arg)) { 656c5c6571SChengwen Feng if (strlen(arg->name_long) <= 3) { 666c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long); 676c5c6571SChengwen Feng return -EINVAL; 686c5c6571SChengwen Feng } 696c5c6571SChengwen Feng if (arg->name_long[1] != '-') { 706c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s must only start with '--'", 716c5c6571SChengwen Feng arg->name_long); 726c5c6571SChengwen Feng return -EINVAL; 736c5c6571SChengwen Feng } 746c5c6571SChengwen Feng if (arg->name_long[2] == '-') { 756c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'", 766c5c6571SChengwen Feng arg->name_long); 776c5c6571SChengwen Feng return -EINVAL; 786c5c6571SChengwen Feng } 796c5c6571SChengwen Feng } 806c5c6571SChengwen Feng 816c5c6571SChengwen Feng if (arg->name_short == NULL) 826c5c6571SChengwen Feng return 0; 836c5c6571SChengwen Feng 846c5c6571SChengwen Feng if (!is_arg_optional(arg)) { 856c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!", 866c5c6571SChengwen Feng arg->name_short); 876c5c6571SChengwen Feng return -EINVAL; 886c5c6571SChengwen Feng } 896c5c6571SChengwen Feng 906c5c6571SChengwen Feng if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' || 916c5c6571SChengwen Feng arg->name_short[1] == '-') { 926c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter", 936c5c6571SChengwen Feng arg->name_short); 946c5c6571SChengwen Feng return -EINVAL; 956c5c6571SChengwen Feng } 966c5c6571SChengwen Feng 976c5c6571SChengwen Feng return 0; 986c5c6571SChengwen Feng } 996c5c6571SChengwen Feng 1006c5c6571SChengwen Feng static int 1016c5c6571SChengwen Feng verify_arg_help(const struct rte_argparse_arg *arg) 1026c5c6571SChengwen Feng { 1036c5c6571SChengwen Feng if (arg->help == NULL) { 1046c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s must have help info!", arg->name_long); 1056c5c6571SChengwen Feng return -EINVAL; 1066c5c6571SChengwen Feng } 1076c5c6571SChengwen Feng 1086c5c6571SChengwen Feng return 0; 1096c5c6571SChengwen Feng } 1106c5c6571SChengwen Feng 1116c5c6571SChengwen Feng static int 1126c5c6571SChengwen Feng verify_arg_has_val(const struct rte_argparse_arg *arg) 1136c5c6571SChengwen Feng { 1146c5c6571SChengwen Feng uint32_t has_val = arg_attr_has_val(arg); 1156c5c6571SChengwen Feng 1166c5c6571SChengwen Feng if (is_arg_positional(arg)) { 1176c5c6571SChengwen Feng if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE) 1186c5c6571SChengwen Feng return 0; 1196c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s is positional, should has zero or required-val!", 1206c5c6571SChengwen Feng arg->name_long); 1216c5c6571SChengwen Feng return -EINVAL; 1226c5c6571SChengwen Feng } 1236c5c6571SChengwen Feng 1246c5c6571SChengwen Feng if (has_val == 0) { 1256c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s is optional, has-val config wrong!", 1266c5c6571SChengwen Feng arg->name_long); 1276c5c6571SChengwen Feng return -EINVAL; 1286c5c6571SChengwen Feng } 1296c5c6571SChengwen Feng 1306c5c6571SChengwen Feng return 0; 1316c5c6571SChengwen Feng } 1326c5c6571SChengwen Feng 1336c5c6571SChengwen Feng static int 1346c5c6571SChengwen Feng verify_arg_saver(const struct rte_argparse *obj, uint32_t index) 1356c5c6571SChengwen Feng { 1366c5c6571SChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); 1376c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 1386c5c6571SChengwen Feng uint32_t val_type = arg_attr_val_type(arg); 1396c5c6571SChengwen Feng uint32_t has_val = arg_attr_has_val(arg); 1406c5c6571SChengwen Feng 1416c5c6571SChengwen Feng if (arg->val_saver == NULL) { 1426c5c6571SChengwen Feng if (val_type != 0) { 1436c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse by callback, val-type must be zero!", 1446c5c6571SChengwen Feng arg->name_long); 1456c5c6571SChengwen Feng return -EINVAL; 1466c5c6571SChengwen Feng } 1476c5c6571SChengwen Feng 1486c5c6571SChengwen Feng if (obj->callback == NULL) { 1496c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse by callback, but callback is NULL!", 1506c5c6571SChengwen Feng arg->name_long); 1516c5c6571SChengwen Feng return -EINVAL; 1526c5c6571SChengwen Feng } 1536c5c6571SChengwen Feng 1546c5c6571SChengwen Feng return 0; 1556c5c6571SChengwen Feng } 1566c5c6571SChengwen Feng 1576c5c6571SChengwen Feng if (val_type == 0 || val_type >= cmp_max) { 1586c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s val-type config wrong!", arg->name_long); 1596c5c6571SChengwen Feng return -EINVAL; 1606c5c6571SChengwen Feng } 1616c5c6571SChengwen Feng 1626c5c6571SChengwen Feng if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE && arg->val_set != NULL) { 1636c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s has required value, val-set should be NULL!", 1646c5c6571SChengwen Feng arg->name_long); 1656c5c6571SChengwen Feng return -EINVAL; 1666c5c6571SChengwen Feng } 1676c5c6571SChengwen Feng 1686c5c6571SChengwen Feng return 0; 1696c5c6571SChengwen Feng } 1706c5c6571SChengwen Feng 1716c5c6571SChengwen Feng static int 1726c5c6571SChengwen Feng verify_arg_flags(const struct rte_argparse *obj, uint32_t index) 1736c5c6571SChengwen Feng { 1746c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 1756c5c6571SChengwen Feng uint32_t unused_bits = arg_attr_unused_bits(arg); 1766c5c6571SChengwen Feng 1776c5c6571SChengwen Feng if (unused_bits != 0) { 1786c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s flags set wrong!", arg->name_long); 1796c5c6571SChengwen Feng return -EINVAL; 1806c5c6571SChengwen Feng } 1816c5c6571SChengwen Feng 1826c5c6571SChengwen Feng if (!(arg->flags & RTE_ARGPARSE_ARG_SUPPORT_MULTI)) 1836c5c6571SChengwen Feng return 0; 1846c5c6571SChengwen Feng 1856c5c6571SChengwen Feng if (is_arg_positional(arg)) { 1866c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!", 1876c5c6571SChengwen Feng arg->name_long); 1886c5c6571SChengwen Feng return -EINVAL; 1896c5c6571SChengwen Feng } 1906c5c6571SChengwen Feng 1916c5c6571SChengwen Feng if (arg->val_saver != NULL) { 1926c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s could occur multiple times, should use callback to parse!", 1936c5c6571SChengwen Feng arg->name_long); 1946c5c6571SChengwen Feng return -EINVAL; 1956c5c6571SChengwen Feng } 1966c5c6571SChengwen Feng 1976c5c6571SChengwen Feng if (obj->callback == NULL) { 1986c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s should use callback to parse, but callback is NULL!", 1996c5c6571SChengwen Feng arg->name_long); 2006c5c6571SChengwen Feng return -EINVAL; 2016c5c6571SChengwen Feng } 2026c5c6571SChengwen Feng 2036c5c6571SChengwen Feng return 0; 2046c5c6571SChengwen Feng } 2056c5c6571SChengwen Feng 2066c5c6571SChengwen Feng static int 2076c5c6571SChengwen Feng verify_arg_repeat(const struct rte_argparse *self, uint32_t index) 2086c5c6571SChengwen Feng { 2096c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &self->args[index]; 2106c5c6571SChengwen Feng uint32_t i; 2116c5c6571SChengwen Feng 2126c5c6571SChengwen Feng for (i = 0; i < index; i++) { 2136c5c6571SChengwen Feng if (!strcmp(arg->name_long, self->args[i].name_long)) { 2146c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long); 2156c5c6571SChengwen Feng return -EINVAL; 2166c5c6571SChengwen Feng } 2176c5c6571SChengwen Feng } 2186c5c6571SChengwen Feng 2196c5c6571SChengwen Feng if (arg->name_short == NULL) 2206c5c6571SChengwen Feng return 0; 2216c5c6571SChengwen Feng 2226c5c6571SChengwen Feng for (i = 0; i < index; i++) { 2236c5c6571SChengwen Feng if (self->args[i].name_short == NULL) 2246c5c6571SChengwen Feng continue; 2256c5c6571SChengwen Feng if (!strcmp(arg->name_short, self->args[i].name_short)) { 2266c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short); 2276c5c6571SChengwen Feng return -EINVAL; 2286c5c6571SChengwen Feng } 2296c5c6571SChengwen Feng } 2306c5c6571SChengwen Feng 2316c5c6571SChengwen Feng return 0; 2326c5c6571SChengwen Feng } 2336c5c6571SChengwen Feng 2346c5c6571SChengwen Feng static int 2356c5c6571SChengwen Feng verify_argparse_arg(const struct rte_argparse *obj, uint32_t index) 2366c5c6571SChengwen Feng { 2376c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 2386c5c6571SChengwen Feng int ret; 2396c5c6571SChengwen Feng 2406c5c6571SChengwen Feng ret = verify_arg_name(arg); 2416c5c6571SChengwen Feng if (ret != 0) 2426c5c6571SChengwen Feng return ret; 2436c5c6571SChengwen Feng 2446c5c6571SChengwen Feng ret = verify_arg_help(arg); 2456c5c6571SChengwen Feng if (ret != 0) 2466c5c6571SChengwen Feng return ret; 2476c5c6571SChengwen Feng 2486c5c6571SChengwen Feng ret = verify_arg_has_val(arg); 2496c5c6571SChengwen Feng if (ret != 0) 2506c5c6571SChengwen Feng return ret; 2516c5c6571SChengwen Feng 2526c5c6571SChengwen Feng ret = verify_arg_saver(obj, index); 2536c5c6571SChengwen Feng if (ret != 0) 2546c5c6571SChengwen Feng return ret; 2556c5c6571SChengwen Feng 2566c5c6571SChengwen Feng ret = verify_arg_flags(obj, index); 2576c5c6571SChengwen Feng if (ret != 0) 2586c5c6571SChengwen Feng return ret; 2596c5c6571SChengwen Feng 2606c5c6571SChengwen Feng ret = verify_arg_repeat(obj, index); 2616c5c6571SChengwen Feng if (ret != 0) 2626c5c6571SChengwen Feng return ret; 2636c5c6571SChengwen Feng 2646c5c6571SChengwen Feng return 0; 2656c5c6571SChengwen Feng } 2666c5c6571SChengwen Feng 2676c5c6571SChengwen Feng static int 2686c5c6571SChengwen Feng verify_argparse(const struct rte_argparse *obj) 2696c5c6571SChengwen Feng { 2706c5c6571SChengwen Feng uint32_t idx; 2716c5c6571SChengwen Feng int ret; 2726c5c6571SChengwen Feng 2736c5c6571SChengwen Feng if (obj->prog_name == NULL) { 2746c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "program name is NULL!"); 2756c5c6571SChengwen Feng return -EINVAL; 2766c5c6571SChengwen Feng } 2776c5c6571SChengwen Feng 2786c5c6571SChengwen Feng if (obj->usage == NULL) { 2796c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "usage is NULL!"); 2806c5c6571SChengwen Feng return -EINVAL; 2816c5c6571SChengwen Feng } 2826c5c6571SChengwen Feng 2836c5c6571SChengwen Feng for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) { 2846c5c6571SChengwen Feng if (obj->reserved[idx] != 0) { 2856c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "reserved field must be zero!"); 2866c5c6571SChengwen Feng return -EINVAL; 2876c5c6571SChengwen Feng } 2886c5c6571SChengwen Feng } 2896c5c6571SChengwen Feng 2906c5c6571SChengwen Feng idx = 0; 2916c5c6571SChengwen Feng while (obj->args[idx].name_long != NULL) { 2926c5c6571SChengwen Feng ret = verify_argparse_arg(obj, idx); 2936c5c6571SChengwen Feng if (ret != 0) 2946c5c6571SChengwen Feng return ret; 2956c5c6571SChengwen Feng idx++; 2966c5c6571SChengwen Feng } 2976c5c6571SChengwen Feng 2986c5c6571SChengwen Feng return 0; 2996c5c6571SChengwen Feng } 3006c5c6571SChengwen Feng 30131ed9f9fSChengwen Feng static uint32_t 30231ed9f9fSChengwen Feng calc_position_count(const struct rte_argparse *obj) 30331ed9f9fSChengwen Feng { 30431ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 30531ed9f9fSChengwen Feng uint32_t count = 0; 30631ed9f9fSChengwen Feng uint32_t i; 30731ed9f9fSChengwen Feng 30831ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 30931ed9f9fSChengwen Feng arg = &obj->args[i]; 31031ed9f9fSChengwen Feng if (obj->args[i].name_long == NULL) 31131ed9f9fSChengwen Feng break; 31231ed9f9fSChengwen Feng if (is_arg_positional(arg)) 31331ed9f9fSChengwen Feng count++; 31431ed9f9fSChengwen Feng } 31531ed9f9fSChengwen Feng 31631ed9f9fSChengwen Feng return count; 31731ed9f9fSChengwen Feng } 31831ed9f9fSChengwen Feng 31931ed9f9fSChengwen Feng static struct rte_argparse_arg * 32031ed9f9fSChengwen Feng find_position_arg(struct rte_argparse *obj, uint32_t index) 32131ed9f9fSChengwen Feng { 32231ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 32331ed9f9fSChengwen Feng uint32_t count = 0; 32431ed9f9fSChengwen Feng uint32_t i; 32531ed9f9fSChengwen Feng 32631ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 32731ed9f9fSChengwen Feng arg = &obj->args[i]; 32831ed9f9fSChengwen Feng if (arg->name_long == NULL) 32931ed9f9fSChengwen Feng break; 33031ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 33131ed9f9fSChengwen Feng continue; 33231ed9f9fSChengwen Feng count++; 33331ed9f9fSChengwen Feng if (count == index) 33431ed9f9fSChengwen Feng return arg; 33531ed9f9fSChengwen Feng } 33631ed9f9fSChengwen Feng 33731ed9f9fSChengwen Feng return NULL; 33831ed9f9fSChengwen Feng } 33931ed9f9fSChengwen Feng 34031ed9f9fSChengwen Feng static bool 34131ed9f9fSChengwen Feng is_arg_match(struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len) 34231ed9f9fSChengwen Feng { 34331ed9f9fSChengwen Feng if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0) 34431ed9f9fSChengwen Feng return true; 34531ed9f9fSChengwen Feng 34631ed9f9fSChengwen Feng if (arg->name_short == NULL) 34731ed9f9fSChengwen Feng return false; 34831ed9f9fSChengwen Feng 34931ed9f9fSChengwen Feng if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0) 35031ed9f9fSChengwen Feng return true; 35131ed9f9fSChengwen Feng 35231ed9f9fSChengwen Feng return false; 35331ed9f9fSChengwen Feng } 35431ed9f9fSChengwen Feng 35531ed9f9fSChengwen Feng static struct rte_argparse_arg * 35631ed9f9fSChengwen Feng find_option_arg(struct rte_argparse *obj, const char *curr_argv, const char *has_equal, 35731ed9f9fSChengwen Feng const char **arg_name) 35831ed9f9fSChengwen Feng { 35931ed9f9fSChengwen Feng uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0); 36031ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 36131ed9f9fSChengwen Feng uint32_t i; 36231ed9f9fSChengwen Feng bool match; 36331ed9f9fSChengwen Feng 36431ed9f9fSChengwen Feng for (i = 0; /* nothing */; i++) { 36531ed9f9fSChengwen Feng arg = &obj->args[i]; 36631ed9f9fSChengwen Feng if (arg->name_long == NULL) 36731ed9f9fSChengwen Feng break; 36831ed9f9fSChengwen Feng match = is_arg_match(arg, curr_argv, len); 36931ed9f9fSChengwen Feng if (match) { 37031ed9f9fSChengwen Feng /* Obtains the exact matching name (long or short). */ 37131ed9f9fSChengwen Feng *arg_name = len > 2 ? arg->name_long : arg->name_short; 37231ed9f9fSChengwen Feng return arg; 37331ed9f9fSChengwen Feng } 37431ed9f9fSChengwen Feng } 37531ed9f9fSChengwen Feng 37631ed9f9fSChengwen Feng return NULL; 37731ed9f9fSChengwen Feng } 37831ed9f9fSChengwen Feng 37931ed9f9fSChengwen Feng static int 38031ed9f9fSChengwen Feng parse_arg_int(struct rte_argparse_arg *arg, const char *value) 38131ed9f9fSChengwen Feng { 38231ed9f9fSChengwen Feng char *s = NULL; 38331ed9f9fSChengwen Feng 38431ed9f9fSChengwen Feng if (value == NULL) { 38531ed9f9fSChengwen Feng *(int *)arg->val_saver = (int)(intptr_t)arg->val_set; 38631ed9f9fSChengwen Feng return 0; 38731ed9f9fSChengwen Feng } 38831ed9f9fSChengwen Feng 38931ed9f9fSChengwen Feng errno = 0; 39031ed9f9fSChengwen Feng *(int *)arg->val_saver = strtol(value, &s, 0); 39131ed9f9fSChengwen Feng if (errno == ERANGE) { 39231ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 39331ed9f9fSChengwen Feng return -EINVAL; 39431ed9f9fSChengwen Feng } 39531ed9f9fSChengwen Feng 39631ed9f9fSChengwen Feng if (s[0] != '\0') { 39731ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long); 39831ed9f9fSChengwen Feng return -EINVAL; 39931ed9f9fSChengwen Feng } 40031ed9f9fSChengwen Feng 40131ed9f9fSChengwen Feng return 0; 40231ed9f9fSChengwen Feng } 40331ed9f9fSChengwen Feng 40431ed9f9fSChengwen Feng static int 40531ed9f9fSChengwen Feng parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) 40631ed9f9fSChengwen Feng { 40731ed9f9fSChengwen Feng static struct { 40831ed9f9fSChengwen Feng int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value); 40931ed9f9fSChengwen Feng } map[] = { 41031ed9f9fSChengwen Feng /* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */ 41131ed9f9fSChengwen Feng { NULL }, 41231ed9f9fSChengwen Feng { parse_arg_int }, 41331ed9f9fSChengwen Feng }; 41431ed9f9fSChengwen Feng uint32_t index = arg_attr_val_type(arg); 41531ed9f9fSChengwen Feng int ret = -EINVAL; 41631ed9f9fSChengwen Feng 41731ed9f9fSChengwen Feng if (index > 0 && index < RTE_DIM(map)) 41831ed9f9fSChengwen Feng ret = map[index].f_parse_type(arg, value); 41931ed9f9fSChengwen Feng 42031ed9f9fSChengwen Feng return ret; 42131ed9f9fSChengwen Feng } 42231ed9f9fSChengwen Feng 42331ed9f9fSChengwen Feng static int 42431ed9f9fSChengwen Feng parse_arg_val(struct rte_argparse *obj, struct rte_argparse_arg *arg, char *value) 425e3e579f5SChengwen Feng { 4266c5c6571SChengwen Feng int ret; 4276c5c6571SChengwen Feng 42831ed9f9fSChengwen Feng if (arg->val_saver == NULL) 42931ed9f9fSChengwen Feng ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque); 43031ed9f9fSChengwen Feng else 43131ed9f9fSChengwen Feng ret = parse_arg_autosave(arg, value); 43231ed9f9fSChengwen Feng if (ret != 0) { 43331ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg->name_long); 43431ed9f9fSChengwen Feng return ret; 43531ed9f9fSChengwen Feng } 43631ed9f9fSChengwen Feng 43731ed9f9fSChengwen Feng return 0; 43831ed9f9fSChengwen Feng } 43931ed9f9fSChengwen Feng 44031ed9f9fSChengwen Feng static bool 44131ed9f9fSChengwen Feng is_help(const char *curr_argv) 44231ed9f9fSChengwen Feng { 44331ed9f9fSChengwen Feng return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0; 44431ed9f9fSChengwen Feng } 44531ed9f9fSChengwen Feng 44631ed9f9fSChengwen Feng static int 44731ed9f9fSChengwen Feng parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help) 44831ed9f9fSChengwen Feng { 44931ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 45031ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 45131ed9f9fSChengwen Feng uint32_t position_index = 0; 45231ed9f9fSChengwen Feng const char *arg_name; 45331ed9f9fSChengwen Feng char *curr_argv; 45431ed9f9fSChengwen Feng char *has_equal; 45531ed9f9fSChengwen Feng char *value; 45631ed9f9fSChengwen Feng int ret; 45731ed9f9fSChengwen Feng int i; 45831ed9f9fSChengwen Feng 45931ed9f9fSChengwen Feng for (i = 1; i < argc; i++) { 46031ed9f9fSChengwen Feng curr_argv = argv[i]; 46131ed9f9fSChengwen Feng if (curr_argv[0] != '-') { 46231ed9f9fSChengwen Feng /* process positional parameters. */ 46331ed9f9fSChengwen Feng position_index++; 46431ed9f9fSChengwen Feng if (position_index > position_count) { 46531ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv); 46631ed9f9fSChengwen Feng return -EINVAL; 46731ed9f9fSChengwen Feng } 46831ed9f9fSChengwen Feng arg = find_position_arg(obj, position_index); 46931ed9f9fSChengwen Feng ret = parse_arg_val(obj, arg, curr_argv); 47031ed9f9fSChengwen Feng if (ret != 0) 47131ed9f9fSChengwen Feng return ret; 47231ed9f9fSChengwen Feng continue; 47331ed9f9fSChengwen Feng } 47431ed9f9fSChengwen Feng 47531ed9f9fSChengwen Feng /* process optional parameters. */ 47631ed9f9fSChengwen Feng if (is_help(curr_argv)) { 47731ed9f9fSChengwen Feng *show_help = true; 47831ed9f9fSChengwen Feng continue; 47931ed9f9fSChengwen Feng } 48031ed9f9fSChengwen Feng 48131ed9f9fSChengwen Feng has_equal = strchr(curr_argv, '='); 48231ed9f9fSChengwen Feng arg_name = NULL; 48331ed9f9fSChengwen Feng arg = find_option_arg(obj, curr_argv, has_equal, &arg_name); 48431ed9f9fSChengwen Feng if (arg == NULL || arg_name == NULL) { 48531ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv); 48631ed9f9fSChengwen Feng return -EINVAL; 48731ed9f9fSChengwen Feng } 48831ed9f9fSChengwen Feng 48931ed9f9fSChengwen Feng if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) { 49031ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not occur multiple!", 49131ed9f9fSChengwen Feng arg_name); 49231ed9f9fSChengwen Feng return -EINVAL; 49331ed9f9fSChengwen Feng } 49431ed9f9fSChengwen Feng 49531ed9f9fSChengwen Feng value = (has_equal != NULL ? has_equal + 1 : NULL); 49631ed9f9fSChengwen Feng if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) { 49731ed9f9fSChengwen Feng if (value != NULL) { 49831ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not take value!", 49931ed9f9fSChengwen Feng arg_name); 50031ed9f9fSChengwen Feng return -EINVAL; 50131ed9f9fSChengwen Feng } 50231ed9f9fSChengwen Feng } else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) { 50331ed9f9fSChengwen Feng if (value == NULL) { 50431ed9f9fSChengwen Feng if (i >= argc - 1) { 50531ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s doesn't have value!", 50631ed9f9fSChengwen Feng arg_name); 50731ed9f9fSChengwen Feng return -EINVAL; 50831ed9f9fSChengwen Feng } 50931ed9f9fSChengwen Feng /* Set value and make i move next. */ 51031ed9f9fSChengwen Feng value = argv[++i]; 51131ed9f9fSChengwen Feng } 51231ed9f9fSChengwen Feng } else { 51331ed9f9fSChengwen Feng /* Do nothing, because it's optional value, only support arg=val or arg. */ 51431ed9f9fSChengwen Feng } 51531ed9f9fSChengwen Feng 51631ed9f9fSChengwen Feng ret = parse_arg_val(obj, arg, value); 51731ed9f9fSChengwen Feng if (ret != 0) 51831ed9f9fSChengwen Feng return ret; 51931ed9f9fSChengwen Feng 52031ed9f9fSChengwen Feng /* This argument parsed success! then mark it parsed. */ 52131ed9f9fSChengwen Feng arg->flags |= ARG_ATTR_FLAG_PARSED_MASK; 52231ed9f9fSChengwen Feng } 52331ed9f9fSChengwen Feng 52431ed9f9fSChengwen Feng return 0; 52531ed9f9fSChengwen Feng } 52631ed9f9fSChengwen Feng 52731ed9f9fSChengwen Feng static void 52831ed9f9fSChengwen Feng show_args_pos_help(const struct rte_argparse *obj) 52931ed9f9fSChengwen Feng { 53031ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 53131ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 53231ed9f9fSChengwen Feng uint32_t i; 53331ed9f9fSChengwen Feng 53431ed9f9fSChengwen Feng if (position_count == 0) 53531ed9f9fSChengwen Feng return; 53631ed9f9fSChengwen Feng 53731ed9f9fSChengwen Feng printf("\npositional arguments:\n"); 53831ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 53931ed9f9fSChengwen Feng arg = &obj->args[i]; 54031ed9f9fSChengwen Feng if (arg->name_long == NULL) 54131ed9f9fSChengwen Feng break; 54231ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 54331ed9f9fSChengwen Feng continue; 54431ed9f9fSChengwen Feng printf(" %s: %s\n", arg->name_long, arg->help); 54531ed9f9fSChengwen Feng } 54631ed9f9fSChengwen Feng } 54731ed9f9fSChengwen Feng 54831ed9f9fSChengwen Feng static void 54931ed9f9fSChengwen Feng show_args_opt_help(const struct rte_argparse *obj) 55031ed9f9fSChengwen Feng { 55131ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 55231ed9f9fSChengwen Feng uint32_t i; 55331ed9f9fSChengwen Feng 55431ed9f9fSChengwen Feng printf("\noptions:\n" 55531ed9f9fSChengwen Feng " -h, --help: show this help message and exit.\n"); 55631ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 55731ed9f9fSChengwen Feng arg = &obj->args[i]; 55831ed9f9fSChengwen Feng if (arg->name_long == NULL) 55931ed9f9fSChengwen Feng break; 56031ed9f9fSChengwen Feng if (!is_arg_optional(arg)) 56131ed9f9fSChengwen Feng continue; 56231ed9f9fSChengwen Feng if (arg->name_short != NULL) 56331ed9f9fSChengwen Feng printf(" %s, %s: %s\n", arg->name_short, arg->name_long, arg->help); 56431ed9f9fSChengwen Feng else 56531ed9f9fSChengwen Feng printf(" %s: %s\n", arg->name_long, arg->help); 56631ed9f9fSChengwen Feng } 56731ed9f9fSChengwen Feng } 56831ed9f9fSChengwen Feng 56931ed9f9fSChengwen Feng static void 57031ed9f9fSChengwen Feng show_args_help(const struct rte_argparse *obj) 57131ed9f9fSChengwen Feng { 57231ed9f9fSChengwen Feng printf("usage: %s %s\n", obj->prog_name, obj->usage); 57331ed9f9fSChengwen Feng if (obj->descriptor != NULL) 57431ed9f9fSChengwen Feng printf("\ndescriptor: %s\n", obj->descriptor); 57531ed9f9fSChengwen Feng 57631ed9f9fSChengwen Feng show_args_pos_help(obj); 57731ed9f9fSChengwen Feng show_args_opt_help(obj); 57831ed9f9fSChengwen Feng 57931ed9f9fSChengwen Feng if (obj->epilog != NULL) 58031ed9f9fSChengwen Feng printf("\n%s\n", obj->epilog); 58131ed9f9fSChengwen Feng } 58231ed9f9fSChengwen Feng 58331ed9f9fSChengwen Feng int 58431ed9f9fSChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) 58531ed9f9fSChengwen Feng { 58631ed9f9fSChengwen Feng bool show_help = false; 58731ed9f9fSChengwen Feng int ret; 5886c5c6571SChengwen Feng 5896c5c6571SChengwen Feng ret = verify_argparse(obj); 5906c5c6571SChengwen Feng if (ret != 0) 5916c5c6571SChengwen Feng goto error; 5926c5c6571SChengwen Feng 59331ed9f9fSChengwen Feng ret = parse_args(obj, argc, argv, &show_help); 59431ed9f9fSChengwen Feng if (ret != 0) 59531ed9f9fSChengwen Feng goto error; 59631ed9f9fSChengwen Feng 59731ed9f9fSChengwen Feng if (show_help) { 59831ed9f9fSChengwen Feng show_args_help(obj); 59931ed9f9fSChengwen Feng exit(0); 60031ed9f9fSChengwen Feng } 60131ed9f9fSChengwen Feng 602e3e579f5SChengwen Feng return 0; 6036c5c6571SChengwen Feng 6046c5c6571SChengwen Feng error: 6056c5c6571SChengwen Feng if (obj->exit_on_error) 6066c5c6571SChengwen Feng exit(ret); 6076c5c6571SChengwen Feng return ret; 608e3e579f5SChengwen Feng } 609*9ccd7b27SChengwen Feng 610*9ccd7b27SChengwen Feng int 611*9ccd7b27SChengwen Feng rte_argparse_parse_type(const char *str, uint64_t val_type, void *val) 612*9ccd7b27SChengwen Feng { 613*9ccd7b27SChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); 614*9ccd7b27SChengwen Feng struct rte_argparse_arg arg = { 615*9ccd7b27SChengwen Feng .name_long = str, 616*9ccd7b27SChengwen Feng .name_short = NULL, 617*9ccd7b27SChengwen Feng .val_saver = val, 618*9ccd7b27SChengwen Feng .val_set = NULL, 619*9ccd7b27SChengwen Feng .flags = val_type, 620*9ccd7b27SChengwen Feng }; 621*9ccd7b27SChengwen Feng uint32_t value_type = arg_attr_val_type(&arg); 622*9ccd7b27SChengwen Feng 623*9ccd7b27SChengwen Feng if (value_type == 0 || value_type >= cmp_max) 624*9ccd7b27SChengwen Feng return -EINVAL; 625*9ccd7b27SChengwen Feng 626*9ccd7b27SChengwen Feng return parse_arg_autosave(&arg, str); 627*9ccd7b27SChengwen Feng } 628