55995124fb6332e5a4a3cf8296b55d55adfde3b2
[argpar.git] / argpar / argpar.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (c) 2019-2021 Philippe Proulx <pproulx@efficios.com>
5 * Copyright (c) 2020-2021 Simon Marchi <simon.marchi@efficios.com>
6 */
7
8 #include <assert.h>
9 #include <stdarg.h>
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "argpar.h"
16
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)
24
25 #define ARGPAR_ASSERT(_cond) assert(_cond)
26
27 /*
28 * An argpar iterator.
29 *
30 * Such a structure contains the state of an iterator between calls to
31 * argpar_iter_next().
32 */
33 struct argpar_iter {
34 /*
35 * Data provided by the user to argpar_iter_create(); immutable
36 * afterwards.
37 */
38 struct {
39 unsigned int argc;
40 const char * const *argv;
41 const struct argpar_opt_descr *descrs;
42 } user;
43
44 /*
45 * Index of the argument to process in the next
46 * argpar_iter_next() call.
47 */
48 unsigned int i;
49
50 /* Counter of non-option arguments */
51 int non_opt_index;
52
53 /*
54 * Current character within the current short option group: if
55 * it's not `NULL`, the parser is within a short option group,
56 * therefore it must resume there in the next argpar_iter_next()
57 * call.
58 */
59 const char *short_opt_group_ch;
60
61 /* Temporary character buffer which only grows */
62 struct {
63 size_t size;
64 char *data;
65 } tmp_buf;
66 };
67
68 /* Base parsing item */
69 struct argpar_item {
70 enum argpar_item_type type;
71 };
72
73 /* Option parsing item */
74 struct argpar_item_opt {
75 struct argpar_item base;
76
77 /* Corresponding descriptor */
78 const struct argpar_opt_descr *descr;
79
80 /* Argument, or `NULL` if none; owned by this */
81 char *arg;
82 };
83
84 /* Non-option parsing item */
85 struct argpar_item_non_opt {
86 struct argpar_item base;
87
88 /*
89 * Complete argument, pointing to one of the entries of the
90 * original arguments (`argv`).
91 */
92 const char *arg;
93
94 /*
95 * Index of this argument amongst all original arguments
96 * (`argv`).
97 */
98 unsigned int orig_index;
99
100 /* Index of this argument amongst other non-option arguments */
101 unsigned int non_opt_index;
102 };
103
104 /* Parsing error */
105 struct argpar_error {
106 /* Original argument index */
107 unsigned int orig_index;
108
109 /* Name of unknown option; owned by this */
110 char *unknown_opt_name;
111
112 /* Option descriptor */
113 const struct argpar_opt_descr *opt_descr;
114
115 /* `true` if a short option caused the error */
116 bool is_short;
117 };
118
119 ARGPAR_HIDDEN
120 enum argpar_item_type argpar_item_type(const struct argpar_item * const item)
121 {
122 ARGPAR_ASSERT(item);
123 return item->type;
124 }
125
126 ARGPAR_HIDDEN
127 const struct argpar_opt_descr *argpar_item_opt_descr(
128 const struct argpar_item * const item)
129 {
130 ARGPAR_ASSERT(item);
131 ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT);
132 return ((const struct argpar_item_opt *) item)->descr;
133 }
134
135 ARGPAR_HIDDEN
136 const char *argpar_item_opt_arg(const struct argpar_item * const item)
137 {
138 ARGPAR_ASSERT(item);
139 ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT);
140 return ((const struct argpar_item_opt *) item)->arg;
141 }
142
143 ARGPAR_HIDDEN
144 const char *argpar_item_non_opt_arg(const struct argpar_item * const item)
145 {
146 ARGPAR_ASSERT(item);
147 ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
148 return ((const struct argpar_item_non_opt *) item)->arg;
149 }
150
151 ARGPAR_HIDDEN
152 unsigned int argpar_item_non_opt_orig_index(
153 const struct argpar_item * const item)
154 {
155 ARGPAR_ASSERT(item);
156 ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
157 return ((const struct argpar_item_non_opt *) item)->orig_index;
158 }
159
160 ARGPAR_HIDDEN
161 unsigned int argpar_item_non_opt_non_opt_index(
162 const struct argpar_item * const item)
163 {
164 ARGPAR_ASSERT(item);
165 ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
166 return ((const struct argpar_item_non_opt *) item)->non_opt_index;
167 }
168
169 ARGPAR_HIDDEN
170 void argpar_item_destroy(const struct argpar_item * const item)
171 {
172 if (!item) {
173 goto end;
174 }
175
176 if (item->type == ARGPAR_ITEM_TYPE_OPT) {
177 struct argpar_item_opt * const opt_item =
178 (struct argpar_item_opt *) item;
179
180 free(opt_item->arg);
181 }
182
183 free((void *) item);
184
185 end:
186 return;
187 }
188
189 /*
190 * Creates and returns an option parsing item for the descriptor `descr`
191 * and having the argument `arg` (copied; may be `NULL`).
192 *
193 * Returns `NULL` on memory error.
194 */
195 static
196 struct argpar_item_opt *create_opt_item(
197 const struct argpar_opt_descr * const descr,
198 const char * const arg)
199 {
200 struct argpar_item_opt *opt_item =
201 ARGPAR_ZALLOC(struct argpar_item_opt);
202
203 if (!opt_item) {
204 goto end;
205 }
206
207 opt_item->base.type = ARGPAR_ITEM_TYPE_OPT;
208 opt_item->descr = descr;
209
210 if (arg) {
211 opt_item->arg = strdup(arg);
212 if (!opt_item->arg) {
213 goto error;
214 }
215 }
216
217 goto end;
218
219 error:
220 argpar_item_destroy(&opt_item->base);
221 opt_item = NULL;
222
223 end:
224 return opt_item;
225 }
226
227 /*
228 * Creates and returns a non-option parsing item for the original
229 * argument `arg` having the original index `orig_index` and the
230 * non-option index `non_opt_index`.
231 *
232 * Returns `NULL` on memory error.
233 */
234 static
235 struct argpar_item_non_opt *create_non_opt_item(const char * const arg,
236 const unsigned int orig_index,
237 const unsigned int non_opt_index)
238 {
239 struct argpar_item_non_opt * const non_opt_item =
240 ARGPAR_ZALLOC(struct argpar_item_non_opt);
241
242 if (!non_opt_item) {
243 goto end;
244 }
245
246 non_opt_item->base.type = ARGPAR_ITEM_TYPE_NON_OPT;
247 non_opt_item->arg = arg;
248 non_opt_item->orig_index = orig_index;
249 non_opt_item->non_opt_index = non_opt_index;
250
251 end:
252 return non_opt_item;
253 }
254
255 /*
256 * If `error` is not `NULL`, sets the error `error` to a new parsing
257 * error object, setting its `unknown_opt_name`, `opt_descr`, and
258 * `is_short` members from the parameters.
259 *
260 * `unknown_opt_name` is the unknown option name without any `-` or `--`
261 * prefix: `is_short` controls which type of unknown option it is.
262 *
263 * Returns 0 on success (including if `error` is `NULL`) or -1 on memory
264 * error.
265 */
266 static
267 int set_error(struct argpar_error ** const error,
268 const char * const unknown_opt_name,
269 const struct argpar_opt_descr * const opt_descr,
270 const bool is_short)
271 {
272 int ret = 0;
273
274 if (!error) {
275 goto end;
276 }
277
278 *error = ARGPAR_ZALLOC(struct argpar_error);
279 if (!*error) {
280 goto error;
281 }
282
283 if (unknown_opt_name) {
284 (*error)->unknown_opt_name = ARGPAR_CALLOC(char,
285 strlen(unknown_opt_name) + 1 + (is_short ? 1 : 2));
286 if (!(*error)->unknown_opt_name) {
287 goto error;
288 }
289
290 if (is_short) {
291 strcpy((*error)->unknown_opt_name, "-");
292 } else {
293 strcpy((*error)->unknown_opt_name, "--");
294 }
295
296 strcat((*error)->unknown_opt_name, unknown_opt_name);
297 }
298
299 (*error)->opt_descr = opt_descr;
300 (*error)->is_short = is_short;
301 goto end;
302
303 error:
304 argpar_error_destroy(*error);
305 ret = -1;
306
307 end:
308 return ret;
309 }
310
311 ARGPAR_HIDDEN
312 unsigned int argpar_error_orig_index(const struct argpar_error * const error)
313 {
314 ARGPAR_ASSERT(error);
315 return error->orig_index;
316 }
317
318 ARGPAR_HIDDEN
319 const char *argpar_error_unknown_opt_name(
320 const struct argpar_error * const error)
321 {
322 ARGPAR_ASSERT(error);
323 ARGPAR_ASSERT(error->unknown_opt_name);
324 return error->unknown_opt_name;
325 }
326
327 ARGPAR_HIDDEN
328 const struct argpar_opt_descr *argpar_error_opt_descr(
329 const struct argpar_error * const error, bool * const is_short)
330 {
331 ARGPAR_ASSERT(error);
332 ARGPAR_ASSERT(error->opt_descr);
333
334 if (is_short) {
335 *is_short = error->is_short;
336 }
337
338 return error->opt_descr;
339 }
340
341 ARGPAR_HIDDEN
342 void argpar_error_destroy(const struct argpar_error * const error)
343 {
344 if (error) {
345 free(error->unknown_opt_name);
346 free((void *) error);
347 }
348 }
349
350 /*
351 * Finds and returns the _first_ descriptor having the short option name
352 * `short_name` or the long option name `long_name` within the option
353 * descriptors `descrs`.
354 *
355 * `short_name` may be `'\0'` to not consider it.
356 *
357 * `long_name` may be `NULL` to not consider it.
358 *
359 * Returns `NULL` if no descriptor is found.
360 */
361 static
362 const struct argpar_opt_descr *find_descr(
363 const struct argpar_opt_descr * const descrs,
364 const char short_name, const char * const long_name)
365 {
366 const struct argpar_opt_descr *descr;
367
368 for (descr = descrs; descr->short_name || descr->long_name; descr++) {
369 if (short_name && descr->short_name &&
370 short_name == descr->short_name) {
371 goto end;
372 }
373
374 if (long_name && descr->long_name &&
375 strcmp(long_name, descr->long_name) == 0) {
376 goto end;
377 }
378 }
379
380 end:
381 return !descr->short_name && !descr->long_name ? NULL : descr;
382 }
383
384 /* Return type of parse_short_opt_group() and parse_long_opt() */
385 enum parse_orig_arg_opt_ret {
386 PARSE_ORIG_ARG_OPT_RET_OK,
387 PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT = -1,
388 PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG = -2,
389 PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG = -4,
390 PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -5,
391 };
392
393 /*
394 * Parses the short option group argument `short_opt_group`, starting
395 * where needed depending on the state of `iter`.
396 *
397 * On success, sets `*item`.
398 *
399 * On error (except for `PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY`), sets
400 * `*error`.
401 */
402 static
403 enum parse_orig_arg_opt_ret parse_short_opt_group(
404 const char * const short_opt_group,
405 const char * const next_orig_arg,
406 const struct argpar_opt_descr * const descrs,
407 struct argpar_iter * const iter,
408 struct argpar_error ** const error,
409 struct argpar_item ** const item)
410 {
411 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
412 bool used_next_orig_arg = false;
413 const char *opt_arg = NULL;
414 const struct argpar_opt_descr *descr;
415 struct argpar_item_opt *opt_item;
416
417 ARGPAR_ASSERT(strlen(short_opt_group) != 0);
418
419 if (!iter->short_opt_group_ch) {
420 iter->short_opt_group_ch = short_opt_group;
421 }
422
423 /* Find corresponding option descriptor */
424 descr = find_descr(descrs, *iter->short_opt_group_ch, NULL);
425 if (!descr) {
426 const char unknown_opt_name[] =
427 {*iter->short_opt_group_ch, '\0'};
428
429 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
430
431 if (set_error(error, unknown_opt_name, NULL, true)) {
432 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
433 }
434
435 goto error;
436 }
437
438 if (descr->with_arg) {
439 if (iter->short_opt_group_ch[1]) {
440 /* `-oarg` form */
441 opt_arg = &iter->short_opt_group_ch[1];
442 } else {
443 /* `-o arg` form */
444 opt_arg = next_orig_arg;
445 used_next_orig_arg = true;
446 }
447
448 /*
449 * We accept `-o ''` (empty option argument), but not
450 * `-o` alone if an option argument is expected.
451 */
452 if (!opt_arg || (iter->short_opt_group_ch[1] &&
453 strlen(opt_arg) == 0)) {
454 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG;
455
456 if (set_error(error, NULL, descr, true)) {
457 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
458 }
459
460 goto error;
461 }
462 }
463
464 /* Create and append option argument */
465 opt_item = create_opt_item(descr, opt_arg);
466 if (!opt_item) {
467 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
468 goto error;
469 }
470
471 *item = &opt_item->base;
472 iter->short_opt_group_ch++;
473
474 if (descr->with_arg || !*iter->short_opt_group_ch) {
475 /* Option has an argument: no more options */
476 iter->short_opt_group_ch = NULL;
477
478 if (used_next_orig_arg) {
479 iter->i += 2;
480 } else {
481 iter->i++;
482 }
483 }
484
485 goto end;
486
487 error:
488 ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK);
489
490 end:
491 return ret;
492 }
493
494 /*
495 * Parses the long option argument `long_opt_arg`.
496 *
497 * On success, sets `*item`.
498 *
499 * On error (except for `PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY`), sets
500 * `*error`.
501 */
502 static
503 enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg,
504 const char * const next_orig_arg,
505 const struct argpar_opt_descr * const descrs,
506 struct argpar_iter * const iter,
507 struct argpar_error ** const error,
508 struct argpar_item ** const item)
509 {
510 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
511 const struct argpar_opt_descr *descr;
512 struct argpar_item_opt *opt_item;
513 bool used_next_orig_arg = false;
514
515 /* Option's argument, if any */
516 const char *opt_arg = NULL;
517
518 /* Position of first `=`, if any */
519 const char *eq_pos;
520
521 /* Option name */
522 const char *long_opt_name = long_opt_arg;
523
524 ARGPAR_ASSERT(strlen(long_opt_arg) != 0);
525
526 /* Find the first `=` in original argument */
527 eq_pos = strchr(long_opt_arg, '=');
528 if (eq_pos) {
529 const size_t long_opt_name_size = eq_pos - long_opt_arg;
530
531 /* Isolate the option name */
532 while (long_opt_name_size > iter->tmp_buf.size - 1) {
533 iter->tmp_buf.size *= 2;
534 iter->tmp_buf.data = ARGPAR_REALLOC(iter->tmp_buf.data,
535 char, iter->tmp_buf.size);
536 if (!iter->tmp_buf.data) {
537 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
538 goto error;
539 }
540 }
541
542 memcpy(iter->tmp_buf.data, long_opt_arg, long_opt_name_size);
543 iter->tmp_buf.data[long_opt_name_size] = '\0';
544 long_opt_name = iter->tmp_buf.data;
545 }
546
547 /* Find corresponding option descriptor */
548 descr = find_descr(descrs, '\0', long_opt_name);
549 if (!descr) {
550 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
551
552 if (set_error(error, long_opt_name, NULL, false)) {
553 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
554 }
555
556 goto error;
557 }
558
559 /* Find option's argument if any */
560 if (descr->with_arg) {
561 if (eq_pos) {
562 /* `--long-opt=arg` style */
563 opt_arg = eq_pos + 1;
564 } else {
565 /* `--long-opt arg` style */
566 if (!next_orig_arg) {
567 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG;
568
569 if (set_error(error, NULL, descr, false)) {
570 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
571 }
572
573 goto error;
574 }
575
576 opt_arg = next_orig_arg;
577 used_next_orig_arg = true;
578 }
579 } else if (eq_pos) {
580 /*
581 * Unexpected `--opt=arg` style for a long option which
582 * doesn't accept an argument.
583 */
584 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG;
585
586 if (set_error(error, NULL, descr, false)) {
587 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
588 }
589
590 goto error;
591 }
592
593 /* Create and append option argument */
594 opt_item = create_opt_item(descr, opt_arg);
595 if (!opt_item) {
596 goto error;
597 }
598
599 if (used_next_orig_arg) {
600 iter->i += 2;
601 } else {
602 iter->i++;
603 }
604
605 *item = &opt_item->base;
606 goto end;
607
608 error:
609 ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK);
610
611 end:
612 return ret;
613 }
614
615 /*
616 * Parses the original argument `orig_arg`.
617 *
618 * On success, sets `*item`.
619 *
620 * On error (except for `PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY`), sets
621 * `*error`.
622 */
623 static
624 enum parse_orig_arg_opt_ret parse_orig_arg_opt(const char * const orig_arg,
625 const char * const next_orig_arg,
626 const struct argpar_opt_descr * const descrs,
627 struct argpar_iter * const iter,
628 struct argpar_error ** const error,
629 struct argpar_item ** const item)
630 {
631 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
632
633 ARGPAR_ASSERT(orig_arg[0] == '-');
634
635 if (orig_arg[1] == '-') {
636 /* Long option */
637 ret = parse_long_opt(&orig_arg[2],
638 next_orig_arg, descrs, iter, error, item);
639 } else {
640 /* Short option */
641 ret = parse_short_opt_group(&orig_arg[1],
642 next_orig_arg, descrs, iter, error, item);
643 }
644
645 return ret;
646 }
647
648 ARGPAR_HIDDEN
649 struct argpar_iter *argpar_iter_create(const unsigned int argc,
650 const char * const * const argv,
651 const struct argpar_opt_descr * const descrs)
652 {
653 struct argpar_iter *iter = ARGPAR_ZALLOC(struct argpar_iter);
654
655 if (!iter) {
656 goto end;
657 }
658
659 iter->user.argc = argc;
660 iter->user.argv = argv;
661 iter->user.descrs = descrs;
662 iter->tmp_buf.size = 128;
663 iter->tmp_buf.data = ARGPAR_CALLOC(char, iter->tmp_buf.size);
664 if (!iter->tmp_buf.data) {
665 argpar_iter_destroy(iter);
666 iter = NULL;
667 goto end;
668 }
669
670 end:
671 return iter;
672 }
673
674 ARGPAR_HIDDEN
675 void argpar_iter_destroy(struct argpar_iter * const iter)
676 {
677 if (iter) {
678 free(iter->tmp_buf.data);
679 free(iter);
680 }
681 }
682
683 ARGPAR_HIDDEN
684 enum argpar_iter_next_status argpar_iter_next(
685 struct argpar_iter * const iter,
686 const struct argpar_item ** const item,
687 const struct argpar_error ** const error)
688 {
689 enum argpar_iter_next_status status;
690 enum parse_orig_arg_opt_ret parse_orig_arg_opt_ret;
691 const char *orig_arg;
692 const char *next_orig_arg;
693 struct argpar_error ** const nc_error = (struct argpar_error **) error;
694
695 ARGPAR_ASSERT(iter->i <= iter->user.argc);
696
697 if (error) {
698 *nc_error = NULL;
699 }
700
701 if (iter->i == iter->user.argc) {
702 status = ARGPAR_ITER_NEXT_STATUS_END;
703 goto end;
704 }
705
706 orig_arg = iter->user.argv[iter->i];
707 next_orig_arg =
708 iter->i < (iter->user.argc - 1) ?
709 iter->user.argv[iter->i + 1] : NULL;
710
711 if (strcmp(orig_arg, "-") == 0 || strcmp(orig_arg, "--") == 0 ||
712 orig_arg[0] != '-') {
713 /* Non-option argument */
714 const struct argpar_item_non_opt * const non_opt_item =
715 create_non_opt_item(orig_arg, iter->i,
716 iter->non_opt_index);
717
718 if (!non_opt_item) {
719 status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY;
720 goto end;
721 }
722
723 iter->non_opt_index++;
724 iter->i++;
725 *item = &non_opt_item->base;
726 status = ARGPAR_ITER_NEXT_STATUS_OK;
727 goto end;
728 }
729
730 /* Option argument */
731 parse_orig_arg_opt_ret = parse_orig_arg_opt(orig_arg,
732 next_orig_arg, iter->user.descrs, iter, nc_error,
733 (struct argpar_item **) item);
734 switch (parse_orig_arg_opt_ret) {
735 case PARSE_ORIG_ARG_OPT_RET_OK:
736 status = ARGPAR_ITER_NEXT_STATUS_OK;
737 break;
738 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT:
739 case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG:
740 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG:
741 if (error) {
742 ARGPAR_ASSERT(*error);
743 (*nc_error)->orig_index = iter->i;
744 }
745
746 switch (parse_orig_arg_opt_ret) {
747 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT:
748 status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT;
749 break;
750 case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG:
751 status = ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG;
752 break;
753 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG:
754 status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG;
755 break;
756 default:
757 abort();
758 }
759
760 break;
761 case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY:
762 status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY;
763 break;
764 default:
765 abort();
766 }
767
768 end:
769 return status;
770 }
771
772 ARGPAR_HIDDEN
773 unsigned int argpar_iter_ingested_orig_args(
774 const struct argpar_iter * const iter)
775 {
776 return iter->i;
777 }
This page took 0.071908 seconds and 4 git commands to generate.