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