diff options
author | David Robillard <d@drobilla.net> | 2015-04-04 09:27:49 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2015-04-04 09:27:49 +0000 |
commit | 9c5ad6b64f33ea07654435e93a8b6f726894581f (patch) | |
tree | cd83370c2a06707dff0b731c084741a737d5b972 | |
parent | 52bce39f06f607dd363ca8f3b774fda658036cf4 (diff) | |
download | ingen-9c5ad6b64f33ea07654435e93a8b6f726894581f.tar.gz ingen-9c5ad6b64f33ea07654435e93a8b6f726894581f.tar.bz2 ingen-9c5ad6b64f33ea07654435e93a8b6f726894581f.zip |
Support GNU style long options.
Update usage output and man page to distinguish flags from options
that take a value.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5660 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r-- | doc/ingen.1 | 22 | ||||
-rw-r--r-- | ingen/Configuration.hpp | 6 | ||||
-rw-r--r-- | src/Configuration.cpp | 110 | ||||
-rw-r--r-- | src/ingen/ingen.cpp | 30 |
4 files changed, 93 insertions, 75 deletions
diff --git a/doc/ingen.1 b/doc/ingen.1 index d646cef0..3234611f 100644 --- a/doc/ingen.1 +++ b/doc/ingen.1 @@ -1,4 +1,4 @@ -.TH INGEN 1 "08 Feb 2015" +.TH INGEN 1 "04 Apr 2015" .SH NAME .B ingen \- A realtime modular audio processor @@ -9,16 +9,16 @@ ingen [OPTION]... .SH OPTIONS .TP -\fB\-C, \-\-client\-port\fR +\fB\-C, \-\-client\-port\fR=\fIINT\fR Client port .TP -\fB\-c, \-\-connect\fR +\fB\-c, \-\-connect\fR=\fISTRING\fR Connect to engine URI .TP \fB\-e, \-\-engine\fR Run (JACK) engine .TP -\fB\-E, \-\-engine-port\fR +\fB\-E, \-\-engine-port\fR=\fIINT\fR Engine listen port .TP \fB\-\-graph\-directory\fR @@ -33,31 +33,31 @@ Print this help message \fB\-\-human\-names\fR Show human names in GUI .TP -\fB\-n, \-\-jack\-name\fR +\fB\-n, \-\-jack\-name\fR=\fISTRING\fR JACK name .TP -\fB\-s, \-\-jack\-server\fR +\fB\-s, \-\-jack\-server\fR=\fISTRING\fR JACK server name .TP -\fB\-l, \-\-load\fR +\fB\-l, \-\-load\fR=\fISTRING\fR Load graph .TP -\fB\-L, \-\-path\fR +\fB\-L, \-\-path\fR=\fISTRING\fR Target path for loaded graph .TP \fB\-\-port\-labels\fR Show port labels in GUI .TP -\fB\-q, \-\-queue-size\fR +\fB\-q, \-\-queue-size\fR=\fIINT\fR Event queue size .TP \fB\-r, \-\-run\fR Run script .TP -\fB\-S, \-\-socket\fR +\fB\-S, \-\-socket\fR=\fISTRING\fR Engine socket path .TP -\fB\-u, \-\-uuid\fR +\fB\-u, \-\-uuid\fR=\fISTRING\fR JACK session UUID .TP \fB\-V, \-\-version\fR diff --git a/ingen/Configuration.hpp b/ingen/Configuration.hpp index a9087ea6..28b6a19d 100644 --- a/ingen/Configuration.hpp +++ b/ingen/Configuration.hpp @@ -115,8 +115,6 @@ public: const Atom& option(const std::string& long_name) const; bool set(const std::string& long_name, const Atom& value); - const std::list<std::string>& files() const { return _files; } - private: struct Option { public: @@ -146,7 +144,8 @@ private: typedef std::map<std::string, Option> Options; typedef std::map<char, std::string> ShortNames; typedef std::map<std::string, std::string> Keys; - typedef std::list<std::string> Files; + + std::string variable_string(LV2_URID type) const; int set_value_from_string(Configuration::Option& option, const std::string& value) @@ -158,7 +157,6 @@ private: Options _options; Keys _keys; ShortNames _short_names; - Files _files; size_t _max_name_length; }; diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 07beeea7..efcd2806 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -36,16 +36,15 @@ Configuration::Configuration(Forge& forge) , _shortdesc("A realtime modular audio processor.") , _desc( "Ingen is a flexible modular system that be used in various ways.\n" - "The engine can run as a stand-alone server controlled via network protocol,\n" - "or internal to another process (e.g. the GUI). The GUI, or other clients,\n" - "can communicate with the engine via any supported protocol, or run in the\n" - "same process. Many clients can connect to an engine at once.\n\n" + "The engine can run as a server controlled via a network protocol,\n" + "as an LV2 plugin, or in a monolithic process with a GUI. The GUI\n" + "may be run separate to control a remote engine, and many clients\n" + "may connect to an engine at once.\n\n" "Examples:\n" - " ingen -e # Run an engine, listen for connections\n" - " ingen -g # Run a GUI, connect to running engine\n" - " ingen -eg # Run an engine and a GUI in one process\n" - " ingen -egl foo.ttl # Run an engine and a GUI and load a graph\n" - " ingen -egl foo.ingen # Run an engine and a GUI and load a graph") + " ingen -e # Run engine, listen for connections\n" + " ingen -g # Run GUI, connect to running engine\n" + " ingen -eg # Run engine and GUI in one process\n" + " ingen -eg foo.ingen # Run engine and GUI and load a graph") , _max_name_length(0) { add("clientPort", "client-port", 'C', "Client port", SESSION, forge.Int, Atom()); @@ -88,22 +87,34 @@ Configuration::add(const std::string& key, return *this; } +std::string +Configuration::variable_string(LV2_URID type) const +{ + if (type == _forge.String) { + return "=STRING"; + } else if (type == _forge.Int) { + return "=INT"; + } + return ""; +} + void Configuration::print_usage(const std::string& program, std::ostream& os) { - os << "Usage: " << program << " [OPTION]..." << std::endl; + os << "Usage: " << program << " [OPTION]... [GRAPH]" << std::endl; os << _shortdesc << std::endl << std::endl; os << _desc << std::endl << std::endl; os << "Options:" << std::endl; - for (auto o : _options) { - Option& option = o.second; + for (const auto& o : _options) { + const Option& option = o.second; os << " "; if (option.letter != '\0') os << "-" << option.letter << ", "; else os << " "; - os.width(_max_name_length + 4); - os << std::left << (std::string("--") + o.first); + os.width(_max_name_length + 11); + os << std::left; + os << (std::string("--") + o.first + variable_string(option.type)); os << option.desc << std::endl; } } @@ -120,7 +131,7 @@ Configuration::set_value_from_string(Configuration::Option& option, option.value = _forge.make(intval); } else { throw OptionError( - (fmt("option `%1%' has non-integer value `%2%'") + (fmt("Option `%1%' has non-integer value `%2%'") % option.name % value).str()); } } else if (option.type == _forge.String) { @@ -131,7 +142,7 @@ Configuration::set_value_from_string(Configuration::Option& option, assert(option.value.type() == _forge.Bool); } else { throw OptionError( - (fmt("bad option type `%1%'") % option.name).str()); + (fmt("Bad option type `%1%'") % option.name).str()); } return EXIT_SUCCESS; } @@ -142,45 +153,60 @@ Configuration::parse(int argc, char** argv) throw (Configuration::OptionError) { for (int i = 1; i < argc; ++i) { if (argv[i][0] != '-' || !strcmp(argv[i], "-")) { - _files.push_back(argv[i]); + // File argument + const Options::iterator o = _options.find("load"); + if (!o->second.value.is_valid()) { + _options.find("load")->second.value = _forge.alloc(argv[i]); + } else { + throw OptionError("Multiple graphs specified"); + } } else if (argv[i][1] == '-') { - const std::string name = std::string(argv[i]).substr(2); - Options::iterator o = _options.find(name); + // Long option + std::string name = std::string(argv[i]).substr(2); + const char* equals = strchr(argv[i], '='); + if (equals) { + name = name.substr(0, name.find('=')); + } + + const Options::iterator o = _options.find(name); if (o == _options.end()) { throw OptionError( - (fmt("unrecognized option `%1%'") % name).str()); - } - if (o->second.type == _forge.Bool) { + (fmt("Unrecognized option `%1%'") % name).str()); + } else if (o->second.type == _forge.Bool) { // --flag o->second.value = _forge.make(true); - } else { - if (++i >= argc) - throw OptionError( - (fmt("missing value for `%1%'") % name).str()); + } else if (equals) { // --opt=val + set_value_from_string(o->second, equals + 1); + } else if (++i < argc) { // --opt val set_value_from_string(o->second, argv[i]); + } else { + throw OptionError( + (fmt("Missing value for `%1%'") % name).str()); } } else { + // Short option const size_t len = strlen(argv[i]); for (size_t j = 1; j < len; ++j) { - char letter = argv[i][j]; - ShortNames::iterator n = _short_names.find(letter); - if (n == _short_names.end()) + const char letter = argv[i][j]; + const ShortNames::iterator n = _short_names.find(letter); + if (n == _short_names.end()) { throw OptionError( - (fmt("unrecognized option `%1%'") % letter).str()); - Options::iterator o = _options.find(n->second); - if (j < len - 1) { - if (o->second.type != _forge.Bool) + (fmt("Unrecognized option `%1%'") % letter).str()); + } + + const Options::iterator o = _options.find(n->second); + if (j < len - 1) { // Non-final POSIX style flag + if (o->second.type != _forge.Bool) { throw OptionError( - (fmt("missing value for `%1%'") % letter).str()); + (fmt("Missing value for `%1%'") % letter).str()); + } + o->second.value = _forge.make(true); + } else if (o->second.type == _forge.Bool) { // -f o->second.value = _forge.make(true); + } else if (++i < argc) { // -v val + set_value_from_string(o->second, argv[i]); } else { - if (o->second.type == _forge.Bool) { - o->second.value = _forge.make(true); - } else { - if (++i >= argc) - throw OptionError( - (fmt("missing value for `%1%'") % letter).str()); - set_value_from_string(o->second, argv[i]); - } + throw OptionError( + (fmt("Missing value for `%1%'") % letter).str()); } } } diff --git a/src/ingen/ingen.cpp b/src/ingen/ingen.cpp index 4ee45441..12a17e99 100644 --- a/src/ingen/ingen.cpp +++ b/src/ingen/ingen.cpp @@ -64,7 +64,7 @@ static void ingen_try(bool cond, const char* msg) { if (!cond) { - cerr << "ingen: Error: " << msg << endl; + cerr << "ingen: error: " << msg << endl; delete world; exit(EXIT_FAILURE); } @@ -101,7 +101,7 @@ main(int argc, char** argv) return print_version(); } } catch (std::exception& e) { - cout << "ingen: " << e.what() << endl; + cout << "ingen: error: " << e.what() << endl; return EXIT_FAILURE; } @@ -113,8 +113,7 @@ main(int argc, char** argv) // Run engine SPtr<Interface> engine_interface; if (conf.option("engine").get<int32_t>()) { - ingen_try(world->load_module("server"), - "Unable to load server module"); + ingen_try(world->load_module("server"), "Failed to load server module"); ingen_try(bool(world->engine()), "Unable to create engine"); world->engine()->listen(); @@ -124,8 +123,7 @@ main(int argc, char** argv) // If we don't have a local engine interface (for GUI), use network if (!engine_interface) { - ingen_try(world->load_module("client"), - "Unable to load client module"); + ingen_try(world->load_module("client"), "Failed to load client module"); #ifdef HAVE_SOCKET Client::SocketClient::register_factories(world); #endif @@ -136,9 +134,9 @@ main(int argc, char** argv) engine_interface = world->new_interface(Raul::URI(uri), client); if (!engine_interface && !conf.option("gui").get<int32_t>()) { - cerr << fmt("ingen: Error: Unable to create interface to `%1%'\n"); + cerr << (fmt("ingen: error: Failed to connect to `%1%'\n") % uri); delete world; - exit(EXIT_FAILURE); + return EXIT_FAILURE; } } @@ -146,19 +144,17 @@ main(int argc, char** argv) // Load GUI if requested if (conf.option("gui").get<int32_t>()) { - ingen_try(world->load_module("gui"), - "Unable to load GUI module"); + ingen_try(world->load_module("gui"), "Failed to load GUI module"); } // Activate the engine, if we have one if (world->engine()) { - ingen_try(world->load_module("jack"), - "Unable to load jack module"); + ingen_try(world->load_module("jack"), "Failed to load jack module"); world->engine()->activate(); } // Load a graph - if (conf.option("load").is_valid() || !conf.files().empty()) { + if (conf.option("load").is_valid()) { boost::optional<Raul::Path> parent; boost::optional<Raul::Symbol> symbol; @@ -175,16 +171,14 @@ main(int argc, char** argv) } } - ingen_try(bool(world->parser()), "Unable to create parser"); + ingen_try(bool(world->parser()), "Failed to create parser"); - const string path = (conf.option("load").is_valid() - ? conf.option("load").ptr<char>() - : conf.files().front()); + const string graph = conf.option("load").ptr<char>(); engine_interface->get(Raul::URI("ingen:/plugins")); engine_interface->get(Node::root_uri()); world->parser()->parse_file( - world, engine_interface.get(), path, parent, symbol); + world, engine_interface.get(), graph, parent, symbol); } // Set up signal handlers that will set quit_flag on interrupt |