Correct some getopt() logic
1. Null pointer dereference: - for (ndx = 0; longopts[ndx].name[0] != '\0'; ndx++) + for (ndx = 0; longopts[ndx].name != NULL; ndx++) 2. Handle single character long options. An option like -x could be either a short option or a long option (under getopt_long_only()). This case was not being handled correctly. 3. Add missing support for optional arguments to short options (indicated with two "::" This effects all members of the getopt() family of APIs. Tested on the simulator using extensions to apps/testing/ostest.
This commit is contained in:
parent
b7c451c5a4
commit
af3c76bb53
@ -69,7 +69,7 @@ static int getopt_long_option(FAR struct getopt_s *go,
|
||||
* The last element of the option arry must be filled with zeroes.
|
||||
*/
|
||||
|
||||
for (ndx = 0; longopts[ndx].name[0] != '\0'; ndx++)
|
||||
for (ndx = 0; longopts[ndx].name != NULL; ndx++)
|
||||
{
|
||||
if (strcmp(go->go_optptr, longopts[ndx].name) == 0)
|
||||
{
|
||||
@ -99,6 +99,7 @@ static int getopt_long_option(FAR struct getopt_s *go,
|
||||
if (next == NULL || next[0] == '-')
|
||||
{
|
||||
go->go_optptr = NULL;
|
||||
go->go_optarg = NULL;
|
||||
go->go_optind++;
|
||||
break;
|
||||
}
|
||||
@ -168,7 +169,6 @@ static int getopt_long_option(FAR struct getopt_s *go,
|
||||
/* This option is not in the list of valid options */
|
||||
|
||||
go->go_optopt = *go->go_optptr;
|
||||
go->go_optptr++;
|
||||
return '?';
|
||||
|
||||
errout:
|
||||
@ -251,6 +251,8 @@ int getopt_common(int argc, FAR char * const argv[],
|
||||
FAR int *longindex,
|
||||
enum getopt_mode_e mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Get thread-specific getopt() variables */
|
||||
|
||||
FAR struct getopt_s *go = getoptvars();
|
||||
@ -360,19 +362,22 @@ int getopt_common(int argc, FAR char * const argv[],
|
||||
/* go->go_optptr now points at the next option and it is not something
|
||||
* crazy. Possibilities:
|
||||
*
|
||||
* -o
|
||||
* -o reqarg
|
||||
* -option
|
||||
* -option reqarg
|
||||
* -option optarg
|
||||
* --option reqarg
|
||||
* --option optarg
|
||||
* FORM APPLICABILITY
|
||||
* -o getopt(), getopt_long_only()
|
||||
* -o reqarg getopt(), getopt_long_only()
|
||||
* -o optarg getopt_long_only()
|
||||
* -option getopt_long_only()
|
||||
* -option reqarg getopt_long_only()
|
||||
* -option optarg getopt_long_only()
|
||||
* --option getopt_long(), getopt_long_only()
|
||||
* --option reqarg getopt_long(), getopt_long_only()
|
||||
* --option optarg getopt_long(), getopt_long_only()
|
||||
*
|
||||
* Where:
|
||||
* o - Some short option
|
||||
* option - Some long option
|
||||
* reqarg - A required argument
|
||||
* optarg - An optional argument
|
||||
* o - Some short option
|
||||
* option - Some long option
|
||||
* reqarg - A required argument
|
||||
* optarg - An optional argument
|
||||
*/
|
||||
|
||||
/* Check for --option forms or -option forms */
|
||||
@ -396,14 +401,25 @@ int getopt_common(int argc, FAR char * const argv[],
|
||||
* must be distinguished from the -o case forms.
|
||||
*/
|
||||
|
||||
if (GETOPT_HAVE_LONGONLY(mode) && *(go->go_optptr + 1) != '\0')
|
||||
else if (GETOPT_HAVE_LONGONLY(mode))
|
||||
{
|
||||
return getopt_long_option(go, argv, longopts, longindex);
|
||||
/* A special case is that the option is of a form like
|
||||
* -o but is represented as a single character long option.
|
||||
* In that case, getopt_long_option() will fail with '?' and,
|
||||
* if it is a single character option, we can just fall
|
||||
* through to the short option logic.
|
||||
*/
|
||||
|
||||
ret = getopt_long_option(go, argv, longopts, longindex);
|
||||
if (ret != '?' || *(go->go_optptr + 1) != '\0')
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the option is in the list of valid short options.
|
||||
* In long option modes, opstring may be NULL. However, but that is
|
||||
* In long option modes, opstring may be NULL. However, that is
|
||||
* an error in any case here because we have not found any
|
||||
* long options.
|
||||
*/
|
||||
@ -435,8 +451,8 @@ int getopt_common(int argc, FAR char * const argv[],
|
||||
return *optchar;
|
||||
}
|
||||
|
||||
/* Yes, it has a required argument. Is the required argument
|
||||
* immediately after the command in this same argument?
|
||||
/* Yes, it may have an argument. Is the argument immediately after
|
||||
* the command in this same argument?
|
||||
*/
|
||||
|
||||
if (go->go_optptr[1] != '\0')
|
||||
@ -449,7 +465,7 @@ int getopt_common(int argc, FAR char * const argv[],
|
||||
return *optchar;
|
||||
}
|
||||
|
||||
/* No.. is the optional argument the next argument in argv[] ? */
|
||||
/* No.. is there an argument in the next value of argv[] ? */
|
||||
|
||||
if (argv[go->go_optind + 1] && *argv[go->go_optind + 1] != '-')
|
||||
{
|
||||
@ -467,7 +483,10 @@ int getopt_common(int argc, FAR char * const argv[],
|
||||
go->go_optarg = NULL;
|
||||
go->go_optopt = *optchar;
|
||||
go->go_optind++;
|
||||
return noarg_ret;
|
||||
|
||||
/* Two colons means that the argument is optional. */
|
||||
|
||||
return (optchar[2] == ':') ? *optchar : noarg_ret;
|
||||
}
|
||||
|
||||
errout:
|
||||
|
Loading…
Reference in New Issue
Block a user