I came across what seems to be potentially a bug while using the ArgumentList
class’ method containsOption
.
More specifically, I was looking for an option using the pipe:
ArgumentList al("", commandLine);
auto containsMyOption = al.containsOption("--list-interfaces|-l");
When I passed a different argument (and one argument only) like this:
myapp --input=/path/to/a/file.dat
the result of containsMyOption
was false
, which was expected.
When I passed the short version of the argument like this
myapp -i=/path/to/a/file.dat
The value of containsMyOption
was true
.
What I noticed was that this is happening when comparing the argument (i.e. the second version), with the option passed in the containsOption
function.
Namely, when the comparison is made between argument and option (containsOption(StringRef option)
calls indexOfOption(StringRef option)
which in turn iterates through the arguments and uses the ==
operator to compare:
bool ArgumentList::Argument::operator== (StringRef wildcard) const
{
for (auto& o : StringArray::fromTokens (wildcard, "|", {}))
{
if (text == o)
return true;
if (isShortOptionFormat (o) && o.length() == 2 && isShortOption ((char) o[1]))
return true;
if (isLongOptionFormat (o) && isLongOption (o))
return true;
}
return false;
}
In the second type of argument mentioned above, the second if of the operator==
function, will return true. The first two operands of the &&
chain correctly return true. The third one:
isShortOption((char)o[1])
also returns true although it shouldn’t since this is the comparison between the actual argument and the given option to compare.
The latter function doesn’t validate that indeed the option used in the argument was the one provided in the top function (containsOption
). Instead, it checks if the short option is generally included in the argument (after its dash has been stripped, because o[1]
is used as an input argument):
bool ArgumentList::Argument::isShortOption ( char option) const
{
jassert (option != '-'); // this is probably not what you intended to pass in
return isShortOption() && text.containsChar (option);
}
isShortOption
tests if the argument is using a short option (which correctly returns true for the second type of command-line argument), while text.containsChar(option)
also correctly returns true because -i=/path/to/file.dat
contains the l
character. Nevertheless it should just be checking the second character and compare it to see if it’s the same option.