From 27ab8a2537deaff65a9bb68b2a03bb267361e91f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 25 Feb 2010 23:20:27 +0000 Subject: First attempt at tab completion for readline/libedit in bbackupquery, with commands and local file names, because it's easy and will help to find compatibility problems. --- bin/bbackupquery/BackupQueries.cpp | 76 +++++++++++++------------------------- bin/bbackupquery/BackupQueries.h | 33 +++++++++++++++++ bin/bbackupquery/bbackupquery.cpp | 72 ++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 51 deletions(-) diff --git a/bin/bbackupquery/BackupQueries.cpp b/bin/bbackupquery/BackupQueries.cpp index f799ab43..2a99c077 100644 --- a/bin/bbackupquery/BackupQueries.cpp +++ b/bin/bbackupquery/BackupQueries.cpp @@ -63,6 +63,30 @@ #define COMPARE_RETURN_ERROR 3 #define COMMAND_RETURN_ERROR 4 +// Data about commands +QueryCommandSpecification commands[] = +{ + { "quit", "" }, + { "exit", "" }, + { "list", "rodIFtTash", }, + { "pwd", "" }, + { "cd", "od" }, + { "lcd", "" }, + { "sh", "" }, + { "getobject", "" }, + { "get", "i" }, + { "compare", "alcqAEQ" }, + { "restore", "drif" }, + { "help", "" }, + { "usage", "m" }, + { "undelete", "" }, + { "delete", "" }, + { NULL, NULL } +}; + +const char *alias[] = {"ls", 0}; +const int aliasIs[] = {Command_List, 0}; + // -------------------------------------------------------------------------- // // Function @@ -100,12 +124,6 @@ BackupQueries::~BackupQueries() { } -typedef struct -{ - const char* name; - const char* opts; -} QueryCommandSpecification; - // -------------------------------------------------------------------------- // // Function @@ -206,51 +224,7 @@ void BackupQueries::DoCommand(const char *Command, bool isFromCommandLine) // blank command return; } - - // Data about commands - static QueryCommandSpecification commands[] = - { - { "quit", "" }, - { "exit", "" }, - { "list", "rodIFtTash", }, - { "pwd", "" }, - { "cd", "od" }, - { "lcd", "" }, - { "sh", "" }, - { "getobject", "" }, - { "get", "i" }, - { "compare", "alcqAEQ" }, - { "restore", "drif" }, - { "help", "" }, - { "usage", "m" }, - { "undelete", "" }, - { "delete", "" }, - { NULL, NULL } - }; - - typedef enum - { - Command_Quit = 0, - Command_Exit, - Command_List, - Command_pwd, - Command_cd, - Command_lcd, - Command_sh, - Command_GetObject, - Command_Get, - Command_Compare, - Command_Restore, - Command_Help, - Command_Usage, - Command_Undelete, - Command_Delete, - } - CommandType; - - static const char *alias[] = {"ls", 0}; - static const int aliasIs[] = {Command_List, 0}; - + // Work out which command it is... int cmd = 0; while(commands[cmd].name != 0 && ::strcmp(cmdElements[0].c_str(), commands[cmd].name) != 0) diff --git a/bin/bbackupquery/BackupQueries.h b/bin/bbackupquery/BackupQueries.h index 392aa428..dfca7130 100644 --- a/bin/bbackupquery/BackupQueries.h +++ b/bin/bbackupquery/BackupQueries.h @@ -20,6 +20,39 @@ class BackupProtocolClient; class Configuration; class ExcludeList; +typedef struct +{ + const char* name; + const char* opts; +} +QueryCommandSpecification; + +// Data about commands +extern QueryCommandSpecification commands[]; + +typedef enum +{ + Command_Quit = 0, + Command_Exit, + Command_List, + Command_pwd, + Command_cd, + Command_lcd, + Command_sh, + Command_GetObject, + Command_Get, + Command_Compare, + Command_Restore, + Command_Help, + Command_Usage, + Command_Undelete, + Command_Delete, +} +CommandType; + +extern const char *alias[]; +extern const int aliasIs[]; + // -------------------------------------------------------------------------- // // Class diff --git a/bin/bbackupquery/bbackupquery.cpp b/bin/bbackupquery/bbackupquery.cpp index 5aa7e97e..6d697087 100644 --- a/bin/bbackupquery/bbackupquery.cpp +++ b/bin/bbackupquery/bbackupquery.cpp @@ -74,6 +74,72 @@ void PrintUsageAndExit() exit(1); } +#ifdef HAVE_LIBREADLINE +// copied from: http://tiswww.case.edu/php/chet/readline/readline.html#SEC44 + +char * command_generator(const char *text, int state) +{ + static int list_index, len; + const char *name; + + /* + * If this is a new word to complete, initialize now. This includes + * saving the length of TEXT for efficiency, and initializing the index + * variable to 0. + */ + if(!state) + { + list_index = 0; + len = strlen(text); + } + + /* Return the next name which partially matches from the command list. */ + while((name = commands[list_index].name)) + { + list_index++; + + if(::strncmp(name, text, len) == 0 && !(state--)) + { + return ::strdup(name); + } + } + + list_index = 0; + + while((name = alias[list_index])) + { + list_index++; + + if(::strncmp(name, text, len) == 0 && !(state--)) + { + return ::strdup(name); + } + } + + /* If no names matched, then return NULL. */ + return (char *) NULL; +} + +char ** bbackupquery_completion(const char *text, int start, int end) +{ + char **matches; + + matches = (char **)NULL; + + /* If this word is at the start of the line, then it is a command + * to complete. Otherwise it is the name of a file in the current + * directory. + */ + if (start == 0) + { + matches = rl_completion_matches(text, command_generator); + } + + return matches; +} + +#endif // HAVE_LIBREADLINE + int main(int argc, const char *argv[]) { int returnCode = 0; @@ -369,6 +435,12 @@ int main(int argc, const char *argv[]) #ifdef HAVE_READLINE_HISTORY using_history(); #endif + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "bbackupquery"; + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = bbackupquery_completion; + char *last_cmd = 0; while(!context.Stop()) { -- cgit v1.2.3