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] != '-') { 70*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s doesn't 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) { 104*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s doesn't 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; 119*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s is positional, must config required-val!", 1206c5c6571SChengwen Feng arg->name_long); 1216c5c6571SChengwen Feng return -EINVAL; 1226c5c6571SChengwen Feng } 1236c5c6571SChengwen Feng 1246c5c6571SChengwen Feng if (has_val == 0) { 125*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s is optional, has-value 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) { 143*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parsed by callback, value-type should not be set!", 1446c5c6571SChengwen Feng arg->name_long); 1456c5c6571SChengwen Feng return -EINVAL; 1466c5c6571SChengwen Feng } 1476c5c6571SChengwen Feng 1486c5c6571SChengwen Feng if (obj->callback == NULL) { 149*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parsed 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) { 158*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s value-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) { 163*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s has required value, value-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) { 178*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s flags unused bits should not be set!", 179*9b8df29bSChengwen Feng arg->name_long); 1806c5c6571SChengwen Feng return -EINVAL; 1816c5c6571SChengwen Feng } 1826c5c6571SChengwen Feng 1836c5c6571SChengwen Feng if (!(arg->flags & RTE_ARGPARSE_ARG_SUPPORT_MULTI)) 1846c5c6571SChengwen Feng return 0; 1856c5c6571SChengwen Feng 1866c5c6571SChengwen Feng if (is_arg_positional(arg)) { 1876c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!", 1886c5c6571SChengwen Feng arg->name_long); 1896c5c6571SChengwen Feng return -EINVAL; 1906c5c6571SChengwen Feng } 1916c5c6571SChengwen Feng 1926c5c6571SChengwen Feng if (arg->val_saver != NULL) { 193*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s supports multiple times, should use callback to parse!", 1946c5c6571SChengwen Feng arg->name_long); 1956c5c6571SChengwen Feng return -EINVAL; 1966c5c6571SChengwen Feng } 1976c5c6571SChengwen Feng 1986c5c6571SChengwen Feng if (obj->callback == NULL) { 1996c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s should use callback to parse, but callback is NULL!", 2006c5c6571SChengwen Feng arg->name_long); 2016c5c6571SChengwen Feng return -EINVAL; 2026c5c6571SChengwen Feng } 2036c5c6571SChengwen Feng 2046c5c6571SChengwen Feng return 0; 2056c5c6571SChengwen Feng } 2066c5c6571SChengwen Feng 2076c5c6571SChengwen Feng static int 2086c5c6571SChengwen Feng verify_arg_repeat(const struct rte_argparse *self, uint32_t index) 2096c5c6571SChengwen Feng { 2106c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &self->args[index]; 2116c5c6571SChengwen Feng uint32_t i; 2126c5c6571SChengwen Feng 2136c5c6571SChengwen Feng for (i = 0; i < index; i++) { 2146c5c6571SChengwen Feng if (!strcmp(arg->name_long, self->args[i].name_long)) { 2156c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long); 2166c5c6571SChengwen Feng return -EINVAL; 2176c5c6571SChengwen Feng } 2186c5c6571SChengwen Feng } 2196c5c6571SChengwen Feng 2206c5c6571SChengwen Feng if (arg->name_short == NULL) 2216c5c6571SChengwen Feng return 0; 2226c5c6571SChengwen Feng 2236c5c6571SChengwen Feng for (i = 0; i < index; i++) { 2246c5c6571SChengwen Feng if (self->args[i].name_short == NULL) 2256c5c6571SChengwen Feng continue; 2266c5c6571SChengwen Feng if (!strcmp(arg->name_short, self->args[i].name_short)) { 2276c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short); 2286c5c6571SChengwen Feng return -EINVAL; 2296c5c6571SChengwen Feng } 2306c5c6571SChengwen Feng } 2316c5c6571SChengwen Feng 2326c5c6571SChengwen Feng return 0; 2336c5c6571SChengwen Feng } 2346c5c6571SChengwen Feng 2356c5c6571SChengwen Feng static int 2366c5c6571SChengwen Feng verify_argparse_arg(const struct rte_argparse *obj, uint32_t index) 2376c5c6571SChengwen Feng { 2386c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 2396c5c6571SChengwen Feng int ret; 2406c5c6571SChengwen Feng 2416c5c6571SChengwen Feng ret = verify_arg_name(arg); 2426c5c6571SChengwen Feng if (ret != 0) 2436c5c6571SChengwen Feng return ret; 2446c5c6571SChengwen Feng 2456c5c6571SChengwen Feng ret = verify_arg_help(arg); 2466c5c6571SChengwen Feng if (ret != 0) 2476c5c6571SChengwen Feng return ret; 2486c5c6571SChengwen Feng 2496c5c6571SChengwen Feng ret = verify_arg_has_val(arg); 2506c5c6571SChengwen Feng if (ret != 0) 2516c5c6571SChengwen Feng return ret; 2526c5c6571SChengwen Feng 2536c5c6571SChengwen Feng ret = verify_arg_saver(obj, index); 2546c5c6571SChengwen Feng if (ret != 0) 2556c5c6571SChengwen Feng return ret; 2566c5c6571SChengwen Feng 2576c5c6571SChengwen Feng ret = verify_arg_flags(obj, index); 2586c5c6571SChengwen Feng if (ret != 0) 2596c5c6571SChengwen Feng return ret; 2606c5c6571SChengwen Feng 2616c5c6571SChengwen Feng ret = verify_arg_repeat(obj, index); 2626c5c6571SChengwen Feng if (ret != 0) 2636c5c6571SChengwen Feng return ret; 2646c5c6571SChengwen Feng 2656c5c6571SChengwen Feng return 0; 2666c5c6571SChengwen Feng } 2676c5c6571SChengwen Feng 2686c5c6571SChengwen Feng static int 2696c5c6571SChengwen Feng verify_argparse(const struct rte_argparse *obj) 2706c5c6571SChengwen Feng { 2716c5c6571SChengwen Feng uint32_t idx; 2726c5c6571SChengwen Feng int ret; 2736c5c6571SChengwen Feng 2746c5c6571SChengwen Feng if (obj->prog_name == NULL) { 2756c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "program name is NULL!"); 2766c5c6571SChengwen Feng return -EINVAL; 2776c5c6571SChengwen Feng } 2786c5c6571SChengwen Feng 2796c5c6571SChengwen Feng if (obj->usage == NULL) { 2806c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "usage is NULL!"); 2816c5c6571SChengwen Feng return -EINVAL; 2826c5c6571SChengwen Feng } 2836c5c6571SChengwen Feng 2846c5c6571SChengwen Feng for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) { 2856c5c6571SChengwen Feng if (obj->reserved[idx] != 0) { 2866c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "reserved field must be zero!"); 2876c5c6571SChengwen Feng return -EINVAL; 2886c5c6571SChengwen Feng } 2896c5c6571SChengwen Feng } 2906c5c6571SChengwen Feng 2916c5c6571SChengwen Feng idx = 0; 2926c5c6571SChengwen Feng while (obj->args[idx].name_long != NULL) { 2936c5c6571SChengwen Feng ret = verify_argparse_arg(obj, idx); 2946c5c6571SChengwen Feng if (ret != 0) 2956c5c6571SChengwen Feng return ret; 2966c5c6571SChengwen Feng idx++; 2976c5c6571SChengwen Feng } 2986c5c6571SChengwen Feng 2996c5c6571SChengwen Feng return 0; 3006c5c6571SChengwen Feng } 3016c5c6571SChengwen Feng 30231ed9f9fSChengwen Feng static uint32_t 30331ed9f9fSChengwen Feng calc_position_count(const struct rte_argparse *obj) 30431ed9f9fSChengwen Feng { 30531ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 30631ed9f9fSChengwen Feng uint32_t count = 0; 30731ed9f9fSChengwen Feng uint32_t i; 30831ed9f9fSChengwen Feng 30931ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 31031ed9f9fSChengwen Feng arg = &obj->args[i]; 31131ed9f9fSChengwen Feng if (obj->args[i].name_long == NULL) 31231ed9f9fSChengwen Feng break; 31331ed9f9fSChengwen Feng if (is_arg_positional(arg)) 31431ed9f9fSChengwen Feng count++; 31531ed9f9fSChengwen Feng } 31631ed9f9fSChengwen Feng 31731ed9f9fSChengwen Feng return count; 31831ed9f9fSChengwen Feng } 31931ed9f9fSChengwen Feng 32031ed9f9fSChengwen Feng static struct rte_argparse_arg * 32131ed9f9fSChengwen Feng find_position_arg(struct rte_argparse *obj, uint32_t index) 32231ed9f9fSChengwen Feng { 32331ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 32431ed9f9fSChengwen Feng uint32_t count = 0; 32531ed9f9fSChengwen Feng uint32_t i; 32631ed9f9fSChengwen Feng 32731ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 32831ed9f9fSChengwen Feng arg = &obj->args[i]; 32931ed9f9fSChengwen Feng if (arg->name_long == NULL) 33031ed9f9fSChengwen Feng break; 33131ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 33231ed9f9fSChengwen Feng continue; 33331ed9f9fSChengwen Feng count++; 33431ed9f9fSChengwen Feng if (count == index) 33531ed9f9fSChengwen Feng return arg; 33631ed9f9fSChengwen Feng } 33731ed9f9fSChengwen Feng 33831ed9f9fSChengwen Feng return NULL; 33931ed9f9fSChengwen Feng } 34031ed9f9fSChengwen Feng 34131ed9f9fSChengwen Feng static bool 34231ed9f9fSChengwen Feng is_arg_match(struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len) 34331ed9f9fSChengwen Feng { 34431ed9f9fSChengwen Feng if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0) 34531ed9f9fSChengwen Feng return true; 34631ed9f9fSChengwen Feng 34731ed9f9fSChengwen Feng if (arg->name_short == NULL) 34831ed9f9fSChengwen Feng return false; 34931ed9f9fSChengwen Feng 35031ed9f9fSChengwen Feng if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0) 35131ed9f9fSChengwen Feng return true; 35231ed9f9fSChengwen Feng 35331ed9f9fSChengwen Feng return false; 35431ed9f9fSChengwen Feng } 35531ed9f9fSChengwen Feng 35631ed9f9fSChengwen Feng static struct rte_argparse_arg * 35731ed9f9fSChengwen Feng find_option_arg(struct rte_argparse *obj, const char *curr_argv, const char *has_equal, 35831ed9f9fSChengwen Feng const char **arg_name) 35931ed9f9fSChengwen Feng { 36031ed9f9fSChengwen Feng uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0); 36131ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 36231ed9f9fSChengwen Feng uint32_t i; 36331ed9f9fSChengwen Feng bool match; 36431ed9f9fSChengwen Feng 36531ed9f9fSChengwen Feng for (i = 0; /* nothing */; i++) { 36631ed9f9fSChengwen Feng arg = &obj->args[i]; 36731ed9f9fSChengwen Feng if (arg->name_long == NULL) 36831ed9f9fSChengwen Feng break; 36931ed9f9fSChengwen Feng match = is_arg_match(arg, curr_argv, len); 37031ed9f9fSChengwen Feng if (match) { 37131ed9f9fSChengwen Feng /* Obtains the exact matching name (long or short). */ 37231ed9f9fSChengwen Feng *arg_name = len > 2 ? arg->name_long : arg->name_short; 37331ed9f9fSChengwen Feng return arg; 37431ed9f9fSChengwen Feng } 37531ed9f9fSChengwen Feng } 37631ed9f9fSChengwen Feng 37731ed9f9fSChengwen Feng return NULL; 37831ed9f9fSChengwen Feng } 37931ed9f9fSChengwen Feng 38031ed9f9fSChengwen Feng static int 38131ed9f9fSChengwen Feng parse_arg_int(struct rte_argparse_arg *arg, const char *value) 38231ed9f9fSChengwen Feng { 38331ed9f9fSChengwen Feng char *s = NULL; 38431ed9f9fSChengwen Feng 38531ed9f9fSChengwen Feng if (value == NULL) { 38631ed9f9fSChengwen Feng *(int *)arg->val_saver = (int)(intptr_t)arg->val_set; 38731ed9f9fSChengwen Feng return 0; 38831ed9f9fSChengwen Feng } 38931ed9f9fSChengwen Feng 39031ed9f9fSChengwen Feng errno = 0; 39131ed9f9fSChengwen Feng *(int *)arg->val_saver = strtol(value, &s, 0); 39231ed9f9fSChengwen Feng if (errno == ERANGE) { 39331ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 39431ed9f9fSChengwen Feng return -EINVAL; 39531ed9f9fSChengwen Feng } 39631ed9f9fSChengwen Feng 39731ed9f9fSChengwen Feng if (s[0] != '\0') { 39831ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long); 39931ed9f9fSChengwen Feng return -EINVAL; 40031ed9f9fSChengwen Feng } 40131ed9f9fSChengwen Feng 40231ed9f9fSChengwen Feng return 0; 40331ed9f9fSChengwen Feng } 40431ed9f9fSChengwen Feng 40531ed9f9fSChengwen Feng static int 4065357c248SChengwen Feng parse_arg_u8(struct rte_argparse_arg *arg, const char *value) 4075357c248SChengwen Feng { 4085357c248SChengwen Feng unsigned long val; 4095357c248SChengwen Feng char *s = NULL; 4105357c248SChengwen Feng 4115357c248SChengwen Feng if (value == NULL) { 4125357c248SChengwen Feng *(uint8_t *)arg->val_saver = (uint8_t)(intptr_t)arg->val_set; 4135357c248SChengwen Feng return 0; 4145357c248SChengwen Feng } 4155357c248SChengwen Feng 4165357c248SChengwen Feng errno = 0; 4175357c248SChengwen Feng val = strtoul(value, &s, 0); 4185357c248SChengwen Feng if (errno == ERANGE || val > UINT8_MAX) { 4195357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4205357c248SChengwen Feng return -EINVAL; 4215357c248SChengwen Feng } 4225357c248SChengwen Feng 4235357c248SChengwen Feng if (s[0] != '\0') { 4245357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint8 value!", arg->name_long); 4255357c248SChengwen Feng return -EINVAL; 4265357c248SChengwen Feng } 4275357c248SChengwen Feng 4285357c248SChengwen Feng *(uint8_t *)arg->val_saver = val; 4295357c248SChengwen Feng 4305357c248SChengwen Feng return 0; 4315357c248SChengwen Feng } 4325357c248SChengwen Feng 4335357c248SChengwen Feng static int 4345357c248SChengwen Feng parse_arg_u16(struct rte_argparse_arg *arg, const char *value) 4355357c248SChengwen Feng { 4365357c248SChengwen Feng unsigned long val; 4375357c248SChengwen Feng char *s = NULL; 4385357c248SChengwen Feng 4395357c248SChengwen Feng if (value == NULL) { 4405357c248SChengwen Feng *(uint16_t *)arg->val_saver = (uint16_t)(intptr_t)arg->val_set; 4415357c248SChengwen Feng return 0; 4425357c248SChengwen Feng } 4435357c248SChengwen Feng 4445357c248SChengwen Feng errno = 0; 4455357c248SChengwen Feng val = strtoul(value, &s, 0); 4465357c248SChengwen Feng if (errno == ERANGE || val > UINT16_MAX) { 4475357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4485357c248SChengwen Feng return -EINVAL; 4495357c248SChengwen Feng } 4505357c248SChengwen Feng 4515357c248SChengwen Feng if (s[0] != '\0') { 4525357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint16 value!", arg->name_long); 4535357c248SChengwen Feng return -EINVAL; 4545357c248SChengwen Feng } 4555357c248SChengwen Feng 4565357c248SChengwen Feng *(uint16_t *)arg->val_saver = val; 4575357c248SChengwen Feng 4585357c248SChengwen Feng return 0; 4595357c248SChengwen Feng } 4605357c248SChengwen Feng 4615357c248SChengwen Feng static int 4625357c248SChengwen Feng parse_arg_u32(struct rte_argparse_arg *arg, const char *value) 4635357c248SChengwen Feng { 4645357c248SChengwen Feng unsigned long val; 4655357c248SChengwen Feng char *s = NULL; 4665357c248SChengwen Feng 4675357c248SChengwen Feng if (value == NULL) { 4685357c248SChengwen Feng *(uint32_t *)arg->val_saver = (uint32_t)(intptr_t)arg->val_set; 4695357c248SChengwen Feng return 0; 4705357c248SChengwen Feng } 4715357c248SChengwen Feng 4725357c248SChengwen Feng errno = 0; 4735357c248SChengwen Feng val = strtoul(value, &s, 0); 4745357c248SChengwen Feng if (errno == ERANGE || val > UINT32_MAX) { 4755357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4765357c248SChengwen Feng return -EINVAL; 4775357c248SChengwen Feng } 4785357c248SChengwen Feng 4795357c248SChengwen Feng if (s[0] != '\0') { 4805357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint32 value!", arg->name_long); 4815357c248SChengwen Feng return -EINVAL; 4825357c248SChengwen Feng } 4835357c248SChengwen Feng 4845357c248SChengwen Feng *(uint32_t *)arg->val_saver = val; 4855357c248SChengwen Feng 4865357c248SChengwen Feng return 0; 4875357c248SChengwen Feng } 4885357c248SChengwen Feng 4895357c248SChengwen Feng static int 4905357c248SChengwen Feng parse_arg_u64(struct rte_argparse_arg *arg, const char *value) 4915357c248SChengwen Feng { 4925357c248SChengwen Feng unsigned long val; 4935357c248SChengwen Feng char *s = NULL; 4945357c248SChengwen Feng 4955357c248SChengwen Feng if (value == NULL) { 4965357c248SChengwen Feng *(uint64_t *)arg->val_saver = (uint64_t)(intptr_t)arg->val_set; 4975357c248SChengwen Feng return 0; 4985357c248SChengwen Feng } 4995357c248SChengwen Feng 5005357c248SChengwen Feng errno = 0; 5015357c248SChengwen Feng val = strtoull(value, &s, 0); 5025357c248SChengwen Feng if (errno == ERANGE) { 5035357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 5045357c248SChengwen Feng return -EINVAL; 5055357c248SChengwen Feng } 5065357c248SChengwen Feng 5075357c248SChengwen Feng if (s[0] != '\0') { 5085357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint64 value!", arg->name_long); 5095357c248SChengwen Feng return -EINVAL; 5105357c248SChengwen Feng } 5115357c248SChengwen Feng 5125357c248SChengwen Feng *(uint64_t *)arg->val_saver = val; 5135357c248SChengwen Feng 5145357c248SChengwen Feng return 0; 5155357c248SChengwen Feng } 5165357c248SChengwen Feng 5175357c248SChengwen Feng static int 51831ed9f9fSChengwen Feng parse_arg_autosave(struct rte_argparse_arg *arg, const char *value) 51931ed9f9fSChengwen Feng { 52031ed9f9fSChengwen Feng static struct { 52131ed9f9fSChengwen Feng int (*f_parse_type)(struct rte_argparse_arg *arg, const char *value); 52231ed9f9fSChengwen Feng } map[] = { 52331ed9f9fSChengwen Feng /* Sort by RTE_ARGPARSE_ARG_VALUE_XXX. */ 52431ed9f9fSChengwen Feng { NULL }, 52531ed9f9fSChengwen Feng { parse_arg_int }, 5265357c248SChengwen Feng { parse_arg_u8 }, 5275357c248SChengwen Feng { parse_arg_u16 }, 5285357c248SChengwen Feng { parse_arg_u32 }, 5295357c248SChengwen Feng { parse_arg_u64 }, 53031ed9f9fSChengwen Feng }; 53131ed9f9fSChengwen Feng uint32_t index = arg_attr_val_type(arg); 53231ed9f9fSChengwen Feng int ret = -EINVAL; 53331ed9f9fSChengwen Feng 53431ed9f9fSChengwen Feng if (index > 0 && index < RTE_DIM(map)) 53531ed9f9fSChengwen Feng ret = map[index].f_parse_type(arg, value); 53631ed9f9fSChengwen Feng 53731ed9f9fSChengwen Feng return ret; 53831ed9f9fSChengwen Feng } 53931ed9f9fSChengwen Feng 540*9b8df29bSChengwen Feng /* arg_parse indicates the name entered by the user, which can be long-name or short-name. */ 54131ed9f9fSChengwen Feng static int 542*9b8df29bSChengwen Feng parse_arg_val(struct rte_argparse *obj, const char *arg_name, 543*9b8df29bSChengwen Feng struct rte_argparse_arg *arg, char *value) 544e3e579f5SChengwen Feng { 5456c5c6571SChengwen Feng int ret; 5466c5c6571SChengwen Feng 54731ed9f9fSChengwen Feng if (arg->val_saver == NULL) 54831ed9f9fSChengwen Feng ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque); 54931ed9f9fSChengwen Feng else 55031ed9f9fSChengwen Feng ret = parse_arg_autosave(arg, value); 55131ed9f9fSChengwen Feng if (ret != 0) { 552*9b8df29bSChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg_name); 55331ed9f9fSChengwen Feng return ret; 55431ed9f9fSChengwen Feng } 55531ed9f9fSChengwen Feng 55631ed9f9fSChengwen Feng return 0; 55731ed9f9fSChengwen Feng } 55831ed9f9fSChengwen Feng 55931ed9f9fSChengwen Feng static bool 56031ed9f9fSChengwen Feng is_help(const char *curr_argv) 56131ed9f9fSChengwen Feng { 56231ed9f9fSChengwen Feng return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0; 56331ed9f9fSChengwen Feng } 56431ed9f9fSChengwen Feng 56531ed9f9fSChengwen Feng static int 56631ed9f9fSChengwen Feng parse_args(struct rte_argparse *obj, int argc, char **argv, bool *show_help) 56731ed9f9fSChengwen Feng { 56831ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 56931ed9f9fSChengwen Feng struct rte_argparse_arg *arg; 57031ed9f9fSChengwen Feng uint32_t position_index = 0; 57131ed9f9fSChengwen Feng const char *arg_name; 57231ed9f9fSChengwen Feng char *curr_argv; 57331ed9f9fSChengwen Feng char *has_equal; 57431ed9f9fSChengwen Feng char *value; 57531ed9f9fSChengwen Feng int ret; 57631ed9f9fSChengwen Feng int i; 57731ed9f9fSChengwen Feng 57831ed9f9fSChengwen Feng for (i = 1; i < argc; i++) { 57931ed9f9fSChengwen Feng curr_argv = argv[i]; 58031ed9f9fSChengwen Feng if (curr_argv[0] != '-') { 58131ed9f9fSChengwen Feng /* process positional parameters. */ 58231ed9f9fSChengwen Feng position_index++; 58331ed9f9fSChengwen Feng if (position_index > position_count) { 58431ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "too much positional argument %s!", curr_argv); 58531ed9f9fSChengwen Feng return -EINVAL; 58631ed9f9fSChengwen Feng } 58731ed9f9fSChengwen Feng arg = find_position_arg(obj, position_index); 588*9b8df29bSChengwen Feng ret = parse_arg_val(obj, arg->name_long, arg, curr_argv); 58931ed9f9fSChengwen Feng if (ret != 0) 59031ed9f9fSChengwen Feng return ret; 59131ed9f9fSChengwen Feng continue; 59231ed9f9fSChengwen Feng } 59331ed9f9fSChengwen Feng 59431ed9f9fSChengwen Feng /* process optional parameters. */ 59531ed9f9fSChengwen Feng if (is_help(curr_argv)) { 59631ed9f9fSChengwen Feng *show_help = true; 59731ed9f9fSChengwen Feng continue; 59831ed9f9fSChengwen Feng } 59931ed9f9fSChengwen Feng 60031ed9f9fSChengwen Feng has_equal = strchr(curr_argv, '='); 60131ed9f9fSChengwen Feng arg_name = NULL; 60231ed9f9fSChengwen Feng arg = find_option_arg(obj, curr_argv, has_equal, &arg_name); 60331ed9f9fSChengwen Feng if (arg == NULL || arg_name == NULL) { 60431ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv); 60531ed9f9fSChengwen Feng return -EINVAL; 60631ed9f9fSChengwen Feng } 60731ed9f9fSChengwen Feng 60831ed9f9fSChengwen Feng if ((arg->flags & ARG_ATTR_FLAG_PARSED_MASK) && !arg_attr_flag_multi(arg)) { 60931ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not occur multiple!", 61031ed9f9fSChengwen Feng arg_name); 61131ed9f9fSChengwen Feng return -EINVAL; 61231ed9f9fSChengwen Feng } 61331ed9f9fSChengwen Feng 61431ed9f9fSChengwen Feng value = (has_equal != NULL ? has_equal + 1 : NULL); 61531ed9f9fSChengwen Feng if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_NO_VALUE) { 61631ed9f9fSChengwen Feng if (value != NULL) { 61731ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s should not take value!", 61831ed9f9fSChengwen Feng arg_name); 61931ed9f9fSChengwen Feng return -EINVAL; 62031ed9f9fSChengwen Feng } 62131ed9f9fSChengwen Feng } else if (arg_attr_has_val(arg) == RTE_ARGPARSE_ARG_REQUIRED_VALUE) { 62231ed9f9fSChengwen Feng if (value == NULL) { 62331ed9f9fSChengwen Feng if (i >= argc - 1) { 62431ed9f9fSChengwen Feng ARGPARSE_LOG(ERR, "argument %s doesn't have value!", 62531ed9f9fSChengwen Feng arg_name); 62631ed9f9fSChengwen Feng return -EINVAL; 62731ed9f9fSChengwen Feng } 62831ed9f9fSChengwen Feng /* Set value and make i move next. */ 62931ed9f9fSChengwen Feng value = argv[++i]; 63031ed9f9fSChengwen Feng } 63131ed9f9fSChengwen Feng } else { 63231ed9f9fSChengwen Feng /* Do nothing, because it's optional value, only support arg=val or arg. */ 63331ed9f9fSChengwen Feng } 63431ed9f9fSChengwen Feng 635*9b8df29bSChengwen Feng ret = parse_arg_val(obj, arg_name, arg, value); 63631ed9f9fSChengwen Feng if (ret != 0) 63731ed9f9fSChengwen Feng return ret; 63831ed9f9fSChengwen Feng 63931ed9f9fSChengwen Feng /* This argument parsed success! then mark it parsed. */ 64031ed9f9fSChengwen Feng arg->flags |= ARG_ATTR_FLAG_PARSED_MASK; 64131ed9f9fSChengwen Feng } 64231ed9f9fSChengwen Feng 64331ed9f9fSChengwen Feng return 0; 64431ed9f9fSChengwen Feng } 64531ed9f9fSChengwen Feng 646676ca0d2SChengwen Feng static uint32_t 647676ca0d2SChengwen Feng calc_help_align(const struct rte_argparse *obj) 648676ca0d2SChengwen Feng { 649676ca0d2SChengwen Feng const struct rte_argparse_arg *arg; 650676ca0d2SChengwen Feng uint32_t width = 12; /* Default "-h, --help " len. */ 651676ca0d2SChengwen Feng uint32_t len; 652676ca0d2SChengwen Feng uint32_t i; 653676ca0d2SChengwen Feng 654676ca0d2SChengwen Feng for (i = 0; /* NULL */; i++) { 655676ca0d2SChengwen Feng arg = &obj->args[i]; 656676ca0d2SChengwen Feng if (arg->name_long == NULL) 657676ca0d2SChengwen Feng break; 658676ca0d2SChengwen Feng len = strlen(arg->name_long); 659676ca0d2SChengwen Feng if (is_arg_optional(arg) && arg->name_short != NULL) { 660676ca0d2SChengwen Feng len += strlen(", "); 661676ca0d2SChengwen Feng len += strlen(arg->name_short); 662676ca0d2SChengwen Feng } 663676ca0d2SChengwen Feng width = RTE_MAX(width, 1 + len + 2); /* start with 1 & end with 2 space. */ 664676ca0d2SChengwen Feng } 665676ca0d2SChengwen Feng 666676ca0d2SChengwen Feng return width; 667676ca0d2SChengwen Feng } 668676ca0d2SChengwen Feng 66931ed9f9fSChengwen Feng static void 670676ca0d2SChengwen Feng show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width) 671676ca0d2SChengwen Feng { 672676ca0d2SChengwen Feng uint32_t len = 0; 673676ca0d2SChengwen Feng uint32_t i; 674676ca0d2SChengwen Feng 675676ca0d2SChengwen Feng if (arg->name_short != NULL) 676676ca0d2SChengwen Feng len = printf(" %s,", arg->name_short); 677676ca0d2SChengwen Feng len += printf(" %s", arg->name_long); 678676ca0d2SChengwen Feng 679676ca0d2SChengwen Feng for (i = len; i < width; i++) 680676ca0d2SChengwen Feng printf(" "); 681676ca0d2SChengwen Feng 682676ca0d2SChengwen Feng printf("%s\n", arg->help); 683676ca0d2SChengwen Feng } 684676ca0d2SChengwen Feng 685676ca0d2SChengwen Feng static void 686676ca0d2SChengwen Feng show_args_pos_help(const struct rte_argparse *obj, uint32_t align) 68731ed9f9fSChengwen Feng { 68831ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 68931ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 69031ed9f9fSChengwen Feng uint32_t i; 69131ed9f9fSChengwen Feng 69231ed9f9fSChengwen Feng if (position_count == 0) 69331ed9f9fSChengwen Feng return; 69431ed9f9fSChengwen Feng 69531ed9f9fSChengwen Feng printf("\npositional arguments:\n"); 69631ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 69731ed9f9fSChengwen Feng arg = &obj->args[i]; 69831ed9f9fSChengwen Feng if (arg->name_long == NULL) 69931ed9f9fSChengwen Feng break; 70031ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 70131ed9f9fSChengwen Feng continue; 702676ca0d2SChengwen Feng show_oneline_help(arg, align); 70331ed9f9fSChengwen Feng } 70431ed9f9fSChengwen Feng } 70531ed9f9fSChengwen Feng 70631ed9f9fSChengwen Feng static void 707676ca0d2SChengwen Feng show_args_opt_help(const struct rte_argparse *obj, uint32_t align) 70831ed9f9fSChengwen Feng { 709676ca0d2SChengwen Feng static const struct rte_argparse_arg help = { 710676ca0d2SChengwen Feng .name_long = "--help", 711676ca0d2SChengwen Feng .name_short = "-h", 712676ca0d2SChengwen Feng .help = "show this help message and exit.", 713676ca0d2SChengwen Feng }; 71431ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 71531ed9f9fSChengwen Feng uint32_t i; 71631ed9f9fSChengwen Feng 717676ca0d2SChengwen Feng printf("\noptions:\n"); 718676ca0d2SChengwen Feng show_oneline_help(&help, align); 71931ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 72031ed9f9fSChengwen Feng arg = &obj->args[i]; 72131ed9f9fSChengwen Feng if (arg->name_long == NULL) 72231ed9f9fSChengwen Feng break; 72331ed9f9fSChengwen Feng if (!is_arg_optional(arg)) 72431ed9f9fSChengwen Feng continue; 725676ca0d2SChengwen Feng show_oneline_help(arg, align); 72631ed9f9fSChengwen Feng } 72731ed9f9fSChengwen Feng } 72831ed9f9fSChengwen Feng 72931ed9f9fSChengwen Feng static void 73031ed9f9fSChengwen Feng show_args_help(const struct rte_argparse *obj) 73131ed9f9fSChengwen Feng { 732676ca0d2SChengwen Feng uint32_t align = calc_help_align(obj); 733676ca0d2SChengwen Feng 73431ed9f9fSChengwen Feng printf("usage: %s %s\n", obj->prog_name, obj->usage); 73531ed9f9fSChengwen Feng if (obj->descriptor != NULL) 73631ed9f9fSChengwen Feng printf("\ndescriptor: %s\n", obj->descriptor); 73731ed9f9fSChengwen Feng 738676ca0d2SChengwen Feng show_args_pos_help(obj, align); 739676ca0d2SChengwen Feng show_args_opt_help(obj, align); 74031ed9f9fSChengwen Feng 74131ed9f9fSChengwen Feng if (obj->epilog != NULL) 74231ed9f9fSChengwen Feng printf("\n%s\n", obj->epilog); 743676ca0d2SChengwen Feng else 744676ca0d2SChengwen Feng printf("\n"); 74531ed9f9fSChengwen Feng } 74631ed9f9fSChengwen Feng 74731ed9f9fSChengwen Feng int 74831ed9f9fSChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) 74931ed9f9fSChengwen Feng { 75031ed9f9fSChengwen Feng bool show_help = false; 75131ed9f9fSChengwen Feng int ret; 7526c5c6571SChengwen Feng 7536c5c6571SChengwen Feng ret = verify_argparse(obj); 7546c5c6571SChengwen Feng if (ret != 0) 7556c5c6571SChengwen Feng goto error; 7566c5c6571SChengwen Feng 75731ed9f9fSChengwen Feng ret = parse_args(obj, argc, argv, &show_help); 75831ed9f9fSChengwen Feng if (ret != 0) 75931ed9f9fSChengwen Feng goto error; 76031ed9f9fSChengwen Feng 76131ed9f9fSChengwen Feng if (show_help) { 76231ed9f9fSChengwen Feng show_args_help(obj); 76331ed9f9fSChengwen Feng exit(0); 76431ed9f9fSChengwen Feng } 76531ed9f9fSChengwen Feng 766e3e579f5SChengwen Feng return 0; 7676c5c6571SChengwen Feng 7686c5c6571SChengwen Feng error: 7696c5c6571SChengwen Feng if (obj->exit_on_error) 7706c5c6571SChengwen Feng exit(ret); 7716c5c6571SChengwen Feng return ret; 772e3e579f5SChengwen Feng } 7739ccd7b27SChengwen Feng 7749ccd7b27SChengwen Feng int 7759ccd7b27SChengwen Feng rte_argparse_parse_type(const char *str, uint64_t val_type, void *val) 7769ccd7b27SChengwen Feng { 7779ccd7b27SChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); 7789ccd7b27SChengwen Feng struct rte_argparse_arg arg = { 7799ccd7b27SChengwen Feng .name_long = str, 7809ccd7b27SChengwen Feng .name_short = NULL, 7819ccd7b27SChengwen Feng .val_saver = val, 7829ccd7b27SChengwen Feng .val_set = NULL, 7839ccd7b27SChengwen Feng .flags = val_type, 7849ccd7b27SChengwen Feng }; 7859ccd7b27SChengwen Feng uint32_t value_type = arg_attr_val_type(&arg); 7869ccd7b27SChengwen Feng 7879ccd7b27SChengwen Feng if (value_type == 0 || value_type >= cmp_max) 7889ccd7b27SChengwen Feng return -EINVAL; 7899ccd7b27SChengwen Feng 7909ccd7b27SChengwen Feng return parse_arg_autosave(&arg, str); 7919ccd7b27SChengwen Feng } 792