OpenShot Audio Library | OpenShotAudio: juce_ConsoleApplication.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.4.0

Loading...
Searching...
No Matches
juce_ConsoleApplication.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
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 File resolveFilename (const String& name)
27{
28 return File::getCurrentWorkingDirectory().getChildFile (name.unquoted());
29}
30
31static File checkFileExists (const File& f)
32{
33 if (! f.exists())
34 ConsoleApplication::fail ("Could not find file: " + f.getFullPathName());
35
36 return f;
37}
38
39static File checkFolderExists (const File& f)
40{
41 if (! f.isDirectory())
42 ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
43
44 return f;
45}
46
47static File resolveFilenameForOption (const ArgumentList& args, StringRef option, const String& filename)
48{
49 if (filename.isEmpty())
50 {
51 args.failIfOptionIsMissing (option);
52 ConsoleApplication::fail ("Expected a filename after the " + option + " option");
53 }
54
55 return resolveFilename (filename);
56}
57
58 File ArgumentList::Argument::resolveAsFile() const
59{
60 return resolveFilename (text);
61}
62
63 File ArgumentList::Argument::resolveAsExistingFile() const
64{
65 return checkFileExists (resolveAsFile());
66}
67
68 File ArgumentList::Argument::resolveAsExistingFolder() const
69{
70 auto f = resolveAsFile();
71
72 if (! f.isDirectory())
73 ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
74
75 return f;
76}
77
78static bool isShortOptionFormat (StringRef s) { return s[0] == '-' && s[1] != '-'; }
79static bool isLongOptionFormat (StringRef s) { return s[0] == '-' && s[1] == '-' && s[2] != '-'; }
80static bool isOptionFormat (StringRef s) { return s[0] == '-'; }
81
82 bool ArgumentList::Argument::isLongOption() const { return isLongOptionFormat (text); }
83 bool ArgumentList::Argument::isShortOption() const { return isShortOptionFormat (text); }
84 bool ArgumentList::Argument::isOption() const { return isOptionFormat (text); }
85
86 bool ArgumentList::Argument::isLongOption (const String& option) const
87{
88 if (! isLongOptionFormat (option))
89 {
90 jassert (! isShortOptionFormat (option)); // this will always fail to match
91 return isLongOption ("--" + option);
92 }
93
94 return text.upToFirstOccurrenceOf ("=", false, false) == option;
95}
96
97 String ArgumentList::Argument::getLongOptionValue() const
98{
99 if (isLongOption())
100 {
101 auto equalsIndex = text.indexOfChar ('=');
102
103 if (equalsIndex > 0)
104 return text.substring (equalsIndex + 1);
105 }
106
107 return {};
108}
109
110 bool ArgumentList::Argument::isShortOption (char option) const
111{
112 jassert (option != '-'); // this is probably not what you intended to pass in
113
114 return isShortOption() && text.containsChar (String (option)[0]);
115}
116
117 bool ArgumentList::Argument::operator== (StringRef wildcard) const
118{
119 for (auto& o : StringArray::fromTokens (wildcard, "|", {}))
120 {
121 if (text == o)
122 return true;
123
124 if (isShortOptionFormat (o) && o.length() == 2 && isShortOption ((char) o[1]))
125 return true;
126
127 if (isLongOptionFormat (o) && isLongOption (o))
128 return true;
129 }
130
131 return false;
132}
133
134 bool ArgumentList::Argument::operator!= (StringRef s) const { return ! operator== (s); }
135
136//==============================================================================
137ArgumentList::ArgumentList (String exeName, StringArray args)
138 : executableName (std::move (exeName))
139{
140 args.trim();
141 args.removeEmptyStrings();
142
143 for (auto& a : args)
144 arguments.add ({ a.unquoted() });
145}
146
147 ArgumentList::ArgumentList (int argc, char* argv[])
148 : ArgumentList (argv[0], StringArray (argv + 1, argc - 1))
149{
150}
151
152 ArgumentList::ArgumentList (const String& exeName, const String& args)
153 : ArgumentList (exeName, StringArray::fromTokens (args, true))
154{
155}
156
157 int ArgumentList::size() const { return arguments.size(); }
158 ArgumentList::Argument ArgumentList::operator[] (int index) const { return arguments[index]; }
159
160 void ArgumentList::checkMinNumArguments (int expectedMinNumberOfArgs) const
161{
162 if (size() < expectedMinNumberOfArgs)
163 ConsoleApplication::fail ("Not enough arguments!");
164}
165
166 int ArgumentList::indexOfOption (StringRef option) const
167{
168 jassert (option == String (option).trim()); // passing non-trimmed strings will always fail to find a match!
169
170 for (int i = 0; i < arguments.size(); ++i)
171 if (arguments.getReference (i) == option)
172 return i;
173
174 return -1;
175}
176
177 bool ArgumentList::containsOption (StringRef option) const
178{
179 return indexOfOption (option) >= 0;
180}
181
182 bool ArgumentList::removeOptionIfFound (StringRef option)
183{
184 auto i = indexOfOption (option);
185
186 if (i >= 0)
187 arguments.remove (i);
188
189 return i >= 0;
190}
191
192 void ArgumentList::failIfOptionIsMissing (StringRef option) const
193{
194 if (indexOfOption (option) < 0)
195 ConsoleApplication::fail ("Expected the option " + option);
196}
197
198 String ArgumentList::getValueForOption (StringRef option) const
199{
200 jassert (isOptionFormat (option)); // the thing you're searching for must be an option
201
202 for (int i = 0; i < arguments.size(); ++i)
203 {
204 auto& arg = arguments.getReference (i);
205
206 if (arg == option)
207 {
208 if (arg.isShortOption())
209 {
210 if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption())
211 return arguments.getReference (i + 1).text;
212
213 return {};
214 }
215
216 if (arg.isLongOption())
217 return arg.getLongOptionValue();
218 }
219 }
220
221 return {};
222}
223
224 String ArgumentList::removeValueForOption (StringRef option)
225{
226 jassert (isOptionFormat (option)); // the thing you're searching for must be an option
227
228 for (int i = 0; i < arguments.size(); ++i)
229 {
230 auto& arg = arguments.getReference (i);
231
232 if (arg == option)
233 {
234 if (arg.isShortOption())
235 {
236 if (i < arguments.size() - 1 && ! arguments.getReference (i + 1).isOption())
237 {
238 auto result = arguments.getReference (i + 1).text;
239 arguments.removeRange (i, 2);
240 return result;
241 }
242
243 arguments.remove (i);
244 return {};
245 }
246
247 if (arg.isLongOption())
248 {
249 auto result = arg.getLongOptionValue();
250 arguments.remove (i);
251 return result;
252 }
253 }
254 }
255
256 return {};
257}
258
259 File ArgumentList::getFileForOption (StringRef option) const
260{
261 return resolveFilenameForOption (*this, option, getValueForOption (option));
262}
263
264 File ArgumentList::getFileForOptionAndRemove (StringRef option)
265{
266 return resolveFilenameForOption (*this, option, removeValueForOption (option));
267}
268
269 File ArgumentList::getExistingFileForOption (StringRef option) const
270{
271 return checkFileExists (getFileForOption (option));
272}
273
274 File ArgumentList::getExistingFileForOptionAndRemove (StringRef option)
275{
276 return checkFileExists (getFileForOptionAndRemove (option));
277}
278
279 File ArgumentList::getExistingFolderForOption (StringRef option) const
280{
281 return checkFolderExists (getFileForOption (option));
282}
283
284 File ArgumentList::getExistingFolderForOptionAndRemove (StringRef option)
285{
286 return checkFolderExists (getFileForOptionAndRemove (option));
287}
288
289//==============================================================================
290struct ConsoleAppFailureCode
291{
292 String errorMessage;
293 int returnCode;
294};
295
296 void ConsoleApplication::fail (String errorMessage, int returnCode)
297{
298 throw ConsoleAppFailureCode { std::move (errorMessage), returnCode };
299}
300
301 int ConsoleApplication::invokeCatchingFailures (std::function<int()>&& f)
302{
303 int returnCode = 0;
304
305 try
306 {
307 returnCode = f();
308 }
309 catch (const ConsoleAppFailureCode& error)
310 {
311 std::cerr << error.errorMessage << std::endl;
312 returnCode = error.returnCode;
313 }
314
315 return returnCode;
316}
317
318 const ConsoleApplication::Command* ConsoleApplication::findCommand (const ArgumentList& args, bool optionMustBeFirstArg) const
319{
320 for (auto& c : commands)
321 {
322 auto index = args.indexOfOption (c.commandOption);
323
324 if (optionMustBeFirstArg ? (index == 0) : (index >= 0))
325 return &c;
326 }
327
328 if (commandIfNoOthersRecognised >= 0)
329 return &commands[(size_t) commandIfNoOthersRecognised];
330
331 return {};
332}
333
334 int ConsoleApplication::findAndRunCommand (const ArgumentList& args, bool optionMustBeFirstArg) const
335{
336 return invokeCatchingFailures ([&args, optionMustBeFirstArg, this]
337 {
338 if (auto c = findCommand (args, optionMustBeFirstArg))
339 c->command (args);
340 else
341 fail ("Unrecognised arguments");
342
343 return 0;
344 });
345}
346
347 int ConsoleApplication::findAndRunCommand (int argc, char* argv[]) const
348{
349 return findAndRunCommand (ArgumentList (argc, argv));
350}
351
352 void ConsoleApplication::addCommand (Command c)
353{
354 commands.emplace_back (std::move (c));
355}
356
357 void ConsoleApplication::addDefaultCommand (Command c)
358{
359 commandIfNoOthersRecognised = (int) commands.size();
360 addCommand (std::move (c));
361}
362
363 void ConsoleApplication::addHelpCommand (String arg, String helpMessage, bool makeDefaultCommand)
364{
365 Command c { arg, arg, "Prints the list of commands", {},
366 [this, helpMessage] (const ArgumentList& args)
367 {
368 std::cout << helpMessage << std::endl;
369 printCommandList (args);
370 }};
371
372 if (makeDefaultCommand)
373 addDefaultCommand (std::move (c));
374 else
375 addCommand (std::move (c));
376}
377
378 void ConsoleApplication::addVersionCommand (String arg, String versionText)
379{
380 addCommand ({ arg, arg, "Prints the current version number", {},
381 [versionText] (const ArgumentList&)
382 {
383 std::cout << versionText << std::endl;
384 }});
385}
386
387 const std::vector<ConsoleApplication::Command>& ConsoleApplication::getCommands() const
388{
389 return commands;
390}
391
392static String getExeNameAndArgs (const ArgumentList& args, const ConsoleApplication::Command& command)
393{
394 auto exeName = args.executableName.fromLastOccurrenceOf ("/", false, false)
395 .fromLastOccurrenceOf ("\\", false, false);
396
397 return " " + exeName + " " + command.argumentDescription;
398}
399
400static void printCommandDescription (const ArgumentList& args, const ConsoleApplication::Command& command,
401 int descriptionIndent)
402{
403 auto nameAndArgs = getExeNameAndArgs (args, command);
404
405 if (nameAndArgs.length() > descriptionIndent)
406 std::cout << nameAndArgs << std::endl << String().paddedRight (' ', descriptionIndent);
407 else
408 std::cout << nameAndArgs.paddedRight (' ', descriptionIndent);
409
410 std::cout << command.shortDescription << std::endl;
411}
412
413 void ConsoleApplication::printCommandList (const ArgumentList& args) const
414{
415 int descriptionIndent = 0;
416
417 for (auto& c : commands)
418 descriptionIndent = std::max (descriptionIndent, getExeNameAndArgs (args, c).length());
419
420 descriptionIndent = std::min (descriptionIndent + 2, 40);
421
422 for (auto& c : commands)
423 printCommandDescription (args, c, descriptionIndent);
424
425 std::cout << std::endl;
426}
427
428 void ConsoleApplication::printCommandDetails (const ArgumentList& args, const Command& command) const
429{
430 auto len = getExeNameAndArgs (args, command).length();
431
432 printCommandDescription (args, command, std::min (len + 3, 40));
433
434 if (command.longDescription.isNotEmpty())
435 std::cout << std::endl << command.longDescription << std::endl;
436}
437
438
439} // namespace juce
juce::File
Definition juce_File.h:45
juce::File::getChildFile
File getChildFile(StringRef relativeOrAbsolutePath) const
Definition juce_File.cpp:420
juce::File::getCurrentWorkingDirectory
static File getCurrentWorkingDirectory()
juce::StringArray
Definition juce_StringArray.h:35
juce::StringArray::removeEmptyStrings
void removeEmptyStrings(bool removeWhitespaceStrings=true)
Definition juce_StringArray.cpp:250
juce::StringArray::fromTokens
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Definition juce_StringArray.cpp:387
juce::StringArray::trim
void trim()
Definition juce_StringArray.cpp:266
juce::StringRef
Definition juce_StringRef.h:62
juce::String
Definition juce_String.h:53
juce::String::length
int length() const noexcept
Definition juce_String.cpp:511
juce::String::fromLastOccurrenceOf
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Definition juce_String.cpp:1575
juce::String::isNotEmpty
bool isNotEmpty() const noexcept
Definition juce_String.h:316
juce::ArgumentList::Argument
Definition juce_ConsoleApplication.h:59
juce::ArgumentList::Argument::operator!=
bool operator!=(StringRef stringToCompare) const
Definition juce_ConsoleApplication.cpp:134
juce::ArgumentList::Argument::resolveAsExistingFile
File resolveAsExistingFile() const
Definition juce_ConsoleApplication.cpp:63
juce::ArgumentList::Argument::text
String text
Definition juce_ConsoleApplication.h:61
juce::ArgumentList::Argument::isLongOption
bool isLongOption() const
Definition juce_ConsoleApplication.cpp:82
juce::ArgumentList::Argument::isLongOption
bool isLongOption(const String &optionRoot) const
Definition juce_ConsoleApplication.cpp:86
juce::ArgumentList::Argument::resolveAsExistingFolder
File resolveAsExistingFolder() const
Definition juce_ConsoleApplication.cpp:68
juce::ArgumentList::Argument::isShortOption
bool isShortOption() const
Definition juce_ConsoleApplication.cpp:83
juce::ArgumentList::Argument::resolveAsFile
File resolveAsFile() const
Definition juce_ConsoleApplication.cpp:58
juce::ArgumentList::Argument::operator==
bool operator==(StringRef stringToCompare) const
Definition juce_ConsoleApplication.cpp:117
juce::ArgumentList::Argument::getLongOptionValue
String getLongOptionValue() const
Definition juce_ConsoleApplication.cpp:97
juce::ArgumentList::Argument::isOption
bool isOption() const
Definition juce_ConsoleApplication.cpp:84
juce::ArgumentList
Definition juce_ConsoleApplication.h:39
juce::ArgumentList::getExistingFileForOptionAndRemove
File getExistingFileForOptionAndRemove(StringRef option)
Definition juce_ConsoleApplication.cpp:274
juce::ArgumentList::removeValueForOption
String removeValueForOption(StringRef option)
Definition juce_ConsoleApplication.cpp:224
juce::ArgumentList::getExistingFileForOption
File getExistingFileForOption(StringRef option) const
Definition juce_ConsoleApplication.cpp:269
juce::ArgumentList::removeOptionIfFound
bool removeOptionIfFound(StringRef option)
Definition juce_ConsoleApplication.cpp:182
juce::ArgumentList::getExistingFolderForOption
File getExistingFolderForOption(StringRef option) const
Definition juce_ConsoleApplication.cpp:279
juce::ArgumentList::indexOfOption
int indexOfOption(StringRef option) const
Definition juce_ConsoleApplication.cpp:166
juce::ArgumentList::executableName
String executableName
Definition juce_ConsoleApplication.h:200
juce::ArgumentList::getFileForOption
File getFileForOption(StringRef option) const
Definition juce_ConsoleApplication.cpp:259
juce::ArgumentList::failIfOptionIsMissing
void failIfOptionIsMissing(StringRef option) const
Definition juce_ConsoleApplication.cpp:192
juce::ArgumentList::arguments
Array< Argument > arguments
Definition juce_ConsoleApplication.h:203
juce::ArgumentList::containsOption
bool containsOption(StringRef option) const
Definition juce_ConsoleApplication.cpp:177
juce::ArgumentList::checkMinNumArguments
void checkMinNumArguments(int expectedMinNumberOfArgs) const
Definition juce_ConsoleApplication.cpp:160
juce::ArgumentList::getValueForOption
String getValueForOption(StringRef option) const
Definition juce_ConsoleApplication.cpp:198
juce::ArgumentList::operator[]
Argument operator[](int index) const
Definition juce_ConsoleApplication.cpp:158
juce::ArgumentList::size
int size() const
Definition juce_ConsoleApplication.cpp:157
juce::ArgumentList::ArgumentList
ArgumentList(String executable, StringArray arguments)
Definition juce_ConsoleApplication.cpp:137
juce::ArgumentList::getFileForOptionAndRemove
File getFileForOptionAndRemove(StringRef option)
Definition juce_ConsoleApplication.cpp:264
juce::ArgumentList::getExistingFolderForOptionAndRemove
File getExistingFolderForOptionAndRemove(StringRef option)
Definition juce_ConsoleApplication.cpp:284
juce::ConsoleApplication::printCommandDetails
void printCommandDetails(const ArgumentList &, const Command &) const
Definition juce_ConsoleApplication.cpp:428
juce::ConsoleApplication::findAndRunCommand
int findAndRunCommand(const ArgumentList &, bool optionMustBeFirstArg=false) const
Definition juce_ConsoleApplication.cpp:334
juce::ConsoleApplication::addDefaultCommand
void addDefaultCommand(Command)
Definition juce_ConsoleApplication.cpp:357
juce::ConsoleApplication::Command::argumentDescription
String argumentDescription
Definition juce_ConsoleApplication.h:256
juce::ConsoleApplication::printCommandList
void printCommandList(const ArgumentList &) const
Definition juce_ConsoleApplication.cpp:413
juce::ConsoleApplication::findCommand
const Command * findCommand(const ArgumentList &, bool optionMustBeFirstArg) const
Definition juce_ConsoleApplication.cpp:318
juce::ConsoleApplication::addCommand
void addCommand(Command)
Definition juce_ConsoleApplication.cpp:352
juce::ConsoleApplication::invokeCatchingFailures
static int invokeCatchingFailures(std::function< int()> &&functionToCall)
Definition juce_ConsoleApplication.cpp:301
juce::ConsoleApplication::addHelpCommand
void addHelpCommand(String helpArgument, String helpMessage, bool makeDefaultCommand)
Definition juce_ConsoleApplication.cpp:363
juce::ConsoleApplication::addVersionCommand
void addVersionCommand(String versionArgument, String versionText)
Definition juce_ConsoleApplication.cpp:378
juce::ConsoleApplication::fail
static void fail(String errorMessage, int returnCode=1)
Definition juce_ConsoleApplication.cpp:296
juce::ConsoleApplication::getCommands
const std::vector< Command > & getCommands() const
Definition juce_ConsoleApplication.cpp:387
juce::ConsoleApplication::Command::longDescription
String longDescription
Definition juce_ConsoleApplication.h:264
juce::ConsoleApplication::Command
Definition juce_ConsoleApplication.h:247