[rkward-cvs] SF.net SVN: rkward:[3356] trunk/rkward
tfry at users.sourceforge.net
tfry at users.sourceforge.net
Sun Jan 9 12:23:00 UTC 2011
Revision: 3356
http://rkward.svn.sourceforge.net/rkward/?rev=3356&view=rev
Author: tfry
Date: 2011-01-09 12:22:59 +0000 (Sun, 09 Jan 2011)
Log Message:
-----------
Fix interleaving of R output and stdout/stderr output
Modified Paths:
--------------
trunk/rkward/ChangeLog
trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp
trunk/rkward/rkward/rbackend/rkrbackend.cpp
trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog 2010-12-28 21:28:59 UTC (rev 3355)
+++ trunk/rkward/ChangeLog 2011-01-09 12:22:59 UTC (rev 3356)
@@ -1,3 +1,4 @@
+- Fixed: Output generated by external processes (system()) was not shown on the console
- Fixed: Converting a variable to factor in the editor would drop existing levels, silently, and lead to NAs
- Fixed: Cursor would keep jumping to the end, when typing a filename in the filename selection field in plugins
- Fixed: Submit button would not become enabled in "Basic Statistics" plugin
Modified: trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp 2010-12-28 21:28:59 UTC (rev 3355)
+++ trunk/rkward/rkward/rbackend/rkfrontendtransmitter.cpp 2011-01-09 12:22:59 UTC (rev 3356)
@@ -111,12 +111,12 @@
void RKFrontendTransmitter::newProcessOutput () {
RK_TRACE (RBACKEND);
-#warning TODO: fix interleaving
+
QString output = QString::fromLocal8Bit (backend->readAll ());
handleOutput (output, output.size (), ROutput::Warning);
}
-void RKFrontendTransmitter::requestReceived(RBackendRequest* request) {
+void RKFrontendTransmitter::requestReceived (RBackendRequest* request) {
RK_TRACE (RBACKEND);
if (request->type == RBackendRequest::Output) {
@@ -130,6 +130,29 @@
RK_ASSERT (request->synchronous);
writeRequest (request); // to tell the backend, that we are keeping up. Also deletes the request.
return;
+ } else if (request->type == RBackendRequest::SyncOutput) {
+ RK_ASSERT (request->synchronous);
+
+ QString token = request->params["endtoken"].toString ();
+ writeRequest (request);
+
+ if (!token.isEmpty ()) {
+ QString buffer;
+
+ disconnect (backend, SIGNAL (readyReadStandardOutput ()), this, SLOT (newProcessOutput ()));
+ for (int i=5; i > 0; --i) { // don't wait forever for the end-token.
+ buffer.append (QString::fromLocal8Bit (backend->readAll ()));
+ if (buffer.endsWith (token)) {
+ buffer = buffer.left (buffer.size () - token.size ());
+ break;
+ }
+ backend->waitForReadyRead (500);
+ }
+ connect (backend, SIGNAL (readyReadStandardOutput ()), this, SLOT (newProcessOutput ()));
+
+ if (!buffer.isEmpty ()) handleOutput (buffer, buffer.size (), ROutput::Warning);
+ }
+ return;
}
RKRBackendEvent* event = new RKRBackendEvent (request);
Modified: trunk/rkward/rkward/rbackend/rkrbackend.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackend.cpp 2010-12-28 21:28:59 UTC (rev 3355)
+++ trunk/rkward/rkward/rbackend/rkrbackend.cpp 2011-01-09 12:22:59 UTC (rev 3356)
@@ -785,6 +785,25 @@
return R_NilValue;
}
+SEXP doSyncOutput (SEXP flushstdout) {
+ RK_TRACE (RBACKEND);
+
+#if (!defined RKWARD_THREADED) && (!defined Q_OS_WIN)
+ const char* token = "##RKOutputEndTag3210723##"; // should be unique enough for practical purposes
+ bool doflushstdout = (RKRSupport::SEXPToInt (flushstdout) != 0);
+
+ RBackendRequest req (true, RBackendRequest::SyncOutput);
+ if (doflushstdout) req.params["endtoken"] = QString (token);
+ RKRBackend::this_pointer->handleRequest (&req);
+ if (doflushstdout) {
+ printf ("%s", token);
+ fflush (stdout);
+ }
+#endif
+
+ return R_NilValue;
+}
+
// returns the MIME-name of the current locale encoding (from Qt)
SEXP doLocaleName () {
RK_TRACE (RBACKEND);
@@ -893,6 +912,7 @@
{ "rk.dialog", (DL_FUNC) &doDialog, 6 },
{ "rk.update.locale", (DL_FUNC) &doUpdateLocale, 0 },
{ "rk.locale.name", (DL_FUNC) &doLocaleName, 0 },
+ { "rk.sync.output", (DL_FUNC) &doSyncOutput, 1 },
{ 0, 0, 0 }
};
R_registerRoutines (R_getEmbeddingDllInfo(), NULL, callMethods, NULL, NULL);
Modified: trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h
===================================================================
--- trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h 2010-12-28 21:28:59 UTC (rev 3355)
+++ trunk/rkward/rkward/rbackend/rkrbackendprotocol_shared.h 2011-01-09 12:22:59 UTC (rev 3356)
@@ -47,6 +47,7 @@
#ifndef RKWARD_THREADED
Output, /**< A piece of output. Note: If the backend runs in a single process, output is handled in a pull fashion, instead of using requests. */
Interrupt, /**< Interrupt evaluation. This request type originates in the frontend, not the backend (the only one so far). */
+ SyncOutput, /**< Synchronization of output between R output and stdout. Note: If the backend runs in a single process, the stdout/stderr channel is not supported anyway. */
#endif
OtherRequest /**< Any other type of request. Note: which requests are in the enum, and which are not has mostly historical reasons. @see params */
};
Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R 2010-12-28 21:28:59 UTC (rev 3355)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R 2011-01-09 12:22:59 UTC (rev 3356)
@@ -452,8 +452,35 @@
formals (menu) <- formals (utils::menu)
.rk.menu.default <- utils::menu
+# Add output synchronisation across system(), and system2() calls.
+"system" <- function () {
+ if (intern || ignore.stdout || ignore.stderr) eval (body (.rk.system.default))
+ else {
+ .Call ("rk.sync.output", 0)
+ on.exit (.Call ("rk.sync.output", 1), TRUE)
+ eval (body (.rk.system.default))
+ }
+}
+formals (system) <- formals (base::system)
+.rk.system.default <- base::system
+
+# NOTE: system2 was not introduced before R 2.12.0 (or was it 2.11.0?)
+if (exists ("system2", base::.BaseNamespaceEnv)) {
+ "system2" <- function () {
+ if (stdout == "" && stderr == "") eval (body (.rk.system2.default))
+ else {
+ .Call ("rk.sync.output", 0)
+ on.exit (.Call ("rk.sync.output", 1), TRUE)
+ eval (body (.rk.system2.default))
+ }
+ }
+ formals (system2) <- formals (base::system2)
+ .rk.system2.default <- base::system2
+}
+
# where masking is not enough, we need to assign in the namespace. This can only be done after package loading,
# so we have a separate function for that.
+#NOTE: TODO: By now we are replacing so many functions, that it would make sense to create a generic framework for doing such replacements.
".rk.fix.assignments" <- function () {
assignInNamespace ("menu", menu, envir=as.environment ("package:utils"))
assignInNamespace ("select.list", select.list, envir=as.environment ("package:utils"))
@@ -461,6 +488,14 @@
unlockBinding ("makeActiveBinding", base::.BaseNamespaceEnv)
assign ("makeActiveBinding", rkward::makeActiveBinding, envir=base::.BaseNamespaceEnv)
})
+ try ({
+ unlockBinding ("system", base::.BaseNamespaceEnv)
+ assign ("system", rkward::system, envir=base::.BaseNamespaceEnv)
+ })
+ try ({
+ unlockBinding ("system2", base::.BaseNamespaceEnv)
+ assign ("system2", rkward::system, envir=base::.BaseNamespaceEnv)
+ })
# call separate assignments functions:
if (exists (".rk.fix.assignments.graphics")) eval (body (.rk.fix.assignments.graphics)) # internal_graphics.R
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