argpar/argpar.{c,h}: fix coding style
[argpar.git] / argpar / argpar.c
CommitLineData
903a5b8a 1/*
03e1579f 2 * SPDX-License-Identifier: MIT
903a5b8a 3 *
fc07e526
SM
4 * Copyright (c) 2019-2021 Philippe Proulx <pproulx@efficios.com>
5 * Copyright (c) 2020-2021 Simon Marchi <simon.marchi@efficios.com>
903a5b8a
SM
6 */
7
7ac57709
SM
8#include <assert.h>
9#include <stdarg.h>
903a5b8a 10#include <stdbool.h>
7ac57709 11#include <stdio.h>
903a5b8a
SM
12#include <stdlib.h>
13#include <string.h>
903a5b8a
SM
14
15#include "argpar.h"
16
fb12ac67
PP
17#define ARGPAR_REALLOC(_ptr, _type, _nmemb) \
18 ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type)))
19
20#define ARGPAR_CALLOC(_type, _nmemb) \
21 ((_type *) calloc((_nmemb), sizeof(_type)))
22
23#define ARGPAR_ZALLOC(_type) ARGPAR_CALLOC(_type, 1)
7ac57709
SM
24
25#define ARGPAR_ASSERT(_cond) assert(_cond)
26
1ae22b5e
SM
27#ifdef __MINGW_PRINTF_FORMAT
28# define ARGPAR_PRINTF_FORMAT __MINGW_PRINTF_FORMAT
29#else
30# define ARGPAR_PRINTF_FORMAT printf
31#endif
32
fc07e526
SM
33/*
34 * An argpar iterator.
35 *
36 * Such a structure contains the state of an iterator between
37 * calls to argpar_iter_parse_next().
38 */
39struct argpar_iter {
40 /*
41 * Data provided by the user to argpar_iter_create(); immutable
42 * afterwards.
43 */
44 unsigned int argc;
45 const char * const *argv;
46 const struct argpar_opt_descr *descrs;
47
48 /*
49 * Index of the argument to process in the next
50 * argpar_iter_parse_next() call.
51 */
52 unsigned int i;
53
54 /* Counter of non-option arguments */
55 int non_opt_index;
56
57 /*
58 * Current character of the current short option group: if it's
59 * not `NULL`, the parser is in within a short option group,
60 * therefore it must resume there in the next
61 * argpar_iter_parse_next() call.
62 */
63 const char *short_opt_ch;
64};
65
1ae22b5e 66static __attribute__((format(ARGPAR_PRINTF_FORMAT, 1, 0)))
fb12ac67 67char *argpar_vasprintf(const char * const fmt, va_list args)
7ac57709
SM
68{
69 int len1, len2;
70 char *str;
71 va_list args2;
72
73 va_copy(args2, args);
7ac57709
SM
74 len1 = vsnprintf(NULL, 0, fmt, args);
75 if (len1 < 0) {
76 str = NULL;
77 goto end;
78 }
79
80 str = malloc(len1 + 1);
81 if (!str) {
82 goto end;
83 }
84
85 len2 = vsnprintf(str, len1 + 1, fmt, args2);
7ac57709
SM
86 ARGPAR_ASSERT(len1 == len2);
87
88end:
92ecd98e 89 va_end(args2);
7ac57709
SM
90 return str;
91}
92
93
1ae22b5e 94static __attribute__((format(ARGPAR_PRINTF_FORMAT, 1, 2)))
fb12ac67 95char *argpar_asprintf(const char * const fmt, ...)
7ac57709
SM
96{
97 va_list args;
98 char *str;
f46b5106 99
7ac57709
SM
100 va_start(args, fmt);
101 str = argpar_vasprintf(fmt, args);
102 va_end(args);
7ac57709
SM
103 return str;
104}
105
1ae22b5e 106static __attribute__((format(ARGPAR_PRINTF_FORMAT, 2, 3)))
fb12ac67 107bool append_string_printf(char ** const str, const char *fmt, ...)
7ac57709
SM
108{
109 char *new_str = NULL;
110 char *addendum;
111 bool success;
112 va_list args;
113
114 ARGPAR_ASSERT(str);
7ac57709
SM
115 va_start(args, fmt);
116 addendum = argpar_vasprintf(fmt, args);
117 va_end(args);
118
119 if (!addendum) {
120 success = false;
121 goto end;
122 }
123
124 new_str = argpar_asprintf("%s%s", *str ? *str : "", addendum);
125 if (!new_str) {
126 success = false;
127 goto end;
128 }
f46b5106 129
7ac57709
SM
130 free(*str);
131 *str = new_str;
7ac57709
SM
132 success = true;
133
134end:
135 free(addendum);
7ac57709
SM
136 return success;
137}
138
fc07e526
SM
139ARGPAR_HIDDEN
140void argpar_item_destroy(const struct argpar_item * const item)
903a5b8a
SM
141{
142 if (!item) {
143 goto end;
144 }
145
1c9a6bde 146 if (item->type == ARGPAR_ITEM_TYPE_OPT) {
fc07e526
SM
147 struct argpar_item_opt * const opt_item =
148 (struct argpar_item_opt *) item;
903a5b8a 149
7ac57709 150 free((void *) opt_item->arg);
903a5b8a
SM
151 }
152
fc07e526 153 free((void *) item);
903a5b8a
SM
154
155end:
156 return;
157}
158
7ac57709 159static
1c9a6bde 160bool push_item(struct argpar_item_array * const array,
fb12ac67 161 const struct argpar_item * const item)
7ac57709
SM
162{
163 bool success;
164
165 ARGPAR_ASSERT(array);
166 ARGPAR_ASSERT(item);
167
168 if (array->n_items == array->n_alloc) {
fb12ac67
PP
169 const unsigned int new_n_alloc = array->n_alloc * 2;
170 const struct argpar_item ** const new_items =
171 ARGPAR_REALLOC(array->items, const struct argpar_item *,
172 new_n_alloc);
7ac57709
SM
173 if (!new_items) {
174 success = false;
175 goto end;
176 }
177
178 array->n_alloc = new_n_alloc;
179 array->items = new_items;
180 }
181
182 array->items[array->n_items] = item;
183 array->n_items++;
7ac57709
SM
184 success = true;
185
186end:
187 return success;
188}
189
190static
1c9a6bde 191void destroy_item_array(struct argpar_item_array * const array)
7ac57709
SM
192{
193 if (array) {
194 unsigned int i;
195
196 for (i = 0; i < array->n_items; i++) {
fc07e526 197 argpar_item_destroy(array->items[i]);
7ac57709
SM
198 }
199
200 free(array->items);
201 free(array);
202 }
203}
204
205static
fb12ac67 206struct argpar_item_array *create_item_array(void)
7ac57709 207{
1c9a6bde 208 struct argpar_item_array *ret;
7ac57709
SM
209 const int initial_size = 10;
210
fb12ac67 211 ret = ARGPAR_ZALLOC(struct argpar_item_array);
7ac57709
SM
212 if (!ret) {
213 goto end;
214 }
215
fb12ac67 216 ret->items = ARGPAR_CALLOC(const struct argpar_item *, initial_size);
7ac57709
SM
217 if (!ret->items) {
218 goto error;
219 }
220
221 ret->n_alloc = initial_size;
7ac57709
SM
222 goto end;
223
224error:
225 destroy_item_array(ret);
226 ret = NULL;
227
228end:
229 return ret;
230}
231
903a5b8a 232static
1c9a6bde
SM
233struct argpar_item_opt *create_opt_item(
234 const struct argpar_opt_descr * const descr,
903a5b8a
SM
235 const char * const arg)
236{
1c9a6bde 237 struct argpar_item_opt *opt_item =
fb12ac67 238 ARGPAR_ZALLOC(struct argpar_item_opt);
903a5b8a
SM
239
240 if (!opt_item) {
241 goto end;
242 }
243
1c9a6bde 244 opt_item->base.type = ARGPAR_ITEM_TYPE_OPT;
903a5b8a
SM
245 opt_item->descr = descr;
246
247 if (arg) {
7ac57709 248 opt_item->arg = strdup(arg);
903a5b8a
SM
249 if (!opt_item->arg) {
250 goto error;
251 }
252 }
253
254 goto end;
255
256error:
fc07e526 257 argpar_item_destroy(&opt_item->base);
903a5b8a
SM
258 opt_item = NULL;
259
260end:
261 return opt_item;
262}
263
264static
1c9a6bde 265struct argpar_item_non_opt *create_non_opt_item(const char * const arg,
903a5b8a
SM
266 const unsigned int orig_index,
267 const unsigned int non_opt_index)
268{
1c9a6bde 269 struct argpar_item_non_opt * const non_opt_item =
fb12ac67 270 ARGPAR_ZALLOC(struct argpar_item_non_opt);
903a5b8a
SM
271
272 if (!non_opt_item) {
273 goto end;
274 }
275
1c9a6bde 276 non_opt_item->base.type = ARGPAR_ITEM_TYPE_NON_OPT;
903a5b8a
SM
277 non_opt_item->arg = arg;
278 non_opt_item->orig_index = orig_index;
279 non_opt_item->non_opt_index = non_opt_index;
280
281end:
282 return non_opt_item;
283}
284
285static
1c9a6bde
SM
286const struct argpar_opt_descr *find_descr(
287 const struct argpar_opt_descr * const descrs,
903a5b8a
SM
288 const char short_name, const char * const long_name)
289{
1c9a6bde 290 const struct argpar_opt_descr *descr;
903a5b8a
SM
291
292 for (descr = descrs; descr->short_name || descr->long_name; descr++) {
293 if (short_name && descr->short_name &&
294 short_name == descr->short_name) {
295 goto end;
296 }
297
298 if (long_name && descr->long_name &&
299 strcmp(long_name, descr->long_name) == 0) {
300 goto end;
301 }
302 }
303
304end:
305 return !descr->short_name && !descr->long_name ? NULL : descr;
306}
307
308enum parse_orig_arg_opt_ret {
309 PARSE_ORIG_ARG_OPT_RET_OK,
310 PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT = -2,
311 PARSE_ORIG_ARG_OPT_RET_ERROR = -1,
312};
313
314static
315enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts,
316 const char * const next_orig_arg,
1c9a6bde 317 const struct argpar_opt_descr * const descrs,
fc07e526
SM
318 struct argpar_iter * const iter,
319 char ** const error, struct argpar_item ** const item)
903a5b8a
SM
320{
321 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
fc07e526
SM
322 bool used_next_orig_arg = false;
323 const char *opt_arg = NULL;
324 const struct argpar_opt_descr *descr;
325 struct argpar_item_opt *opt_item;
903a5b8a
SM
326
327 if (strlen(short_opts) == 0) {
fb12ac67 328 append_string_printf(error, "Invalid argument");
903a5b8a
SM
329 goto error;
330 }
331
fc07e526
SM
332 if (!iter->short_opt_ch) {
333 iter->short_opt_ch = short_opts;
334 }
903a5b8a 335
fc07e526
SM
336 /* Find corresponding option descriptor */
337 descr = find_descr(descrs, *iter->short_opt_ch, NULL);
338 if (!descr) {
339 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
fb12ac67
PP
340 append_string_printf(error, "Unknown option `-%c`",
341 *iter->short_opt_ch);
fc07e526
SM
342 goto error;
343 }
903a5b8a 344
fc07e526
SM
345 if (descr->with_arg) {
346 if (iter->short_opt_ch[1]) {
347 /* `-oarg` form */
348 opt_arg = &iter->short_opt_ch[1];
349 } else {
350 /* `-o arg` form */
351 opt_arg = next_orig_arg;
352 used_next_orig_arg = true;
903a5b8a
SM
353 }
354
fc07e526
SM
355 /*
356 * We accept `-o ''` (empty option argument), but not
357 * `-o` alone if an option argument is expected.
358 */
fb12ac67
PP
359 if (!opt_arg || (iter->short_opt_ch[1] &&
360 strlen(opt_arg) == 0)) {
361 append_string_printf(error,
fc07e526
SM
362 "Missing required argument for option `-%c`",
363 *iter->short_opt_ch);
364 used_next_orig_arg = false;
903a5b8a
SM
365 goto error;
366 }
fc07e526 367 }
903a5b8a 368
fc07e526
SM
369 /* Create and append option argument */
370 opt_item = create_opt_item(descr, opt_arg);
371 if (!opt_item) {
372 goto error;
373 }
903a5b8a 374
fc07e526
SM
375 *item = &opt_item->base;
376 iter->short_opt_ch++;
903a5b8a 377
fc07e526
SM
378 if (descr->with_arg || !*iter->short_opt_ch) {
379 /* Option has an argument: no more options */
380 iter->short_opt_ch = NULL;
381
382 if (used_next_orig_arg) {
383 iter->i += 2;
384 } else {
385 iter->i++;
386 }
903a5b8a
SM
387 }
388
389 goto end;
390
391error:
392 if (ret == PARSE_ORIG_ARG_OPT_RET_OK) {
393 ret = PARSE_ORIG_ARG_OPT_RET_ERROR;
394 }
395
396end:
397 return ret;
398}
399
400static
401enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg,
402 const char * const next_orig_arg,
1c9a6bde 403 const struct argpar_opt_descr * const descrs,
fc07e526
SM
404 struct argpar_iter * const iter,
405 char ** const error, struct argpar_item ** const item)
903a5b8a
SM
406{
407 const size_t max_len = 127;
408 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
1c9a6bde
SM
409 const struct argpar_opt_descr *descr;
410 struct argpar_item_opt *opt_item;
fc07e526 411 bool used_next_orig_arg = false;
903a5b8a
SM
412
413 /* Option's argument, if any */
414 const char *opt_arg = NULL;
415
416 /* Position of first `=`, if any */
417 const char *eq_pos;
418
419 /* Buffer holding option name when `long_opt_arg` contains `=` */
420 char buf[max_len + 1];
421
422 /* Option name */
423 const char *long_opt_name = long_opt_arg;
424
425 if (strlen(long_opt_arg) == 0) {
fb12ac67 426 append_string_printf(error, "Invalid argument");
903a5b8a
SM
427 goto error;
428 }
429
430 /* Find the first `=` in original argument */
431 eq_pos = strchr(long_opt_arg, '=');
432 if (eq_pos) {
433 const size_t long_opt_name_size = eq_pos - long_opt_arg;
434
435 /* Isolate the option name */
436 if (long_opt_name_size > max_len) {
fb12ac67
PP
437 append_string_printf(error, "Invalid argument `--%s`",
438 long_opt_arg);
903a5b8a
SM
439 goto error;
440 }
441
442 memcpy(buf, long_opt_arg, long_opt_name_size);
443 buf[long_opt_name_size] = '\0';
444 long_opt_name = buf;
445 }
446
447 /* Find corresponding option descriptor */
448 descr = find_descr(descrs, '\0', long_opt_name);
449 if (!descr) {
fb12ac67
PP
450 append_string_printf(error, "Unknown option `--%s`",
451 long_opt_name);
903a5b8a
SM
452 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
453 goto error;
454 }
455
456 /* Find option's argument if any */
457 if (descr->with_arg) {
458 if (eq_pos) {
459 /* `--long-opt=arg` style */
460 opt_arg = eq_pos + 1;
461 } else {
462 /* `--long-opt arg` style */
463 if (!next_orig_arg) {
fb12ac67 464 append_string_printf(error,
903a5b8a
SM
465 "Missing required argument for option `--%s`",
466 long_opt_name);
467 goto error;
468 }
469
470 opt_arg = next_orig_arg;
fc07e526 471 used_next_orig_arg = true;
903a5b8a 472 }
430fe886
SM
473 } else if (eq_pos) {
474 /*
475 * Unexpected `--opt=arg` style for a long option which
476 * doesn't accept an argument.
477 */
fb12ac67 478 append_string_printf(error,
fc07e526 479 "Unexpected argument for option `--%s`", long_opt_name);
430fe886 480 goto error;
903a5b8a
SM
481 }
482
483 /* Create and append option argument */
484 opt_item = create_opt_item(descr, opt_arg);
485 if (!opt_item) {
486 goto error;
487 }
488
fc07e526
SM
489 if (used_next_orig_arg) {
490 iter->i += 2;
491 } else {
492 iter->i++;
7ac57709
SM
493 }
494
fc07e526 495 *item = &opt_item->base;
903a5b8a
SM
496 goto end;
497
498error:
499 if (ret == PARSE_ORIG_ARG_OPT_RET_OK) {
500 ret = PARSE_ORIG_ARG_OPT_RET_ERROR;
501 }
502
503end:
504 return ret;
505}
506
507static
508enum parse_orig_arg_opt_ret parse_orig_arg_opt(const char * const orig_arg,
509 const char * const next_orig_arg,
1c9a6bde 510 const struct argpar_opt_descr * const descrs,
fb12ac67 511 struct argpar_iter * const iter, char ** const error,
fc07e526 512 struct argpar_item ** const item)
903a5b8a
SM
513{
514 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
515
7ac57709 516 ARGPAR_ASSERT(orig_arg[0] == '-');
903a5b8a
SM
517
518 if (orig_arg[1] == '-') {
519 /* Long option */
520 ret = parse_long_opt(&orig_arg[2],
fc07e526 521 next_orig_arg, descrs, iter, error, item);
903a5b8a
SM
522 } else {
523 /* Short option */
524 ret = parse_short_opts(&orig_arg[1],
fc07e526 525 next_orig_arg, descrs, iter, error, item);
903a5b8a
SM
526 }
527
528 return ret;
529}
530
531static
fb12ac67 532bool prepend_while_parsing_arg_to_error(char ** const error,
903a5b8a
SM
533 const unsigned int i, const char * const arg)
534{
7ac57709
SM
535 char *new_error;
536 bool success;
903a5b8a 537
7ac57709
SM
538 ARGPAR_ASSERT(error);
539 ARGPAR_ASSERT(*error);
7ac57709
SM
540 new_error = argpar_asprintf("While parsing argument #%u (`%s`): %s",
541 i + 1, arg, *error);
542 if (!new_error) {
543 success = false;
903a5b8a
SM
544 goto end;
545 }
546
7ac57709
SM
547 free(*error);
548 *error = new_error;
549 success = true;
903a5b8a
SM
550
551end:
7ac57709 552 return success;
903a5b8a
SM
553}
554
7ac57709 555ARGPAR_HIDDEN
fc07e526
SM
556struct argpar_iter *argpar_iter_create(const unsigned int argc,
557 const char * const * const argv,
558 const struct argpar_opt_descr * const descrs)
903a5b8a 559{
fb12ac67 560 struct argpar_iter * const iter = ARGPAR_ZALLOC(struct argpar_iter);
903a5b8a 561
fc07e526
SM
562 if (!iter) {
563 goto end;
903a5b8a
SM
564 }
565
fc07e526
SM
566 iter->argc = argc;
567 iter->argv = argv;
568 iter->descrs = descrs;
903a5b8a 569
fc07e526
SM
570end:
571 return iter;
572}
903a5b8a 573
fc07e526
SM
574ARGPAR_HIDDEN
575void argpar_iter_destroy(struct argpar_iter * const iter)
576{
577 free(iter);
578}
903a5b8a 579
fc07e526
SM
580ARGPAR_HIDDEN
581enum argpar_iter_parse_next_status argpar_iter_parse_next(
582 struct argpar_iter * const iter,
fb12ac67 583 const struct argpar_item ** const item, char ** const error)
fc07e526
SM
584{
585 enum argpar_iter_parse_next_status status;
586 enum parse_orig_arg_opt_ret parse_orig_arg_opt_ret;
587 const char *orig_arg;
588 const char *next_orig_arg;
7ac57709 589
fc07e526
SM
590 ARGPAR_ASSERT(iter->i <= iter->argc);
591 *error = NULL;
592
593 if (iter->i == iter->argc) {
594 status = ARGPAR_ITER_PARSE_NEXT_STATUS_END;
595 goto end;
596 }
7ac57709 597
fc07e526
SM
598 orig_arg = iter->argv[iter->i];
599 next_orig_arg =
600 iter->i < (iter->argc - 1) ? iter->argv[iter->i + 1] : NULL;
601
602 if (orig_arg[0] != '-') {
603 /* Non-option argument */
604 struct argpar_item_non_opt * const non_opt_item =
605 create_non_opt_item(orig_arg, iter->i,
606 iter->non_opt_index);
607
608 if (!non_opt_item) {
609 status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR;
610 goto end;
903a5b8a
SM
611 }
612
fc07e526
SM
613 iter->non_opt_index++;
614 iter->i++;
615 *item = &non_opt_item->base;
616 status = ARGPAR_ITER_PARSE_NEXT_STATUS_OK;
617 goto end;
618 }
903a5b8a 619
fc07e526
SM
620 /* Option argument */
621 parse_orig_arg_opt_ret = parse_orig_arg_opt(orig_arg,
622 next_orig_arg, iter->descrs, iter, error,
623 (struct argpar_item **) item);
624 switch (parse_orig_arg_opt_ret) {
625 case PARSE_ORIG_ARG_OPT_RET_OK:
626 status = ARGPAR_ITER_PARSE_NEXT_STATUS_OK;
627 break;
628 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT:
629 prepend_while_parsing_arg_to_error(error, iter->i, orig_arg);
630 status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT;
631 break;
632 case PARSE_ORIG_ARG_OPT_RET_ERROR:
633 prepend_while_parsing_arg_to_error(error, iter->i, orig_arg);
634 status = ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR;
635 break;
636 default:
637 abort();
638 }
639
640end:
641 return status;
642}
643
644ARGPAR_HIDDEN
645unsigned int argpar_iter_get_ingested_orig_args(
646 const struct argpar_iter * const iter)
647{
648 return iter->i;
649}
650
651ARGPAR_HIDDEN
652struct argpar_parse_ret argpar_parse(const unsigned int argc,
653 const char * const * const argv,
654 const struct argpar_opt_descr * const descrs,
655 const bool fail_on_unknown_opt)
656{
657 struct argpar_parse_ret parse_ret = { 0 };
658 const struct argpar_item *item = NULL;
659 struct argpar_iter *iter = NULL;
660
fb12ac67 661 parse_ret.items = create_item_array();
fc07e526
SM
662 if (!parse_ret.items) {
663 parse_ret.error = strdup("Failed to create items array.");
664 ARGPAR_ASSERT(parse_ret.error);
665 goto error;
666 }
667
668 iter = argpar_iter_create(argc, argv, descrs);
669 if (!iter) {
670 parse_ret.error = strdup("Failed to create argpar iter.");
671 ARGPAR_ASSERT(parse_ret.error);
672 goto error;
673 }
674
675 while (true) {
fb12ac67
PP
676 const enum argpar_iter_parse_next_status status =
677 argpar_iter_parse_next(iter, &item, &parse_ret.error);
fc07e526 678
fc07e526
SM
679 if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR) {
680 goto error;
681 } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_END) {
682 break;
683 } else if (status == ARGPAR_ITER_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
903a5b8a 684 if (fail_on_unknown_opt) {
fc07e526
SM
685 parse_ret.ingested_orig_args =
686 argpar_iter_get_ingested_orig_args(iter);
903a5b8a
SM
687 goto error;
688 }
689
7ac57709 690 free(parse_ret.error);
903a5b8a 691 parse_ret.error = NULL;
fc07e526 692 break;
903a5b8a
SM
693 }
694
fc07e526
SM
695 ARGPAR_ASSERT(status == ARGPAR_ITER_PARSE_NEXT_STATUS_OK);
696
fb12ac67 697 if (!push_item(parse_ret.items, item)) {
fc07e526 698 goto error;
903a5b8a 699 }
fc07e526
SM
700
701 item = NULL;
903a5b8a
SM
702 }
703
fc07e526 704 ARGPAR_ASSERT(!parse_ret.error);
fb12ac67 705 parse_ret.ingested_orig_args = argpar_iter_get_ingested_orig_args(iter);
903a5b8a
SM
706 goto end;
707
708error:
fc07e526
SM
709 ARGPAR_ASSERT(parse_ret.error);
710
711 /* That's how we indicate that an error occurred */
7ac57709
SM
712 destroy_item_array(parse_ret.items);
713 parse_ret.items = NULL;
903a5b8a
SM
714
715end:
fc07e526
SM
716 argpar_iter_destroy(iter);
717 argpar_item_destroy(item);
903a5b8a
SM
718 return parse_ret;
719}
720
7ac57709 721ARGPAR_HIDDEN
fb12ac67 722void argpar_parse_ret_fini(struct argpar_parse_ret * const ret)
903a5b8a 723{
7ac57709 724 ARGPAR_ASSERT(ret);
7ac57709
SM
725 destroy_item_array(ret->items);
726 ret->items = NULL;
7ac57709
SM
727 free(ret->error);
728 ret->error = NULL;
903a5b8a 729}
This page took 0.052565 seconds and 4 git commands to generate.