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 4055357c248SChengwen Feng parse_arg_u8(struct rte_argparse_arg *arg, const char *value) 4065357c248SChengwen Feng { 4075357c248SChengwen Feng unsigned long val; 4085357c248SChengwen Feng char *s = NULL; 4095357c248SChengwen Feng 4105357c248SChengwen Feng if (value == NULL) { 4115357c248SChengwen Feng *(uint8_t *)arg->val_saver = (uint8_t)(intptr_t)arg->val_set; 4125357c248SChengwen Feng return 0; 4135357c248SChengwen Feng } 4145357c248SChengwen Feng 4155357c248SChengwen Feng errno = 0; 4165357c248SChengwen Feng val = strtoul(value, &s, 0); 4175357c248SChengwen Feng if (errno == ERANGE || val > UINT8_MAX) { 4185357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4195357c248SChengwen Feng return -EINVAL; 4205357c248SChengwen Feng } 4215357c248SChengwen Feng 4225357c248SChengwen Feng if (s[0] != '\0') { 4235357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint8 value!", arg->name_long); 4245357c248SChengwen Feng return -EINVAL; 4255357c248SChengwen Feng } 4265357c248SChengwen Feng 4275357c248SChengwen Feng *(uint8_t *)arg->val_saver = val; 4285357c248SChengwen Feng 4295357c248SChengwen Feng return 0; 4305357c248SChengwen Feng } 4315357c248SChengwen Feng 4325357c248SChengwen Feng static int 4335357c248SChengwen Feng parse_arg_u16(struct rte_argparse_arg *arg, const char *value) 4345357c248SChengwen Feng { 4355357c248SChengwen Feng unsigned long val; 4365357c248SChengwen Feng char *s = NULL; 4375357c248SChengwen Feng 4385357c248SChengwen Feng if (value == NULL) { 4395357c248SChengwen Feng *(uint16_t *)arg->val_saver = (uint16_t)(intptr_t)arg->val_set; 4405357c248SChengwen Feng return 0; 4415357c248SChengwen Feng } 4425357c248SChengwen Feng 4435357c248SChengwen Feng errno = 0; 4445357c248SChengwen Feng val = strtoul(value, &s, 0); 4455357c248SChengwen Feng if (errno == ERANGE || val > UINT16_MAX) { 4465357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4475357c248SChengwen Feng return -EINVAL; 4485357c248SChengwen Feng } 4495357c248SChengwen Feng 4505357c248SChengwen Feng if (s[0] != '\0') { 4515357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint16 value!", arg->name_long); 4525357c248SChengwen Feng return -EINVAL; 4535357c248SChengwen Feng } 4545357c248SChengwen Feng 4555357c248SChengwen Feng *(uint16_t *)arg->val_saver = val; 4565357c248SChengwen Feng 4575357c248SChengwen Feng return 0; 4585357c248SChengwen Feng } 4595357c248SChengwen Feng 4605357c248SChengwen Feng static int 4615357c248SChengwen Feng parse_arg_u32(struct rte_argparse_arg *arg, const char *value) 4625357c248SChengwen Feng { 4635357c248SChengwen Feng unsigned long val; 4645357c248SChengwen Feng char *s = NULL; 4655357c248SChengwen Feng 4665357c248SChengwen Feng if (value == NULL) { 4675357c248SChengwen Feng *(uint32_t *)arg->val_saver = (uint32_t)(intptr_t)arg->val_set; 4685357c248SChengwen Feng return 0; 4695357c248SChengwen Feng } 4705357c248SChengwen Feng 4715357c248SChengwen Feng errno = 0; 4725357c248SChengwen Feng val = strtoul(value, &s, 0); 4735357c248SChengwen Feng if (errno == ERANGE || val > UINT32_MAX) { 4745357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 4755357c248SChengwen Feng return -EINVAL; 4765357c248SChengwen Feng } 4775357c248SChengwen Feng 4785357c248SChengwen Feng if (s[0] != '\0') { 4795357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint32 value!", arg->name_long); 4805357c248SChengwen Feng return -EINVAL; 4815357c248SChengwen Feng } 4825357c248SChengwen Feng 4835357c248SChengwen Feng *(uint32_t *)arg->val_saver = val; 4845357c248SChengwen Feng 4855357c248SChengwen Feng return 0; 4865357c248SChengwen Feng } 4875357c248SChengwen Feng 4885357c248SChengwen Feng static int 4895357c248SChengwen Feng parse_arg_u64(struct rte_argparse_arg *arg, const char *value) 4905357c248SChengwen Feng { 4915357c248SChengwen Feng unsigned long val; 4925357c248SChengwen Feng char *s = NULL; 4935357c248SChengwen Feng 4945357c248SChengwen Feng if (value == NULL) { 4955357c248SChengwen Feng *(uint64_t *)arg->val_saver = (uint64_t)(intptr_t)arg->val_set; 4965357c248SChengwen Feng return 0; 4975357c248SChengwen Feng } 4985357c248SChengwen Feng 4995357c248SChengwen Feng errno = 0; 5005357c248SChengwen Feng val = strtoull(value, &s, 0); 5015357c248SChengwen Feng if (errno == ERANGE) { 5025357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long); 5035357c248SChengwen Feng return -EINVAL; 5045357c248SChengwen Feng } 5055357c248SChengwen Feng 5065357c248SChengwen Feng if (s[0] != '\0') { 5075357c248SChengwen Feng ARGPARSE_LOG(ERR, "argument %s expect an uint64 value!", arg->name_long); 5085357c248SChengwen Feng return -EINVAL; 5095357c248SChengwen Feng } 5105357c248SChengwen Feng 5115357c248SChengwen Feng *(uint64_t *)arg->val_saver = val; 5125357c248SChengwen Feng 5135357c248SChengwen Feng return 0; 5145357c248SChengwen Feng } 5155357c248SChengwen Feng 5165357c248SChengwen 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 }, 5255357c248SChengwen Feng { parse_arg_u8 }, 5265357c248SChengwen Feng { parse_arg_u16 }, 5275357c248SChengwen Feng { parse_arg_u32 }, 5285357c248SChengwen 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 643*676ca0d2SChengwen Feng static uint32_t 644*676ca0d2SChengwen Feng calc_help_align(const struct rte_argparse *obj) 645*676ca0d2SChengwen Feng { 646*676ca0d2SChengwen Feng const struct rte_argparse_arg *arg; 647*676ca0d2SChengwen Feng uint32_t width = 12; /* Default "-h, --help " len. */ 648*676ca0d2SChengwen Feng uint32_t len; 649*676ca0d2SChengwen Feng uint32_t i; 650*676ca0d2SChengwen Feng 651*676ca0d2SChengwen Feng for (i = 0; /* NULL */; i++) { 652*676ca0d2SChengwen Feng arg = &obj->args[i]; 653*676ca0d2SChengwen Feng if (arg->name_long == NULL) 654*676ca0d2SChengwen Feng break; 655*676ca0d2SChengwen Feng len = strlen(arg->name_long); 656*676ca0d2SChengwen Feng if (is_arg_optional(arg) && arg->name_short != NULL) { 657*676ca0d2SChengwen Feng len += strlen(", "); 658*676ca0d2SChengwen Feng len += strlen(arg->name_short); 659*676ca0d2SChengwen Feng } 660*676ca0d2SChengwen Feng width = RTE_MAX(width, 1 + len + 2); /* start with 1 & end with 2 space. */ 661*676ca0d2SChengwen Feng } 662*676ca0d2SChengwen Feng 663*676ca0d2SChengwen Feng return width; 664*676ca0d2SChengwen Feng } 665*676ca0d2SChengwen Feng 66631ed9f9fSChengwen Feng static void 667*676ca0d2SChengwen Feng show_oneline_help(const struct rte_argparse_arg *arg, uint32_t width) 668*676ca0d2SChengwen Feng { 669*676ca0d2SChengwen Feng uint32_t len = 0; 670*676ca0d2SChengwen Feng uint32_t i; 671*676ca0d2SChengwen Feng 672*676ca0d2SChengwen Feng if (arg->name_short != NULL) 673*676ca0d2SChengwen Feng len = printf(" %s,", arg->name_short); 674*676ca0d2SChengwen Feng len += printf(" %s", arg->name_long); 675*676ca0d2SChengwen Feng 676*676ca0d2SChengwen Feng for (i = len; i < width; i++) 677*676ca0d2SChengwen Feng printf(" "); 678*676ca0d2SChengwen Feng 679*676ca0d2SChengwen Feng printf("%s\n", arg->help); 680*676ca0d2SChengwen Feng } 681*676ca0d2SChengwen Feng 682*676ca0d2SChengwen Feng static void 683*676ca0d2SChengwen Feng show_args_pos_help(const struct rte_argparse *obj, uint32_t align) 68431ed9f9fSChengwen Feng { 68531ed9f9fSChengwen Feng uint32_t position_count = calc_position_count(obj); 68631ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 68731ed9f9fSChengwen Feng uint32_t i; 68831ed9f9fSChengwen Feng 68931ed9f9fSChengwen Feng if (position_count == 0) 69031ed9f9fSChengwen Feng return; 69131ed9f9fSChengwen Feng 69231ed9f9fSChengwen Feng printf("\npositional arguments:\n"); 69331ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 69431ed9f9fSChengwen Feng arg = &obj->args[i]; 69531ed9f9fSChengwen Feng if (arg->name_long == NULL) 69631ed9f9fSChengwen Feng break; 69731ed9f9fSChengwen Feng if (!is_arg_positional(arg)) 69831ed9f9fSChengwen Feng continue; 699*676ca0d2SChengwen Feng show_oneline_help(arg, align); 70031ed9f9fSChengwen Feng } 70131ed9f9fSChengwen Feng } 70231ed9f9fSChengwen Feng 70331ed9f9fSChengwen Feng static void 704*676ca0d2SChengwen Feng show_args_opt_help(const struct rte_argparse *obj, uint32_t align) 70531ed9f9fSChengwen Feng { 706*676ca0d2SChengwen Feng static const struct rte_argparse_arg help = { 707*676ca0d2SChengwen Feng .name_long = "--help", 708*676ca0d2SChengwen Feng .name_short = "-h", 709*676ca0d2SChengwen Feng .help = "show this help message and exit.", 710*676ca0d2SChengwen Feng }; 71131ed9f9fSChengwen Feng const struct rte_argparse_arg *arg; 71231ed9f9fSChengwen Feng uint32_t i; 71331ed9f9fSChengwen Feng 714*676ca0d2SChengwen Feng printf("\noptions:\n"); 715*676ca0d2SChengwen Feng show_oneline_help(&help, align); 71631ed9f9fSChengwen Feng for (i = 0; /* NULL */; i++) { 71731ed9f9fSChengwen Feng arg = &obj->args[i]; 71831ed9f9fSChengwen Feng if (arg->name_long == NULL) 71931ed9f9fSChengwen Feng break; 72031ed9f9fSChengwen Feng if (!is_arg_optional(arg)) 72131ed9f9fSChengwen Feng continue; 722*676ca0d2SChengwen Feng show_oneline_help(arg, align); 72331ed9f9fSChengwen Feng } 72431ed9f9fSChengwen Feng } 72531ed9f9fSChengwen Feng 72631ed9f9fSChengwen Feng static void 72731ed9f9fSChengwen Feng show_args_help(const struct rte_argparse *obj) 72831ed9f9fSChengwen Feng { 729*676ca0d2SChengwen Feng uint32_t align = calc_help_align(obj); 730*676ca0d2SChengwen Feng 73131ed9f9fSChengwen Feng printf("usage: %s %s\n", obj->prog_name, obj->usage); 73231ed9f9fSChengwen Feng if (obj->descriptor != NULL) 73331ed9f9fSChengwen Feng printf("\ndescriptor: %s\n", obj->descriptor); 73431ed9f9fSChengwen Feng 735*676ca0d2SChengwen Feng show_args_pos_help(obj, align); 736*676ca0d2SChengwen Feng show_args_opt_help(obj, align); 73731ed9f9fSChengwen Feng 73831ed9f9fSChengwen Feng if (obj->epilog != NULL) 73931ed9f9fSChengwen Feng printf("\n%s\n", obj->epilog); 740*676ca0d2SChengwen Feng else 741*676ca0d2SChengwen Feng printf("\n"); 74231ed9f9fSChengwen Feng } 74331ed9f9fSChengwen Feng 74431ed9f9fSChengwen Feng int 74531ed9f9fSChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) 74631ed9f9fSChengwen Feng { 74731ed9f9fSChengwen Feng bool show_help = false; 74831ed9f9fSChengwen Feng int ret; 7496c5c6571SChengwen Feng 7506c5c6571SChengwen Feng ret = verify_argparse(obj); 7516c5c6571SChengwen Feng if (ret != 0) 7526c5c6571SChengwen Feng goto error; 7536c5c6571SChengwen Feng 75431ed9f9fSChengwen Feng ret = parse_args(obj, argc, argv, &show_help); 75531ed9f9fSChengwen Feng if (ret != 0) 75631ed9f9fSChengwen Feng goto error; 75731ed9f9fSChengwen Feng 75831ed9f9fSChengwen Feng if (show_help) { 75931ed9f9fSChengwen Feng show_args_help(obj); 76031ed9f9fSChengwen Feng exit(0); 76131ed9f9fSChengwen Feng } 76231ed9f9fSChengwen Feng 763e3e579f5SChengwen Feng return 0; 7646c5c6571SChengwen Feng 7656c5c6571SChengwen Feng error: 7666c5c6571SChengwen Feng if (obj->exit_on_error) 7676c5c6571SChengwen Feng exit(ret); 7686c5c6571SChengwen Feng return ret; 769e3e579f5SChengwen Feng } 7709ccd7b27SChengwen Feng 7719ccd7b27SChengwen Feng int 7729ccd7b27SChengwen Feng rte_argparse_parse_type(const char *str, uint64_t val_type, void *val) 7739ccd7b27SChengwen Feng { 7749ccd7b27SChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); 7759ccd7b27SChengwen Feng struct rte_argparse_arg arg = { 7769ccd7b27SChengwen Feng .name_long = str, 7779ccd7b27SChengwen Feng .name_short = NULL, 7789ccd7b27SChengwen Feng .val_saver = val, 7799ccd7b27SChengwen Feng .val_set = NULL, 7809ccd7b27SChengwen Feng .flags = val_type, 7819ccd7b27SChengwen Feng }; 7829ccd7b27SChengwen Feng uint32_t value_type = arg_attr_val_type(&arg); 7839ccd7b27SChengwen Feng 7849ccd7b27SChengwen Feng if (value_type == 0 || value_type >= cmp_max) 7859ccd7b27SChengwen Feng return -EINVAL; 7869ccd7b27SChengwen Feng 7879ccd7b27SChengwen Feng return parse_arg_autosave(&arg, str); 7889ccd7b27SChengwen Feng } 789