Bug Summary

File:.build-ci/../util/argconfig.c
Warning:line 434, column 3
Potential leak of memory pointed to by 'long_opt_map'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name argconfig.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -fcoverage-compilation-dir=/__w/nvme-cli/nvme-cli/.build-ci -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /__w/nvme-cli/nvme-cli/.build-ci/nvme-config.h -I nvme.p -I . -I .. -I ccan -I ../ccan -I libnvme/src -I ../libnvme/src -I /usr/include/json-c -D _FILE_OFFSET_BITS=64 -D _GNU_SOURCE -U NDEBUG -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -std=gnu99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /__w/nvme-cli/nvme-cli/.build-ci/scan-results/2026-06-24-175442-590-1 -x c ../util/argconfig.c
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2014 PMC-Sierra, Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20
21/*
22 *
23 * Author: Logan Gunthorpe
24 *
25 * Date: Oct 23 2014
26 *
27 * Description:
28 * Functions for parsing command line options.
29 *
30 */
31
32#include <errno(*__errno_location ()).h>
33#include <getopt.h>
34#include <inttypes.h>
35#include <limits.h>
36#include <locale.h>
37#include <stdbool.h>
38#include <stdarg.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include "argconfig.h"
44#include "cleanup.h"
45#include "suffix.h"
46
47const char *libnvme_strerror(int errnum);
48
49static bool_Bool is_null_or_empty(const char *s)
50{
51 return !s || !*s;
52}
53
54static const char *append_usage_str = "";
55
56void argconfig_append_usage(const char *str)
57{
58 append_usage_str = str;
59}
60
61void print_word_wrapped(const char *s, int indent, int start, FILE *stream)
62{
63 const int width = 76;
64 const char *c, *t;
65 int next_space = -1;
66 int last_line = indent;
67
68 while (start < indent) {
69 putc(' ', stream);
70 start++;
71 }
72
73 for (c = s; *c != 0; c++) {
74 if (*c == '\n')
75 goto new_line;
76
77 if (*c == ' ' || next_space < 0) {
78 next_space = 0;
79 for (t = c + 1; *t != 0 && *t != ' '; t++)
80 next_space++;
81
82 if (((int)(c - s) + start + next_space) > (last_line - indent + width)) {
83 int i;
84new_line:
85 last_line = (int) (c-s) + start;
86 putc('\n', stream);
87 for (i = 0; i < indent; i++)
88 putc(' ', stream);
89 start = indent;
90 continue;
91 }
92 }
93 putc(*c, stream);
94 }
95}
96
97static void show_option(const struct argconfig_commandline_options *option)
98{
99 char buffer[0x1000];
100 char *b = buffer;
101
102 b += sprintf(b, " [ ");
103 if (option->option) {
104 b += sprintf(b, " --%s", option->option);
105 if (option->argument_type == optional_argument2)
106 b += sprintf(b, "[=<%s>]", option->meta ? option->meta : "arg");
107 if (option->argument_type == required_argument1)
108 b += sprintf(b, "=<%s>", option->meta ? option->meta : "arg");
109 if (option->short_option)
110 b += sprintf(b, ",");
111 }
112 if (option->short_option) {
113 b += sprintf(b, " -%c", option->short_option);
114 if (option->argument_type == optional_argument2)
115 b += sprintf(b, " [<%s>]", option->meta ? option->meta : "arg");
116 if (option->argument_type == required_argument1)
117 b += sprintf(b, " <%s>", option->meta ? option->meta : "arg");
118 }
119 b += sprintf(b, " ] ");
120
121 fprintf(stderrstderr, "%s", buffer);
122 if (option->help) {
123 print_word_wrapped("--- ", 40, b - buffer, stderrstderr);
124 print_word_wrapped(option->help, 44, 44, stderrstderr);
125 }
126 fprintf(stderrstderr, "\n");
127}
128
129void argconfig_print_help(const char *program_desc,
130 struct argconfig_commandline_options *s)
131{
132 const char *pending_header = "Options";
133 bool_Bool header_printed = false0;
134
135 fprintf(stderrstderr, "\033[1mUsage: %s\033[0m\n\n",
136 append_usage_str);
137
138 print_word_wrapped(program_desc, 0, 0, stderrstderr);
139 fprintf(stderrstderr, "\n");
140
141 if (!s || !s->option)
142 return;
143
144 for (; s->option; s++) {
145 if (s->config_type == CFG_GROUP_SEPARATOR) {
146 pending_header = s->help;
147 header_printed = false0;
148 continue;
149 }
150 if (!header_printed) {
151 fprintf(stderrstderr, "\n\033[1m%s:\033[0m\n", pending_header);
152 header_printed = true1;
153 }
154 if (!s->hidden)
155 show_option(s);
156 }
157}
158
159static int argconfig_error(char *type, const char *opt, const char *arg)
160{
161 fprintf(stderrstderr, "Expected %s argument for '%s' but got '%s'!\n", type, opt, arg);
162 return -EINVAL22;
163}
164
165static int argconfig_parse_type(struct argconfig_commandline_options *s)
166{
167 void *value = s->default_value;
168 char *endptr;
169 int ret = 0;
170
171 errno(*__errno_location ()) = 0; /* To distinguish success/failure after strtol/stroul call */
172
173 switch (s->config_type) {
174 case CFG_STRING:
175 *(char **)value = optarg;
176 break;
177 case CFG_INT:
178 *(int *)value = strtol(optarg, &endptr, 0);
179 if (errno(*__errno_location ()) || optarg == endptr)
180 ret = argconfig_error("integer", s->option, optarg);
181 break;
182 case CFG_BYTE: {
183 unsigned long tmp = strtoul(optarg, &endptr, 0);
184
185 if (errno(*__errno_location ()) || tmp >= 1 << 8 || optarg == endptr)
186 ret = argconfig_error("byte", s->option, optarg);
187 else
188 *(uint8_t *)value = tmp;
189 break;
190 }
191 case CFG_SHORT: {
192 unsigned long tmp = strtoul(optarg, &endptr, 0);
193
194 if (errno(*__errno_location ()) || tmp >= 1 << 16 || optarg == endptr)
195 ret = argconfig_error("short", s->option, optarg);
196 else
197 *(uint16_t *)value = tmp;
198 break;
199 }
200 case CFG_POSITIVE: {
201 uint32_t tmp = strtoul(optarg, &endptr, 0);
202
203 if (errno(*__errno_location ()) || optarg == endptr)
204 ret = argconfig_error("word", s->option, optarg);
205 else
206 *(uint32_t *)value = tmp;
207 break;
208 }
209 case CFG_INCREMENT:
210 *(int *)value += 1;
211 break;
212 case CFG_LONG:
213 *(unsigned long *)value = strtoul(optarg, &endptr, 0);
214 if (errno(*__errno_location ()) || optarg == endptr)
215 ret = argconfig_error("long integer", s->option, optarg);
216 break;
217 case CFG_LONG_SUFFIX:
218 ret = suffix_binary_parse(optarg, &endptr, (uint64_t *)value);
219 if (ret)
220 argconfig_error("long suffixed integer", s->option, optarg);
221 break;
222 case CFG_DOUBLE:
223 *(double *)value = strtod(optarg, &endptr);
224 if (errno(*__errno_location ()) || optarg == endptr)
225 ret = argconfig_error("float", s->option, optarg);
226 break;
227 case CFG_FLAG:
228 *(bool_Bool *)value = true1;
229 break;
230 case CFG_GROUP_SEPARATOR:
231 break;
232 }
233
234 return ret;
235}
236
237static void argconfig_set_opt_val(enum argconfig_types type, union argconfig_val *opt_val, void *val)
238{
239 switch (type) {
240 case CFG_FLAG:
241 *(bool_Bool *)val = opt_val->bool_val;
242 break;
243 case CFG_LONG_SUFFIX:
244 *(uint64_t *)val = opt_val->long_suffix;
245 break;
246 case CFG_POSITIVE:
247 *(uint32_t *)val = opt_val->positive;
248 break;
249 case CFG_INT:
250 *(int *)val = opt_val->int_val;
251 break;
252 case CFG_LONG:
253 *(unsigned long *)val = opt_val->long_val;
254 break;
255 case CFG_DOUBLE:
256 *(double *)val = opt_val->double_val;
257 break;
258 case CFG_BYTE:
259 *(uint8_t *)val = opt_val->byte;
260 break;
261 case CFG_SHORT:
262 *(uint16_t *)val = opt_val->short_val;
263 break;
264 case CFG_INCREMENT:
265 *(int *)val = opt_val->increment;
266 break;
267 case CFG_STRING:
268 *(char **)val = opt_val->string;
269 break;
270 case CFG_GROUP_SEPARATOR:
271 break;
272 }
273}
274
275static struct argconfig_opt_val *
276argconfig_match_val(struct argconfig_opt_val *v, const char *str)
277{
278 size_t len = strlen(str);
279 struct argconfig_opt_val *match = NULL((void*)0);
280
281 for (; v->str; v++) {
282 if (strncasecmp(str, v->str, len))
283 continue;
284
285 if (len == strlen(v->str))
286 return v;
287
288 if (match)
289 return NULL((void*)0); /* multiple matches; input is ambiguous */
290
291 match = v;
292 }
293
294 return match;
295}
296
297static int argconfig_parse_val(struct argconfig_commandline_options *s)
298{
299 struct argconfig_opt_val *v = s->opt_val;
300
301 if (v)
302 v = argconfig_match_val(v, optarg);
303 if (!v)
304 return argconfig_parse_type(s);
305
306 argconfig_set_opt_val(v->type, &v->val, s->default_value);
307 return 0;
308}
309
310static bool_Bool argconfig_check_verbose(struct argconfig_commandline_options *s)
311{
312 for (; s && s->option; s++) {
313 if (!strcmp(s->option, "verbose") &&
314 s->config_type == CFG_INCREMENT)
315 return s->seen;
316 }
317
318 return false0;
319}
320
321int argconfig_parse(int argc, char *argv[], const char *program_desc,
322 struct argconfig_commandline_options *options)
323{
324 __cleanup_free__attribute__((cleanup(freep))) char *short_opts = NULL((void*)0);
325 __cleanup_free__attribute__((cleanup(freep))) struct option *long_opts = NULL((void*)0);
326 __cleanup_free__attribute__((cleanup(freep))) int *long_opt_map = NULL((void*)0);
327 struct argconfig_commandline_options *s;
328 int c, long_opt_index = 0, opt_index = 0, short_index = 0, options_count = 0;
329 int ret = 0;
330
331 errno(*__errno_location ()) = 0;
332 for (s = options; s->option; s++)
333 options_count++;
334
335 long_opts = calloc(options_count + 2, sizeof(struct option));
336 short_opts = calloc(options_count * 3 + 3, sizeof(*short_opts));
337 long_opt_map = calloc(options_count + 2, sizeof(*long_opt_map));
338
339 if (!long_opts || !short_opts || !long_opt_map) {
340 fprintf(stderrstderr, "failed to allocate memory for opts: %s\n", libnvme_strerror(errno(*__errno_location ())));
341 return -errno(*__errno_location ());
342 }
343
344 for (s = options, opt_index = 0; s->option; s++, opt_index++) {
345 s->seen = false0;
346 if (s->config_type == CFG_GROUP_SEPARATOR)
347 continue;
348 if (s->short_option) {
349 short_opts[short_index++] = s->short_option;
350 if (s->argument_type == required_argument1 ||
351 s->argument_type == optional_argument2)
352 short_opts[short_index++] = ':';
353 if (s->argument_type == optional_argument2)
354 short_opts[short_index++] = ':';
355 }
356 if (!is_null_or_empty(s->option)) {
357 long_opts[long_opt_index].name = s->option;
358 long_opts[long_opt_index].has_arg = s->argument_type;
359 long_opt_map[long_opt_index] = opt_index;
360 long_opt_index++;
361 }
362 }
363
364 long_opts[long_opt_index].name = "help";
365 long_opts[long_opt_index].val = 'h';
366
367 short_opts[short_index++] = '?';
368 short_opts[short_index] = 'h';
369
370 optind = 0;
371 while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &long_opt_index)) != -1) {
372 if (c) {
373 if (c == '?' || c == 'h') {
374 argconfig_print_help(program_desc, options);
375 ret = -EINVAL22;
376 break;
377 }
378 for (opt_index = 0; opt_index < options_count; opt_index++) {
379 if (c == options[opt_index].short_option)
380 break;
381 }
382 if (opt_index == options_count)
383 continue;
384 } else {
385 opt_index = long_opt_map[long_opt_index];
386 }
387
388 s = &options[opt_index];
389 s->seen = true1;
390
391 if (!s->default_value)
392 continue;
393
394 ret = argconfig_parse_val(s);
395 if (ret)
396 break;
397 }
398
399 if (!argconfig_check_verbose(options))
400 setlocale(LC_ALL6, "C");
401
402 return ret;
403}
404
405/*
406 * Parse global (pre-subcommand) options from argc/argv. Stops at the first
407 * non-option argument (i.e. the subcommand name) so that subcommand-specific
408 * options are left in place for the subcommand dispatcher. After a successful
409 * call, optind points to the first non-option argument (the subcommand).
410 *
411 * Returns 0 on success, negative errno on failure.
412 */
413int argconfig_parse_global(int argc, char *argv[],
414 struct argconfig_commandline_options *options)
415{
416 __cleanup_free__attribute__((cleanup(freep))) char *short_opts = NULL((void*)0);
417 __cleanup_free__attribute__((cleanup(freep))) struct option *long_opts = NULL((void*)0);
418 __cleanup_free__attribute__((cleanup(freep))) int *long_opt_map = NULL((void*)0);
419 struct argconfig_commandline_options *s;
420 int c, long_opt_index = 0, opt_index = 0;
421 int short_index = 0, options_count = 0;
422 int ret = 0;
423
424 errno(*__errno_location ()) = 0;
425 for (s = options; s->option; s++)
1
Loop condition is false. Execution continues on line 428
426 options_count++;
427
428 long_opts = calloc(options_count + 2, sizeof(struct option));
429 /* '+' prefix: stop at the first non-option argument (the subcommand) */
430 short_opts = calloc(options_count * 3 + 4, sizeof(*short_opts));
431 long_opt_map = calloc(options_count + 2, sizeof(*long_opt_map));
2
Memory is allocated
432
433 if (!long_opts || !short_opts || !long_opt_map) {
3
Assuming 'long_opts' is null
434 fprintf(stderrstderr, "failed to allocate memory for opts: %s\n",
4
Potential leak of memory pointed to by 'long_opt_map'
435 libnvme_strerror(errno(*__errno_location ())));
436 return -errno(*__errno_location ());
437 }
438
439 short_opts[short_index++] = '+';
440
441 for (s = options, opt_index = 0; s->option; s++, opt_index++) {
442 s->seen = false0;
443 if (s->config_type == CFG_GROUP_SEPARATOR)
444 continue;
445 if (s->short_option) {
446 short_opts[short_index++] = s->short_option;
447 if (s->argument_type == required_argument1 ||
448 s->argument_type == optional_argument2)
449 short_opts[short_index++] = ':';
450 if (s->argument_type == optional_argument2)
451 short_opts[short_index++] = ':';
452 }
453 if (!is_null_or_empty(s->option)) {
454 long_opts[long_opt_index].name = s->option;
455 long_opts[long_opt_index].has_arg = s->argument_type;
456 long_opt_map[long_opt_index] = opt_index;
457 long_opt_index++;
458 }
459 }
460
461 optind = 0;
462 while ((c = getopt_long(argc, argv, short_opts,
463 long_opts, &long_opt_index)) != -1) {
464 if (c == '?' || c == ':') {
465 ret = -EINVAL22;
466 break;
467 }
468 if (c) {
469 for (opt_index = 0; opt_index < options_count;
470 opt_index++) {
471 if (c == options[opt_index].short_option)
472 break;
473 }
474 if (opt_index == options_count) {
475 ret = -EINVAL22;
476 break;
477 }
478 } else {
479 opt_index = long_opt_map[long_opt_index];
480 }
481
482 s = &options[opt_index];
483 s->seen = true1;
484
485 if (!s->default_value)
486 continue;
487
488 ret = argconfig_parse_val(s);
489 if (ret)
490 break;
491 }
492
493 return ret;
494}
495
496#define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(name, ret_t, ret_max)int argconfig_parse_comma_sep_arrayname(char *string, ret_t *
val, unsigned int max_length) { int ret = 0; uintmax_t v; char
*tmp; char *p; if (is_null_or_empty(string)) return 0; tmp =
strtok(string, ","); while (tmp) { if (ret >= max_length)
return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > ret_max) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
\
497int argconfig_parse_comma_sep_array ## name(char *string, \
498 ret_t *val, \
499 unsigned int max_length) \
500{ \
501 int ret = 0; \
502 uintmax_t v; \
503 char *tmp; \
504 char *p; \
505 \
506 if (is_null_or_empty(string)) \
507 return 0; \
508 \
509 tmp = strtok(string, ","); \
510 \
511 while (tmp) { \
512 if (ret >= max_length) \
513 return -1; \
514 \
515 v = strtoumax(tmp, &p, 0); \
516 if (*p != 0) \
517 return -1; \
518 if (v > ret_max) { \
519 fprintf(stderrstderr, "%s out of range\n", tmp); \
520 return -1; \
521 } \
522 val[ret] = v; \
523 ret++; \
524 \
525 tmp = strtok(NULL((void*)0), ","); \
526 } \
527 \
528 return ret; \
529}
530
531DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(, int, UINT_MAX)int argconfig_parse_comma_sep_array(char *string, int *val, unsigned
int max_length) { int ret = 0; uintmax_t v; char *tmp; char *
p; if (is_null_or_empty(string)) return 0; tmp = strtok(string
, ","); while (tmp) { if (ret >= max_length) return -1; v =
strtoumax(tmp, &p, 0); if (*p != 0) return -1; if (v >
(2147483647 *2U +1U)) { fprintf(stderr, "%s out of range\n",
tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void*
)0), ","); } return ret; }
532DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(_short, unsigned short, UINT16_MAX)int argconfig_parse_comma_sep_array_short(char *string, unsigned
short *val, unsigned int max_length) { int ret = 0; uintmax_t
v; char *tmp; char *p; if (is_null_or_empty(string)) return 0
; tmp = strtok(string, ","); while (tmp) { if (ret >= max_length
) return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > (65535)) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
533DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(_long, unsigned long long, ULLONG_MAX)int argconfig_parse_comma_sep_array_long(char *string, unsigned
long long *val, unsigned int max_length) { int ret = 0; uintmax_t
v; char *tmp; char *p; if (is_null_or_empty(string)) return 0
; tmp = strtok(string, ","); while (tmp) { if (ret >= max_length
) return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > (9223372036854775807LL*2ULL+1ULL)) { fprintf(
stderr, "%s out of range\n", tmp); return -1; } val[ret] = v;
ret++; tmp = strtok(((void*)0), ","); } return ret; }
534
535#define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(size)int argconfig_parse_comma_sep_array_usize(char *string, __usize
*val, unsigned int max_length) { int ret = 0; uintmax_t v; char
*tmp; char *p; if (is_null_or_empty(string)) return 0; tmp =
strtok(string, ","); while (tmp) { if (ret >= max_length)
return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > UINTsize_MAX) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
\
536 DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(_u ## size, __u ## size, \int argconfig_parse_comma_sep_array_u ## size(char *string, __u
## size *val, unsigned int max_length) { int ret = 0; uintmax_t
v; char *tmp; char *p; if (is_null_or_empty(string)) return 0
; tmp = strtok(string, ","); while (tmp) { if (ret >= max_length
) return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > UINT ## size ## _MAX) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
537 UINT ## size ## _MAX)int argconfig_parse_comma_sep_array_u ## size(char *string, __u
## size *val, unsigned int max_length) { int ret = 0; uintmax_t
v; char *tmp; char *p; if (is_null_or_empty(string)) return 0
; tmp = strtok(string, ","); while (tmp) { if (ret >= max_length
) return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > UINT ## size ## _MAX) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
538
539DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(16)int argconfig_parse_comma_sep_array_u16(char *string, __u16 *
val, unsigned int max_length) { int ret = 0; uintmax_t v; char
*tmp; char *p; if (is_null_or_empty(string)) return 0; tmp =
strtok(string, ","); while (tmp) { if (ret >= max_length)
return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > (65535)) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
;
540DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(32)int argconfig_parse_comma_sep_array_u32(char *string, __u32 *
val, unsigned int max_length) { int ret = 0; uintmax_t v; char
*tmp; char *p; if (is_null_or_empty(string)) return 0; tmp =
strtok(string, ","); while (tmp) { if (ret >= max_length)
return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > (4294967295U)) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
;
541DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(64)int argconfig_parse_comma_sep_array_u64(char *string, __u64 *
val, unsigned int max_length) { int ret = 0; uintmax_t v; char
*tmp; char *p; if (is_null_or_empty(string)) return 0; tmp =
strtok(string, ","); while (tmp) { if (ret >= max_length)
return -1; v = strtoumax(tmp, &p, 0); if (*p != 0) return
-1; if (v > (18446744073709551615UL)) { fprintf(stderr, "%s out of range\n"
, tmp); return -1; } val[ret] = v; ret++; tmp = strtok(((void
*)0), ","); } return ret; }
;
542
543bool_Bool argconfig_parse_seen(struct argconfig_commandline_options *s,
544 const char *option)
545{
546 for (; s && s->option; s++) {
547 if (!strcmp(s->option, option))
548 return s->seen;
549 }
550
551 return false0;
552}