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