[rkward-cvs] rkward/rkward/rbackend rcommand.cpp,1.6,1.7 rcommand.h,1.14,1.15 rembed.cpp,1.21,1.22 rembed.h,1.8,1.9 rembedinternal.cpp,1.20,1.21 rembedinternal.h,1.12,1.13 rinterface.cpp,1.26,1.27

Thomas Friedrichsmeier tfry at users.sourceforge.net
Fri Sep 23 14:29:49 UTC 2005


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

Modified Files:
	rcommand.cpp rcommand.h rembed.cpp rembed.h rembedinternal.cpp 
	rembedinternal.h rinterface.cpp 
Log Message:
Finished moving away from file-sinks to more direct method of retrieving output. Unfortunately, there is no way, yet, to reliably identify warning messages

Index: rembed.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembed.cpp,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -d -r1.21 -r1.22
*** rembed.cpp	18 Sep 2005 15:17:54 -0000	1.21
--- rembed.cpp	23 Sep 2005 14:29:47 -0000	1.22
***************
*** 32,35 ****
--- 32,39 ----
  #include "../debug.h"
  
+ // static
+ //bool REmbedInternal::next_output_is_error = false;
+ //bool REmbedInternal::output_is_warning = false;
+ 
  REmbed::REmbed (RThread *thread) : REmbedInternal() {
  	RK_TRACE (RBACKEND);
***************
*** 46,63 ****
  }
  
! void REmbed::handleSubstackCall (char **call, int call_length) {
  	RK_TRACE (RBACKEND);
! 	thread->doSubstack (call, call_length);
  }
  /*
! char **REmbed::handleGetValueCall (char **call, int call_length, int *reply_length) {
  	RK_TRACE (RBACKEND);
! 	return thread->fetchValue (call, call_length, reply_length);
! }*/
  
  void REmbed::handleStandardCallback (RCallbackArgs *args) {
  	RK_TRACE (RBACKEND);
  
- 	if (args->type == RCallbackArgs::RWriteConsole) qDebug ("Write console: '%s'", *(args->chars_a));
  	thread->doStandardCallback (args);
  }
--- 50,115 ----
  }
  
! void REmbed::handleOutput (char *buf, int buf_length) {
  	RK_TRACE (RBACKEND);
! 
! 	if (!buf_length) return;
! /*	if (REmbedInternal::next_output_is_error) {
! 		REmbedInternal::next_output_is_error = false;
! 		return;
! 	}*/
! 	if (!thread->current_command) return;
! 
! 	ROutput *out = new ROutput;
! 	out->type = ROutput::Output;
! 	out->output = QString (buf);
! 
! 	thread->current_command->output_list.append (out);
! 	thread->current_command->status |= RCommand::HasOutput;
! 	// TODO: pass a signal to the thread for real-time update of output
! 
! 	RK_DO (qDebug ("output '%s'", buf), RBACKEND, DL_DEBUG);
  }
+ 
  /*
! void REmbed::handleCondition (char **call, int call_length) {
! 	RK_TRACE (RBACKEND);
! 
! 	RK_ASSERT (call_length >= 2);
! 	if (!call_length) return;
! 
! 	//REmbedInternal::next_output_is_error = true;
! 	qDebug ("condition '%s', message '%s'", call[0], call[1]);
! } */
! 
! void REmbed::handleError (char **call, int call_length) {
  	RK_TRACE (RBACKEND);
! 
! 	if (!call_length) return;
! 
! 	// Unfortunately, errors still get printed to the output. We try this crude method for the time being:
! 	thread->current_command->output_list.last ()->type = ROutput::Error;
! 	thread->current_command->status |= RCommand::HasError;
! 
! /*	// for now we ignore everything but the first string.
! 	ROutput *out = new ROutput;
! 	out->type = ROutput::Error;
! 	out->output = QString (call[0]);
! 
! 	thread->current_command->output_list.append (out);
! 	thread->current_command->status |= RCommand::HasError; */
! 	// TODO: pass a signal to the thread for real-time update of output
! 
! 	//REmbedInternal::next_output_is_error = true;
! 	RK_DO (qDebug ("error '%s'", call[0]), RBACKEND, DL_DEBUG);
! }
! 
! void REmbed::handleSubstackCall (char **call, int call_length) {
! 	RK_TRACE (RBACKEND);
! 	thread->doSubstack (call, call_length);
! }
  
  void REmbed::handleStandardCallback (RCallbackArgs *args) {
  	RK_TRACE (RBACKEND);
  
  	thread->doStandardCallback (args);
  }
