OpenShot Library | libopenshot-audio 0.2.0
juce_ConsoleApplication.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26static inline File resolveFilename (const String& name)
27{
28 return File::getCurrentWorkingDirectory().getChildFile (name.unquoted());
29}
30
31static inline void checkFileExists (const File& f)
32{
33 if (! f.exists())
34 ConsoleApplication::fail ("Could not find file: " + f.getFullPathName());
35}
36
37static inline void checkFolderExists (const File& f)
38{
39 if (! f.isDirectory())
40 ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
41}
42
44{
45 return resolveFilename (text);
46}
47
49{
50 auto f = resolveAsFile();
51 checkFileExists (f);
52 return f;
53}
54
56{
57 auto f = resolveAsFile();
58
59 if (! f.isDirectory())
60 ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
61
62 return f;
63}
64
65static inline bool isShortOptionFormat (StringRef s) { return s[0] == '-' && s[1] != '-'; }
66static inline bool isLongOptionFormat (StringRef s) { return s[0] == '-' && s[1] == '-' && s[2] != '-'; }
67static inline bool isOptionFormat (StringRef s) { return s[0] == '-'; }
68
69bool ArgumentList::Argument::isLongOption() const { return isLongOptionFormat (text); }
70bool ArgumentList::Argument::isShortOption() const { return isShortOptionFormat (text); }
71bool ArgumentList::Argument::isOption() const { return isOptionFormat (text); }
72
74{
75 if (! isLongOptionFormat (option))
76 {
77 jassert (! isShortOptionFormat (option)); // this will always fail to match
78 return isLongOption ("--" + option);
79 }
80
81 return text.upToFirstOccurrenceOf ("=", false, false) == option;
82}
83
85{
86 if (isLongOption())
87 if (auto equalsIndex = text.indexOfChar ('='))
88 return text.substring (equalsIndex + 1);
89
90 return {};
91}
92
94{
95 jassert (option != '-'); // this is probably not what you intended to pass in
96
97 return isShortOption() && text.containsChar (option);
98}
99
101{
102 for (auto& o : StringArray::fromTokens (wildcard, "|", {}))
103 {
104 if (text == o)
105 return true;
106
107 if (isShortOptionFormat (o) && o.length() == 2 && isShortOption ((char) o[1]))
108 return true;
109
110 if (isLongOptionFormat (o) && isLongOption (o))
111 return true;
112 }
113
114 return false;
115}
116
117bool ArgumentList::Argument::operator!= (StringRef s) const { return ! operator== (s); }
118
119//==============================================================================
121 : executableName (std::move (exeName))
122{
123 args.trim();
124 args.removeEmptyStrings();
125
126 for (auto& a : args)
127 arguments.add ({ a });
128}
129
130ArgumentList::ArgumentList (int argc, char* argv[])
131 : ArgumentList (argv[0], StringArray (argv + 1, argc - 1))
132{
133}
134
135ArgumentList::ArgumentList (const String& exeName, const String& args)
136 : ArgumentList (exeName, StringArray::fromTokens (args, true))
137{
138}
139
140int ArgumentList::size() const { return arguments.size(); }
142
143void ArgumentList::checkMinNumArguments (int expectedMinNumberOfArgs) const
144{
145 if (size() < expectedMinNumberOfArgs)
146 ConsoleApplication::fail ("Not enough arguments!");
147}
148
150{
151 jassert (option == String (option).trim()); // passing non-trimmed strings will always fail to find a match!
152
153 for (int i = 0; i < arguments.size(); ++i)
154 if (arguments.getReference(i) == option)
155 return i;
156
157 return -1;
158}
159
161{
162 return indexOfOption (option) >= 0;
163}
164
166{
167 if (! containsOption (option))
168 ConsoleApplication::fail ("Expected the option " + option);
169}
170
172{
173 jassert (isOptionFormat (option)); // the thing you're searching for must be an option
174
175 for (int i = 0; i < arguments.size(); ++i)
176 {
177 auto& arg = arguments.getReference(i);
178
179 if (arg == option)
180 {
181 if (arg.isShortOption())
182 {
183 if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption())
184 return arguments.getReference (i + 1).text;
185
186 return {};
187 }
188
189 if (arg.isLongOption())
190 return arg.getLongOptionValue();
191 }
192 }
193
194 return {};
195}
196
198{
199 auto text = getValueForOption (option);
200
201 if (text.isEmpty())
202 {
203 failIfOptionIsMissing (option);
204 ConsoleApplication::fail ("Expected a filename after the " + option + " option");
205 }
206
207 return resolveFilename (text);
208}
209
211{
212 auto file = getFileForOption (option);
213 checkFileExists (file);
214 return file;
215}
216
218{
219 auto file = getFileForOption (option);
220 checkFolderExists (file);
221 return file;
222}
223
224//==============================================================================
226{
227 String errorMessage;
228 int returnCode;
229};
230
231void ConsoleApplication::fail (String errorMessage, int returnCode)
232{
233 throw ConsoleAppFailureCode { std::move (errorMessage), returnCode };
234}
235
236int ConsoleApplication::invokeCatchingFailures (std::function<int()>&& f)
237{
238 int returnCode = 0;
239
240 try
241 {
242 returnCode = f();
243 }
244 catch (const ConsoleAppFailureCode& error)
245 {
246 std::cout << error.errorMessage << std::endl;
247 returnCode = error.returnCode;
248 }
249
250 return returnCode;
251}
252
253const ConsoleApplication::Command* ConsoleApplication::findCommand (const ArgumentList& args, bool optionMustBeFirstArg) const
254{
255 for (auto& c : commands)
256 {
257 auto index = args.indexOfOption (c.commandOption);
258
259 if (optionMustBeFirstArg ? (index == 0) : (index >= 0))
260 return &c;
261 }
262
263 if (commandIfNoOthersRecognised >= 0)
264 return &commands[(size_t) commandIfNoOthersRecognised];
265
266 return {};
267}
268
269int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool optionMustBeFirstArg) const
270{
271 if (auto c = findCommand (args, optionMustBeFirstArg))
272 return invokeCatchingFailures ([=] { c->command (args); return 0; });
273
274 fail ("Unrecognised arguments");
275 return 0;
276}
277
278int ConsoleApplication::findAndRunCommand (int argc, char* argv[]) const
279{
280 return findAndRunCommand (ArgumentList (argc, argv));
281}
282
284{
285 commands.emplace_back (std::move (c));
286}
287
289{
290 commandIfNoOthersRecognised = (int) commands.size();
291 addCommand (std::move (c));
292}
293
294void ConsoleApplication::addHelpCommand (String arg, String helpMessage, bool makeDefaultCommand)
295{
296 Command c { arg, arg, "Prints the list of commands", {},
297 [this, helpMessage] (const ArgumentList& args)
298 {
299 std::cout << helpMessage << std::endl;
300 printCommandList (args);
301 }};
302
303 if (makeDefaultCommand)
304 addDefaultCommand (std::move (c));
305 else
306 addCommand (std::move (c));
307}
308
310{
311 addCommand ({ arg, arg, "Prints the current version number", {},
312 [versionText] (const ArgumentList&)
313 {
314 std::cout << versionText << std::endl;
315 }});
316}
317
318const std::vector<ConsoleApplication::Command>& ConsoleApplication::getCommands() const
319{
320 return commands;
321}
322
324{
325 auto exeName = args.executableName.fromLastOccurrenceOf ("/", false, false)
326 .fromLastOccurrenceOf ("\\", false, false);
327
328 StringArray namesAndArgs;
329 int descriptionIndent = 0;
330
331 for (auto& c : commands)
332 {
333 auto nameAndArgs = exeName + " " + c.argumentDescription;
334 namesAndArgs.add (nameAndArgs);
335 descriptionIndent = std::max (descriptionIndent, nameAndArgs.length());
336 }
337
338 descriptionIndent = std::min (descriptionIndent + 1, 40);
339
340 for (size_t i = 0; i < commands.size(); ++i)
341 {
342 auto nameAndArgs = namesAndArgs[(int) i];
343 std::cout << ' ';
344
345 if (nameAndArgs.length() > descriptionIndent)
346 std::cout << nameAndArgs << std::endl << String::repeatedString (" ", descriptionIndent + 1);
347 else
348 std::cout << nameAndArgs.paddedRight (' ', descriptionIndent);
349
350 std::cout << commands[i].shortDescription << std::endl;
351 }
352
353 std::cout << std::endl;
354}
355
356} // namespace juce
Represents a local file or directory.
Definition juce_File.h:45
File getChildFile(StringRef relativeOrAbsolutePath) const
Returns a file that represents a relative (or absolute) sub-path of the current one.
static File getCurrentWorkingDirectory()
Returns the current working directory.
A special array for holding a list of strings.
void removeEmptyStrings(bool removeWhitespaceStrings=true)
Removes empty strings from the array.
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Returns an array containing the tokens in a given string.
void trim()
Deletes any whitespace characters from the starts and ends of all the strings.
void add(String stringToAdd)
Appends a string at the end of the array.
A simple class for holding temporary references to a string literal or String.
The JUCE String class!
Definition juce_String.h:43
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
Creates a string which is a version of a string repeated and joined together.
String paddedRight(juce_wchar padCharacter, int minimumLength) const
Returns a copy of this string with the specified character repeatedly added to its end until the tota...
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from the last occurrence of a given substring.
Represents a command that can be executed if its command-line arguments are matched.
One of the arguments in an ArgumentList.
bool operator!=(StringRef stringToCompare) const
Compares this argument against a string.
File resolveAsExistingFile() const
Resolves this argument as an absolute File, using the current working directory as a base for resolvi...
String text
The original text of this argument.
bool isLongOption() const
Returns true if this argument starts with a double dash.
File resolveAsExistingFolder() const
Resolves a user-supplied folder name into an absolute File, using the current working directory as a ...
bool isShortOption() const
Returns true if this argument starts with a single dash.
File resolveAsFile() const
Resolves this argument as an absolute File, using the current working directory as a base for resolvi...
bool operator==(StringRef stringToCompare) const
Compares this argument against a string.
String getLongOptionValue() const
If this argument is a long option with a value, this returns the value.
bool isOption() const
Returns true if this argument starts with one or more dashes.
Holds a list of command-line arguments, and provides useful methods for searching and operating on th...
File getExistingFileForOption(StringRef option) const
Looks for a file argument using getFileForOption() and fails with a suitable error if the file doesn'...
File getExistingFolderForOption(StringRef option) const
Looks for a filename argument using getFileForOption() and fails with a suitable error if the file is...
int indexOfOption(StringRef option) const
Returns the index of the given string if it matches one of the arguments, or -1 if it doesn't.
String executableName
The name or path of the executable that was invoked, as it was specified on the command-line.
File getFileForOption(StringRef option) const
Looks for the value of argument using getValueForOption() and tries to parse that value as a file.
void failIfOptionIsMissing(StringRef option) const
Throws an error unless the given option is found in the argument list.
Array< Argument > arguments
The list of arguments (not including the name of the executable that was invoked).
bool containsOption(StringRef option) const
Returns true if the given string matches one of the arguments.
void checkMinNumArguments(int expectedMinNumberOfArgs) const
Throws an error unless there are at least the given number of arguments.
String getValueForOption(StringRef option) const
Looks for a given argument and returns either its assigned value (for long options) or the string tha...
Argument operator[](int index) const
Returns one of the arguments.
int size() const
Returns the number of arguments in the list.
ArgumentList(String executable, StringArray arguments)
Creates an argument list for a given executable.
int findAndRunCommand(const ArgumentList &, bool optionMustBeFirstArg=false) const
Looks for the first command in the list which matches the given arguments, and tries to invoke it.
void addDefaultCommand(Command)
Adds a command to the list, and marks it as one which is invoked if no other command matches.
void printCommandList(const ArgumentList &) const
Prints out the list of commands and their short descriptions in a format that's suitable for use as h...
const Command * findCommand(const ArgumentList &, bool optionMustBeFirstArg) const
Looks for the first command in the list which matches the given arguments.
void addCommand(Command)
Adds a command to the list.
static int invokeCatchingFailures(std::function< int()> &&functionToCall)
Invokes a function, catching any fail() calls that it might trigger, and handling them by printing th...
void addHelpCommand(String helpArgument, String helpMessage, bool makeDefaultCommand)
Adds a help command to the list.
void addVersionCommand(String versionArgument, String versionText)
Adds a command that will print the given text in response to the "--version" option.
static void fail(String errorMessage, int returnCode=1)
Throws a failure exception to cause a command-line app to terminate.
const std::vector< Command > & getCommands() const
Gives read-only access to the list of registered commands.