[rkward-cvs] SF.net SVN: rkward: [1577] trunk/rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Wed Mar 14 13:23:27 UTC 2007


Revision: 1577
          http://svn.sourceforge.net/rkward/?rev=1577&view=rev
Author:   tfry
Date:     2007-03-14 06:23:26 -0700 (Wed, 14 Mar 2007)

Log Message:
-----------
Make sure never to run parts of incomplete user commands

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/rkward/rbackend/rcommand.h
    trunk/rkward/rkward/rbackend/rembedinternal.cpp
    trunk/rkward/rkward/rbackend/rembedinternal.h
    trunk/rkward/rkward/rkconsole.cpp

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2007-03-14 12:38:17 UTC (rev 1576)
+++ trunk/rkward/ChangeLog	2007-03-14 13:23:26 UTC (rev 1577)
@@ -1,3 +1,4 @@
+- make sure not to run parts of an incomplete user command. It would lead to all sorts of subtle problems
 - if an incomplete command was piped through the console, the console does not become blocked for piping
 - make "run current line" advance the cursor to next line after running
 - warnings and errors are highlighted in command log / console (warnings only for R >= 2.5.x)

Modified: trunk/rkward/rkward/rbackend/rcommand.h
===================================================================
--- trunk/rkward/rkward/rbackend/rcommand.h	2007-03-14 12:38:17 UTC (rev 1576)
+++ trunk/rkward/rkward/rbackend/rcommand.h	2007-03-14 13:23:26 UTC (rev 1577)
@@ -200,6 +200,8 @@
 	void removeReceiver (RCommandReceiver *receiver);
 	void addTypeFlag (int flag) { _type |= flag; };
 	ROutputList &getOutput () { return output_list; };
+/** modify the command string. DO NOT CALL THIS after the command has been submitted! */
+	void setCommand (const QString &command) { _command = command; };
 private:
 friend class RThread;
 friend class RInterface;

Modified: trunk/rkward/rkward/rbackend/rembedinternal.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rembedinternal.cpp	2007-03-14 12:38:17 UTC (rev 1576)
+++ trunk/rkward/rkward/rbackend/rembedinternal.cpp	2007-03-14 13:23:26 UTC (rev 1577)
@@ -645,13 +645,11 @@
 	return true;
 }
 
-SEXP runCommandInternalBase (const QString &command_qstring, REmbedInternal::RKWardRError *error) {
+SEXP parseCommand (const QString &command_qstring, REmbedInternal::RKWardRError *error) {
 	RK_TRACE (RBACKEND);
 
-// some copying from RServe below
-	int r_error = 0;
 	ParseStatus status = PARSE_NULL;
-	SEXP cv, pr, exp;
+	SEXP cv, pr;
 
 	int len = -1;
 	QCString localc = REmbedInternal::this_pointer->current_locale_codec->fromUnicode (command_qstring, len);		// needed so the string below does not go out of scope
@@ -686,34 +684,43 @@
 		} else { // PARSE_NULL
 			*error = REmbedInternal::OtherError;
 		}
-		exp = R_NilValue;
-	} else {			// no error during parsing, let's try to evaluate the command
-		PROTECT (pr);
-		exp=R_NilValue;
+		pr = R_NilValue;
+	}
 
