[Monetdb-developers] readline things

Hi, I, as a frequent MapiClient user, have added some convenience functions to the readline interface over time: - commandline-selectable "save/load history" option (default=off). - basic 'tab' command completion (for SQL only, as of now). Completes on table names and SQL commands. Could be improved, but this already saves a lot of typing. I have added the .mx code and patch for MapiClient.mx and Makefile.ag If someone could look over this code; it would be nice to have it in cvs. -- Arjan Scherpenisse Centrum voor Wiskunde en Informatica, Amsterdam, the Netherlands Index: MapiClient.mx =================================================================== RCS file: /cvsroot/monetdb/MonetDB/src/mapi/clients/C/MapiClient.mx,v retrieving revision 1.57 diff -u -r1.57 MapiClient.mx --- MapiClient.mx 11 May 2004 11:03:04 -0000 1.57 +++ MapiClient.mx 2 Jun 2004 14:56:16 -0000 @@ -56,6 +56,7 @@ -t & --trace & trace Monet interaction \\ -T & --time & time commands \\ -u user & --user=user & user id \\ + -H & --history & load/save cmdline history (default off) \\ -? & --help & show this usage message \\ \end{tabular} @@ -83,6 +84,7 @@ #ifdef HAVE_LIBREADLINE #include <readline/readline.h> #include <readline/history.h> +#include "ReadlineTools.h" #endif #ifndef S_ISCHR @@ -805,6 +807,7 @@ fprintf(stderr, " -t | --trace /* trace Monet interaction */\n"); fprintf(stderr, " -T | --time /* time commands */\n"); fprintf(stderr, " -u user | --user=user /* user id */\n" ); + fprintf(stderr, " -H | --history /* load/save cmdline history (default off) */\n" ); fprintf(stderr, " -? | --help /* show this usage message */\n"); exit(-1); } @@ -832,8 +835,9 @@ int guest = 0; int linemode = 1; int c; - int quiet = 0; Mapi mid; + int quiet = 0; + int save_history = 0; static struct option long_options[] = { {"blocked", 1, 0, 'b'}, {"config", 1, 0, 'c'}, @@ -848,6 +852,7 @@ {"time", 0, 0, 'T'}, {"trace", 0, 0, 't'}, {"user", 1, 0, 'u'}, + {"history", 0, 0, 'H'}, {"quiet", 0, 0, 'q'}, {"help", 0, 0, '?'}, {0, 0, 0, 0} @@ -860,7 +865,7 @@ if ((setlen = mo_builtin_settings(&set)) == 0) usage(argv[0]); - while ((c = getopt_long(argc, argv, "b:c:l:u:p:P:qh:s:DtTd::?", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "b:c:l:u:p:P:qHh:s:DtTd::?", long_options, NULL)) != -1) { switch (c) { case 'b': if (*optarg == 't' || *optarg == 'T' || *optarg == '1') @@ -924,6 +929,9 @@ *eq = '='; break; } + case 'H': + save_history = 1; + break; case '?': usage(argv[0]); default: @@ -998,6 +1006,10 @@ optind++; } +#ifdef HAVE_LIBREADLINE + init_readline(mid, language, save_history); +#endif + if (command) { c = doRequest(mid, command); } else { @@ -1014,6 +1026,11 @@ } c = doFileByLines(mid, stdin, prompt, linemode); } + +#ifdef HAVE_LIBREADLINE + deinit_readline(); +#endif + mapi_disconnect(mid); return c; } Index: Makefile.ag =================================================================== RCS file: /cvsroot/monetdb/MonetDB/src/mapi/clients/C/Makefile.ag,v retrieving revision 1.3 diff -u -r1.3 Makefile.ag --- Makefile.ag 25 May 2004 21:02:46 -0000 1.3 +++ Makefile.ag 2 Jun 2004 14:56:16 -0000 @@ -27,7 +27,7 @@ MAPI_LIBS = $(SOCKET_LIBS) lib_Mapi = { - SOURCES = Mapi.mx + SOURCES = Mapi.mx LIBS = $(MAPI_LIBS) ../../../common/libmutils ../../../common/libstream HEADERS = h } @@ -37,9 +37,9 @@ SOURCES = Mapi.mx } -BINS = { - SOURCES = MapiClient.mx - MapiClient_LIBS = libMapi $(MAPI_LIBS) $(READLINE_LIBS) \ +bin_MapiClient = { + SOURCES = MapiClient.mx ReadlineTools.mx + LIBS = libMapi $(MAPI_LIBS) $(READLINE_LIBS) \ ../../../common/libmutils ../../../common/libstream \ $(ICONV_LIBS) } @h #ifndef READLINETOOLS_H_INCLUDED #define READLINETOOLS_H_INCLUDED #include <monet_options.h> #include <readline/readline.h> #include <readline/history.h> #include "Mapi.h" void init_readline(Mapi mid, const char *language, int save_history); void deinit_readline(); char **sql_completion (const char *text, int start, int end); char *sql_tablename_generator (const char *text, int state); char *sql_command_generator (const char *text, int state); #endif @c /* * Readline specific stuff */ #include "ReadlineTools.h" #define PATHLENGTH 256 /* maximum file pathname length. */ const char *SQL_COMMANDS[] = { "SELECT", "INSERT", "UPDATE", "SET", "DELETE", "COMMIT", "ROLLBACK", "DROP TABLE", "CREATE", "ALTER", "RELEASE SAVEPOINT", "START TRANSACTION", 0}; Mapi _mid; char _history_file[PATHLENGTH]; int _save_history = 0; void init_readline(Mapi mid, const char *language, int save_history) { _mid = mid; /* Allow conditional parsing of the ~/.inputrc file. */ rl_readline_name = "MapiClient"; /* Tell the completer that we want to try our own completion before std completion (filename) kicks in. */ if (strcmp(language, "sql")==0) { rl_attempted_completion_function = sql_completion; } else { // FIXME: mil completion } if (save_history) { #ifndef NATIVE_WIN32 if (getenv("HOME")!=NULL) { snprintf(_history_file, PATHLENGTH, "%s/.mapiclient_history_%s", getenv("HOME"), language); _save_history = 1; } #else snprintf(_history_file, PATHLENGTH, "%s%c_mapiclient_history_%s", mo_find_option(&set, setlen, "prefix"), DIR_SEP, language); _save_history = 1; #endif read_history(_history_file); } } void deinit_readline() { if (_save_history) { write_history(_history_file); } } char ** sql_completion (const char *text, int start, int end) { char **matches; matches = (char **)NULL; if (start==0 || end == 0) { } if (start == 0) { matches = rl_completion_matches (text, sql_command_generator); } else { matches = rl_completion_matches (text, sql_tablename_generator); } return (matches); } char *sql_tablename_generator (const char *text, int state) { static int seekpos, len, rowcount; static MapiHdl table_hdl; char *name; if (!state) { seekpos = 0; len = strlen (text); if ((table_hdl = mapi_query(_mid, "SELECT name FROM tables"))==NULL || mapi_error(_mid)) { if (table_hdl) { mapi_explain_query(table_hdl, stderr); mapi_close_handle(table_hdl); } else mapi_explain(_mid, stderr); return NULL; } rowcount = mapi_get_row_count(table_hdl); } while (seekpos < rowcount) { mapi_seek_row(table_hdl, seekpos++, MAPI_SEEK_SET); mapi_fetch_row(table_hdl); name = mapi_fetch_field(table_hdl, 0); if (strncmp(name, text, len) == 0) return strdup(name); } return NULL; } // SQL commands (at start of line) char *sql_command_generator (const char *text, int state) { static int index, len; const char *name; if (!state) { index = 0; len = strlen(text); } while ((name = SQL_COMMANDS[index++])) { #ifdef HAVE_STRNCASECMP if (strncasecmp(name, text, len)==0) #else if (strncmp(name, text, len)==0) #endif return strdup(name); } return NULL; }
participants (1)
-
Arjan Scherpenisse