R-alpha: hack to have line editing and command history in R

Valerio Aimale (valerio@frank.com.dist.unige.it)
Fri, 16 Aug 1996 15:11:21 +0200


From: "Valerio Aimale" <valerio@frank.com.dist.unige.it>
Message-Id: <9608161511.ZM8080@frank.com.dist.unige.it>
Date: Fri, 16 Aug 1996 15:11:21 +0200
To: r-testers@stat.math.ethz.ch
Subject: R-alpha: hack to have line editing and command history in R

HI,

I am a newcomer to this list and to the R environment.

I have recently started using the R implementation () and I have found it very
useful.

Given that I am not perfect at typewriting and I am lazy typewriter, I tried to
add line editing and command history to the R sources, using readline() and
history() from GNU lib.

I have modified the R-0.9alpha sources and finally it worked. I have modified
yyprompt() in gram.y  so that it writes the prompt in a static buffer called
R_readline_buf (tentatively dimensioned to 1024 bytes, I don't know how large a
prompt can grow) instead of printing it, and ReadKBD() in UNIXsystem.c so that
it reads the line through readline() using the given prompt and saving in the
history buffer the current command. I added some code in main() and in
do_quit() to handle the history buffer which is saved in "~/.RData/.Audit".
After some use of the history buffer, this file grows rather big, so now there
is the need for a R function to trim it. The R_readline_buf is also used
temporary to build the
"~/.RData/.Audit" pathname.

WARNING! this is definitely a hack and you will use it at your own risk. I
tested it only in a Linux box, i486, kernel 2.0.12.

To use this hack you will have to get the  readline-2.0.tar.gz file from some
gnu library mirror, untar it, compiling and installing it, because this hack
require to be linked with -lreadline (i.e. you should have the readline.a file
in /usr/lib or /usr/local/Lib).

This would probably work with others Unices, but I could not test it. If you
want to try you have to edit the $RHOME/src/Systems/<your OS> file, adding
-ltermcap and -lreadline to the LIBS variable (see under)

Start with an unmodified R-0.9alpha source tree and do
cd $RHOME/..
patch -p0 < this message

and recompile the whole thing.

Hopefully you should have an R environment with line editing and command
history.

Ciao.



Valerio Aimale                                           Tel. ++39-19-802891
University of Genoa                                      FAX. ++39-19-805749
ITALY                                                email: valerio@linux.it

-------------------------------------------------------------------------------
Diffs for the hack follow:

diff -u --recursive --new-file Roriginal/src/Systems/Linux R/src/Systems/Linux
--- Roriginal/src/Systems/Linux	Thu May 16 00:57:45 1996
+++ R/src/Systems/Linux	Fri Aug 16 12:38:48 1996
@@ -26,4 +26,4 @@
 LD= f77 -g

 # Libraries to Load Against
-LIBS= -L$(X11BASE)/lib -lX11
+LIBS= -L$(X11BASE)/lib -lX11 -lreadline -ltermcap
diff -u --recursive --new-file Roriginal/src/main/UNIXsystem.c
R/src/main/UNIXsystem.c
--- Roriginal/src/main/UNIXsystem.c	Wed May 15 06:54:09 1996
+++ R/src/main/UNIXsystem.c	Fri Aug 16 14:21:36 1996
@@ -17,6 +17,8 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */

+#include <readline/history.h>
+
 #include "Defn.h"

 	/*--- I / O -- S u p p o r t -- C o d e ---*/
@@ -31,18 +33,32 @@
 	/* Fill a text buffer with user typed console input. */
 	/* This routine is only called when R_Console == 1. */

+char R_readline_buf[1024];
+
 int ReadKBD(char *buf, int len)
 {
+char *tb;
+int l;
 #ifdef OLD
 	if (fgets(buf, len, R_Inputfile) == NULL)
 #endif
-	if (fgets(buf, len, stdin) == NULL)
-		return 0;
-	else {
-		if( !isatty(0) )
-			fputs(buf,stdout);
-		return 1;
-	}
+        if( !isatty(0) ) {
+                if (fgets(buf, len, stdin) == NULL) return 0;
+                else {
+                        fputs(buf,stdout);
+                        return (1);
+                }
+        } else {
+                tb = readline(R_readline_buf);
+                if (tb) {
+			add_history(tb);
+                        l = (((len-2) > strlen(tb)) ? strlen(tb) : (len-2));
+                        strncpy(buf, tb, l);
+                        buf[l] = '\n'; buf[l+1]= '\0';
+                        free(tb);
+                        return(1);
+                } else return (0);
+        }
 }


@@ -163,7 +179,8 @@
 		else
 			R_VSize = value * 1000000;
 	}
-
+	sprintf(R_readline_buf,"%s/.RData/.Audit",getenv("HOME"));
+	read_history(R_readline_buf);
 	mainloop();
 	return 0;
 }
diff -u --recursive --new-file Roriginal/src/main/gram.y R/src/main/gram.y
--- Roriginal/src/main/gram.y	Tue Jun  4 07:11:57 1996
+++ R/src/main/gram.y	Fri Aug 16 12:17:00 1996
@@ -552,6 +552,8 @@
 	return feof(R_Inputfile);
 }

+extern char R_readline_buf[1024];
+
 void yyprompt(char *format, ...)
 {
 	va_list(ap);
@@ -560,7 +562,7 @@
 		DevHold();
 #endif
 	va_start(ap, format);
-	REvprintf(format, ap);
+	vsprintf(R_readline_buf,format, ap);
 	va_end(ap);
 	fflush(stdout);
 	RBusy(0);
diff -u --recursive --new-file Roriginal/src/main/main.c R/src/main/main.c
--- Roriginal/src/main/main.c	Wed May 15 04:30:06 1996
+++ R/src/main/main.c	Fri Aug 16 14:21:52 1996
@@ -408,6 +408,8 @@
 	return tmp;
 }

+extern char R_readline_buf[1024];
+
 SEXP do_quit(SEXP call, SEXP op, SEXP args, SEXP rho)
 {
 	char *tmp;
@@ -428,6 +430,8 @@
 		ask=3;
 	else
 		errorcall(call,"unrecognized value of ask\n");
+        sprintf(R_readline_buf,"%s/.RData/.Audit",getenv("HOME"));
+	write_history(R_readline_buf);
 	RCleanUp(ask);
 	exit(0);
 	/*NOTREACHED*/
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
r-testers mailing list -- To (un)subscribe, send
subscribe	or	unsubscribe
(in the "body", not the subject !)  To: r-testers-request@stat.math.ethz.ch
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-