The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. The code included in this file is provided under the terms of the ISC license
  8. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  9. To use, copy, modify, and/or distribute this software for any purpose with or
  10. without fee is hereby granted provided that the above copyright notice and
  11. this permission notice appear in all copies.
  12. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  13. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  14. DISCLAIMED.
  15. ==============================================================================
  16. */
  17. namespace juce
  18. {
  19. //==============================================================================
  20. /**
  21. Holds a list of command-line arguments, and provides useful methods for searching
  22. and operating on them.
  23. You can create an ArgumentList manually, or give it some argv/argc values from a
  24. main() function to parse.
  25. @see ConsoleApplication
  26. */
  27. struct ArgumentList
  28. {
  29. /** Creates an argument list for a given executable. */
  30. ArgumentList (String executable, StringArray arguments);
  31. /** Parses a standard argv/argc pair to create an argument list. */
  32. ArgumentList (int argc, char* argv[]);
  33. /** Tokenises a string containing all the arguments to create an argument list. */
  34. ArgumentList (const String& executable, const String& arguments);
  35. ArgumentList (const ArgumentList&) = default;
  36. ArgumentList& operator= (const ArgumentList&) = default;
  37. //==============================================================================
  38. /**
  39. One of the arguments in an ArgumentList.
  40. */
  41. struct Argument
  42. {
  43. /** The original text of this argument. */
  44. String text;
  45. /** Resolves this argument as an absolute File, using the current working
  46. directory as a base for resolving relative paths, and stripping quotes, etc.
  47. */
  48. File resolveAsFile() const;
  49. /** Resolves this argument as an absolute File, using the current working
  50. directory as a base for resolving relative paths, and also doing a check to
  51. make sure the file exists.
  52. If the file doesn't exist, this will call fail() with a suitable error.
  53. @see resolveAsFile, resolveAsExistingFolder
  54. */
  55. File resolveAsExistingFile() const;
  56. /** Resolves a user-supplied folder name into an absolute File, using the current working
  57. directory as a base for resolving relative paths, and also doing a check to make
  58. sure the folder exists.
  59. If the folder doesn't exist, this will call fail() with a suitable error.
  60. @see resolveAsFile, resolveAsExistingFile
  61. */
  62. File resolveAsExistingFolder() const;
  63. /** Returns true if this argument starts with a double dash. */
  64. bool isLongOption() const;
  65. /** Returns true if this argument starts with a single dash. */
  66. bool isShortOption() const;
  67. /** Returns true if this argument starts with a double dash, followed by the given string. */
  68. bool isLongOption (const String& optionRoot) const;
  69. /** Returns true if this argument starts with a single dash and then contains the given character somewhere inside it. */
  70. bool isShortOption (char shortOptionCharacter) const;
  71. /** Compares this argument against a string.
  72. The string may be a pipe-separated list of options, e.g. "--help|-h"
  73. */
  74. bool operator== (StringRef stringToCompare) const;
  75. /** Compares this argument against a string.
  76. The string may be a pipe-separated list of options, e.g. "--help|-h"
  77. */
  78. bool operator!= (StringRef stringToCompare) const;
  79. };
  80. //==============================================================================
  81. /** Returns the number of arguments in the list. */
  82. int size() const;
  83. /** Returns one of the arguments */
  84. Argument operator[] (int index) const;
  85. /** Throws an error unless there are at least the given number of arguments. */
  86. void checkMinNumArguments (int expectedMinNumberOfArgs) const;
  87. /** Returns true if the given string matches one of the arguments.
  88. The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
  89. */
  90. bool containsOption (StringRef option) const;
  91. /** Returns the index of the given string if it matches one of the arguments, or -1 if it doesn't.
  92. The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
  93. */
  94. int indexOfOption (StringRef option) const;
  95. /** Throws an error unless the given option is found in the argument list. */
  96. void failIfOptionIsMissing (StringRef option) const;
  97. /** Looks for the given argument and returns the one that follows it in the list.
  98. The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
  99. If the argument isn't found, this returns an empty string.
  100. */
  101. Argument getArgumentAfterOption (StringRef option) const;
  102. /** Looks for a given argument and tries to parse the following argument as a file.
  103. The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
  104. If the option isn't found, or if the next argument isn't a filename, it will throw
  105. an error.
  106. */
  107. File getFileAfterOption (StringRef option) const;
  108. /** Looks for a given argument and tries to parse the following argument as a file
  109. which must exist for this to succeed.
  110. The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
  111. If the option isn't found, or if the next argument isn't a filename, or if the file
  112. doesn't exist, or if it's a folder rather than a file, then it will throw a suitable error.
  113. */
  114. File getExistingFileAfterOption (StringRef option) const;
  115. /** Looks for a given argument and tries to parse the following argument as a folder
  116. which must exist for this to succeed.
  117. The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
  118. If the option isn't found, or if the next argument isn't a filename, or if it doesn't
  119. point to a folder, then it will throw a suitable error.
  120. */
  121. File getExistingFolderAfterOption (StringRef option) const;
  122. /** The name or path of the executable that was invoked, as it was specified on the command-line. */
  123. String executableName;
  124. /** The list of arguments (not including the name of the executable that was invoked). */
  125. Array<Argument> arguments;
  126. };
  127. //==============================================================================
  128. /**
  129. Represents a the set of commands that a console app can perform, and provides
  130. helper functions for performing them.
  131. When using these helper classes to implement a console app, you probably want to
  132. do something along these lines:
  133. @code
  134. int main (int argc, char* argv[])
  135. {
  136. ConsoleApplication app;
  137. app.addHelpCommand ("--help|-h", "Usage:", true);
  138. app.addVersionCommand ("--version|-v", "MyApp version 1.2.3");
  139. app.addCommand ({ "--foo",
  140. "--foo filename",
  141. "Performs a foo operation on the given file",
  142. [] (const auto& args) { doFoo (args); }});
  143. return app.findAndRunCommand (argc, argv);
  144. }
  145. @endcode
  146. @see ArgumentList
  147. */
  148. struct ConsoleApplication
  149. {
  150. //==============================================================================
  151. /**
  152. Represents a command that can be executed if its command-line arguments are matched.
  153. @see ConsoleApplication::addCommand(), ConsoleApplication::findAndRunCommand()
  154. */
  155. struct Command
  156. {
  157. /** The option string that must appear in the argument list for this command to be invoked.
  158. This can also be a list of different versions separated by pipes, e.g. "--help|-h"
  159. */
  160. String commandOption;
  161. /** A description of the command-line arguments needed for this command, which will be
  162. printed as part of the help text.
  163. */
  164. String argumentDescription;
  165. /** A description of the meaning of this command, for use in the help text. */
  166. String commandDescription;
  167. /** The actual command that should be invoked to perform this action. */
  168. std::function<void(const ArgumentList&)> command;
  169. };
  170. //==============================================================================
  171. /** Adds a command to the list. */
  172. void addCommand (Command);
  173. /** Adds a help command to the list.
  174. This command will print the user-supplied message that's passed in here as an
  175. argument, followed by a list of all the registered commands.
  176. */
  177. void addHelpCommand (String helpArgument, String helpMessage,
  178. bool invokeIfNoOtherCommandRecognised);
  179. /** Adds a command that will print the given text in response to the "--version" option. */
  180. void addVersionCommand (String versionArgument, String versionText);
  181. //==============================================================================
  182. /** Throws a failure exception to cause a command-line app to terminate.
  183. This is intended to be called from code in a Command, so that the
  184. exception will be automatically caught and turned into a printed error message
  185. and a return code which will be returned from main().
  186. @see ConsoleApplication::invokeCatchingFailures()
  187. */
  188. static void fail (String errorMessage, int returnCode = 1);
  189. /** Invokes a function, catching any fail() calls that it might trigger, and handling
  190. them by printing their error message and returning their error code.
  191. @see ConsoleApplication::fail()
  192. */
  193. static int invokeCatchingFailures (std::function<int()>&& functionToCall);
  194. //==============================================================================
  195. /** Looks for the first command in the list which matches the given arguments, and
  196. tries to invoke it.
  197. If no command is found, it prints a help message listing the available commands.
  198. If the command calls the fail() function, this will throw an exception that gets
  199. automatically caught and handled, and this method will return the error code that
  200. was passed into the fail() call.
  201. */
  202. int findAndRunCommand (const ArgumentList&) const;
  203. /** Creates an ArgumentList object from the argc and argv variablrs, and invokes
  204. findAndRunCommand() using it.
  205. */
  206. int findAndRunCommand (int argc, char* argv[]) const;
  207. private:
  208. //==============================================================================
  209. std::vector<Command> commands;
  210. String commandIfNoOthersRecognised;
  211. void printHelp (const String& preamble, const ArgumentList&) const;
  212. };
  213. } // namespace juce