Hello all, I would like to request that getConnection() and the struct Rconn declarations be added to the R embedded interface. Here's why.
It's common in CGI scripts for web applications to direct stdin, stdout, and stderr map to reading from the browser, writing to the browser, and writing to a web log file respectively; very nice and neat. However, things get a little hairy once language interpreters are embedded into web servers. For modules like RApache, there are Apache api calls that govern how to read/write from/to the browser so simple redirection is not feasible. With the above request, here is how RApache can alter stdout's behavior: ... Rf_initEmbeddedR(argc, argv); /* initialize R */ /* Redirect stdout to apache specific routines */ con = getConnection(1); con->private = (void *) apr_pcalloc(p,sizeof(struct ApacheOutpcon)); con->text = FALSE; /* allows us to do binary writes */ con->vfprintf = mr_stdout_vfprintf; con->write = mr_stdout_write; con->fflush = mr_stdout_fflush; ... And here are the definitions of the mr_* functions: int mr_stdout_vfprintf(Rconnection con, const char *format, va_list ap){ RApacheOutpcon this = con->private; apr_status_t rv; rv = apr_brigade_vprintf(this->brigade, ap_filter_flush, this->filter, format, ap); return (rv == APR_SUCCESS)? 0 : 1; } int mr_stdout_fflush(Rconnection con){ RApacheOutpcon this = con->private; ap_filter_flush(this->brigade,this->filter); /* still need a return value */ } size_t mr_stdout_write(const void *ptr, size_t size, size_t n, Rconnection con){ RApacheOutpcon this = con->private; apr_status_t rv; rv = apr_brigade_write(this->brigade, ap_filter_flush, this->filter, (const char *)ptr, size*n); return (rv == APR_SUCCESS)? n : 1; } (stdin and stderr can be altered in a similar manner, but they not shown). And with that, it's easy to implement simple code to write data to the web browser in various formats: dataprovider <- function(r){ args <- apache.get_args(r); con <- dbConnect(dbDriver("MySQL"),dbname=db) d <- dbGetQuery(con,"select * from table") if (is.null(args$format)){ apache.set_content_type(r,"text/html") if (length(d)>1) HTML(d,file=stdout()) # from R2HTML else cat("<H1>Empty</H1>") } else if (args$format == 'csv'){ apache.set_content_type(r,"text/csv") write.csv(d) } else if (args$format == 'xml'){ apache.set_content_type(r,"text/xml") writeSDML(d) # from StatDataML } else if (args$format == 'rds'){ apache.set_content_type(r,'application/octet-stream') save(d,file=stdout()) # yes, even this works } dbDisconnect(con) OK } And of course the output of the above can either be sent to the browser or even to an interactive R session like this: load(url("http://example.com/dataprovider?format=rds")) or this via StatDataML d <- readSDML(file="http://example.com/dataprovider?format=xml") or this via read.csv d <- read.csv(file=url("http://example.com/dataprovider?format=csv") Of course there are other ways to accomplish this, like allowing c code to place c generated connection objects onto the Connection array and then use sink(), but that only works for stdout. Another way is to enhance the default stdin, stdout, stderr reading and writing routines to test for the existence of user provided routines, similar to the way stdout_vfprintf tests R_Outputfile. Jeff -- http://biostat.mc.vanderbilt.edu/JeffreyHorner ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel