Sometimes it is useful to know where options appear on the command
line. You can tell in which order options (and suboptions) appear
by taking advantage of the fact that callbacks (see Option Callbacks) are called in the same order that the corresponding options
appear on the command line. However, if you want to determine the
ordering of non-option positional arguments as well as options,
you must instead use an argument callback, or use the
MU_OPT_CONTINUE
flag (see Option Parsing Flags).
To use an argument callback, you must use the
mu_opt_context_set_arg_callback
function.
void
mu_opt_context_set_arg_callback (MU_OPT_CONTEXT *context, int callback (const char *arg, void *data, char *err), void *data, int destructor (void *data))
¶This function sets an argument callback in context. context
must not have been created with the MU_OPT_CONTINUE
flag
(see Option Parsing Flags), and it must never have been passed to
mu_parse_opts
(see Parsing Options and Environment).
callback will be called for each positional argument found when
mu_parse_opts
is called. callback may not be
NULL
. data will be passed to callback as the
data argument. When context is destroyed using
mu_opt_context_free
, destructor will be called with
data passed as its data argument.
callback should indicate success by returning zero. If
callback fails, it should return nonzero and copy an error string
to err (not exceeding MU_OPT_ERR_MAX
). See callback error indication for more information.
Note that if either of the flags MU_OPT_PERMUTE
or
MU_OPT_STOP_AT_ARG
are used when the option parsing context is
created (see Option Parsing Flags), then the successful return value
of mu_parse_opts
will not include the positional arguments
parsed (see Parsing Options and Environment). This is so that, after
shifting the arguments by the return value of mu_parse_opts
with
mu_shift_args
, the remaining arguments will be the positional
arguments.
Normally, however, when using an argument callback, you shouldn’t need
the return value of mu_parse_opts
except to check for errors.
If neither of the flags MU_OPT_PERMUTE
nor
MU_OPT_STOP_AT_ARG
are given, then the return value of
mu_parse_opts
will include the positional arguments (i.e.,
a successful return from mu_parse_opts
will always return the
total number of arguments, options or otherwise). This is because, if
neither MU_OPT_PERMUTE
nor MU_OPT_STOP_AT_ARG
are given,
it cannot be guaranteed that all positional arguments will appear after
all options. Thus, the return value of mu_parse_opts
should not
be used to shift the arguments, and should only be used to check for
errors.
Here is an example of how to use argument callbacks:
#include <stdio.h> #include <mu/options.h> #include <mu/safe.h> /* For mu_opt_context_x{new,free} */ /* Callbacks to print a message when we find an option or argument. */ static int print_example(void *data, char *err) { puts("Option found: example"); return 0; } static int print_another(void *data, char *err) { puts("Option found: another"); return 0; } static int print_argument(const char *arg, void *data, char *err) { printf("Argument found: %s\n", arg); return 0; } int main(int argc, char **argv) { const MU_OPT options[] = { { .short_opt = "e", .long_opt = "example", .has_arg = MU_OPT_NONE, .callback_none = print_example }, { .short_opt = "a", .long_opt = "another", .has_arg = MU_OPT_NONE, .callback_none = print_another }, { 0 } }; MU_OPT_CONTEXT *context; int ret; context = mu_opt_context_xnew(argc, argv, options, 0); mu_opt_context_set_arg_callback(context, print_argument, NULL, NULL); ret = mu_parse_opts(context); mu_opt_context_xfree(context); return MU_OPT_ERR(ret); }
Here is the output of the example program:
$ ./option-ordered-callback foo -e bar --another baz -| Argument found: foo -| Option found: example -| Argument found: bar -| Option found: another -| Argument found: baz $ ./option-ordered-callback -a foo bar --example -| Option found: another -| Argument found: foo -| Argument found: bar -| Option found: example
Alternatively, you can also determine the order in which options and
positional arguments appear using the MU_OPT_CONTINUE
flag. If
you use this flag, you should not use the MU_OPT_PERMUTE
flag
(otherwise, all options will be parsed at once and the
MU_OPT_CONTINUE
flag is rendered useless). The
MU_OPT_STOP_AT_ARG
is also useless if you use
MU_OPT_CONTINUE
, because if you use MU_OPT_STOP_AT_ARG
,
you might as well just parse the options once and then parse the rest of
the arguments, which will only be positional arguments.
Using the MU_OPT_CONTINUE
flag, you should parse options (maybe
using callbacks if you care about the order of the options themselves),
then parse positional arguments, and then options again until all
arguments are used up. Note, however, that normally you must not call
mu_parse_opts
more than once, unless you pass the
MU_OPT_CONTINUE
flag
All the environment variables will be parsed on the first call of
mu_parse_opts
. They will not be parsed again in subsequent
calls. See Parsing the Environment for more information.
After you parse each non-option argument, you must call
mu_opt_context_shift
on the option context in order to ensure
that mu_parse_opts
will not stop at the argument you just parsed.
int
mu_opt_context_shift (MU_OPT_CONTEXT *context, int amount)
¶Update the internal index of context by amount. amount may be negative.
Normally, this function returns zero. However, in the case that the new index would be less that 1, the new index will instead be set to 1 and the amount that could not be shifted will be returned. And in the case that the new index would be greater than or equal to the number of arguments in context, the new index will instead be set to the number of arguments minus one, and again, the amount that could not be shifted is returned.
Here is an example illustrating how to parse options and positional arguments while preserving the order, without using argument callbacks:
#include <stdio.h> #include <mu/options.h> #include <mu/safe.h> /* For mu_opt_context_x{new,free} */ /* Callbacks to print a message when we find an option. */ static int print_example(void *data, char *err) { puts("Option found: example"); return 0; } static int print_another(void *data, char *err) { puts("Option found: another"); return 0; } int main(int argc, char **argv) { const MU_OPT options[] = { { .short_opt = "e", .long_opt = "example", .has_arg = MU_OPT_NONE, .callback_none = print_example }, { .short_opt = "a", .long_opt = "another", .has_arg = MU_OPT_NONE, .callback_none = print_another }, { 0 } }; MU_OPT_CONTEXT *context; context = mu_opt_context_xnew(argc, argv, options, MU_OPT_CONTINUE); while (argc > 1) { int ret; /* Parse options. */ ret = mu_parse_opts(context); if (MU_OPT_ERR(ret)) return 1; /* Shift the arguments (to get rid of the options we just parsed). */ mu_shift_args(&argc, &argv, ret); if (argc > 1) { /* Print an argument (we don't have to print them all at once because if `mu_parse_opts' doesn't find any options, it will just return 0). */ printf("Argument found: %s\n", argv[1]); /* Shift away this argument. */ mu_shift_args(&argc, &argv, 1); mu_opt_context_shift(context, 1); } } mu_opt_context_xfree(context); return 0; }
The behavior of the above program is identical to the one using argument callbacks (see argument callback example).