Command abbreviation.
authorFlorian Pose <fp@igh-essen.com>
Tue, 22 Jul 2008 11:38:21 +0000
changeset 1125 9976f7b9fe66
parent 1124 5da7c73c4f63
child 1126 b09fd81894cb
Command abbreviation.
tool/cmd_alias.cpp
tool/globals.h
tool/main.cpp
--- a/tool/cmd_alias.cpp	Tue Jul 22 09:03:10 2008 +0000
+++ b/tool/cmd_alias.cpp	Tue Jul 22 11:38:21 2008 +0000
@@ -47,7 +47,7 @@
     unsigned int numSlaves, i;
 
     if (commandArgs.size() != 1) {
-        err << "'" << command << "' takes exactly one argument!";
+        err << "'" << commandName << "' takes exactly one argument!";
         throw InvalidUsageException(err);
     }
 
--- a/tool/globals.h	Tue Jul 22 09:03:10 2008 +0000
+++ b/tool/globals.h	Tue Jul 22 11:38:21 2008 +0000
@@ -21,7 +21,7 @@
     Verbose
 };
 
-extern string command;
+extern string commandName;
 extern int slavePosition;
 extern int domainIndex;
 extern vector<string> commandArgs;
--- a/tool/main.cpp	Tue Jul 22 09:03:10 2008 +0000
+++ b/tool/main.cpp	Tue Jul 22 11:38:21 2008 +0000
@@ -20,7 +20,7 @@
 unsigned int masterIndex = 0;
 int slavePosition = -1;
 int domainIndex = -1;
-string command;
+string commandName;
 vector<string> commandArgs;
 Verbosity verbosity = Normal;
 string dataTypeStr;
@@ -33,6 +33,7 @@
 /*****************************************************************************/
 
 struct Command {
+    const char *name;
     void (*func)(void);
     const char *helpString;
 
@@ -40,27 +41,20 @@
     void displayHelp(void) const;
 };
 
-struct CommandAlias {
-    const char *name;
-    const Command *command;
-};
-
 /*****************************************************************************/
 
 #define COMMAND(name) \
     void command_##name(void); \
-    extern const char *help_##name; \
-    const Command cmd_##name = {command_##name, help_##name};
+    extern const char *help_##name
+
+#define INIT_COMMAND(name) {#name, command_##name, help_##name}
 
 COMMAND(alias);
 COMMAND(config);
 
-const CommandAlias commandAliases[] = {
-    {"alias",  &cmd_alias},
-
-    {"config", &cmd_config},
-    {"conf",   &cmd_config},
-    {"cf",     &cmd_config},
+static const Command commands[] = {
+    INIT_COMMAND(alias),
+    INIT_COMMAND(config),
 };
 
 #if 0
@@ -115,6 +109,7 @@
         << "  slaves        Show slaves." << endl
         << "  state         Request slave states." << endl
         << "  xml           Generate slave information xmls." << endl
+        << "Commands can be generously abbreviated." << endl
 		<< "Global options:" << endl
         << "  --master  -m <master>  Index of the master to use. Default: 0"
 		<< endl
@@ -241,7 +236,7 @@
         exit(!helpRequested);
 	}
 
-    command = argv[optind];
+    commandName = argv[optind];
     while (++optind < argc)
         commandArgs.push_back(string(argv[optind]));
 }
@@ -271,7 +266,41 @@
 
 void Command::displayHelp() const
 {
-    cerr << binaryBaseName << " " << command << " " << helpString;
+    cerr << binaryBaseName << " " << commandName << " " << helpString;
+}
+
+/****************************************************************************/
+
+bool abbrevMatch(const string &abb, const string &full)
+{
+    unsigned int abbIndex;
+    size_t fullPos = 0;
+
+    for (abbIndex = 0; abbIndex < abb.length(); abbIndex++) {
+        fullPos = full.find(abb[abbIndex], fullPos);
+        if (fullPos == string::npos)
+            return false;
+    }
+
+    return true;
+}
+    
+/****************************************************************************/
+
+list<const Command *> getMatchingCommands(const string &cmdStr)
+{
+    const Command *cmd, *endCmd =
+        commands + sizeof(commands) / sizeof(Command);
+    list<const Command *> res;
+
+    // find matching commands
+    for (cmd = commands; cmd < endCmd; cmd++) {
+        if (abbrevMatch(cmdStr, cmd->name)) {
+            res.push_back(cmd);
+        }
+    }
+
+    return res;
 }
 
 /****************************************************************************/
@@ -279,28 +308,35 @@
 int main(int argc, char **argv)
 {
     int retval = 0;
-    const CommandAlias *alias;
-    const CommandAlias *endAlias =
-        commandAliases + sizeof(commandAliases) / sizeof(CommandAlias);
+    list<const Command *> commands;
+    list<const Command *>::const_iterator ci;
+    const Command *cmd;
 
     binaryBaseName = basename(argv[0]);
 	getOptions(argc, argv);
 
-    // search command alias in alias map
-    for (alias = commandAliases; alias < endAlias; alias++) {
-        if (command == alias->name)
-            break;
-    }
-
-    if (alias < endAlias) { // command alias found
-        if (!helpRequested) {
-            masterDev.setIndex(masterIndex);
-            retval = alias->command->execute();
+    commands = getMatchingCommands(commandName);
+
+    if (commands.size()) {
+        if (commands.size() == 1) {
+            cmd = commands.front();
+            if (!helpRequested) {
+                masterDev.setIndex(masterIndex);
+                retval = cmd->execute();
+            } else {
+                cmd->displayHelp();
+            }
         } else {
-            alias->command->displayHelp();
+            cerr << "Ambigous command abbreviation! Matching:" << endl;
+            for (ci = commands.begin(); ci != commands.end(); ci++) {
+                cerr << (*ci)->name << endl;
+            }
+            cerr << endl;
+            printUsage();
+            retval = 1;
         }
-    } else { // command not found
-        cerr << "Unknown command " << command << "!" << endl << endl;
+    } else {
+        cerr << "Unknown command " << commandName << "!" << endl << endl;
         printUsage();
         retval = 1;
     }