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