***************
*** 99,106 ****
  	runCommandInternal (command + "))\n", &error);
  	if (error) status |= OtherFail;
! 	runCommandInternal ("sink (\"" + RKSettingsModuleLogfiles::filesPath () + "/r_out\")\n", &error);
! 	if (error) status |= SinkFail;
! 	runCommandInternal ("sink (file (\"" +RKSettingsModuleLogfiles::filesPath () +"/r_err\", \"w\"), FALSE, \"message\")\n", &error);
  	if (error) status |= SinkFail;
  	runCommandInternal ("options (htmlhelp=TRUE); options (browser=\"dcop " + kapp->dcopClient ()->appId () + " rkwardapp openHTMLHelp \")", &error);
  	if (error) status |= OtherFail;
--- 151,158 ----
  	runCommandInternal (command + "))\n", &error);
  	if (error) status |= OtherFail;
! 	runCommandInternal ("options (error=quote (.rk.do.error ()))\n", &error);
  	if (error) status |= SinkFail;
+ /*	runCommandInternal (".rk.init.handlers ()\n", &error);
+ 	if (error) status |= SinkFail; */
  	runCommandInternal ("options (htmlhelp=TRUE); options (browser=\"dcop " + kapp->dcopClient ()->appId () + " rkwardapp openHTMLHelp \")", &error);
  	if (error) status |= OtherFail;
***************
*** 109,122 ****
  	outfile_offset = 0;
  	errfile_offset = 0;
! 		
! 	outfile.setName (RKSettingsModuleLogfiles::filesPath () + "/r_out");
! 	if (!outfile.open (IO_ReadOnly)) {
! 		if (error) status |= SinkFail;
! 	}
! 	errfile.setName (RKSettingsModuleLogfiles::filesPath () + "/r_err");
! 	if (!errfile.open (IO_ReadOnly)) {
! 		if (error) status |= SinkFail;
! 	}
! 	
  	return status;
  }
--- 161,165 ----
  	outfile_offset = 0;
  	errfile_offset = 0;
! 
  	return status;
  }
***************
*** 124,128 ****
  void REmbed::runCommand (RCommand *command) {
  	RK_TRACE (RBACKEND);
! 	
  	if (command->type () & RCommand::EmptyCommand) return;
  	
--- 167,171 ----
  void REmbed::runCommand (RCommand *command) {
  	RK_TRACE (RBACKEND);
! 
  	if (command->type () & RCommand::EmptyCommand) return;
  	
***************
*** 171,192 ****
  	}
  
  	if (command->type () & RCommand::DirectToOutput) {
! 		runCommandInternal ("sink ()\n", &error);
! 	}
! 
! 	QString temp = "";
! 	while (!outfile.atEnd ()) {
! 		outfile.readLine (temp, 2048);
! 		command->_output.append (temp);
! 		command->status |= RCommand::HasOutput;
  	}
  
! 	temp = "";
! 	while (!errfile.atEnd ()) {
! 		errfile.readLine (temp, 2048);
! 		command->_error.append (temp);
! 		command->status |= RCommand::HasError;
  	}
- 	
- 	RK_DO (if (error) qDebug ("- error message was: '%s'", command->error ().latin1 ()), RBACKEND, DL_WARNING);
  }
--- 214,225 ----
  	}
  
+ 	RKWardRError dummy;
  	if (command->type () & RCommand::DirectToOutput) {
! 		runCommandInternal ("sink ()\n", &dummy);
  	}
  
! 	if (error) {
! 		RK_DO (qDebug ("- error message was: '%s'", command->error ().latin1 ()), RBACKEND, DL_WARNING);
! //		runCommandInternal (".rk.init.handlers ()\n", &dummy);
  	}
  }

