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