Remove unused ARGPAR_PRINTF_FORMAT macro
[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
fc07e526
SM
27/*
28 * An argpar iterator.
29 *
2af370d0
PP
30 * Such a structure contains the state of an iterator between calls to
31 * argpar_iter_next().
fc07e526
SM
32 */
33struct argpar_iter {
34 /*
35 * Data provided by the user to argpar_iter_create(); immutable
36 * afterwards.
37 */
64875a48
PP
38 struct {
39 unsigned int argc;
40 const char * const *argv;
41 const struct argpar_opt_descr *descrs;
42 } user;
fc07e526
SM
43
44 /*
45 * Index of the argument to process in the next
2af370d0 46 * argpar_iter_next() call.
fc07e526
SM
47 */
48 unsigned int i;
49
50 /* Counter of non-option arguments */
51 int non_opt_index;
52
53 /*
d7a82d7f
PP
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.
fc07e526 58 */
d7a82d7f 59 const char *short_opt_group_ch;
d1f7bbdb
PP
60
61 /* Temporary character buffer which only grows */
62 struct {
63 size_t size;
64 char *data;
65 } tmp_buf;
fc07e526
SM
66};
67
d4539a90
PP
68/* Base parsing item */
69struct argpar_item {
70 enum argpar_item_type type;
71};
72
73/* Option parsing item */
74struct 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 */
85struct 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
8b95d883
PP
104/* Parsing error */
105struct argpar_error {
106 /* Original argument index */
107 unsigned int orig_index;
7ac57709 108
8b95d883
PP
109 /* Name of unknown option; owned by this */
110 char *unknown_opt_name;
f46b5106 111
8b95d883
PP
112 /* Option descriptor */
113 const struct argpar_opt_descr *opt_descr;
7ac57709 114
8b95d883
PP
115 /* `true` if a short option caused the error */
116 bool is_short;
117};
7ac57709 118
d4539a90
PP
119ARGPAR_HIDDEN
120enum argpar_item_type argpar_item_type(const struct argpar_item * const item)
121{
122 ARGPAR_ASSERT(item);
123 return item->type;
124}
125
126ARGPAR_HIDDEN
127const 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
135ARGPAR_HIDDEN
136const 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
143ARGPAR_HIDDEN
144const 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
151ARGPAR_HIDDEN
152unsigned 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
160ARGPAR_HIDDEN
161unsigned 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
fc07e526
SM
169ARGPAR_HIDDEN
170void argpar_item_destroy(const struct argpar_item * const item)
903a5b8a
SM
171{
172 if (!item) {
173 goto end;
174 }
175
1c9a6bde 176 if (item->type == ARGPAR_ITEM_TYPE_OPT) {
fc07e526
SM
177 struct argpar_item_opt * const opt_item =
178 (struct argpar_item_opt *) item;
903a5b8a 179
d4539a90 180 free(opt_item->arg);
903a5b8a
SM
181 }
182
fc07e526 183 free((void *) item);
903a5b8a
SM
184
185end:
186 return;
187}
188
793f1620
PP
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 */
903a5b8a 195static
1c9a6bde
SM
196struct argpar_item_opt *create_opt_item(
197 const struct argpar_opt_descr * const descr,
903a5b8a
SM
198 const char * const arg)
199{
1c9a6bde 200 struct argpar_item_opt *opt_item =
fb12ac67 201 ARGPAR_ZALLOC(struct argpar_item_opt);
903a5b8a
SM
202
203 if (!opt_item) {
204 goto end;
205 }
206
1c9a6bde 207 opt_item->base.type = ARGPAR_ITEM_TYPE_OPT;
903a5b8a
SM
208 opt_item->descr = descr;
209
210 if (arg) {
7ac57709 211 opt_item->arg = strdup(arg);
903a5b8a
SM
212 if (!opt_item->arg) {
213 goto error;
214 }
215 }
216
217 goto end;
218
219error:
fc07e526 220 argpar_item_destroy(&opt_item->base);
903a5b8a
SM
221 opt_item = NULL;
222
223end:
224 return opt_item;
225}
226
793f1620
PP
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 */
903a5b8a 234static
1c9a6bde 235struct argpar_item_non_opt *create_non_opt_item(const char * const arg,
903a5b8a
SM
236 const unsigned int orig_index,
237 const unsigned int non_opt_index)
238{
1c9a6bde 239 struct argpar_item_non_opt * const non_opt_item =
fb12ac67 240 ARGPAR_ZALLOC(struct argpar_item_non_opt);
903a5b8a
SM
241
242 if (!non_opt_item) {
243 goto end;
244 }
245
1c9a6bde 246 non_opt_item->base.type = ARGPAR_ITEM_TYPE_NON_OPT;
903a5b8a
SM
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
251end:
252 return non_opt_item;
253}
254
8b95d883
PP
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 */
266static
267int 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,
c530e1dc 285 strlen(unknown_opt_name) + 1 + (is_short ? 1 : 2));
8b95d883
PP
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
303error:
304 argpar_error_destroy(*error);
305 ret = -1;
306
307end:
308 return ret;
309}
310
311ARGPAR_HIDDEN
312unsigned int argpar_error_orig_index(const struct argpar_error * const error)
313{
314 ARGPAR_ASSERT(error);
315 return error->orig_index;
316}
317
318ARGPAR_HIDDEN
319const 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
327ARGPAR_HIDDEN
328const 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
341ARGPAR_HIDDEN
342void 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
793f1620
PP
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 */
903a5b8a 361static
1c9a6bde
SM
362const struct argpar_opt_descr *find_descr(
363 const struct argpar_opt_descr * const descrs,
903a5b8a
SM
364 const char short_name, const char * const long_name)
365{
1c9a6bde 366 const struct argpar_opt_descr *descr;
903a5b8a
SM
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
380end:
381 return !descr->short_name && !descr->long_name ? NULL : descr;
382}
383
793f1620 384/* Return type of parse_short_opt_group() and parse_long_opt() */
903a5b8a
SM
385enum parse_orig_arg_opt_ret {
386 PARSE_ORIG_ARG_OPT_RET_OK,
871eba32
PP
387 PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT = -1,
388 PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG = -2,
871eba32
PP
389 PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG = -4,
390 PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -5,
903a5b8a
SM
391};
392
793f1620
PP
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 */
903a5b8a 402static
d7a82d7f
PP
403enum parse_orig_arg_opt_ret parse_short_opt_group(
404 const char * const short_opt_group,
903a5b8a 405 const char * const next_orig_arg,
1c9a6bde 406 const struct argpar_opt_descr * const descrs,
fc07e526 407 struct argpar_iter * const iter,
8b95d883
PP
408 struct argpar_error ** const error,
409 struct argpar_item ** const item)
903a5b8a
SM
410{
411 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
fc07e526
SM
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;
903a5b8a 416
d7a82d7f 417 ARGPAR_ASSERT(strlen(short_opt_group) != 0);
903a5b8a 418
d7a82d7f
PP
419 if (!iter->short_opt_group_ch) {
420 iter->short_opt_group_ch = short_opt_group;
fc07e526 421 }
903a5b8a 422
fc07e526 423 /* Find corresponding option descriptor */
d7a82d7f 424 descr = find_descr(descrs, *iter->short_opt_group_ch, NULL);
fc07e526 425 if (!descr) {
8b95d883
PP
426 const char unknown_opt_name[] =
427 {*iter->short_opt_group_ch, '\0'};
428
871eba32 429 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
8b95d883
PP
430
431 if (set_error(error, unknown_opt_name, NULL, true)) {
432 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
433 }
434
fc07e526
SM
435 goto error;
436 }
903a5b8a 437
fc07e526 438 if (descr->with_arg) {
d7a82d7f 439 if (iter->short_opt_group_ch[1]) {
fc07e526 440 /* `-oarg` form */
d7a82d7f 441 opt_arg = &iter->short_opt_group_ch[1];
fc07e526
SM
442 } else {
443 /* `-o arg` form */
444 opt_arg = next_orig_arg;
445 used_next_orig_arg = true;
903a5b8a
SM
446 }
447
fc07e526
SM
448 /*
449 * We accept `-o ''` (empty option argument), but not
450 * `-o` alone if an option argument is expected.
451 */
d7a82d7f 452 if (!opt_arg || (iter->short_opt_group_ch[1] &&
fb12ac67 453 strlen(opt_arg) == 0)) {
871eba32 454 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG;
8b95d883
PP
455
456 if (set_error(error, NULL, descr, true)) {
457 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
458 }
459
903a5b8a
SM
460 goto error;
461 }
fc07e526 462 }
903a5b8a 463
fc07e526
SM
464 /* Create and append option argument */
465 opt_item = create_opt_item(descr, opt_arg);
466 if (!opt_item) {
871eba32 467 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
fc07e526
SM
468 goto error;
469 }
903a5b8a 470
fc07e526 471 *item = &opt_item->base;
d7a82d7f 472 iter->short_opt_group_ch++;
903a5b8a 473
d7a82d7f 474 if (descr->with_arg || !*iter->short_opt_group_ch) {
fc07e526 475 /* Option has an argument: no more options */
d7a82d7f 476 iter->short_opt_group_ch = NULL;
fc07e526
SM
477
478 if (used_next_orig_arg) {
479 iter->i += 2;
480 } else {
481 iter->i++;
482 }
903a5b8a
SM
483 }
484
485 goto end;
486
487error:
871eba32 488 ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK);
903a5b8a
SM
489
490end:
491 return ret;
492}
493
793f1620
PP
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 */
903a5b8a
SM
502static
503enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg,
504 const char * const next_orig_arg,
1c9a6bde 505 const struct argpar_opt_descr * const descrs,
fc07e526 506 struct argpar_iter * const iter,
8b95d883
PP
507 struct argpar_error ** const error,
508 struct argpar_item ** const item)
903a5b8a 509{
903a5b8a 510 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
1c9a6bde
SM
511 const struct argpar_opt_descr *descr;
512 struct argpar_item_opt *opt_item;
fc07e526 513 bool used_next_orig_arg = false;
903a5b8a
SM
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
903a5b8a
SM
521 /* Option name */
522 const char *long_opt_name = long_opt_arg;
523
dd757a65 524 ARGPAR_ASSERT(strlen(long_opt_arg) != 0);
903a5b8a
SM
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 */
d1f7bbdb
PP
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 }
903a5b8a
SM
540 }
541
d1f7bbdb
PP
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;
903a5b8a
SM
545 }
546
547 /* Find corresponding option descriptor */
548 descr = find_descr(descrs, '\0', long_opt_name);
549 if (!descr) {
903a5b8a 550 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
8b95d883
PP
551
552 if (set_error(error, long_opt_name, NULL, false)) {
553 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
554 }
555
903a5b8a
SM
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) {
871eba32 567 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG;
8b95d883
PP
568
569 if (set_error(error, NULL, descr, false)) {
570 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
571 }
572
903a5b8a
SM
573 goto error;
574 }
575
576 opt_arg = next_orig_arg;
fc07e526 577 used_next_orig_arg = true;
903a5b8a 578 }
430fe886
SM
579 } else if (eq_pos) {
580 /*
581 * Unexpected `--opt=arg` style for a long option which
582 * doesn't accept an argument.
583 */
871eba32 584 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG;
8b95d883
PP
585
586 if (set_error(error, NULL, descr, false)) {
587 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
588 }
589
430fe886 590 goto error;
903a5b8a
SM
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
fc07e526
SM
599 if (used_next_orig_arg) {
600 iter->i += 2;
601 } else {
602 iter->i++;
7ac57709
SM
603 }
604
fc07e526 605 *item = &opt_item->base;
903a5b8a
SM
606 goto end;
607
608error:
871eba32 609 ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK);
903a5b8a
SM
610
611end:
612 return ret;
613}
614
793f1620
PP
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 */
903a5b8a
SM
623static
624enum parse_orig_arg_opt_ret parse_orig_arg_opt(const char * const orig_arg,
625 const char * const next_orig_arg,
1c9a6bde 626 const struct argpar_opt_descr * const descrs,
8b95d883
PP
627 struct argpar_iter * const iter,
628 struct argpar_error ** const error,
fc07e526 629 struct argpar_item ** const item)
903a5b8a
SM
630{
631 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
632
7ac57709 633 ARGPAR_ASSERT(orig_arg[0] == '-');
903a5b8a
SM
634
635 if (orig_arg[1] == '-') {
636 /* Long option */
637 ret = parse_long_opt(&orig_arg[2],
fc07e526 638 next_orig_arg, descrs, iter, error, item);
903a5b8a
SM
639 } else {
640 /* Short option */
d7a82d7f 641 ret = parse_short_opt_group(&orig_arg[1],
fc07e526 642 next_orig_arg, descrs, iter, error, item);
903a5b8a
SM
643 }
644
645 return ret;
646}
647
7ac57709 648ARGPAR_HIDDEN
fc07e526
SM
649struct argpar_iter *argpar_iter_create(const unsigned int argc,
650 const char * const * const argv,
651 const struct argpar_opt_descr * const descrs)
903a5b8a 652{
d1f7bbdb 653 struct argpar_iter *iter = ARGPAR_ZALLOC(struct argpar_iter);
903a5b8a 654
fc07e526
SM
655 if (!iter) {
656 goto end;
903a5b8a
SM
657 }
658
64875a48
PP
659 iter->user.argc = argc;
660 iter->user.argv = argv;
661 iter->user.descrs = descrs;
d1f7bbdb
PP
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 }
903a5b8a 669
fc07e526
SM
670end:
671 return iter;
672}
903a5b8a 673
fc07e526
SM
674ARGPAR_HIDDEN
675void argpar_iter_destroy(struct argpar_iter * const iter)
676{
d1f7bbdb
PP
677 if (iter) {
678 free(iter->tmp_buf.data);
679 free(iter);
680 }
fc07e526 681}
903a5b8a 682
fc07e526 683ARGPAR_HIDDEN
2af370d0 684enum argpar_iter_next_status argpar_iter_next(
fc07e526 685 struct argpar_iter * const iter,
8b95d883
PP
686 const struct argpar_item ** const item,
687 const struct argpar_error ** const error)
fc07e526 688{
2af370d0 689 enum argpar_iter_next_status status;
fc07e526
SM
690 enum parse_orig_arg_opt_ret parse_orig_arg_opt_ret;
691 const char *orig_arg;
692 const char *next_orig_arg;
8b95d883 693 struct argpar_error ** const nc_error = (struct argpar_error **) error;
7ac57709 694
64875a48 695 ARGPAR_ASSERT(iter->i <= iter->user.argc);
37bb2b1f
PP
696
697 if (error) {
8b95d883 698 *nc_error = NULL;
37bb2b1f 699 }
fc07e526 700
64875a48 701 if (iter->i == iter->user.argc) {
2af370d0 702 status = ARGPAR_ITER_NEXT_STATUS_END;
fc07e526
SM
703 goto end;
704 }
7ac57709 705
64875a48 706 orig_arg = iter->user.argv[iter->i];
fc07e526 707 next_orig_arg =
64875a48
PP
708 iter->i < (iter->user.argc - 1) ?
709 iter->user.argv[iter->i + 1] : NULL;
fc07e526 710
dd757a65
PP
711 if (strcmp(orig_arg, "-") == 0 || strcmp(orig_arg, "--") == 0 ||
712 orig_arg[0] != '-') {
fc07e526 713 /* Non-option argument */
dd757a65 714 const struct argpar_item_non_opt * const non_opt_item =
fc07e526
SM
715 create_non_opt_item(orig_arg, iter->i,
716 iter->non_opt_index);
717
718 if (!non_opt_item) {
2af370d0 719 status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY;
fc07e526 720 goto end;
903a5b8a
SM
721 }
722
fc07e526
SM
723 iter->non_opt_index++;
724 iter->i++;
725 *item = &non_opt_item->base;
2af370d0 726 status = ARGPAR_ITER_NEXT_STATUS_OK;
fc07e526
SM
727 goto end;
728 }
903a5b8a 729
fc07e526
SM
730 /* Option argument */
731 parse_orig_arg_opt_ret = parse_orig_arg_opt(orig_arg,
64875a48 732 next_orig_arg, iter->user.descrs, iter, nc_error,
fc07e526
SM
733 (struct argpar_item **) item);
734 switch (parse_orig_arg_opt_ret) {
735 case PARSE_ORIG_ARG_OPT_RET_OK:
2af370d0 736 status = ARGPAR_ITER_NEXT_STATUS_OK;
fc07e526
SM
737 break;
738 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT:
871eba32 739 case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG:
871eba32 740 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG:
8b95d883
PP
741 if (error) {
742 ARGPAR_ASSERT(*error);
743 (*nc_error)->orig_index = iter->i;
744 }
d4d05805
PP
745
746 switch (parse_orig_arg_opt_ret) {
747 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT:
2af370d0 748 status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNKNOWN_OPT;
d4d05805
PP
749 break;
750 case PARSE_ORIG_ARG_OPT_RET_ERROR_MISSING_OPT_ARG:
2af370d0 751 status = ARGPAR_ITER_NEXT_STATUS_ERROR_MISSING_OPT_ARG;
d4d05805 752 break;
d4d05805 753 case PARSE_ORIG_ARG_OPT_RET_ERROR_UNEXPECTED_OPT_ARG:
2af370d0 754 status = ARGPAR_ITER_NEXT_STATUS_ERROR_UNEXPECTED_OPT_ARG;
d4d05805
PP
755 break;
756 default:
757 abort();
758 }
759
760 break;
761 case PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY:
2af370d0 762 status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY;
fc07e526
SM
763 break;
764 default:
765 abort();
766 }
767
768end:
769 return status;
770}
771
772ARGPAR_HIDDEN
f3ab5ca1 773unsigned int argpar_iter_ingested_orig_args(
fc07e526
SM
774 const struct argpar_iter * const iter)
775{
776 return iter->i;
777}
This page took 0.095409 seconds and 4 git commands to generate.