GCC Code Coverage Report


Directory: lib/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 84.2% 235 / 0 / 279
Functions: 100.0% 13 / 0 / 13
Branches: 81.3% 148 / 0 / 182

core_convert.c
Line Branch Exec Source
1 #include <errno.h>
2 #include <float.h>
3 #include <limits.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "ap_internal.h"
8
9 48 static int parse_int32(const char *text, int32_t *out_value) {
10 48 char *end = NULL;
11 long value;
12
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
48 if (!text || !out_value) {
13 return -1;
14 }
15 48 errno = 0;
16 48 value = strtol(text, &end, 10);
17
4/6
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
48 if (*text == '\0' || *end != '\0' || errno == ERANGE) {
18 4 return -1;
19 }
20
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 40 times.
44 if (value < INT32_MIN || value > INT32_MAX) {
21 4 return -1;
22 }
23 40 *out_value = (int32_t)value;
24 40 return 0;
25 }
26
27 26 static int parse_int64(const char *text, int64_t *out_value) {
28 26 char *end = NULL;
29 long long value;
30
2/4
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
26 if (!text || !out_value) {
31 return -1;
32 }
33 26 errno = 0;
34 26 value = strtoll(text, &end, 10);
35
5/6
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 16 times.
26 if (*text == '\0' || *end != '\0' || errno == ERANGE) {
36 10 return -1;
37 }
38 if (value < INT64_MIN || value > INT64_MAX) {
39 return -1;
40 }
41 16 *out_value = (int64_t)value;
42 16 return 0;
43 }
44
45 36 static int parse_uint64(const char *text, uint64_t *out_value) {
46 36 char *end = NULL;
47 unsigned long long value;
48
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
36 if (!text || !out_value) {
49 return -1;
50 }
51 36 errno = 0;
52 36 value = strtoull(text, &end, 10);
53
6/8
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 26 times.
36 if (*text == '\0' || *end != '\0' || errno == ERANGE || text[0] == '-') {
54 10 return -1;
55 }
56 26 *out_value = (uint64_t)value;
57 26 return 0;
58 }
59
60 18 static int parse_double(const char *text, double *out_value) {
61 18 char *end = NULL;
62 double value;
63
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
18 if (!text || !out_value) {
64 return -1;
65 }
66 18 errno = 0;
67 18 value = strtod(text, &end);
68
5/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 8 times.
18 if (*text == '\0' || *end != '\0' || errno == ERANGE) {
69 10 return -1;
70 }
71 8 *out_value = value;
72 8 return 0;
73 }
74
75 112 static int fill_values_from_default(const ap_arg_def *def, ap_strvec *values,
76 ap_error *err) {
77 char *copy;
78
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 8 times.
112 if (!def->opts.default_value) {
79 104 return 0;
80 }
81 8 copy = ap_strdup(def->opts.default_value);
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!copy) {
83 ap_error_set(err, AP_ERR_NO_MEMORY, def->dest, "out of memory");
84 return -1;
85 }
86
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (ap_strvec_push(values, copy) != 0) {
87 free(copy);
88 ap_error_set(err, AP_ERR_NO_MEMORY, def->dest, "out of memory");
89 return -1;
90 }
91 8 return 0;
92 }
93
94 272 static int copy_string_values(const ap_strvec *src, ap_ns_entry *dst,
95 ap_error *err) {
96 int i;
97
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 240 times.
272 if (src->count == 0) {
98 32 dst->as.strings = NULL;
99 32 dst->count = 0;
100 32 return 0;
101 }
102 240 dst->as.strings = calloc((size_t)src->count, sizeof(char *));
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (!dst->as.strings) {
104 ap_error_set(err, AP_ERR_NO_MEMORY, dst->dest, "out of memory");
105 return -1;
106 }
107 240 dst->count = src->count;
108
2/2
✓ Branch 0 taken 524 times.
✓ Branch 1 taken 240 times.
764 for (i = 0; i < src->count; i++) {
109 524 dst->as.strings[i] = ap_strdup(src->items[i]);
110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 524 times.
524 if (!dst->as.strings[i]) {
111 ap_error_set(err, AP_ERR_NO_MEMORY, dst->dest, "out of memory");
112 return -1;
113 }
114 }
115 240 return 0;
116 }
117
118 94 static int copy_int_values(const ap_arg_def *def, const ap_strvec *src,
119 ap_ns_entry *dst, ap_error *err) {
120 int i;
121
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 46 times.
94 if (src->count == 0) {
122 48 dst->as.ints = NULL;
123 48 dst->count = 0;
124 48 return 0;
125 }
126 46 dst->as.ints = calloc((size_t)src->count, sizeof(int32_t));
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (!dst->as.ints) {
128 ap_error_set(err, AP_ERR_NO_MEMORY, dst->dest, "out of memory");
129 return -1;
130 }
131 46 dst->count = src->count;
132
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 38 times.
86 for (i = 0; i < src->count; i++) {
133
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 40 times.
48 if (parse_int32(src->items[i], &dst->as.ints[i]) != 0) {
134 8 ap_error_set(err, AP_ERR_INVALID_INT32, ap_error_argument_name(def),
135 "argument '%s' must be a valid int32: '%s'",
136 8 ap_error_argument_name(def), src->items[i]);
137 8 return -1;
138 }
139 }
140 38 return 0;
141 }
142
143 28 static int copy_int64_values(const ap_arg_def *def, const ap_strvec *src,
144 ap_ns_entry *dst, ap_error *err) {
145 int i;
146
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 22 times.
28 if (src->count == 0) {
147 6 dst->as.int64s = NULL;
148 6 dst->count = 0;
149 6 return 0;
150 }
151 22 dst->as.int64s = calloc((size_t)src->count, sizeof(int64_t));
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (!dst->as.int64s) {
153 ap_error_set(err, AP_ERR_NO_MEMORY, dst->dest, "out of memory");
154 return -1;
155 }
156 22 dst->count = src->count;
157
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12 times.
38 for (i = 0; i < src->count; i++) {
158
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 16 times.
26 if (parse_int64(src->items[i], &dst->as.int64s[i]) != 0) {
159 10 ap_error_set(err, AP_ERR_INVALID_INT64, ap_error_argument_name(def),
160 "argument '%s' must be a valid int64: '%s'",
161 10 ap_error_argument_name(def), src->items[i]);
162 10 return -1;
163 }
164 }
165 12 return 0;
166 }
167
168 44 static int copy_uint64_values(const ap_arg_def *def, const ap_strvec *src,
169 ap_ns_entry *dst, ap_error *err) {
170 int i;
171
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 30 times.
44 if (src->count == 0) {
172 14 dst->as.uint64s = NULL;
173 14 dst->count = 0;
174 14 return 0;
175 }
176 30 dst->as.uint64s = calloc((size_t)src->count, sizeof(uint64_t));
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (!dst->as.uint64s) {
178 ap_error_set(err, AP_ERR_NO_MEMORY, dst->dest, "out of memory");
179 return -1;
180 }
181 30 dst->count = src->count;
182
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 20 times.
56 for (i = 0; i < src->count; i++) {
183
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 26 times.
36 if (parse_uint64(src->items[i], &dst->as.uint64s[i]) != 0) {
184 10 ap_error_set(err, AP_ERR_INVALID_UINT64, ap_error_argument_name(def),
185 "argument '%s' must be a valid uint64: '%s'",
186 10 ap_error_argument_name(def), src->items[i]);
187 10 return -1;
188 }
189 }
190 20 return 0;
191 }
192
193 18 static int copy_double_values(const ap_arg_def *def, const ap_strvec *src,
194 ap_ns_entry *dst, ap_error *err) {
195 int i;
196
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (src->count == 0) {
197 2 dst->as.doubles = NULL;
198 2 dst->count = 0;
199 2 return 0;
200 }
201 16 dst->as.doubles = calloc((size_t)src->count, sizeof(double));
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if (!dst->as.doubles) {
203 ap_error_set(err, AP_ERR_NO_MEMORY, dst->dest, "out of memory");
204 return -1;
205 }
206 16 dst->count = src->count;
207
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
24 for (i = 0; i < src->count; i++) {
208
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 8 times.
18 if (parse_double(src->items[i], &dst->as.doubles[i]) != 0) {
209 10 ap_error_set(err, AP_ERR_INVALID_DOUBLE, ap_error_argument_name(def),
210 "argument '%s' must be a valid double: '%s'",
211 10 ap_error_argument_name(def), src->items[i]);
212 10 return -1;
213 }
214 }
215 6 return 0;
216 }
217
218 452 static int validate_choices_merged(const ap_arg_def *def,
219 const ap_strvec *values, ap_error *err) {
220 int i;
221 int j;
222 char label[96];
223
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
452 if (!def->opts.choices.items || def->opts.choices.count <= 0) {
224 438 return 0;
225 }
226
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
18 for (i = 0; i < values->count; i++) {
227 6 bool found = false;
228
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
14 for (j = 0; j < def->opts.choices.count; j++) {
229
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (strcmp(values->items[i], def->opts.choices.items[j]) == 0) {
230 4 found = true;
231 4 break;
232 }
233 }
234
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 if (!found) {
235 2 ap_error_label_for_arg(def, label, sizeof(label));
236 2 ap_error_set(err, AP_ERR_INVALID_CHOICE, ap_error_argument_name(def),
237 2 "invalid choice '%s' for %s", values->items[i], label);
238 2 return -1;
239 }
240 }
241 12 return 0;
242 }
243
244 734 static int run_action_callback(const ap_parser *parser, const ap_arg_def *def,
245 const ap_parsed_arg *parsed, ap_namespace *ns,
246 ap_error *err) {
247 ap_action_request request;
248
249
2/2
✓ Branch 0 taken 728 times.
✓ Branch 1 taken 6 times.
734 if (!def->opts.action_callback) {
250 728 return 0;
251 }
252
253 6 memset(&request, 0, sizeof(request));
254 6 request.parser = parser;
255 6 request.dest = def->dest;
256 6 request.argc = parsed->tokens.count;
257 6 request.argv = parsed->tokens.items;
258
259
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
6 if (def->opts.action_callback(&request, ns, def->opts.action_user_data,
260 err) == 0) {
261 2 return 0;
262 }
263
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 if (!err || err->code == AP_ERR_NONE) {
264 2 ap_error_set(err, AP_ERR_INVALID_DEFINITION, ap_error_argument_name(def),
265 "action callback failed for '%s'",
266 ap_error_argument_name(def));
267 }
268 4 return -1;
269 }
270
271 256 int ap_build_namespace(const ap_parser *parser, const ap_parsed_arg *parsed,
272 ap_namespace **out_ns, ap_error *err) {
273 ap_namespace *ns;
274 int i;
275 256 bool help_requested = false;
276
277
2/2
✓ Branch 0 taken 782 times.
✓ Branch 1 taken 244 times.
1026 for (i = 0; i < parser->defs_count; i++) {
278 782 const ap_arg_def *def = &parser->defs[i];
279
2/2
✓ Branch 0 taken 298 times.
✓ Branch 1 taken 484 times.
782 if (def->opts.action == AP_ACTION_STORE_TRUE &&
280
4/4
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 244 times.
298 strcmp(def->dest, "help") == 0 && parsed[i].seen) {
281 12 help_requested = true;
282 12 break;
283 }
284 }
285
286 256 ns = calloc(1, sizeof(ap_namespace));
287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 256 times.
256 if (!ns) {
288 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
289 return -1;
290 }
291
292 256 ns->entries = calloc((size_t)parser->defs_count, sizeof(ap_ns_entry));
293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 256 times.
256 if (!ns->entries) {
294 ap_namespace_free(ns);
295 ap_error_set(err, AP_ERR_NO_MEMORY, "", "out of memory");
296 return -1;
297 }
298 256 ns->count = parser->defs_count;
299
300
2/2
✓ Branch 0 taken 776 times.
✓ Branch 1 taken 210 times.
986 for (i = 0; i < parser->defs_count; i++) {
301 776 const ap_arg_def *def = &parser->defs[i];
302 776 const ap_parsed_arg *p = &parsed[i];
303 776 ap_ns_entry *entry = &ns->entries[i];
304 776 ap_strvec merged = {0};
305
306 776 entry->dest = ap_strdup(def->dest);
307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 776 times.
776 if (!entry->dest) {
308 ap_namespace_free(ns);
309 ap_error_set(err, AP_ERR_NO_MEMORY, def->dest, "out of memory");
310 46 return -1;
311 }
312
313
2/2
✓ Branch 0 taken 298 times.
✓ Branch 1 taken 478 times.
776 if (def->opts.action == AP_ACTION_STORE_TRUE) {
314 298 entry->type = AP_NS_VALUE_BOOL;
315 298 entry->count = 1;
316 298 entry->as.boolean = p->seen ? true : false;
317 298 goto run_callback;
318 }
319
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 476 times.
478 if (def->opts.action == AP_ACTION_STORE_FALSE) {
320 2 entry->type = AP_NS_VALUE_BOOL;
321 2 entry->count = 1;
322 2 entry->as.boolean = p->seen ? false : true;
323 2 goto run_callback;
324 }
325
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 462 times.
476 if (def->opts.action == AP_ACTION_COUNT) {
326 14 entry->type = AP_NS_VALUE_INT32;
327 14 entry->count = 1;
328 14 entry->as.ints = calloc(1, sizeof(int32_t));
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (!entry->as.ints) {
330 ap_namespace_free(ns);
331 ap_error_set(err, AP_ERR_NO_MEMORY, def->dest, "out of memory");
332 return -1;
333 }
334 14 entry->as.ints[0] = p->values.count;
335 14 goto run_callback;
336 }
337
338
2/2
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 112 times.
462 if (p->values.count > 0) {
339 int j;
340
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 350 times.
998 for (j = 0; j < p->values.count; j++) {
341 648 char *copy = ap_strdup(p->values.items[j]);
342
2/4
✓ Branch 0 taken 648 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 648 times.
648 if (!copy || ap_strvec_push(&merged, copy) != 0) {
343 free(copy);
344 ap_strvec_free(&merged);
345 ap_namespace_free(ns);
346 ap_error_set(err, AP_ERR_NO_MEMORY, def->dest, "out of memory");
347 return -1;
348 }
349 }
350
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
112 } else if (fill_values_from_default(def, &merged, err) != 0) {
351 ap_strvec_free(&merged);
352 ap_namespace_free(ns);
353 return -1;
354 }
355
356
4/4
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 450 times.
462 if (!help_requested && validate_choices_merged(def, &merged, err) != 0) {
357 2 ap_strvec_free(&merged);
358 2 ap_namespace_free(ns);
359 2 return -1;
360 }
361
362
6/6
✓ Branch 0 taken 450 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 390 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 58 times.
460 if (!help_requested && def->opts.required && merged.count == 0 &&
363
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 def->opts.nargs == AP_NARGS_ONE) {
364 char label[96];
365 2 ap_strvec_free(&merged);
366 2 ap_namespace_free(ns);
367 2 ap_error_label_for_arg(def, label, sizeof(label));
368 2 ap_error_set(err, AP_ERR_MISSING_REQUIRED, ap_error_argument_name(def),
369 "%s is required", label);
370 2 return -1;
371 }
372
373
2/2
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 186 times.
458 if (def->opts.type == AP_TYPE_STRING) {
374 272 entry->type = AP_NS_VALUE_STRING;
375
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 272 times.
272 if (copy_string_values(&merged, entry, err) != 0) {
376 ap_strvec_free(&merged);
377 ap_namespace_free(ns);
378 return -1;
379 }
380
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 92 times.
186 } else if (def->opts.type == AP_TYPE_INT32) {
381 94 entry->type = AP_NS_VALUE_INT32;
382
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 86 times.
94 if (copy_int_values(def, &merged, entry, err) != 0) {
383 8 ap_strvec_free(&merged);
384 8 ap_namespace_free(ns);
385 8 return -1;
386 }
387
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 64 times.
92 } else if (def->opts.type == AP_TYPE_INT64) {
388 28 entry->type = AP_NS_VALUE_INT64;
389
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 18 times.
28 if (copy_int64_values(def, &merged, entry, err) != 0) {
390 10 ap_strvec_free(&merged);
391 10 ap_namespace_free(ns);
392 10 return -1;
393 }
394
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 20 times.
64 } else if (def->opts.type == AP_TYPE_UINT64) {
395 44 entry->type = AP_NS_VALUE_UINT64;
396
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 34 times.
44 if (copy_uint64_values(def, &merged, entry, err) != 0) {
397 10 ap_strvec_free(&merged);
398 10 ap_namespace_free(ns);
399 10 return -1;
400 }
401
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 } else if (def->opts.type == AP_TYPE_DOUBLE) {
402 18 entry->type = AP_NS_VALUE_DOUBLE;
403
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 8 times.
18 if (copy_double_values(def, &merged, entry, err) != 0) {
404 10 ap_strvec_free(&merged);
405 10 ap_namespace_free(ns);
406 10 return -1;
407 }
408 } else {
409 2 entry->type = AP_NS_VALUE_BOOL;
410 2 entry->count = 1;
411 2 entry->as.boolean = merged.count > 0;
412 }
413
414
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 416 times.
420 if (run_action_callback(parser, def, p, ns, err) != 0) {
415 4 ap_strvec_free(&merged);
416 4 ap_namespace_free(ns);
417 4 return -1;
418 }
419
420 416 ap_strvec_free(&merged);
421 416 continue;
422
423 314 run_callback:
424
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 314 times.
314 if (run_action_callback(parser, def, p, ns, err) != 0) {
425 ap_namespace_free(ns);
426 return -1;
427 }
428 }
429
430 210 *out_ns = ns;
431 210 return 0;
432 }
433