[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