dte test coverage


Directory: ./
File: src/command/args.c
Date: 2025-02-14 16:55:22
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 8411 ArgParseError do_parse_args(const Command *cmd, CommandArgs *a)
16 {
17 8411 char **args = a->args;
18 8411 BUG_ON(!args);
19
20 8411 const char *flag_desc = cmd->flags;
21 8411 bool flags_after_arg = !(cmd->cmdopts & CMDOPT_NO_FLAGS_AFTER_ARGS);
22 8411 size_t argc = string_array_length(args);
23 8411 size_t nr_flags = 0;
24 8411 size_t nr_flag_args = 0;
25
26
2/2
✓ Branch 0 (29→5) taken 14705 times.
✓ Branch 1 (29→30) taken 6171 times.
20876 for (size_t i = 0; args[i]; ) {
27 14705 char *arg = args[i];
28
2/2
✓ Branch 0 (5→6) taken 40 times.
✓ Branch 1 (5→7) taken 14665 times.
14705 if (unlikely(streq(arg, "--"))) {
29 // Move the NULL too
30 40 memmove(args + i, args + i + 1, (argc - i) * sizeof(*args));
31 40 free(arg);
32 40 argc--;
33 40 break;
34 }
35
36
4/4
✓ Branch 0 (7→8) taken 1571 times.
✓ Branch 1 (7→9) taken 13094 times.
✓ Branch 2 (8→9) taken 7 times.
✓ Branch 3 (8→26) taken 1564 times.
14665 if (arg[0] != '-' || arg[1] == '\0') {
37
2/2
✓ Branch 0 (9→10) taken 10912 times.
✓ Branch 1 (9→30) taken 2189 times.
13101 if (!flags_after_arg) {
38 break;
39 }
40 10912 i++;
41 10912 continue;
42 }
43
44
2/2
✓ Branch 0 (26→11) taken 1876 times.
✓ Branch 1 (26→27) taken 1553 times.
3429 for (size_t j = 1; arg[j]; j++) {
45 1876 unsigned char flag = arg[j];
46 1876 const char *flagp = strchr(flag_desc, flag);
47
2/2
✓ Branch 0 (11→12) taken 3 times.
✓ Branch 1 (11→13) taken 1873 times.
1876 if (unlikely(!flagp || flag == '=')) {
48 3 a->flags[0] = flag;
49 3 return ARGERR_INVALID_OPTION;
50 }
51
52 1873 a->flag_set |= cmdargs_flagset_value(flag);
53 1873 a->flags[nr_flags++] = flag;
54
2/2
✓ Branch 0 (14→15) taken 1872 times.
✓ Branch 1 (14→34) taken 1 times.
1873 if (unlikely(nr_flags == ARRAYLEN(a->flags))) {
55 return ARGERR_TOO_MANY_OPTIONS;
56 }
57
58
2/2
✓ Branch 0 (15→16) taken 1834 times.
✓ Branch 1 (15→17) taken 38 times.
1872 if (likely(flagp[1] != '=')) {
59 1834 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 1553 memmove(args + i, args + i + 1, (argc - i) * sizeof(*args));
86 1553 free(arg);
87 1553 argc--;
88 }
89
90 8400 a->flags[nr_flags] = '\0';
91 8400 a->nr_flags = nr_flags;
92 8400 a->nr_args = argc - nr_flag_args;
93 8400 a->nr_flag_args = nr_flag_args;
94
95
2/2
✓ Branch 0 (30→31) taken 8362 times.
✓ Branch 1 (30→34) taken 38 times.
8400 if (unlikely(a->nr_args < cmd->min_args)) {
96 return ARGERR_TOO_FEW_ARGUMENTS;
97 }
98
99 8362 static_assert_compatible_types(cmd->max_args, uint8_t);
100
4/4
✓ Branch 0 (31→32) taken 6 times.
✓ Branch 1 (31→34) taken 8356 times.
✓ Branch 2 (32→33) taken 4 times.
✓ Branch 3 (32→34) taken 2 times.
8362 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 6590 bool parse_args(const Command *cmd, CommandArgs *a, ErrorBuffer *ebuf)
148 {
149 6590 ArgParseError err = do_parse_args(cmd, a);
150
3/4
✓ Branch 0 (3→4) taken 7 times.
✓ Branch 1 (3→7) taken 6583 times.
✗ Branch 2 (5→6) not taken.
✓ Branch 3 (5→7) taken 7 times.
6590 return likely(err == ARGERR_NONE) || arg_parse_error_msg(cmd, a, err, ebuf);
151 }
152