RInside Version 0.2.16
RInside.cpp
Go to the documentation of this file.
1 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 //
3 // RInside.cpp: R/C++ interface class library -- Easier R embedding into C++
4 //
5 // Copyright (C) 2009 Dirk Eddelbuettel
6 // Copyright (C) 2010 - 2019 Dirk Eddelbuettel and Romain Francois
7 //
8 // This file is part of RInside.
9 //
10 // RInside is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // RInside is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with RInside. If not, see <http://www.gnu.org/licenses/>.
22 
23 #include <RInside.h>
24 #include <Callbacks.h>
25 #ifndef _WIN32
26  #define R_INTERFACE_PTRS
27  #include <Rinterface.h>
28 #endif
29 
31 
32 const char *programName = "RInside";
33 
34 #ifdef _WIN32
35  // on Windows, we need to provide setenv which is in the file setenv.c here
36  #include "setenv/setenv.c"
37  extern int optind;
38 
39  #include <windef.h>
40  char rHome[MAX_PATH];
41 #endif
42 
43 RInside::~RInside() { // now empty as MemBuf is internal
44  R_dot_Last();
45  R_RunExitFinalizers();
46  R_CleanTempDir();
47  //Rf_KillAllDevices();
48  //#ifndef WIN32
49  //fpu_setup(FALSE);
50  //#endif
51  Rf_endEmbeddedR(0);
52  instance_m = 0 ;
53  delete global_env_m;
54 }
55 
57 #ifdef RINSIDE_CALLBACKS
58  , callbacks(0)
59 #endif
60 {
61  initialize(0, 0, false, false, false);
62 }
63 
64 #ifdef _WIN32
65 static int myReadConsole(const char *prompt, char *buf, int len, int addtohistory) {
66  fputs(prompt, stdout);
67  fflush(stdout);
68  if (fgets(buf, len, stdin))
69  return 1;
70  else
71  return 0;
72 }
73 
74 static void myWriteConsole(const char *buf, int len) {
75  fwrite(buf, sizeof(char), len, stdout);
76  fflush(stdout);
77 }
78 
79 static void myCallBack() {
80  /* called during i/o, eval, graphics in ProcessEvents */
81 }
82 
83 static void myBusy(int which) {
84  /* set a busy cursor ... if which = 1, unset if which = 0 */
85 }
86 
87 void myAskOk(const char *info) {
88 
89 }
90 
91 int myAskYesNoCancel(const char *question) {
92  const int yes = 1;
93  return yes;
94 }
95 
96 #endif
97 
98 RInside::RInside(const int argc, const char* const argv[], const bool loadRcpp,
99  const bool verbose, const bool interactive)
100 #ifdef RINSIDE_CALLBACKS
101  : callbacks(0)
102 #endif
103 {
104  initialize(argc, argv, loadRcpp, verbose, interactive);
105 }
106 
107 // TODO: use a vector<string> would make all this a bit more readable
108 void RInside::initialize(const int argc, const char* const argv[], const bool loadRcpp,
109  const bool verbose, const bool interactive) {
110 
111  if (instance_m) {
112  throw std::runtime_error( "can only have one RInside instance" ) ;
113  } else {
114  instance_m = this ;
115  }
116 
117  verbose_m = verbose; // Default is false
118  interactive_m = interactive;
119 
120  // generated from Makevars{.win}
121  #include "RInsideEnvVars.h"
122 
123  #ifdef _WIN32
124  // we need a special case for Windows where users may deploy an RInside binary from CRAN
125  // which will have R_HOME set at compile time to CRAN's value -- so let's try to correct
126  // this here: a) allow user's setting of R_HOME and b) use R's get_R_HOME() function
127  if (getenv("R_HOME") == NULL) { // if on Windows and not set
128  char *rhome = get_R_HOME(); // query it, including registry
129  if (rhome != NULL) { // if something was found
130  setenv("R_HOME", get_R_HOME(), 1); // store what we got as R_HOME
131  } // this will now be used in next blocks
132  }
133  #endif
134 
135  for (int i = 0; R_VARS[i] != NULL; i+= 2) {
136  if (getenv(R_VARS[i]) == NULL) { // if env variable is not yet set
137  if (setenv(R_VARS[i],R_VARS[i+1],1) != 0){
138  throw std::runtime_error(std::string("Could not set R environment variable ") +
139  std::string(R_VARS[i]) + std::string(" to ") +
140  std::string(R_VARS[i+1]));
141  }
142  }
143  }
144 
145  #ifndef _WIN32
146  R_SignalHandlers = 0; // Don't let R set up its own signal handlers
147  #endif
148 
149  init_tempdir();
150 
151  const char *R_argv[] = {(char*)programName, "--gui=none", "--no-save",
152  "--silent", "--vanilla", "--slave", "--no-readline"};
153  int R_argc = sizeof(R_argv) / sizeof(R_argv[0]);
154  if (interactive_m) R_argc--; //Deleting the --no-readline option in interactive mode
155  Rf_initEmbeddedR(R_argc, (char**)R_argv);
156 
157  #ifndef _WIN32
158  R_CStackLimit = -1; // Don't do any stack checking, see R Exts, '8.1.5 Threading issues'
159  #endif
160 
161  R_ReplDLLinit(); // this is to populate the repl console buffers
162 
163  structRstart Rst;
164  R_DefParams(&Rst);
165  Rst.R_Interactive = (Rboolean) interactive_m; // sets interactive() to eval to false
166  #ifdef _WIN32
167 
168  char *temp = getenv("R_HOME"); // which is set above as part of R_VARS
169  strncpy(rHome, temp, MAX_PATH);
170  Rst.rhome = rHome;
171 
172  Rst.home = getRUser();
173  Rst.CharacterMode = LinkDLL;
174  Rst.ReadConsole = myReadConsole;
175  Rst.WriteConsole = myWriteConsole;
176  Rst.CallBack = myCallBack;
177  Rst.ShowMessage = myAskOk;
178  Rst.YesNoCancel = myAskYesNoCancel;
179  Rst.Busy = myBusy;
180  #endif
181  R_SetParams(&Rst);
182 
183  if (true || loadRcpp) { // we always need Rcpp, so load it anyway
184  // Rf_install is used best by first assigning like this so that symbols get into
185  // the symbol table where they cannot be garbage collected; doing it on the fly
186  // does expose a minuscule risk of garbage collection -- with thanks to Doug Bates
187  // for the explanation and Luke Tierney for the heads-up
188  SEXP suppressMessagesSymbol = Rf_install("suppressMessages");
189  SEXP requireSymbol = Rf_install("require");
190  SEXP reqsymlang, langobj;
191  // Protect temporaries as suggested by 'rchk', with thanks to Tomas Kalibera
192  PROTECT(reqsymlang = Rf_lang2(requireSymbol, Rf_mkString("Rcpp")));
193  PROTECT(langobj = Rf_lang2(suppressMessagesSymbol, reqsymlang));
194  Rf_eval(langobj, R_GlobalEnv);
195  UNPROTECT(2);
196  }
197 
198  global_env_m = new Rcpp::Environment(); // member variable for access to R's global environment
199 
200  autoloads(); // loads all default packages, using code autogenerate from Makevars{,.win}
201 
202  if ((argc - optind) > 1){ // for argv vector in Global Env */
203  Rcpp::CharacterVector s_argv( argv+(1+optind), argv+argc );
204  assign(s_argv, "argv");
205  } else {
206  assign(R_NilValue, "argv") ;
207  }
208 
209  init_rand(); // for tempfile() to work correctly */
210 }
211 
213  const char *tmp;
214  // FIXME: if per-session temp directory is used (as R does) then return
215  tmp = getenv("TMPDIR");
216  if (tmp == NULL) {
217  tmp = getenv("TMP");
218  if (tmp == NULL) {
219  tmp = getenv("TEMP");
220  if (tmp == NULL)
221  tmp = "/tmp";
222  }
223  }
224  R_TempDir = (char*) tmp;
225  if (setenv("R_SESSION_TMPDIR",tmp,1) != 0){
226  throw std::runtime_error(std::string("Could not set / replace R_SESSION_TMPDIR to ") + std::string(tmp));
227  }
228 }
229 
230 void RInside::init_rand(void) { // code borrows from R's TimeToSeed() in datetime.c
231  unsigned int pid = getpid();
232  struct timeval tv; // this is ifdef'ed by R, we just assume we have it
233  gettimeofday (&tv, NULL);
234  unsigned int seed = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
235  seed ^= (pid << 16); // R 2.14.0 started to also use pid to support parallel
236  srand(seed);
237 }
238 
240 
241  #include "RInsideAutoloads.h"
242 
243  // Autoload default packages and names from autoloads.h
244  //
245  // This function behaves in almost every way like
246  // R's autoload:
247  // function (name, package, reset = FALSE, ...)
248  // {
249  // if (!reset && exists(name, envir = .GlobalEnv, inherits = FALSE))
250  // stop("an object with that name already exists")
251  // m <- match.call()
252  // m[[1]] <- as.name("list")
253  // newcall <- eval(m, parent.frame())
254  // newcall <- as.call(c(as.name("autoloader"), newcall))
255  // newcall$reset <- NULL
256  // if (is.na(match(package, .Autoloaded)))
257  // assign(".Autoloaded", c(package, .Autoloaded), env = .AutoloadEnv)
258  // do.call("delayedAssign", list(name, newcall, .GlobalEnv,
259  // .AutoloadEnv))
260  // invisible()
261  // }
262  //
263  // What's missing is the updating of the string vector .Autoloaded with
264  // the list of packages, which by my code analysis is useless and only
265  // for informational purposes.
266  //
267  //
268 
269  // we build the call :
270  //
271  // delayedAssign( NAME,
272  // autoloader( name = NAME, package = PACKAGE),
273  // .GlobalEnv,
274  // .AutoloadEnv )
275  //
276  // where :
277  // - PACKAGE is updated in a loop
278  // - NAME is updated in a loop
279  //
280  //
281 
282  int i,j, idx=0, nobj ;
283  Rcpp::Language delayed_assign_call(Rcpp::Function("delayedAssign"),
284  R_NilValue, // arg1: assigned in loop
285  R_NilValue, // arg2: assigned in loop
286  *global_env_m,
287  global_env_m->find(".AutoloadEnv")
288  );
289  Rcpp::Language::Proxy delayed_assign_name = delayed_assign_call[1];
290 
291  Rcpp::Language autoloader_call(Rcpp::Function("autoloader"),
292  Rcpp::Named( "name", R_NilValue) , // arg1 : assigned in loop
293  Rcpp::Named( "package", R_NilValue) // arg2 : assigned in loop
294  );
295  Rcpp::Language::Proxy autoloader_name = autoloader_call[1];
296  Rcpp::Language::Proxy autoloader_pack = autoloader_call[2];
297  delayed_assign_call[2] = autoloader_call;
298 
299  try {
300  for( i=0; i<packc; i++){
301 
302  // set the 'package' argument of the autoloader call */
303  autoloader_pack = pack[i] ;
304 
305  nobj = packobjc[i] ;
306  for (j = 0; j < nobj ; j++){
307 
308  // set the 'name' argument of the autoloader call */
309  autoloader_name = packobj[idx+j] ;
310 
311  // Set the 'name' argument of the delayedAssign call */
312  delayed_assign_name = packobj[idx+j] ;
313 
314  // evaluate the call */
315  delayed_assign_call.eval() ;
316 
317  }
318  idx += packobjc[i] ;
319  }
320  } catch( std::exception& ex){
321  throw std::runtime_error(std::string("Error calling delayedAssign: ") + std::string(ex.what()));
322  }
323 }
324 
325 // this is a non-throwing version returning an error code
326 int RInside::parseEval(const std::string & line, SEXP & ans) {
327  ParseStatus status;
328  SEXP cmdSexp, cmdexpr = R_NilValue;
329  int i, errorOccurred;
330 
331  mb_m.add((char*)line.c_str());
332 
333  PROTECT(cmdSexp = Rf_allocVector(STRSXP, 1));
334  SET_STRING_ELT(cmdSexp, 0, Rf_mkChar(mb_m.getBufPtr()));
335 
336  cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
337 
338  switch (status){
339  case PARSE_OK:
340  // Loop is needed here as EXPSEXP might be of length > 1
341  for(i = 0; i < Rf_length(cmdexpr); i++){
342  ans = R_tryEval(VECTOR_ELT(cmdexpr, i), *global_env_m, &errorOccurred);
343  if (errorOccurred) {
344  if (verbose_m) Rf_warning("%s: Error in evaluating R code (%d)\n", programName, status);
345  UNPROTECT(2);
346  mb_m.rewind();
347  return 1;
348  }
349  if (verbose_m) {
350  Rf_PrintValue(ans);
351  }
352  }
353  mb_m.rewind();
354  break;
355  case PARSE_INCOMPLETE:
356  // need to read another line
357  break;
358  case PARSE_NULL:
359  if (verbose_m) Rf_warning("%s: ParseStatus is null (%d)\n", programName, status);
360  UNPROTECT(2);
361  mb_m.rewind();
362  return 1;
363  break;
364  case PARSE_ERROR:
365  if (verbose_m) Rf_warning("Parse Error: \"%s\"\n", line.c_str());
366  UNPROTECT(2);
367  mb_m.rewind();
368  return 1;
369  break;
370  case PARSE_EOF:
371  if (verbose_m) Rf_warning("%s: ParseStatus is eof (%d)\n", programName, status);
372  break;
373  default:
374  if (verbose_m) Rf_warning("%s: ParseStatus is not documented %d\n", programName, status);
375  UNPROTECT(2);
376  mb_m.rewind();
377  return 1;
378  break;
379  }
380  UNPROTECT(2);
381  return 0;
382 }
383 
384 void RInside::parseEvalQ(const std::string & line) {
385  SEXP ans;
386  int rc = parseEval(line, ans);
387  if (rc != 0) {
388  throw std::runtime_error(std::string("Error evaluating: ") + line);
389  }
390 }
391 
392 void RInside::parseEvalQNT(const std::string & line) {
393  SEXP ans;
394  parseEval(line, ans);
395 }
396 
397 RInside::Proxy RInside::parseEval(const std::string & line) {
398  SEXP ans;
399  int rc = parseEval(line, ans);
400  if (rc != 0) {
401  throw std::runtime_error(std::string("Error evaluating: ") + line);
402  }
403  return Proxy( ans );
404 }
405 
406 RInside::Proxy RInside::parseEvalNT(const std::string & line) {
407  SEXP ans;
408  parseEval(line, ans);
409  return Proxy( ans );
410 }
411 
412 Rcpp::Environment::Binding RInside::operator[]( const std::string& name ){
413  return (*global_env_m)[name];
414 }
415 
417  return *instance_m;
418 }
419 
421  return instance_m;
422 }
423 
425  R_ReplDLLinit();
426  while (R_ReplDLLdo1() > 0) {}
427 }
428 
429 /* callbacks */
430 
431 #ifdef RINSIDE_CALLBACKS
432 
433 void Callbacks::Busy_( int which ){
434  R_is_busy = static_cast<bool>( which ) ;
435  Busy( R_is_busy ) ;
436 }
437 
438 int Callbacks::ReadConsole_( const char* prompt, unsigned char* buf, int len, int addtohistory ){
439  try {
440  std::string res( ReadConsole( prompt, static_cast<bool>(addtohistory) ) ) ;
441 
442  /* At some point we need to figure out what to do if the result is
443  * longer than "len"... For now, just truncate. */
444 
445  int l = res.size() ;
446  int last = (l>len-1)?len-1:l ;
447  strncpy( (char*)buf, res.c_str(), last ) ;
448  buf[last] = 0 ;
449  return 1 ;
450  } catch( const std::exception& ex){
451  return -1 ;
452  }
453 }
454 
455 
456 void Callbacks::WriteConsole_( const char* buf, int len, int oType ){
457  if( len ){
458  buffer.assign( buf, len ) ;
459  WriteConsole( buffer, oType) ;
460  }
461 }
462 
463 void RInside_ShowMessage( const char* message ){
464  RInside::instance().callbacks->ShowMessage( message ) ;
465 }
466 
467 void RInside_WriteConsoleEx( const char* message, int len, int oType ){
468  RInside::instance().callbacks->WriteConsole_( message, len, oType ) ;
469 }
470 
471 int RInside_ReadConsole(const char *prompt, unsigned char *buf, int len, int addtohistory){
472  return RInside::instance().callbacks->ReadConsole_( prompt, buf, len, addtohistory ) ;
473 }
474 
475 void RInside_ResetConsole(){
476  RInside::instance().callbacks->ResetConsole() ;
477 }
478 
479 void RInside_FlushConsole(){
480  RInside::instance().callbacks->FlushConsole() ;
481 }
482 
483 void RInside_ClearerrConsole(){
484  RInside::instance().callbacks->CleanerrConsole() ;
485 }
486 
487 void RInside_Busy( int which ){
488  RInside::instance().callbacks->Busy_(which) ;
489 }
490 
491 void RInside::set_callbacks(Callbacks* callbacks_){
492  callbacks = callbacks_ ;
493 
494 #ifdef _WIN32
495  // do something to tell user that he doesn't get this
496 #else
497 
498  /* short circuit the callback function pointers */
499  if( callbacks->has_ShowMessage() ){
500  ptr_R_ShowMessage = RInside_ShowMessage ;
501  }
502  if( callbacks->has_ReadConsole() ){
503  ptr_R_ReadConsole = RInside_ReadConsole;
504  }
505  if( callbacks->has_WriteConsole() ){
506  ptr_R_WriteConsoleEx = RInside_WriteConsoleEx ;
507  ptr_R_WriteConsole = NULL;
508  }
509  if( callbacks->has_ResetConsole() ){
510  ptr_R_ResetConsole = RInside_ResetConsole;
511  }
512  if( callbacks->has_FlushConsole() ){
513  ptr_R_FlushConsole = RInside_FlushConsole;
514  }
515  if( callbacks->has_CleanerrConsole() ){
516  ptr_R_ClearerrConsole = RInside_ClearerrConsole;
517  }
518  if( callbacks->has_Busy() ){
519  ptr_R_Busy = RInside_Busy;
520  }
521 
522  R_Outputfile = NULL;
523  R_Consolefile = NULL;
524 #endif
525 }
526 
527 #endif
RInside()
Definition: RInside.cpp:56
void autoloads(void)
Definition: RInside.cpp:239
bool interactive_m
Definition: RInside.h:35
~RInside()
Definition: RInside.cpp:43
void rewind()
Definition: MemBuf.cpp:42
Rcpp::Environment::Binding operator[](const std::string &name)
Definition: RInside.cpp:412
MemBuf mb_m
Definition: RInside.h:31
void repl()
Definition: RInside.cpp:424
bool verbose_m
Definition: RInside.h:34
void parseEvalQ(const std::string &line)
Definition: RInside.cpp:384
static RInside * instancePtr()
Definition: RInside.cpp:420
void add(const std::string &)
Definition: MemBuf.cpp:46
static RInside * instance_m
Definition: RInside.h:44
int setenv(const char *env_var, const char *env_val, int dummy)
Definition: setenv.c:28
int parseEval(const std::string &line, SEXP &ans)
Definition: RInside.cpp:326
Proxy parseEvalNT(const std::string &line)
Definition: RInside.cpp:406
void parseEvalQNT(const std::string &line)
Definition: RInside.cpp:392
const char * getBufPtr()
Definition: MemBuf.h:33
void initialize(const int argc, const char *const argv[], const bool loadRcpp, const bool verbose, const bool interactive)
Definition: RInside.cpp:108
Rcpp::Environment * global_env_m
Definition: RInside.h:32
const char * programName
Definition: RInside.cpp:32
void assign(const T &object, const std::string &nam)
Definition: RInside.h:78
bool verbose
static RInside & instance()
Definition: RInside.cpp:416
void init_rand(void)
Definition: RInside.cpp:230
void init_tempdir(void)
Definition: RInside.cpp:212