OpenShot Library | libopenshot-audio  0.1.9
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 
23 namespace juce
24 {
25 
26 static inline File resolveFilename (const String& name)
27 {
28  return File::getCurrentWorkingDirectory().getChildFile (name.unquoted());
29 }
30 
31 static inline void checkFileExists (const File& f)
32 {
33  if (! f.exists())
34  ConsoleApplication::fail ("Could not find file: " + f.getFullPathName());
35 }
36 
37 static 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 
65 static inline bool isShortOptionFormat (StringRef s) { return s[0] == '-' && s[1] != '-'; }
66 static inline bool isLongOptionFormat (StringRef s) { return s[0] == '-' && s[1] == '-' && s[2] != '-'; }
67 static inline bool isOptionFormat (StringRef s) { return s[0] == '-'; }
68 
69 bool ArgumentList::Argument::isLongOption() const { return isLongOptionFormat (text); }
70 bool ArgumentList::Argument::isShortOption() const { return isShortOptionFormat (text); }
71 bool ArgumentList::Argument::isOption() const { return isOptionFormat (text); }
72 
73 bool ArgumentList::Argument::isLongOption (const String& option) const
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 
93 bool ArgumentList::Argument::isShortOption (char option) const
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 
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 
130 ArgumentList::ArgumentList (int argc, char* argv[])
131  : ArgumentList (argv[0], StringArray (argv + 1, argc - 1))
132 {
133 }
134 
135 ArgumentList::ArgumentList (const String& exeName, const String& args)
136  : ArgumentList (exeName, StringArray::fromTokens (args, true))
137 {
138 }
139 
140 int ArgumentList::size() const { return arguments.size(); }
141 ArgumentList::Argument ArgumentList::operator[] (int index) const { return arguments[index]; }
142 
143 void 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 
231 void ConsoleApplication::fail (String errorMessage, int returnCode)
232 {
233  throw ConsoleAppFailureCode { std::move (errorMessage), returnCode };
234 }
235 
236 int 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 
253 const 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 
269 int 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 
278 int 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 
294 void 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 
318 const 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
Array< Argument > arguments
The list of arguments (not including the name of the executable that was invoked).
String getLongOptionValue() const
If this argument is a long option with a value, this returns the value.
ArgumentList(String executable, StringArray arguments)
Creates an argument list for a given executable.
bool isShortOption() const
Returns true if this argument starts with a single dash.
bool isOption() const
Returns true if this argument starts with one or more dashes.
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...
String text
The original text of this argument.
String getValueForOption(StringRef option) const
Looks for a given argument and returns either its assigned value (for long options) or the string tha...
A simple class for holding temporary references to a string literal or String.
int indexOfOption(StringRef option) const
Returns the index of the given string if it matches one of the arguments, or -1 if it doesn&#39;t...
Holds a list of command-line arguments, and provides useful methods for searching and operating on th...
void removeEmptyStrings(bool removeWhitespaceStrings=true)
Removes empty strings from the array.
static void fail(String errorMessage, int returnCode=1)
Throws a failure exception to cause a command-line app to terminate.
File getFileForOption(StringRef option) const
Looks for the value of argument using getValueForOption() and tries to parse that value as a file...
bool containsChar(juce_wchar character) const noexcept
Tests whether the string contains a particular character.
STL namespace.
A special array for holding a list of strings.
File getChildFile(StringRef relativeOrAbsolutePath) const
Returns a file that represents a relative (or absolute) sub-path of the current one.
Definition: juce_File.cpp:394
The JUCE String class!
Definition: juce_String.h:42
const Command * findCommand(const ArgumentList &, bool optionMustBeFirstArg) const
Looks for the first command in the list which matches the given arguments.
void trim()
Deletes any whitespace characters from the starts and ends of all the strings.
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from the last occurrence of a given substring.
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...
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
Creates a string which is a version of a string repeated and joined together.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
void addCommand(Command)
Adds a command to the list.
Represents a command that can be executed if its command-line arguments are matched.
void addDefaultCommand(Command)
Adds a command to the list, and marks it as one which is invoked if no other command matches...
Argument operator[](int index) const
Returns one of the arguments.
bool operator!=(StringRef stringToCompare) const
Compares this argument against a string.
File resolveAsExistingFolder() const
Resolves a user-supplied folder name into an absolute File, using the current working directory as a ...
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Returns an array containing the tokens in a given string.
const std::vector< Command > & getCommands() const
Gives read-only access to the list of registered commands.
One of the arguments in an ArgumentList.
Represents a local file or directory.
Definition: juce_File.h:44
File resolveAsFile() const
Resolves this argument as an absolute File, using the current working directory as a base for resolvi...
File resolveAsExistingFile() const
Resolves this argument as an absolute File, using the current working directory as a base for resolvi...
File getExistingFileForOption(StringRef option) const
Looks for a file argument using getFileForOption() and fails with a suitable error if the file doesn&#39;...
void checkMinNumArguments(int expectedMinNumberOfArgs) const
Throws an error unless there are at least the given number of arguments.
void addHelpCommand(String helpArgument, String helpMessage, bool makeDefaultCommand)
Adds a help command to the list.
String executableName
The name or path of the executable that was invoked, as it was specified on the command-line.
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Returns the start of this string, up to the first occurrence of a substring.
void printCommandList(const ArgumentList &) const
Prints out the list of commands and their short descriptions in a format that&#39;s suitable for use as h...
bool operator==(StringRef stringToCompare) const
Compares this argument against a string.
void failIfOptionIsMissing(StringRef option) const
Throws an error unless the given option is found in the argument list.
int size() const
Returns the number of arguments in the list.
bool isLongOption() const
Returns true if this argument starts with a double dash.
int indexOfChar(juce_wchar characterToLookFor) const noexcept
Searches for a character inside this string.
static File getCurrentWorkingDirectory()
Returns the current working directory.
static int invokeCatchingFailures(std::function< int()> &&functionToCall)
Invokes a function, catching any fail() calls that it might trigger, and handling them by printing th...
File getExistingFolderForOption(StringRef option) const
Looks for a filename argument using getFileForOption() and fails with a suitable error if the file is...
void add(String stringToAdd)
Appends a string at the end of the array.
bool containsOption(StringRef option) const
Returns true if the given string matches one of the arguments.
void addVersionCommand(String versionArgument, String versionText)
Adds a command that will print the given text in response to the "--version" option.