Index: rinterface.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rinterface.cpp,v
retrieving revision 1.26
retrieving revision 1.27
diff -C2 -d -r1.26 -r1.27
*** rinterface.cpp	14 Sep 2005 16:32:25 -0000	1.26
--- rinterface.cpp	23 Sep 2005 14:29:47 -0000	1.27
***************
*** 129,133 ****
  		if (command->status & RCommand::Canceled) {
  			command->status |= RCommand::HasError;
! 			command->_error.append ("--- interrupted ---");
  			if (running_command_canceled) {
  				RK_ASSERT (command == running_command_canceled);
--- 129,136 ----
  		if (command->status & RCommand::Canceled) {
  			command->status |= RCommand::HasError;
! 			ROutput *out = new ROutput;
! 			out->type = ROutput::Error;
! 			out->output = ("--- interrupted ---");
! 			command->output_list.append (out);
  			if (running_command_canceled) {
  				RK_ASSERT (command == running_command_canceled);

Index: rembed.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembed.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** rembed.h	12 Sep 2005 17:09:59 -0000	1.8
--- rembed.h	23 Sep 2005 14:29:47 -0000	1.9
***************
*** 60,68 ****
  Note that you should call initialize only once in a application */
  	int initialize ();
! 	
  /** 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
--- 60,79 ----
  Note that you should call initialize only once in a application */
  	int initialize ();
! 
! /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! generates standard output. @see REmbedInternal::handleOutput () */
! 	void handleOutput (char *buf, int buf_length);
! 
! /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! signals a condition. @see REmbedInternal::handleCondition () */
! //	void handleCondition (char **call, int call_length);
! 
! /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
! reports an error. @see REmbedInternal::handleError () */
! 	void handleError (char **call, int call_length);
! 
  /** 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);
  
  /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend

Index: rembedinternal.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembedinternal.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** rembedinternal.h	14 Sep 2005 16:32:25 -0000	1.12
--- rembedinternal.h	23 Sep 2005 14:29:47 -0000	1.13
***************
*** 115,122 ****
  	static void processX11Events ();
  
  /** The main callback from R to rkward. Since we need QStrings and stuff to handle the requests, this is only a pure virtual function. The real
  implementation is in REmbed::handleSubstackCall () */
  	virtual void handleSubstackCall (char **call, int call_length) = 0;
- 	//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
--- 115,130 ----
  	static void processX11Events ();
  
+ /** This gets called, on normal R output (R_WriteConsole). Used to get at output. */
+ 	virtual void handleOutput (char *buf, int buf_length) = 0;
+ 
+ /** This gets called, when R reports warnings/messages. Used to get at warning-output. */
+ //	virtual void handleCondition (char **call, int call_length) = 0;
+ 
+ /** This gets called, when R reports an error (override of options ("error") in R). Used to get at error-output. */
+ 	virtual void handleError (char **call, int call_length) = 0;
+ 
  /** The main callback from R to rkward. Since we need QStrings and stuff to handle the requests, this is only a pure virtual function. The real
  implementation is in REmbed::handleSubstackCall () */
  	virtual void handleSubstackCall (char **call, int call_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
***************
*** 128,131 ****
--- 136,144 ----
  /** 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;
+ 
+ /** Flags used to classify output. */
+ //	static bool output_is_warning;
+ /** Flags used to classify output. */
+ //	static bool next_output_is_error;
  private:
  // can't declare this as part of the class, as it would confuse REmbed

Index: rembedinternal.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembedinternal.cpp,v
retrieving revision 1.20
retrieving revision 1.21
diff -C2 -d -r1.20 -r1.21
*** rembedinternal.cpp	19 Sep 2005 20:10:21 -0000	1.20
--- rembedinternal.cpp	23 Sep 2005 14:29:47 -0000	1.21
***************
*** 70,78 ****
  
  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);
  }
  
--- 70,79 ----
  
  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); */
! 	REmbedInternal::this_pointer->handleOutput (buf, buflen);
  }
  
***************
*** 157,161 ****
  	REmbedInternal::this_pointer->handleStandardCallback (&args);
  
! // default impelementation seems to return 1 if nfile <= 0, else 1. No idea, what for. see unix/std-sys.c
  	return (nfile <= 0);
  }
--- 158,162 ----
  	REmbedInternal::this_pointer->handleStandardCallback (&args);
  
! // default implementation seems to return 1 if nfile <= 0, else 1. No idea, what for. see unix/std-sys.c
  	return (nfile <= 0);
  }
***************
*** 171,175 ****
  /// ############## R Standard callback overrides END ####################
  
