[rkward-cvs] rkward/rkward/rbackend rembed.cpp,1.18,1.19 rembed.h,1.7,1.8 rembedinternal.cpp,1.15,1.16 rembedinternal.h,1.9,1.10 rinterface.cpp,1.23,1.24 rinterface.h,1.15,1.16 rthread.cpp,1.14,1.15 rthread.h,1.13,1.14

Thomas Friedrichsmeier tfry at users.sourceforge.net
Mon Sep 12 17:10:01 UTC 2005


Update of /cvsroot/rkward/rkward/rkward/rbackend
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16330/rkward/rbackend

Modified Files:
	rembed.cpp rembed.h rembedinternal.cpp rembedinternal.h 
	rinterface.cpp rinterface.h rthread.cpp rthread.h 
Log Message:
Started implementing R standard callbacks

Index: rthread.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rthread.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** rthread.h	4 May 2005 14:04:30 -0000	1.13
--- rthread.h	12 Sep 2005 17:09:59 -0000	1.14
***************
*** 25,28 ****
--- 25,29 ----
  class REmbed;
  class RInterface;
+ struct RCallbackArgs;
  
  #define RCOMMAND_IN_EVENT 10001
***************
*** 32,35 ****
--- 33,37 ----
  #define RSTARTED_EVENT 11001
  #define R_EVAL_REQUEST_EVENT 12001
+ #define R_CALLBACK_REQUEST_EVENT 12002
  // don't use the numbers following RSTARTUP_ERROR_EVENT, because an error code will be added!
  #define RSTARTUP_ERROR_EVENT 13000
***************
*** 81,87 ****
  	void kill () { killed = true; };
  
! /** this is a sub-eventloop, being run when the backend request information from the frontend. See \ref RThread for a more detailed description */
  	void doSubstack (char **call, int call_length);
  
  /** The command currently being executed. This is used from RInterface::cancelCommand to find out, whether the command to be cancelled is
  already/still running. */
--- 83,99 ----
  	void kill () { killed = true; };
  
! /** this is a sub-eventloop, being run when the backend request information from the frontend. See \ref RThread for a more detailed description
! 
! @see REmbed::handleSubstackCall () */
  	void doSubstack (char **call, int call_length);
  
+ /** this is a minimal sub-eventloop, being run, when the backend requests simple information from the frontend. It differs from doSubstack in two
+ points:
+ 1) it does not create a full-fledged substack for additional R commands
+ 2) it may return information via the args parameter immediately
+ 
+ @see REmbed::handleStandardCallback () */
+ 	void doStandardCallback (RCallbackArgs *args);
+ 
  /** The command currently being executed. This is used from RInterface::cancelCommand to find out, whether the command to be cancelled is
  already/still running. */

Index: rembed.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembed.cpp,v
retrieving revision 1.18
retrieving revision 1.19
diff -C2 -d -r1.18 -r1.19
*** rembed.cpp	4 May 2005 15:23:02 -0000	1.18
--- rembed.cpp	12 Sep 2005 17:09:59 -0000	1.19
***************
*** 53,56 ****
--- 53,63 ----
  }*/
  
