1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkRInterface.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16   Copyright 2009 Sandia Corporation.
17   Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18   the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20 
21 #include "vtkRInterface.h"
22 
23 #undef HAVE_UINTPTR_T
24 #ifdef HAVE_VTK_UINTPTR_T
25 #define HAVE_UINTPTR_T HAVE_VTK_UINTPTR_T
26 #ifndef WIN32
27 #include <stdint.h>
28 #endif
29 #endif
30 
31 #include "vtkInformation.h"
32 #include "vtkInformationVector.h"
33 #include "vtkObjectFactory.h"
34 #include "vtkDataArray.h"
35 #include "vtkRAdapter.h"
36 
37 vtkStandardNewMacro(vtkRInterface);
38 
39 #include "R.h"
40 #include "Rmath.h"
41 #include "Rembedded.h"
42 #include "Rversion.h"
43 #include "Rdefines.h"
44 
45 #ifndef WIN32
46 #define CSTACK_DEFNS
47 #define R_INTERFACE_PTRS
48 #include "Rinterface.h"
49 #endif
50 
51 #include "R_ext/Parse.h"
52 
53 #include "vtksys/SystemTools.hxx"
54 
55 /**
56  * This global boolean is used to keep track of whether or not R has been
57  * initialized.  Rf_initialize_R() cannot be called more than once, yet
58  * R provides no way to detect whether or not it has already been called.
59  * In previous versions of this code we used atexit() to shut down the R
60  * interface, but this causes nondeterministic errors when working with R's
61  * parallel library.
62  **/
63 bool VTK_R_INITIALIZED = false;
64 
65 class vtkImplementationRSingleton
66 {
67 public:
68   static vtkImplementationRSingleton* Instance();
69 
InitializeR()70   void InitializeR()
71   {
72 
73   if(this->Rinitialized)
74     {
75     this->refcount++;
76     return;
77     }
78 
79 #ifndef WIN32
80     R_SignalHandlers = 0;
81 #endif
82 
83   const char* path = vtksys::SystemTools::GetEnv("R_HOME");
84   if (!path)
85     {
86     std::string newPath = "R_HOME=";
87     newPath=newPath+VTK_R_HOME;
88     vtksys::SystemTools::PutEnv(newPath.c_str());
89     }
90     const char *R_argv[]= {"vtkRInterface", "--gui=none", "--no-save", "--no-readline", "--silent"};
91 
92     if (!VTK_R_INITIALIZED)
93       {
94       Rf_initialize_R(sizeof(R_argv)/sizeof(R_argv[0]),
95                       const_cast<char **>(R_argv));
96 
97       #ifdef CSTACK_DEFNS
98           R_CStackLimit = (uintptr_t)-1;
99       #endif
100 
101       #ifndef WIN32
102           R_Interactive = static_cast<Rboolean>(TRUE);
103       #endif
104           setup_Rmainloop();
105 
106       VTK_R_INITIALIZED = true;
107       }
108 
109     this->Rinitialized = 1;
110     this->refcount++;
111 
112     std::string  rcommand;
113     rcommand.append("f<-file(paste(tempdir(), \"/Routput.txt\", sep = \"\"), open=\"wt+\")\nsink(f)\n");
114     this->tmpFilePath.clear();
115     this->tmpFilePath.append(R_TempDir);
116 #ifdef WIN32
117     this->tmpFilePath.append("\\Routput.txt");
118 #else
119     this->tmpFilePath.append("/Routput.txt");
120 #endif
121 
122     ParseStatus status;
123     SEXP cmdSexp, cmdexpr = R_NilValue;
124     int error;
125 
126 
127     PROTECT(cmdSexp = allocVector(STRSXP, 1));
128     SET_STRING_ELT(cmdSexp, 0, mkChar(rcommand.c_str()));
129 
130     cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
131     for(int i = 0; i < length(cmdexpr); i++)
132       {
133       R_tryEval(VECTOR_ELT(cmdexpr, i),NULL,&error);
134       }
135     UNPROTECT(2);
136 
137   };
138 
GetROutputFilePath()139   const char* GetROutputFilePath()
140     {
141     return tmpFilePath.c_str();
142     };
143 
CloseR()144   void CloseR()
145     {
146     this->refcount--;
147     if (this->refcount < 1 && ins)
148       {
149       delete ins;
150       ins = NULL;
151       }
152     };
153 
154 protected:
155 
156   ~vtkImplementationRSingleton();
157 
158   vtkImplementationRSingleton();
159 
160   vtkImplementationRSingleton(const vtkImplementationRSingleton&);
161 
162   vtkImplementationRSingleton& operator=(const vtkImplementationRSingleton&);
163 
164 private:
165 
166   std::string tmpFilePath;
167   int refcount;
168   int Rinitialized;
169   static vtkImplementationRSingleton* ins;
170   static void shutdownR(void);
171 
172 };
173 
174 
Instance()175 vtkImplementationRSingleton* vtkImplementationRSingleton::Instance()
176 {
177 
178   if(ins == 0)
179     {
180     ins = new vtkImplementationRSingleton;
181     }
182 
183   ins->InitializeR();
184   return(ins);
185 
186 }
187 
188 
~vtkImplementationRSingleton()189 vtkImplementationRSingleton::~vtkImplementationRSingleton()
190 {
191 
192   R_CleanTempDir();
193   Rf_endEmbeddedR(0);
194 
195 }
196 
vtkImplementationRSingleton()197 vtkImplementationRSingleton::vtkImplementationRSingleton()
198 {
199 
200   this->refcount = 0;
201   this->Rinitialized = 0;
202 
203 }
204 
205 vtkImplementationRSingleton* vtkImplementationRSingleton::ins = 0;
206 
207 //----------------------------------------------------------------------------
vtkRInterface()208 vtkRInterface::vtkRInterface()
209 {
210 
211   this->rs = vtkImplementationRSingleton::Instance();
212   this->buffer = 0;
213   this->buffer_size = 0;
214   this->vra = vtkRAdapter::New();
215 
216 }
217 
218 //----------------------------------------------------------------------------
~vtkRInterface()219 vtkRInterface::~vtkRInterface()
220 {
221 
222   this->rs->CloseR();
223   this->vra->Delete();
224 
225 }
226 
EvalRscript(const char * string,bool showRoutput)227 int vtkRInterface::EvalRscript(const char *string, bool showRoutput)
228 {
229 
230   ParseStatus status;
231   SEXP cmdSexp, cmdexpr = R_NilValue;
232   SEXP ans;
233   int i;
234   int error;
235 
236   PROTECT(cmdSexp = allocVector(STRSXP, 1));
237   SET_STRING_ELT(cmdSexp, 0, mkChar(string));
238 
239   cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
240   switch (status)
241     {
242     case PARSE_OK:
243       for(i = 0; i < length(cmdexpr); i++)
244         {
245         ans = R_tryEval(VECTOR_ELT(cmdexpr, i),NULL,&error);
246         if (error)
247           {
248           return 1;
249           }
250         if(showRoutput)
251           {
252           PrintValue(ans);
253           }
254         }
255       break;
256 
257     case PARSE_INCOMPLETE:
258       vtkErrorMacro(<<"R parse status is PARSE_INCOMPLETE");
259       /* need to read another line */
260       break;
261 
262     case PARSE_NULL:
263       vtkErrorMacro(<<"R parse status is PARSE_NULL");
264       return 1;
265 
266     case PARSE_ERROR:
267       vtkErrorMacro(<<"R parse status is PARSE_ERROR");
268       return 1;
269 
270     case PARSE_EOF:
271       vtkErrorMacro(<<"R parse status is PARSE_EOF");
272       break;
273 
274     default:
275       vtkErrorMacro(<<"R parse status is NOT DOCUMENTED");
276       return 1;
277     }
278   UNPROTECT(2);
279   this->FillOutputBuffer();
280   return 0;
281 
282 }
283 
EvalRcommand(const char * funcName,int param)284 int vtkRInterface::EvalRcommand(const char *funcName, int param)
285 {
286 
287   SEXP e;
288   SEXP arg;
289   int errorOccurred;
290 
291   PROTECT(arg = allocVector(INTSXP, 1));
292   INTEGER(arg)[0]  = param;
293   PROTECT(e = lang2(install(funcName), arg));
294 
295   R_tryEval(e, R_GlobalEnv, &errorOccurred);
296 
297   UNPROTECT(2);
298   return(errorOccurred);
299 
300 }
301 
AssignVTKDataArrayToRVariable(vtkDataArray * da,const char * RVariableName)302 void vtkRInterface::AssignVTKDataArrayToRVariable(vtkDataArray* da, const char* RVariableName)
303 {
304 
305   SEXP s;
306   s = this->vra->VTKDataArrayToR(da);
307   defineVar(install(RVariableName), s, R_GlobalEnv);
308 
309 }
310 
AssignVTKArrayToRVariable(vtkArray * da,const char * RVariableName)311 void vtkRInterface::AssignVTKArrayToRVariable(vtkArray* da, const char* RVariableName)
312 {
313 
314   SEXP s;
315   s = this->vra->VTKArrayToR(da);
316   defineVar(install(RVariableName), s, R_GlobalEnv);
317 
318 }
319 
AssignVTKTreeToRVariable(vtkTree * tr,const char * RVariableName)320 void vtkRInterface::AssignVTKTreeToRVariable(vtkTree* tr, const char* RVariableName)
321 {
322 
323   SEXP s;
324   s = this->vra->VTKTreeToR(tr);
325   defineVar(install(RVariableName), s, R_GlobalEnv);
326 
327 }
328 
329 
AssignRVariableToVTKTree(const char * RVariableName)330 vtkTree* vtkRInterface::AssignRVariableToVTKTree(const char* RVariableName)
331 {
332 
333   SEXP s;
334 
335   s = findVar(install(RVariableName), R_GlobalEnv);
336 
337   if(s != R_UnboundValue)
338     return(this->vra->RToVTKTree(s));
339   else
340     return(0);
341 
342 }
343 
AssignRVariableToVTKDataArray(const char * RVariableName)344 vtkDataArray* vtkRInterface::AssignRVariableToVTKDataArray(const char* RVariableName)
345 {
346 
347   SEXP s;
348 
349   s = findVar(install(RVariableName), R_GlobalEnv);
350 
351   if(s != R_UnboundValue)
352     return(this->vra->RToVTKDataArray(s));
353   else
354     return(0);
355 
356 }
357 
AssignRVariableToVTKArray(const char * RVariableName)358 vtkArray* vtkRInterface::AssignRVariableToVTKArray(const char* RVariableName)
359 {
360 
361   SEXP s;
362 
363   s = findVar(install(RVariableName), R_GlobalEnv);
364 
365   if(s != R_UnboundValue)
366     return(this->vra->RToVTKArray(s));
367   else
368     return(0);
369 
370 }
371 
AssignRVariableToVTKTable(const char * RVariableName)372 vtkTable* vtkRInterface::AssignRVariableToVTKTable(const char* RVariableName)
373 {
374 
375   SEXP s;
376 
377   s = findVar(install(RVariableName), R_GlobalEnv);
378 
379   if(s != R_UnboundValue)
380     return(this->vra->RToVTKTable(s));
381   else
382     return(0);
383 
384 }
385 
AssignVTKTableToRVariable(vtkTable * table,const char * RVariableName)386 void vtkRInterface::AssignVTKTableToRVariable(vtkTable* table, const char* RVariableName)
387 {
388 
389   SEXP s;
390   s = this->vra->VTKTableToR(table);
391   defineVar(install(RVariableName), s, R_GlobalEnv);
392 
393 }
394 
OutputBuffer(char * p,int n)395 int vtkRInterface::OutputBuffer(char* p, int n)
396 {
397 
398   this->buffer = p;
399   this->buffer_size = n;
400   if(this->buffer && (this->buffer_size > 0) )
401     {
402     this->buffer[0] = '\0';
403     }
404   return(1);
405 
406 }
407 
FillOutputBuffer()408 int vtkRInterface::FillOutputBuffer()
409 {
410 
411   FILE *fp;
412   long len;
413   long rlen;
414   long tlen;
415 
416   if(this->buffer && (this->buffer_size > 0) )
417     {
418     fp = fopen(this->rs->GetROutputFilePath(),"rb");
419 
420     if(!fp)
421       {
422       vtkErrorMacro(<<"Can't open input file named " << this->rs->GetROutputFilePath());
423       return(0);
424       }
425 
426     fseek(fp,0,SEEK_END);
427     len = ftell(fp);
428 
429     if(len == 0)
430       {
431       fclose(fp);
432       return(1);
433       }
434 
435     tlen = ((len >= this->buffer_size) ? this->buffer_size-1 : len);
436     fseek(fp,len-tlen,SEEK_SET);
437     rlen = static_cast<long>(fread(this->buffer,1,tlen,fp));
438     this->buffer[tlen] = '\0';
439 
440     fclose(fp);
441 
442     if (rlen != tlen)
443       {
444       vtkErrorMacro(<<"Error while reading file " << this->rs->GetROutputFilePath());
445       return(0);
446       }
447 
448     return(1);
449 
450     }
451   else
452     {
453     return(0);
454     }
455 
456 }
457 
PrintSelf(ostream & os,vtkIndent indent)458 void vtkRInterface::PrintSelf(ostream& os, vtkIndent indent)
459 {
460 
461   this->Superclass::PrintSelf(os, indent);
462 
463   os << indent << "buffer_size: " << this->buffer_size << endl;
464   os << indent << "buffer: " << (this->buffer ? this->buffer : "NULL") << endl;
465 
466   if(this->vra)
467     {
468     this->vra->PrintSelf(os, indent);
469     }
470 
471 }
472 
473