- 
  REmbedInternal::REmbedInternal() {
  	RKGlobals::empty_char = strdup ("");
--- 172,175 ----
***************
*** 187,190 ****
--- 187,192 ----
  
  // connect R standard callback to our own functions. Important: Don't do so, before our own versions are ready to be used!
+ 	R_Outputfile = NULL;
+ 	R_Consolefile = NULL;
  	ptr_R_Suicide = RSuicide;
  	ptr_R_ShowMessage = RShowMessage;			// when exactly does this ever get used?
***************
*** 281,292 ****
  	return strings;
  }
  /*
! SEXP getValueCall (SEXP call) {
  	int count;
  	char **strings = extractStrings (call, &count);
! 	int reply_length;
! 	REmbedInternal::this_pointer->handleGetValueCall (strings, count, &reply_length);
! 	return call;
! }*/
  
  SEXP doSubstackCall (SEXP call) {
--- 283,312 ----
  	return strings;
  }
+ 
+ void deleteStrings (char **strings, int count) {
+ 	for (int i= (count-1); i >=0; --i) {
+ 		delete (strings[i]);
+ 	}
+ 	delete [] strings;
+ }
+ 
+ SEXP doError (SEXP call) {
+ 	extern int R_ShowErrorMessages;
+ 	if (R_ShowErrorMessages) {
+ 		int count;
+ 		char **strings = extractStrings (call, &count);
+ 		REmbedInternal::this_pointer->handleError (strings, count);
+ 		deleteStrings (strings, count);
+ 	}
+ 	return R_NilValue;
+ }
+ 
  /*
! SEXP doCondition (SEXP call) {
  	int count;
  	char **strings = extractStrings (call, &count);
! 	REmbedInternal::this_pointer->handleCondition (strings, count);
! 	return R_NilValue;
! } */
  
  SEXP doSubstackCall (SEXP call) {
***************
*** 294,297 ****
--- 314,318 ----
  	char **strings = extractStrings (call, &count);
  	REmbedInternal::this_pointer->handleSubstackCall (strings, count);
+ 	deleteStrings (strings, count);
  	return R_NilValue;
  }