+ void REmbed::handleStandardCallback (RCallbackArgs *args) {
+ 	RK_TRACE (RBACKEND);
+ 
+ 	if (args->type == RCallbackArgs::RWriteConsole) qDebug ("Write console: '%s'", *(args->chars_a));
+ 	thread->doStandardCallback (args);
+ }
+ 
  int REmbed::initialize () {
  	RK_TRACE (RBACKEND);
***************
*** 67,75 ****
  	
  	startR (r_home, argc, argv);
! 	
  	for (--argc; argc >= 0; --argc) {
  		delete argv[argc];
  	}
! 	
  	RKWardRError error;
  	int status = 0;
--- 74,84 ----
  	
  	startR (r_home, argc, argv);
! 
  	for (--argc; argc >= 0; --argc) {
  		delete argv[argc];
  	}
! 
! 	connectCallbacks ();
! 
  	RKWardRError error;
  	int status = 0;

Index: rinterface.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rinterface.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -C2 -d -r1.15 -r1.16
*** rinterface.h	4 May 2005 15:23:02 -0000	1.15
--- rinterface.h	12 Sep 2005 17:09:59 -0000	1.16
***************
*** 30,33 ****
--- 30,34 ----
  class RCommand;
  class RKwardApp;
+ struct RCallbackArgs;
  
  /** This class provides the main interface to the R-processor.
***************
*** 70,76 ****
  	RThread *r_thread;
  	RCommand *running_command_canceled;
! 	
  	void processREvalRequest (REvalRequest *request);
! //	void processRGetValueRequest (RGetValueRequest);	
  friend class RKwardApp;
  	RKwatch *watch;
--- 71,80 ----
  	RThread *r_thread;
  	RCommand *running_command_canceled;
! 
! /** See \ref RThread::doSubstack (). Does the actual job. */
  	void processREvalRequest (REvalRequest *request);
! //	void processRGetValueRequest (RGetValueRequest);
! /** See \ref RThread::doStandardCallback (). Does the actual job. */
! 	void processRCallbackRequest (RCallbackArgs *args);
  friend class RKwardApp;
  	RKwatch *watch;

Index: rembed.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembed.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -d -r1.7 -r1.8
*** rembed.h	28 Apr 2005 23:41:08 -0000	1.7
--- rembed.h	12 Sep 2005 17:09:59 -0000	1.8
***************
*** 62,68 ****
  	
  /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! places a call to the frontend. The call will be directly passed up to RThread::doSubstack (). */
  	void handleSubstackCall (char **call, int call_length);
  	//char **handleGetValueCall (char **call, int call_length, int *reply_length);
  private:
  	QIODevice::Offset outfile_offset;
--- 62,72 ----
  	
  /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! places a call to the frontend. The call will be directly passed up to RThread::doSubstack (). @see REmbedInternal::handleSubstackCall () */
  	void handleSubstackCall (char **call, int call_length);
  	//char **handleGetValueCall (char **call, int call_length, int *reply_length);
+ 
+ /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
+ requests a standard callback. The call will be directly passed up to RThread::doStandardCallback (). @see REmbedInternal::handleStandardCallback () */
+ 	void handleStandardCallback (RCallbackArgs *args);
  private:
  	QIODevice::Offset outfile_offset;

Index: rembedinternal.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembedinternal.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** rembedinternal.h	28 Apr 2005 23:41:08 -0000	1.9
--- rembedinternal.h	12 Sep 2005 17:09:59 -0000	1.10
***************
*** 19,24 ****
  #define R_EMBED_H
  
!  /** The main purpose of separating this class from REmbed is
! 	that R- and Qt-includes don't like each other. Hence this class is Qt-agnostic while
  	REmbed is essentially R-agnostic.
  	
--- 19,49 ----
  #define R_EMBED_H
  
! /** This struct is an ugly hack that allows us to pass all R standard callbacks to the main thread and back using the same mechanism.
! Basically, it contains enough space for all arguments and return values ever used. However, of course, it is inherently totally unsafe.
! All rests on having the handling functions know exactly, how these variables are used. So be extremely careful with modifications!
! 
! Also, of course, this method of passing the arguments is somewhat wasteful, as most of the time we're alocating a lot more memory than needed.
! However, since all R standard callbacks are used very infrequently (and ask for user interaction), this is not really an issue.
! 
! The bool done member is used to find out, when exactly the main thread has finished processing the callback. */
! struct RCallbackArgs {
! /** is main thread done with the callback, yet? Initialized to false inside the true handler: RThread::doStandardCallback () */
! 	bool done;
! 
! /** This enum specifies, what sort of callback this is */
! 	enum RCallbackType { RSuicide, RShowMessage, RReadConsole, RWriteConsole, RResetConsole, RFlushConsole, RClearerrConsole,
! 											RBusy, RCleanUp, RShowFiles, RChooseFile, REditFile, REditFiles
! 	} type;
! 
! 	char **chars_a;
! 	char **chars_b;
! 	char **chars_c;
! 	int int_a;
! 	int int_b;
! 	int int_c;
! 	bool bool_a;
! };
! 
!  /** The main purpose of separating this class from REmbed is that R- and Qt-includes don't go together well. Hence this class is Qt-agnostic while
  	REmbed is essentially R-agnostic.
  	
***************
*** 35,38 ****
--- 60,66 ----
  	virtual ~REmbedInternal();
  
+ /** connect R standard callbacks */
+ 	void connectCallbacks ();
+ 
  /** Enum specifying types of errors that may occur while parsing/evaluation a command in R */
  	enum RKWardRError {
***************
*** 90,93 ****
--- 118,127 ----
  	//virtual char **handleGetValueCall (char **call, int call_length, int *reply_length) = 0;
  
+ /** This second callback handles R standard callbacks. The difference to the first one is, that these are typically required to finish within the same
+ functions. On the other hand, also, they don't require further computations in R, and hence no full-fledged substack.
+ 
+ Otherwise it is very similar to handleSubstackCall (), esp. in that is implemented in REmbed::handleStandardCallback () */
+ 	virtual void handleStandardCallback (RCallbackArgs *args) = 0;
+ 
  /** only one instance of this class may be around. This pointer keeps the reference to it, for interfacing to from C to C++ */
  	static REmbedInternal *this_pointer;

Index: rembedinternal.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembedinternal.cpp,v
retrieving revision 1.15
retrieving revision 1.16
diff -C2 -d -r1.15 -r1.16
*** rembedinternal.cpp	4 May 2005 14:04:30 -0000	1.15
--- rembedinternal.cpp	12 Sep 2005 17:09:59 -0000	1.16
***************
*** 23,26 ****
--- 23,27 ----
   
  extern "C" {
+ #define R_INTERFACE_PTRS 1
  
  #include "R_ext/Rdynload.h"
***************
*** 28,31 ****
--- 29,33 ----
  #include "R.h"
  #include "Rinternals.h"
+ #include "Rinterface.h"
  
  #include <stdlib.h>
***************
*** 36,39 ****
--- 38,121 ----
  #include "../rkglobals.h"
  
+ /// ############## R Standard callback overrides BEGIN ####################
+ void RSuicide (char* message) {
+ // TODO
+ }
+ 
+ void RShowMessage (char* message) {
+ 	RCallbackArgs args;
+ 	args.type = RCallbackArgs::RShowMessage;
+ 	args.chars_a = &message;
+ 	REmbedInternal::this_pointer->handleStandardCallback (&args);
+ }
+ 
+ int RReadConsole (char* prompt, unsigned char* buf, int buflen, int hist) {
+ 	RCallbackArgs args;
+ 	args.type = RCallbackArgs::RReadConsole;
+ 	args.chars_a = &prompt;
+ 	args.chars_b = (char **) (&buf);
+ 	args.int_a = buflen;
+ 	args.int_b = hist;		// actually, we ignore hist
+ 
+ 	REmbedInternal::this_pointer->handleStandardCallback (&args);
+ // default implementation seems to return 1 on success, 0 on failure, contrary to some documentation. see unix/std-sys.c
+ 	if (buf)	return 1;
+ 	return 0;
+ }
+ 
+ void RWriteConsole (char *buf, int buflen) {
+ 	RCallbackArgs args;
+ 	args.type = RCallbackArgs::RWriteConsole;
+ 	args.chars_a = &buf;
+ 	args.int_a = buflen;
+ 	REmbedInternal::this_pointer->handleStandardCallback (&args);
+ }
+ 
+ void RResetConsole () {
+ // we leave this un-implemented on purpose! We simply don't want that sort of thing to be done.
+ }
+ 
+ void RFlushConsole () {
+ // we leave this un-implemented on purpose! We simply don't want that sort of thing to be done.
+ }
+ 
+ void RClearerrConsole () {
+ // we leave this un-implemented on purpose! We simply don't want that sort of thing to be done.
+ }
+ 
+ void RBusy (int which) {
+ //TODO
+ }
+ 
+ void RCleanUp (SA_TYPE saveact, int status, int RunLast) {
+ // TODO
+ }
+ 
+ int RShowFiles (int nfile, char **file, char **headers, char *wtitle, Rboolean del, char *pager) {
+ // TODO
+ // default implementation seems to returns 1 on success, 0 on failure. see unix/std-sys.c
+ 	return 1;
+ }
+ 
+ int RChooseFile (int isnew, char *buf, int len) {
+ // TODO
+ // return length of filename (strlen (buf))
+ 	return 0;
+ }
+ 
+ int REditFile (char *buf) {
+ // TODO
+ // does not exist in standard R 2.1.0, so no idea what to return.
+ 	return 0;
+ }
+ 
+ int REditFiles (int nfile, char **file, char **title, char *editor) {
+ //TODO
+ // default impelementation seems to return 1 if nfile <= 0, else 1. No idea, what for. see unix/std-sys.c
+ 	return (nfile <= 0);
+ }
+ /// ############## R Standard callback overrides END ####################
+ 
+ 
  REmbedInternal::REmbedInternal() {
  	RKGlobals::empty_char = strdup ("");
***************
*** 42,46 ****
  }
  
! REmbedInternal::~REmbedInternal(){
  }
  
--- 124,155 ----
  }
  
! void REmbedInternal::connectCallbacks () {
! // R standard callback pointers.
! // Rinterface.h thinks this can only ever be done on aqua, apparently. Here, we define it the other way around, i.e. #ifndef instead of #ifdef
! #ifndef HAVE_AQUA
! 	extern int  (*ptr_R_EditFiles)(int, char **, char **, char *);
! #endif
! 
! // connect R standard callback to our own functions. Important: Don't do so, before our own versions are ready to be used!
! //	ptr_R_Suicide = RSuicide;
! 	ptr_R_ShowMessage = RShowMessage;			// when exactly does this ever get used?
! 	ptr_R_ReadConsole = RReadConsole;
! 	ptr_R_WriteConsole = RWriteConsole;				// when exactly does this ever get used? Apparently it does not get called if a sink is in place, but otherwise it is! Probably we can get rid of our sink, then, and provide "real-time" output! More '!'s!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 	ptr_R_ResetConsole = RResetConsole;
! 	ptr_R_FlushConsole = RFlushConsole;
! 	ptr_R_ClearerrConsole = RClearerrConsole;
! //	ptr_R_Busy = RBusy;
! //	ptr_R_CleanUp = RCleanUp;
! //	ptr_R_ShowFiles = RShowFiles;
! //	ptr_R_ChooseFile = RChooseFile;
! //	ptr_R_EditFile = REditFile;
! //	ptr_R_EditFiles = REditFiles;
! 
! // these two, we won't override
! //	ptr_R_loadhistory = ... 	// we keep our own history
! //	ptr_R_savehistory = ...	// we keep our own history
! }
! 
! REmbedInternal::~REmbedInternal (){
  }
  
***************
*** 68,72 ****
  TODO: verify we really need this. */
  	if (++timeout_counter > 100) {
! 		extern void (* R_timeout_handler) ();
  		if (R_timeout_handler) R_timeout_handler ();
  		timeout_counter = 0;
--- 177,181 ----
  TODO: verify we really need this. */
  	if (++timeout_counter > 100) {
! //		extern void (* R_timeout_handler) ();	// already defined in Rinferface.h
  		if (R_timeout_handler) R_timeout_handler ();
  		timeout_counter = 0;

Index: rthread.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rthread.cpp,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** rthread.cpp	20 Apr 2005 17:44:12 -0000	1.14
--- rthread.cpp	12 Sep 2005 17:09:59 -0000	1.15
***************
*** 154,155 ****
--- 154,177 ----
  	delete reply_stack;
  }
+ 
+ void RThread::doStandardCallback (RCallbackArgs *args) {
+ 	RK_TRACE (RBACKEND);
+ 
+ 	QCustomEvent *event = new QCustomEvent (R_CALLBACK_REQUEST_EVENT);
+ 	event->setData (args);
+ 	qApp->postEvent (inter, event);
+ 	
+ 	bool done = false;
+ 	while (!done) {
+ 		// callback not done yet? Sleep for a while
+ 		msleep (10);
+ 
+ 		MUTEX_LOCK;
+ 		embeddedR->processX11Events ();
+ 
+ 		if (args->done) {
+ 			done = true;		// safe to access only while the mutex is locked
+ 		}
+ 		MUTEX_UNLOCK;
+ 	}
+ }

Index: rinterface.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rinterface.cpp,v
retrieving revision 1.23
retrieving revision 1.24
diff -C2 -d -r1.23 -r1.24
*** rinterface.cpp	8 May 2005 16:54:29 -0000	1.23
--- rinterface.cpp	12 Sep 2005 17:09:59 -0000	1.24
***************
*** 144,147 ****
--- 144,149 ----
  	} else if ((e->type () == R_EVAL_REQUEST_EVENT)) {
  		processREvalRequest (static_cast<REvalRequest *> (e->data ()));
+ 	} else if ((e->type () == R_CALLBACK_REQUEST_EVENT)) {
+ 		processRCallbackRequest (static_cast<RCallbackArgs *> (e->data ()));
  	} else if ((e->type () == RSTARTED_EVENT)) {
  		r_thread->unlock ();
***************
*** 281,282 ****
--- 283,303 ----
  }
  
+ void RInterface::processRCallbackRequest (RCallbackArgs *args) {
+ 	RK_TRACE (RBACKEND);
+ 
+ 	// first, copy out the type while mutex is locked. Allows for easier typing below
+ 	MUTEX_LOCK;
+ 	RCallbackArgs::RCallbackType type = args->type;
+ 
+ 	if (type == RCallbackArgs::RShowMessage) {
+ 		KMessageBox::information (0, QString (*(args->chars_a)), i18n ("Message from the R backend"));
+ 	} else if (type == RCallbackArgs::RReadConsole) {
+ 		QString res = KInputDialog::getText (i18n ("R backend requests information"), QString (*(args->chars_a)));
+ 		res = res.left (args->int_a - 2) + "\n";
+ 		qstrcpy (*(args->chars_b), res.latin1 ());
+ 	}
+ 
+ 	args->done = true;
+ 	MUTEX_UNLOCK;
+ }
+ 





More information about the rkward-tracker mailing list