diff options
author | Dave Reisner <dreisner@archlinux.org> | 2013-03-01 13:57:55 -0500 |
---|---|---|
committer | Dave Reisner <dreisner@archlinux.org> | 2013-03-01 14:11:36 -0500 |
commit | 6903b4975e38e29008e21222a7323d3920b804e8 (patch) | |
tree | c4b6c4113006dd371ea2cddd7840559843ae973e | |
parent | dc8588eea147bbdde8bcc69f46c3f9004954a925 (diff) | |
download | mirror-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.cc | 38 |
1 files changed, 30 insertions, 8 deletions
@@ -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) { |