From 8686a730474a8cf0505d877e8e4ed1c32da6879e Mon Sep 17 00:00:00 2001 From: pnenzi Date: Thu, 14 Aug 2003 19:21:10 +0000 Subject: [PATCH] Added readline patch (support for command history). --- ChangeLog | 18 ++++++ configure.in | 3 +- src/frontend/com_history.c | 35 +++++++++++ src/frontend/misccoms.c | 16 ++++- src/frontend/parser/glob.c | 7 ++- src/frontend/plotting/x11.c | 3 + src/frontend/signal_handler.c | 4 +- src/include/ngspice.h | 5 +- src/main.c | 115 ++++++++++++++++++++++++++++++++++ src/misc/tilde.c | 82 +++++++++++++++++++++++- src/misc/tilde.h | 5 +- 11 files changed, 283 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0a68042f7..b45bda33b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2003-08-14 Paolo Nenzi + + * configure.in, src/main.c, src/misc/tilde.c, src/misc/tilde.h, + src/frontend/com_history.c, src/frontend/misccoms.h, + src/frontend/signal_handler.c, src/frontend/plotting/x11.c, + src/frontend/parser/glob.c, src/include/ngspice.h: + + Added Andrew Veliath patch fo readline support. Using + readline with ngspice IS A VIOLATION OF GPL LICENSE, you + have been warned. The final decision is up to you. The + patch has been applied in the perspective of changing + readline library with libedit. Libedit aims to be a + replacement of readline and is covered by BSD license. + Libedit is available at the URL: libedit.sourceforge.net. + + Readline code has been extrapolated from a patch available + on http://www.btae.mam.gov.tr/~genc/ngspice/. + 2003-08-11 Paolo Nenzi * doc/ngspice.texi: updated documentation. Still incomplete diff --git a/configure.in b/configure.in index abb105f91..f42e8e4cd 100644 --- a/configure.in +++ b/configure.in @@ -463,9 +463,8 @@ fi dnl --with-readline : the user wants to use readline library AC_ARG_WITH(readline, - [ --with-readline Use the readline package: SEE README], + [ --with-readline Use the readline library. WARNING: breaks GPL license], AC_MSG_RESULT(Checking for readline library:) - Check for the readline library: AC_CHECK_LIB(readline, readline, AC_DEFINE(HAVE_GNUREADLINE) LIBS="$LIBS -lreadline") ) diff --git a/src/frontend/com_history.c b/src/frontend/com_history.c index f6b03a77b..0fa5cb2ed 100644 --- a/src/frontend/com_history.c +++ b/src/frontend/com_history.c @@ -10,6 +10,13 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "com_history.h" +#ifdef HAVE_GNUREADLINE + +/* Added GNU Readline Support -- Andrew Veliath */ +#include +#include + +#endif /* HAVE_GNUREADLINE */ /* static declarations */ static wordlist * dohsubst(char *string); @@ -346,8 +353,10 @@ cp_addhistent(int event, wordlist *wlist) cp_lastone->hi_next = NULL; cp_lastone->hi_event = event; cp_lastone->hi_wlist = wl_copy(wlist); +#ifndef HAVE_GNUREADLINE freehist(histlength - cp_maxhistlength); histlength++; +#endif return; } @@ -484,10 +493,36 @@ com_history(wordlist *wl) wl = wl->wl_next; rev = TRUE; } +#ifdef HAVE_GNUREADLINE + /* Added GNU Readline Support -- Andrew Veliath */ + { + HIST_ENTRY *he; + int i, N; + + N = (wl == NULL) ? history_length : atoi(wl->wl_word); + + if (N < 0) N = 0; + if (N > history_length) N = history_length; + + if (rev) + for (i = history_length; i > 0 && N; --i, --N) { + he = history_get(i); + if (!he) return; + fprintf(cp_out, "%d\t%s\n", i, he->line); + } + else + for (i = history_length - N + 1; i <= history_length; ++i) { + he = history_get(i); + if (!he) return; + fprintf(cp_out, "%d\t%s\n", i, he->line); + } + } +#else if (wl == NULL) cp_hprint(cp_event - 1, cp_event - histlength, rev); else cp_hprint(cp_event - 1, cp_event - 1 - atoi(wl->wl_word), rev); +#endif /* ifelse HAVE_GNUREADLINE */ return; } diff --git a/src/frontend/misccoms.c b/src/frontend/misccoms.c index bec8db9b9..09fc0e7ed 100644 --- a/src/frontend/misccoms.c +++ b/src/frontend/misccoms.c @@ -15,6 +15,13 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "hcomp.h" #include "variable.h" +#ifdef HAVE_GNUREADLINE +#include +#include + +extern int gnu_history_lines; +extern char gnu_history_file[]; +#endif static void byemesg(void); @@ -79,9 +86,14 @@ com_quit(wordlist *wl) byemesg(); } else byemesg(); - +#ifdef HAVE_GNUREADLINE + /* Added GNU Readline Support -- Andrew Veliath */ + if (cp_interactive && (cp_maxhistlength > 0)) { + stifle_history(cp_maxhistlength); + write_history(gnu_history_file); + } +#endif /* HAVE_GNUREADLINE */ exit(EXIT_NORMAL); - } diff --git a/src/frontend/parser/glob.c b/src/frontend/parser/glob.c index 4135e6eaa..7a46c3bda 100644 --- a/src/frontend/parser/glob.c +++ b/src/frontend/parser/glob.c @@ -42,7 +42,7 @@ char cp_til = '~'; * globbing in them. Sort after the second phase but not the first... */ -/* MW. Now only tilde is supportef, {}*? don't work */ +/* MW. Now only tilde is supported, {}*? don't work */ wordlist * cp_doglob(wordlist *wlist) @@ -72,8 +72,11 @@ cp_tildexpand(char *string) { char *result; +#ifdef HAVE_READLINE + result = tildexpand(string); +#else result = tilde_expand(string); - +#endif if (!result) { if (cp_nonomatch) { return copy(string); diff --git a/src/frontend/plotting/x11.c b/src/frontend/plotting/x11.c index 9fce9606b..8f337fcad 100644 --- a/src/frontend/plotting/x11.c +++ b/src/frontend/plotting/x11.c @@ -788,12 +788,15 @@ zoomin(GRAPH *graph) graph->commandline, fx0, fx1, fy0, fy1); } +/* don't use the following if using GNU Readline - AV */ +#ifndef HAVE_GNUREADLINE /* hack for Gordon Jacobs */ /* add to history list if plothistory is set */ if (cp_getvar("plothistory", VT_BOOL, (char *) &dummy)) { wl = cp_parse(buf); (void) cp_addhistent(cp_event++, wl); } +#endif /* HAVE_GNUREADLINE */ (void) cp_evloop(buf); diff --git a/src/frontend/signal_handler.c b/src/frontend/signal_handler.c index 4f51bab0d..37a2a7a56 100644 --- a/src/frontend/signal_handler.c +++ b/src/frontend/signal_handler.c @@ -32,6 +32,8 @@ extern jmp_buf jbuf; extern pid_t getpid (void); +/* not using SIGINT with GNU Readline - AV */ +#ifndef HAVE_GNUREADLINE RETSIGTYPE ft_sigintr(void) { @@ -55,7 +57,7 @@ ft_sigintr(void) cp_resetcontrol(); longjmp(jbuf, 1); } - +#endif /* !HAVE_GNUREADLINE */ RETSIGTYPE sigfloat(int sig, int code) diff --git a/src/include/ngspice.h b/src/include/ngspice.h index e3149d8a7..e5f1aa11c 100644 --- a/src/include/ngspice.h +++ b/src/include/ngspice.h @@ -134,8 +134,11 @@ extern int scannum(char *str); extern int ciprefix(register char *p, register char *s); extern int cieq(register char *p, register char *s); extern void strtolower(char *str); +#ifdef HAVE_GNUREADLINE +extern char *tildexpand(char *string); +#else extern char *tilde_expand(char *string); - +#endif extern char *smktemp(char *id); extern char *copy(char *str); diff --git a/src/main.c b/src/main.c index 62d1807cd..5a640034d 100644 --- a/src/main.c +++ b/src/main.c @@ -43,6 +43,14 @@ #include #endif +#ifdef HAVE_GNUREADLINE +/* Added GNU Readline Support 11/3/97 -- Andrew Veliath */ +/* from spice3f4 patch to ng-spice. jmr */ +#include +#include +#include "fteinput.h" +#endif + #ifndef HAVE_GETRUSAGE #ifdef HAVE_FTIME #include @@ -64,6 +72,11 @@ bool ft_intrpt = FALSE; /* Set by the (void) signal handlers. */ bool ft_setflag = FALSE; /* Don't abort after an interrupt. */ char *ft_rawfile = "rawspice.raw"; +#ifdef HAVE_GNUREADLINE +char gnu_history_file[512]; +static char *application_name; +#endif + bool oflag = FALSE; /* Output über redefinierte Funktionen */ FILE *flogp; // hvogt 15.12.2001 @@ -309,6 +322,89 @@ shutdown(int exitval) exit (exitval); } +#ifdef HAVE_GNUREADLINE +/* Adapted ../lib/cp/lexical.c:prompt() for GNU Readline -- Andrew Veliath */ +static char * +prompt() +{ + static char pbuf[128]; + char *p = pbuf, *s; + + if (cp_interactive == FALSE) + return; + if (cp_promptstring == NULL) + s = "-> "; + else + s = cp_promptstring; + if (cp_altprompt) + s = cp_altprompt; + while (*s) { + switch (strip(*s)) { + case '!': + p += sprintf(p, "%d", where_history() + 1); + break; + case '\\': + if (*(s + 1)) + p += sprintf(p, "%c", strip(*++s)); + default: + *p = strip(*s); ++p; + break; + } + s++; + } + *p = 0; + return pbuf; +} + +/* Process device events in Readline's hook since there is no where + else to do it now - AV */ +int rl_event_func() +{ + static REQUEST reqst = { checkup_option, 0 }; + Input(&reqst, NULL); + return 0; +} + +/* Added GNU Readline Support -- Andrew Veliath */ +void app_rl_readlines() +{ + char *line, *expanded_line; + + strcpy(gnu_history_file, getenv("HOME")); + strcat(gnu_history_file, "/."); + strcat(gnu_history_file, application_name); + strcat(gnu_history_file, "_history"); + + using_history(); + read_history(gnu_history_file); + + rl_readline_name = application_name; + rl_instream = cp_in; + rl_outstream = cp_out; + rl_event_hook = rl_event_func; + + while (1) { + history_set_pos(history_length); + line = readline(prompt()); + if (line && *line) { + int s = history_expand(line, &expanded_line); + + if (s == 2) { + fprintf(stderr, "-> %s\n", expanded_line); + } else if (s == -1) { + fprintf(stderr, "readline: %s\n", expanded_line); + } else { + cp_evloop(expanded_line); + add_history(expanded_line); + } + free(expanded_line); + } + if (line) free(line); + } + /* History gets written in ../fte/misccoms.c com_quit */ +} +#endif /* HAVE_GNUREADLINE */ + void show_help(void) { @@ -423,6 +519,13 @@ main(int argc, char **argv) } started = TRUE; +#ifdef HAVE_GNUREADLINE + if (!(application_name = strrchr(argv[0],'/'))) + application_name = argv[0]; + else + ++application_name; +#endif + #ifdef PARALLEL_ARCH PBEGIN_(argc, argv); ARCHme = NODEID_(); @@ -617,7 +720,11 @@ main(int argc, char **argv) /* Set up signal handling */ if (!ft_batchmode) { + +#ifndef HAVE_GNUREADLINE signal(SIGINT, ft_sigintr); +#endif + signal(SIGFPE, sigfloat); #if defined(SIGTSTP) // && !defined(__MINGW32__) signal(SIGTSTP, sigstop); @@ -788,7 +895,11 @@ evl: } else { (void) setjmp(jbuf); cp_interactive = TRUE; +#ifdef HAVE_GNUREADLINE + app_rl_readlines(); +#else while (cp_evloop((char *) NULL) == 1) ; +#endif /* ifelse HAVE_GNUREADLINE */ } #else /* ~ SIMULATOR */ @@ -806,7 +917,11 @@ evl: /* Nutmeg "main" */ (void) setjmp(jbuf); cp_interactive = TRUE; +#ifdef HAVE_GNUREADLINE + app_rl_readlines(); +#else while (cp_evloop((char *) NULL) == 1) ; +#endif /* ifelse HAVE_GNUREADLINE */ #endif /* ~ SIMULATOR */ diff --git a/src/misc/tilde.c b/src/misc/tilde.c index ece5fde70..1e72b4e27 100644 --- a/src/misc/tilde.c +++ b/src/misc/tilde.c @@ -1,5 +1,6 @@ /********** Copyright 1991 Regents of the University of California. All rights reserved. +Modified: 2002 R. Oktas, **********/ #include @@ -14,11 +15,30 @@ Copyright 1991 Regents of the University of California. All rights reserved. #include #endif +/* XXX To prevent a name collision with `readline's `tilde_expand', + the original name: `tilde_expand' has changed to `tildexpand'. This + situation naturally brings to mind that `tilde_expand' could be used + directly from `readline' (since it will already be included if we + wish to activate the `readline' support). Following implementation of + 'tilde expanding' has some problems which constitutes another good + reason why it should be replaced: eg. it returns NULL which should + not behave this way, IMHO. Anyway... Don't care for the moment, may + be in the future. -- ro */ - +/* PN: Since readline patch is not compiled in by default the behaviour + described above is not acceptable. I will make two different version + of tilde expansion routine, the one choosen depends on HAVE_GNUREADLINE + Note: since a readline replacement called libedit is under + development at libedit.sourceforge.net, I will switch to it + ASAP, since libedit is covered by BSD licnse. + + */ + +#ifndef HAVE_GNUREADLINE char * tilde_expand(char *string) { + #ifdef HAVE_PWD_H struct passwd *pw; /*extern struct passwd *getpwuid( );*/ @@ -60,3 +80,63 @@ tilde_expand(char *string) return copy(string); #endif } + +#else /* HAVE_GNUREADLINE */ + +char * +tildexpand(char *string) +{ + + char buf[BSIZE_SP]; + char *result, *k, c; + if (!string) + return NULL; + + while (*string && isspace(*string)) + string++; + + if (*string != '~') + return copy(string); + + string += 1; + + if (!*string || *string == '/') { + /* First try the environment setting. May also make life easier + for non-unix platforms, eg. MS-DOS. -- ro */ + result = getenv("HOME"); +#ifdef HAVE_PWD_H + /* Can't find a result from the environment, let's try + the other stuff. -- ro */ + if (!result) { + struct passwd *pw; + pw = getpwuid(getuid()); + if (pw) + result = pw->pw_dir; + *buf = 0; + } + } else { + struct passwd *pw; + k = buf; + while ((c = *string) && c != '/') + *k++ = c, string++; + *k = 0; + pw = getpwnam(buf); + if (pw) + result = pw->pw_dir; +#endif + } + if (result) { +#ifdef HAVE_PWD_H + strcpy(buf, result); + if (*string) + strcat(buf, string); + return copy(buf); + } else + return NULL; +#else + + /* Emulate the old behavior to prevent side effects. -- ro */ + return copy(string); +#endif +} +#endif /* HAVE_GNUREADLINE */ diff --git a/src/misc/tilde.h b/src/misc/tilde.h index 9f98faa16..54b605aee 100644 --- a/src/misc/tilde.h +++ b/src/misc/tilde.h @@ -6,7 +6,10 @@ #ifndef TILDE_H_INCLUDED #define TILDE_H_INCLUDED +#ifdef HAVE_GNUREADLINE +char * tildexpand(char *string); +#else char * tilde_expand(char *string); - +#endif #endif