I am writing an option parser for a bash-like shell I develop.
Nevertheless, to be compatible with bash options, I must read some options which begin with a '+', like this:
./42sh +O autocd [...]
(The manual page says these options will passed to the builtin shopt
which sets the values of settings).
The problem is that getopt_long()
function only returns the options which begin with a -
or --
, if they are not alone. If they are, bash counsider them respectively as an alias for standard input and a end of options marker.
How I could get this type of options with getopt_long()
? Have I to parse these options by myself ?
EDIT : according to the @jxh response and the man 3 getopt
page, I discovered that getopt
and getopt_long
arranges the **argv
parameters array to move all arguments that don't seem to be valid options - from their point of view - at the end. So, I wrote the following code after the usual code which gets the normal options (all suggestions and remarks greatly appreciated):
EDIT2 : fixed memory leak due to strdup() at each iteration of the loop.
for(; optind < argc; ++optind)
{
const char *argv_copy = strdup(argv[optind]);
if (argv_copy[0] == '+' && argv_copy[1] == 'O')
{
/* A deactivation parameter have been just found ! */
if (handle_shopt_options(shell_options,
argv[optind + 1],
DISABLE) == EXIT_FAILURE)
{
usage(argv[optind]);
free_shell_options(shell_options);
shell_options = NULL;
}
++optind;
}
free(argv_copy);
argv_copy = NULL;
}
Some explanations:
optind
is the argv
index which tells us which argument will be parsed at the next pass. Since we parsed all the getopt() point-of-view valid arguments, and since getopt() moves all the non-options at the end, we will parse all remaining arguments, included the ones which interest us.argv[argc] == NULL
: this trick is used to know where is the end of the arguments list, so it is useless to parse the argument when optind == argc
.argv
value, so I preferred to copy it in a new string, but I am probably wrong, to be verfied.Some remarks:
getopt_long()
will be available only if _GNU_SOURCE
macro is defined.strdup()
will be available only if macro _XOPEN_SOURCE >= 500
or macro _POSIX_C_SOURCE >= 200809L
.As you have noted in your research, you cannot use getopt_long
to parse options that begin with +
.
As a workaround, you can scan argv[]
yourself, and then create a new argument vector that substitutes --plus-
in front of every argument you think is a +
style option in the original argv[]
. This new array should be parseable by getopt_long
.