/* ============================================================================ * Copyright (C) 1999 Angus Mackay. All rights reserved; * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ============================================================================ */ /* * sqlplusplus.c * * a wrapper the lame oracle SQL Plus to give you readline command editing * and history. * * NOTE: You must get GNU ReadLine working before compiling this program!!! * See http://theory.uwinnipeg.ca/localfiles/infofiles/rlman_toc.html * * compile with(if your readline is in $HOME): * cc -I$HOME/include sqlplusplus.c -lreadline -ltermcap -o sqlplusplus * */ #include #include #include #include #include #include #include #include #include #define SQLPLUS "sqlplus" /******************************************************/ static volatile int g_done = 0; static volatile int g_exit_code = 0; static pid_t g_childpid = -1; char *commands[] = { /* SQL*Plus commands */ "ACCEPT", "DEFINE", "DESCRIBE", "EDIT", "EXIT", "QUIT", "GET", "HOST", "HELP", "LIST", "PROMPT", "RUN", "SAVE", "SHOW", "SPOOL", "START", /* SQL commands */ "ALTER", "CLEAR", "COMMIT", "CREATE", "DELETE", "DROP", "EXPLAIN", "GRANT", "INSERT", "LOCK", "RENAME", "REVOKE", "ROLLBACK", "SAVEPOINT", "SELECT", "SET", "TRUNCATE", "UPDATE", /* SQL modifiers */ "WHERE", "FROM", "INTO", "VALUES", /* add your table names here */ NULL }; /******************************************************/ void sigchld_handler(int sig) { int exit_code; g_done = 1; wait(&exit_code); g_exit_code = exit_code; } void signal_forwarder(int sig) { kill(g_childpid, sig); signal(sig, signal_forwarder); } char *command_generator(char *text, int state) { static int list_index, len; 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]) != NULL) { list_index++; if(strncasecmp(name, text, len) == 0) { return(strdup(name)); } } /* If no names matched, then return NULL. */ return((char *)NULL); } char ** completion_func(char *text, int start, int end) { /* fprintf(stderr, "text: %s, start: %d, end: %d\n", text, start, end); */ /* fprintf(stderr, "rl_line_buffer: %s\n", rl_line_buffer); */ return(completion_matches(text, command_generator)); } void initialize_readline(void) { /* Allow conditional parsing of the ~/.inputrc file. */ rl_readline_name = "sqlplusplus"; /* Tell the completer that we want a crack first. */ rl_attempted_completion_function = (CPPFunction *)completion_func; /* init history */ using_history(); /* keep a lid on the history */ stifle_history(getenv("HISTSIZE") == NULL ? 256 : atoi(getenv("HISTSIZE"))); /* read old history file */ if(getenv("SQL_HISTFILE")) { read_history(getenv("SQL_HISTFILE")); } } int create_child(char **argv, pid_t *pid) { int fildes[2]; int new_pid; fflush(stdin); fflush(stdout); fflush(stderr); pipe(fildes); switch((new_pid=vfork())) { case -1: perror("fork"); exit(1); break; case 0: /* child */ if(dup2(fildes[1], 0) == -1) { perror("dup2"); exit(errno); } execvp(argv[0], argv); perror(argv[0]); exit(1); break; default: /* parent */ *pid = new_pid; return(fildes[0]); break; } return(-1); } int main(int argc, char **argv) { char *line; char *command; char *prompt; int i; int commandlen; int childfd; argv[0] = SQLPLUS; /* if this is not a tty just use the real program */ if(!isatty(0)) { execvp(argv[0], argv); perror("exec"); return(errno); } prompt = "SQL> "; /* trap for exit */ signal(SIGCHLD, sigchld_handler); /* trap for forwarding */ signal(SIGINT, signal_forwarder); signal(SIGHUP, signal_forwarder); signal(SIGQUIT, signal_forwarder); signal(SIGTERM, signal_forwarder); commandlen = strlen(SQLPLUS) + 1; for(i=1; i