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 47*31ed9f9fSChengwen Feng static inline bool 48*31ed9f9fSChengwen Feng arg_attr_flag_multi(const struct rte_argparse_arg *arg) 49*31ed9f9fSChengwen Feng { 50*31ed9f9fSChengwen Feng return RTE_FIELD_GET64(ARG_ATTR_SUPPORT_MULTI_MASK, arg->flags); 51*31ed9f9fSChengwen Feng } 52*31ed9f9fSChengwen 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 301*31ed9f9fSChengwen Feng static uint32_t 302*31ed9f9fSChengwen Feng calc_position_count(const struct rte_argparse *obj) 303*31ed9f9fSChengwen Feng { 304*31ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 305*31ed9f9fSChengwen Feng uint32_t count = 0; 306*31ed9f9fSChengwen Feng uint32_t i; 307*31ed9f9fSChengwen Feng 308*31ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 309*31ed9f9fSChengwen Feng arg = &obj->args[i]; 310*31ed9f9fSChengwen Feng if (obj->args[i].name_long == NULL) 311*31ed9f9fSChengwen Feng break; 312*31ed9f9fSChengwen Feng if (is_arg_positional(arg)) 313*31ed9f9fSChengwen Feng count++; 314*31ed9f9fSChengwen Feng } 315*31ed9f9fSChengwen Feng 316*31ed9f9fSChengwen Feng return count; 317*31ed9f9fSChengwen Feng } 318*31ed9f9fSChengwen Feng 319*31ed9f9fSChengwen Feng static struct rte_argparse_arg * 320*31ed9f9fSChengwen Feng find_position_arg(struct rte_argparse *obj, uint32_t index) 321*31ed9f9fSChengwen Feng { 322*31ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 323*31ed9f9fSChengwen Feng uint32_t count = 0; 324*31ed9f9fSChengwen Feng uint32_t i; 325*31ed9f9fSChengwen Feng 326*31ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 327*31ed9f9fSChengwen Feng arg = &obj->args[i]; 328*31ed9f9fSChengwen Feng if (arg->name_long == NULL) 329*31ed9f9fSChengwen Feng break; 330*31ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 331*31ed9f9fSChengwen Feng continue; 332*31ed9f9fSChengwen Feng count++; 333*31ed9f9fSChengwen Feng if (count == index) 334*31ed9f9fSChengwen Feng return arg; 335*31ed9f9fSChengwen Feng } 336*31ed9f9fSChengwen Feng 337*31ed9f9fSChengwen Feng return NULL; 338*31ed9f9fSChengwen Feng } 339*31ed9f9fSChengwen Feng 340*31ed9f9fSChengwen Feng static bool 341*31ed9f9fSChengwen Feng is_arg_match(struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len) 342*31ed9f9fSChengwen Feng { 343*31ed9f9fSChengwen Feng if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0) 344*31ed9f9fSChengwen Feng return true; 345*31ed9f9fSChengwen Feng 346*31ed9f9fSChengwen Feng if (arg->name_short == NULL) 347*31ed9f9fSChengwen Feng return false; 348*31ed9f9fSChengwen Feng 349*31ed9f9fSChengwen Feng if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0) 350*31ed9f9fSChengwen Feng return true; 351*31ed9f9fSChengwen Feng 352*31ed9f9fSChengwen Feng return false; 353*31ed9f9fSChengwen Feng } 354*31ed9f9fSChengwen Feng 355*31ed9f9fSChengwen Feng static struct rte_argparse_arg * 356*31ed9f9fSChengwen Feng find_option_arg(struct rte_argparse *obj, const char *curr_argv, const char *has_equal, 357*31ed9f9fSChengwen Feng const char **arg_name) 358*31ed9f9fSChengwen Feng { 359*31ed9f9fSChengwen Feng uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0); 360*31ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 361*31ed9f9fSChengwen Feng uint32_t i; 362*31ed9f9fSChengwen Feng bool match; 363*31ed9f9fSChengwen Feng 364*31ed9f9fSChengwen Feng for (i = 0; /* nothing */; i++) { 365*31ed9f9fSChengwen Feng arg = &obj->args[i]; 366*31ed9f9fSChengwen Feng if (arg->name_long == NULL) 367*31ed9f9fSChengwen Feng break; 368*31ed9f9fSChengwen Feng match = is_arg_match(arg, curr_argv, len); 369*31ed9f9fSChengwen Feng if (match) { 370*31ed9f9fSChengwen Feng /* Obtains the exact matching name (long or short). */ 371*31ed9f9fSChengwen Feng *arg_name = len > 2 ? arg->name_long : arg->name_short; 372*31ed9f9fSChengwen Feng return arg; 373*31ed9f9fSChengwen Feng } 374*31ed9f9fSChengwen Feng } 375*31ed9f9fSChengwen Feng 376*31ed9f9fSChengwen Feng return NULL; 377*31ed9f9fSChengwen Feng } 378*31ed9f9fSChengwen Feng 379*31ed9f9fSChengwen Feng static int 380*31ed9f9fSChengwen Feng parse_arg_int(struct rte_argparse_arg *arg, const char *value) 381*31ed9f9fSChengwen Feng { 382*31ed9f9fSChengwen Feng char *s = NULL; 383*31ed9f9fSChengwen Feng 384*31ed9f9fSChengwen Feng if (value == NULL) { 385*31ed9f9fSChengwen Feng *(int *)arg->val_saver = (int)(intptr_t)arg->val_set; 386*31ed9f9fSChengwen Feng return 0; 387*31ed9f9fSChengwen Feng } 388*31ed9f9fSChengwen Feng 389*31ed9f9fSChengwen Feng errno = 0; 390*31ed9f9fSChengwen Feng *(int *)arg->val_saver = strtol(value, &s, 0); 391*31ed9f9fSChengwen Feng if (errno == ERANGE) { 392*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 393*31ed9f9fSChengwen Feng return -EINVAL; 394*31ed9f9fSChengwen Feng } 395*31ed9f9fSChengwen Feng 396*31ed9f9fSChengwen Feng if (s[0] != '\0') { 397*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long); 398*31ed9f9fSChengwen Feng return -EINVAL; 399*31ed9f9fSChengwen Feng } 400*31ed9f9fSChengwen Feng 401*31ed9f9fSChengwen Feng return 0; 402*31ed9f9fSChengwen Feng } 403*31ed9f9fSChengwen Feng 404*31ed9f9fSChengwen Feng static int 405*31ed9f9fSChengwen Feng parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) 406*31ed9f9fSChengwen Feng { 407*31ed9f9fSChengwen Feng static struct { 408*31ed9f9fSChengwen Feng int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value); 409*31ed9f9fSChengwen Feng } map[] = { 410*31ed9f9fSChengwen Feng /* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */ 411*31ed9f9fSChengwen Feng { NULL }, 412*31ed9f9fSChengwen Feng { parse_arg_int }, 413*31ed9f9fSChengwen Feng }; 414*31ed9f9fSChengwen Feng uint32_t index = arg_attr_val_type(arg); 415*31ed9f9fSChengwen Feng int ret = -EINVAL; 416*31ed9f9fSChengwen Feng 417*31ed9f9fSChengwen Feng if (index > 0 && index < RTE_DIM(map)) 418*31ed9f9fSChengwen Feng ret = map[index].f_parse_type(arg, value); 419*31ed9f9fSChengwen Feng 420*31ed9f9fSChengwen Feng return ret; 421*31ed9f9fSChengwen Feng } 422*31ed9f9fSChengwen Feng 423*31ed9f9fSChengwen Feng static int 424*31ed9f9fSChengwen Feng parse_arg_val(struct rte_argparse *obj, struct rte_argparse_arg *arg, char *value) 425e3e579f5SChengwen Feng { 4266c5c6571SChengwen Feng int ret; 4276c5c6571SChengwen Feng 428*31ed9f9fSChengwen Feng if (arg->val_saver == NULL) 429*31ed9f9fSChengwen Feng ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque); 430*31ed9f9fSChengwen Feng else 431*31ed9f9fSChengwen Feng ret = parse_arg_autosave(arg, value); 432*31ed9f9fSChengwen Feng if (ret != 0) { 433*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg->name_long); 434*31ed9f9fSChengwen Feng return ret; 435*31ed9f9fSChengwen Feng } 436*31ed9f9fSChengwen Feng 437*31ed9f9fSChengwen Feng return 0; 438*31ed9f9fSChengwen Feng } 439*31ed9f9fSChengwen Feng 440*31ed9f9fSChengwen Feng static bool 441*31ed9f9fSChengwen Feng is_help(const char *curr_argv) 442*31ed9f9fSChengwen Feng { 443*31ed9f9fSChengwen Feng return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0; 444*31ed9f9fSChengwen Feng } 445*31ed9f9fSChengwen Feng 446*31ed9f9fSChengwen Feng static int 447*31ed9f9fSChengwen Feng parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help) 448*31ed9f9fSChengwen Feng { 449*31ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 450*31ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 451*31ed9f9fSChengwen Feng uint32_t position_index = 0; 452*31ed9f9fSChengwen Feng const char *arg_name; 453*31ed9f9fSChengwen Feng char *curr_argv; 454*31ed9f9fSChengwen Feng char *has_equal; 455*31ed9f9fSChengwen Feng char *value; 456*31ed9f9fSChengwen Feng int ret; 457*31ed9f9fSChengwen Feng int i; 458*31ed9f9fSChengwen Feng 459*31ed9f9fSChengwen Feng for (i = 1; i < argc; i++) { 460*31ed9f9fSChengwen Feng curr_argv = argv[i]; 461*31ed9f9fSChengwen Feng if (curr_argv[0] != '-') { 462*31ed9f9fSChengwen Feng /* process positional parameters. */ 463*31ed9f9fSChengwen Feng position_index++; 464*31ed9f9fSChengwen Feng if (position_index > position_count) { 465*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv); 466*31ed9f9fSChengwen Feng return -EINVAL; 467*31ed9f9fSChengwen Feng } 468*31ed9f9fSChengwen Feng arg = find_position_arg(obj, position_index); 469*31ed9f9fSChengwen Feng ret = parse_arg_val(obj, arg, curr_argv); 470*31ed9f9fSChengwen Feng if (ret != 0) 471*31ed9f9fSChengwen Feng return ret; 472*31ed9f9fSChengwen Feng continue; 473*31ed9f9fSChengwen Feng } 474*31ed9f9fSChengwen Feng 475*31ed9f9fSChengwen Feng /* process optional parameters. */ 476*31ed9f9fSChengwen Feng if (is_help(curr_argv)) { 477*31ed9f9fSChengwen Feng *show_help = true; 478*31ed9f9fSChengwen Feng continue; 479*31ed9f9fSChengwen Feng } 480*31ed9f9fSChengwen Feng 481*31ed9f9fSChengwen Feng has_equal = strchr(curr_argv, '='); 482*31ed9f9fSChengwen Feng arg_name = NULL; 483*31ed9f9fSChengwen Feng arg = find_option_arg(obj, curr_argv, has_equal, &arg_name); 484*31ed9f9fSChengwen Feng if (arg == NULL || arg_name == NULL) { 485*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv); 486*31ed9f9fSChengwen Feng return -EINVAL; 487*31ed9f9fSChengwen Feng } 488*31ed9f9fSChengwen Feng 489*31ed9f9fSChengwen Feng if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) { 490*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not occur multiple!", 491*31ed9f9fSChengwen Feng arg_name); 492*31ed9f9fSChengwen Feng return -EINVAL; 493*31ed9f9fSChengwen Feng } 494*31ed9f9fSChengwen Feng 495*31ed9f9fSChengwen Feng value = (has_equal != NULL ? has_equal + 1 : NULL); 496*31ed9f9fSChengwen Feng if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) { 497*31ed9f9fSChengwen Feng if (value != NULL) { 498*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not take value!", 499*31ed9f9fSChengwen Feng arg_name); 500*31ed9f9fSChengwen Feng return -EINVAL; 501*31ed9f9fSChengwen Feng } 502*31ed9f9fSChengwen Feng } else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) { 503*31ed9f9fSChengwen Feng if (value == NULL) { 504*31ed9f9fSChengwen Feng if (i >= argc - 1) { 505*31ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s doesn't have value!", 506*31ed9f9fSChengwen Feng arg_name); 507*31ed9f9fSChengwen Feng return -EINVAL; 508*31ed9f9fSChengwen Feng } 509*31ed9f9fSChengwen Feng /* Set value and make i move next. */ 510*31ed9f9fSChengwen Feng value = argv[++i]; 511*31ed9f9fSChengwen Feng } 512*31ed9f9fSChengwen Feng } else { 513*31ed9f9fSChengwen Feng /* Do nothing, because it's optional value, only support arg=val or arg. */ 514*31ed9f9fSChengwen Feng } 515*31ed9f9fSChengwen Feng 516*31ed9f9fSChengwen Feng ret = parse_arg_val(obj, arg, value); 517*31ed9f9fSChengwen Feng if (ret != 0) 518*31ed9f9fSChengwen Feng return ret; 519*31ed9f9fSChengwen Feng 520*31ed9f9fSChengwen Feng /* This argument parsed success! then mark it parsed. */ 521*31ed9f9fSChengwen Feng arg->flags |= ARG_ATTR_FLAG_PARSED_MASK; 522*31ed9f9fSChengwen Feng } 523*31ed9f9fSChengwen Feng 524*31ed9f9fSChengwen Feng return 0; 525*31ed9f9fSChengwen Feng } 526*31ed9f9fSChengwen Feng 527*31ed9f9fSChengwen Feng static void 528*31ed9f9fSChengwen Feng show_args_pos_help(const struct rte_argparse *obj) 529*31ed9f9fSChengwen Feng { 530*31ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 531*31ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 532*31ed9f9fSChengwen Feng uint32_t i; 533*31ed9f9fSChengwen Feng 534*31ed9f9fSChengwen Feng if (position_count == 0) 535*31ed9f9fSChengwen Feng return; 536*31ed9f9fSChengwen Feng 537*31ed9f9fSChengwen Feng printf("\npositional arguments:\n"); 538*31ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 539*31ed9f9fSChengwen Feng arg = &obj->args[i]; 540*31ed9f9fSChengwen Feng if (arg->name_long == NULL) 541*31ed9f9fSChengwen Feng break; 542*31ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 543*31ed9f9fSChengwen Feng continue; 544*31ed9f9fSChengwen Feng printf(" %s: %s\n", arg->name_long, arg->help); 545*31ed9f9fSChengwen Feng } 546*31ed9f9fSChengwen Feng } 547*31ed9f9fSChengwen Feng 548*31ed9f9fSChengwen Feng static void 549*31ed9f9fSChengwen Feng show_args_opt_help(const struct rte_argparse *obj) 550*31ed9f9fSChengwen Feng { 551*31ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 552*31ed9f9fSChengwen Feng uint32_t i; 553*31ed9f9fSChengwen Feng 554*31ed9f9fSChengwen Feng printf("\noptions:\n" 555*31ed9f9fSChengwen Feng " -h, --help: show this help message and exit.\n"); 556*31ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 557*31ed9f9fSChengwen Feng arg = &obj->args[i]; 558*31ed9f9fSChengwen Feng if (arg->name_long == NULL) 559*31ed9f9fSChengwen Feng break; 560*31ed9f9fSChengwen Feng if (!is_arg_optional(arg)) 561*31ed9f9fSChengwen Feng continue; 562*31ed9f9fSChengwen Feng if (arg->name_short != NULL) 563*31ed9f9fSChengwen Feng printf(" %s, %s: %s\n", arg->name_short, arg->name_long, arg->help); 564*31ed9f9fSChengwen Feng else 565*31ed9f9fSChengwen Feng printf(" %s: %s\n", arg->name_long, arg->help); 566*31ed9f9fSChengwen Feng } 567*31ed9f9fSChengwen Feng } 568*31ed9f9fSChengwen Feng 569*31ed9f9fSChengwen Feng static void 570*31ed9f9fSChengwen Feng show_args_help(const struct rte_argparse *obj) 571*31ed9f9fSChengwen Feng { 572*31ed9f9fSChengwen Feng printf("usage: %s %s\n", obj->prog_name, obj->usage); 573*31ed9f9fSChengwen Feng if (obj->descriptor != NULL) 574*31ed9f9fSChengwen Feng printf("\ndescriptor: %s\n", obj->descriptor); 575*31ed9f9fSChengwen Feng 576*31ed9f9fSChengwen Feng show_args_pos_help(obj); 577*31ed9f9fSChengwen Feng show_args_opt_help(obj); 578*31ed9f9fSChengwen Feng 579*31ed9f9fSChengwen Feng if (obj->epilog != NULL) 580*31ed9f9fSChengwen Feng printf("\n%s\n", obj->epilog); 581*31ed9f9fSChengwen Feng } 582*31ed9f9fSChengwen Feng 583*31ed9f9fSChengwen Feng int 584*31ed9f9fSChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) 585*31ed9f9fSChengwen Feng { 586*31ed9f9fSChengwen Feng bool show_help = false; 587*31ed9f9fSChengwen Feng int ret; 5886c5c6571SChengwen Feng 5896c5c6571SChengwen Feng ret = verify_argparse(obj); 5906c5c6571SChengwen Feng if (ret != 0) 5916c5c6571SChengwen Feng goto error; 5926c5c6571SChengwen Feng 593*31ed9f9fSChengwen Feng ret = parse_args(obj, argc, argv, &show_help); 594*31ed9f9fSChengwen Feng if (ret != 0) 595*31ed9f9fSChengwen Feng goto error; 596*31ed9f9fSChengwen Feng 597*31ed9f9fSChengwen Feng if (show_help) { 598*31ed9f9fSChengwen Feng show_args_help(obj); 599*31ed9f9fSChengwen Feng exit(0); 600*31ed9f9fSChengwen Feng } 601*31ed9f9fSChengwen 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