dte test coverage


Directory: ./
File: src/command/args.c
Date: 2025-05-08 15:05:54
Exec Total Coverage
Lines: 75 75 100.0%
Functions: 3 3 100.0%
Branches: 40 43 93.0%

Line Branch Exec Source
1 #include <stdlib.h>
2 #include <string.h>
3 #include "args.h"
4 #include "util/str-array.h"
5 #include "util/xstring.h"
6
7 /*
8 * Flags and first "--" are removed.
9 * Flag arguments are moved to beginning.
10 * Other arguments come right after flag arguments.
11 *
12 * a->args field should be set before calling.
13 * If parsing succeeds, the other fields are set and 0 is returned.
14 */
15 8999 ArgParseError do_parse_args(const Command *cmd, CommandArgs *a)
16 {
17 8999 char **args = a->args;
18 8999 BUG_ON(!args);
19
20 8999 const char *flag_desc = cmd->flags;
21 8999 bool flags_after_arg = !(cmd->cmdopts & CMDOPT_NO_FLAGS_AFTER_ARGS);
22 8999 size_t argc = string_array_length(args);
23 8999 size_t nr_flags = 0;
24 8999 size_t nr_flag_args = 0;
25
26
2/2
✓ Branch 0 (29→5) taken 15357 times.
✓ Branch 1 (29→30) taken 6464 times.
21821 for (size_t i = 0; args[i]; ) {
27 15357 char *arg = args[i];
28
2/2
✓ Branch 0 (5→6) taken 41 times.
✓ Branch 1 (5→7) taken 15316 times.
15357 if (unlikely(streq(arg, "--"))) {
29 // Move the NULL too
30 41 memmove(args + i, args + i + 1, (argc - i) * sizeof(*args));
31 41 free(arg);
32 41 argc--;
33 41 break;
34 }
35
36
4/4
✓ Branch 0 (7→8) taken 1736 times.
✓ Branch 1 (7→9) taken 13580 times.
✓ Branch 2 (8→9) taken 7 times.
✓ Branch 3 (8→26) taken 1729 times.
15316 if (arg[0] != '-' || arg[1] == '\0') {
37
2/2
✓ Branch 0 (9→10) taken 11104 times.
✓ Branch 1 (9→30) taken 2483 times.
13587 if (!flags_after_arg) {
38 break;
39 }
40 11104 i++;
41 11104 continue;
42 }
43
44
2/2
✓ Branch 0 (26→11) taken 2108 times.
✓ Branch 1 (26→27) taken 1718 times.
3826 for (size_t j = 1; arg[j]; j++) {
45 2108 unsigned char flag = arg[j];
46 2108 const char *flagp = strchr(flag_desc, flag);
47
2/2
✓ Branch 0 (11→12) taken 3 times.
✓ Branch 1 (11→13) taken 2105 times.
2108 if (unlikely(!flagp || flag == '=')) {
48 3 a->flags[0] = flag;
49 3 return ARGERR_INVALID_OPTION;
50 }
51
52 2105 a->flag_set |= cmdargs_flagset_bit(flag);
53 2105 a->flags[nr_flags++] = flag;
54
2/2
✓ Branch 0 (14→15) taken 2104 times.
✓ Branch 1 (14→34) taken 1 times.
2105 if (unlikely(nr_flags == ARRAYLEN(a->flags))) {
55 return ARGERR_TOO_MANY_OPTIONS;
56 }
57
58
2/2
✓ Branch 0 (15→16) taken 2066 times.
✓ Branch 1 (15→17) taken 38 times.
2104 if (likely(flagp[1] != '=')) {
59 2066 continue;
60 }
61
62
3/4
✓ Branch 0 (17→18) taken 38 times.
✗ Branch 1 (17→19) not taken.
✓ Branch 2 (18→19) taken 2 times.
✓ Branch 3 (18→20) taken 36 times.
38 if (unlikely(j > 1 || arg[j + 1])) {
63 2 a->flags[0] = flag;
64 2 return ARGERR_OPTION_ARGUMENT_NOT_SEPARATE;
65 }
66
67 36 char *flag_arg = args[i + 1];
68
2/2
✓ Branch 0 (20→21) taken 5 times.
✓ Branch 1 (20→22) taken 31 times.
36 if (unlikely(!flag_arg)) {
69 5 a->flags[0] = flag;
70 5 return ARGERR_OPTION_ARGUMENT_MISSING;
71 }
72
73 // Move flag argument before any other arguments
74
2/2
✓ Branch 0 (22→23) taken 1 times.
✓ Branch 1 (22→24) taken 30 times.
31 if (i != nr_flag_args) {
75 // farg1 arg1 arg2 -f farg2 arg3
76 // farg1 farg2 arg1 arg2 arg3
77 1 size_t count = i - nr_flag_args;
78 1 char **ptr = args + nr_flag_args;
79 1 memmove(ptr + 1, ptr, count * sizeof(*args));
80 }
81 31 args[nr_flag_args++] = flag_arg;
82 31 i++;
83 }
84
85 1718 memmove(args + i, args + i + 1, (argc - i) * sizeof(*args));
86 1718 free(arg);
87 1718 argc--;
88 }
89
90 8988 a->flags[nr_flags] = '\0';
91 8988 a->nr_flags = nr_flags;
92 8988 a->nr_args = argc - nr_flag_args;
93 8988 a->nr_flag_args = nr_flag_args;
94
95
2/2
✓ Branch 0 (30→31) taken 8950 times.
✓ Branch 1 (30→34) taken 38 times.
8988 if (unlikely(a->nr_args < cmd->min_args)) {
96 return ARGERR_TOO_FEW_ARGUMENTS;
97 }
98
99 8950 static_assert_compatible_types(cmd->max_args, uint8_t);
100
4/4
✓ Branch 0 (31→32) taken 6 times.
✓ Branch 1 (31→34) taken 8944 times.
✓ Branch 2 (32→33) taken 4 times.
✓ Branch 3 (32→34) taken 2 times.
8950 if (unlikely(a->nr_args > cmd->max_args && cmd->max_args != 0xFF)) {
101 4 return ARGERR_TOO_MANY_ARGUMENTS;
102 }
103
104 return 0;
105 }
106
107 7 static bool arg_parse_error_msg (
108 const Command *cmd,
109 const CommandArgs *a,
110 ArgParseError err,
111 ErrorBuffer *ebuf
112 ) {
113 7 const char *name = cmd->name;
114
6/7
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→4) taken 1 times.
✓ Branch 2 (2→5) taken 1 times.
✓ Branch 3 (2→6) taken 1 times.
✓ Branch 4 (2→7) taken 2 times.
✓ Branch 5 (2→8) taken 1 times.
✗ Branch 6 (2→9) not taken.
7 switch (err) {
115 1 case ARGERR_INVALID_OPTION:
116 1 return error_msg_for_cmd(ebuf, name, "Invalid option -%c", a->flags[0]);
117 1 case ARGERR_TOO_MANY_OPTIONS:
118 1 return error_msg_for_cmd(ebuf, name, "Too many options given");
119 1 case ARGERR_OPTION_ARGUMENT_MISSING:
120 1 return error_msg_for_cmd(ebuf, name, "Option -%c requires an argument", a->flags[0]);
121 1 case ARGERR_OPTION_ARGUMENT_NOT_SEPARATE:
122 1 return error_msg_for_cmd (
123 ebuf, name,
124 "Option -%c must be given separately because it requires an argument",
125 1 a->flags[0]
126 );
127 2 case ARGERR_TOO_FEW_ARGUMENTS:
128 2 return error_msg_for_cmd (
129 ebuf, name,
130 "Too few arguments (got: %zu, minimum: %u)",
131 2 a->nr_args, (unsigned int)cmd->min_args
132 );
133 1 case ARGERR_TOO_MANY_ARGUMENTS:
134 1 return error_msg_for_cmd (
135 ebuf, name,
136 "Too many arguments (got: %zu, maximum: %u)",
137 1 a->nr_args, (unsigned int)cmd->max_args
138 );
139 case ARGERR_NONE:
140 break;
141 }
142
143 BUG("unhandled error type");
144 return false;
145 }
146
147 6954 bool parse_args(const Command *cmd, CommandArgs *a, ErrorBuffer *ebuf)
148 {
149 6954 ArgParseError err = do_parse_args(cmd, a);
150
3/4
✓ Branch 0 (3→4) taken 7 times.
✓ Branch 1 (3→7) taken 6947 times.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→7) taken 7 times.
6954 return likely(err == ARGERR_NONE) || arg_parse_error_msg(cmd, a, err, ebuf);
151 }
152