aboutsummaryrefslogtreecommitdiffstats
path: root/ponymix.cc
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 /ponymix.cc
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).
Diffstat (limited to 'ponymix.cc')
-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) {