diff --git a/modules/juce_core/misc/juce_ConsoleApplication.cpp b/modules/juce_core/misc/juce_ConsoleApplication.cpp index 0a1cfd0454..f461180266 100644 --- a/modules/juce_core/misc/juce_ConsoleApplication.cpp +++ b/modules/juce_core/misc/juce_ConsoleApplication.cpp @@ -28,16 +28,31 @@ static inline File resolveFilename (const String& name) return File::getCurrentWorkingDirectory().getChildFile (name.unquoted()); } -static inline void checkFileExists (const File& f) +static inline File checkFileExists (const File& f) { if (! f.exists()) ConsoleApplication::fail ("Could not find file: " + f.getFullPathName()); + + return f; } -static inline void checkFolderExists (const File& f) +static inline File checkFolderExists (const File& f) { if (! f.isDirectory()) ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName()); + + return f; +} + +static inline File resolveFilenameForOption (const ArgumentList& args, StringRef option, const String& filename) +{ + if (filename.isEmpty()) + { + args.failIfOptionIsMissing (option); + ConsoleApplication::fail ("Expected a filename after the " + option + " option"); + } + + return resolveFilename (filename); } File ArgumentList::Argument::resolveAsFile() const @@ -47,9 +62,7 @@ File ArgumentList::Argument::resolveAsFile() const File ArgumentList::Argument::resolveAsExistingFile() const { - auto f = resolveAsFile(); - checkFileExists (f); - return f; + return checkFileExists (resolveAsFile()); } File ArgumentList::Argument::resolveAsExistingFolder() const @@ -84,8 +97,12 @@ bool ArgumentList::Argument::isLongOption (const String& option) const String ArgumentList::Argument::getLongOptionValue() const { if (isLongOption()) - if (auto equalsIndex = text.indexOfChar ('=')) + { + auto equalsIndex = text.indexOfChar ('='); + + if (equalsIndex > 0) return text.substring (equalsIndex + 1); + } return {}; } @@ -162,9 +179,19 @@ bool ArgumentList::containsOption (StringRef option) const return indexOfOption (option) >= 0; } +bool ArgumentList::removeOptionIfFound (StringRef option) +{ + auto i = indexOfOption (option); + + if (i >= 0) + arguments.remove (i); + + return i >= 0; +} + void ArgumentList::failIfOptionIsMissing (StringRef option) const { - if (! containsOption (option)) + if (indexOfOption (option) < 0) ConsoleApplication::fail ("Expected the option " + option); } @@ -192,33 +219,72 @@ String ArgumentList::getValueForOption (StringRef option) const } return {}; + } -File ArgumentList::getFileForOption (StringRef option) const +String ArgumentList::removeValueForOption (StringRef option) { - auto text = getValueForOption (option); + jassert (isOptionFormat (option)); // the thing you're searching for must be an option - if (text.isEmpty()) + for (int i = 0; i < arguments.size(); ++i) { - failIfOptionIsMissing (option); - ConsoleApplication::fail ("Expected a filename after the " + option + " option"); + auto& arg = arguments.getReference(i); + + if (arg == option) + { + if (arg.isShortOption()) + { + if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption()) + { + auto result = arguments.getReference (i + 1).text; + arguments.removeRange (i, 2); + return result; + } + + arguments.remove (i); + return {}; + } + + if (arg.isLongOption()) + { + auto result = arg.getLongOptionValue(); + arguments.remove (i); + return result; + } + } } - return resolveFilename (text); + return {}; +} + +File ArgumentList::getFileForOption (StringRef option) const +{ + return resolveFilenameForOption (*this, option, getValueForOption (option)); +} + +File ArgumentList::getFileForOptionAndRemove (StringRef option) +{ + return resolveFilenameForOption (*this, option, removeValueForOption (option)); } File ArgumentList::getExistingFileForOption (StringRef option) const { - auto file = getFileForOption (option); - checkFileExists (file); - return file; + return checkFileExists (getFileForOption (option)); +} + +File ArgumentList::getExistingFileForOptionAndRemove (StringRef option) +{ + return checkFileExists (getFileForOptionAndRemove (option)); } File ArgumentList::getExistingFolderForOption (StringRef option) const { - auto file = getFileForOption (option); - checkFolderExists (file); - return file; + return checkFolderExists (getFileForOption (option)); +} + +File ArgumentList::getExistingFolderForOptionAndRemove (StringRef option) +{ + return checkFolderExists (getFileForOptionAndRemove (option)); } //============================================================================== @@ -269,7 +335,7 @@ const ConsoleApplication::Command* ConsoleApplication::findCommand (const Argume int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool optionMustBeFirstArg) const { if (auto c = findCommand (args, optionMustBeFirstArg)) - return invokeCatchingFailures ([=] { c->command (args); return 0; }); + return invokeCatchingFailures ([&args, c] { c->command (args); return 0; }); fail ("Unrecognised arguments"); return 0; diff --git a/modules/juce_core/misc/juce_ConsoleApplication.h b/modules/juce_core/misc/juce_ConsoleApplication.h index 336bb9d00f..6cdacf08b3 100644 --- a/modules/juce_core/misc/juce_ConsoleApplication.h +++ b/modules/juce_core/misc/juce_ConsoleApplication.h @@ -120,9 +120,17 @@ struct ArgumentList /** Returns true if the given string matches one of the arguments. The option can also be a list of different versions separated by pipes, e.g. "--help|-h" + @see removeOptionIfFound */ bool containsOption (StringRef option) const; + /** Returns true if the given string matches one of the arguments, and also removes the + argument from the list if found. + The option can also be a list of different versions separated by pipes, e.g. "--help|-h" + @see containsOption + */ + bool removeOptionIfFound (StringRef option); + /** Returns the index of the given string if it matches one of the arguments, or -1 if it doesn't. The option can also be a list of different versions separated by pipes, e.g. "--help|-h" */ @@ -142,23 +150,48 @@ struct ArgumentList */ String getValueForOption (StringRef option) const; - /** 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. + /** Looks for a given argument and returns either its assigned value (for long options) or the + string that follows it (for short options). + This works like getValueForOption() but also removes the option argument (and any value arguments) + from the list if they are found. + */ + String removeValueForOption (StringRef option); + + /** 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 getFileForOption (StringRef option) const; + /** Looks for the value of argument using getValueForOption() and tries to parse that value as a file. + This works like getFileForOption() but also removes the option argument (and any value arguments) + from the list if they are found. + */ + File getFileForOptionAndRemove (StringRef option); + /** Looks for a file argument using getFileForOption() and fails with a suitable error if the file doesn't exist. */ File getExistingFileForOption (StringRef option) const; + /** Looks for a file argument using getFileForOption() and fails with a suitable error if + the file doesn't exist. + This works like getExistingFileForOption() but also removes the option argument (and any + value arguments) from the list if they are found. + */ + File getExistingFileForOptionAndRemove (StringRef option); + /** Looks for a filename argument using getFileForOption() and fails with a suitable error if the file isn't a folder that exists. */ File getExistingFolderForOption (StringRef option) const; + /** Looks for a filename argument using getFileForOption() and fails with a suitable error if + the file isn't a folder that exists. + This works like getExistingFolderForOption() but also removes the option argument (and any + value arguments) from the list if they are found. + */ + File getExistingFolderForOptionAndRemove (StringRef option); + /** The name or path of the executable that was invoked, as it was specified on the command-line. */ String executableName;