getopt_long(): Add support for required argument format
The Linux man page requires that the getopt_long() and getopt_long_only() functions accept arguments to options in a form like: --option=argument This PR adds that missing functionality. This change effects only getopt_long() and getopt_long_only() Tested on a simulator NSH configuration with a modified version of the getopt() test in apps/testing/ostest.
This commit is contained in:
parent
e7bce54fa9
commit
7de43596da
@ -42,6 +42,60 @@
|
|||||||
* Prive Functions
|
* Prive Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: compare_long_option
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Compare a command argument with a long option, handling the cases:
|
||||||
|
*
|
||||||
|
* --option: Any argument is in the next argv entry
|
||||||
|
* --option=argument: The argument is in the same argv entry
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int compare_long_option(FAR const char *cmdarg,
|
||||||
|
FAR const char *optname,
|
||||||
|
FAR const char **argument)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
*argument = NULL;
|
||||||
|
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
|
int rawchar = *cmdarg++;
|
||||||
|
int optchar = *optname++;
|
||||||
|
int cmdchar;
|
||||||
|
|
||||||
|
/* The command line option may terminate with either '\0' or '='. */
|
||||||
|
|
||||||
|
cmdchar = rawchar;
|
||||||
|
if (cmdchar == '=')
|
||||||
|
{
|
||||||
|
cmdchar = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the comparison */
|
||||||
|
|
||||||
|
result = cmdchar - optchar;
|
||||||
|
if (result != 0 || cmdchar == '\0')
|
||||||
|
{
|
||||||
|
/* If the '=' is the real terminator, then return the argument
|
||||||
|
* that follows the '='
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (rawchar == '=')
|
||||||
|
{
|
||||||
|
*argument = cmdarg;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: getopt_long_option
|
* Name: getopt_long_option
|
||||||
*
|
*
|
||||||
@ -71,64 +125,104 @@ static int getopt_long_option(FAR struct getopt_s *go,
|
|||||||
|
|
||||||
for (ndx = 0; longopts[ndx].name != NULL; ndx++)
|
for (ndx = 0; longopts[ndx].name != NULL; ndx++)
|
||||||
{
|
{
|
||||||
if (strcmp(go->go_optptr, longopts[ndx].name) == 0)
|
FAR char *terminator = NULL;
|
||||||
|
|
||||||
|
if (compare_long_option(go->go_optptr, longopts[ndx].name,
|
||||||
|
(FAR const char **)&terminator) == 0)
|
||||||
{
|
{
|
||||||
/* Found the option with the matching name. Does it have an
|
/* Found the option with the matching name. Does it have an
|
||||||
* required argument? And optional argument?
|
* argument provided in the same argv entry like
|
||||||
|
* --option=argument?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (longopts[ndx].has_arg)
|
if (terminator != NULL)
|
||||||
{
|
{
|
||||||
FAR char *next;
|
/* Skip over the option + argument */
|
||||||
|
|
||||||
case no_argument:
|
go->go_optptr = NULL;
|
||||||
/* No, no arguments. Just return the option that we
|
go->go_optind++;
|
||||||
* found.
|
|
||||||
*/
|
|
||||||
|
|
||||||
go->go_optptr = NULL;
|
switch (longopts[ndx].has_arg)
|
||||||
go->go_optind++;
|
{
|
||||||
break;
|
case no_argument:
|
||||||
|
|
||||||
case optional_argument:
|
/* But no argument is expected! */
|
||||||
/* Check if there is a following argument and if that
|
|
||||||
* following argument is another option.
|
|
||||||
*/
|
|
||||||
|
|
||||||
next = argv[go->go_optind + 1];
|
|
||||||
if (next == NULL || next[0] == '-')
|
|
||||||
{
|
|
||||||
go->go_optptr = NULL;
|
|
||||||
go->go_optarg = NULL;
|
go->go_optarg = NULL;
|
||||||
|
return '?';
|
||||||
|
|
||||||
|
case optional_argument:
|
||||||
|
case required_argument:
|
||||||
|
|
||||||
|
/* Return the required argument */
|
||||||
|
|
||||||
|
go->go_optarg = terminator;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto errout;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Does the option have a required argument in the next argv
|
||||||
|
* entry? An optional argument?
|
||||||
|
*/
|
||||||
|
|
||||||
|
switch (longopts[ndx].has_arg)
|
||||||
|
{
|
||||||
|
FAR char *next;
|
||||||
|
|
||||||
|
case no_argument:
|
||||||
|
/* No, no arguments. Just return the argument that we
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
|
||||||
|
go->go_optptr = NULL;
|
||||||
go->go_optind++;
|
go->go_optind++;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/* Fall through and treat as a required option */
|
case optional_argument:
|
||||||
|
/* Check if there is a following argument and if that
|
||||||
|
* following argument is another option.
|
||||||
|
*/
|
||||||
|
|
||||||
case required_argument:
|
next = argv[go->go_optind + 1];
|
||||||
|
if (next == NULL || next[0] == '-')
|
||||||
|
{
|
||||||
|
go->go_optptr = NULL;
|
||||||
|
go->go_optarg = NULL;
|
||||||
|
go->go_optind++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Verify that the required option is present */
|
/* Fall through and treat as a required option */
|
||||||
|
|
||||||
next = argv[go->go_optind + 1];
|
case required_argument:
|
||||||
if (next == NULL || next[0] == '-')
|
|
||||||
{
|
|
||||||
go->go_optptr = NULL;
|
|
||||||
go->go_optarg = NULL;
|
|
||||||
go->go_optind++;
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the required option */
|
/* Verify that the required argument is present */
|
||||||
|
|
||||||
go->go_optptr = NULL;
|
next = argv[go->go_optind + 1];
|
||||||
go->go_optarg = next;
|
if (next == NULL || next[0] == '-')
|
||||||
go->go_optind += 2;
|
{
|
||||||
break;
|
go->go_optptr = NULL;
|
||||||
|
go->go_optarg = NULL;
|
||||||
|
go->go_optind++;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
/* Return the required argument */
|
||||||
goto errout;
|
|
||||||
break;
|
go->go_optptr = NULL;
|
||||||
|
go->go_optarg = next;
|
||||||
|
go->go_optind += 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto errout;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup return value.
|
/* Setup return value.
|
||||||
|
Loading…
Reference in New Issue
Block a user