|
|
@@ -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)
|
|
|
|