Browse Source

Added and updated some methods in the ArgumentList classes

tags/2021-05-28
jules 6 years ago
parent
commit
1dee28660e
3 changed files with 130 additions and 76 deletions
  1. +1
    -1
      extras/UnitTestRunner/Source/Main.cpp
  2. +97
    -55
      modules/juce_core/misc/juce_ConsoleApplication.cpp
  3. +32
    -20
      modules/juce_core/misc/juce_ConsoleApplication.h

+ 1
- 1
extras/UnitTestRunner/Source/Main.cpp View File

@@ -80,7 +80,7 @@ int main (int argc, char **argv)
}
if (args.containsOption ("--category"))
runner.runTestsInCategory (args.getArgumentAfterOption ("--category").text);
runner.runTestsInCategory (args.getValueForOption ("--category"));
}
Logger::setCurrentLogger (nullptr);


+ 97
- 55
modules/juce_core/misc/juce_ConsoleApplication.cpp View File

@@ -23,18 +23,32 @@
namespace juce
{
File ArgumentList::Argument::resolveAsFile() const
static inline File resolveFilename (const String& name)
{
return File::getCurrentWorkingDirectory().getChildFile (text.unquoted());
return File::getCurrentWorkingDirectory().getChildFile (name.unquoted());
}
File ArgumentList::Argument::resolveAsExistingFile() const
static inline void checkFileExists (const File& f)
{
auto f = resolveAsFile();
if (! f.exists())
ConsoleApplication::fail ("Could not find file: " + f.getFullPathName());
}
static inline void checkFolderExists (const File& f)
{
if (! f.isDirectory())
ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
}
File ArgumentList::Argument::resolveAsFile() const
{
return resolveFilename (text);
}
File ArgumentList::Argument::resolveAsExistingFile() const
{
auto f = resolveAsFile();
checkFileExists (f);
return f;
}
@@ -48,17 +62,32 @@ File ArgumentList::Argument::resolveAsExistingFolder() const
return f;
}
bool ArgumentList::Argument::isLongOption() const { return text[0] == '-' && text[1] == '-' && text[2] != '-'; }
bool ArgumentList::Argument::isShortOption() const { return text[0] == '-' && text[1] != '-'; }
static inline bool isShortOptionFormat (StringRef s) { return s[0] == '-' && s[1] != '-'; }
static inline bool isLongOptionFormat (StringRef s) { return s[0] == '-' && s[1] == '-' && s[2] != '-'; }
static inline bool isOptionFormat (StringRef s) { return s[0] == '-'; }
bool ArgumentList::Argument::isLongOption() const { return isLongOptionFormat (text); }
bool ArgumentList::Argument::isShortOption() const { return isShortOptionFormat (text); }
bool ArgumentList::Argument::isOption() const { return isOptionFormat (text); }
bool ArgumentList::Argument::isLongOption (const String& option) const
{
if (option.startsWith ("--"))
return text == option;
if (! isLongOptionFormat (option))
{
jassert (! isShortOptionFormat (option)); // this will always fail to match
return isLongOption ("--" + option);
}
return text.upToFirstOccurrenceOf ("=", false, false) == option;
}
jassert (! option.startsWithChar ('-')); // this will always fail to match
String ArgumentList::Argument::getLongOptionValue() const
{
if (isLongOption())
if (auto equalsIndex = text.indexOfChar ('='))
return text.substring (equalsIndex + 1);
return text == "--" + option;
return {};
}
bool ArgumentList::Argument::isShortOption (char option) const
@@ -68,23 +97,23 @@ bool ArgumentList::Argument::isShortOption (char option) const
return isShortOption() && text.containsChar (option);
}
static bool compareOptionStrings (StringRef s1, StringRef s2)
bool ArgumentList::Argument::operator== (StringRef wildcard) const
{
if (s1 == s2)
return true;
for (auto& o : StringArray::fromTokens (wildcard, "|", {}))
{
if (text == o)
return true;
auto toks1 = StringArray::fromTokens (s1, "|", {});
auto toks2 = StringArray::fromTokens (s2, "|", {});
if (isShortOptionFormat (o) && o.length() == 2 && isShortOption ((char) o[1]))
return true;
for (auto& part1 : toks1)
for (auto& part2 : toks2)
if (part1.trim() == part2.trim())
return true;
if (isLongOptionFormat (o) && isLongOption (o))
return true;
}
return false;
}
bool ArgumentList::Argument::operator== (StringRef s) const { return compareOptionStrings (text, s); }
bool ArgumentList::Argument::operator!= (StringRef s) const { return ! operator== (s); }
//==============================================================================
@@ -139,46 +168,57 @@ void ArgumentList::failIfOptionIsMissing (StringRef option) const
ConsoleApplication::fail ("Expected the option " + option);
}
ArgumentList::Argument ArgumentList::getArgumentAfterOption (StringRef option) const
String ArgumentList::getValueForOption (StringRef option) const
{
for (int i = 0; i < arguments.size() - 1; ++i)
if (arguments.getReference(i) == option)
return arguments.getReference (i + 1);
jassert (isOptionFormat (option)); // the thing you're searching for must be an option
return {};
}
for (int i = 0; i < arguments.size(); ++i)
{
auto& arg = arguments.getReference(i);
File ArgumentList::getFileAfterOption (StringRef option) const
{
failIfOptionIsMissing (option);
auto arg = getArgumentAfterOption (option);
if (arg == option)
{
if (arg.isShortOption())
{
if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption())
return arguments.getReference (i + 1).text;
if (arg.text.isEmpty() || arg.text.startsWithChar ('-'))
ConsoleApplication::fail ("Expected a filename after the " + option + " option");
return {};
}
return arg.resolveAsFile();
if (arg.isLongOption())
return arg.getLongOptionValue();
}
}
return {};
}
File ArgumentList::getExistingFileAfterOption (StringRef option) const
File ArgumentList::getFileForOption (StringRef option) const
{
failIfOptionIsMissing (option);
auto arg = getArgumentAfterOption (option);
auto text = getValueForOption (option);
if (arg.text.isEmpty())
if (text.isEmpty())
{
failIfOptionIsMissing (option);
ConsoleApplication::fail ("Expected a filename after the " + option + " option");
}
return arg.resolveAsExistingFile();
return resolveFilename (text);
}
File ArgumentList::getExistingFolderAfterOption (StringRef option) const
File ArgumentList::getExistingFileForOption (StringRef option) const
{
failIfOptionIsMissing (option);
auto arg = getArgumentAfterOption (option);
if (arg.text.isEmpty())
ConsoleApplication::fail ("Expected a folder name after the " + option + " option");
auto file = getFileForOption (option);
checkFileExists (file);
return file;
}
return arg.resolveAsExistingFolder();
File ArgumentList::getExistingFolderForOption (StringRef option) const
{
auto file = getFileForOption (option);
checkFolderExists (file);
return file;
}
//==============================================================================
@@ -210,16 +250,18 @@ int ConsoleApplication::invokeCatchingFailures (std::function<int()>&& f)
return returnCode;
}
int ConsoleApplication::findAndRunCommand (const ArgumentList& args) const
int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool commandFlagMustBeFirst) const
{
for (auto& c : commands)
if (args.containsOption (c.commandOption))
{
auto index = args.indexOfOption (c.commandOption);
if (commandFlagMustBeFirst ? (index == 0) : (index >= 0))
return invokeCatchingFailures ([&] { c.command (args); return 0; });
}
if (commandIfNoOthersRecognised.isNotEmpty())
for (auto& c : commands)
if (compareOptionStrings (c.commandOption, commandIfNoOthersRecognised))
return invokeCatchingFailures ([&] { c.command (args); return 0; });
if (commandIfNoOthersRecognised >= 0)
return invokeCatchingFailures ([&] { commands[(size_t) commandIfNoOthersRecognised].command (args); return 0; });
fail ("Unrecognised arguments");
return 0;
@@ -237,11 +279,11 @@ void ConsoleApplication::addCommand (Command c)
void ConsoleApplication::addHelpCommand (String arg, String helpMessage, bool invokeIfNoOtherCommandRecognised)
{
if (invokeIfNoOtherCommandRecognised)
commandIfNoOthersRecognised = (int) commands.size();
addCommand ({ arg, arg, "Prints this message",
[this, helpMessage] (const ArgumentList& args) { printHelp (helpMessage, args); }});
if (invokeIfNoOtherCommandRecognised)
commandIfNoOthersRecognised = arg;
}
void ConsoleApplication::addVersionCommand (String arg, String versionText)


+ 32
- 20
modules/juce_core/misc/juce_ConsoleApplication.h View File

@@ -86,9 +86,17 @@ struct ArgumentList
/** Returns true if this argument starts with a double dash, followed by the given string. */
bool isLongOption (const String& optionRoot) const;
/** If this argument is a long option with a value, this returns the value.
e.g. for "--foo=bar", this would return 'bar'.
*/
String getLongOptionValue() const;
/** Returns true if this argument starts with a single dash and then contains the given character somewhere inside it. */
bool isShortOption (char shortOptionCharacter) const;
/** Returns true if this argument starts with one or more dashes. */
bool isOption() const;
/** Compares this argument against a string.
The string may be a pipe-separated list of options, e.g. "--help|-h"
*/
@@ -123,34 +131,33 @@ struct ArgumentList
/** Throws an error unless the given option is found in the argument list. */
void failIfOptionIsMissing (StringRef option) const;
/** Looks for the given argument and returns the one that follows it in the list.
/** Looks for a given argument and returns either its assigned value (for long options) or the
string that follows it (for short options).
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
If it finds a long option, it will look for an assignment with a '=' sign, e.g. "--file=foo.txt",
and will return the string following the '='. If there's no '=', it will return an empty string.
If it finds a short option, it will attempt to return the argument that follows it, unless
it's another option.
If the argument isn't found, this returns an empty string.
*/
Argument getArgumentAfterOption (StringRef option) const;
String getValueForOption (StringRef option) const;
/** Looks for a given argument and tries to parse the following argument as a file.
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
If the option isn't found, or if the next argument isn't a filename, it will throw
/** Looks for the value of argument using getValueForOption() and tries to parse that value
as a file.
If the option isn't found, or if the value can't be parsed as a filename, it will throw
an error.
*/
File getFileAfterOption (StringRef option) const;
File getFileForOption (StringRef option) const;
/** Looks for a given argument and tries to parse the following argument as a file
which must exist for this to succeed.
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
If the option isn't found, or if the next argument isn't a filename, or if the file
doesn't exist, or if it's a folder rather than a file, then it will throw a suitable error.
/** Looks for a file argument using getFileForOption() and fails with a suitable error if
the file doesn't exist.
*/
File getExistingFileAfterOption (StringRef option) const;
File getExistingFileForOption (StringRef option) const;
/** Looks for a given argument and tries to parse the following argument as a folder
which must exist for this to succeed.
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
If the option isn't found, or if the next argument isn't a filename, or if it doesn't
point to a folder, then it will throw a suitable error.
/** Looks for a filename argument using getFileForOption() and fails with a suitable error if
the file isn't a folder that exists.
*/
File getExistingFolderAfterOption (StringRef option) const;
File getExistingFolderForOption (StringRef option) const;
/** The name or path of the executable that was invoked, as it was specified on the command-line. */
String executableName;
@@ -250,8 +257,13 @@ struct ConsoleApplication
If the command calls the fail() function, this will throw an exception that gets
automatically caught and handled, and this method will return the error code that
was passed into the fail() call.
If commandFlagMustBeFirst is true, then only the first argument will be looked at
when searching the available commands - this lets you do 'git' style commands where
the executable name is followed by a verb.
*/
int findAndRunCommand (const ArgumentList&) const;
int findAndRunCommand (const ArgumentList&,
bool commandFlagMustBeFirst = false) const;
/** Creates an ArgumentList object from the argc and argv variablrs, and invokes
findAndRunCommand() using it.
@@ -261,7 +273,7 @@ struct ConsoleApplication
private:
//==============================================================================
std::vector<Command> commands;
String commandIfNoOthersRecognised;
int commandIfNoOthersRecognised = -1;
void printHelp (const String& preamble, const ArgumentList&) const;
};


Loading…
Cancel
Save