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 405*5357c248SChengwen Feng parse_arg_u8(struct rte_argparse_arg *arg, const char *value) 406*5357c248SChengwen Feng { 407*5357c248SChengwen Feng unsigned long val; 408*5357c248SChengwen Feng char *s = NULL; 409*5357c248SChengwen Feng 410*5357c248SChengwen Feng if (value == NULL) { 411*5357c248SChengwen Feng *(uint8_t *)arg->val_saver = (uint8_t)(intptr_t)arg->val_set; 412*5357c248SChengwen Feng return 0; 413*5357c248SChengwen Feng } 414*5357c248SChengwen Feng 415*5357c248SChengwen Feng errno = 0; 416*5357c248SChengwen Feng val = strtoul(value, &s, 0); 417*5357c248SChengwen Feng if (errno == ERANGE || val > UINT8_MAX) { 418*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 419*5357c248SChengwen Feng return -EINVAL; 420*5357c248SChengwen Feng } 421*5357c248SChengwen Feng 422*5357c248SChengwen Feng if (s[0] != '\0') { 423*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint8 value!", arg->name_long); 424*5357c248SChengwen Feng return -EINVAL; 425*5357c248SChengwen Feng } 426*5357c248SChengwen Feng 427*5357c248SChengwen Feng *(uint8_t *)arg->val_saver = val; 428*5357c248SChengwen Feng 429*5357c248SChengwen Feng return 0; 430*5357c248SChengwen Feng } 431*5357c248SChengwen Feng 432*5357c248SChengwen Feng static int 433*5357c248SChengwen Feng parse_arg_u16(struct rte_argparse_arg *arg, const char *value) 434*5357c248SChengwen Feng { 435*5357c248SChengwen Feng unsigned long val; 436*5357c248SChengwen Feng char *s = NULL; 437*5357c248SChengwen Feng 438*5357c248SChengwen Feng if (value == NULL) { 439*5357c248SChengwen Feng *(uint16_t *)arg->val_saver = (uint16_t)(intptr_t)arg->val_set; 440*5357c248SChengwen Feng return 0; 441*5357c248SChengwen Feng } 442*5357c248SChengwen Feng 443*5357c248SChengwen Feng errno = 0; 444*5357c248SChengwen Feng val = strtoul(value, &s, 0); 445*5357c248SChengwen Feng if (errno == ERANGE || val > UINT16_MAX) { 446*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 447*5357c248SChengwen Feng return -EINVAL; 448*5357c248SChengwen Feng } 449*5357c248SChengwen Feng 450*5357c248SChengwen Feng if (s[0] != '\0') { 451*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint16 value!", arg->name_long); 452*5357c248SChengwen Feng return -EINVAL; 453*5357c248SChengwen Feng } 454*5357c248SChengwen Feng 455*5357c248SChengwen Feng *(uint16_t *)arg->val_saver = val; 456*5357c248SChengwen Feng 457*5357c248SChengwen Feng return 0; 458*5357c248SChengwen Feng } 459*5357c248SChengwen Feng 460*5357c248SChengwen Feng static int 461*5357c248SChengwen Feng parse_arg_u32(struct rte_argparse_arg *arg, const char *value) 462*5357c248SChengwen Feng { 463*5357c248SChengwen Feng unsigned long val; 464*5357c248SChengwen Feng char *s = NULL; 465*5357c248SChengwen Feng 466*5357c248SChengwen Feng if (value == NULL) { 467*5357c248SChengwen Feng *(uint32_t *)arg->val_saver = (uint32_t)(intptr_t)arg->val_set; 468*5357c248SChengwen Feng return 0; 469*5357c248SChengwen Feng } 470*5357c248SChengwen Feng 471*5357c248SChengwen Feng errno = 0; 472*5357c248SChengwen Feng val = strtoul(value, &s, 0); 473*5357c248SChengwen Feng if (errno == ERANGE || val > UINT32_MAX) { 474*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 475*5357c248SChengwen Feng return -EINVAL; 476*5357c248SChengwen Feng } 477*5357c248SChengwen Feng 478*5357c248SChengwen Feng if (s[0] != '\0') { 479*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint32 value!", arg->name_long); 480*5357c248SChengwen Feng return -EINVAL; 481*5357c248SChengwen Feng } 482*5357c248SChengwen Feng 483*5357c248SChengwen Feng *(uint32_t *)arg->val_saver = val; 484*5357c248SChengwen Feng 485*5357c248SChengwen Feng return 0; 486*5357c248SChengwen Feng } 487*5357c248SChengwen Feng 488*5357c248SChengwen Feng static int 489*5357c248SChengwen Feng parse_arg_u64(struct rte_argparse_arg *arg, const char *value) 490*5357c248SChengwen Feng { 491*5357c248SChengwen Feng unsigned long val; 492*5357c248SChengwen Feng char *s = NULL; 493*5357c248SChengwen Feng 494*5357c248SChengwen Feng if (value == NULL) { 495*5357c248SChengwen Feng *(uint64_t *)arg->val_saver = (uint64_t)(intptr_t)arg->val_set; 496*5357c248SChengwen Feng return 0; 497*5357c248SChengwen Feng } 498*5357c248SChengwen Feng 499*5357c248SChengwen Feng errno = 0; 500*5357c248SChengwen Feng val = strtoull(value, &s, 0); 501*5357c248SChengwen Feng if (errno == ERANGE) { 502*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 503*5357c248SChengwen Feng return -EINVAL; 504*5357c248SChengwen Feng } 505*5357c248SChengwen Feng 506*5357c248SChengwen Feng if (s[0] != '\0') { 507*5357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint64 value!", arg->name_long); 508*5357c248SChengwen Feng return -EINVAL; 509*5357c248SChengwen Feng } 510*5357c248SChengwen Feng 511*5357c248SChengwen Feng *(uint64_t *)arg->val_saver = val; 512*5357c248SChengwen Feng 513*5357c248SChengwen Feng return 0; 514*5357c248SChengwen Feng } 515*5357c248SChengwen Feng 516*5357c248SChengwen Feng static int 51731ed9f9fSChengwen Feng parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) 51831ed9f9fSChengwen Feng { 51931ed9f9fSChengwen Feng static struct { 52031ed9f9fSChengwen Feng int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value); 52131ed9f9fSChengwen Feng } map[] = { 52231ed9f9fSChengwen Feng /* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */ 52331ed9f9fSChengwen Feng { NULL }, 52431ed9f9fSChengwen Feng { parse_arg_int }, 525*5357c248SChengwen Feng { parse_arg_u8 }, 526*5357c248SChengwen Feng { parse_arg_u16 }, 527*5357c248SChengwen Feng { parse_arg_u32 }, 528*5357c248SChengwen Feng { parse_arg_u64 }, 52931ed9f9fSChengwen Feng }; 53031ed9f9fSChengwen Feng uint32_t index = arg_attr_val_type(arg); 53131ed9f9fSChengwen Feng int ret = -EINVAL; 53231ed9f9fSChengwen Feng 53331ed9f9fSChengwen Feng if (index > 0 && index < RTE_DIM(map)) 53431ed9f9fSChengwen Feng ret = map[index].f_parse_type(arg, value); 53531ed9f9fSChengwen Feng 53631ed9f9fSChengwen Feng return ret; 53731ed9f9fSChengwen Feng } 53831ed9f9fSChengwen Feng 53931ed9f9fSChengwen Feng static int 54031ed9f9fSChengwen Feng parse_arg_val(struct rte_argparse *obj, struct rte_argparse_arg *arg, char *value) 541e3e579f5SChengwen Feng { 5426c5c6571SChengwen Feng int ret; 5436c5c6571SChengwen Feng 54431ed9f9fSChengwen Feng if (arg->val_saver == NULL) 54531ed9f9fSChengwen Feng ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque); 54631ed9f9fSChengwen Feng else 54731ed9f9fSChengwen Feng ret = parse_arg_autosave(arg, value); 54831ed9f9fSChengwen Feng if (ret != 0) { 54931ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg->name_long); 55031ed9f9fSChengwen Feng return ret; 55131ed9f9fSChengwen Feng } 55231ed9f9fSChengwen Feng 55331ed9f9fSChengwen Feng return 0; 55431ed9f9fSChengwen Feng } 55531ed9f9fSChengwen Feng 55631ed9f9fSChengwen Feng static bool 55731ed9f9fSChengwen Feng is_help(const char *curr_argv) 55831ed9f9fSChengwen Feng { 55931ed9f9fSChengwen Feng return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0; 56031ed9f9fSChengwen Feng } 56131ed9f9fSChengwen Feng 56231ed9f9fSChengwen Feng static int 56331ed9f9fSChengwen Feng parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help) 56431ed9f9fSChengwen Feng { 56531ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 56631ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 56731ed9f9fSChengwen Feng uint32_t position_index = 0; 56831ed9f9fSChengwen Feng const char *arg_name; 56931ed9f9fSChengwen Feng char *curr_argv; 57031ed9f9fSChengwen Feng char *has_equal; 57131ed9f9fSChengwen Feng char *value; 57231ed9f9fSChengwen Feng int ret; 57331ed9f9fSChengwen Feng int i; 57431ed9f9fSChengwen Feng 57531ed9f9fSChengwen Feng for (i = 1; i < argc; i++) { 57631ed9f9fSChengwen Feng curr_argv = argv[i]; 57731ed9f9fSChengwen Feng if (curr_argv[0] != '-') { 57831ed9f9fSChengwen Feng /* process positional parameters. */ 57931ed9f9fSChengwen Feng position_index++; 58031ed9f9fSChengwen Feng if (position_index > position_count) { 58131ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv); 58231ed9f9fSChengwen Feng return -EINVAL; 58331ed9f9fSChengwen Feng } 58431ed9f9fSChengwen Feng arg = find_position_arg(obj, position_index); 58531ed9f9fSChengwen Feng ret = parse_arg_val(obj, arg, curr_argv); 58631ed9f9fSChengwen Feng if (ret != 0) 58731ed9f9fSChengwen Feng return ret; 58831ed9f9fSChengwen Feng continue; 58931ed9f9fSChengwen Feng } 59031ed9f9fSChengwen Feng 59131ed9f9fSChengwen Feng /* process optional parameters. */ 59231ed9f9fSChengwen Feng if (is_help(curr_argv)) { 59331ed9f9fSChengwen Feng *show_help = true; 59431ed9f9fSChengwen Feng continue; 59531ed9f9fSChengwen Feng } 59631ed9f9fSChengwen Feng 59731ed9f9fSChengwen Feng has_equal = strchr(curr_argv, '='); 59831ed9f9fSChengwen Feng arg_name = NULL; 59931ed9f9fSChengwen Feng arg = find_option_arg(obj, curr_argv, has_equal, &arg_name); 60031ed9f9fSChengwen Feng if (arg == NULL || arg_name == NULL) { 60131ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv); 60231ed9f9fSChengwen Feng return -EINVAL; 60331ed9f9fSChengwen Feng } 60431ed9f9fSChengwen Feng 60531ed9f9fSChengwen Feng if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) { 60631ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not occur multiple!", 60731ed9f9fSChengwen Feng arg_name); 60831ed9f9fSChengwen Feng return -EINVAL; 60931ed9f9fSChengwen Feng } 61031ed9f9fSChengwen Feng 61131ed9f9fSChengwen Feng value = (has_equal != NULL ? has_equal + 1 : NULL); 61231ed9f9fSChengwen Feng if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) { 61331ed9f9fSChengwen Feng if (value != NULL) { 61431ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not take value!", 61531ed9f9fSChengwen Feng arg_name); 61631ed9f9fSChengwen Feng return -EINVAL; 61731ed9f9fSChengwen Feng } 61831ed9f9fSChengwen Feng } else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) { 61931ed9f9fSChengwen Feng if (value == NULL) { 62031ed9f9fSChengwen Feng if (i >= argc - 1) { 62131ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s doesn't have value!", 62231ed9f9fSChengwen Feng arg_name); 62331ed9f9fSChengwen Feng return -EINVAL; 62431ed9f9fSChengwen Feng } 62531ed9f9fSChengwen Feng /* Set value and make i move next. */ 62631ed9f9fSChengwen Feng value = argv[++i]; 62731ed9f9fSChengwen Feng } 62831ed9f9fSChengwen Feng } else { 62931ed9f9fSChengwen Feng /* Do nothing, because it's optional value, only support arg=val or arg. */ 63031ed9f9fSChengwen Feng } 63131ed9f9fSChengwen Feng 63231ed9f9fSChengwen Feng ret = parse_arg_val(obj, arg, value); 63331ed9f9fSChengwen Feng if (ret != 0) 63431ed9f9fSChengwen Feng return ret; 63531ed9f9fSChengwen Feng 63631ed9f9fSChengwen Feng /* This argument parsed success! then mark it parsed. */ 63731ed9f9fSChengwen Feng arg->flags |= ARG_ATTR_FLAG_PARSED_MASK; 63831ed9f9fSChengwen Feng } 63931ed9f9fSChengwen Feng 64031ed9f9fSChengwen Feng return 0; 64131ed9f9fSChengwen Feng } 64231ed9f9fSChengwen Feng 64331ed9f9fSChengwen Feng static void 64431ed9f9fSChengwen Feng show_args_pos_help(const struct rte_argparse *obj) 64531ed9f9fSChengwen Feng { 64631ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 64731ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 64831ed9f9fSChengwen Feng uint32_t i; 64931ed9f9fSChengwen Feng 65031ed9f9fSChengwen Feng if (position_count == 0) 65131ed9f9fSChengwen Feng return; 65231ed9f9fSChengwen Feng 65331ed9f9fSChengwen Feng printf("\npositional arguments:\n"); 65431ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 65531ed9f9fSChengwen Feng arg = &obj->args[i]; 65631ed9f9fSChengwen Feng if (arg->name_long == NULL) 65731ed9f9fSChengwen Feng break; 65831ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 65931ed9f9fSChengwen Feng continue; 66031ed9f9fSChengwen Feng printf(" %s: %s\n", arg->name_long, arg->help); 66131ed9f9fSChengwen Feng } 66231ed9f9fSChengwen Feng } 66331ed9f9fSChengwen Feng 66431ed9f9fSChengwen Feng static void 66531ed9f9fSChengwen Feng show_args_opt_help(const struct rte_argparse *obj) 66631ed9f9fSChengwen Feng { 66731ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 66831ed9f9fSChengwen Feng uint32_t i; 66931ed9f9fSChengwen Feng 67031ed9f9fSChengwen Feng printf("\noptions:\n" 67131ed9f9fSChengwen Feng " -h, --help: show this help message and exit.\n"); 67231ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 67331ed9f9fSChengwen Feng arg = &obj->args[i]; 67431ed9f9fSChengwen Feng if (arg->name_long == NULL) 67531ed9f9fSChengwen Feng break; 67631ed9f9fSChengwen Feng if (!is_arg_optional(arg)) 67731ed9f9fSChengwen Feng continue; 67831ed9f9fSChengwen Feng if (arg->name_short != NULL) 67931ed9f9fSChengwen Feng printf(" %s, %s: %s\n", arg->name_short, arg->name_long, arg->help); 68031ed9f9fSChengwen Feng else 68131ed9f9fSChengwen Feng printf(" %s: %s\n", arg->name_long, arg->help); 68231ed9f9fSChengwen Feng } 68331ed9f9fSChengwen Feng } 68431ed9f9fSChengwen Feng 68531ed9f9fSChengwen Feng static void 68631ed9f9fSChengwen Feng show_args_help(const struct rte_argparse *obj) 68731ed9f9fSChengwen Feng { 68831ed9f9fSChengwen Feng printf("usage: %s %s\n", obj->prog_name, obj->usage); 68931ed9f9fSChengwen Feng if (obj->descriptor != NULL) 69031ed9f9fSChengwen Feng printf("\ndescriptor: %s\n", obj->descriptor); 69131ed9f9fSChengwen Feng 69231ed9f9fSChengwen Feng show_args_pos_help(obj); 69331ed9f9fSChengwen Feng show_args_opt_help(obj); 69431ed9f9fSChengwen Feng 69531ed9f9fSChengwen Feng if (obj->epilog != NULL) 69631ed9f9fSChengwen Feng printf("\n%s\n", obj->epilog); 69731ed9f9fSChengwen Feng } 69831ed9f9fSChengwen Feng 69931ed9f9fSChengwen Feng int 70031ed9f9fSChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) 70131ed9f9fSChengwen Feng { 70231ed9f9fSChengwen Feng bool show_help = false; 70331ed9f9fSChengwen Feng int ret; 7046c5c6571SChengwen Feng 7056c5c6571SChengwen Feng ret = verify_argparse(obj); 7066c5c6571SChengwen Feng if (ret != 0) 7076c5c6571SChengwen Feng goto error; 7086c5c6571SChengwen Feng 70931ed9f9fSChengwen Feng ret = parse_args(obj, argc, argv, &show_help); 71031ed9f9fSChengwen Feng if (ret != 0) 71131ed9f9fSChengwen Feng goto error; 71231ed9f9fSChengwen Feng 71331ed9f9fSChengwen Feng if (show_help) { 71431ed9f9fSChengwen Feng show_args_help(obj); 71531ed9f9fSChengwen Feng exit(0); 71631ed9f9fSChengwen Feng } 71731ed9f9fSChengwen Feng 718e3e579f5SChengwen Feng return 0; 7196c5c6571SChengwen Feng 7206c5c6571SChengwen Feng error: 7216c5c6571SChengwen Feng if (obj->exit_on_error) 7226c5c6571SChengwen Feng exit(ret); 7236c5c6571SChengwen Feng return ret; 724e3e579f5SChengwen Feng } 7259ccd7b27SChengwen Feng 7269ccd7b27SChengwen Feng int 7279ccd7b27SChengwen Feng rte_argparse_parse_type(const char *str, uint64_t val_type, void *val) 7289ccd7b27SChengwen Feng { 7299ccd7b27SChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); 7309ccd7b27SChengwen Feng struct rte_argparse_arg arg = { 7319ccd7b27SChengwen Feng .name_long = str, 7329ccd7b27SChengwen Feng .name_short = NULL, 7339ccd7b27SChengwen Feng .val_saver = val, 7349ccd7b27SChengwen Feng .val_set = NULL, 7359ccd7b27SChengwen Feng .flags = val_type, 7369ccd7b27SChengwen Feng }; 7379ccd7b27SChengwen Feng uint32_t value_type = arg_attr_val_type(&arg); 7389ccd7b27SChengwen Feng 7399ccd7b27SChengwen Feng if (value_type == 0 || value_type >= cmp_max) 7409ccd7b27SChengwen Feng return -EINVAL; 7419ccd7b27SChengwen Feng 7429ccd7b27SChengwen Feng return parse_arg_autosave(&arg, str); 7439ccd7b27SChengwen Feng } 744