[Sciviews-commits] r155 - pkg/svSocket/R
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Tue Jul 21 11:04:44 CEST 2009
Author: romain
Date: 2009-07-21 11:04:41 +0200 (Tue, 21 Jul 2009)
New Revision: 155
Modified:
pkg/svSocket/R/evalServer.R
Log:
fix on evalServer contributed by Matthew Dowle
Modified: pkg/svSocket/R/evalServer.R
===================================================================
--- pkg/svSocket/R/evalServer.R 2009-07-16 04:48:52 UTC (rev 154)
+++ pkg/svSocket/R/evalServer.R 2009-07-21 09:04:41 UTC (rev 155)
@@ -1,41 +1,51 @@
-evalServer <- function (con, expr, send = NULL) {
- # Evaluate expr on the server, and return its value
- # expr may be quoted or not e.g. can pass a quoted "x=2" to send an assignment
- # send is optional. If supplied, expr must be a single object name (unquoted).
- # Then send is evaluated on the client and the result is assigned to that
- # object name on the server.
- x <- substitute(expr)
- if (!missing(send) && (!length(x) == 1 || mode(x) != "name"))
- stop("When send is supplied, expr must be an target variable name (unquoted) on the server to assign the result of the send expr to.")
- if (!is.character(x)) x <- deparse(x)
- # Flush the input stream just in case previous calls failed to clean up
- scan(con, "", quiet = TRUE)
- if (missing(send)) {
- writeLines(paste('.Last.value = try(eval(parse(text = "', x, '"))); dump(".Last.value", file = ""); cat("<<<endflag>>>")', sep = ""), con)
- } else {
- .Last.value <- send
- sendtxtcon <- textConnection("tmptxt", open = "w", local = TRUE)
- dump(".Last.value", sendtxtcon)
- on.exit(close(sendtxtcon))
- writeLines(paste(paste(tmptxt, collapse = ""), ';', x, ' = .Last.value; cat("<<<endflag>>>")', sep = ""), con)
- }
- # The explicit .Last.value is required to suppress the output of the value
- # of expression back to the client e.g. "[1] 2" being sent back
- # We use .Last.value as its a safe temporary variable to overwrite.
- # The evaluate and dump must be sent as a single string
- # using a single call to writeLines, to ensure multiple clients
- # do not get mixed up results.
- objdump <- ""
- while (regexpr("<<<endflag>>>", objdump) < 0)
- objdump <- paste(objdump, readLines(con), sep = "", collapse = "\n")
- objdump <- sub("<<<endflag>>>", "", objdump)
- if (!missing(send)) {
- if (!identical(objdump, "")) stop(objdump)
- return(TRUE)
- }
- # Source the content of objdump, locally in this frame
- objcon <- textConnection(objdump)
- on.exit(close(objcon))
- source(objcon, local = TRUE, echo = FALSE, verbose = FALSE)
- .Last.value
+evalServer = function(con,expr,send=NULL) {
+ # Evaluate expr on the R server, and return its value
+ # con as returned by socketConnection(port=8888)
+ # send is optional. If supplied, expr must be a single unquoted object name. Then send is evaluated on the client and the result is assigned
+ # to that object on the server.
+ # robust flushing and dumping is just for windows. linux is probably fine without but no harm to leave in for now since binary mode will moot this.
+ x=substitute(expr)
+ if (!missing(send) && (!length(x)==1 || mode(x)!="name")) stop("When send is supplied, expr must be a target variable name (unquoted) on the server to assign the result of the send expr to.")
+ if (!is.character(x)) x= deparse(x)
+ readLines(con) # flush input stream just incase previous call failed to clean up.
+ if (missing(send)) {
+ cat('..Last.value=try(eval(parse(text="',x,'")));.f=file();dump("..Last.value",file=.f);flush(.f);seek(.f,0);cat("\\n<<<startflag>>>",readLines(.f),"<<<endflag>>>\\n",sep="\\n");close(.f);rm(.f,..Last.value);flush.console()\n',file=con,sep="")
+ # its important that one line only is written, so that other clients don't mix in with these lines.
+ } else {
+ .f=file()
+ on.exit(close(.f))
+ ..Last.value=send
+ dump("..Last.value",file=.f) # dump can stop prematurely if file=con, but also good to remove the /n from dump's output before sending (to avoid possible conflicts with other clients)
+ flush(.f)
+ seek(.f,0)
+ cat(readLines(.f),';',x,'=..Last.value;rm(..Last.value);cat("\\n<<<endflag>>>\\n");flush.console()\n',file=con,sep="")
+ }
+ objdump=""
+ endloc=NULL
+ while(!length(endloc)) {
+ obj=readLines(con,n=1000,warn=FALSE)
+ if (!length(obj)) {Sys.sleep(0.01);next} # wait for data to come back. Without this sleep, you get 20-30 calls to readLines before data arrives.
+ endloc=grep("<<<endflag>>>",obj)
+ if (length(endloc)) obj=obj[0:(endloc-1)]
+ objdump<-c(objdump,obj) # this is more robust than paste'ing together a potentially very large single string.
+ }
+ if (!missing(send)) {
+ if (!all(objdump=="")) stop(objdump)
+ return(TRUE)
+ }
+ start = grep("<<<startflag>>>",objdump)
+ if (length(start)!=1) stop("Unable to find <<<startflag>>>")
+ objdump = objdump[-(1:start)] # the startflag is because sometimes (strangely rarely) seek, flush and dump can write return value to stdout which do not source.
+ # Fix any output buffer wrap issues. There are line breaks mid number sometimes which don't source.
+ # This is why warn=FALSE appears above in the call to readLines since it warns about these noncomplete lines otherwise.
+ nospace=grep("[^ ]$",objdump)
+ nospace=nospace[nospace<length(objdump)]
+ for (i in rev(nospace)) { #robust to consecutive lines to be joined
+ objdump[i] = paste(objdump[i],objdump[i+1],sep="")
+ objdump[i+1] = ""
+ }
+ objcon = textConnection(objdump)
+ on.exit(close(objcon))
+ source(objcon,local=TRUE,echo=FALSE,verbose=FALSE)
+ ..Last.value
}
More information about the Sciviews-commits
mailing list