-		if (TYPEOF(pr)==EXPRSXP && LENGTH(pr)>0) {
-			int bi=0;
-			while (bi<LENGTH(pr)) {
-				SEXP pxp=VECTOR_ELT(pr, bi);
-				exp=R_tryEval(pxp, R_GlobalEnv, &r_error);
-				bi++;
-				if (r_error) {
-					break;
-				}
+	return pr;
+}
+
+SEXP runCommandInternalBase (SEXP pr, REmbedInternal::RKWardRError *error) {
+	RK_TRACE (RBACKEND);
+
+	SEXP exp;
+	int r_error = 0;
+
+	PROTECT (pr);
+	exp=R_NilValue;
+
+	if (TYPEOF(pr)==EXPRSXP && LENGTH(pr)>0) {
+		int bi=0;
+		while (bi<LENGTH(pr)) {
+			SEXP pxp=VECTOR_ELT(pr, bi);
+			exp=R_tryEval(pxp, R_GlobalEnv, &r_error);
+			bi++;
+			if (r_error) {
+				break;
 			}
-		} else {
-			exp=R_tryEval(pr, R_GlobalEnv, &r_error);
 		}
+	} else {
+		exp=R_tryEval(pr, R_GlobalEnv, &r_error);
+	}
 
-		if (r_error) {
-			*error = REmbedInternal::OtherError;
-		} else {
-			*error = REmbedInternal::NoError;
-		}
-
-		UNPROTECT(1); /* pr */
+	if (r_error) {
+		*error = REmbedInternal::OtherError;
+	} else {
+		*error = REmbedInternal::NoError;
 	}
 
+	UNPROTECT(1); /* pr */
+
 	// for safety, let's protect exp for the two print calls below.
 	// TODO: this is not good. It causes an additional PROTECT and UPROTECT. Need to (re-)move printing
 	PROTECT (exp);
@@ -782,9 +789,13 @@
 
 	connectCallbacks ();		// sorry, but we will not play nicely with additional frontends trying to override our callbacks. (Unless they start their own R event loop, then they should be fine)
 
+	*error = NoError;
 	if (!print_result) {
-		runCommandInternalBase (command_qstring, error);
+		SEXP parsed = parseCommand (command_qstring, error);
+		if (*error == NoError) runCommandInternalBase (parsed, error);
 	} else {		// run a user command
+		SEXP parsed = parseCommand (command_qstring, error);
+		if ((*error != NoError)) return;
 #ifdef USE_R_REPLDLLDO1
 /* Using R_ReplDLLdo1 () is a pain, but it seems to be the only entry point for evaluating a command as if it had been entered on a plain R console (with auto-printing if not invisible, etc.). Esp. since R_Visible is no longer exported in R 2.5.0, as it seems as of today (2007-01-17).
 
@@ -837,10 +848,8 @@
 		R_Visible = (Rboolean) 0;
 
 		SEXP exp;
-		PROTECT (exp = runCommandInternalBase (command_qstring, error));
-/*		char dummy[100];
-		sprintf (dummy, "type: %d", TYPEOF (exp));
-		Rprintf (dummy, 100); */
+		PROTECT (exp = runCommandInternalBase (parsed, error));
+
 		if (*error == NoError) {
 			SET_SYMVALUE (R_LastvalueSymbol, exp);
 			if (R_Visible) {
@@ -862,9 +871,11 @@
 
 	SEXP exp;
 	QString *list = 0;
+
+	*error = NoError;
+	SEXP parsed = parseCommand (command, error);
+	if (*error == NoError) PROTECT (exp = runCommandInternalBase (parsed, error));
 	
-	PROTECT (exp = runCommandInternalBase (command, error));
-	
 	if (*error == NoError) {
 		list = SEXPToStringList (exp, count);
 	}
@@ -884,7 +895,9 @@
 	SEXP exp;
 	double *reals = 0;
 	
-	PROTECT (exp = runCommandInternalBase (command, error));
+	*error = NoError;
+	SEXP parsed = parseCommand (command, error);
+	if (*error == NoError) PROTECT (exp = runCommandInternalBase (parsed, error));
 	
 	if (*error == NoError) {
 		reals = SEXPToRealArray (exp, count);
@@ -905,7 +918,9 @@
 	SEXP exp;
 	int *integers = 0;
 	
-	PROTECT (exp = runCommandInternalBase (command, error));
+	*error = NoError;
+	SEXP parsed = parseCommand (command, error);
+	if (*error == NoError) PROTECT (exp = runCommandInternalBase (parsed, error));
 	
 	if (*error == NoError) {
 		integers = SEXPToIntArray (exp, count);
@@ -926,7 +941,9 @@
 	SEXP exp;
 	RData *data = 0;
 	
-	PROTECT (exp = runCommandInternalBase (command, error));
+	*error = NoError;
+	SEXP parsed = parseCommand (command, error);
+	if (*error == NoError) PROTECT (exp = runCommandInternalBase (parsed, error));
 	
 	if (*error == NoError) {
 		data = SEXPToRData (exp);

Modified: trunk/rkward/rkward/rbackend/rembedinternal.h
===================================================================
--- trunk/rkward/rkward/rbackend/rembedinternal.h	2007-03-14 12:38:17 UTC (rev 1576)
+++ trunk/rkward/rkward/rbackend/rembedinternal.h	2007-03-14 13:23:26 UTC (rev 1577)
@@ -94,7 +94,8 @@
 @param command command to be run
 @param error this will be set to a value in RKWardError depending on success/failure of the command
 @param print_result whether the R_Visible flag should be set. If true, R will behave mostly as if in a regular console session. Otherwise values
-will only be printed if called for expressedly with print ("...") or similar. */
+will only be printed if called for expressedly with print ("...") or similar.
+ at param suppress_incomplete make sure never to run an incomplete command */
 	void runCommandInternal (const QString &command, RKWardRError *error, bool print_result=false);
 /** basically a wrapper to runCommandInternal (). Tries to convert the result of the command to an array of char* after running the command. Since
 this will not ever be done for user commands, the R_Visible flag will never be set.

Modified: trunk/rkward/rkward/rkconsole.cpp
===================================================================
--- trunk/rkward/rkward/rkconsole.cpp	2007-03-14 12:38:17 UTC (rev 1576)
+++ trunk/rkward/rkward/rkconsole.cpp	2007-03-14 13:23:26 UTC (rev 1577)
@@ -775,12 +775,18 @@
 			RKGlobals::rInterface ()->issueCommand (command);
 		}
 	} else {
-		QString text = command->command ();
+		QString command_string = command->command ();
+		QString text = command_string;
 		text.replace ("\n", QString ("\n") + iprefix);
 		doc->insertText (doc->numLines () - 1, QString (nprefix).length (), text + '\n');
 		command->addReceiver (this);
 		command->addTypeFlag (RCommand::Console);
 		current_command = command;
+		if (command_incomplete) {
+			RK_ASSERT (command_was_piped);
+			command_string.prepend (incomplete_command);
+			command->setCommand (command_string);
+		}
 		command_was_piped = true;
 		RKGlobals::rInterface ()->issueCommand (command);
 	}


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list