GCC Code Coverage Report


Directory: lib/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 84.7% 361 / 0 / 426
Functions: 100.0% 14 / 0 / 14
Branches: 77.7% 269 / 0 / 346

core_parser.c
Line Branch Exec Source
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "ap_internal.h"
5
6 576 static bool action_takes_no_value(ap_action action) {
7
3/4
✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 448 times.
✓ Branch 3 taken 86 times.
534 return action == AP_ACTION_STORE_TRUE || action == AP_ACTION_STORE_FALSE ||
8
4/4
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 444 times.
1110 action == AP_ACTION_COUNT || action == AP_ACTION_STORE_CONST;
9 }
10
11 178 static bool action_allows_multiple_occurrences(ap_action action) {
12
5/6
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 74 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
178 return action == AP_ACTION_APPEND || action == AP_ACTION_COUNT ||
13 action == AP_ACTION_STORE_CONST;
14 }
15
16 static int push_value(ap_parsed_arg *parsed, int def_index, const char *token,
17 ap_error *err);
18 static int push_token(ap_parsed_arg *parsed, int def_index, const char *token,
19 ap_error *err);
20 static void free_parsed_storage(const ap_parser *parser, ap_parsed_arg *parsed);
21
22 1684 static int find_flag_index(const ap_parser *parser, const char *token) {
23 int i;
24 int j;
25 1684 int abbrev_match = -1;
26
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1678 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
1684 bool consider_abbrev = parser && parser->allow_abbrev && token &&
27
3/6
✓ Branch 0 taken 1684 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
3374 token[0] != '\0' && token[1] != '\0' &&
28
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 token[0] == token[1];
29
2/2
✓ Branch 0 taken 5732 times.
✓ Branch 1 taken 1174 times.
6906 for (i = 0; i < parser->defs_count; i++) {
30 5732 const ap_arg_def *def = &parser->defs[i];
31
2/2
✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 4664 times.
5732 if (!def->is_optional) {
32 1068 continue;
33 }
34
2/2
✓ Branch 0 taken 8268 times.
✓ Branch 1 taken 4154 times.
12422 for (j = 0; j < def->flags_count; j++) {
35
2/2
✓ Branch 0 taken 508 times.
✓ Branch 1 taken 7760 times.
8268 if (strcmp(def->flags[j], token) == 0) {
36 508 return i;
37 }
38
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7746 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
7760 if (consider_abbrev && def->flags[j][0] == token[0] &&
39
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 def->flags[j][1] == token[0] &&
40
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 strncmp(def->flags[j], token, strlen(token)) == 0) {
41
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
6 if (abbrev_match >= 0 && abbrev_match != i) {
42 2 return -2;
43 }
44 4 abbrev_match = i;
45 }
46 }
47 }
48 1174 return abbrev_match >= 0 ? abbrev_match : -1;
49 }
50
51 20 static int find_flag_index_n(const ap_parser *parser, const char *token,
52 size_t token_len) {
53 int i;
54 int j;
55 20 int abbrev_match = -1;
56
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
20 bool consider_abbrev = parser && parser->allow_abbrev && token &&
57
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
40 token_len >= 2 && token[0] == token[1];
58
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 8 times.
68 for (i = 0; i < parser->defs_count; i++) {
59 60 const ap_arg_def *def = &parser->defs[i];
60
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 52 times.
60 if (!def->is_optional) {
61 8 continue;
62 }
63
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 40 times.
132 for (j = 0; j < def->flags_count; j++) {
64 92 const char *flag = def->flags[j];
65
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 12 times.
92 if (strlen(flag) == token_len && strncmp(flag, token, token_len) == 0) {
66 10 return i;
67 }
68
5/6
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
82 if (consider_abbrev && strlen(flag) >= token_len && flag[0] == token[0] &&
69
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
6 flag[1] == token[0] && strncmp(flag, token, token_len) == 0) {
70
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (abbrev_match >= 0 && abbrev_match != i) {
71 2 return -2;
72 }
73 2 abbrev_match = i;
74 }
75 }
76 }
77 8 return abbrev_match >= 0 ? abbrev_match : -1;
78 }
79
80 924 static int parse_short_cluster(const ap_parser *parser, const char *token,
81 bool allow_unknown, ap_parsed_arg *parsed,
82 ap_error *err) {
83 size_t i;
84 char short_flag[3];
85 char prefix;
86
87
4/6
✓ Branch 0 taken 924 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 924 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 152 times.
✓ Branch 6 taken 772 times.
924 if (!token || !ap_token_has_prefix(parser, token) || token[2] == '\0') {
88 152 return 1;
89 }
90 772 prefix = token[0];
91
2/2
✓ Branch 0 taken 754 times.
✓ Branch 1 taken 18 times.
772 if (token[1] == prefix) {
92 754 return 1;
93 }
94
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (strchr(token, '=') != NULL) {
95 2 return 1;
96 }
97
98 16 short_flag[0] = prefix;
99 16 short_flag[2] = '\0';
100
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 4 times.
34 for (i = 1; token[i] != '\0'; i++) {
101 int def_index;
102 30 short_flag[1] = token[i];
103 30 def_index = find_flag_index(parser, short_flag);
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (def_index == -2) {
105 ap_error_set(err, AP_ERR_DUPLICATE_OPTION, short_flag,
106 "ambiguous option '%s'", short_flag);
107 return -1;
108 }
109
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 26 times.
30 if (def_index < 0) {
110
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (!allow_unknown) {
111 2 ap_error_set(err, AP_ERR_UNKNOWN_OPTION, short_flag,
112 "unknown option '%s'", short_flag);
113 }
114
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 return allow_unknown ? 1 : -1;
115 }
116
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14 times.
26 if (parser->defs[def_index].opts.action != AP_ACTION_STORE_TRUE &&
117
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 parser->defs[def_index].opts.action != AP_ACTION_STORE_FALSE &&
118
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 parser->defs[def_index].opts.action != AP_ACTION_COUNT) {
119
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (allow_unknown) {
120 2 return 1;
121 }
122 4 ap_error_set(err, AP_ERR_INVALID_NARGS, short_flag,
123 "option '%s' cannot be used in a short option cluster",
124 short_flag);
125 4 return -1;
126 }
127
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
26 if (parsed[def_index].seen && !action_allows_multiple_occurrences(
128 6 parser->defs[def_index].opts.action)) {
129 2 ap_error_set(err, AP_ERR_DUPLICATE_OPTION, short_flag,
130 "duplicate option '%s'", short_flag);
131 2 return -1;
132 }
133 18 parsed[def_index].seen = true;
134
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
18 if (push_token(parsed, def_index, token, err) != 0) {
135 return -1;
136 }
137
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
24 if (parser->defs[def_index].opts.action == AP_ACTION_COUNT &&
138 6 push_value(parsed, def_index, "1", err) != 0) {
139 return -1;
140 }
141 }
142
143 4 return 0;
144 }
145
146 108 static int positional_min_required(const ap_arg_def *def) {
147
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
108 if (action_takes_no_value(def->opts.action)) {
148 return 0;
149 }
150
3/4
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
108 switch (def->opts.nargs) {
151 92 case AP_NARGS_ONE:
152 92 return 1;
153 4 case AP_NARGS_ONE_OR_MORE:
154 4 return 1;
155 12 case AP_NARGS_FIXED:
156 12 return def->opts.nargs_count;
157 case AP_NARGS_OPTIONAL:
158 case AP_NARGS_ZERO_OR_MORE:
159 default:
160 return 0;
161 }
162 }
163
164 214 static int remaining_min_required(const ap_parser *parser,
165 const int *positional_defs,
166 int positional_count, int from_index) {
167 214 int min_required = 0;
168 int i;
169
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 214 times.
322 for (i = from_index; i < positional_count; i++) {
170 108 min_required += positional_min_required(&parser->defs[positional_defs[i]]);
171 }
172 214 return min_required;
173 }
174
175 362 static int collect_positional_def_indexes(const ap_parser *parser,
176 int **out_defs, int *out_count) {
177 362 int *positional_defs = NULL;
178 362 int positional_count = 0;
179 int i;
180
181
3/6
✓ Branch 0 taken 362 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 362 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 362 times.
362 if (!parser || !out_defs || !out_count) {
182 return -1;
183 }
184
185
2/2
✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 362 times.
1444 for (i = 0; i < parser->defs_count; i++) {
186
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 846 times.
1082 if (!parser->defs[i].is_optional) {
187 236 positional_count++;
188 }
189 }
190
191
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 210 times.
362 if (positional_count > 0) {
192 152 positional_defs = malloc(sizeof(int) * (size_t)positional_count);
193
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 150 times.
152 if (!positional_defs) {
194 2 return -1;
195 }
196 150 positional_count = 0;
197
2/2
✓ Branch 0 taken 586 times.
✓ Branch 1 taken 150 times.
736 for (i = 0; i < parser->defs_count; i++) {
198
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 352 times.
586 if (!parser->defs[i].is_optional) {
199 234 positional_defs[positional_count++] = i;
200 }
201 }
202 }
203
204 360 *out_defs = positional_defs;
205 360 *out_count = positional_count;
206 360 return 0;
207 }
208
209 40 const ap_arg_def *ap_next_positional_def(const ap_parser *parser,
210 int consumed_positionals) {
211 40 int *positional_defs = NULL;
212 40 int positional_defs_count = 0;
213 40 int positional_cursor = 0;
214 40 int next_slot = consumed_positionals + 1;
215 40 const ap_arg_def *result = NULL;
216 int i;
217
218
4/4
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 36 times.
40 if (!parser || consumed_positionals < 0) {
219 4 return NULL;
220 }
221
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
36 if (collect_positional_def_indexes(parser, &positional_defs,
222 &positional_defs_count) != 0) {
223 return NULL;
224 }
225
226
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 14 times.
52 for (i = 0; i < positional_defs_count; i++) {
227 38 const ap_arg_def *def = &parser->defs[positional_defs[i]];
228 38 int values_left = next_slot - positional_cursor;
229 38 int min_after = remaining_min_required(parser, positional_defs,
230 positional_defs_count, i + 1);
231 38 int take = 0;
232
233
5/6
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
38 switch (def->opts.nargs) {
234 24 case AP_NARGS_ONE:
235 24 take = values_left > 0 ? 1 : 0;
236 24 break;
237 2 case AP_NARGS_OPTIONAL:
238 2 take = values_left > min_after ? 1 : 0;
239 2 break;
240 4 case AP_NARGS_ZERO_OR_MORE:
241 4 take = values_left - min_after;
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (take < 0) {
243 take = 0;
244 }
245 4 break;
246 2 case AP_NARGS_ONE_OR_MORE:
247 2 take = values_left - min_after;
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (take < 1) {
249 take = 1;
250 }
251 2 break;
252 6 case AP_NARGS_FIXED:
253 6 take = def->opts.nargs_count;
254 6 break;
255 }
256
257
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 if (positional_cursor < next_slot &&
258
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 16 times.
38 positional_cursor + take >= next_slot) {
259 22 result = def;
260 22 break;
261 }
262 16 positional_cursor += take;
263 }
264
265 36 free(positional_defs);
266 36 return result;
267 }
268
269 776 static int push_value(ap_parsed_arg *parsed, int def_index, const char *token,
270 ap_error *err) {
271 776 char *copy = ap_strdup(token);
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 776 times.
776 if (!copy) {
273 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
274 return -1;
275 }
276
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 776 times.
776 if (ap_strvec_push(&parsed[def_index].values, copy) != 0) {
277 free(copy);
278 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
279 return -1;
280 }
281 776 return 0;
282 }
283
284 838 static int push_token(ap_parsed_arg *parsed, int def_index, const char *token,
285 ap_error *err) {
286 838 char *copy = ap_strdup(token);
287
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 836 times.
838 if (!copy) {
288 2 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
289 2 return -1;
290 }
291
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 836 times.
836 if (ap_strvec_push(&parsed[def_index].tokens, copy) != 0) {
292 free(copy);
293 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
294 return -1;
295 }
296 836 return 0;
297 }
298
299 56 static void free_parsed_storage(const ap_parser *parser,
300 ap_parsed_arg *parsed) {
301 int i;
302
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
56 if (!parser || !parsed) {
303 return;
304 }
305
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 56 times.
202 for (i = 0; i < parser->defs_count; i++) {
306 146 ap_strvec_free(&parsed[i].tokens);
307 146 ap_strvec_free(&parsed[i].values);
308 }
309 }
310
311 468 static int consume_optional_values(const ap_parser *parser, int argc,
312 char **argv, int *idx, int def_index,
313 const char *inline_value,
314 ap_parsed_arg *parsed, ap_error *err) {
315 468 const ap_arg_def *def = &parser->defs[def_index];
316 468 int start = *idx;
317
318
2/2
✓ Branch 1 taken 132 times.
✓ Branch 2 taken 336 times.
468 if (action_takes_no_value(def->opts.action)) {
319
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 126 times.
132 if (inline_value) {
320 6 ap_error_set(err, AP_ERR_INVALID_NARGS, def->flags[0],
321 6 "option '%s' does not take a value", def->flags[0]);
322 6 return -1;
323 }
324
3/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
210 if (def->opts.action == AP_ACTION_COUNT &&
325 84 push_value(parsed, def_index, "1", err) != 0) {
326 return -1;
327 }
328
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
128 if (def->opts.action == AP_ACTION_STORE_CONST &&
329 2 push_value(parsed, def_index, def->opts.const_value, err) != 0) {
330 return -1;
331 }
332 126 return 0;
333 }
334
335
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 24 times.
336 if (def->opts.nargs == AP_NARGS_ONE) {
336
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 308 times.
312 if (inline_value) {
337 4 return push_value(parsed, def_index, inline_value, err);
338 }
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
308 if (start + 1 >= argc) {
340 ap_error_set(err, AP_ERR_MISSING_VALUE, def->flags[0],
341 "option '%s' requires a value", def->flags[0]);
342 return -1;
343 }
344
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 306 times.
308 if (find_flag_index(parser, argv[start + 1]) >= 0) {
345 2 ap_error_set(err, AP_ERR_MISSING_VALUE, def->flags[0],
346 2 "option '%s' requires a value", def->flags[0]);
347 2 return -1;
348 }
349
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 306 times.
306 if (push_value(parsed, def_index, argv[start + 1], err) != 0) {
350 return -1;
351 }
352 306 *idx = start + 1;
353 306 return 0;
354 }
355
356
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 if (def->opts.nargs == AP_NARGS_OPTIONAL) {
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (inline_value) {
358 return push_value(parsed, def_index, inline_value, err);
359 }
360
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (start + 1 < argc) {
361 16 int next_flag_idx = find_flag_index(parser, argv[start + 1]);
362
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
16 if (next_flag_idx < 0) {
363
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
14 if (push_value(parsed, def_index, argv[start + 1], err) != 0) {
364 return -1;
365 }
366 14 *idx = start + 1;
367 }
368 }
369 16 return 0;
370 }
371
372
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (def->opts.nargs == AP_NARGS_FIXED) {
373 4 int need = def->opts.nargs_count;
374 4 int consumed = 0;
375 4 int j = start + 1;
376
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (inline_value) {
377 if (push_value(parsed, def_index, inline_value, err) != 0) {
378 return -1;
379 }
380 consumed++;
381 }
382
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 while (consumed < need) {
383
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
14 if (j >= argc || strcmp(argv[j], "--") == 0 ||
384 6 find_flag_index(parser, argv[j]) >= 0) {
385 2 ap_error_set(err, AP_ERR_INVALID_NARGS, def->flags[0],
386 2 "option '%s' requires exactly %d values", def->flags[0],
387 2 def->opts.nargs_count);
388 2 return -1;
389 }
390
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (push_value(parsed, def_index, argv[j], err) != 0) {
391 return -1;
392 }
393 6 consumed++;
394 6 j++;
395 }
396 2 *idx = j - 1;
397 2 return 0;
398 }
399
400 {
401 4 int j = start + 1;
402 4 int consumed = 0;
403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (inline_value) {
404 if (push_value(parsed, def_index, inline_value, err) != 0) {
405 return -1;
406 }
407 consumed = 1;
408 }
409
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while (j < argc) {
410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (strcmp(argv[j], "--") == 0) {
411 break;
412 }
413
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (find_flag_index(parser, argv[j]) >= 0) {
414 break;
415 }
416
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (push_value(parsed, def_index, argv[j], err) != 0) {
417 return -1;
418 }
419 4 consumed++;
420 4 j++;
421 }
422
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 if (def->opts.nargs == AP_NARGS_ONE_OR_MORE && consumed == 0) {
423 2 ap_error_set(err, AP_ERR_INVALID_NARGS, def->flags[0],
424 2 "option '%s' requires at least one value", def->flags[0]);
425 2 return -1;
426 }
427 2 *idx = j - 1;
428 2 return 0;
429 }
430 }
431
432 326 int ap_parser_parse(const ap_parser *parser, int argc, char **argv,
433 bool allow_unknown, ap_parsed_arg **out_parsed,
434 ap_strvec *positionals, ap_strvec *unknown_args,
435 ap_error *err) {
436 ap_parsed_arg *parsed;
437 326 int positional_defs_count = 0;
438 326 int *positional_defs = NULL;
439 int i;
440 326 int positional_cursor = 0;
441 326 int token_index = 1;
442 326 bool positional_only = false;
443
444 326 parsed = calloc((size_t)parser->defs_count, sizeof(ap_parsed_arg));
445
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 326 times.
326 if (!parsed) {
446 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
447 return -1;
448 }
449
450
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 324 times.
326 if (collect_positional_def_indexes(parser, &positional_defs,
451 &positional_defs_count) != 0) {
452 2 free(parsed);
453 2 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
454 2 return -1;
455 }
456
457
2/2
✓ Branch 0 taken 1374 times.
✓ Branch 1 taken 276 times.
1650 while (token_index < argc) {
458 1374 const char *token = argv[token_index];
459
460
4/4
✓ Branch 0 taken 1296 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 1262 times.
1374 if (!positional_only && strcmp(token, "--") == 0) {
461
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
34 if (allow_unknown && unknown_args) {
462 int j;
463
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 16 times.
174 for (j = token_index + 1; j < argc; j++) {
464 158 char *copy = ap_strdup(argv[j]);
465
2/4
✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 158 times.
158 if (!copy || ap_strvec_push(unknown_args, copy) != 0) {
466 free(copy);
467 free(positional_defs);
468 free(parsed);
469 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
470 return -1;
471 }
472 }
473 16 token_index = argc;
474 16 break;
475 }
476 18 positional_only = true;
477 18 token_index++;
478 18 continue;
479 }
480
481
4/4
✓ Branch 0 taken 1262 times.
✓ Branch 1 taken 78 times.
✓ Branch 3 taken 924 times.
✓ Branch 4 taken 338 times.
1340 if (!positional_only && ap_token_has_prefix(parser, token)) {
482 int cluster_rc =
483 924 parse_short_cluster(parser, token, allow_unknown, parsed, err);
484
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 920 times.
924 if (cluster_rc == 0) {
485 4 token_index++;
486 4 continue;
487 }
488
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 912 times.
920 if (cluster_rc < 0) {
489 8 free_parsed_storage(parser, parsed);
490 8 free(positional_defs);
491 8 free(parsed);
492 8 return -1;
493 }
494
495 912 const char *eq = strchr(token, '=');
496 912 const char *inline_value = NULL;
497 912 int def_index = -1;
498
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 892 times.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
912 if (eq && eq != token) {
499 20 def_index = find_flag_index_n(parser, token, (size_t)(eq - token));
500
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 if (def_index >= 0) {
501 10 inline_value = eq + 1;
502 }
503 } else {
504 892 def_index = find_flag_index(parser, token);
505 }
506
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 908 times.
912 if (def_index == -2) {
507 4 ap_error_set(err, AP_ERR_DUPLICATE_OPTION, token,
508 "ambiguous option '%s'", token);
509 4 goto fail;
510 }
511
2/2
✓ Branch 0 taken 436 times.
✓ Branch 1 taken 472 times.
908 if (def_index < 0) {
512
2/2
✓ Branch 0 taken 432 times.
✓ Branch 1 taken 4 times.
436 if (allow_unknown) {
513 432 char *copy = ap_strdup(token);
514
3/6
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 432 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 432 times.
864 if (!copy || !unknown_args ||
515 432 ap_strvec_push(unknown_args, copy) != 0) {
516 free(copy);
517 ap_error_set(err, AP_ERR_NO_MEMORY, token, "out of memory");
518 goto fail;
519 }
520
2/2
✓ Branch 0 taken 428 times.
✓ Branch 1 taken 4 times.
432 if (token_index + 1 < argc &&
521
3/4
✓ Branch 0 taken 428 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 410 times.
✓ Branch 3 taken 18 times.
856 strcmp(argv[token_index + 1], "--") != 0 &&
522 428 find_flag_index(parser, argv[token_index + 1]) < 0 &&
523
2/2
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 270 times.
410 !ap_token_has_prefix(parser, argv[token_index + 1])) {
524 140 char *next_copy = ap_strdup(argv[token_index + 1]);
525
2/4
✓ Branch 0 taken 140 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 140 times.
140 if (!next_copy || ap_strvec_push(unknown_args, next_copy) != 0) {
526 free(next_copy);
527 ap_error_set(err, AP_ERR_NO_MEMORY, token, "out of memory");
528 goto fail;
529 }
530 140 token_index += 2;
531 140 continue;
532 }
533 292 token_index++;
534 292 continue;
535 }
536 4 ap_error_set(err, AP_ERR_UNKNOWN_OPTION, token, "unknown option '%s'",
537 token);
538 4 goto fail;
539 }
540
4/4
✓ Branch 0 taken 172 times.
✓ Branch 1 taken 300 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 170 times.
644 if (parsed[def_index].seen && !action_allows_multiple_occurrences(
541 172 parser->defs[def_index].opts.action)) {
542 2 ap_error_set(err, AP_ERR_DUPLICATE_OPTION, token,
543 "duplicate option '%s'", token);
544 2 goto fail;
545 }
546
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 468 times.
470 if (push_token(parsed, def_index, token, err) != 0) {
547 2 goto fail;
548 }
549
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 456 times.
468 if (consume_optional_values(parser, argc, argv, &token_index, def_index,
550 inline_value, parsed, err) != 0) {
551 12 free_parsed_storage(parser, parsed);
552 12 free(positional_defs);
553 12 free(parsed);
554 12 return -1;
555 }
556 456 parsed[def_index].seen = true;
557 456 token_index++;
558 456 continue;
559 }
560
561
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 416 times.
416 if (ap_strvec_push(positionals, ap_strdup(token)) != 0) {
562 free_parsed_storage(parser, parsed);
563 free(positional_defs);
564 free(parsed);
565 ap_error_set(err, AP_ERR_NO_MEMORY, token, "out of memory");
566 return -1;
567 }
568 416 token_index++;
569 }
570
571
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 286 times.
462 for (i = 0; i < positional_defs_count; i++) {
572 176 const ap_arg_def *def = &parser->defs[positional_defs[i]];
573 176 int values_left = positionals->count - positional_cursor;
574 176 int min_after = remaining_min_required(parser, positional_defs,
575 positional_defs_count, i + 1);
576 176 int take = 0;
577
578
4/6
✓ Branch 0 taken 132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
176 switch (def->opts.nargs) {
579 132 case AP_NARGS_ONE:
580 132 take = values_left > 0 ? 1 : 0;
581 132 break;
582 case AP_NARGS_OPTIONAL:
583 take = values_left > min_after ? 1 : 0;
584 break;
585 24 case AP_NARGS_ZERO_OR_MORE:
586 24 take = values_left - min_after;
587
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24 if (take < 0) {
588 2 take = 0;
589 }
590 24 break;
591 2 case AP_NARGS_ONE_OR_MORE:
592 2 take = values_left - min_after;
593
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (take < 1) {
594 char label[96];
595 2 ap_error_label_for_arg(def, label, sizeof(label));
596 2 ap_error_set(err, AP_ERR_INVALID_NARGS, ap_error_argument_name(def),
597 "%s requires at least one value", label);
598 2 goto fail;
599 }
600 break;
601 18 case AP_NARGS_FIXED:
602 18 take = def->opts.nargs_count;
603
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 if (values_left < take) {
604 char label[96];
605 4 ap_error_label_for_arg(def, label, sizeof(label));
606 4 ap_error_set(err, AP_ERR_INVALID_NARGS, ap_error_argument_name(def),
607 "%s requires exactly %d values", label,
608 4 def->opts.nargs_count);
609 4 goto fail;
610 }
611 14 break;
612 }
613
614
3/4
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 170 times.
✓ Branch 2 taken 350 times.
✗ Branch 3 not taken.
520 while (take-- > 0 && positional_cursor < positionals->count) {
615
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 if (push_token(parsed, positional_defs[i],
616 350 positionals->items[positional_cursor], err) != 0) {
617 goto fail;
618 }
619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 350 times.
350 if (push_value(parsed, positional_defs[i],
620 350 positionals->items[positional_cursor], err) != 0) {
621 goto fail;
622 }
623 350 positional_cursor++;
624 }
625 }
626
627
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 264 times.
286 if (positional_cursor < positionals->count) {
628
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
22 if (allow_unknown && unknown_args) {
629
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 while (positional_cursor < positionals->count) {
630 6 char *extra = ap_strdup(positionals->items[positional_cursor]);
631
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
6 if (!extra || ap_strvec_push(unknown_args, extra) != 0) {
632 free(extra);
633 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
634 goto fail;
635 }
636 6 positional_cursor++;
637 }
638 4 free(positional_defs);
639 4 *out_parsed = parsed;
640 4 return 0;
641 }
642 18 ap_error_set(err, AP_ERR_UNEXPECTED_POSITIONAL,
643 18 positionals->items[positional_cursor],
644 "unexpected positional argument '%s'",
645 18 positionals->items[positional_cursor]);
646 18 goto fail;
647 }
648
649 264 free(positional_defs);
650 264 *out_parsed = parsed;
651 264 return 0;
652
653 36 fail: {
654 36 free_parsed_storage(parser, parsed);
655 36 free(positional_defs);
656 36 free(parsed);
657 36 return -1;
658 }
659 }
660