src/common: use single Makefile for parallel builds
[lttng-tools.git] / src / common / argpar / argpar.c
CommitLineData
e2fb96d8
SM
1/*
2 * SPDX-License-Identifier: MIT
3 *
d50d200a
SM
4 * Copyright (c) 2019-2021 Philippe Proulx <pproulx@efficios.com>
5 * Copyright (c) 2020-2021 Simon Marchi <simon.marchi@efficios.com>
e2fb96d8
SM
6 */
7
e2fb96d8
SM
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
d50d200a
SM
16#define ARGPAR_REALLOC(_ptr, _type, _nmemb) \
17 ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type)))
e2fb96d8 18
d50d200a
SM
19#define ARGPAR_CALLOC(_type, _nmemb) \
20 ((_type *) calloc((_nmemb), sizeof(_type)))
e2fb96d8 21
d50d200a
SM
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))
e2fb96d8 30#else
d50d200a
SM
31# include <assert.h>
32# define ARGPAR_ASSERT(_cond) assert(_cond)
e2fb96d8
SM
33#endif
34
4624dad0 35/*
d50d200a 36 * An argpar iterator.
4624dad0 37 *
d50d200a
SM
38 * Such a structure contains the state of an iterator between calls to
39 * argpar_iter_next().
4624dad0 40 */
d50d200a 41struct argpar_iter {
4624dad0 42 /*
d50d200a 43 * Data provided by the user to argpar_iter_create(); immutable
4624dad0
SM
44 * afterwards.
45 */
d50d200a
SM
46 struct {
47 unsigned int argc;
48 const char * const *argv;
49 const struct argpar_opt_descr *descrs;
50 } user;
4624dad0
SM
51
52 /*
d50d200a
SM
53 * Index of the argument to process in the next
54 * argpar_iter_next() call.
4624dad0
SM
55 */
56 unsigned int i;
57
d50d200a 58 /* Counter of non-option arguments */
4624dad0
SM
59 int non_opt_index;
60
61 /*
d50d200a
SM
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()
4624dad0
SM
65 * call.
66 */
d50d200a 67 const char *short_opt_group_ch;
4624dad0 68
d50d200a
SM
69 /* Temporary character buffer which only grows */
70 struct {
71 size_t size;
72 char *data;
73 } tmp_buf;
74};
e2fb96d8 75
d50d200a
SM
76/* Base parsing item */
77struct argpar_item {
78 enum argpar_item_type type;
79};
e2fb96d8 80
d50d200a
SM
81/* Option parsing item */
82struct argpar_item_opt {
83 struct argpar_item base;
e2fb96d8 84
d50d200a
SM
85 /* Corresponding descriptor */
86 const struct argpar_opt_descr *descr;
e2fb96d8 87
d50d200a
SM
88 /* Argument, or `NULL` if none; owned by this */
89 char *arg;
90};
e2fb96d8 91
d50d200a
SM
92/* Non-option parsing item */
93struct argpar_item_non_opt {
94 struct argpar_item base;
e2fb96d8 95
d50d200a
SM
96 /*
97 * Complete argument, pointing to one of the entries of the
98 * original arguments (`argv`).
99 */
100 const char *arg;
e2fb96d8 101
d50d200a
SM
102 /*
103 * Index of this argument amongst all original arguments
104 * (`argv`).
105 */
106 unsigned int orig_index;
e2fb96d8 107
d50d200a
SM
108 /* Index of this argument amongst other non-option arguments */
109 unsigned int non_opt_index;
110};
e2fb96d8 111
d50d200a
SM
112/* Parsing error */
113struct argpar_error {
114 /* Error type */
115 enum argpar_error_type type;
e2fb96d8 116
d50d200a
SM
117 /* Original argument index */
118 unsigned int orig_index;
e2fb96d8 119
d50d200a
SM
120 /* Name of unknown option; owned by this */
121 char *unknown_opt_name;
e2fb96d8 122
d50d200a
SM
123 /* Option descriptor */
124 const struct argpar_opt_descr *opt_descr;
e2fb96d8 125
d50d200a
SM
126 /* `true` if a short option caused the error */
127 bool is_short;
128};
e2fb96d8 129
d50d200a
SM
130ARGPAR_HIDDEN
131enum argpar_item_type argpar_item_type(const struct argpar_item * const item)
132{
133 ARGPAR_ASSERT(item);
134 return item->type;
e2fb96d8
SM
135}
136
4624dad0 137ARGPAR_HIDDEN
d50d200a
SM
138const struct argpar_opt_descr *argpar_item_opt_descr(
139 const struct argpar_item * const item)
e2fb96d8 140{
d50d200a
SM
141 ARGPAR_ASSERT(item);
142 ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT);
143 return ((const struct argpar_item_opt *) item)->descr;
e2fb96d8
SM
144}
145
d50d200a
SM
146ARGPAR_HIDDEN
147const char *argpar_item_opt_arg(const struct argpar_item * const item)
e2fb96d8 148{
e2fb96d8 149 ARGPAR_ASSERT(item);
d50d200a
SM
150 ARGPAR_ASSERT(item->type == ARGPAR_ITEM_TYPE_OPT);
151 return ((const struct argpar_item_opt *) item)->arg;
e2fb96d8
SM
152}
153
d50d200a
SM
154ARGPAR_HIDDEN
155const char *argpar_item_non_opt_arg(const struct argpar_item * const item)
e2fb96d8 156{
d50d200a
SM
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}
e2fb96d8 161
d50d200a
SM
162ARGPAR_HIDDEN
163unsigned 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;
e2fb96d8
SM
169}
170
d50d200a
SM
171ARGPAR_HIDDEN
172unsigned int argpar_item_non_opt_non_opt_index(
173 const struct argpar_item * const item)
e2fb96d8 174{
d50d200a
SM
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}
e2fb96d8 179
d50d200a
SM
180ARGPAR_HIDDEN
181void argpar_item_destroy(const struct argpar_item * const item)
182{
183 if (!item) {
e2fb96d8
SM
184 goto end;
185 }
186
d50d200a
SM
187 if (item->type == ARGPAR_ITEM_TYPE_OPT) {
188 struct argpar_item_opt * const opt_item =
189 (struct argpar_item_opt *) item;
e2fb96d8 190
d50d200a
SM
191 free(opt_item->arg);
192 }
e2fb96d8 193
d50d200a 194 free((void *) item);
e2fb96d8
SM
195
196end:
d50d200a 197 return;
e2fb96d8
SM
198}
199
d50d200a
SM
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 */
e2fb96d8
SM
206static
207struct 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 =
d50d200a 212 ARGPAR_ZALLOC(struct argpar_item_opt);
e2fb96d8
SM
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
230error:
4624dad0 231 argpar_item_destroy(&opt_item->base);
e2fb96d8
SM
232 opt_item = NULL;
233
234end:
235 return opt_item;
236}
237
d50d200a
SM
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 */
e2fb96d8
SM
245static
246struct 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 =
d50d200a 251 ARGPAR_ZALLOC(struct argpar_item_non_opt);
e2fb96d8
SM
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
262end:
263 return non_opt_item;
264}
265
d50d200a
SM
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 */
277static
278int 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
317error:
318 argpar_error_destroy(*error);
319 ret = -1;
320
321end:
322 return ret;
323}
324
325ARGPAR_HIDDEN
326enum argpar_error_type argpar_error_type(
327 const struct argpar_error * const error)
328{
329 ARGPAR_ASSERT(error);
330 return error->type;
331}
332
333ARGPAR_HIDDEN
334unsigned int argpar_error_orig_index(const struct argpar_error * const error)
335{
336 ARGPAR_ASSERT(error);
337 return error->orig_index;
338}
339
340ARGPAR_HIDDEN
341const 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
350ARGPAR_HIDDEN
351const 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
366ARGPAR_HIDDEN
367void 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 */
e2fb96d8
SM
386static
387const 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
405end:
406 return !descr->short_name && !descr->long_name ? NULL : descr;
407}
408
d50d200a 409/* Return type of parse_short_opt_group() and parse_long_opt() */
e2fb96d8
SM
410enum parse_orig_arg_opt_ret {
411 PARSE_ORIG_ARG_OPT_RET_OK,
e2fb96d8 412 PARSE_ORIG_ARG_OPT_RET_ERROR = -1,
d50d200a 413 PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY = -2,
e2fb96d8
SM
414};
415
d50d200a
SM
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 */
e2fb96d8 425static
d50d200a
SM
426enum parse_orig_arg_opt_ret parse_short_opt_group(
427 const char * const short_opt_group,
e2fb96d8
SM
428 const char * const next_orig_arg,
429 const struct argpar_opt_descr * const descrs,
d50d200a
SM
430 struct argpar_iter * const iter,
431 struct argpar_error ** const error,
432 struct argpar_item ** const item)
e2fb96d8
SM
433{
434 enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
4624dad0 435 bool used_next_orig_arg = false;
4624dad0
SM
436 const char *opt_arg = NULL;
437 const struct argpar_opt_descr *descr;
438 struct argpar_item_opt *opt_item;
e2fb96d8 439
d50d200a
SM
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
4624dad0 446 /* Find corresponding option descriptor */
d50d200a 447 descr = find_descr(descrs, *iter->short_opt_group_ch, NULL);
4624dad0 448 if (!descr) {
d50d200a
SM
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
4624dad0
SM
459 goto error;
460 }
e2fb96d8 461
4624dad0 462 if (descr->with_arg) {
d50d200a 463 if (iter->short_opt_group_ch[1]) {
4624dad0 464 /* `-oarg` form */
d50d200a 465 opt_arg = &iter->short_opt_group_ch[1];
4624dad0
SM
466 } else {
467 /* `-o arg` form */
468 opt_arg = next_orig_arg;
469 used_next_orig_arg = true;
e2fb96d8
SM
470 }
471
4624dad0 472 /*
d50d200a
SM
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
e2fb96d8
SM
485 goto error;
486 }
4624dad0 487 }
e2fb96d8 488
4624dad0
SM
489 /* Create and append option argument */
490 opt_item = create_opt_item(descr, opt_arg);
491 if (!opt_item) {
d50d200a 492 ret = PARSE_ORIG_ARG_OPT_RET_ERROR_MEMORY;
4624dad0
SM
493 goto error;
494 }
e2fb96d8 495
4624dad0 496 *item = &opt_item->base;
d50d200a 497 iter->short_opt_group_ch++;
e2fb96d8 498
d50d200a 499 if (descr->with_arg || !*iter->short_opt_group_ch) {
4624dad0 500 /* Option has an argument: no more options */
d50d200a 501 iter->short_opt_group_ch = NULL;
4624dad0
SM
502
503 if (used_next_orig_arg) {
d50d200a 504 iter->i += 2;
4624dad0 505 } else {
d50d200a 506 iter->i++;
4624dad0 507 }
e2fb96d8
SM
508 }
509
510 goto end;
511
512error:
d50d200a 513 ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK);
e2fb96d8
SM
514
515end:
516 return ret;
517}
518
d50d200a
SM
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 */
e2fb96d8
SM
527static
528enum 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,
d50d200a
SM
531 struct argpar_iter * const iter,
532 struct argpar_error ** const error,
533 struct argpar_item ** const item)
e2fb96d8 534{
e2fb96d8
SM
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;
4624dad0 538 bool used_next_orig_arg = false;
e2fb96d8
SM
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
e2fb96d8
SM
546 /* Option name */
547 const char *long_opt_name = long_opt_arg;
548
d50d200a 549 ARGPAR_ASSERT(strlen(long_opt_arg) != 0);
e2fb96d8
SM
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 */
d50d200a
SM
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 }
e2fb96d8
SM
565 }
566
d50d200a
SM
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;
e2fb96d8
SM
570 }
571
572 /* Find corresponding option descriptor */
573 descr = find_descr(descrs, '\0', long_opt_name);
574 if (!descr) {
d50d200a
SM
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
e2fb96d8
SM
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) {
d50d200a
SM
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
e2fb96d8
SM
600 goto error;
601 }
602
603 opt_arg = next_orig_arg;
4624dad0 604 used_next_orig_arg = true;
e2fb96d8 605 }
ebdbbd32
SM
606 } else if (eq_pos) {
607 /*
608 * Unexpected `--opt=arg` style for a long option which
609 * doesn't accept an argument.
610 */
d50d200a
SM
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
ebdbbd32 618 goto error;
e2fb96d8
SM
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
4624dad0 627 if (used_next_orig_arg) {
d50d200a 628 iter->i += 2;
4624dad0 629 } else {
d50d200a 630 iter->i++;
e2fb96d8
SM
631 }
632
4624dad0 633 *item = &opt_item->base;
e2fb96d8
SM
634 goto end;
635
636error:
d50d200a 637 ARGPAR_ASSERT(ret != PARSE_ORIG_ARG_OPT_RET_OK);
e2fb96d8
SM
638
639end:
640 return ret;
641}
642
d50d200a
SM
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 */
e2fb96d8
SM
651static
652enum 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,
d50d200a
SM
655 struct argpar_iter * const iter,
656 struct argpar_error ** const error,
657 struct argpar_item ** const item)
e2fb96d8
SM
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],
d50d200a 666 next_orig_arg, descrs, iter, error, item);
e2fb96d8
SM
667 } else {
668 /* Short option */
d50d200a
SM
669 ret = parse_short_opt_group(&orig_arg[1],
670 next_orig_arg, descrs, iter, error, item);
e2fb96d8
SM
671 }
672
673 return ret;
674}
675
4624dad0 676ARGPAR_HIDDEN
d50d200a
SM
677struct argpar_iter *argpar_iter_create(const unsigned int argc,
678 const char * const * const argv,
4624dad0
SM
679 const struct argpar_opt_descr * const descrs)
680{
d50d200a 681 struct argpar_iter *iter = ARGPAR_ZALLOC(struct argpar_iter);
4624dad0 682
d50d200a 683 if (!iter) {
4624dad0
SM
684 goto end;
685 }
686
d50d200a
SM
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 }
4624dad0
SM
697
698end:
d50d200a 699 return iter;
4624dad0
SM
700}
701
702ARGPAR_HIDDEN
d50d200a 703void argpar_iter_destroy(struct argpar_iter * const iter)
4624dad0 704{
d50d200a
SM
705 if (iter) {
706 free(iter->tmp_buf.data);
707 free(iter);
708 }
4624dad0
SM
709}
710
711ARGPAR_HIDDEN
d50d200a
SM
712enum 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)
4624dad0 716{
d50d200a
SM
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;
4624dad0 722
d50d200a 723 ARGPAR_ASSERT(iter->i <= iter->user.argc);
4624dad0 724
d50d200a
SM
725 if (error) {
726 *nc_error = NULL;
727 }
4624dad0 728
d50d200a
SM
729 if (iter->i == iter->user.argc) {
730 status = ARGPAR_ITER_NEXT_STATUS_END;
4624dad0
SM
731 goto end;
732 }
733
d50d200a
SM
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;
4624dad0 738
d50d200a
SM
739 if (strcmp(orig_arg, "-") == 0 || strcmp(orig_arg, "--") == 0 ||
740 orig_arg[0] != '-') {
4624dad0 741 /* Non-option argument */
d50d200a
SM
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);
4624dad0
SM
745
746 if (!non_opt_item) {
d50d200a 747 status = ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY;
4624dad0
SM
748 goto end;
749 }
750
d50d200a
SM
751 iter->non_opt_index++;
752 iter->i++;
4624dad0 753 *item = &non_opt_item->base;
d50d200a 754 status = ARGPAR_ITER_NEXT_STATUS_OK;
4624dad0
SM
755 goto end;
756 }
757
758 /* Option argument */
759 parse_orig_arg_opt_ret = parse_orig_arg_opt(orig_arg,
d50d200a
SM
760 next_orig_arg, iter->user.descrs, iter, nc_error,
761 (struct argpar_item **) item);
4624dad0
SM
762 switch (parse_orig_arg_opt_ret) {
763 case PARSE_ORIG_ARG_OPT_RET_OK:
d50d200a 764 status = ARGPAR_ITER_NEXT_STATUS_OK;
4624dad0 765 break;
4624dad0 766 case PARSE_ORIG_ARG_OPT_RET_ERROR:
d50d200a
SM
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;
4624dad0
SM
775 break;
776 default:
777 abort();
778 }
779
780end:
781 return status;
782}
783
784ARGPAR_HIDDEN
d50d200a
SM
785unsigned int argpar_iter_ingested_orig_args(
786 const struct argpar_iter * const iter)
e2fb96d8 787{
d50d200a 788 return iter->i;
e2fb96d8 789}
This page took 0.063152 seconds and 4 git commands to generate.