Preparing to add widget support
[RExecServer.git] / RInterpreter.m
blob55eb9024029fe90ec771f9aa9107e43946151b3c
1 #import "RInterpreter.h"
2 #import "RDevice.h"
3 #import "DeviceWindowController.h"
4 #import "NSData+RSerialize.h"
5 #import "TerminalDelegate.h"
7 #define R_INTERFACE_PTRS 1
8 #define CSTACK_DEFNS     1
10 #include <Rinternals.h>
11 #include <Rinterface.h>
12 #include <R_ext/Utils.h>
13 #include <Rgraphics.h>
14 #include <R_ext/GraphicsDevice.h>
15 #include <R_ext/eventloop.h>
16 #include <R_ext/Rdynload.h>
17 #include <Rversion.h>
19 #include <pthread.h>
20 #include <signal.h>
23 #undef Boolean
24 #undef error
26 @interface RInterpreter (Private)
27 - (void)configure;
28 - (void)readyToEvaluate;
29 - (Rboolean)openDevice:(NewDevDesc *)dev withDisplay:(char *)display width:(double)width height:(double)height
30         pointsize:(double)ps family:(char*)family antialias:(Rboolean)antialias autorefresh:(Rboolean)autorefreash 
31         quartzpos:(int)quartzpos background:(int)bg;
32 - (void)registerInterface;
33 @end
35 @implementation RInterpreter
37 + (RInterpreter*)sharedInterpreter {
38         static RInterpreter *interp = nil;
39         if(nil == interp) interp = [[RInterpreter alloc] init];
40         return interp;
43 - (id)init {
44         if(nil == [super init]) return nil;
45         
46         //Some configuration defaults
47         bufferSize           = 2048;
48         buffer               = [[NSMutableAttributedString alloc] init];
51         suppressOutput       = NO;
52         allowTerminal        = NO;
53         vend                 = YES;
54         waiting              = YES;
55         delegate             = nil;
57         deviceList = [[NSMutableArray alloc] init];
58         evalLock   = [[NSLock alloc] init];
59         
60         _argc = 0;
61         _argv = NULL;
63         outputTag = [[NSDictionary alloc] initWithObjectsAndKeys:@"ROutput",@"RTextType",nil];
64         promptTag = [[NSDictionary alloc] initWithObjectsAndKeys:@"RInput",@"RTextType",nil];
65         errorTag  = [[NSDictionary alloc] initWithObjectsAndKeys:@"RError",@"RTextType",nil];
67         //Set some environment variables to their defaults if they are not presently set.
68         setenv("R_HOME",[[[NSBundle bundleWithIdentifier:@"org.r-project.R-framework"] resourcePath] UTF8String],0);
69         setenv("LANG",[[NSString stringWithFormat:@"%@.UTF-8",[[NSLocale currentLocale] localeIdentifier]] UTF8String],0);
70         
71         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeInterpreter:) name:NSApplicationWillTerminateNotification object:nil];
72         
73         return self;
76 - (void)closeInterpreter:(NSNotification*)aNotify {
77         if(nil != delegate) [delegate didCloseInterpreter:self];
80 - (BOOL)isConfigured { return configured; }
82 - (void)setArgv:(char**)argv argc:(int)argc {
83         _argc = argc;
84         _argv = argv;
87 - (id)delegate { return delegate; }
88 - (void)setDelegate:(id)aDelegate { delegate = aDelegate; }
90 - (long)bufferSize   { return bufferSize; }
91 - (void)setBufferSize:(long)aSize {
92         bufferSize = aSize;
94 - (BOOL)allowTerminal { return allowTerminal; }
95 - (void)setAllowTerminal:(BOOL)aBool { allowTerminal = aBool; }
97 - (BOOL)vend { return vend; }
98 - (void)setVend:(BOOL)aBool { vend = aBool; }
100 - (NSString*)homePath { return (NULL == getenv("R_HOME")) ? nil : [NSString stringWithUTF8String:getenv("R_HOME")]; }
101 - (void)setHomePath:(NSString*)aPath {
102         setenv("R_HOME",[aPath UTF8String],1);
105 - (NSString*)localeIdentifier { return (NULL == getenv("LANG")) ? nil : [NSString stringWithUTF8String:getenv("LANG")]; }
106 - (void)setLocaleIdentifier:(NSString*)aLocale {
107         setenv("LANG",[aLocale UTF8String],1);
110 - (void)_run {
111         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
112         [evalLock lock];
113         if(nil != delegate) [delegate didBeginEvaluationForInterpreter:self];
114         setup_Rmainloop();
115         [self registerInterface];
116         [pool release];
117         run_Rmainloop();
120 - (void)run {
121         if(NO == [self isConfigured]) [self configure];
122         if(YES == [self vend]) {
123                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
124                 if(NULL != getenv("RVENDNAME")) {
125                         vendName = [[NSString alloc] initWithUTF8String:getenv("RVENDNAME")];
126                         NSLog(@"Vending with specified name: %@",vendName);
127                         NSConnection *conn = [NSConnection defaultConnection];
128                         [conn setRootObject:self];
129                         if(NO == [conn registerName:vendName]) {
130                                 NSLog(@"Unable to register server as %@");
131                                 [vendName release];
132                                 vendName = nil;
133                         }
134                 } else {
135                         int vend_num = 0;
136                         NSConnection *conn = [NSConnection defaultConnection];
137                         [conn setRootObject:self];
138                         while(vend_num < 17) {
139                                 vendName = [[NSString alloc] initWithFormat:@"R Execution Server %d",++vend_num];
140                                 if(YES == [conn registerName:vendName]) {
141                                         break;
142                                 } else
143                                         [vendName release];
144                         }
145                         if(vend_num == 17) {
146                                 NSLog(@"Unable to register server. Presently, a maximum of 16 local execution servers are allowed per machine");
147                                 vendName = nil;
148                         }
149                 }
150                 [pool release];
151         }
152         //If we don't have a delegate yet, enter the event loop. The delegate (when it connects)
153         //should post a stop message via awakeConsole.
154         if(nil == delegate) {
155                 NSLog(@"Waiting for a delegate");
156                 waiting = YES;
157                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
158                 [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"RExecServerStartedVending" object:vendName];
159                 [NSApp run];
160                 [pool release];
161         }
162         waiting = NO;
163         [self _run];
167 - (void)awakeConsole {
168         if(YES == waiting) {
169                 NSLog(@"Awake Console");
170                 //Post a stop event so that we fall out of the wait loop at the 
171                 [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined 
172                                                                                 location:NSMakePoint(0,0)
173                                                                                 modifierFlags:0
174                                                                                 timestamp:0 
175                                                                                 windowNumber:0 
176                                                                                 context:nil 
177                                                                                 subtype:1337 
178                                                                                 data1:0 
179                                                                                 data2:0] atStart:NO];   
180         }
183 - (void)evaluateInput:(NSString*)aString {
184         readerBufferUsed = [aString length];
185         if(readerBufferUsed > readerBufferLength) readerBufferUsed = readerBufferLength;
186         memcpy(readerBuffer,[aString UTF8String],sizeof(unsigned char)*readerBufferUsed);
187         [self readyToEvaluate];
190 - (NSArray*)devices { return deviceList; }
192 - (NSString*)serverName { return vendName; }
193 - (REnvironment*)environment { return [REnvironment globalEnv]; }
195 - (NSData*)serializeObjectWithName:(NSString*)anName error:(NSError**)anError {
196         const char *name = [anName UTF8String];
197         SEXP  obj  = findVar(install(name),R_GlobalEnv);
198         if(obj != R_UnboundValue) {
199                 PROTECT(obj);
200                 NSMutableData *data = [[NSMutableData alloc] init];
201                 [data serialize:obj];
202                 UNPROTECT(1);
203                 return [data autorelease];
204         } else { 
205                 return nil;
206         }
208 - (BOOL)deserializeObject:(NSData*)anObject withName:(NSString*)aName replace:(BOOL)shouldReplace error:(NSError**)error {
209         error = nil;
210         if(anObject == nil) {
211                 *error = [NSError errorWithDomain:@"org.r-project.RExecServer" code:1 userInfo:nil];
212                 return NO;
213         }
214         
215         
216         const char *name = [aName UTF8String];
217         SEXP  cur  = findVar(install(name),R_GlobalEnv);
218         if(cur != R_UnboundValue && NO == shouldReplace) {
219                 *error = [NSError errorWithDomain:@"org.r-project.RExecServer" code:1 userInfo:nil];
220                 return NO;
221         }
222         Rf_setVar(install(name),[anObject unserialize],R_GlobalEnv);
223         return YES;
226 - (void)copyObjectWithName:(NSString*)aName toServer:(NSString*)aServer error:(NSError**)error {
227         id theProxy = [[NSConnection rootProxyForConnectionWithRegisteredName:aServer host:nil] retain];
228         *error = nil;
229         NSData *serialized = [self serializeObjectWithName:aName error:error];
230         if(nil == error) 
231                 [theProxy deserializeObject:serialized withName:aName replace:YES error:error];
232         [theProxy release];
235 - (RDevice*)deviceCopyOfType:(NSString*)aType withTarget:(NSString*)aTarget {
236         return nil;
240 @end
243 #pragma mark Function Prototypes
244 void RInterp_Suicide(char*);
245 void RInterp_ShowMessage(char*);
246 void RInterp_FlushConsole();
247 void RInterp_WritePrompt(char*);
248 int  RInterp_ReadConsole(char*,unsigned char*,int,int);
249 void RInterp_ResetConsole();
250 void RInterp_WriteConsole(char*,int);
251 void RInterp_ClearerrConsole();
252 void RInterp_Busy();
253 void RInterp_CleanUp(SA_TYPE,int,int);
254 int  RInterp_ShowFiles(int,char**,char**,char*,Rboolean,char*);
255 int  RInterp_ChooseFile(int,char*,int);
256 int  RInterp_EditFile(char*);
257 void RInterp_System(char*);
258 void RInterp_ProcessEvents();
259 Rboolean RInterp_Device(NewDevDesc*,char*,double,double,double,char*,Rboolean,Rboolean,int,int);
260 void RInterp_DeviceParams(double*,double*,double*,char*,Rboolean*,Rboolean*,int*);
261 int  RInterp_CustomPrint(char *,SEXP);
262 SEXP RInterp_do_selectlist(SEXP,SEXP,SEXP,SEXP);
266 extern void     (*ptr_R_ProcessEvents)(void);
267 extern void     (*ptr_CocoaSystem)(char*);
268 extern Rboolean (*ptr_CocoaInnerQuartzDevice)(NewDevDesc*,char*,double,double,double,char*,Rboolean,Rboolean,int,int);
269 extern void     (*ptr_CocoaGetQuartzParameters)(double*,double*,double*,char*,Rboolean*,Rboolean*,int*);
270 extern int      (*ptr_Raqua_CustomPrint)(char *, SEXP);
272 extern DL_FUNC ptr_do_wsbrowser,
273     ptr_do_dataentry, ptr_do_browsepkgs, ptr_do_datamanger,
274     ptr_do_packagemanger, ptr_do_flushconsole, ptr_do_hsbrowser,
275     ptr_do_selectlist;
276         
279 extern void Rstd_WriteConsole(char*,int);
281 @implementation RInterpreter (Private)
283 - (void)_dummy { }
285 - (void)configure {
286         char *argv_orig[] = {"R","--gui=cocoa","--no-save","--no-restore-data"};
287         char **argv;
288         int   argc = 0;
289         
290         if(_argc > 0) {
291                 int i,j,has_gui=0,has_g=0;
292                 
293                 argc=_argc;
294                 for(i=1;i<_argc;i++) {
295                         if(strncmp(_argv[i],"-g",2)==0) 
296                                 has_g = 1; 
297                         else if(strncmp(_argv[i],"--gui",5)==0)
298                                 has_gui = 1;
299                 }
300                 if(has_g || has_gui)
301                         printf("warning: Execution server will ignore GUI settings.\n");
302                 if(has_g) argc -= 1; else if(!has_g && !has_gui) argc++;
303                 argv = malloc(sizeof(char*)*argc);
304                 
305                 j=0;
306                 for(i=0;i<_argc;i++) {
307                         if(strncmp(_argv[i],"-g",2)==0) {
308                                 i++;
309                         } else if(strncmp(_argv[i],"--gui",5)==0) {
310                         } else {
311                                 argv[j++] = _argv[i];
312                         }
313                 }
314                 argv[j++] = "--gui=cocoa";
315         } else {
316                 argc = 4;
317                 argv = argv_orig;
318         }
319         Rf_initialize_R(argc,argv);
320         //R_GUIType = "RExecServer";    //We are NOT the Aqua GUI, but not being the aqua gui is even more annoying.
321         if(YES == allowTerminal) {
322                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
323                 TerminalDelegate *tempDel = [[TerminalDelegate alloc] init];
324                 [tempDel setReaderFunction:ptr_R_ReadConsole];
325                 [tempDel setWriterFunction:Rstd_WriteConsole];
326                 [tempDel setFlushFunction:ptr_R_FlushConsole];
327                 [self setDelegate:tempDel];
328                 [pool release];
329         }
330         R_Outputfile  = NULL;
331         R_Consolefile = NULL;
333 #ifdef R_USING_TRAMPOLINE
334 //On systems supporting libffi we can generate a direct trampoline
335 //function that dispatches to the R level. This is coming later.
336 #else
337     ptr_R_Suicide                = RInterp_Suicide;
338     ptr_R_ShowMessage            = RInterp_ShowMessage;
339     ptr_R_ReadConsole            = RInterp_ReadConsole;
340     ptr_R_WriteConsole           = RInterp_WriteConsole;
341         ptr_R_WriteConsoleEx         = NULL;
342     ptr_R_ShowFiles              = RInterp_ShowFiles;
343     ptr_R_EditFile               = RInterp_EditFile;
344     ptr_R_ChooseFile             = RInterp_ChooseFile;
345     ptr_Raqua_CustomPrint        = RInterp_CustomPrint;
346         ptr_R_ProcessEvents          = RInterp_ProcessEvents;
347     ptr_CocoaInnerQuartzDevice   = RInterp_Device;
348     ptr_CocoaGetQuartzParameters = RInterp_DeviceParams;
349     ptr_CocoaSystem              = RInterp_System;
350 #endif
351         
352         //Put ourselves into a multithreaded state
353         //[NSThread detachNewThreadSelector:@selector(_dummy) toTarget:self withObject:nil];
356 - (void)writeConsole:(char*)output length:(int)aLength {
357         char c = output[aLength];
358         output[aLength] = '\0';
359         if(nil != delegate) [delegate appendString:[NSString stringWithUTF8String:output] ofType:0 forInterpreter:self];
360         output[aLength] = c;
363 - (int)readConsoleWithPrompt:(char*)aPrompt buffer:(unsigned char*)aBuffer length:(int)aLength history:(int)useHistory {
364         //Put those there for something that wants to write a string
365         readerPrompt = aPrompt;
366         readerBuffer = aBuffer;
367         readerBufferLength = aLength;
368         readerAddToHistory = useHistory;
369         
370         memset(readerBuffer,0,sizeof(unsigned char)*aLength);
371         
372         //Flush any drawing that may have happened since the last time we were here.
373         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
374         if(nil != delegate) [delegate didFinishEvaluationForInterpreter:self];
375         NSEnumerator *e = [deviceList objectEnumerator];
376         RDevice *dev;
377         while((dev = (RDevice*)[e nextObject]) != nil) {
378                 [dev flushDrawing];
379         }
380         [pool release];
381         [evalLock unlock];
382         pool = [[NSAutoreleasePool alloc] init];
383         if(nil != delegate) [delegate appendString:[NSString stringWithUTF8String:aPrompt] ofType:2 forInterpreter:self];
384         if(nil != delegate) [delegate didBeginWaitingForInputWithMaximumLength:readerBufferLength addToHistory:(useHistory == 1) ? YES : NO forInterpreter:self];
385         [NSApp run];
386         if(nil != delegate) [delegate didGetInputForInterpreter:self];
387         [evalLock lock];
388         if(nil != delegate) [delegate didBeginEvaluationForInterpreter:self];
389         [pool release];
390         return readerBufferUsed;
393 - (void)removeDevice:(NSNotification*)aNotify {
394         if(nil != delegate) [delegate didCloseDevice:[aNotify object] forInterpreter:self];
395         [deviceList removeObject:[aNotify object]];
397         
398 - (Rboolean)openDevice:(NewDevDesc *)dev withDisplay:(char *)display width:(double)width height:(double)height
399         pointsize:(double)ps family:(char*)family antialias:(Rboolean)antialias autorefresh:(Rboolean)autorefreash 
400         quartzpos:(int)quartzpos background:(int)bg {
401         NSString *aDisplay = [NSString stringWithUTF8String:display];
402         NSArray  *bits     = [[aDisplay componentsSeparatedByString:@":"] retain];
403         Class deviceClass = nil;
404         deviceClass = [RDevice deviceForDisplay:([bits count] < 2) ? @"" : [bits objectAtIndex:1]];
406         //Can't create device.
407         if(nil == deviceClass) return 0;
408         RDevice *rd = [[deviceClass alloc] initWithDevice:dev size:NSMakeSize(width,height) pointSize:ps 
409                 display:[bits objectAtIndex:0]
410                 target:[bits count] < 2 ? nil : [bits objectAtIndex:1] background:bg antialias:antialias];
411         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeDevice:) name:@"RDeviceClosed" object:rd];
412         [deviceList addObject:rd];
413         if(nil != delegate) [delegate didOpenDevice:rd forInterpreter:self];
414         [rd finishOpening];
415         [rd release];
416         return TRUE;
419 - (void)flushConsole {
422 - (void)showMessage:(char*)aMsg {
423         [self writeConsole:aMsg length:strlen(aMsg)];
426 - (void)suicide:(char*)aMsg {
427         [self writeConsole:aMsg length:strlen(aMsg)];
430 - (void)resetConsole {
433 - (void)clearErrorConsole {
436 - (void)busy {
439 - (void)system:(char*)cmd {
440         system(cmd);
443 - (int)editFile:(char*)aFileName {
444         if(YES == allowTerminal) {
445                 NSLog(@"Editing file: %s",aFileName);
446                 return 0;
447         } else {
448                 return 0;
449         }
452 - (int)showFiles:(int)nfiles file:(char**)file headers:(char**)headers wtitle:(char*)wtitle del:(Rboolean)del pager:(char*)pager {
453         return 0;
456 - (int)customPrintType:(char*)aType list:(SEXP)aList {
457         NSLog(@"This is hosed for right now. Might need support from R itself.");
458         return 0;
461 - (SEXP)selectListWithCall:(SEXP)call op:(SEXP)op args:(SEXP)args rho:(SEXP)rho {
462         return R_NilValue;
465 - (void)readyToEvaluate {
466         [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined 
467                                                                         location:NSMakePoint(0,0)
468                                                                          modifierFlags:0
469                                                                          timestamp:0 
470                                                                          windowNumber:0 
471                                                                          context:nil 
472                                                                          subtype:1337 
473                                                                          data1:0 
474                                                                          data2:0] atStart:NO];  
477 SEXP RES_ServerName() {
478         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
479         const char *str = [[[RInterpreter sharedInterpreter] serverName] UTF8String];
480         SEXP ret;
481         PROTECT(ret = allocVector(STRSXP,1));
482         SET_STRING_ELT(ret,0,mkChar(str));
483         UNPROTECT(1);
484         [pool release];
485         return ret;
488 SEXP RES_CopyObject(SEXP name,SEXP server) {
489         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
490         NSString *aStr = [[NSString alloc] initWithUTF8String:CHAR(STRING_ELT(name,0))];
491         NSString *bStr = [[NSString alloc] initWithUTF8String:CHAR(STRING_ELT(server,0))];
492         NSError *error = nil;
493         [[RInterpreter sharedInterpreter] copyObjectWithName:aStr toServer:bStr error:&error];
494         [aStr release];
495         [bStr release];
496         [pool release];
497         if(nil != error)
498                 Rf_error("Problem copying object");
499         return R_NilValue;
502 static const R_CallMethodDef R_CallDef[] = {
503         {"RES_ServerName",(DL_FUNC)RES_ServerName,0},
504         {"RES_CopyObject",(DL_FUNC)RES_CopyObject,2},
505         NULL
508 extern void
509 R_addCallRoutine(DllInfo *info, const R_CallMethodDef * const croutine,void*sym);
511 - (void)registerInterface {
512         R_registerRoutines(R_getEmbeddingDllInfo(),NULL,R_CallDef,NULL,NULL);
515 @end
517 #ifdef R_USING_TRAMPOLINE
518 #else
519 void RInterp_Suicide(char*aMsg) { 
520         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
521         [[RInterpreter sharedInterpreter] suicide:aMsg]; 
522         [pool release];
524 void RInterp_ShowMessage(char*aMsg) { 
525         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
526         [[RInterpreter sharedInterpreter] showMessage:aMsg]; 
527         [pool release];
529 void RInterp_FlushConsole() { 
530         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
531         [[RInterpreter sharedInterpreter] flushConsole]; 
532         [pool release];
534 int  RInterp_ReadConsole(char*prompt,unsigned char*buffer,int length,int history) {
535         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
536         int ret = [[RInterpreter sharedInterpreter] readConsoleWithPrompt:prompt buffer:buffer length:length history:history];
537         [pool release];
538         return ret;
540 void RInterp_ResetConsole() { [[RInterpreter sharedInterpreter] resetConsole]; }
541 void RInterp_WriteConsole(char*buffer,int length) { 
542         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
543         [[RInterpreter sharedInterpreter] writeConsole:buffer length:length]; 
544         [pool release];
546 void RInterp_ClearerrConsole() { [[RInterpreter sharedInterpreter] clearErrorConsole]; }
547 void RInterp_Busy() { [[RInterpreter sharedInterpreter] busy]; }
548 void RInterp_CleanUp(SA_TYPE type,int a,int b) {
549         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
550         [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:NSApplicationWillTerminateNotification object:nil]];
551         [[RInterpreter sharedInterpreter] closeInterpreter:nil];
552         [pool release];
554 int  RInterp_ShowFiles(int a,char**b,char**c,char*d,Rboolean e,char*f) { 
555         return [[RInterpreter sharedInterpreter] showFiles:a file:b headers:c wtitle:d del:e pager:f];
557 int  RInterp_ChooseFile(int a,char*b,int c) { return 0; }
558 int  RInterp_EditFile(char*a) { return [[RInterpreter sharedInterpreter] editFile:a]; }
559 void RInterp_System(char*a) { [[RInterpreter sharedInterpreter] system:a]; }
560 void RInterp_ProcessEvents() { 
561         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
562         [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined 
563                                                                         location:NSMakePoint(0,0)
564                                                                          modifierFlags:0
565                                                                          timestamp:0 
566                                                                          windowNumber:0 
567                                                                          context:nil 
568                                                                          subtype:1337 
569                                                                          data1:0 
570                                                                          data2:0] atStart:NO];
571         [NSApp run];
572         [pool release];
574 Rboolean RInterp_Device(NewDevDesc *dev,
575         char *display,double width,double height,
576         double ps,char *family,Rboolean antialias,Rboolean autorefresh,int quartzpos,int bg) {
577         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
578         Rboolean ret = [[RInterpreter sharedInterpreter] openDevice:dev
579          withDisplay:display width:width height:height pointsize:ps family:family
580           antialias:antialias autorefresh:autorefresh quartzpos:quartzpos background:bg];
581         [pool release];
582         return ret;
584 void RInterp_DeviceParams(double*a,double*b,double*c,char*d,Rboolean*e,Rboolean*f,int*g) { }
585 int  RInterp_CustomPrint(char *a,SEXP b) { return [[RInterpreter sharedInterpreter] customPrintType:a list:b]; }
587 SEXP RInterp_do_selectlist(SEXP call,SEXP op,SEXP args,SEXP rho) {
588         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
589         SEXP ret = [[RInterpreter sharedInterpreter] selectListWithCall:call op:op args:args rho:rho];
590         [pool release];
591         return ret;
594 #endif