Branch data Line data Source code
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 : : #include <ctype.h>
9 : :
10 : : #include <eal_export.h>
11 : : #include <rte_log.h>
12 : : #include <rte_os.h>
13 : :
14 : : #include "rte_argparse.h"
15 : :
16 [ - + ]: 253 : RTE_LOG_REGISTER_DEFAULT(rte_argparse_logtype, INFO);
17 : : #define RTE_LOGTYPE_ARGPARSE rte_argparse_logtype
18 : : #define ARGPARSE_LOG(level, ...) \
19 : : RTE_LOG_LINE(level, ARGPARSE, "" __VA_ARGS__)
20 : :
21 : : static inline bool
22 : : is_arg_optional(const struct rte_argparse_arg *arg)
23 : : {
24 : 12483 : return arg->name_long[0] == '-';
25 : : }
26 : :
27 : : static inline bool
28 : : is_arg_positional(const struct rte_argparse_arg *arg)
29 : : {
30 : 38950 : return arg->name_long[0] != '-';
31 : : }
32 : :
33 : : static inline bool
34 : : is_valid_has_value_field(const struct rte_argparse_arg *arg)
35 : : {
36 : 12475 : switch (arg->value_required) {
37 : : case RTE_ARGPARSE_VALUE_NONE:
38 : : case RTE_ARGPARSE_VALUE_OPTIONAL:
39 : : case RTE_ARGPARSE_VALUE_REQUIRED:
40 : : return true;
41 : : /* omit default case so compiler warns on any missing enum values */
42 : : }
43 : : return false;
44 : : }
45 : :
46 : : static inline bool
47 : : is_valid_value_type_field(const struct rte_argparse_arg *arg)
48 : : {
49 [ + - ]: 10913 : switch (arg->value_type) {
50 : : case RTE_ARGPARSE_VALUE_TYPE_NONE:
51 : : case RTE_ARGPARSE_VALUE_TYPE_INT:
52 : : case RTE_ARGPARSE_VALUE_TYPE_U8:
53 : : case RTE_ARGPARSE_VALUE_TYPE_U16:
54 : : case RTE_ARGPARSE_VALUE_TYPE_U32:
55 : : case RTE_ARGPARSE_VALUE_TYPE_U64:
56 : : case RTE_ARGPARSE_VALUE_TYPE_STR:
57 : : case RTE_ARGPARSE_VALUE_TYPE_BOOL:
58 : : case RTE_ARGPARSE_VALUE_TYPE_CORELIST:
59 : : return true;
60 : : /* omit default case so compiler warns on any missing enum values */
61 : : }
62 : : return false;
63 : : }
64 : :
65 : :
66 : : static inline bool
67 : : arg_attr_flag_multi(const struct rte_argparse_arg *arg)
68 : : {
69 : 8 : return (arg->flags & RTE_ARGPARSE_FLAG_SUPPORT_MULTI) != 0;
70 : : }
71 : :
72 : : static inline uint64_t
73 : : arg_attr_unused_bits(const struct rte_argparse_arg *arg)
74 : : {
75 : : #define USED_BIT_MASK (RTE_ARGPARSE_FLAG_SUPPORT_MULTI)
76 : 12463 : return arg->flags & ~USED_BIT_MASK;
77 : : }
78 : :
79 : : static int
80 : 12483 : verify_arg_name(const struct rte_argparse_arg *arg)
81 : : {
82 [ + + ]: 12483 : if (is_arg_optional(arg)) {
83 [ + + ]: 12472 : if (strlen(arg->name_long) <= 3) {
84 : 1 : ARGPARSE_LOG(ERR, "optional long name %s too short!", arg->name_long);
85 : 1 : return -EINVAL;
86 : : }
87 [ + + ]: 12471 : if (arg->name_long[1] != '-') {
88 : 1 : ARGPARSE_LOG(ERR, "optional long name %s doesn't start with '--'",
89 : : arg->name_long);
90 : 1 : return -EINVAL;
91 : : }
92 [ + + ]: 12470 : if (arg->name_long[2] == '-') {
93 : 1 : ARGPARSE_LOG(ERR, "optional long name %s should not start with '---'",
94 : : arg->name_long);
95 : 1 : return -EINVAL;
96 : : }
97 : : }
98 : :
99 [ + + ]: 12480 : if (arg->name_short == NULL)
100 : : return 0;
101 : :
102 [ + + ]: 3109 : if (!is_arg_optional(arg)) {
103 : 1 : ARGPARSE_LOG(ERR, "short name %s corresponding long name must be optional!",
104 : : arg->name_short);
105 : 1 : return -EINVAL;
106 : : }
107 : :
108 [ + + + + ]: 3108 : if (strlen(arg->name_short) != 2 || arg->name_short[0] != '-' ||
109 [ - + ]: 3105 : arg->name_short[1] == '-') {
110 : 3 : ARGPARSE_LOG(ERR, "short name %s must start with a hyphen (-) followed by an English letter",
111 : : arg->name_short);
112 : 3 : return -EINVAL;
113 : : }
114 : :
115 : : return 0;
116 : : }
117 : :
118 : : static int
119 : : verify_arg_help(const struct rte_argparse_arg *arg)
120 : : {
121 [ + + ]: 12476 : if (arg->help == NULL) {
122 : 1 : ARGPARSE_LOG(ERR, "argument %s doesn't have help info!", arg->name_long);
123 : : return -EINVAL;
124 : : }
125 : :
126 : : return 0;
127 : : }
128 : :
129 : : static int
130 [ + - ]: 12475 : verify_arg_has_val(const struct rte_argparse_arg *arg)
131 : : {
132 : : if (!is_valid_has_value_field(arg)) {
133 : 0 : ARGPARSE_LOG(ERR, "argument %s has invalid value field!", arg->name_long);
134 : 0 : return -EINVAL;
135 : : }
136 [ + + ]: 12475 : if (is_arg_positional(arg)) {
137 [ + + ]: 10 : if (arg->value_required == RTE_ARGPARSE_VALUE_REQUIRED)
138 : : return 0;
139 : 2 : ARGPARSE_LOG(ERR, "argument %s is positional, must config required-val!",
140 : : arg->name_long);
141 : 2 : return -EINVAL;
142 : : }
143 : :
144 : : return 0;
145 : : }
146 : :
147 : : static int
148 : 12473 : verify_arg_saver(const struct rte_argparse *obj, uint32_t index)
149 : : {
150 : : const struct rte_argparse_arg *arg = &obj->args[index];
151 : :
152 [ + + ]: 12473 : if (arg->val_saver == NULL) {
153 [ + + ]: 1560 : if (arg->value_type != RTE_ARGPARSE_VALUE_TYPE_NONE) {
154 : 1 : ARGPARSE_LOG(ERR, "argument %s parsed by callback, value-type should not be set!",
155 : : arg->name_long);
156 : 1 : return -EINVAL;
157 : : }
158 [ + + ]: 1559 : if (obj->callback == NULL) {
159 : 1 : ARGPARSE_LOG(ERR, "argument %s parsed by callback, but callback is NULL!",
160 : : arg->name_long);
161 : 1 : return -EINVAL;
162 : : }
163 : : return 0;
164 : : }
165 : :
166 : : /* check value_type field */
167 : : if (!is_valid_value_type_field(arg)) {
168 : 0 : ARGPARSE_LOG(ERR, "argument %s has invalid value-type field!", arg->name_long);
169 : 0 : return -EINVAL;
170 : : }
171 [ + + ]: 10913 : if (arg->value_type == RTE_ARGPARSE_VALUE_TYPE_NONE) {
172 : 7 : ARGPARSE_LOG(ERR, "missing value-type for argument %s!", arg->name_long);
173 : 7 : return -EINVAL;
174 : : }
175 : :
176 [ + + + + ]: 10906 : if (arg->value_required == RTE_ARGPARSE_VALUE_REQUIRED && arg->val_set != NULL) {
177 : 1 : ARGPARSE_LOG(ERR, "argument %s has required value, value-set should be NULL!",
178 : : arg->name_long);
179 : 1 : return -EINVAL;
180 : : }
181 : :
182 : : return 0;
183 : : }
184 : :
185 : : static int
186 : 12463 : verify_arg_flags(const struct rte_argparse *obj, uint32_t index)
187 : : {
188 : : const struct rte_argparse_arg *arg = &obj->args[index];
189 : : uint64_t unused_bits = arg_attr_unused_bits(arg);
190 : :
191 [ - + ]: 12463 : if (unused_bits != 0) {
192 : 0 : ARGPARSE_LOG(ERR, "argument %s flags unused bits should not be set!",
193 : : arg->name_long);
194 : 0 : return -EINVAL;
195 : : }
196 : :
197 [ + + ]: 12463 : if (!(arg->flags & RTE_ARGPARSE_FLAG_SUPPORT_MULTI))
198 : : return 0;
199 : :
200 [ + + ]: 1520 : if (is_arg_positional(arg)) {
201 : 1 : ARGPARSE_LOG(ERR, "argument %s is positional, don't support multiple times!",
202 : : arg->name_long);
203 : 1 : return -EINVAL;
204 : : }
205 : :
206 [ - + ]: 1519 : if (arg->val_saver != NULL) {
207 : 0 : ARGPARSE_LOG(ERR, "argument %s supports multiple times, should use callback to parse!",
208 : : arg->name_long);
209 : 0 : return -EINVAL;
210 : : }
211 : :
212 : : return 0;
213 : : }
214 : :
215 : : static int
216 : 12462 : verify_arg_repeat(const struct rte_argparse *self, uint32_t index)
217 : : {
218 : : const struct rte_argparse_arg *arg = &self->args[index];
219 : : uint32_t i;
220 : :
221 [ + + ]: 310006 : for (i = 0; i < index; i++) {
222 [ - + ]: 297544 : if (!strcmp(arg->name_long, self->args[i].name_long)) {
223 : 0 : ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_long);
224 : 0 : return -EINVAL;
225 : : }
226 : : }
227 : :
228 [ + + ]: 12462 : if (arg->name_short == NULL)
229 : : return 0;
230 : :
231 [ + + ]: 48395 : for (i = 0; i < index; i++) {
232 [ + + ]: 45301 : if (self->args[i].name_short == NULL)
233 : 28589 : continue;
234 [ - + ]: 16712 : if (!strcmp(arg->name_short, self->args[i].name_short)) {
235 : 0 : ARGPARSE_LOG(ERR, "argument %s repeat!", arg->name_short);
236 : 0 : return -EINVAL;
237 : : }
238 : : }
239 : :
240 : : return 0;
241 : : }
242 : :
243 : : static int
244 : 12483 : verify_argparse_arg(const struct rte_argparse *obj, uint32_t index)
245 : : {
246 : 12483 : const struct rte_argparse_arg *arg = &obj->args[index];
247 : : int ret;
248 : :
249 : 12483 : ret = verify_arg_name(arg);
250 [ + + ]: 12483 : if (ret != 0)
251 : : return ret;
252 : :
253 : : ret = verify_arg_help(arg);
254 : : if (ret != 0)
255 : 1 : return ret;
256 : :
257 : 12475 : ret = verify_arg_has_val(arg);
258 [ + + ]: 12475 : if (ret != 0)
259 : : return ret;
260 : :
261 : 12473 : ret = verify_arg_saver(obj, index);
262 [ + + ]: 12473 : if (ret != 0)
263 : : return ret;
264 : :
265 : 12463 : ret = verify_arg_flags(obj, index);
266 [ + + ]: 12463 : if (ret != 0)
267 : : return ret;
268 : :
269 : 12462 : ret = verify_arg_repeat(obj, index);
270 [ - + ]: 12462 : if (ret != 0)
271 : 0 : return ret;
272 : :
273 : : return 0;
274 : : }
275 : :
276 : : static int
277 : 326 : verify_argparse(const struct rte_argparse *obj, size_t *nb_args)
278 : : {
279 : : size_t idx;
280 : : int ret;
281 : :
282 [ + + ]: 326 : if (obj->prog_name == NULL) {
283 : 1 : ARGPARSE_LOG(ERR, "program name is NULL!");
284 : 1 : return -EINVAL;
285 : : }
286 : :
287 [ + + ]: 325 : if (obj->usage == NULL) {
288 : 1 : ARGPARSE_LOG(ERR, "usage is NULL!");
289 : 1 : return -EINVAL;
290 : : }
291 : :
292 [ + + ]: 2268 : for (idx = 0; idx < RTE_DIM(obj->reserved_flags); idx++) {
293 [ - + ]: 1944 : if (obj->reserved_flags[idx]) {
294 : 0 : ARGPARSE_LOG(ERR, "reserved flags cannot be set!");
295 : 0 : return -EINVAL;
296 : : }
297 : : }
298 : :
299 [ + + ]: 5184 : for (idx = 0; idx < RTE_DIM(obj->reserved); idx++) {
300 [ - + ]: 4860 : if (obj->reserved[idx] != 0) {
301 : 0 : ARGPARSE_LOG(ERR, "reserved field must be zero!");
302 : 0 : return -EINVAL;
303 : : }
304 : : }
305 : :
306 : : idx = 0;
307 [ + + ]: 12786 : while (obj->args[idx].name_long != NULL) {
308 [ + + + + ]: 12484 : if (is_arg_positional(&obj->args[idx]) && obj->ignore_non_flag_args) {
309 : 1 : ARGPARSE_LOG(ERR, "Error validating argparse object: positional args are not allowed when ignore_non_flag_args is set!");
310 : 1 : return -EINVAL;
311 : : }
312 : 12483 : ret = verify_argparse_arg(obj, idx);
313 [ + + ]: 12483 : if (ret != 0)
314 : 21 : return ret;
315 : 12462 : idx++;
316 : : }
317 : 302 : *nb_args = idx;
318 : :
319 : 302 : return 0;
320 : : }
321 : :
322 : : static uint32_t
323 : : calc_position_count(const struct rte_argparse *obj)
324 : : {
325 : : const struct rte_argparse_arg *arg;
326 : : uint32_t count = 0;
327 : : uint32_t i;
328 : :
329 : 12462 : for (i = 0; /* NULL */; i++) {
330 : 12462 : arg = &obj->args[i];
331 [ - - + + ]: 12764 : if (obj->args[i].name_long == NULL)
332 : : break;
333 [ - - + + ]: 12462 : if (is_arg_positional(arg))
334 : 7 : count++;
335 : : }
336 : :
337 : : return count;
338 : : }
339 : :
340 : : static const struct rte_argparse_arg *
341 : : find_position_arg(const struct rte_argparse *obj, uint32_t index)
342 : : {
343 : : const struct rte_argparse_arg *arg;
344 : : uint32_t count = 0;
345 : : uint32_t i;
346 : :
347 : 2 : for (i = 0; /* NULL */; i++) {
348 : 9 : arg = &obj->args[i];
349 [ + - ]: 9 : if (arg->name_long == NULL)
350 : : break;
351 [ - + ]: 9 : if (!is_arg_positional(arg))
352 : 0 : continue;
353 : 9 : count++;
354 [ + + ]: 9 : if (count == index)
355 : : return arg;
356 : : }
357 : :
358 : : return NULL;
359 : : }
360 : :
361 : : static bool
362 : 14376 : is_arg_match(const struct rte_argparse_arg *arg, const char *curr_argv, uint32_t len)
363 : : {
364 [ + + + + ]: 14376 : if (strlen(arg->name_long) == len && strncmp(arg->name_long, curr_argv, len) == 0)
365 : : return true;
366 : :
367 [ + + ]: 13949 : if (arg->name_short == NULL)
368 : : return false;
369 : :
370 [ + + + + ]: 4938 : if (strlen(arg->name_short) == len && strncmp(arg->name_short, curr_argv, len) == 0)
371 : 199 : return true;
372 : :
373 : : return false;
374 : : }
375 : :
376 : : static const struct rte_argparse_arg *
377 : 627 : find_option_arg(const struct rte_argparse *obj, uint32_t *idx,
378 : : const char *curr_argv, const char *has_equal, const char **arg_name)
379 : : {
380 [ + + ]: 627 : uint32_t len = strlen(curr_argv) - (has_equal != NULL ? strlen(has_equal) : 0);
381 : : const struct rte_argparse_arg *arg;
382 : : uint32_t i;
383 : : bool match;
384 : :
385 : 13750 : for (i = 0; /* nothing */; i++) {
386 : 14377 : arg = &obj->args[i];
387 [ + + ]: 14377 : if (arg->name_long == NULL)
388 : : break;
389 : 14376 : match = is_arg_match(arg, curr_argv, len);
390 [ + + ]: 14376 : if (match) {
391 : : /* Obtains the exact matching name (long or short). */
392 [ + + ]: 626 : *arg_name = len > 2 ? arg->name_long : arg->name_short;
393 : 626 : *idx = i;
394 : 626 : return arg;
395 : : }
396 : : }
397 : :
398 : : return NULL;
399 : : }
400 : :
401 : : static int
402 : 26 : parse_arg_int(const struct rte_argparse_arg *arg, const char *value)
403 : : {
404 : 26 : char *s = NULL;
405 : :
406 [ + + ]: 26 : if (value == NULL) {
407 : 5 : *(int *)arg->val_saver = (int)(intptr_t)arg->val_set;
408 : 5 : return 0;
409 : : }
410 : :
411 : 21 : errno = 0;
412 : 21 : *(int *)arg->val_saver = strtol(value, &s, 0);
413 [ + + ]: 21 : if (errno == ERANGE) {
414 : 1 : ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
415 : 1 : return -EINVAL;
416 : : }
417 : :
418 [ + + ]: 20 : if (s[0] != '\0') {
419 : 5 : ARGPARSE_LOG(ERR, "argument %s expect an integer value!", arg->name_long);
420 : 5 : return -EINVAL;
421 : : }
422 : :
423 : : return 0;
424 : : }
425 : :
426 : : static int
427 : 4 : parse_arg_u8(const struct rte_argparse_arg *arg, const char *value)
428 : : {
429 : : unsigned long val;
430 : 4 : char *s = NULL;
431 : :
432 [ - + ]: 4 : if (value == NULL) {
433 : 0 : *(uint8_t *)arg->val_saver = (uint8_t)(intptr_t)arg->val_set;
434 : 0 : return 0;
435 : : }
436 : :
437 : 4 : errno = 0;
438 : 4 : val = strtoul(value, &s, 0);
439 [ + + + + ]: 4 : if (errno == ERANGE || val > UINT8_MAX) {
440 : 2 : ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
441 : 2 : return -EINVAL;
442 : : }
443 : :
444 [ + + ]: 2 : if (s[0] != '\0') {
445 : 1 : ARGPARSE_LOG(ERR, "argument %s expect an uint8 value!", arg->name_long);
446 : 1 : return -EINVAL;
447 : : }
448 : :
449 : 1 : *(uint8_t *)arg->val_saver = val;
450 : :
451 : 1 : return 0;
452 : : }
453 : :
454 : : static int
455 : 4 : parse_arg_u16(const struct rte_argparse_arg *arg, const char *value)
456 : : {
457 : : unsigned long val;
458 : 4 : char *s = NULL;
459 : :
460 [ - + ]: 4 : if (value == NULL) {
461 : 0 : *(uint16_t *)arg->val_saver = (uint16_t)(intptr_t)arg->val_set;
462 : 0 : return 0;
463 : : }
464 : :
465 : 4 : errno = 0;
466 : 4 : val = strtoul(value, &s, 0);
467 [ + + + + ]: 4 : if (errno == ERANGE || val > UINT16_MAX) {
468 : 2 : ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
469 : 2 : return -EINVAL;
470 : : }
471 : :
472 [ + + ]: 2 : if (s[0] != '\0') {
473 : 1 : ARGPARSE_LOG(ERR, "argument %s expect an uint16 value!", arg->name_long);
474 : 1 : return -EINVAL;
475 : : }
476 : :
477 : 1 : *(uint16_t *)arg->val_saver = val;
478 : :
479 : 1 : return 0;
480 : : }
481 : :
482 : : static int
483 : 4 : parse_arg_u32(const struct rte_argparse_arg *arg, const char *value)
484 : : {
485 : : unsigned long val;
486 : 4 : char *s = NULL;
487 : :
488 [ - + ]: 4 : if (value == NULL) {
489 : 0 : *(uint32_t *)arg->val_saver = (uint32_t)(intptr_t)arg->val_set;
490 : 0 : return 0;
491 : : }
492 : :
493 : 4 : errno = 0;
494 : 4 : val = strtoul(value, &s, 0);
495 [ + + + + ]: 4 : if (errno == ERANGE || val > UINT32_MAX) {
496 : 2 : ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
497 : 2 : return -EINVAL;
498 : : }
499 : :
500 [ + + ]: 2 : if (s[0] != '\0') {
501 : 1 : ARGPARSE_LOG(ERR, "argument %s expect an uint32 value!", arg->name_long);
502 : 1 : return -EINVAL;
503 : : }
504 : :
505 : 1 : *(uint32_t *)arg->val_saver = val;
506 : :
507 : 1 : return 0;
508 : : }
509 : :
510 : : static int
511 : 3 : parse_arg_u64(const struct rte_argparse_arg *arg, const char *value)
512 : : {
513 : : unsigned long val;
514 : 3 : char *s = NULL;
515 : :
516 [ - + ]: 3 : if (value == NULL) {
517 : 0 : *(uint64_t *)arg->val_saver = (uint64_t)(intptr_t)arg->val_set;
518 : 0 : return 0;
519 : : }
520 : :
521 : 3 : errno = 0;
522 : 3 : val = strtoull(value, &s, 0);
523 [ + + ]: 3 : if (errno == ERANGE) {
524 : 1 : ARGPARSE_LOG(ERR, "argument %s numerical out of range!", arg->name_long);
525 : 1 : return -EINVAL;
526 : : }
527 : :
528 [ + + ]: 2 : if (s[0] != '\0') {
529 : 1 : ARGPARSE_LOG(ERR, "argument %s expect an uint64 value!", arg->name_long);
530 : 1 : return -EINVAL;
531 : : }
532 : :
533 : 1 : *(uint64_t *)arg->val_saver = val;
534 : :
535 : 1 : return 0;
536 : : }
537 : :
538 : : static int
539 : : parse_arg_str(const struct rte_argparse_arg *arg, const char *value)
540 : : {
541 [ + + ]: 413 : if (value == NULL) {
542 : 5 : *(char **)arg->val_saver = arg->val_set;
543 : 5 : return 0;
544 : : }
545 : 408 : *(const char **)arg->val_saver = value;
546 : :
547 : 408 : return 0;
548 : : }
549 : :
550 : : static int
551 : 131 : parse_arg_bool(const struct rte_argparse_arg *arg, const char *value)
552 : : {
553 [ + + ]: 131 : if (value == NULL) {
554 : 125 : *(bool *)arg->val_saver = (arg->val_set != NULL);
555 : 125 : return 0;
556 : : }
557 : :
558 [ + + + + ]: 6 : if (strcmp(value, "true") == 0 || strcmp(value, "1") == 0)
559 : 2 : *(bool *)arg->val_saver = true;
560 [ + + + + ]: 4 : else if (strcmp(value, "false") == 0 || strcmp(value, "0") == 0)
561 : 2 : *(bool *)arg->val_saver = false;
562 : : else {
563 : 2 : ARGPARSE_LOG(ERR, "argument %s expects a boolean (true/false, 0/1) value!",
564 : : arg->name_long);
565 : 2 : return -EINVAL;
566 : : }
567 : :
568 : : return 0;
569 : : }
570 : :
571 : : static int
572 : 34 : parse_arg_corelist(const struct rte_argparse_arg *arg, const char *value)
573 : : {
574 : 34 : rte_cpuset_t *cpuset = arg->val_saver;
575 : : const char *last = value;
576 : : int min = -1;
577 : :
578 [ - + ]: 34 : if (value == NULL) {
579 : 0 : *cpuset = *(rte_cpuset_t *)arg->val_set;
580 : 0 : return 0;
581 : : }
582 : :
583 : 34 : CPU_ZERO(cpuset);
584 [ + + ]: 76 : while (*last != '\0') {
585 : : char *end;
586 : : int64_t idx;
587 : : int32_t max;
588 : :
589 [ + + ]: 67 : while (isblank(*value))
590 : 6 : value++;
591 : :
592 [ + + ]: 61 : if (!isdigit(*value)) {
593 : 13 : ARGPARSE_LOG(ERR, "argument %s has an unexpected non digit character!",
594 : : arg->name_long);
595 : 19 : return -EINVAL;
596 : : }
597 : :
598 : 48 : errno = 0;
599 : 48 : idx = strtol(value, &end, 10);
600 : 48 : last = end;
601 [ + - + + ]: 48 : if (errno || idx > UINT16_MAX) {
602 : 1 : ARGPARSE_LOG(ERR, "argument %s contains a numerical value out of range!",
603 : : arg->name_long);
604 : 1 : return -EINVAL;
605 : : }
606 : :
607 [ + + ]: 47 : if (*end == '-') {
608 [ + + ]: 16 : if (min != -1) { /* can't have '-' within a range */
609 : 2 : ARGPARSE_LOG(ERR, "argument %s has an unexpected - character!",
610 : : arg->name_long);
611 : 2 : return -EINVAL;
612 : : }
613 : 14 : min = idx; /* start of range, move to next loop stage */
614 [ + + ]: 31 : } else if (*end == ',' || *end == '\0') {
615 : : /* single value followed by comma or end (min is set only by '-') */
616 [ + + ]: 28 : if (min == -1) {
617 : 20 : min = max = idx;
618 [ + + ]: 8 : } else if (min > idx) {
619 : : /* we have range from high to low */
620 : : max = min;
621 : 1 : min = idx;
622 : : } else {
623 : : /* range from low to high */
624 : 7 : max = idx;
625 : : }
626 : :
627 [ + + ]: 206 : for (; min <= max; min++)
628 [ + - ]: 178 : CPU_SET(min, cpuset);
629 : :
630 : : min = -1; /* no longer in a range */
631 : : } else {
632 : : /* end is an unexpected character, return error */
633 : 3 : ARGPARSE_LOG(ERR, "argument %s has an unexpected character!",
634 : : arg->name_long);
635 : 3 : return -EINVAL;
636 : : }
637 : 42 : value = last + 1;
638 : : }
639 : : return 0;
640 : : }
641 : :
642 : : static int
643 : 619 : parse_arg_autosave(const struct rte_argparse_arg *arg, const char *value)
644 : : {
645 [ - + + + : 619 : switch (arg->value_type) {
+ + + + +
- ]
646 : 0 : case RTE_ARGPARSE_VALUE_TYPE_NONE:
647 : 0 : ARGPARSE_LOG(ERR, "argument %s doesn't specify a value-type!", arg->name_long);
648 : 0 : return -EINVAL;
649 : 26 : case RTE_ARGPARSE_VALUE_TYPE_INT:
650 : 26 : return parse_arg_int(arg, value);
651 : 4 : case RTE_ARGPARSE_VALUE_TYPE_U8:
652 : 4 : return parse_arg_u8(arg, value);
653 : 4 : case RTE_ARGPARSE_VALUE_TYPE_U16:
654 : 4 : return parse_arg_u16(arg, value);
655 : 4 : case RTE_ARGPARSE_VALUE_TYPE_U32:
656 : 4 : return parse_arg_u32(arg, value);
657 : 3 : case RTE_ARGPARSE_VALUE_TYPE_U64:
658 : 3 : return parse_arg_u64(arg, value);
659 : : case RTE_ARGPARSE_VALUE_TYPE_STR:
660 : : return parse_arg_str(arg, value);
661 : 131 : case RTE_ARGPARSE_VALUE_TYPE_BOOL:
662 : 131 : return parse_arg_bool(arg, value);
663 : 34 : case RTE_ARGPARSE_VALUE_TYPE_CORELIST:
664 : 34 : return parse_arg_corelist(arg, value);
665 : : /* omit default case so compiler warns on missing enum values */
666 : : }
667 : : return -EINVAL;
668 : : }
669 : :
670 : : /* arg_parse indicates the name entered by the user, which can be long-name or short-name. */
671 : : static int
672 : 625 : parse_arg_val(const struct rte_argparse *obj, const char *arg_name,
673 : : const struct rte_argparse_arg *arg, char *value)
674 : : {
675 : : int ret;
676 : :
677 [ + + ]: 625 : if (arg->val_saver == NULL)
678 : 64 : ret = obj->callback((uint32_t)(uintptr_t)arg->val_set, value, obj->opaque);
679 : : else
680 : 561 : ret = parse_arg_autosave(arg, value);
681 [ + + ]: 625 : if (ret != 0) {
682 : 7 : ARGPARSE_LOG(ERR, "argument %s parse value fail!", arg_name);
683 : 7 : return ret;
684 : : }
685 : :
686 : : return 0;
687 : : }
688 : :
689 : : static bool
690 : 627 : is_help(const char *curr_argv)
691 : : {
692 [ + - + - ]: 627 : return strcmp(curr_argv, "-h") == 0 || strcmp(curr_argv, "--help") == 0;
693 : : }
694 : :
695 : : static int
696 : 302 : parse_args(const struct rte_argparse *obj, bool *arg_parsed,
697 : : int argc, char **argv, bool *show_help)
698 : : {
699 : : uint32_t position_count = calc_position_count(obj);
700 : : const struct rte_argparse_arg *arg;
701 : : uint32_t position_index = 0;
702 : : const char *arg_name;
703 : : size_t n_args_to_move;
704 : : char **args_to_move;
705 : : uint32_t arg_idx;
706 : : char *curr_argv;
707 : : char *value;
708 : : int ret;
709 : : int i;
710 : :
711 : : n_args_to_move = 0;
712 : 302 : args_to_move = calloc(argc, sizeof(args_to_move[0]));
713 [ - + ]: 302 : if (args_to_move == NULL) {
714 : 0 : ARGPARSE_LOG(ERR, "failed to allocate memory for internal flag processing!");
715 : 0 : return -ENOMEM;
716 : : }
717 : :
718 [ + + ]: 949 : for (i = 1; i < argc; i++) {
719 : 667 : curr_argv = argv[i];
720 : :
721 [ + + ]: 667 : if (strcmp(argv[i], "--") == 0) {
722 : 1 : i++;
723 : 1 : break;
724 : : }
725 : :
726 [ + + ]: 666 : if (curr_argv[0] != '-') {
727 [ + + ]: 39 : if (obj->ignore_non_flag_args) {
728 : : /* Move non-flag args to args_to_move array. */
729 : 29 : args_to_move[n_args_to_move++] = curr_argv;
730 : 29 : argv[i] = NULL;
731 : 29 : continue;
732 : : }
733 : : /* process positional parameters. */
734 : 10 : position_index++;
735 [ + + ]: 10 : if (position_index > position_count) {
736 : 3 : ARGPARSE_LOG(ERR, "too many positional arguments %s!", curr_argv);
737 : : ret = -EINVAL;
738 : 3 : goto err_out;
739 : : }
740 : : arg = find_position_arg(obj, position_index);
741 : 7 : ret = parse_arg_val(obj, arg->name_long, arg, curr_argv);
742 [ + + ]: 7 : if (ret != 0)
743 : 2 : goto err_out;
744 : 5 : continue;
745 : : }
746 : :
747 : : /* process optional parameters. */
748 [ - + ]: 627 : if (is_help(curr_argv)) {
749 : 0 : *show_help = true;
750 : 0 : continue;
751 : : }
752 : :
753 : 627 : value = strchr(curr_argv, '=');
754 [ + + + + : 627 : if (value == NULL && curr_argv[1] != '-' && strlen(curr_argv) > 2)
+ + ]
755 : 4 : value = &curr_argv[2];
756 : 627 : arg_name = NULL;
757 : 627 : arg = find_option_arg(obj, &arg_idx, curr_argv, value, &arg_name);
758 [ + + - + ]: 627 : if (arg == NULL || arg_name == NULL) {
759 : 1 : ARGPARSE_LOG(ERR, "unknown argument %s!", curr_argv);
760 : : ret = -EINVAL;
761 : 1 : goto err_out;
762 : : }
763 : :
764 [ + + + + ]: 626 : if (arg_parsed[arg_idx] && !arg_attr_flag_multi(arg)) {
765 : 1 : ARGPARSE_LOG(ERR, "argument %s should not occur multiple times!", arg_name);
766 : : ret = -EINVAL;
767 : 1 : goto err_out;
768 : : }
769 : :
770 [ + + + + ]: 625 : if (value != NULL && value[0] == '=')
771 : 251 : value++; /* skip '=' */
772 [ + + ]: 625 : if (arg->value_required == RTE_ARGPARSE_VALUE_NONE) {
773 [ - + ]: 147 : if (value != NULL) {
774 : 0 : ARGPARSE_LOG(ERR, "argument %s should not take value!", arg_name);
775 : : ret = -EINVAL;
776 : 0 : goto err_out;
777 : : }
778 [ + + ]: 478 : } else if (arg->value_required == RTE_ARGPARSE_VALUE_REQUIRED) {
779 [ + + ]: 450 : if (value == NULL) {
780 [ + + ]: 213 : if (i >= argc - 1) {
781 : 7 : ARGPARSE_LOG(ERR, "argument %s doesn't have value!",
782 : : arg_name);
783 : : ret = -EINVAL;
784 : 7 : goto err_out;
785 : : }
786 : : /* Set value and make i move next. */
787 : 206 : value = argv[++i];
788 : : }
789 : : } else {
790 : : /* Do nothing, because it's optional value, only support arg=val or arg. */
791 : : }
792 : :
793 : 618 : ret = parse_arg_val(obj, arg_name, arg, value);
794 [ + + ]: 618 : if (ret != 0)
795 : 5 : goto err_out;
796 : :
797 : : /* This argument parsed success! then mark it parsed. */
798 : 613 : arg_parsed[arg_idx] = true;
799 : : }
800 : :
801 : : ret = i;
802 [ + + ]: 283 : if (n_args_to_move > 0) {
803 : : /* Close the gaps in argv array by moving elements down filling in the NULLs. */
804 : : int j = 1;
805 [ + + ]: 87 : for (i = 1; i < ret; i++) {
806 [ + + ]: 72 : if (argv[i] != NULL)
807 : 43 : argv[j++] = argv[i];
808 : : }
809 : : ret = j; /* only return args actually handled */
810 : : /* Then put contents of the args_to_move array into the argv in the space left. */
811 [ + + ]: 44 : for (i = 0; i < (int)n_args_to_move; i++)
812 : 29 : argv[j++] = args_to_move[i];
813 : : }
814 : 283 : err_out:
815 : 302 : free(args_to_move);
816 : 302 : return ret;
817 : : }
818 : :
819 : : static uint32_t
820 : 0 : calc_help_align(const struct rte_argparse *obj)
821 : : {
822 : : const struct rte_argparse_arg *arg;
823 : : uint32_t width = 12; /* Default "-h, --help " len. */
824 : : uint32_t len;
825 : : uint32_t i;
826 : :
827 : 0 : for (i = 0; /* NULL */; i++) {
828 : 0 : arg = &obj->args[i];
829 [ # # ]: 0 : if (arg->name_long == NULL)
830 : : break;
831 : 0 : len = strlen(arg->name_long);
832 [ # # # # ]: 0 : if (is_arg_optional(arg) && arg->name_short != NULL) {
833 : 0 : len += strlen(", ");
834 : 0 : len += strlen(arg->name_short);
835 : : }
836 : 0 : width = RTE_MAX(width, 1 + len + 2); /* start with 1 & end with 2 space. */
837 : : }
838 : :
839 : 0 : return width;
840 : : }
841 : :
842 : : static void
843 : 0 : show_oneline_help(FILE *stream, const struct rte_argparse_arg *arg, uint32_t width)
844 : : {
845 : : uint32_t len = 0;
846 : : uint32_t i;
847 : :
848 [ # # ]: 0 : if (arg->name_short != NULL)
849 : 0 : len = fprintf(stream, " %s,", arg->name_short);
850 : 0 : len += fprintf(stream, " %s", arg->name_long);
851 : :
852 [ # # ]: 0 : for (i = len; i < width; i++)
853 : : fprintf(stream, " ");
854 : :
855 : 0 : fprintf(stream, "%s\n", arg->help);
856 : 0 : }
857 : :
858 : : static void
859 : 0 : show_args_pos_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
860 : : {
861 : : uint32_t position_count = calc_position_count(obj);
862 : : const struct rte_argparse_arg *arg;
863 : : uint32_t i;
864 : :
865 [ # # ]: 0 : if (position_count == 0)
866 : : return;
867 : :
868 : : fprintf(stream, "\npositional arguments:\n");
869 : 0 : for (i = 0; /* NULL */; i++) {
870 : 0 : arg = &obj->args[i];
871 [ # # ]: 0 : if (arg->name_long == NULL)
872 : : break;
873 [ # # ]: 0 : if (!is_arg_positional(arg))
874 : 0 : continue;
875 : 0 : show_oneline_help(stream, arg, align);
876 : : }
877 : : }
878 : :
879 : : static void
880 : 0 : show_args_opt_help(FILE *stream, const struct rte_argparse *obj, uint32_t align)
881 : : {
882 : : static const struct rte_argparse_arg help = {
883 : : .name_long = "--help",
884 : : .name_short = "-h",
885 : : .help = "show this help message and exit.",
886 : : };
887 : : const struct rte_argparse_arg *arg;
888 : : uint32_t i;
889 : :
890 : : fprintf(stream, "\noptions:\n");
891 : 0 : show_oneline_help(stream, &help, align);
892 : 0 : for (i = 0; /* NULL */; i++) {
893 : 0 : arg = &obj->args[i];
894 [ # # ]: 0 : if (arg->name_long == NULL)
895 : : break;
896 [ # # ]: 0 : if (!is_arg_optional(arg))
897 : 0 : continue;
898 : 0 : show_oneline_help(stream, arg, align);
899 : : }
900 : 0 : }
901 : :
902 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_print_help, 25.11)
903 : : void
904 : 0 : rte_argparse_print_help(FILE *stream, const struct rte_argparse *obj)
905 : : {
906 : 0 : uint32_t align = calc_help_align(obj);
907 : :
908 : 0 : fprintf(stream, "usage: %s %s\n", obj->prog_name, obj->usage);
909 [ # # ]: 0 : if (obj->descriptor != NULL)
910 : : fprintf(stream, "\ndescriptor: %s\n", obj->descriptor);
911 : :
912 : 0 : show_args_pos_help(stream, obj, align);
913 : 0 : show_args_opt_help(stream, obj, align);
914 : :
915 [ # # ]: 0 : if (obj->epilog != NULL)
916 : : fprintf(stream, "\n%s\n", obj->epilog);
917 : : else
918 : : fprintf(stream, "\n");
919 : 0 : }
920 : :
921 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_parse, 24.03)
922 : : int
923 : 326 : rte_argparse_parse(const struct rte_argparse *obj, int argc, char **argv)
924 : : {
925 : : bool *arg_parsed = NULL;
926 : 326 : bool show_help = false;
927 : 326 : size_t nb_args = 0;
928 : : int ret;
929 : :
930 : 326 : ret = verify_argparse(obj, &nb_args);
931 [ + + ]: 326 : if (ret != 0)
932 : 24 : goto error;
933 : :
934 : : /* allocate the flags array to indicate what arguments are parsed or not */
935 : 302 : arg_parsed = calloc(nb_args, sizeof(*arg_parsed));
936 [ - + ]: 302 : if (arg_parsed == NULL) {
937 : 0 : ARGPARSE_LOG(ERR, "failed to allocate memory for argument flags!");
938 : : ret = -ENOMEM;
939 : 0 : goto error;
940 : : }
941 : :
942 : 302 : ret = parse_args(obj, arg_parsed, argc, argv, &show_help);
943 : 302 : free(arg_parsed);
944 [ + + ]: 302 : if (ret < 0)
945 : 19 : goto error;
946 : :
947 [ - + ]: 283 : if (show_help) {
948 [ # # ]: 0 : if (obj->print_help != NULL)
949 : 0 : obj->print_help(obj);
950 : : else
951 : 0 : rte_argparse_print_help(stdout, obj);
952 : 0 : exit(0);
953 : : }
954 : :
955 : : return ret;
956 : :
957 : 43 : error:
958 [ + + ]: 43 : if (obj->exit_on_error)
959 : 7 : exit(ret);
960 : : return ret;
961 : : }
962 : :
963 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_argparse_parse_type, 24.03)
964 : : int
965 : 58 : rte_argparse_parse_type(const char *str, enum rte_argparse_value_type val_type, void *val)
966 : : {
967 : 58 : struct rte_argparse_arg arg = {
968 : : .name_long = str,
969 : : .name_short = NULL,
970 : : .val_saver = val,
971 : : .val_set = NULL,
972 : : .value_type = val_type,
973 : : };
974 [ - + ]: 58 : if (val_type == RTE_ARGPARSE_VALUE_TYPE_NONE) {
975 : 0 : ARGPARSE_LOG(ERR, "argument %s doesn't have value-type!", str);
976 : 0 : return -EINVAL;
977 : : }
978 : 58 : return parse_arg_autosave(&arg, str);
979 : : }
|