***************
*** 311,315 ****
  	
  	R_CallMethodDef callMethods [] = {
! 		//{ "rk.get.value", (DL_FUNC) &getValueCall, 1 },
  		{ "rk.do.command", (DL_FUNC) &doSubstackCall, 1 },
  		{ 0, 0, 0 }
--- 332,337 ----
  	
  	R_CallMethodDef callMethods [] = {
! //		{ "rk.do.condition", (DL_FUNC) &doCondition, 1 },
! 		{ "rk.do.error", (DL_FUNC) &doError, 1 },
  		{ "rk.do.command", (DL_FUNC) &doSubstackCall, 1 },
  		{ 0, 0, 0 }

Index: rcommand.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rcommand.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** rcommand.h	27 Apr 2005 17:11:28 -0000	1.14
--- rcommand.h	23 Sep 2005 14:29:47 -0000	1.15
***************
*** 23,26 ****
--- 23,27 ----
  #include <qobject.h>
  #include <qptrlist.h>
+ #include <qvaluelist.h>
  
  class RCommandReceiver;
***************
*** 61,64 ****
--- 62,77 ----
  };
  
+ /** this struct is used to store the R output to an RCommand. The RCommand basically keeps a list of ROutputString (s). The difference to a normal
+ QString is, that additionally we store information on whether the output was "normal", "warning", or an "error". */
+ struct ROutput {
+ 	enum ROutputType {
+ 		Output,			/**< normal output */
+ 		Warning,		/**< R warning */
+ 		Error				/**< R error */
+ 	};
+ 	ROutputType type;
+ 	QString output;
+ };
+ 
  /*
  struct RGetValueRequest {
***************
*** 121,128 ****
  	int id () { return _id; };
  /* TODO: Adjust these two functions to allow re-getting of output and error-messages from logs */
! /** @returns the output of the command, if any (e.g. "[1] 1" for "print (1)"). @see RCommand::succeeded @see RCommand::hasOutput */
! 	QString output () { return _output; };
  /** @returns the error message given by R, if any. @see RCommand::failed @see RCommand::hasError */
! 	QString error () { return _error; };
  /** Types of commands (potentially more to come), bitwise or-able,
  	although partially exclusive. See \ref UsingTheInterfaceToR for a overview of what these are used for. TODO: find out, why Canceled is in here, and document that fact. */
--- 134,145 ----
  	int id () { return _id; };
  /* TODO: Adjust these two functions to allow re-getting of output and error-messages from logs */
! /** @returns the full output of the command, i.e. all "regular" output, warning messages, and errors, in the order they were encountered. @see RCommand::output @see RCommand::error @see RCommand::warnings */
! 	QString fullOutput ();
! /** @returns the "regular" (ROutput::Output) output of the command, if any (e.g. "[1] 1" for "print (1)"). @see RCommand::succeeded @see RCommand::hasOutput */
! 	QString output ();
! /** @returns the warning message(s) given by R, if any. @see RCommand::output @see RCommand::error */
! 	QString warnings ();
  /** @returns the error message given by R, if any. @see RCommand::failed @see RCommand::hasError */
! 	QString error ();
  /** Types of commands (potentially more to come), bitwise or-able,
  	although partially exclusive. See \ref UsingTheInterfaceToR for a overview of what these are used for. TODO: find out, why Canceled is in here, and document that fact. */
***************
*** 145,148 ****
--- 162,166 ----
  		HasOutput=4,					/**< command has a string output retrievable via RCommand::output () */
  		HasError=8,						/**< command has an error-message retrievable via RCommand::error () */
+ 		HasWarnings=16,			/**< command has warning-message(s) retrievable via RCommand::warnings () */
  		ErrorIncomplete=512,		/**< backend rejected command as being incomplete */
  		ErrorSyntax=1024,			/**< backend rejected command as having a syntax error */
***************
*** 188,193 ****
  /** internal function will be called by the backend, as the command gets passed through. Takes care of sending this command (back) to its receiver */
  	void finished ();
! 	QString _output;
! 	QString _error;
  	QString _command;
  	char **string_data;
--- 206,210 ----
  /** internal function will be called by the backend, as the command gets passed through. Takes care of sending this command (back) to its receiver */
  	void finished ();
! 	QValueList<ROutput*> output_list;
  	QString _command;
  	char **string_data;

Index: rcommand.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rcommand.cpp,v
retrieving revision 1.6
retrieving revision 1.7
diff -C2 -d -r1.6 -r1.7
*** rcommand.cpp	14 Sep 2004 23:34:01 -0000	1.6
--- rcommand.cpp	23 Sep 2005 14:29:47 -0000	1.7
***************
*** 52,55 ****
--- 52,60 ----
  	delete real_data;
  	delete integer_data;
+ 
+ 	for (QValueList<ROutput*>::iterator it = output_list.begin (); it != output_list.end (); ++it) {
+ 		delete (*it);
+ 	}
+ 	// The output_list itself is cleared automatically
  }
  
***************
*** 61,62 ****
--- 66,113 ----
  	}
  }
+ 
+ QString RCommand::error () {
+ 	RK_TRACE (RBACKEND);
+ 
+ 	QString ret;
+ 	for (QValueList<ROutput*>::const_iterator it = output_list.begin (); it != output_list.end (); ++it) {
+ 		if ((*it)->type == ROutput::Error) {
+ 			ret.append ((*it)->output);
+ 		}
+ 	}
+ 	return ret;
+ }
+ 
+ QString RCommand::output () {
+ 	RK_TRACE (RBACKEND);
+ 
+ 	QString ret;
+ 	for (QValueList<ROutput*>::const_iterator it = output_list.begin (); it != output_list.end (); ++it) {
+ 		if ((*it)->type == ROutput::Output) {
+ 			ret.append ((*it)->output);
+ 		}
+ 	}
+ 	return ret;
+ }
+ 
+ QString RCommand::warnings () {
+ 	RK_TRACE (RBACKEND);
+ 
+ 	QString ret;
+ 	for (QValueList<ROutput*>::const_iterator it = output_list.begin (); it != output_list.end (); ++it) {
+ 		if ((*it)->type == ROutput::Warning) {
+ 			ret.append ((*it)->output);
+ 		}
+ 	}
+ 	return ret;
+ }
+ 
+ QString RCommand::fullOutput () {
+ 	RK_TRACE (RBACKEND);
+ 
+ 	QString ret;
+ 	for (QValueList<ROutput*>::const_iterator it = output_list.begin (); it != output_list.end (); ++it) {
+ 		ret.append ((*it)->output);
+ 	}
+ 	return ret;
+ }





More information about the rkward-tracker mailing list