1e3e579f5SChengwen Feng /* SPDX-License-Identifier: BSD-3-Clause 2e3e579f5SChengwen Feng * Copyright(c) 2024 HiSilicon Limited 3e3e579f5SChengwen Feng */ 4e3e579f5SChengwen Feng 5*6c5c6571SChengwen Feng #include <errno.h> 6*6c5c6571SChengwen Feng #include <stdlib.h> 7*6c5c6571SChengwen Feng #include <string.h> 8*6c5c6571SChengwen Feng 9*6c5c6571SChengwen Feng #include <rte_log.h> 10*6c5c6571SChengwen Feng 11e3e579f5SChengwen Feng #include "rte_argparse.h" 12e3e579f5SChengwen Feng 13*6c5c6571SChengwen Feng RTE_LOG_REGISTER_DEFAULT(rte_argparse_logtype, INFO); 14*6c5c6571SChengwen Feng #define RTE_LOGTYPE_ARGPARSE rte_argparse_logtype 15*6c5c6571SChengwen Feng #define ARGPARSE_LOG(level, ...) \ 16*6c5c6571SChengwen Feng RTE_LOG_LINE(level, ARGPARSE, "" __VA_ARGS__) 17*6c5c6571SChengwen Feng 18*6c5c6571SChengwen Feng #define ARG_ATTR_HAS_VAL_MASK RTE_GENMASK64(1, 0) 19*6c5c6571SChengwen Feng #define ARG_ATTR_VAL_TYPE_MASK RTE_GENMASK64(9, 2) 20*6c5c6571SChengwen Feng #define ARG_ATTR_SUPPORT_MULTI_MASK RTE_BIT64(10) 21*6c5c6571SChengwen Feng #define ARG_ATTR_FLAG_PARSED_MASK RTE_BIT64(63) 22*6c5c6571SChengwen Feng 23*6c5c6571SChengwen Feng static inline bool 24*6c5c6571SChengwen Feng is_arg_optional(const struct rte_argparse_arg *arg) 25*6c5c6571SChengwen Feng { 26*6c5c6571SChengwen Feng return arg->name_long[0] == '-'; 27*6c5c6571SChengwen Feng } 28*6c5c6571SChengwen Feng 29*6c5c6571SChengwen Feng static inline bool 30*6c5c6571SChengwen Feng is_arg_positional(const struct rte_argparse_arg *arg) 31*6c5c6571SChengwen Feng { 32*6c5c6571SChengwen Feng return arg->name_long[0] != '-'; 33*6c5c6571SChengwen Feng } 34*6c5c6571SChengwen Feng 35*6c5c6571SChengwen Feng static inline uint32_t 36*6c5c6571SChengwen Feng arg_attr_has_val(const struct rte_argparse_arg *arg) 37*6c5c6571SChengwen Feng { 38*6c5c6571SChengwen Feng return RTE_FIELD_GET64(ARG_ATTR_HAS_VAL_MASK, arg->flags); 39*6c5c6571SChengwen Feng } 40*6c5c6571SChengwen Feng 41*6c5c6571SChengwen Feng static inline uint32_t 42*6c5c6571SChengwen Feng arg_attr_val_type(const struct rte_argparse_arg *arg) 43*6c5c6571SChengwen Feng { 44*6c5c6571SChengwen Feng return RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, arg->flags); 45*6c5c6571SChengwen Feng } 46*6c5c6571SChengwen Feng 47*6c5c6571SChengwen Feng static inline uint32_t 48*6c5c6571SChengwen Feng arg_attr_unused_bits(const struct rte_argparse_arg *arg) 49*6c5c6571SChengwen Feng { 50*6c5c6571SChengwen Feng #define USED_BIT_MASK (ARG_ATTR_HAS_VAL_MASK | ARG_ATTR_VAL_TYPE_MASK | \ 51*6c5c6571SChengwen Feng ARG_ATTR_SUPPORT_MULTI_MASK) 52*6c5c6571SChengwen Feng return arg->flags & ~USED_BIT_MASK; 53*6c5c6571SChengwen Feng } 54*6c5c6571SChengwen Feng 55*6c5c6571SChengwen Feng static int 56*6c5c6571SChengwen Feng verify_arg_name(const struct rte_argparse_arg *arg) 57*6c5c6571SChengwen Feng { 58*6c5c6571SChengwen Feng if (is_arg_optional(arg)) { 59*6c5c6571SChengwen Feng if (strlen(arg->name_long) <= 3) { 60*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long); 61*6c5c6571SChengwen Feng return -EINVAL; 62*6c5c6571SChengwen Feng } 63*6c5c6571SChengwen Feng if (arg->name_long[1] != '-') { 64*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s must only start with '--'", 65*6c5c6571SChengwen Feng arg->name_long); 66*6c5c6571SChengwen Feng return -EINVAL; 67*6c5c6571SChengwen Feng } 68*6c5c6571SChengwen Feng if (arg->name_long[2] == '-') { 69*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'", 70*6c5c6571SChengwen Feng arg->name_long); 71*6c5c6571SChengwen Feng return -EINVAL; 72*6c5c6571SChengwen Feng } 73*6c5c6571SChengwen Feng } 74*6c5c6571SChengwen Feng 75*6c5c6571SChengwen Feng if (arg->name_short == NULL) 76*6c5c6571SChengwen Feng return 0; 77*6c5c6571SChengwen Feng 78*6c5c6571SChengwen Feng if (!is_arg_optional(arg)) { 79*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!", 80*6c5c6571SChengwen Feng arg->name_short); 81*6c5c6571SChengwen Feng return -EINVAL; 82*6c5c6571SChengwen Feng } 83*6c5c6571SChengwen Feng 84*6c5c6571SChengwen Feng if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' || 85*6c5c6571SChengwen Feng arg->name_short[1] == '-') { 86*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter", 87*6c5c6571SChengwen Feng arg->name_short); 88*6c5c6571SChengwen Feng return -EINVAL; 89*6c5c6571SChengwen Feng } 90*6c5c6571SChengwen Feng 91*6c5c6571SChengwen Feng return 0; 92*6c5c6571SChengwen Feng } 93*6c5c6571SChengwen Feng 94*6c5c6571SChengwen Feng static int 95*6c5c6571SChengwen Feng verify_arg_help(const struct rte_argparse_arg *arg) 96*6c5c6571SChengwen Feng { 97*6c5c6571SChengwen Feng if (arg->help == NULL) { 98*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s must have help info!", arg->name_long); 99*6c5c6571SChengwen Feng return -EINVAL; 100*6c5c6571SChengwen Feng } 101*6c5c6571SChengwen Feng 102*6c5c6571SChengwen Feng return 0; 103*6c5c6571SChengwen Feng } 104*6c5c6571SChengwen Feng 105*6c5c6571SChengwen Feng static int 106*6c5c6571SChengwen Feng verify_arg_has_val(const struct rte_argparse_arg *arg) 107*6c5c6571SChengwen Feng { 108*6c5c6571SChengwen Feng uint32_t has_val = arg_attr_has_val(arg); 109*6c5c6571SChengwen Feng 110*6c5c6571SChengwen Feng if (is_arg_positional(arg)) { 111*6c5c6571SChengwen Feng if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE) 112*6c5c6571SChengwen Feng return 0; 113*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s is positional, should has zero or required-val!", 114*6c5c6571SChengwen Feng arg->name_long); 115*6c5c6571SChengwen Feng return -EINVAL; 116*6c5c6571SChengwen Feng } 117*6c5c6571SChengwen Feng 118*6c5c6571SChengwen Feng if (has_val == 0) { 119*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s is optional, has-val config wrong!", 120*6c5c6571SChengwen Feng arg->name_long); 121*6c5c6571SChengwen Feng return -EINVAL; 122*6c5c6571SChengwen Feng } 123*6c5c6571SChengwen Feng 124*6c5c6571SChengwen Feng return 0; 125*6c5c6571SChengwen Feng } 126*6c5c6571SChengwen Feng 127*6c5c6571SChengwen Feng static int 128*6c5c6571SChengwen Feng verify_arg_saver(const struct rte_argparse *obj, uint32_t index) 129*6c5c6571SChengwen Feng { 130*6c5c6571SChengwen Feng uint32_t cmp_max = RTE_FIELD_GET64(ARG_ATTR_VAL_TYPE_MASK, RTE_ARGPARSE_ARG_VALUE_MAX); 131*6c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 132*6c5c6571SChengwen Feng uint32_t val_type = arg_attr_val_type(arg); 133*6c5c6571SChengwen Feng uint32_t has_val = arg_attr_has_val(arg); 134*6c5c6571SChengwen Feng 135*6c5c6571SChengwen Feng if (arg->val_saver == NULL) { 136*6c5c6571SChengwen Feng if (val_type != 0) { 137*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse by callback, val-type must be zero!", 138*6c5c6571SChengwen Feng arg->name_long); 139*6c5c6571SChengwen Feng return -EINVAL; 140*6c5c6571SChengwen Feng } 141*6c5c6571SChengwen Feng 142*6c5c6571SChengwen Feng if (obj->callback == NULL) { 143*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s parse by callback, but callback is NULL!", 144*6c5c6571SChengwen Feng arg->name_long); 145*6c5c6571SChengwen Feng return -EINVAL; 146*6c5c6571SChengwen Feng } 147*6c5c6571SChengwen Feng 148*6c5c6571SChengwen Feng return 0; 149*6c5c6571SChengwen Feng } 150*6c5c6571SChengwen Feng 151*6c5c6571SChengwen Feng if (val_type == 0 || val_type >= cmp_max) { 152*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s val-type config wrong!", arg->name_long); 153*6c5c6571SChengwen Feng return -EINVAL; 154*6c5c6571SChengwen Feng } 155*6c5c6571SChengwen Feng 156*6c5c6571SChengwen Feng if (has_val == RTE_ARGPARSE_ARG_REQUIRED_VALUE && arg->val_set != NULL) { 157*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s has required value, val-set should be NULL!", 158*6c5c6571SChengwen Feng arg->name_long); 159*6c5c6571SChengwen Feng return -EINVAL; 160*6c5c6571SChengwen Feng } 161*6c5c6571SChengwen Feng 162*6c5c6571SChengwen Feng return 0; 163*6c5c6571SChengwen Feng } 164*6c5c6571SChengwen Feng 165*6c5c6571SChengwen Feng static int 166*6c5c6571SChengwen Feng verify_arg_flags(const struct rte_argparse *obj, uint32_t index) 167*6c5c6571SChengwen Feng { 168*6c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 169*6c5c6571SChengwen Feng uint32_t unused_bits = arg_attr_unused_bits(arg); 170*6c5c6571SChengwen Feng 171*6c5c6571SChengwen Feng if (unused_bits != 0) { 172*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s flags set wrong!", arg->name_long); 173*6c5c6571SChengwen Feng return -EINVAL; 174*6c5c6571SChengwen Feng } 175*6c5c6571SChengwen Feng 176*6c5c6571SChengwen Feng if (!(arg->flags & RTE_ARGPARSE_ARG_SUPPORT_MULTI)) 177*6c5c6571SChengwen Feng return 0; 178*6c5c6571SChengwen Feng 179*6c5c6571SChengwen Feng if (is_arg_positional(arg)) { 180*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!", 181*6c5c6571SChengwen Feng arg->name_long); 182*6c5c6571SChengwen Feng return -EINVAL; 183*6c5c6571SChengwen Feng } 184*6c5c6571SChengwen Feng 185*6c5c6571SChengwen Feng if (arg->val_saver != NULL) { 186*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s could occur multiple times, should use callback to parse!", 187*6c5c6571SChengwen Feng arg->name_long); 188*6c5c6571SChengwen Feng return -EINVAL; 189*6c5c6571SChengwen Feng } 190*6c5c6571SChengwen Feng 191*6c5c6571SChengwen Feng if (obj->callback == NULL) { 192*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s should use callback to parse, but callback is NULL!", 193*6c5c6571SChengwen Feng arg->name_long); 194*6c5c6571SChengwen Feng return -EINVAL; 195*6c5c6571SChengwen Feng } 196*6c5c6571SChengwen Feng 197*6c5c6571SChengwen Feng return 0; 198*6c5c6571SChengwen Feng } 199*6c5c6571SChengwen Feng 200*6c5c6571SChengwen Feng static int 201*6c5c6571SChengwen Feng verify_arg_repeat(const struct rte_argparse *self, uint32_t index) 202*6c5c6571SChengwen Feng { 203*6c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &self->args[index]; 204*6c5c6571SChengwen Feng uint32_t i; 205*6c5c6571SChengwen Feng 206*6c5c6571SChengwen Feng for (i = 0; i < index; i++) { 207*6c5c6571SChengwen Feng if (!strcmp(arg->name_long, self->args[i].name_long)) { 208*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long); 209*6c5c6571SChengwen Feng return -EINVAL; 210*6c5c6571SChengwen Feng } 211*6c5c6571SChengwen Feng } 212*6c5c6571SChengwen Feng 213*6c5c6571SChengwen Feng if (arg->name_short == NULL) 214*6c5c6571SChengwen Feng return 0; 215*6c5c6571SChengwen Feng 216*6c5c6571SChengwen Feng for (i = 0; i < index; i++) { 217*6c5c6571SChengwen Feng if (self->args[i].name_short == NULL) 218*6c5c6571SChengwen Feng continue; 219*6c5c6571SChengwen Feng if (!strcmp(arg->name_short, self->args[i].name_short)) { 220*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short); 221*6c5c6571SChengwen Feng return -EINVAL; 222*6c5c6571SChengwen Feng } 223*6c5c6571SChengwen Feng } 224*6c5c6571SChengwen Feng 225*6c5c6571SChengwen Feng return 0; 226*6c5c6571SChengwen Feng } 227*6c5c6571SChengwen Feng 228*6c5c6571SChengwen Feng static int 229*6c5c6571SChengwen Feng verify_argparse_arg(const struct rte_argparse *obj, uint32_t index) 230*6c5c6571SChengwen Feng { 231*6c5c6571SChengwen Feng const struct rte_argparse_arg *arg = &obj->args[index]; 232*6c5c6571SChengwen Feng int ret; 233*6c5c6571SChengwen Feng 234*6c5c6571SChengwen Feng ret = verify_arg_name(arg); 235*6c5c6571SChengwen Feng if (ret != 0) 236*6c5c6571SChengwen Feng return ret; 237*6c5c6571SChengwen Feng 238*6c5c6571SChengwen Feng ret = verify_arg_help(arg); 239*6c5c6571SChengwen Feng if (ret != 0) 240*6c5c6571SChengwen Feng return ret; 241*6c5c6571SChengwen Feng 242*6c5c6571SChengwen Feng ret = verify_arg_has_val(arg); 243*6c5c6571SChengwen Feng if (ret != 0) 244*6c5c6571SChengwen Feng return ret; 245*6c5c6571SChengwen Feng 246*6c5c6571SChengwen Feng ret = verify_arg_saver(obj, index); 247*6c5c6571SChengwen Feng if (ret != 0) 248*6c5c6571SChengwen Feng return ret; 249*6c5c6571SChengwen Feng 250*6c5c6571SChengwen Feng ret = verify_arg_flags(obj, index); 251*6c5c6571SChengwen Feng if (ret != 0) 252*6c5c6571SChengwen Feng return ret; 253*6c5c6571SChengwen Feng 254*6c5c6571SChengwen Feng ret = verify_arg_repeat(obj, index); 255*6c5c6571SChengwen Feng if (ret != 0) 256*6c5c6571SChengwen Feng return ret; 257*6c5c6571SChengwen Feng 258*6c5c6571SChengwen Feng return 0; 259*6c5c6571SChengwen Feng } 260*6c5c6571SChengwen Feng 261*6c5c6571SChengwen Feng static int 262*6c5c6571SChengwen Feng verify_argparse(const struct rte_argparse *obj) 263*6c5c6571SChengwen Feng { 264*6c5c6571SChengwen Feng uint32_t idx; 265*6c5c6571SChengwen Feng int ret; 266*6c5c6571SChengwen Feng 267*6c5c6571SChengwen Feng if (obj->prog_name == NULL) { 268*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "program name is NULL!"); 269*6c5c6571SChengwen Feng return -EINVAL; 270*6c5c6571SChengwen Feng } 271*6c5c6571SChengwen Feng 272*6c5c6571SChengwen Feng if (obj->usage == NULL) { 273*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "usage is NULL!"); 274*6c5c6571SChengwen Feng return -EINVAL; 275*6c5c6571SChengwen Feng } 276*6c5c6571SChengwen Feng 277*6c5c6571SChengwen Feng for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) { 278*6c5c6571SChengwen Feng if (obj->reserved[idx] != 0) { 279*6c5c6571SChengwen Feng ARGPARSE_LOG(ERR, "reserved field must be zero!"); 280*6c5c6571SChengwen Feng return -EINVAL; 281*6c5c6571SChengwen Feng } 282*6c5c6571SChengwen Feng } 283*6c5c6571SChengwen Feng 284*6c5c6571SChengwen Feng idx = 0; 285*6c5c6571SChengwen Feng while (obj->args[idx].name_long != NULL) { 286*6c5c6571SChengwen Feng ret = verify_argparse_arg(obj, idx); 287*6c5c6571SChengwen Feng if (ret != 0) 288*6c5c6571SChengwen Feng return ret; 289*6c5c6571SChengwen Feng idx++; 290*6c5c6571SChengwen Feng } 291*6c5c6571SChengwen Feng 292*6c5c6571SChengwen Feng return 0; 293*6c5c6571SChengwen Feng } 294*6c5c6571SChengwen Feng 295e3e579f5SChengwen Feng int 296e3e579f5SChengwen Feng rte_argparse_parse(struct rte_argparse *obj, int argc, char **argv) 297e3e579f5SChengwen Feng { 298*6c5c6571SChengwen Feng int ret; 299*6c5c6571SChengwen Feng 300e3e579f5SChengwen Feng (void)argc; 301e3e579f5SChengwen Feng (void)argv; 302*6c5c6571SChengwen Feng 303*6c5c6571SChengwen Feng ret = verify_argparse(obj); 304*6c5c6571SChengwen Feng if (ret != 0) 305*6c5c6571SChengwen Feng goto error; 306*6c5c6571SChengwen Feng 307e3e579f5SChengwen Feng return 0; 308*6c5c6571SChengwen Feng 309*6c5c6571SChengwen Feng error: 310*6c5c6571SChengwen Feng if (obj->exit_on_error) 311*6c5c6571SChengwen Feng exit(ret); 312*6c5c6571SChengwen Feng return ret; 313e3e579f5SChengwen Feng } 314