tap: import some changes
[argpar.git] / argpar / argpar.h
1 /*
2 * SPDX-License-Identifier: MIT
3 * SPDX-FileCopyrightText: 2019-2024 Philippe Proulx <pproulx@efficios.com>
4 * SPDX-FileCopyrightText: 2020-2024 Simon Marchi <simon.marchi@efficios.com>
5 */
6
7 #ifndef ARGPAR_ARGPAR_H
8 #define ARGPAR_ARGPAR_H
9
10 #include <stdbool.h>
11
12 #if defined(__cplusplus)
13 extern "C" {
14 #endif
15
16 /*!
17 @mainpage
18
19 See the \ref api module.
20
21 @addtogroup api argpar API
22 @{
23
24 argpar is a library which provides an iterator-based API to parse
25 command-line arguments.
26
27 The argpar parser supports:
28
29 <ul>
30 <li>
31 Short options without an argument, possibly tied together:
32
33 @code{.unparsed}
34 -f -auf -n
35 @endcode
36
37 <li>
38 Short options with arguments:
39
40 @code{.unparsed}
41 -b 45 -f/mein/file -xyzhello
42 @endcode
43
44 <li>
45 Long options without an argument:
46
47 @code{.unparsed}
48 --five-guys --burger-king --pizza-hut --subway
49 @endcode
50
51 <li>
52 Long options with arguments (two original arguments or a single
53 one with a <code>=</code> character):
54
55 @code{.unparsed}
56 --security enable --time=18.56
57 @endcode
58
59 <li>
60 Non-option arguments (anything else, including
61 <code>-</code> and <code>\--</code>).
62
63 A non-option argument cannot have the form of an option, for example
64 if you need to pass the exact relative path
65 <code>\--component</code>. In that case, you would need to pass
66 <code>./\--component</code>. There's no generic way to escape
67 <code>-</code> as of this version.
68 </ul>
69
70 Create a parsing iterator with argpar_iter_create(), then repeatedly
71 call argpar_iter_next() to access the parsing results (items), until one
72 of:
73
74 - There are no more arguments.
75
76 - The argument parser encounters an error (for example, an unknown
77 option).
78
79 - You need to stop.
80
81 argpar_iter_create() accepts duplicate option descriptors in
82 \p descrs (argpar_iter_next() produces one item for each
83 instance).
84
85 A parsing item (the result of argpar_iter_next()) has the type
86 #argpar_item.
87
88 Get the type (option or non-option) of an item with
89 \link argpar_item_type(const argpar_item_t *) argpar_item_type()\endlink.
90 Each item type has its set of dedicated functions
91 (\c argpar_item_opt_ and \c argpar_item_non_opt_ prefixes).
92
93 argpar_iter_next() produces the items in the same order that it parses
94 original arguments, including non-option arguments. This means, for
95 example, that for:
96
97 @code{.unparsed}
98 --hello --count=23 /path/to/file -ab --type file -- magie
99 @endcode
100
101 argpar_iter_next() produces the following items, in this order:
102
103 -# Option item: <code>\--hello</code>.
104 -# Option item: <code>\--count</code> with argument <code>23</code>.
105 -# Non-option item: <code>/path/to/file</code>.
106 -# Option item: <code>-a</code>.
107 -# Option item: <code>-b</code>.
108 -# Option item: <code>\--type</code> with argument <code>file</code>.
109 -# Non-option item: <code>\--</code>.
110 -# Non-option item: <code>magie</code>.
111 */
112
113 /* Internal: `noexcept` specifier if C++ ≥ 11 */
114 #if defined(__cplusplus) && (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900))
115 # define ARGPAR_NOEXCEPT noexcept
116 #else
117 # define ARGPAR_NOEXCEPT
118 #endif
119
120 typedef struct argpar_opt_descr argpar_opt_descr_t;
121
122 /*!
123 @name Item API
124 @{
125 */
126
127 /*!
128 @brief
129 Type of a parsing item, as returned by
130 \link argpar_item_type(const argpar_item *) argpar_item_type()\endlink.
131 */
132 typedef enum argpar_item_type
133 {
134 /// Option
135 ARGPAR_ITEM_TYPE_OPT,
136
137 /// Non-option
138 ARGPAR_ITEM_TYPE_NON_OPT,
139 } argpar_item_type_t;
140
141 /*!
142 @struct argpar_item
143
144 @brief
145 Opaque parsing item type
146
147 argpar_iter_next() sets a pointer to such a type.
148 */
149 typedef struct argpar_item argpar_item_t;
150
151 /*!
152 @brief
153 Returns the type of the parsing item \p item.
154
155 @param[in] item
156 Parsing item of which to get the type.
157
158 @returns
159 Type of \p item.
160
161 @pre
162 \p item is not \c NULL.
163 */
164 argpar_item_type_t argpar_item_type(const argpar_item_t *item) ARGPAR_NOEXCEPT;
165
166 /*!
167 @brief
168 Returns the option descriptor of the option parsing item \p item.
169
170 @param[in] item
171 Option parsing item of which to get the option descriptor.
172
173 @returns
174 Option descriptor of \p item.
175
176 @pre
177 \p item is not \c NULL.
178 @pre
179 \p item has the type #ARGPAR_ITEM_TYPE_OPT.
180 */
181 const argpar_opt_descr_t *argpar_item_opt_descr(const argpar_item_t *item) ARGPAR_NOEXCEPT;
182
183 /*!
184 @brief
185 Returns the argument of the option parsing item \p item, or
186 \c NULL if none.
187
188 @param[in] item
189 Option parsing item of which to get the argument.
190
191 @returns
192 Argument of \p item, or \c NULL if none.
193
194 @pre
195 \p item is not \c NULL.
196 @pre
197 \p item has the type #ARGPAR_ITEM_TYPE_OPT.
198 */
199 const char *argpar_item_opt_arg(const argpar_item_t *item) ARGPAR_NOEXCEPT;
200
201 /*!
202 @brief
203 Returns the complete original argument, pointing to one of the
204 entries of the original arguments (in \p argv, as passed to
205 argpar_iter_create()), of the non-option parsing item \p item.
206
207 @param[in] item
208 Non-option parsing item of which to get the complete original
209 argument.
210
211 @returns
212 Complete original argument of \p item.
213
214 @pre
215 \p item is not \c NULL.
216 @pre
217 \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT.
218 */
219 const char *argpar_item_non_opt_arg(const argpar_item_t *item) ARGPAR_NOEXCEPT;
220
221 /*!
222 @brief
223 Returns the index, within \em all the original arguments (in
224 \p argv, as passed to argpar_iter_create()), of the non-option
225 parsing item \p item.
226
227 For example, with the following command line (all options have no
228 argument):
229
230 @code{.unparsed}
231 -f -m meow --jus mix --kilo
232 @endcode
233
234 The original argument index of \c meow is&nbsp;2 while the original
235 argument index of \c mix is&nbsp;4.
236
237 @param[in] item
238 Non-option parsing item of which to get the original argument index.
239
240 @returns
241 Original argument index of \p item.
242
243 @pre
244 \p item is not \c NULL.
245 @pre
246 \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT.
247
248 @sa
249 argpar_item_non_opt_non_opt_index() -- Returns the non-option index
250 of a non-option parsing item.
251 */
252 unsigned int argpar_item_non_opt_orig_index(const argpar_item_t *item) ARGPAR_NOEXCEPT;
253
254 /*!
255 @brief
256 Returns the index, within the parsed non-option parsing items, of
257 the non-option parsing item \p item.
258
259 For example, with the following command line (all options have no
260 argument):
261
262 @code{.unparsed}
263 -f -m meow --jus mix --kilo
264 @endcode
265
266 The non-option index of \c meow is&nbsp;0 while the original
267 argument index of \c mix is&nbsp;1.
268
269 @param[in] item
270 Non-option parsing item of which to get the non-option index.
271
272 @returns
273 Non-option index of \p item.
274
275 @pre
276 \p item is not \c NULL.
277 @pre
278 \p item has the type #ARGPAR_ITEM_TYPE_NON_OPT.
279
280 @sa
281 argpar_item_non_opt_orig_index() -- Returns the original argument
282 index of a non-option parsing item.
283 */
284 unsigned int argpar_item_non_opt_non_opt_index(const argpar_item_t *item) ARGPAR_NOEXCEPT;
285
286 /*!
287 @brief
288 Destroys the parsing item \p item.
289
290 @param[in] item
291 Parsing item to destroy (may be \c NULL).
292 */
293 void argpar_item_destroy(const argpar_item_t *item) ARGPAR_NOEXCEPT;
294
295 /*!
296 @def ARGPAR_ITEM_DESTROY_AND_RESET(_item)
297
298 @brief
299 Calls argpar_item_destroy() with \p _item, and then sets \p _item
300 to \c NULL.
301
302 @param[in] _item
303 Item to destroy and variable to reset
304 (<code>const argpar_item_t *</code> type).
305 */
306 #define ARGPAR_ITEM_DESTROY_AND_RESET(_item) \
307 { \
308 argpar_item_destroy(_item); \
309 (_item) = NULL; \
310 }
311
312 /// @}
313
314 /*!
315 @name Error API
316 @{
317 */
318
319 /*!
320 @brief
321 Parsing error type, as returned by
322 \link argpar_error_type(const argpar_error_t *) argpar_error_type()\endlink.
323 */
324 typedef enum argpar_error_type
325 {
326 /// Unknown option error
327 ARGPAR_ERROR_TYPE_UNKNOWN_OPT,
328
329 /// Missing option argument error
330 ARGPAR_ERROR_TYPE_MISSING_OPT_ARG,
331
332 /// Unexpected option argument error
333 ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG,
334 } argpar_error_type_t;
335
336 /*!
337 @struct argpar_error
338
339 @brief
340 Opaque parsing error type
341 */
342 typedef struct argpar_error argpar_error_t;
343
344 /*!
345 @brief
346 Returns the type of the parsing error object \p error.
347
348 @param[in] error
349 Parsing error of which to get the type.
350
351 @returns
352 Type of \p error.
353
354 @pre
355 \p error is not \c NULL.
356 */
357 argpar_error_type_t argpar_error_type(const argpar_error_t *error) ARGPAR_NOEXCEPT;
358
359 /*!
360 @brief
361 Returns the index of the original argument (in \p argv, as passed to
362 argpar_iter_create()) for which the parsing error described by
363 \p error occurred.
364
365 @param[in] error
366 Parsing error of which to get the original argument index.
367
368 @returns
369 Original argument index of \p error.
370
371 @pre
372 \p error is not \c NULL.
373 */
374 unsigned int argpar_error_orig_index(const argpar_error_t *error) ARGPAR_NOEXCEPT;
375
376 /*!
377 @brief
378 Returns the name of the unknown option for which the parsing error
379 described by \p error occurred.
380
381 The returned name includes any <code>-</code> or <code>\--</code>
382 prefix.
383
384 With the long option with argument form, for example
385 <code>\--mireille=deyglun</code>, this function only returns the name
386 part (<code>\--mireille</code> in the last example).
387
388 @param[in] error
389 Parsing error of which to get the name of the unknown option.
390
391 @returns
392 Name of the unknown option of \p error.
393
394 @pre
395 \p error is not \c NULL.
396 @pre
397 The type of \p error, as returned by
398 \link argpar_error_type(const argpar_error_t *) argpar_error_type()\endlink,
399 is #ARGPAR_ERROR_TYPE_UNKNOWN_OPT.
400 */
401 const char *argpar_error_unknown_opt_name(const argpar_error_t *error) ARGPAR_NOEXCEPT;
402
403 /*!
404 @brief
405 Returns the descriptor of the option for which the parsing error
406 described by \p error occurred.
407
408 @param[in] error
409 Parsing error of which to get the option descriptor.
410 @param[out] is_short
411 @parblock
412 If not \c NULL, this function sets \p *is_short to:
413
414 - \c true if the option for which \p error occurred is a short
415 option.
416
417 - \c false if the option for which \p error occurred is a long
418 option.
419 @endparblock
420
421 @returns
422 Descriptor of the option of \p error.
423
424 @pre
425 \p error is not \c NULL.
426 @pre
427 The type of \p error, as returned by
428 \link argpar_error_type(const argpar_error_t *) argpar_error_type()\endlink,
429 is #ARGPAR_ERROR_TYPE_MISSING_OPT_ARG or
430 #ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG.
431 */
432 const argpar_opt_descr_t *argpar_error_opt_descr(const argpar_error_t *error,
433 bool *is_short) ARGPAR_NOEXCEPT;
434
435 /*!
436 @brief
437 Destroys the parsing error \p error.
438
439 @param[in] error
440 Parsing error to destroy (may be \c NULL).
441 */
442 void argpar_error_destroy(const argpar_error_t *error) ARGPAR_NOEXCEPT;
443
444 /// @}
445
446 /*!
447 @name Iterator API
448 @{
449 */
450
451 /*!
452 @brief
453 Option descriptor
454
455 argpar_iter_create() accepts an array of instances of such a type,
456 terminated with #ARGPAR_OPT_DESCR_SENTINEL, as its \p descrs parameter.
457
458 The typical usage is, for example:
459
460 @code
461 const argpar_opt_descr_t descrs[] = {
462 { 0, 'd', NULL, false },
463 { 1, '\0', "squeeze", true },
464 { 2, 'm', "meow", true },
465 ARGPAR_OPT_DESCR_SENTINEL,
466 };
467 @endcode
468 */
469 typedef struct argpar_opt_descr
470 {
471 /// Numeric ID, to uniquely identify this descriptor
472 const int id;
473
474 /// Short option character, or <code>'\0'</code>
475 const char short_name;
476
477 /// Long option name (without the <code>\--</code> prefix), or \c NULL
478 const char * const long_name;
479
480 /// \c true if this option has an argument
481 const bool with_arg;
482 } argpar_opt_descr_t;
483
484 /*!
485 @brief
486 Sentinel for an option descriptor array
487
488 The typical usage is, for example:
489
490 @code
491 const argpar_opt_descr_t descrs[] = {
492 { 0, 'd', NULL, false },
493 { 1, '\0', "squeeze", true },
494 { 2, 'm', "meow", true },
495 ARGPAR_OPT_DESCR_SENTINEL,
496 };
497 @endcode
498 */
499 #define ARGPAR_OPT_DESCR_SENTINEL \
500 { \
501 -1, '\0', NULL, false \
502 }
503
504 /*!
505 @struct argpar_iter
506
507 @brief
508 Opaque argpar iterator type
509
510 argpar_iter_create() returns a pointer to such a type.
511 */
512 typedef struct argpar_iter argpar_iter_t;
513
514 /*!
515 @brief
516 Creates and returns an argument parsing iterator to parse the
517 original arguments \p argv of which the count is \p argc using the
518 option descriptors \p descrs.
519
520 This function initializes the returned structure, but doesn't actually
521 start parsing the arguments.
522
523 argpar considers \em all the elements of \p argv, including the first
524 one, so that you would typically pass <code>(argc - 1)</code> as \p argc
525 and <code>\&argv[1]</code> as \p argv from what <code>main()</code>
526 receives, or ignore the parsing item of the first call to
527 argpar_iter_next().
528
529 \p *argv and \p *descrs must \em not change for all of:
530
531 - The lifetime of the returned iterator (until you call
532 argpar_iter_destroy()).
533
534 - The lifetime of any parsing item (until you call
535 argpar_item_destroy()) which argpar_iter_next() creates from the
536 returned iterator.
537
538 - The lifetime of any parsing error (until you call
539 argpar_error_destroy()) which argpar_iter_next() creates from the
540 returned iterator.
541
542 @param[in] argc
543 Number of original arguments to parse in \p argv.
544 @param[in] argv
545 Original arguments to parse, of which the count is \p argc.
546 @param[in] descrs
547 @parblock
548 Option descriptor array, terminated with #ARGPAR_OPT_DESCR_SENTINEL.
549
550 May contain duplicate entries.
551 @endparblock
552
553 @returns
554 New argument parsing iterator, or \c NULL on memory error.
555
556 @pre
557 \p argc is greater than 0.
558 @pre
559 \p argv is not \c NULL.
560 @pre
561 The first \p argc elements of \p argv are not \c NULL.
562 @pre
563 \p descrs is not \c NULL.
564
565 @sa
566 argpar_iter_destroy() -- Destroys an argument parsing iterator.
567 */
568 argpar_iter_t *argpar_iter_create(unsigned int argc, const char * const *argv,
569 const argpar_opt_descr_t *descrs) ARGPAR_NOEXCEPT;
570
571 /*!
572 @brief
573 Destroys the argument parsing iterator \p iter.
574
575 @param[in] iter
576 Argument parsing iterator to destroy (may be \c NULL).
577
578 @sa
579 argpar_iter_create() -- Creates an argument parsing iterator.
580 */
581 void argpar_iter_destroy(argpar_iter_t *iter) ARGPAR_NOEXCEPT;
582
583 /*!
584 @brief
585 Return type of argpar_iter_next().
586
587 Error status enumerators have a negative value.
588 */
589 typedef enum argpar_iter_next_status
590 {
591 /// Success
592 ARGPAR_ITER_NEXT_STATUS_OK,
593
594 /// End of iteration (no more original arguments to parse)
595 ARGPAR_ITER_NEXT_STATUS_END,
596
597 /// Parsing error
598 ARGPAR_ITER_NEXT_STATUS_ERROR = -1,
599
600 /// Memory error
601 ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY = -12,
602 } argpar_iter_next_status_t;
603
604 /*!
605 @brief
606 Sets \p *item to the next item of the argument parsing iterator
607 \p iter and advances \p iter.
608
609 If there are no more original arguments to parse, this function returns
610 #ARGPAR_ITER_NEXT_STATUS_END.
611
612 @param[in] iter
613 Argument parsing iterator from which to get the next parsing item.
614 @param[out] item
615 @parblock
616 On success, \p *item is the next parsing item of \p iter.
617
618 Destroy \p *item with argpar_item_destroy().
619 @endparblock
620 @param[out] error
621 @parblock
622 When this function returns #ARGPAR_ITER_NEXT_STATUS_ERROR,
623 if this parameter is not \c NULL, \p *error contains details about
624 the error.
625
626 Destroy \p *error with argpar_error_destroy().
627 @endparblock
628
629 @returns
630 Status code.
631
632 @pre
633 \p iter is not \c NULL.
634 @pre
635 \p item is not \c NULL.
636 */
637 argpar_iter_next_status_t argpar_iter_next(argpar_iter_t *iter, const argpar_item_t **item,
638 const argpar_error_t **error) ARGPAR_NOEXCEPT;
639
640 /*
641 * Returns the number of ingested elements from `argv`, as passed to
642 * argpar_iter_create() to create `*iter`, that were required to produce
643 * the previously returned items.
644 */
645
646 /*!
647 @brief
648 Returns the number of ingested original arguments (in
649 \p argv, as passed to argpar_iter_create() to create \p iter) that
650 the parser ingested to produce the \em previous parsing items.
651
652 @param[in] iter
653 Argument parsing iterator of which to get the number of ingested
654 original arguments.
655
656 @returns
657 Number of original arguments which \p iter ingested.
658
659 @pre
660 \p iter is not \c NULL.
661 */
662 unsigned int argpar_iter_ingested_orig_args(const argpar_iter_t *iter) ARGPAR_NOEXCEPT;
663
664 /// @}
665
666 /// @}
667
668 #if defined(__cplusplus)
669 }
670 #endif
671
672 #endif /* ARGPAR_ARGPAR_H */
This page took 0.041689 seconds and 5 git commands to generate.