summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2015-04-04 09:27:49 +0000
committerDavid Robillard <d@drobilla.net>2015-04-04 09:27:49 +0000
commit9c5ad6b64f33ea07654435e93a8b6f726894581f (patch)
treecd83370c2a06707dff0b731c084741a737d5b972
parent52bce39f06f607dd363ca8f3b774fda658036cf4 (diff)
downloadingen-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.122
-rw-r--r--ingen/Configuration.hpp6
-rw-r--r--src/Configuration.cpp110
-rw-r--r--src/ingen/ingen.cpp30
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