aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Reisner <dreisner@archlinux.org>2013-03-01 13:57:55 -0500
committerDave Reisner <dreisner@archlinux.org>2013-03-01 14:11:36 -0500
commit6903b4975e38e29008e21222a7323d3920b804e8 (patch)
treec4b6c4113006dd371ea2cddd7840559843ae973e
parentdc8588eea147bbdde8bcc69f46c3f9004954a925 (diff)
downloadmirror-ponymix-6903b4975e38e29008e21222a7323d3920b804e8.tar.gz
mirror-ponymix-6903b4975e38e29008e21222a7323d3920b804e8.tar.bz2
mirror-ponymix-6903b4975e38e29008e21222a7323d3920b804e8.zip
allow matching commands on prefixes
Allow for invocations such as "ponymix get-v" or "ponymix -d SB set-d". Bail when the command is ambiguous and print the possible matches. This necessarily means changing the return type of string_to_command to return the whole pair<> out of the action map to allow for useful errors when we do arg checking (as we don't necessarily have the full command name from the user).
-rw-r--r--ponymix.cc38
1 files changed, 30 insertions, 8 deletions
diff --git a/ponymix.cc b/ponymix.cc
index e3a1b4b..b3c1b98 100644
--- a/ponymix.cc
+++ b/ponymix.cc
@@ -418,7 +418,9 @@ static int Kill(PulseClient& ponymix, int, char*[]) {
return !ponymix.Kill(*device);
}
-static const Command& string_to_command(const char* str) {
+
+static const std::pair<const string, const Command>& string_to_command(
+ const char* str) {
static std::map<string, const Command> actionmap = {
// command name function arg min arg max
{ "defaults", { ShowDefaults, { 0, 0 } } },
@@ -446,11 +448,29 @@ static const Command& string_to_command(const char* str) {
{ "kill", { Kill, { 0, 0 } } }
};
- try {
- return actionmap.at(str);
- } catch(std::out_of_range) {
- errx(1, "error: Invalid action specified: %s", str);
+ const auto match = actionmap.lower_bound(str);
+ for (auto iter = match; iter != actionmap.end(); iter++) {
+ // Match on prefix, ensure only a single match
+ if (iter->first.find(str) != 0) {
+ if (iter == match) {
+ errx(1, "error: Invalid action specified: %s", str);
+ } else {
+ break;
+ }
+ }
+ if (iter != match) {
+ auto i = match;
+ string cand = i->first;
+ i++;
+ while (i->first.find(str) == 0) {
+ cand += ", " + i->first;
+ i++;
+ }
+ errx(1, "error: Ambiguous action specified: %s (%s)", str, cand.c_str());
+ }
}
+
+ return *match;
}
static void usage() {
@@ -524,10 +544,12 @@ static int CommandDispatch(PulseClient& ponymix, int argc, char *argv[]) {
return 0;
}
- const Command& cmd = string_to_command(opt_action);
- if (cmd.args.InRange(argc) != 0) error_wrong_args(cmd, opt_action);
+ const auto& cmd = string_to_command(opt_action);
+ if (cmd.second.args.InRange(argc) != 0) {
+ error_wrong_args(cmd.second, cmd.first.c_str());
+ }
- return cmd.fn(ponymix, argc, argv);
+ return cmd.second.fn(ponymix, argc, argv);
}
bool parse_options(int argc, char** argv) {