GCC Code Coverage Report


Directory: lib/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 83.6% 1265 / 0 / 1513
Functions: 100.0% 101 / 0 / 101
Branches: 72.2% 916 / 0 / 1268

api.c
Line Branch Exec Source
1 #include <ctype.h>
2 #include <stdarg.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "ap_internal.h"
8
9 1582 static int ensure_defs_capacity(ap_parser *parser) {
10
2/2
✓ Branch 0 taken 948 times.
✓ Branch 1 taken 634 times.
1582 if (parser->defs_count < parser->defs_cap) {
11 948 return 0;
12 }
13
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 630 times.
634 int next_cap = parser->defs_cap == 0 ? 8 : parser->defs_cap * 2;
14 ap_arg_def *next =
15 634 realloc(parser->defs, sizeof(ap_arg_def) * (size_t)next_cap);
16
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 634 times.
634 if (!next) {
17 return -1;
18 }
19 634 parser->defs = next;
20 634 parser->defs_cap = next_cap;
21 634 return 0;
22 }
23
24 126 static int ensure_subcommands_capacity(ap_parser *parser) {
25
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 122 times.
126 if (parser->subcommands_count < parser->subcommands_cap) {
26 4 return 0;
27 }
28
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 int next_cap = parser->subcommands_cap == 0 ? 4 : parser->subcommands_cap * 2;
29 122 ap_subcommand_def *next = realloc(
30 122 parser->subcommands, sizeof(ap_subcommand_def) * (size_t)next_cap);
31
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
122 if (!next) {
32 return -1;
33 }
34 122 parser->subcommands = next;
35 122 parser->subcommands_cap = next_cap;
36 122 return 0;
37 }
38
39 10 static int ensure_mutex_groups_capacity(ap_parser *parser) {
40
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (parser->mutex_groups_count < parser->mutex_groups_cap) {
41 return 0;
42 }
43 10 int next_cap =
44
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 parser->mutex_groups_cap == 0 ? 4 : parser->mutex_groups_cap * 2;
45 10 ap_mutex_group_def *next = realloc(
46 10 parser->mutex_groups, sizeof(ap_mutex_group_def) * (size_t)next_cap);
47
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!next) {
48 return -1;
49 }
50 10 parser->mutex_groups = next;
51 10 parser->mutex_groups_cap = next_cap;
52 10 return 0;
53 }
54
55 10 static int ensure_arg_groups_capacity(ap_parser *parser) {
56
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (parser->arg_groups_count < parser->arg_groups_cap) {
57 return 0;
58 }
59
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 int next_cap = parser->arg_groups_cap == 0 ? 4 : parser->arg_groups_cap * 2;
60 ap_arg_group_def *next =
61 10 realloc(parser->arg_groups, sizeof(ap_arg_group_def) * (size_t)next_cap);
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!next) {
63 return -1;
64 }
65 10 parser->arg_groups = next;
66 10 parser->arg_groups_cap = next_cap;
67 10 return 0;
68 }
69
70 18 static int mutex_group_push_arg(ap_mutex_group_def *group, int arg_index) {
71 int *next;
72 int next_cap;
73
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 if (group->arg_count < group->arg_cap) {
74 8 group->arg_indexes[group->arg_count++] = arg_index;
75 8 return 0;
76 }
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 next_cap = group->arg_cap == 0 ? 4 : group->arg_cap * 2;
78 10 next = realloc(group->arg_indexes, sizeof(int) * (size_t)next_cap);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!next) {
80 return -1;
81 }
82 10 group->arg_indexes = next;
83 10 group->arg_cap = next_cap;
84 10 group->arg_indexes[group->arg_count++] = arg_index;
85 10 return 0;
86 }
87
88 10 static int argument_group_push_arg(ap_arg_group_def *group, int arg_index) {
89 int *next;
90 int next_cap;
91
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if (group->arg_count < group->arg_cap) {
92 4 group->arg_indexes[group->arg_count++] = arg_index;
93 4 return 0;
94 }
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 next_cap = group->arg_cap == 0 ? 4 : group->arg_cap * 2;
96 6 next = realloc(group->arg_indexes, sizeof(int) * (size_t)next_cap);
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!next) {
98 return -1;
99 }
100 6 group->arg_indexes = next;
101 6 group->arg_cap = next_cap;
102 6 group->arg_indexes[group->arg_count++] = arg_index;
103 6 return 0;
104 }
105
106 638 static const char *default_completion_entrypoint(void) { return "__complete"; }
107
108 132 static bool is_reserved_completion_name(const ap_parser *parser,
109 const char *name) {
110
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 4 times.
132 return parser && parser->completion_enabled &&
111
3/6
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 128 times.
✗ Branch 5 not taken.
392 parser->completion_entrypoint && name &&
112
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
128 strcmp(parser->completion_entrypoint, name) == 0;
113 }
114
115 1608 static void arg_def_free(ap_arg_def *def) {
116 int i;
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1608 times.
1608 if (!def) {
118 return;
119 }
120 1608 free(def->dest);
121
2/2
✓ Branch 0 taken 2414 times.
✓ Branch 1 taken 1608 times.
4022 for (i = 0; i < def->flags_count; i++) {
122 2414 free(def->flags[i]);
123 }
124 1608 free(def->flags);
125 }
126
127 1590 static int parser_find_def_by_dest(const ap_parser *parser, const char *dest) {
128 int i;
129
2/4
✓ Branch 0 taken 1590 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1590 times.
1590 if (!parser || !dest) {
130 return -1;
131 }
132
2/2
✓ Branch 0 taken 1888 times.
✓ Branch 1 taken 1582 times.
3470 for (i = 0; i < parser->defs_count; i++) {
133
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1880 times.
1888 if (strcmp(parser->defs[i].dest, dest) == 0) {
134 8 return i;
135 }
136 }
137 1582 return -1;
138 }
139
140 2386 static int parser_find_def_by_flag(const ap_parser *parser, const char *flag) {
141 int i;
142 int j;
143
2/4
✓ Branch 0 taken 2386 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2386 times.
2386 if (!parser || !flag) {
144 return -1;
145 }
146
2/2
✓ Branch 0 taken 2122 times.
✓ Branch 1 taken 2384 times.
4506 for (i = 0; i < parser->defs_count; i++) {
147 2122 const ap_arg_def *def = &parser->defs[i];
148
2/2
✓ Branch 0 taken 3558 times.
✓ Branch 1 taken 2120 times.
5678 for (j = 0; j < def->flags_count; j++) {
149
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3556 times.
3558 if (strcmp(def->flags[j], flag) == 0) {
150 2 return i;
151 }
152 }
153 }
154 2384 return -1;
155 }
156
157 2 static void remove_arg_index(int **indexes, int *count, int pos) {
158 int i;
159
5/10
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
2 if (!indexes || !*indexes || !count || pos < 0 || pos >= *count) {
160 return;
161 }
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 for (i = pos; i < *count - 1; i++) {
163 (*indexes)[i] = (*indexes)[i + 1];
164 }
165 2 (*count)--;
166 }
167
168 6 static void parser_remove_def(ap_parser *parser, int def_index) {
169 int i;
170 int j;
171
172
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
6 if (!parser || def_index < 0 || def_index >= parser->defs_count) {
173 return;
174 }
175
176 6 arg_def_free(&parser->defs[def_index]);
177
178
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 for (i = 0; i < parser->mutex_groups_count; i++) {
179 2 ap_mutex_group_def *group = &parser->mutex_groups[i];
180
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (j = 0; j < group->arg_count; j++) {
181
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (group->arg_indexes[j] == def_index) {
182 2 remove_arg_index(&group->arg_indexes, &group->arg_count, j);
183 2 j--;
184 } else if (group->arg_indexes[j] > def_index) {
185 group->arg_indexes[j]--;
186 }
187 }
188 }
189
190
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 for (i = 0; i < parser->arg_groups_count; i++) {
191 2 ap_arg_group_def *group = &parser->arg_groups[i];
192
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (j = 0; j < group->arg_count; j++) {
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (group->arg_indexes[j] == def_index) {
194 remove_arg_index(&group->arg_indexes, &group->arg_count, j);
195 j--;
196
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (group->arg_indexes[j] > def_index) {
197 2 group->arg_indexes[j]--;
198 }
199 }
200 }
201
202
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 for (i = def_index; i < parser->defs_count - 1; i++) {
203 2 parser->defs[i] = parser->defs[i + 1];
204 }
205 6 parser->defs_count--;
206 }
207
208 210 void ap_error_set(ap_error *err, ap_error_code code, const char *argument,
209 const char *fmt, ...) {
210 va_list ap;
211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (!err) {
212 return;
213 }
214 210 err->code = code;
215 210 err->argument[0] = '\0';
216 210 err->message[0] = '\0';
217
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 if (argument) {
218 210 snprintf(err->argument, sizeof(err->argument), "%s", argument);
219 }
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (!fmt) {
221 return;
222 }
223 210 va_start(ap, fmt);
224 210 vsnprintf(err->message, sizeof(err->message), fmt, ap);
225 210 va_end(ap);
226 }
227
228 140 const char *ap_error_argument_name(const ap_arg_def *def) {
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
140 if (!def) {
230 return "";
231 }
232
2/4
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
✗ Branch 3 not taken.
140 if (def->flags_count > 0 && def->flags[0]) {
233 140 return def->flags[0];
234 }
235 return def->dest ? def->dest : "";
236 }
237
238 30 void ap_error_label_for_arg(const ap_arg_def *def, char *buf, size_t buf_size) {
239 const char *kind;
240 const char *name;
241
242
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
30 if (!buf || buf_size == 0) {
243 return;
244 }
245
246
3/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 10 times.
30 kind = (def && def->is_optional) ? "option" : "argument";
247 30 name = ap_error_argument_name(def);
248 30 snprintf(buf, buf_size, "%s '%s'", kind, name);
249 }
250
251 9984 char *ap_strdup(const char *s) {
252 size_t len;
253 char *buf;
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9984 times.
9984 if (!s) {
255 return NULL;
256 }
257 9984 len = strlen(s);
258 9984 buf = malloc(len + 1);
259
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9972 times.
9984 if (!buf) {
260 12 return NULL;
261 }
262 9972 memcpy(buf, s, len + 1);
263 9972 return buf;
264 }
265
266 2418 char *ap_strndup(const char *s, size_t n) {
267 char *buf;
268 size_t len;
269
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2418 times.
2418 if (!s) {
270 return NULL;
271 }
272 2418 len = strnlen(s, n);
273 2418 buf = malloc(len + 1);
274
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2416 times.
2418 if (!buf) {
275 2 return NULL;
276 }
277 2416 memcpy(buf, s, len);
278 2416 buf[len] = '\0';
279 2416 return buf;
280 }
281
282 2406 void ap_trim_inplace(char *s) {
283 char *start;
284 char *end;
285 size_t len;
286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2406 times.
2406 if (!s) {
287 return;
288 }
289 2406 start = s;
290
2/4
✓ Branch 0 taken 2406 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2406 times.
2406 while (*start && isspace((unsigned char)*start)) {
291 start++;
292 }
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2406 times.
2406 if (start != s) {
294 memmove(s, start, strlen(start) + 1);
295 }
296 2406 len = strlen(s);
297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2406 times.
2406 if (len == 0) {
298 return;
299 }
300 2406 end = s + len - 1;
301
2/4
✓ Branch 0 taken 2406 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2406 times.
2406 while (end >= s && isspace((unsigned char)*end)) {
302 *end = '\0';
303 end--;
304 }
305 }
306
307 12 bool ap_starts_with_dash(const char *s) {
308
6/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
12 return s && s[0] == '-' && s[1] != '\0';
309 }
310
311 8208 bool ap_token_has_prefix(const ap_parser *parser, const char *s) {
312 const char *prefixes;
313
5/6
✓ Branch 0 taken 8208 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8198 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 8176 times.
8208 if (!s || s[0] == '\0' || s[1] == '\0') {
314 32 return false;
315 }
316
2/4
✓ Branch 0 taken 8176 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8176 times.
✗ Branch 3 not taken.
8176 prefixes = (parser && parser->prefix_chars && parser->prefix_chars[0] != '\0')
317 ? parser->prefix_chars
318
1/2
✓ Branch 0 taken 8176 times.
✗ Branch 1 not taken.
16352 : "-";
319 8176 return strchr(prefixes, s[0]) != NULL;
320 }
321
322 4780 bool ap_is_long_flag(const char *flag) {
323
4/6
✓ Branch 0 taken 4780 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4766 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 4766 times.
✗ Branch 5 not taken.
4780 return flag && strncmp(flag, "--", 2) == 0 && flag[2] != '\0';
324 }
325
326 6702 bool ap_is_short_flag(const char *flag) {
327
6/8
✓ Branch 0 taken 6702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6698 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1936 times.
✓ Branch 5 taken 4762 times.
✓ Branch 6 taken 1936 times.
✗ Branch 7 not taken.
8638 return flag && flag[0] == '-' && flag[1] != '-' && flag[1] != '\0' &&
328
1/2
✓ Branch 0 taken 1936 times.
✗ Branch 1 not taken.
1936 flag[2] == '\0';
329 }
330
331 3452 int ap_strvec_push(ap_strvec *vec, char *item) {
332 char **next_items;
333 int next_cap;
334
2/2
✓ Branch 0 taken 1824 times.
✓ Branch 1 taken 1628 times.
3452 if (vec->count < vec->cap) {
335 1824 vec->items[vec->count++] = item;
336 1824 return 0;
337 }
338
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 1414 times.
1628 next_cap = vec->cap == 0 ? 4 : vec->cap * 2;
339 1628 next_items = realloc(vec->items, sizeof(char *) * (size_t)next_cap);
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1628 times.
1628 if (!next_items) {
341 return -1;
342 }
343 1628 vec->items = next_items;
344 1628 vec->cap = next_cap;
345 1628 vec->items[vec->count++] = item;
346 1628 return 0;
347 }
348
349 3408 void ap_strvec_free(ap_strvec *vec) {
350 int i;
351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3408 times.
3408 if (!vec) {
352 return;
353 }
354
2/2
✓ Branch 0 taken 2708 times.
✓ Branch 1 taken 3408 times.
6116 for (i = 0; i < vec->count; i++) {
355 2708 free(vec->items[i]);
356 }
357 3408 free(vec->items);
358 3408 vec->items = NULL;
359 3408 vec->count = 0;
360 3408 vec->cap = 0;
361 }
362
363 934 static char *normalize_auto_dest(const char *raw) {
364 size_t i;
365 934 char *dest = ap_strdup(raw);
366
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 932 times.
934 if (!dest) {
367 2 return NULL;
368 }
369
2/2
✓ Branch 0 taken 5716 times.
✓ Branch 1 taken 932 times.
6648 for (i = 0; dest[i] != '\0'; i++) {
370
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 5626 times.
5716 if (dest[i] == '-') {
371 90 dest[i] = '_';
372 }
373 }
374 932 return dest;
375 }
376
377 934 static char *pick_default_dest(bool is_optional, char **flags,
378 int flags_count) {
379 934 const char *raw_dest = NULL;
380 int i;
381
382
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 698 times.
934 if (!is_optional) {
383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (flags_count < 1) {
384 return NULL;
385 }
386 236 raw_dest = flags[0];
387 } else {
388
2/2
✓ Branch 0 taken 870 times.
✓ Branch 1 taken 8 times.
878 for (i = 0; i < flags_count; i++) {
389
3/4
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 690 times.
✗ Branch 3 not taken.
870 if (strncmp(flags[i], "--", 2) == 0 && flags[i][2] != '\0') {
390 690 raw_dest = flags[i] + 2;
391 690 break;
392 }
393 }
394
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 690 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
698 if (!raw_dest && flags_count > 0) {
395 8 raw_dest = flags[0];
396
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 while (*raw_dest == '-') {
397 8 raw_dest++;
398 }
399 }
400 }
401
402
2/4
✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 934 times.
934 if (!raw_dest || raw_dest[0] == '\0') {
403 return NULL;
404 }
405 934 return normalize_auto_dest(raw_dest);
406 }
407
408 1602 static int split_flags(const char *name_or_flags, char ***out_flags,
409 int *out_count) {
410 1602 const char *p = name_or_flags;
411 1602 char **flags = NULL;
412 1602 int flags_count = 0;
413 1602 int flags_cap = 0;
414
415
2/2
✓ Branch 0 taken 2408 times.
✓ Branch 1 taken 1598 times.
4006 while (*p) {
416 const char *start;
417 const char *end;
418 size_t len;
419 char *token;
420 char **next;
421
422
4/4
✓ Branch 0 taken 806 times.
✓ Branch 1 taken 3214 times.
✓ Branch 2 taken 806 times.
✓ Branch 3 taken 2408 times.
4020 while (*p == ' ' || *p == ',') {
423 1612 p++;
424 }
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2408 times.
2408 if (*p == '\0') {
426 break;
427 }
428
429 2408 start = p;
430
4/4
✓ Branch 0 taken 13580 times.
✓ Branch 1 taken 1602 times.
✓ Branch 2 taken 12774 times.
✓ Branch 3 taken 806 times.
15182 while (*p && *p != ',') {
431 12774 p++;
432 }
433 2408 end = p;
434
2/4
✓ Branch 0 taken 2408 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2408 times.
2408 while (end > start && isspace((unsigned char)*(end - 1))) {
435 end--;
436 }
437
2/4
✓ Branch 0 taken 2408 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2408 times.
2408 while (start < end && isspace((unsigned char)*start)) {
438 start++;
439 }
440 2408 len = (size_t)(end - start);
441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2408 times.
2408 if (len == 0) {
442 continue;
443 }
444
445 2408 token = ap_strndup(start, len);
446
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2406 times.
2408 if (!token) {
447 2 goto fail;
448 }
449 2406 ap_trim_inplace(token);
450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2406 times.
2406 if (token[0] == '\0') {
451 free(token);
452 continue;
453 }
454
455
2/2
✓ Branch 0 taken 1600 times.
✓ Branch 1 taken 806 times.
2406 if (flags_count == flags_cap) {
456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1600 times.
1600 int next_cap = flags_cap == 0 ? 2 : flags_cap * 2;
457 1600 next = realloc(flags, sizeof(char *) * (size_t)next_cap);
458
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1598 times.
1600 if (!next) {
459 2 free(token);
460 2 goto fail;
461 }
462 1598 flags = next;
463 1598 flags_cap = next_cap;
464 }
465 2404 flags[flags_count++] = token;
466 }
467
468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1598 times.
1598 if (flags_count == 0) {
469 return -1;
470 }
471
472 1598 *out_flags = flags;
473 1598 *out_count = flags_count;
474 1598 return 0;
475
476 4 fail:
477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 while (flags_count > 0) {
478 free(flags[--flags_count]);
479 }
480 4 free(flags);
481 4 return -1;
482 }
483
484 628 ap_parser_options ap_parser_options_default(void) {
485 ap_parser_options options;
486 628 options.completion_enabled = true;
487 628 options.completion_entrypoint = default_completion_entrypoint();
488 628 options.prefix_chars = "-";
489 628 options.allow_abbrev = false;
490 628 options.fromfile_prefix_chars = NULL;
491 628 options.inherit_from = NULL;
492 628 options.conflict_policy = AP_PARSER_CONFLICT_ERROR;
493 628 options.help_formatter_mode = AP_HELP_FORMATTER_STANDARD;
494 628 return options;
495 }
496
497 1580 ap_arg_options ap_arg_options_default(void) {
498 ap_arg_options options;
499 1580 memset(&options, 0, sizeof(options));
500 1580 options.type = AP_TYPE_STRING;
501 1580 options.action = AP_ACTION_STORE;
502 1580 options.nargs = AP_NARGS_ONE;
503 1580 options.nargs_count = 1;
504 1580 return options;
505 }
506
507 160 void ap_completion_result_init(ap_completion_result *result) {
508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
160 if (!result) {
509 return;
510 }
511 160 memset(result, 0, sizeof(*result));
512 }
513
514 68 void ap_completion_result_free(ap_completion_result *result) {
515 int i;
516
517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 if (!result) {
518 return;
519 }
520
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 68 times.
138 for (i = 0; i < result->count; i++) {
521 70 free((void *)result->items[i].value);
522 70 free((void *)result->items[i].help);
523 }
524 68 free(result->items);
525 68 ap_completion_result_init(result);
526 }
527
528 76 int ap_completion_result_add(ap_completion_result *result, const char *value,
529 const char *help, ap_error *err) {
530 ap_completion_candidate *next;
531 int next_cap;
532
533
3/6
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 76 times.
76 if (!result || !value || value[0] == '\0') {
534 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "",
535 "completion value is required");
536 return -1;
537 }
538
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 34 times.
76 if (result->count == result->cap) {
539
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 next_cap = result->cap == 0 ? 4 : result->cap * 2;
540 42 next = realloc(result->items,
541 42 sizeof(ap_completion_candidate) * (size_t)next_cap);
542
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40 times.
42 if (!next) {
543 2 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
544 2 return -1;
545 }
546 40 result->items = next;
547 40 result->cap = next_cap;
548 }
549 74 result->items[result->count].value = ap_strdup(value);
550
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 40 times.
74 result->items[result->count].help = help ? ap_strdup(help) : NULL;
551
4/4
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 40 times.
74 if (!result->items[result->count].value ||
552
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 30 times.
32 (help && !result->items[result->count].help)) {
553 4 free((void *)result->items[result->count].value);
554 4 free((void *)result->items[result->count].help);
555 4 result->items[result->count].value = NULL;
556 4 result->items[result->count].help = NULL;
557 4 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
558 4 return -1;
559 }
560 70 result->count++;
561 70 return 0;
562 }
563
564 630 static int add_builtin_help(ap_parser *parser) {
565 ap_arg_options opts;
566 ap_error ignored_err;
567 char flags_buf[32];
568 630 char prefix = '-';
569
570
3/6
✓ Branch 0 taken 630 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 630 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 630 times.
✗ Branch 5 not taken.
630 if (parser && parser->prefix_chars && parser->prefix_chars[0] != '\0') {
571 630 prefix = parser->prefix_chars[0];
572 }
573
574 630 opts = ap_arg_options_default();
575 630 opts.type = AP_TYPE_BOOL;
576 630 opts.action = AP_ACTION_STORE_TRUE;
577 630 opts.nargs = AP_NARGS_ONE;
578 630 opts.help = "show this help message and exit";
579 630 opts.dest = "help";
580 630 snprintf(flags_buf, sizeof(flags_buf), "%ch, %c%chelp", prefix, prefix,
581 prefix);
582 630 return ap_add_argument(parser, flags_buf, opts, &ignored_err);
583 }
584
585 10 static int clone_arg_def(const ap_arg_def *src, ap_arg_def *dst) {
586 int i;
587
588 10 memset(dst, 0, sizeof(*dst));
589 10 dst->is_optional = src->is_optional;
590 10 dst->inherited = true;
591 10 dst->mutex_group_index = src->mutex_group_index;
592 10 dst->arg_group_index = src->arg_group_index;
593 10 dst->opts = src->opts;
594 10 dst->flags_count = src->flags_count;
595
596 10 dst->dest = ap_strdup(src->dest);
597
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!dst->dest) {
598 arg_def_free(dst);
599 return -1;
600 }
601
602
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (dst->flags_count > 0) {
603 10 dst->flags = calloc((size_t)dst->flags_count, sizeof(char *));
604
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!dst->flags) {
605 arg_def_free(dst);
606 return -1;
607 }
608
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (i = 0; i < dst->flags_count; i++) {
609 10 dst->flags[i] = ap_strdup(src->flags[i]);
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!dst->flags[i]) {
611 arg_def_free(dst);
612 return -1;
613 }
614 }
615 }
616 10 return 0;
617 }
618
619 6 static int import_parser_defs(ap_parser *dst, const ap_parser *src,
620 ap_parser_conflict_policy policy, ap_error *err) {
621 int i;
622 6 int *imported_mutex_map = NULL;
623 6 int *imported_arg_map = NULL;
624
625
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (src->mutex_groups_count > 0) {
626 2 imported_mutex_map = malloc(sizeof(int) * (size_t)src->mutex_groups_count);
627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!imported_mutex_map) {
628 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
629 return -1;
630 }
631
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (i = 0; i < src->mutex_groups_count; i++) {
632 2 imported_mutex_map[i] = -1;
633 }
634 }
635
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (src->arg_groups_count > 0) {
636 2 imported_arg_map = malloc(sizeof(int) * (size_t)src->arg_groups_count);
637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!imported_arg_map) {
638 free(imported_mutex_map);
639 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
640 return -1;
641 }
642
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (i = 0; i < src->arg_groups_count; i++) {
643 2 imported_arg_map[i] = -1;
644 }
645 }
646
647
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 6 times.
22 for (i = 0; i < src->defs_count; i++) {
648 ap_arg_def cloned;
649 16 const ap_arg_def *src_def = &src->defs[i];
650 int dest_conflict;
651 int j;
652 16 int flag_conflict = -1;
653
654
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 if (strcmp(src_def->dest, "help") == 0) {
655 6 continue;
656 }
657
658 10 dest_conflict = parser_find_def_by_dest(dst, src_def->dest);
659
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
20 for (j = 0; j < src_def->flags_count && flag_conflict < 0; j++) {
660 10 flag_conflict = parser_find_def_by_flag(dst, src_def->flags[j]);
661 }
662
663
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (dest_conflict >= 0 || flag_conflict >= 0) {
664 if (policy == AP_PARSER_CONFLICT_KEEP_EXISTING) {
665 continue;
666 }
667 if (policy == AP_PARSER_CONFLICT_REPLACE) {
668 while ((dest_conflict = parser_find_def_by_dest(dst, src_def->dest)) >=
669 0) {
670 parser_remove_def(dst, dest_conflict);
671 }
672 for (j = 0; j < src_def->flags_count; j++) {
673 while ((flag_conflict =
674 parser_find_def_by_flag(dst, src_def->flags[j])) >= 0) {
675 parser_remove_def(dst, flag_conflict);
676 }
677 }
678 } else {
679 ap_error_set(err, AP_ERR_INVALID_DEFINITION, src_def->dest,
680 "dest '%s' already exists", src_def->dest);
681 free(imported_mutex_map);
682 free(imported_arg_map);
683 return -1;
684 }
685 }
686
687
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (clone_arg_def(src_def, &cloned) != 0) {
688 ap_error_set(err, AP_ERR_NO_MEMORY, src_def->dest, "out of memory");
689 free(imported_mutex_map);
690 free(imported_arg_map);
691 return -1;
692 }
693
694
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 if (src_def->mutex_group_index >= 0) {
695 4 int src_group_index = src_def->mutex_group_index;
696
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (imported_mutex_map[src_group_index] < 0) {
697 2 ap_mutex_group_def *src_group = &src->mutex_groups[src_group_index];
698 ap_mutex_group_def *new_group;
699
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (ensure_mutex_groups_capacity(dst) != 0) {
700 arg_def_free(&cloned);
701 ap_error_set(err, AP_ERR_NO_MEMORY, src_def->dest, "out of memory");
702 free(imported_mutex_map);
703 free(imported_arg_map);
704 return -1;
705 }
706 2 new_group = &dst->mutex_groups[dst->mutex_groups_count];
707 2 memset(new_group, 0, sizeof(*new_group));
708 2 new_group->required = src_group->required;
709 2 new_group->handle.parser = dst;
710 2 new_group->handle.index = dst->mutex_groups_count;
711 2 imported_mutex_map[src_group_index] = dst->mutex_groups_count;
712 2 dst->mutex_groups_count++;
713 }
714 4 cloned.mutex_group_index = imported_mutex_map[src_group_index];
715 }
716
717
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (src_def->arg_group_index >= 0) {
718 int src_group_index = src_def->arg_group_index;
719 if (imported_arg_map[src_group_index] < 0) {
720 ap_arg_group_def *src_group = &src->arg_groups[src_group_index];
721 ap_arg_group_def *new_group;
722 if (ensure_arg_groups_capacity(dst) != 0) {
723 arg_def_free(&cloned);
724 ap_error_set(err, AP_ERR_NO_MEMORY, src_def->dest, "out of memory");
725 free(imported_mutex_map);
726 free(imported_arg_map);
727 return -1;
728 }
729 new_group = &dst->arg_groups[dst->arg_groups_count];
730 memset(new_group, 0, sizeof(*new_group));
731 new_group->title = ap_strdup(src_group->title ? src_group->title : "");
732 new_group->description =
733 src_group->description ? ap_strdup(src_group->description) : NULL;
734 if (!new_group->title ||
735 (src_group->description && !new_group->description)) {
736 free(new_group->title);
737 free(new_group->description);
738 arg_def_free(&cloned);
739 ap_error_set(err, AP_ERR_NO_MEMORY, src_def->dest, "out of memory");
740 free(imported_mutex_map);
741 free(imported_arg_map);
742 return -1;
743 }
744 new_group->handle.parser = dst;
745 new_group->handle.index = dst->arg_groups_count;
746 imported_arg_map[src_group_index] = dst->arg_groups_count;
747 dst->arg_groups_count++;
748 }
749 cloned.arg_group_index = imported_arg_map[src_group_index];
750 }
751
752
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (ensure_defs_capacity(dst) != 0) {
753 arg_def_free(&cloned);
754 ap_error_set(err, AP_ERR_NO_MEMORY, src_def->dest, "out of memory");
755 free(imported_mutex_map);
756 free(imported_arg_map);
757 return -1;
758 }
759 10 dst->defs[dst->defs_count++] = cloned;
760
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
14 if (cloned.mutex_group_index >= 0 &&
761 4 mutex_group_push_arg(&dst->mutex_groups[cloned.mutex_group_index],
762 4 dst->defs_count - 1) != 0) {
763 parser_remove_def(dst, dst->defs_count - 1);
764 ap_error_set(err, AP_ERR_NO_MEMORY, src_def->dest, "out of memory");
765 free(imported_mutex_map);
766 free(imported_arg_map);
767 return -1;
768 }
769
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (cloned.arg_group_index >= 0 &&
770 argument_group_push_arg(&dst->arg_groups[cloned.arg_group_index],
771 dst->defs_count - 1) != 0) {
772 parser_remove_def(dst, dst->defs_count - 1);
773 ap_error_set(err, AP_ERR_NO_MEMORY, src_def->dest, "out of memory");
774 free(imported_mutex_map);
775 free(imported_arg_map);
776 return -1;
777 }
778 }
779 6 free(imported_mutex_map);
780 6 free(imported_arg_map);
781 6 return 0;
782 }
783
784 632 static ap_parser *parser_alloc(const char *prog, const char *description,
785 const char *command_name, ap_parser *parent,
786 ap_parser_options options) {
787 632 ap_parser *parser = calloc(1, sizeof(ap_parser));
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 632 times.
632 if (!parser) {
789 return NULL;
790 }
791
792
1/2
✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
632 parser->prog = ap_strdup(prog ? prog : "program");
793
1/2
✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
632 parser->description = ap_strdup(description ? description : "");
794
1/2
✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
632 parser->command_name = ap_strdup(command_name ? command_name : "");
795 632 parser->completion_enabled = options.completion_enabled;
796 632 parser->completion_entrypoint = ap_strdup(
797
1/2
✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
632 options.completion_entrypoint ? options.completion_entrypoint
798 : default_completion_entrypoint());
799 632 parser->prefix_chars =
800
1/2
✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
632 ap_strdup(options.prefix_chars ? options.prefix_chars : "-");
801 632 parser->allow_abbrev = options.allow_abbrev;
802 1264 parser->fromfile_prefix_chars = options.fromfile_prefix_chars
803 6 ? ap_strdup(options.fromfile_prefix_chars)
804
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 626 times.
632 : NULL;
805 632 parser->conflict_policy = options.conflict_policy;
806 632 parser->help_formatter_mode = options.help_formatter_mode;
807 632 parser->parent = parent;
808
4/6
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 630 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 630 times.
✗ Branch 5 not taken.
632 if (!parser->prog || !parser->description || !parser->command_name ||
809
2/4
✓ Branch 0 taken 630 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 630 times.
✗ Branch 3 not taken.
630 !parser->completion_entrypoint || !parser->prefix_chars ||
810
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 624 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
630 (options.fromfile_prefix_chars && !parser->fromfile_prefix_chars)) {
811 2 ap_parser_free(parser);
812 2 return NULL;
813 }
814
815
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 630 times.
630 if (add_builtin_help(parser) != 0) {
816 ap_parser_free(parser);
817 return NULL;
818 }
819
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 624 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
636 if (options.inherit_from &&
820 6 import_parser_defs(parser, options.inherit_from, options.conflict_policy,
821 NULL) != 0) {
822 ap_parser_free(parser);
823 return NULL;
824 }
825 630 return parser;
826 }
827
828 472 ap_parser *ap_parser_new(const char *prog, const char *description) {
829 472 return ap_parser_new_with_options(prog, description,
830 ap_parser_options_default());
831 }
832
833 506 ap_parser *ap_parser_new_with_options(const char *prog, const char *description,
834 ap_parser_options options) {
835 506 return parser_alloc(prog, description, "", NULL, options);
836 }
837
838 20 int ap_parser_set_completion(ap_parser *parser, bool enabled,
839 const char *entrypoint, ap_error *err) {
840 int i;
841 char *next_entrypoint;
842
843
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
20 if (!parser) {
844 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "", "parser is required");
845 2 return -1;
846 }
847
848 next_entrypoint =
849
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
18 ap_strdup(entrypoint ? entrypoint : default_completion_entrypoint());
850
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (!next_entrypoint) {
851 2 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
852 2 return -1;
853 }
854
855
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
20 for (i = 0; i < parser->subcommands_count; i++) {
856
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
8 if (enabled && strcmp(parser->subcommands[i].name, next_entrypoint) == 0) {
857 4 ap_error_set(
858 err, AP_ERR_INVALID_DEFINITION, next_entrypoint,
859 "subcommand '%s' conflicts with reserved completion entrypoint",
860 next_entrypoint);
861 4 free(next_entrypoint);
862 4 return -1;
863 }
864 }
865
866 12 free(parser->completion_entrypoint);
867 12 parser->completion_entrypoint = next_entrypoint;
868 12 parser->completion_enabled = enabled;
869 12 return 0;
870 }
871
872 8 bool ap_parser_completion_enabled(const ap_parser *parser) {
873
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
8 return parser && parser->completion_enabled;
874 }
875
876 1808 const char *ap_parser_completion_entrypoint(const ap_parser *parser) {
877
1/2
✓ Branch 0 taken 1806 times.
✗ Branch 1 not taken.
1806 return parser && parser->completion_entrypoint
878 ? parser->completion_entrypoint
879
2/2
✓ Branch 0 taken 1806 times.
✓ Branch 1 taken 2 times.
3614 : default_completion_entrypoint();
880 }
881
882 1594 static int validate_options(const ap_arg_options *options, bool is_optional,
883 const char *name_or_flags, ap_error *err) {
884
2/2
✓ Branch 0 taken 862 times.
✓ Branch 1 taken 732 times.
1594 if (options->action == AP_ACTION_STORE_TRUE ||
885
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 856 times.
862 options->action == AP_ACTION_STORE_FALSE) {
886
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 736 times.
738 if (options->type != AP_TYPE_BOOL) {
887 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
888 "store_true/store_false requires bool type");
889 2 return -1;
890 }
891
3/4
✓ Branch 0 taken 734 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 734 times.
✗ Branch 3 not taken.
736 if (options->choices.items || options->default_value ||
892
2/4
✓ Branch 0 taken 734 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 734 times.
734 options->const_value || options->nargs != AP_NARGS_ONE) {
893 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
894 "store_true/store_false do not support "
895 "choices/default_value/const_value/custom nargs");
896 2 return -1;
897 }
898 734 return 0;
899 }
900
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 824 times.
856 if (options->action == AP_ACTION_COUNT) {
901
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 30 times.
32 if (options->type != AP_TYPE_INT32) {
902 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
903 "count action requires int32 type");
904 2 return -1;
905 }
906
3/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
30 if (options->choices.items || options->default_value ||
907
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
28 options->const_value || options->nargs != AP_NARGS_ONE) {
908 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
909 "count action does not support "
910 "choices/default_value/const_value/custom nargs");
911 2 return -1;
912 }
913 28 return 0;
914 }
915
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 808 times.
824 if (options->action == AP_ACTION_STORE_CONST) {
916
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (!options->const_value) {
917 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
918 "store_const requires const_value");
919 2 return -1;
920 }
921
3/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 2 times.
14 if (options->default_value || options->choices.items ||
922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 options->nargs != AP_NARGS_ONE) {
923 2 ap_error_set(
924 err, AP_ERR_INVALID_DEFINITION, name_or_flags,
925 "store_const does not support default_value/choices/custom nargs");
926 2 return -1;
927 }
928 12 return 0;
929 }
930
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 756 times.
808 if (options->action != AP_ACTION_STORE &&
931
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
52 options->action != AP_ACTION_APPEND && options->type == AP_TYPE_BOOL) {
932 return 0;
933 }
934
4/4
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 644 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 38 times.
808 if (options->nargs != AP_NARGS_ONE && options->nargs != AP_NARGS_OPTIONAL &&
935
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 42 times.
126 options->nargs != AP_NARGS_ZERO_OR_MORE &&
936
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 28 times.
84 options->nargs != AP_NARGS_ONE_OR_MORE &&
937
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 54 times.
56 options->nargs != AP_NARGS_FIXED) {
938 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
939 "invalid nargs definition");
940 2 return -1;
941 }
942
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 752 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 52 times.
806 if (options->nargs == AP_NARGS_FIXED && options->nargs_count <= 0) {
943 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
944 "fixed nargs requires nargs_count > 0");
945 2 return -1;
946 }
947
4/4
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 568 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 206 times.
804 if (!is_optional && options->action != AP_ACTION_STORE &&
948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 options->action != AP_ACTION_APPEND) {
949 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
950 "positional arguments support only store/append actions");
951 return -1;
952 }
953 804 return 0;
954 }
955
956 1604 int ap_add_argument(ap_parser *parser, const char *name_or_flags,
957 ap_arg_options options, ap_error *err) {
958 ap_arg_def def;
959 int i;
960
961
4/6
✓ Branch 0 taken 1602 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1602 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1602 times.
1604 if (!parser || !name_or_flags || name_or_flags[0] == '\0') {
962 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "",
963 "parser and argument name are required");
964 2 return -1;
965 }
966
967 1602 memset(&def, 0, sizeof(def));
968 1602 def.is_optional = ap_token_has_prefix(parser, name_or_flags);
969 1602 def.mutex_group_index = -1;
970 1602 def.arg_group_index = -1;
971
972
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1598 times.
1602 if (split_flags(name_or_flags, &def.flags, &def.flags_count) != 0) {
973 4 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
974 "invalid argument declaration");
975 4 return -1;
976 }
977
978
2/2
✓ Branch 0 taken 1360 times.
✓ Branch 1 taken 238 times.
1598 if (def.is_optional) {
979
2/2
✓ Branch 0 taken 2164 times.
✓ Branch 1 taken 1358 times.
3522 for (i = 0; i < def.flags_count; i++) {
980
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2162 times.
2164 if (!ap_token_has_prefix(parser, def.flags[i])) {
981 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, def.flags[i],
982 "optional argument flags must start with '-'");
983 2 arg_def_free(&def);
984 2 return -1;
985 }
986 }
987
3/4
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 236 times.
474 } else if (def.flags_count != 1 ||
988 236 ap_token_has_prefix(parser, def.flags[0])) {
989 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name_or_flags,
990 "positional argument must be a single non-flag token");
991 2 arg_def_free(&def);
992 2 return -1;
993 }
994
995
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1578 times.
1594 if (validate_options(&options, def.is_optional, name_or_flags, err) != 0) {
996 16 arg_def_free(&def);
997 16 return -1;
998 }
999
1000
2/2
✓ Branch 0 taken 850 times.
✓ Branch 1 taken 728 times.
1578 if (options.action == AP_ACTION_STORE_TRUE ||
1001
2/2
✓ Branch 0 taken 844 times.
✓ Branch 1 taken 6 times.
850 options.action == AP_ACTION_STORE_FALSE ||
1002
2/2
✓ Branch 0 taken 816 times.
✓ Branch 1 taken 28 times.
844 options.action == AP_ACTION_COUNT ||
1003
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 804 times.
816 options.action == AP_ACTION_STORE_CONST) {
1004 774 options.nargs = AP_NARGS_ONE;
1005 774 options.nargs_count = 1;
1006 }
1007
1008 644 def.dest = options.dest ? ap_strdup(options.dest)
1009
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 934 times.
1578 : pick_default_dest(def.is_optional, def.flags,
1010 def.flags_count);
1011
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1576 times.
1578 if (!def.dest) {
1012 2 ap_error_set(err, AP_ERR_NO_MEMORY, name_or_flags, "out of memory");
1013 2 arg_def_free(&def);
1014 2 return -1;
1015 }
1016
1017 1576 def.opts = options;
1018
1019 4 while (true) {
1020 1580 int conflict_index = parser_find_def_by_dest(parser, def.dest);
1021
2/2
✓ Branch 0 taken 1572 times.
✓ Branch 1 taken 8 times.
1580 if (conflict_index < 0) {
1022 1572 break;
1023 }
1024
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (parser->conflict_policy == AP_PARSER_CONFLICT_REPLACE) {
1025 4 parser_remove_def(parser, conflict_index);
1026 4 continue;
1027 }
1028 4 ap_error_set(err, AP_ERR_INVALID_DEFINITION, def.dest,
1029 "dest '%s' already exists", def.dest);
1030 4 arg_def_free(&def);
1031 4 return -1;
1032 }
1033
1034
2/2
✓ Branch 0 taken 2374 times.
✓ Branch 1 taken 1572 times.
3946 for (i = 0; i < def.flags_count; i++) {
1035 2 while (true) {
1036 2376 int conflict_index = parser_find_def_by_flag(parser, def.flags[i]);
1037
2/2
✓ Branch 0 taken 2374 times.
✓ Branch 1 taken 2 times.
2376 if (conflict_index < 0) {
1038 2374 break;
1039 }
1040
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (parser->conflict_policy == AP_PARSER_CONFLICT_REPLACE) {
1041 2 parser_remove_def(parser, conflict_index);
1042 2 continue;
1043 }
1044 ap_error_set(err, AP_ERR_INVALID_DEFINITION, def.flags[i],
1045 "flag '%s' already exists", def.flags[i]);
1046 arg_def_free(&def);
1047 return -1;
1048 }
1049 }
1050
1051
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1572 times.
1572 if (ensure_defs_capacity(parser) != 0) {
1052 ap_error_set(err, AP_ERR_NO_MEMORY, def.dest, "out of memory");
1053 arg_def_free(&def);
1054 return -1;
1055 }
1056
1057 1572 parser->defs[parser->defs_count++] = def;
1058 1572 return 0;
1059 }
1060
1061 10 ap_mutually_exclusive_group *ap_add_mutually_exclusive_group(ap_parser *parser,
1062 bool required,
1063 ap_error *err) {
1064 ap_mutex_group_def *def;
1065
1066
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if (!parser) {
1067 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "", "parser is required");
1068 2 return NULL;
1069 }
1070
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (ensure_mutex_groups_capacity(parser) != 0) {
1071 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
1072 return NULL;
1073 }
1074 8 def = &parser->mutex_groups[parser->mutex_groups_count];
1075 8 memset(def, 0, sizeof(*def));
1076 8 def->required = required;
1077 8 def->handle.parser = parser;
1078 8 def->handle.index = parser->mutex_groups_count;
1079 8 parser->mutex_groups_count++;
1080 8 return &def->handle;
1081 }
1082
1083 14 ap_argument_group *ap_add_argument_group(ap_parser *parser, const char *title,
1084 const char *description,
1085 ap_error *err) {
1086 ap_arg_group_def *def;
1087
1088
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
14 if (!parser || !title || title[0] == '\0') {
1089 4 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "",
1090 "parser and title are required");
1091 4 return NULL;
1092 }
1093
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (ensure_arg_groups_capacity(parser) != 0) {
1094 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
1095 return NULL;
1096 }
1097 10 def = &parser->arg_groups[parser->arg_groups_count];
1098 10 memset(def, 0, sizeof(*def));
1099 10 def->title = ap_strdup(title);
1100
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 def->description = ap_strdup(description ? description : "");
1101
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (!def->title || !def->description) {
1102 free(def->title);
1103 free(def->description);
1104 def->title = NULL;
1105 def->description = NULL;
1106 ap_error_set(err, AP_ERR_NO_MEMORY, title, "out of memory");
1107 return NULL;
1108 }
1109 10 def->handle.parser = parser;
1110 10 def->handle.index = parser->arg_groups_count;
1111 10 parser->arg_groups_count++;
1112 10 return &def->handle;
1113 }
1114
1115 16 int ap_group_add_argument(ap_mutually_exclusive_group *group,
1116 const char *name_or_flags, ap_arg_options options,
1117 ap_error *err) {
1118 ap_parser *parser;
1119 int arg_index;
1120
1121
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
16 if (!group || !group->parser) {
1122 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "", "group is required");
1123 2 return -1;
1124 }
1125 14 parser = group->parser;
1126 14 arg_index = parser->defs_count;
1127
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 if (ap_add_argument(parser, name_or_flags, options, err) != 0) {
1128 return -1;
1129 }
1130 14 parser->defs[arg_index].mutex_group_index = group->index;
1131
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 if (mutex_group_push_arg(&parser->mutex_groups[group->index], arg_index) !=
1132 0) {
1133 ap_error_set(err, AP_ERR_NO_MEMORY, name_or_flags, "out of memory");
1134 return -1;
1135 }
1136 14 return 0;
1137 }
1138
1139 12 int ap_argument_group_add_argument(ap_argument_group *group,
1140 const char *name_or_flags,
1141 ap_arg_options options, ap_error *err) {
1142 ap_parser *parser;
1143 int arg_index;
1144
1145
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
12 if (!group || !group->parser) {
1146 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "", "group is required");
1147 2 return -1;
1148 }
1149 10 parser = group->parser;
1150 10 arg_index = parser->defs_count;
1151
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (ap_add_argument(parser, name_or_flags, options, err) != 0) {
1152 return -1;
1153 }
1154 10 parser->defs[arg_index].arg_group_index = group->index;
1155
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if (argument_group_push_arg(&parser->arg_groups[group->index], arg_index) !=
1156 0) {
1157 ap_error_set(err, AP_ERR_NO_MEMORY, name_or_flags, "out of memory");
1158 return -1;
1159 }
1160 10 return 0;
1161 }
1162
1163 134 ap_parser *ap_add_subcommand(ap_parser *parser, const char *name,
1164 const char *description, ap_error *err) {
1165 ap_subcommand_def def;
1166 134 char *prog = NULL;
1167 size_t prog_len;
1168 int i;
1169
1170
4/8
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 134 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 134 times.
✗ Branch 7 not taken.
268 if (!parser || !name || name[0] == '\0' ||
1171
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 132 times.
268 ap_token_has_prefix(parser, name) || strchr(name, ' ') != NULL) {
1172
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name ? name : "",
1173 "subcommand name must be a single non-flag token");
1174 2 return NULL;
1175 }
1176
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 130 times.
132 if (is_reserved_completion_name(parser, name)) {
1177 2 ap_error_set(
1178 err, AP_ERR_INVALID_DEFINITION, name,
1179 "subcommand '%s' conflicts with reserved completion entrypoint", name);
1180 2 return NULL;
1181 }
1182
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 128 times.
134 for (i = 0; i < parser->subcommands_count; i++) {
1183
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (strcmp(parser->subcommands[i].name, name) == 0) {
1184 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, name,
1185 "subcommand '%s' already exists", name);
1186 2 return NULL;
1187 }
1188 }
1189
1190 128 prog_len = strlen(parser->prog) + strlen(name) + 2;
1191 128 prog = malloc(prog_len);
1192
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
128 if (!prog) {
1193 2 ap_error_set(err, AP_ERR_NO_MEMORY, name, "out of memory");
1194 2 return NULL;
1195 }
1196 126 snprintf(prog, prog_len, "%s %s", parser->prog, name);
1197
1198 126 memset(&def, 0, sizeof(def));
1199 126 def.name = ap_strdup(name);
1200
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 def.help = ap_strdup(description ? description : "");
1201 {
1202 126 ap_parser_options child_options = ap_parser_options_default();
1203 126 child_options.completion_enabled = parser->completion_enabled;
1204 126 child_options.completion_entrypoint = parser->completion_entrypoint;
1205 126 child_options.prefix_chars = parser->prefix_chars;
1206 126 child_options.allow_abbrev = parser->allow_abbrev;
1207 126 child_options.fromfile_prefix_chars = parser->fromfile_prefix_chars;
1208 126 child_options.help_formatter_mode = parser->help_formatter_mode;
1209
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 def.parser = parser_alloc(prog, description ? description : "", name,
1210 parser, child_options);
1211 }
1212 126 free(prog);
1213
3/6
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 126 times.
126 if (!def.name || !def.help || !def.parser) {
1214 free(def.name);
1215 free(def.help);
1216 ap_parser_free(def.parser);
1217 ap_error_set(err, AP_ERR_NO_MEMORY, name, "out of memory");
1218 return NULL;
1219 }
1220
1221
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
126 if (ensure_subcommands_capacity(parser) != 0) {
1222 free(def.name);
1223 free(def.help);
1224 ap_parser_free(def.parser);
1225 ap_error_set(err, AP_ERR_NO_MEMORY, name, "out of memory");
1226 return NULL;
1227 }
1228
1229 126 parser->subcommands[parser->subcommands_count++] = def;
1230 126 return def.parser;
1231 }
1232
1233 804 static const ap_ns_entry *find_entry(const ap_namespace *ns, const char *dest) {
1234 int i;
1235
2/4
✓ Branch 0 taken 804 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 804 times.
804 if (!ns || !dest) {
1236 return NULL;
1237 }
1238
2/2
✓ Branch 0 taken 2182 times.
✓ Branch 1 taken 24 times.
2206 for (i = 0; i < ns->count; i++) {
1239
2/2
✓ Branch 0 taken 780 times.
✓ Branch 1 taken 1402 times.
2182 if (strcmp(ns->entries[i].dest, dest) == 0) {
1240 780 return &ns->entries[i];
1241 }
1242 }
1243 24 return NULL;
1244 }
1245
1246 328 static void free_parsed_args(const ap_parser *parser, ap_parsed_arg *parsed) {
1247 int i;
1248
3/4
✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 268 times.
328 if (!parser || !parsed) {
1249 60 return;
1250 }
1251
2/2
✓ Branch 0 taken 832 times.
✓ Branch 1 taken 268 times.
1100 for (i = 0; i < parser->defs_count; i++) {
1252 832 ap_strvec_free(&parsed[i].tokens);
1253 832 ap_strvec_free(&parsed[i].values);
1254 }
1255 268 free(parsed);
1256 }
1257
1258 326 static int find_subcommand_arg_index(const ap_parser *parser, int argc,
1259 char **argv, int *out_index,
1260 int *out_subcommand_index) {
1261 int i;
1262 326 bool positional_only = false;
1263
1264 326 *out_index = -1;
1265 326 *out_subcommand_index = -1;
1266
1267
2/2
✓ Branch 0 taken 1700 times.
✓ Branch 1 taken 310 times.
2010 for (i = 1; i < argc; i++) {
1268 1700 const char *token = argv[i];
1269 int j;
1270
1271
4/4
✓ Branch 0 taken 1464 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 1430 times.
1700 if (!positional_only && strcmp(token, "--") == 0) {
1272 34 positional_only = true;
1273 34 continue;
1274 }
1275
1276
4/4
✓ Branch 0 taken 1430 times.
✓ Branch 1 taken 236 times.
✓ Branch 3 taken 928 times.
✓ Branch 4 taken 502 times.
1666 if (!positional_only && ap_token_has_prefix(parser, token)) {
1277 928 const char *eq = strchr(token, '=');
1278
2/2
✓ Branch 0 taken 2906 times.
✓ Branch 1 taken 456 times.
3362 for (j = 0; j < parser->defs_count; j++) {
1279 2906 const ap_arg_def *def = &parser->defs[j];
1280 int k;
1281
2/2
✓ Branch 0 taken 446 times.
✓ Branch 1 taken 2460 times.
2906 if (!def->is_optional) {
1282 446 continue;
1283 }
1284
2/2
✓ Branch 0 taken 4290 times.
✓ Branch 1 taken 1988 times.
6278 for (k = 0; k < def->flags_count; k++) {
1285 4290 size_t flag_len = strlen(def->flags[k]);
1286 4290 bool exact_match = strcmp(def->flags[k], token) == 0;
1287 4382 bool inline_match = eq &&
1288
4/4
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4198 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 82 times.
4300 strncmp(def->flags[k], token, flag_len) == 0 &&
1289
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 token[flag_len] == '=';
1290
4/4
✓ Branch 0 taken 3828 times.
✓ Branch 1 taken 462 times.
✓ Branch 2 taken 3818 times.
✓ Branch 3 taken 10 times.
4290 if (!exact_match && !inline_match) {
1291 3818 continue;
1292 }
1293
2/2
✓ Branch 0 taken 462 times.
✓ Branch 1 taken 10 times.
472 if (!inline_match &&
1294
2/2
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 216 times.
462 (def->opts.action == AP_ACTION_STORE ||
1295
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 126 times.
246 def->opts.action == AP_ACTION_APPEND) &&
1296
3/4
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 312 times.
✗ Branch 3 not taken.
336 def->opts.nargs == AP_NARGS_ONE && i + 1 < argc) {
1297 312 i++;
1298
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 10 times.
160 } else if (!inline_match &&
1299
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 24 times.
150 (def->opts.action == AP_ACTION_STORE ||
1300
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 def->opts.action == AP_ACTION_APPEND) &&
1301
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
24 def->opts.nargs == AP_NARGS_OPTIONAL && i + 1 < argc &&
1302
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 2 times.
16 !ap_token_has_prefix(parser, argv[i + 1])) {
1303 14 i++;
1304
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 10 times.
146 } else if (!inline_match &&
1305
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 10 times.
136 (def->opts.action == AP_ACTION_STORE ||
1306
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 def->opts.action == AP_ACTION_APPEND) &&
1307
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 def->opts.nargs == AP_NARGS_FIXED) {
1308 4 i += def->opts.nargs_count;
1309
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 10 times.
142 } else if (!inline_match &&
1310
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 6 times.
132 (def->opts.action == AP_ACTION_STORE ||
1311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 def->opts.action == AP_ACTION_APPEND) &&
1312
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 (def->opts.nargs == AP_NARGS_ZERO_OR_MORE ||
1313
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 def->opts.nargs == AP_NARGS_ONE_OR_MORE)) {
1314
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 while (i + 1 < argc && strcmp(argv[i + 1], "--") != 0 &&
1315
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 !ap_token_has_prefix(parser, argv[i + 1])) {
1316 4 i++;
1317 }
1318 }
1319 472 goto next_token;
1320 }
1321 }
1322 }
1323
1324
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1178 times.
1194 for (j = 0; j < parser->subcommands_count; j++) {
1325
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (strcmp(parser->subcommands[j].name, token) == 0) {
1326 16 *out_index = i;
1327 16 *out_subcommand_index = j;
1328 16 return 0;
1329 }
1330 }
1331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1178 times.
1178 if (parser->subcommands_count > 0) {
1332 return 0;
1333 }
1334
1335 1178 next_token:
1336 1650 continue;
1337 }
1338
1339 310 return 0;
1340 }
1341
1342 10 static int append_namespace_entries(ap_namespace *dst, const ap_namespace *src,
1343 ap_error *err) {
1344 ap_ns_entry *next;
1345 int old_count;
1346 10 int added_count = 0;
1347 int i;
1348
1349
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 if (!src || src->count == 0) {
1350 return 0;
1351 }
1352
1353 10 old_count = dst->count;
1354 10 next = realloc(dst->entries,
1355 10 sizeof(ap_ns_entry) * (size_t)(old_count + src->count));
1356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!next) {
1357 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
1358 return -1;
1359 }
1360 10 dst->entries = next;
1361 10 memset(dst->entries + old_count, 0, sizeof(ap_ns_entry) * (size_t)src->count);
1362
1363
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 10 times.
52 for (i = 0; i < src->count; i++) {
1364 ap_ns_entry *entry;
1365 42 const ap_ns_entry *src_entry = &src->entries[i];
1366 int j;
1367
1368
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 32 times.
42 if (strcmp(src_entry->dest, "help") == 0) {
1369 10 continue;
1370 }
1371
1372 32 entry = &dst->entries[old_count + added_count];
1373
1374
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 28 times.
134 for (j = 0; j < old_count + added_count; j++) {
1375
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 102 times.
106 if (strcmp(dst->entries[j].dest, src_entry->dest) == 0) {
1376
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (strcmp(src_entry->dest, "subcommand_path") == 0) {
1377 4 entry = NULL;
1378 4 break;
1379 }
1380 ap_error_set(err, AP_ERR_INVALID_DEFINITION, src_entry->dest,
1381 "dest '%s' already exists", src_entry->dest);
1382 return -1;
1383 }
1384 }
1385
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 28 times.
32 if (!entry) {
1386 4 continue;
1387 }
1388
1389 28 entry->dest = ap_strdup(src_entry->dest);
1390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (!entry->dest) {
1391 ap_error_set(err, AP_ERR_NO_MEMORY, src_entry->dest, "out of memory");
1392 return -1;
1393 }
1394 28 entry->type = src_entry->type;
1395 28 entry->count = src_entry->count;
1396
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
28 if (src_entry->type == AP_NS_VALUE_STRING && src_entry->count > 0) {
1397 18 entry->as.strings = calloc((size_t)src_entry->count, sizeof(char *));
1398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!entry->as.strings) {
1399 ap_error_set(err, AP_ERR_NO_MEMORY, src_entry->dest, "out of memory");
1400 return -1;
1401 }
1402
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 for (j = 0; j < src_entry->count; j++) {
1403 18 entry->as.strings[j] = ap_strdup(src_entry->as.strings[j]);
1404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!entry->as.strings[j]) {
1405 ap_error_set(err, AP_ERR_NO_MEMORY, src_entry->dest, "out of memory");
1406 return -1;
1407 }
1408 }
1409
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 } else if (src_entry->type == AP_NS_VALUE_INT32 && src_entry->count > 0) {
1410 entry->as.ints = calloc((size_t)src_entry->count, sizeof(int32_t));
1411 if (!entry->as.ints) {
1412 ap_error_set(err, AP_ERR_NO_MEMORY, src_entry->dest, "out of memory");
1413 return -1;
1414 }
1415 memcpy(entry->as.ints, src_entry->as.ints,
1416 sizeof(int32_t) * (size_t)src_entry->count);
1417
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 } else if (src_entry->type == AP_NS_VALUE_INT64 && src_entry->count > 0) {
1418 entry->as.int64s = calloc((size_t)src_entry->count, sizeof(int64_t));
1419 if (!entry->as.int64s) {
1420 ap_error_set(err, AP_ERR_NO_MEMORY, src_entry->dest, "out of memory");
1421 return -1;
1422 }
1423 memcpy(entry->as.int64s, src_entry->as.int64s,
1424 sizeof(int64_t) * (size_t)src_entry->count);
1425
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 } else if (src_entry->type == AP_NS_VALUE_UINT64 && src_entry->count > 0) {
1426 entry->as.uint64s = calloc((size_t)src_entry->count, sizeof(uint64_t));
1427 if (!entry->as.uint64s) {
1428 ap_error_set(err, AP_ERR_NO_MEMORY, src_entry->dest, "out of memory");
1429 return -1;
1430 }
1431 memcpy(entry->as.uint64s, src_entry->as.uint64s,
1432 sizeof(uint64_t) * (size_t)src_entry->count);
1433
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 } else if (src_entry->type == AP_NS_VALUE_DOUBLE && src_entry->count > 0) {
1434 entry->as.doubles = calloc((size_t)src_entry->count, sizeof(double));
1435 if (!entry->as.doubles) {
1436 ap_error_set(err, AP_ERR_NO_MEMORY, src_entry->dest, "out of memory");
1437 return -1;
1438 }
1439 memcpy(entry->as.doubles, src_entry->as.doubles,
1440 sizeof(double) * (size_t)src_entry->count);
1441
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 } else if (src_entry->type == AP_NS_VALUE_BOOL) {
1442 10 entry->as.boolean = src_entry->as.boolean;
1443 }
1444 28 added_count++;
1445 }
1446
1447 10 dst->count = old_count + added_count;
1448 10 return 0;
1449 }
1450
1451 16 static int add_string_entry(ap_namespace *ns, const char *dest,
1452 const char *value, ap_error *err) {
1453 ap_ns_entry *next;
1454 ap_ns_entry *entry;
1455
1456 16 next = realloc(ns->entries, sizeof(ap_ns_entry) * (size_t)(ns->count + 1));
1457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!next) {
1458 ap_error_set(err, AP_ERR_NO_MEMORY, dest ? dest : "", "out of memory");
1459 return -1;
1460 }
1461 16 ns->entries = next;
1462 16 entry = &ns->entries[ns->count];
1463 16 memset(entry, 0, sizeof(*entry));
1464 16 entry->dest = ap_strdup(dest);
1465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!entry->dest) {
1466 ap_error_set(err, AP_ERR_NO_MEMORY, dest ? dest : "", "out of memory");
1467 return -1;
1468 }
1469 16 entry->type = AP_NS_VALUE_STRING;
1470 16 entry->count = 1;
1471 16 entry->as.strings = calloc(1, sizeof(char *));
1472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!entry->as.strings) {
1473 ap_error_set(err, AP_ERR_NO_MEMORY, dest ? dest : "", "out of memory");
1474 return -1;
1475 }
1476 16 entry->as.strings[0] = ap_strdup(value);
1477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!entry->as.strings[0]) {
1478 ap_error_set(err, AP_ERR_NO_MEMORY, dest ? dest : "", "out of memory");
1479 return -1;
1480 }
1481 16 ns->count++;
1482 16 return 0;
1483 }
1484
1485 6 static int add_subcommand_entry(ap_namespace *ns, const char *name,
1486 ap_error *err) {
1487 6 return add_string_entry(ns, "subcommand", name, err);
1488 }
1489
1490 10 static int add_subcommand_path_entry(ap_namespace *ns, const char *name,
1491 const ap_namespace *sub_ns,
1492 ap_error *err) {
1493 10 const ap_ns_entry *sub_path_entry = find_entry(sub_ns, "subcommand_path");
1494 14 const char *sub_path = sub_path_entry &&
1495
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 sub_path_entry->type == AP_NS_VALUE_STRING &&
1496
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 sub_path_entry->count > 0
1497 4 ? sub_path_entry->as.strings[0]
1498
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
14 : NULL;
1499
1500
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
10 if (sub_path && sub_path[0] != '\0') {
1501 4 size_t path_len = strlen(name) + 1 + strlen(sub_path) + 1;
1502 4 char *path = malloc(path_len);
1503 int rc;
1504
1505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!path) {
1506 ap_error_set(err, AP_ERR_NO_MEMORY, "subcommand_path", "out of memory");
1507 return -1;
1508 }
1509 4 snprintf(path, path_len, "%s %s", name, sub_path);
1510 4 rc = add_string_entry(ns, "subcommand_path", path, err);
1511 4 free(path);
1512 4 return rc;
1513 }
1514
1515 6 return add_string_entry(ns, "subcommand_path", name, err);
1516 }
1517
1518 6 static int read_fromfile_tokens(ap_strvec *out_tokens, const char *path,
1519 ap_error *err) {
1520 FILE *fp;
1521 char line[1024];
1522
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!out_tokens || !path) {
1523 return -1;
1524 }
1525 6 fp = fopen(path, "r");
1526
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (!fp) {
1527 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, path,
1528 "failed to open args file '%s'", path);
1529 2 return -1;
1530 }
1531
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
16 while (fgets(line, sizeof(line), fp) != NULL) {
1532 12 char *cursor = line;
1533
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
22 while (*cursor != '\0') {
1534 char *start;
1535
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 14 times.
36 while (*cursor != '\0' && isspace((unsigned char)*cursor)) {
1536 16 cursor++;
1537 }
1538
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 14 times.
20 if (*cursor == '\0') {
1539 6 break;
1540 }
1541
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
14 if (*cursor == '#') {
1542 4 break;
1543 }
1544 10 start = cursor;
1545
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 8 times.
52 while (*cursor != '\0' && !isspace((unsigned char)*cursor)) {
1546 42 cursor++;
1547 }
1548
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (cursor > start) {
1549 10 char *token = ap_strndup(start, (size_t)(cursor - start));
1550
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 if (!token || ap_strvec_push(out_tokens, token) != 0) {
1551 free(token);
1552 fclose(fp);
1553 ap_error_set(err, AP_ERR_NO_MEMORY, path, "out of memory");
1554 return -1;
1555 }
1556 }
1557 }
1558 }
1559 4 fclose(fp);
1560 4 return 0;
1561 }
1562
1563 328 static int expand_fromfile_argv(const ap_parser *parser, int argc, char **argv,
1564 ap_strvec *owned_tokens, char ***out_argv,
1565 int *out_argc, ap_error *err) {
1566 int i;
1567 328 const char *prefixes = NULL;
1568
3/6
✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 328 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 328 times.
328 if (!owned_tokens || !out_argv || !out_argc) {
1569 return -1;
1570 }
1571 328 *out_argv = argv;
1572 328 *out_argc = argc;
1573
3/4
✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 322 times.
328 if (!parser || !parser->fromfile_prefix_chars ||
1574
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 parser->fromfile_prefix_chars[0] == '\0') {
1575 322 return 0;
1576 }
1577 6 prefixes = parser->fromfile_prefix_chars;
1578
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 for (i = 1; i < argc; i++) {
1579 10 const char *token = argv[i];
1580
4/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 4 times.
10 if (token && token[0] != '\0' && strchr(prefixes, token[0]) != NULL &&
1581
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 token[1] != '\0') {
1582
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
6 if (read_fromfile_tokens(owned_tokens, token + 1, err) != 0) {
1583 2 return -1;
1584 }
1585 } else {
1586
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 char *copy = ap_strdup(token ? token : "");
1587
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (!copy || ap_strvec_push(owned_tokens, copy) != 0) {
1588 free(copy);
1589 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
1590 return -1;
1591 }
1592 }
1593 }
1594
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (owned_tokens->count > 0) {
1595 4 char **expanded = calloc((size_t)owned_tokens->count + 1, sizeof(char *));
1596
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!expanded) {
1597 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
1598 return -1;
1599 }
1600 4 expanded[0] = argv[0];
1601
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
18 for (i = 0; i < owned_tokens->count; i++) {
1602 14 expanded[i + 1] = owned_tokens->items[i];
1603 }
1604 4 *out_argv = expanded;
1605 4 *out_argc = owned_tokens->count + 1;
1606 }
1607 4 return 0;
1608 }
1609
1610 332 static int parse_internal(ap_parser *parser, int argc, char **argv,
1611 bool allow_unknown, ap_namespace **out_ns,
1612 char ***out_unknown_args, int *out_unknown_count,
1613 ap_error *err) {
1614 332 ap_parsed_arg *parsed = NULL;
1615 332 ap_namespace *ns = NULL;
1616 332 ap_namespace *sub_ns = NULL;
1617 ap_strvec positionals;
1618 ap_strvec unknown_args;
1619 332 char **sub_unknown_args = NULL;
1620 332 int sub_unknown_count = 0;
1621 332 int subcommand_arg_index = -1;
1622 332 int subcommand_index = -1;
1623 ap_strvec expanded_tokens;
1624 332 char **effective_argv = argv;
1625 332 int effective_argc = argc;
1626 332 char **expanded_argv = NULL;
1627 int rc;
1628
1629
4/4
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 328 times.
332 if (!parser || !out_ns) {
1630 4 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "",
1631 "parser and out_ns are required");
1632 4 return -1;
1633 }
1634
1635 328 memset(&positionals, 0, sizeof(positionals));
1636 328 memset(&unknown_args, 0, sizeof(unknown_args));
1637 328 memset(&expanded_tokens, 0, sizeof(expanded_tokens));
1638 328 *out_ns = NULL;
1639
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 262 times.
328 if (out_unknown_args) {
1640 66 *out_unknown_args = NULL;
1641 }
1642
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 262 times.
328 if (out_unknown_count) {
1643 66 *out_unknown_count = 0;
1644 }
1645
1646 328 rc = expand_fromfile_argv(parser, argc, argv, &expanded_tokens,
1647 &effective_argv, &effective_argc, err);
1648
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 326 times.
328 if (rc != 0) {
1649 2 goto done;
1650 }
1651
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 322 times.
326 expanded_argv = effective_argv != argv ? effective_argv : NULL;
1652
1653 326 rc = find_subcommand_arg_index(parser, effective_argc, effective_argv,
1654 &subcommand_arg_index, &subcommand_index);
1655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 326 times.
326 if (rc != 0) {
1656 goto done;
1657 }
1658
1659
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 260 times.
652 rc = ap_parser_parse(
1660
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 310 times.
326 parser, subcommand_arg_index >= 0 ? subcommand_arg_index : effective_argc,
1661 effective_argv, allow_unknown, &parsed, &positionals,
1662 allow_unknown ? &unknown_args : NULL, err);
1663
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 268 times.
326 if (rc != 0) {
1664 58 goto done;
1665 }
1666
1667 268 rc = ap_validate_args(parser, parsed, err);
1668
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 248 times.
268 if (rc != 0) {
1669 20 goto done;
1670 }
1671
1672 248 rc = ap_build_namespace(parser, parsed, &ns, err);
1673
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 204 times.
248 if (rc != 0) {
1674 44 goto done;
1675 }
1676
1677
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 188 times.
204 if (subcommand_arg_index >= 0) {
1678 16 ap_parser *subparser = parser->subcommands[subcommand_index].parser;
1679
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 12 times.
16 rc = parse_internal(subparser, effective_argc - subcommand_arg_index,
1680 16 effective_argv + subcommand_arg_index, allow_unknown,
1681 &sub_ns, allow_unknown ? &sub_unknown_args : NULL,
1682 allow_unknown ? &sub_unknown_count : NULL, err);
1683
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 if (rc != 0) {
1684 6 goto done;
1685 }
1686
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
10 if (!find_entry(sub_ns, "subcommand")) {
1687 6 rc = add_subcommand_entry(ns, parser->subcommands[subcommand_index].name,
1688 err);
1689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (rc != 0) {
1690 goto done;
1691 }
1692 }
1693 10 rc = add_subcommand_path_entry(
1694 10 ns, parser->subcommands[subcommand_index].name, sub_ns, err);
1695
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (rc != 0) {
1696 goto done;
1697 }
1698 10 rc = append_namespace_entries(ns, sub_ns, err);
1699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (rc != 0) {
1700 goto done;
1701 }
1702
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
188 } else if (parser->subcommands_count > 0 && !allow_unknown) {
1703 6 bool help_requested = false;
1704 int i;
1705
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (i = 0; i < parser->defs_count; i++) {
1706
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
6 if (strcmp(parser->defs[i].dest, "help") == 0 && parsed[i].seen) {
1707 4 help_requested = true;
1708 4 break;
1709 }
1710 }
1711
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (!help_requested) {
1712 2 ap_error_set(err, AP_ERR_MISSING_REQUIRED, "subcommand",
1713 "a subcommand is required");
1714 2 rc = -1;
1715 2 goto done;
1716 }
1717 }
1718
1719 196 *out_ns = ns;
1720 196 ns = NULL;
1721
4/6
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 60 times.
196 if (allow_unknown && out_unknown_args && out_unknown_count) {
1722 int i;
1723
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 60 times.
72 for (i = 0; i < sub_unknown_count; i++) {
1724 12 char *copy = ap_strdup(sub_unknown_args[i]);
1725
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 if (!copy || ap_strvec_push(&unknown_args, copy) != 0) {
1726 free(copy);
1727 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
1728 rc = -1;
1729 goto done;
1730 }
1731 }
1732 60 *out_unknown_args = unknown_args.items;
1733 60 *out_unknown_count = unknown_args.count;
1734 60 unknown_args.items = NULL;
1735 60 unknown_args.count = 0;
1736 60 unknown_args.cap = 0;
1737 }
1738
1739 136 done:
1740 328 free_parsed_args(parser, parsed);
1741 328 ap_strvec_free(&positionals);
1742 328 ap_strvec_free(&unknown_args);
1743 328 ap_free_tokens(sub_unknown_args, sub_unknown_count);
1744 328 free(expanded_argv);
1745 328 ap_strvec_free(&expanded_tokens);
1746 328 ap_namespace_free(sub_ns);
1747 328 ap_namespace_free(ns);
1748 328 return rc;
1749 }
1750
1751 254 int ap_parse_args(ap_parser *parser, int argc, char **argv,
1752 ap_namespace **out_ns, ap_error *err) {
1753 254 return parse_internal(parser, argc, argv, false, out_ns, NULL, NULL, err);
1754 }
1755
1756 64 int ap_parse_known_args(ap_parser *parser, int argc, char **argv,
1757 ap_namespace **out_ns, char ***out_unknown_args,
1758 int *out_unknown_count, ap_error *err) {
1759
5/8
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 62 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 62 times.
64 if (!parser || !out_ns || !out_unknown_args || !out_unknown_count) {
1760 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "",
1761 "parser, outputs and unknown outputs are required");
1762 2 return -1;
1763 }
1764 62 return parse_internal(parser, argc, argv, true, out_ns, out_unknown_args,
1765 out_unknown_count, err);
1766 }
1767
1768 2 int ap_parse_intermixed_args(ap_parser *parser, int argc, char **argv,
1769 ap_namespace **out_ns, ap_error *err) {
1770 2 return ap_parse_args(parser, argc, argv, out_ns, err);
1771 }
1772
1773 2 int ap_parse_known_intermixed_args(ap_parser *parser, int argc, char **argv,
1774 ap_namespace **out_ns,
1775 char ***out_unknown_args,
1776 int *out_unknown_count, ap_error *err) {
1777 2 return ap_parse_known_args(parser, argc, argv, out_ns, out_unknown_args,
1778 out_unknown_count, err);
1779 }
1780
1781 40 char *ap_format_usage(const ap_parser *parser) {
1782 40 return ap_usage_build(parser);
1783 }
1784
1785 162 char *ap_format_help(const ap_parser *parser) { return ap_help_build(parser); }
1786
1787 910 char *ap_format_manpage(const ap_parser *parser) {
1788 910 return ap_manpage_build(parser);
1789 }
1790
1791 688 char *ap_format_bash_completion(const ap_parser *parser) {
1792 688 return ap_bash_completion_build(parser);
1793 }
1794
1795 1874 char *ap_format_fish_completion(const ap_parser *parser) {
1796 1874 return ap_fish_completion_build(parser);
1797 }
1798
1799 1178 char *ap_format_zsh_completion(const ap_parser *parser) {
1800 1178 return ap_zsh_completion_build(parser);
1801 }
1802
1803 38 int ap_try_handle_completion(const ap_parser *parser, int argc, char **argv,
1804 const char *default_shell, int *out_handled,
1805 ap_completion_result *out_result, ap_error *err) {
1806 38 int arg_index = 2;
1807 const char *shell;
1808
1809
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (out_handled) {
1810 38 *out_handled = 0;
1811 }
1812
8/10
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 34 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 32 times.
38 if (!parser || argc < 0 || !out_result || (argc > 0 && !argv)) {
1813 6 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "",
1814 "parser, argv, and completion result are required");
1815 6 return -1;
1816 }
1817
1818 32 ap_completion_result_init(out_result);
1819
4/6
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
32 if (!parser->completion_enabled || argc <= 1 || !argv[1] ||
1820
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 22 times.
28 strcmp(argv[1], ap_parser_completion_entrypoint(parser)) != 0) {
1821 10 return 0;
1822 }
1823
1824
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
22 shell = default_shell ? default_shell : "bash";
1825
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
22 if (arg_index < argc && argv[arg_index] &&
1826
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 2 times.
20 strcmp(argv[arg_index], "--shell") == 0 && arg_index + 1 < argc &&
1827
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 argv[arg_index + 1]) {
1828 14 shell = argv[arg_index + 1];
1829 14 arg_index += 2;
1830 }
1831
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
22 if (arg_index < argc && argv[arg_index] &&
1832
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
18 strcmp(argv[arg_index], "--") == 0) {
1833 14 arg_index++;
1834 }
1835
1836
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (out_handled) {
1837 22 *out_handled = 1;
1838 }
1839 22 return ap_complete(parser, argc - arg_index, argv + arg_index, shell,
1840 out_result, err);
1841 }
1842
1843 30 static bool completion_action_takes_no_value(ap_action action) {
1844
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
30 return action == AP_ACTION_STORE_TRUE || action == AP_ACTION_STORE_FALSE ||
1845
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
60 action == AP_ACTION_COUNT || action == AP_ACTION_STORE_CONST;
1846 }
1847
1848 38 static const ap_arg_def *find_def_by_flag(const ap_parser *parser,
1849 const char *flag) {
1850 int i;
1851 int j;
1852
1853
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38 times.
38 if (!parser || !flag) {
1854 return NULL;
1855 }
1856
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 8 times.
84 for (i = 0; i < parser->defs_count; i++) {
1857 76 const ap_arg_def *def = &parser->defs[i];
1858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
76 if (!def->is_optional) {
1859 continue;
1860 }
1861
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 46 times.
160 for (j = 0; j < def->flags_count; j++) {
1862
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 84 times.
114 if (strcmp(def->flags[j], flag) == 0) {
1863 30 return def;
1864 }
1865 }
1866 }
1867 8 return NULL;
1868 }
1869
1870 32 static const ap_subcommand_def *find_subcommand_def(const ap_parser *parser,
1871 const char *name) {
1872 int i;
1873
1874
2/4
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
32 if (!parser || !name) {
1875 return NULL;
1876 }
1877
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 12 times.
32 for (i = 0; i < parser->subcommands_count; i++) {
1878
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 if (strcmp(parser->subcommands[i].name, name) == 0) {
1879 20 return &parser->subcommands[i];
1880 }
1881 }
1882 12 return NULL;
1883 }
1884
1885 20 static int append_completion_path(char *buf, size_t buf_size,
1886 const char *current_path,
1887 const char *segment) {
1888
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (!buf || buf_size == 0) {
1889 return -1;
1890 }
1891
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
20 if (!segment || segment[0] == '\0') {
1892 return snprintf(buf, buf_size, "%s", current_path ? current_path : "");
1893 }
1894
3/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 14 times.
20 if (!current_path || current_path[0] == '\0') {
1895 6 return snprintf(buf, buf_size, "%s", segment);
1896 }
1897 14 return snprintf(buf, buf_size, "%s %s", current_path, segment);
1898 }
1899
1900 24 static int add_static_completion_items(const ap_arg_def *def,
1901 ap_completion_result *result,
1902 ap_error *err) {
1903 int i;
1904 ap_completion_kind kind;
1905
1906
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 if (!def || !result) {
1907 return 0;
1908 }
1909 24 kind = def->opts.completion_kind;
1910
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
24 if (kind == AP_COMPLETION_KIND_NONE && def->opts.choices.items &&
1911
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 def->opts.choices.count > 0) {
1912 22 kind = AP_COMPLETION_KIND_CHOICES;
1913 }
1914
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24 if (kind != AP_COMPLETION_KIND_CHOICES) {
1915 2 return 0;
1916 }
1917
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 20 times.
62 for (i = 0; i < def->opts.choices.count; i++) {
1918
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 40 times.
42 if (ap_completion_result_add(result, def->opts.choices.items[i], NULL,
1919 err) != 0) {
1920 2 return -1;
1921 }
1922 }
1923 20 return 0;
1924 }
1925
1926 56 int ap_complete(const ap_parser *parser, int argc, char **argv,
1927 const char *shell, ap_completion_result *out_result,
1928 ap_error *err) {
1929 56 const ap_parser *active_parser = parser;
1930 56 const ap_arg_def *active_def = NULL;
1931 56 const char *active_option = NULL;
1932 56 const char *current_token = "";
1933 56 int positional_count = 0;
1934 int scan_count;
1935 int i;
1936 56 bool positional_only = false;
1937 char subcommand_path[256];
1938 ap_completion_request request;
1939
1940
7/10
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 48 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 46 times.
56 if (!parser || argc < 0 || !out_result || (argc > 0 && !argv)) {
1941 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, "",
1942 "parser, argv, and completion result are required");
1943 2 return -1;
1944 }
1945
1946 54 ap_completion_result_init(out_result);
1947 54 subcommand_path[0] = '\0';
1948 54 scan_count = argc > 0 ? argc - 1 : 0;
1949
4/6
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✗ Branch 5 not taken.
54 if (argc > 0 && argv && argv[argc - 1]) {
1950 46 current_token = argv[argc - 1];
1951 }
1952
1953
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 54 times.
126 for (i = 0; i < scan_count; i++) {
1954 72 const char *token = argv[i];
1955 const ap_subcommand_def *sub;
1956 const ap_arg_def *def;
1957
1958
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 70 times.
72 if (!token) {
1959 2 continue;
1960 }
1961
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 68 times.
70 if (active_def &&
1962
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 !completion_action_takes_no_value(active_def->opts.action)) {
1963 2 active_def = NULL;
1964 2 active_option = NULL;
1965 2 continue;
1966 }
1967
3/4
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 66 times.
68 if (!positional_only && strcmp(token, "--") == 0) {
1968 2 positional_only = true;
1969 2 continue;
1970 }
1971
3/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 32 times.
66 if (!positional_only && token[0] == '-') {
1972 34 const char *eq = strchr(token, '=');
1973 char option_name[128];
1974
1975
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 28 times.
34 if (eq) {
1976 6 size_t name_len = (size_t)(eq - token);
1977
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (name_len >= sizeof(option_name)) {
1978 4 name_len = sizeof(option_name) - 1;
1979 }
1980 6 memcpy(option_name, token, name_len);
1981 6 option_name[name_len] = '\0';
1982 6 def = find_def_by_flag(active_parser, option_name);
1983 } else {
1984 28 def = find_def_by_flag(active_parser, token);
1985 }
1986
5/6
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 26 times.
✓ Branch 6 taken 2 times.
34 if (def && !completion_action_takes_no_value(def->opts.action) && !eq) {
1987 26 active_def = def;
1988 26 active_option = token;
1989 }
1990 34 continue;
1991 }
1992
1993
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if (!positional_only) {
1994 32 sub = find_subcommand_def(active_parser, token);
1995
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 12 times.
32 if (sub) {
1996 char next_path[256];
1997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (append_completion_path(next_path, sizeof(next_path),
1998 20 subcommand_path, sub->name) < 0) {
1999 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
2000 ap_completion_result_free(out_result);
2001 return -1;
2002 }
2003 20 memcpy(subcommand_path, next_path, strlen(next_path) + 1);
2004 20 active_parser = sub->parser;
2005 20 positional_count = 0;
2006 20 continue;
2007 }
2008 }
2009
2010 12 positional_count++;
2011 }
2012
2013
4/6
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
54 if (scan_count > 0 && argv && argv[scan_count - 1]) {
2014 42 const char *token = argv[scan_count - 1];
2015 42 const char *eq = strchr(token, '=');
2016
2017
5/6
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
42 if (!positional_only && eq && token[0] == '-') {
2018 char option_name[128];
2019 4 size_t name_len = (size_t)(eq - token);
2020
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (name_len >= sizeof(option_name)) {
2021 2 name_len = sizeof(option_name) - 1;
2022 }
2023 4 memcpy(option_name, token, name_len);
2024 4 option_name[name_len] = '\0';
2025 4 active_def = find_def_by_flag(active_parser, option_name);
2026
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 active_option = active_def ? option_name : NULL;
2027 4 current_token = eq + 1;
2028 }
2029 }
2030
2031
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 2 times.
54 if (!active_def &&
2032
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 4 times.
26 (positional_only || !ap_token_has_prefix(parser, current_token))) {
2033 24 active_def = ap_next_positional_def(active_parser, positional_count);
2034 }
2035
2036
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 36 times.
54 if (!active_def) {
2037 18 return 0;
2038 }
2039
2040 36 memset(&request, 0, sizeof(request));
2041 36 request.parser = active_parser;
2042 36 request.shell = shell;
2043
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 request.current_token = current_token ? current_token : "";
2044 36 request.active_option = active_option;
2045 36 request.subcommand_path = subcommand_path;
2046 36 request.dest = active_def->dest;
2047 36 request.argc = argc;
2048 36 request.argv = argv;
2049
2050
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
36 if (active_def->opts.completion_callback) {
2051
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
12 if (active_def->opts.completion_callback(
2052 12 &request, out_result, active_def->opts.completion_user_data, err) !=
2053 0) {
2054 2 ap_completion_result_free(out_result);
2055 2 return -1;
2056 }
2057 }
2058
2059
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 22 times.
58 if (out_result->count == 0 &&
2060 24 add_static_completion_items(active_def, out_result, err) != 0) {
2061 2 ap_completion_result_free(out_result);
2062 2 return -1;
2063 }
2064 32 return 0;
2065 }
2066
2067 10 int ap_parser_get_info(const ap_parser *parser, ap_parser_info *out_info) {
2068
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6 times.
10 if (!parser || !out_info) {
2069 4 return -1;
2070 }
2071
2072 6 out_info->prog = parser->prog;
2073 6 out_info->description = parser->description;
2074 6 out_info->argument_count = parser->defs_count;
2075 6 out_info->subcommand_count = parser->subcommands_count;
2076 6 return 0;
2077 }
2078
2079 20 int ap_parser_get_argument(const ap_parser *parser, int index,
2080 ap_arg_info *out_info) {
2081 const ap_arg_def *def;
2082
2083
8/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 12 times.
20 if (!parser || !out_info || index < 0 || index >= parser->defs_count) {
2084 8 return -1;
2085 }
2086
2087 12 def = &parser->defs[index];
2088 12 out_info->kind =
2089 12 def->is_optional ? AP_ARG_KIND_OPTIONAL : AP_ARG_KIND_POSITIONAL;
2090 12 out_info->flag_count = def->flags_count;
2091 12 out_info->flags = (const char *const *)def->flags;
2092 12 out_info->dest = def->dest;
2093 12 out_info->help = def->opts.help;
2094 12 out_info->metavar = def->opts.metavar;
2095 12 out_info->choices = def->opts.choices;
2096 12 out_info->completion_kind = def->opts.completion_kind;
2097 12 out_info->completion_hint = def->opts.completion_hint;
2098 12 out_info->has_completion_callback = def->opts.completion_callback != NULL;
2099 12 out_info->has_action_callback = def->opts.action_callback != NULL;
2100 12 out_info->required = def->opts.required;
2101 12 out_info->nargs = def->opts.nargs;
2102 12 out_info->nargs_count = def->opts.nargs_count;
2103 12 out_info->type = def->opts.type;
2104 12 out_info->action = def->opts.action;
2105 12 return 0;
2106 }
2107
2108 12 int ap_parser_get_subcommand(const ap_parser *parser, int index,
2109 ap_subcommand_info *out_info) {
2110 const ap_subcommand_def *def;
2111
2112
8/8
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 4 times.
12 if (!parser || !out_info || index < 0 || index >= parser->subcommands_count) {
2113 8 return -1;
2114 }
2115
2116 4 def = &parser->subcommands[index];
2117 4 out_info->name = def->name;
2118 4 out_info->description = def->help;
2119 4 out_info->parser = def->parser;
2120 4 return 0;
2121 }
2122
2123 16 static int ap_arg_flag_count_by_kind(const ap_arg_info *info, bool long_flag) {
2124 int i;
2125 16 int count = 0;
2126
2127
4/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
16 if (!info || !info->flags || info->flag_count < 1) {
2128 4 return 0;
2129 }
2130
2131
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 12 times.
32 for (i = 0; i < info->flag_count; i++) {
2132
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 12 times.
30 if (long_flag ? ap_is_long_flag(info->flags[i])
2133 10 : ap_is_short_flag(info->flags[i])) {
2134 8 count++;
2135 }
2136 }
2137 12 return count;
2138 }
2139
2140 24 static const char *ap_arg_flag_at_by_kind(const ap_arg_info *info, int index,
2141 bool long_flag) {
2142 int i;
2143 24 int current = 0;
2144
2145
5/6
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
24 if (!info || !info->flags || index < 0) {
2146 8 return NULL;
2147 }
2148
2149
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 for (i = 0; i < info->flag_count; i++) {
2150 14 bool matches = long_flag ? ap_is_long_flag(info->flags[i])
2151
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 10 times.
38 : ap_is_short_flag(info->flags[i]);
2152
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (!matches) {
2153 12 continue;
2154 }
2155
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 if (current == index) {
2156 8 return info->flags[i];
2157 }
2158 4 current++;
2159 }
2160 8 return NULL;
2161 }
2162
2163 8 int ap_arg_short_flag_count(const ap_arg_info *info) {
2164 8 return ap_arg_flag_count_by_kind(info, false);
2165 }
2166
2167 12 const char *ap_arg_short_flag_at(const ap_arg_info *info, int index) {
2168 12 return ap_arg_flag_at_by_kind(info, index, false);
2169 }
2170
2171 8 int ap_arg_long_flag_count(const ap_arg_info *info) {
2172 8 return ap_arg_flag_count_by_kind(info, true);
2173 }
2174
2175 12 const char *ap_arg_long_flag_at(const ap_arg_info *info, int index) {
2176 12 return ap_arg_flag_at_by_kind(info, index, true);
2177 }
2178
2179 14 char *ap_format_error(const ap_parser *parser, const ap_error *err) {
2180 14 char *usage = NULL;
2181 14 char *out = NULL;
2182 int needed;
2183 14 const char *msg = "unknown error";
2184
2185
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (!parser) {
2186 2 return NULL;
2187 }
2188
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
12 if (err && err->message[0] != '\0') {
2189 8 msg = err->message;
2190 }
2191
2192 12 usage = ap_usage_build(parser);
2193
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (!usage) {
2194 4 return NULL;
2195 }
2196
2197 8 needed = snprintf(NULL, 0, "error: %s\n%s", msg, usage);
2198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (needed < 0) {
2199 free(usage);
2200 return NULL;
2201 }
2202 8 out = malloc((size_t)needed + 1);
2203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!out) {
2204 free(usage);
2205 return NULL;
2206 }
2207 8 snprintf(out, (size_t)needed + 1, "error: %s\n%s", msg, usage);
2208 8 free(usage);
2209 8 return out;
2210 }
2211
2212 634 void ap_parser_free(ap_parser *parser) {
2213 int i;
2214
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 632 times.
634 if (!parser) {
2215 2 return;
2216 }
2217
2/2
✓ Branch 0 taken 1576 times.
✓ Branch 1 taken 632 times.
2208 for (i = 0; i < parser->defs_count; i++) {
2218 1576 arg_def_free(&parser->defs[i]);
2219 }
2220 632 free(parser->defs);
2221
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 632 times.
642 for (i = 0; i < parser->mutex_groups_count; i++) {
2222 10 free(parser->mutex_groups[i].arg_indexes);
2223 }
2224 632 free(parser->mutex_groups);
2225
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 632 times.
642 for (i = 0; i < parser->arg_groups_count; i++) {
2226 10 free(parser->arg_groups[i].title);
2227 10 free(parser->arg_groups[i].description);
2228 10 free(parser->arg_groups[i].arg_indexes);
2229 }
2230 632 free(parser->arg_groups);
2231
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 632 times.
758 for (i = 0; i < parser->subcommands_count; i++) {
2232 126 free(parser->subcommands[i].name);
2233 126 free(parser->subcommands[i].help);
2234 126 ap_parser_free(parser->subcommands[i].parser);
2235 }
2236 632 free(parser->subcommands);
2237 632 free(parser->prog);
2238 632 free(parser->description);
2239 632 free(parser->command_name);
2240 632 free(parser->completion_entrypoint);
2241 632 free(parser->prefix_chars);
2242 632 free(parser->fromfile_prefix_chars);
2243 632 free(parser);
2244 }
2245
2246 896 void ap_namespace_free(ap_namespace *ns) {
2247 int i;
2248 int j;
2249
2/2
✓ Branch 0 taken 640 times.
✓ Branch 1 taken 256 times.
896 if (!ns) {
2250 640 return;
2251 }
2252
2/2
✓ Branch 0 taken 836 times.
✓ Branch 1 taken 256 times.
1092 for (i = 0; i < ns->count; i++) {
2253 836 free(ns->entries[i].dest);
2254
2/2
✓ Branch 0 taken 326 times.
✓ Branch 1 taken 510 times.
836 if (ns->entries[i].type == AP_NS_VALUE_STRING) {
2255
2/2
✓ Branch 0 taken 558 times.
✓ Branch 1 taken 326 times.
884 for (j = 0; j < ns->entries[i].count; j++) {
2256 558 free(ns->entries[i].as.strings[j]);
2257 }
2258 326 free(ns->entries[i].as.strings);
2259
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 402 times.
510 } else if (ns->entries[i].type == AP_NS_VALUE_INT32) {
2260 108 free(ns->entries[i].as.ints);
2261
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 374 times.
402 } else if (ns->entries[i].type == AP_NS_VALUE_INT64) {
2262 28 free(ns->entries[i].as.int64s);
2263
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 330 times.
374 } else if (ns->entries[i].type == AP_NS_VALUE_UINT64) {
2264 44 free(ns->entries[i].as.uint64s);
2265
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 312 times.
330 } else if (ns->entries[i].type == AP_NS_VALUE_DOUBLE) {
2266 18 free(ns->entries[i].as.doubles);
2267 }
2268 }
2269 256 free(ns->entries);
2270 256 free(ns);
2271 }
2272
2273 386 void ap_free_tokens(char **tokens, int count) {
2274 int i;
2275
2/2
✓ Branch 0 taken 326 times.
✓ Branch 1 taken 60 times.
386 if (!tokens) {
2276 326 return;
2277 }
2278
2/2
✓ Branch 0 taken 744 times.
✓ Branch 1 taken 60 times.
804 for (i = 0; i < count; i++) {
2279 744 free(tokens[i]);
2280 }
2281 60 free(tokens);
2282 }
2283
2284 58 bool ap_ns_get_bool(const ap_namespace *ns, const char *dest, bool *out_value) {
2285 58 const ap_ns_entry *entry = find_entry(ns, dest);
2286
5/6
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 54 times.
58 if (!entry || entry->type != AP_NS_VALUE_BOOL || !out_value) {
2287 4 return false;
2288 }
2289 54 *out_value = entry->as.boolean;
2290 54 return true;
2291 }
2292
2293 190 bool ap_ns_get_string(const ap_namespace *ns, const char *dest,
2294 const char **out_value) {
2295 190 const ap_ns_entry *entry = find_entry(ns, dest);
2296
6/8
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 180 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 180 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 180 times.
190 if (!entry || entry->type != AP_NS_VALUE_STRING || entry->count < 1 ||
2297 !out_value) {
2298 10 return false;
2299 }
2300 180 *out_value = entry->as.strings[0];
2301 180 return true;
2302 }
2303
2304 48 bool ap_ns_get_int32(const ap_namespace *ns, const char *dest,
2305 int32_t *out_value) {
2306 48 const ap_ns_entry *entry = find_entry(ns, dest);
2307
7/8
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 42 times.
48 if (!entry || entry->type != AP_NS_VALUE_INT32 || entry->count < 1 ||
2308 !out_value) {
2309 6 return false;
2310 }
2311 42 *out_value = entry->as.ints[0];
2312 42 return true;
2313 }
2314
2315 10 bool ap_ns_get_int64(const ap_namespace *ns, const char *dest,
2316 int64_t *out_value) {
2317 10 const ap_ns_entry *entry = find_entry(ns, dest);
2318
5/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
10 if (!entry || entry->type != AP_NS_VALUE_INT64 || entry->count < 1 ||
2319 !out_value) {
2320 2 return false;
2321 }
2322 8 *out_value = entry->as.int64s[0];
2323 8 return true;
2324 }
2325
2326 36 bool ap_ns_get_uint64(const ap_namespace *ns, const char *dest,
2327 uint64_t *out_value) {
2328 36 const ap_ns_entry *entry = find_entry(ns, dest);
2329
6/8
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
36 if (!entry || entry->type != AP_NS_VALUE_UINT64 || entry->count < 1 ||
2330 !out_value) {
2331 18 return false;
2332 }
2333 18 *out_value = entry->as.uint64s[0];
2334 18 return true;
2335 }
2336
2337 6 bool ap_ns_get_double(const ap_namespace *ns, const char *dest,
2338 double *out_value) {
2339 6 const ap_ns_entry *entry = find_entry(ns, dest);
2340
5/8
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
6 if (!entry || entry->type != AP_NS_VALUE_DOUBLE || entry->count < 1 ||
2341 !out_value) {
2342 2 return false;
2343 }
2344 4 *out_value = entry->as.doubles[0];
2345 4 return true;
2346 }
2347
2348 62 int ap_ns_get_count(const ap_namespace *ns, const char *dest) {
2349 62 const ap_ns_entry *entry = find_entry(ns, dest);
2350
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 60 times.
62 if (!entry) {
2351 2 return -1;
2352 }
2353
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 58 times.
60 if (entry->type == AP_NS_VALUE_BOOL) {
2354 2 return 1;
2355 }
2356 58 return entry->count;
2357 }
2358
2359 330 const char *ap_ns_get_string_at(const ap_namespace *ns, const char *dest,
2360 int index) {
2361 330 const ap_ns_entry *entry = find_entry(ns, dest);
2362
4/6
✓ Branch 0 taken 328 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 328 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 328 times.
✗ Branch 5 not taken.
330 if (!entry || entry->type != AP_NS_VALUE_STRING || index < 0 ||
2363
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 326 times.
328 index >= entry->count) {
2364 4 return NULL;
2365 }
2366 326 return entry->as.strings[index];
2367 }
2368
2369 10 bool ap_ns_get_int32_at(const ap_namespace *ns, const char *dest, int index,
2370 int32_t *out_value) {
2371 10 const ap_ns_entry *entry = find_entry(ns, dest);
2372
4/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 2 times.
10 if (!entry || entry->type != AP_NS_VALUE_INT32 || index < 0 ||
2373
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
8 index >= entry->count || !out_value) {
2374 6 return false;
2375 }
2376 4 *out_value = entry->as.ints[index];
2377 4 return true;
2378 }
2379
2380 10 bool ap_ns_get_int64_at(const ap_namespace *ns, const char *dest, int index,
2381 int64_t *out_value) {
2382 10 const ap_ns_entry *entry = find_entry(ns, dest);
2383
4/6
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
10 if (!entry || entry->type != AP_NS_VALUE_INT64 || index < 0 ||
2384
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 index >= entry->count || !out_value) {
2385 2 return false;
2386 }
2387 8 *out_value = entry->as.int64s[index];
2388 8 return true;
2389 }
2390
2391 18 bool ap_ns_get_uint64_at(const ap_namespace *ns, const char *dest, int index,
2392 uint64_t *out_value) {
2393 18 const ap_ns_entry *entry = find_entry(ns, dest);
2394
4/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
18 if (!entry || entry->type != AP_NS_VALUE_UINT64 || index < 0 ||
2395
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
16 index >= entry->count || !out_value) {
2396 6 return false;
2397 }
2398 12 *out_value = entry->as.uint64s[index];
2399 12 return true;
2400 }
2401
2402 6 bool ap_ns_get_double_at(const ap_namespace *ns, const char *dest, int index,
2403 double *out_value) {
2404 6 const ap_ns_entry *entry = find_entry(ns, dest);
2405
4/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
6 if (!entry || entry->type != AP_NS_VALUE_DOUBLE || index < 0 ||
2406
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 index >= entry->count || !out_value) {
2407 2 return false;
2408 }
2409 4 *out_value = entry->as.doubles[index];
2410 4 return true;
2411 }
2412