comparison R/rdyncall/src/rcallback.c @ 0:0cfcc391201f

initial from svn dyncall-1745
author Daniel Adler
date Thu, 19 Mar 2015 22:26:28 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0cfcc391201f
1 /** ===========================================================================
2 ** R-Package: rdyncall
3 ** File: src/rcallback.c
4 ** Description: dyncall callback R backend
5 **/
6
7 #include "Rinternals.h"
8 #include "Rdefines.h"
9 #include "dyncall_callback.h"
10
11 typedef struct
12 {
13 int disabled;
14 SEXP fun;
15 SEXP rho;
16 int nargs;
17 const char* signature; /* argument signature without call mode prefix */
18 } R_Callback;
19
20 char dcCallbackHandler_R( DCCallback* pcb, DCArgs* args, DCValue* result, void* userdata )
21 {
22 R_Callback* rdata;
23 const char* ptr;
24 int i,n;
25 SEXP s, x, ans, item;
26 char ch;
27
28 rdata = (R_Callback*) userdata;
29
30 if (rdata->disabled) return DC_SIGCHAR_VOID;
31
32 ptr = rdata->signature;
33
34 // allocate an nargs + 1 'call' language object
35 // first argument is function
36 // rest is arguments from callback
37 n = 1 + rdata->nargs;
38
39 PROTECT( s = allocList(n) );
40 SET_TYPEOF(s, LANGSXP);
41 SETCAR( s, rdata->fun ); x = CDR(s);
42
43 // fill up call object
44
45 i = 1;
46 for( ;; ++i) {
47 ch = *ptr++;
48 if (ch == ')') break;
49 if (i >= n) {
50 warning("invalid signature.");
51 rdata->disabled = 1;
52 UNPROTECT(1);
53 return DC_SIGCHAR_VOID;
54 }
55 switch(ch) {
56 case DC_SIGCHAR_BOOL: item = ScalarLogical( ( dcbArgBool(args) == DC_FALSE ) ? FALSE : TRUE ); break;
57 case DC_SIGCHAR_CHAR: item = ScalarInteger( (int) dcbArgChar(args) ); break;
58 case DC_SIGCHAR_UCHAR: item = ScalarInteger( (int) dcbArgUChar(args) ); break;
59 case DC_SIGCHAR_SHORT: item = ScalarInteger( (int) dcbArgShort(args) ); break;
60 case DC_SIGCHAR_USHORT: item = ScalarInteger( (int) dcbArgUShort(args) ); break;
61 case DC_SIGCHAR_INT: item = ScalarInteger( (int) dcbArgInt(args) ); break;
62 case DC_SIGCHAR_UINT: item = ScalarReal( (double) dcbArgUInt(args) ); break;
63 case DC_SIGCHAR_LONG: item = ScalarReal( (double) dcbArgLong(args) ); break;
64 case DC_SIGCHAR_ULONG: item = ScalarReal( (double) dcbArgULong(args) ); break;
65 case DC_SIGCHAR_LONGLONG: item = ScalarReal( (double) dcbArgLongLong(args) ); break;
66 case DC_SIGCHAR_ULONGLONG: item = ScalarReal( (double) dcbArgULongLong(args) ); break;
67 case DC_SIGCHAR_FLOAT: item = ScalarReal( (double) dcbArgFloat(args) ); break;
68 case DC_SIGCHAR_DOUBLE: item = ScalarReal( dcbArgDouble(args) ); break;
69 case DC_SIGCHAR_POINTER: item = R_MakeExternalPtr( dcbArgPointer(args), R_NilValue, R_NilValue ); break;
70 case DC_SIGCHAR_STRING: item = mkString( dcbArgPointer(args) ); break;
71 default:
72 case '\0':
73 warning("invalid signature");
74 rdata->disabled = 1;
75 UNPROTECT(1);
76 return DC_SIGCHAR_VOID;
77 }
78 SETCAR( x, item);
79 x = CDR(x);
80 }
81
82 /* evaluate expression */
83
84 int error = 0;
85
86 PROTECT( ans = R_tryEval( s, rdata->rho, &error ) );
87
88 if (error)
89 {
90 warning("an error occurred during callback invocation in R. Callback disabled.");
91 rdata->disabled = 1;
92 UNPROTECT(2);
93 return DC_SIGCHAR_VOID;
94 }
95
96 /* propagate return value */
97
98 ch = *ptr; /* scan return value type character */
99
100 /* handle NULL and len(x) == 0 expressions special */
101 if ( (ans == R_NilValue) || (LENGTH(ans) == 0) )
102 {
103 /* handle NULL */
104 result->L = 0;
105 }
106 else
107 {
108 switch(ch)
109 {
110 case DC_SIGCHAR_VOID:
111 break;
112 case DC_SIGCHAR_BOOL:
113 switch( TYPEOF(ans) )
114 {
115 case INTSXP: result->B = (INTEGER(ans)[0] == 0 ) ? DC_FALSE : DC_TRUE; break;
116 case LGLSXP: result->B = (LOGICAL(ans)[0] == FALSE ) ? DC_FALSE : DC_TRUE; break;
117 default: result->B = DC_FALSE; break;
118 }
119 break;
120 case DC_SIGCHAR_CHAR:
121 case DC_SIGCHAR_UCHAR:
122 case DC_SIGCHAR_SHORT:
123 case DC_SIGCHAR_USHORT:
124 case DC_SIGCHAR_INT:
125 case DC_SIGCHAR_UINT:
126 case DC_SIGCHAR_LONG:
127 case DC_SIGCHAR_ULONG:
128 switch( TYPEOF(ans) )
129 {
130 case INTSXP: result->i = INTEGER(ans)[0]; break;
131 case REALSXP: result->i = (int) REAL(ans)[0]; break;
132 default: result->i = 0; break;
133 }
134 break;
135 case DC_SIGCHAR_ULONGLONG:
136 case DC_SIGCHAR_LONGLONG:
137 switch( TYPEOF(ans) )
138 {
139 case INTSXP: result->L = (long long) INTEGER(ans)[0]; break;
140 case REALSXP: result->L = (long long) REAL(ans)[0]; break;
141 default: result->L = 0; break;
142 }
143 break;
144 case DC_SIGCHAR_FLOAT:
145 switch( TYPEOF(ans) )
146 {
147 case INTSXP: result->f = (float) INTEGER(ans)[0]; break;
148 case REALSXP: result->f = (float) REAL(ans)[0]; break;
149 default: result->f = 0.0f; break;
150 }
151 break;
152 case DC_SIGCHAR_DOUBLE:
153 switch( TYPEOF(ans) )
154 {
155 case INTSXP: result->d = (double) INTEGER(ans)[0]; break;
156 case REALSXP: result->d = REAL(ans)[0]; break;
157 default: result->d = 0.0; break;
158 }
159 break;
160 case DC_SIGCHAR_POINTER:
161 switch( TYPEOF(ans) )
162 {
163 case EXTPTRSXP: result->p = R_ExternalPtrAddr(ans); break;
164 case INTSXP : result->p = (DCpointer) (ptrdiff_t) (unsigned long long int) INTEGER(ans)[0]; break;
165 case REALSXP : result->p = (DCpointer) (ptrdiff_t) (unsigned long long int) REAL(ans)[0]; break;
166 default: result->p = NULL; break;
167 }
168 break;
169 case DC_SIGCHAR_STRING:
170 warning("not implemented");
171 rdata->disabled = 1;
172 break;
173 }
174 }
175 UNPROTECT(2);
176 return ch;
177 }
178
179 void R_callback_finalizer(SEXP x);
180
181 SEXP r_new_callback(SEXP sig_x, SEXP fun_x, SEXP rho_x)
182 {
183 const char* signature;
184 R_Callback* rdata;
185 const char* ptr;
186 char ch;
187 signature = CHAR( STRING_ELT( sig_x, 0 ) );
188 rdata = Calloc(1, R_Callback);
189 rdata->disabled = 0;
190 rdata->fun = fun_x;
191 rdata->rho = rho_x;
192 R_PreserveObject(rdata->fun);
193 R_PreserveObject(rdata->rho);
194 ptr = signature;
195 // skip call mode signature
196 if ( (ch=*ptr) == '_') {
197 ptr += 2;
198 ch=*ptr;
199 }
200 rdata->signature = ptr++;
201 int nargs = 0;
202 while( ch != ')') {
203 nargs ++;
204 ch = *ptr++;
205 }
206 rdata->nargs = nargs;
207 DCCallback* cb = dcbNewCallback( signature, dcCallbackHandler_R, rdata);
208 SEXP ans = R_MakeExternalPtr( cb, R_NilValue, R_NilValue );
209 R_RegisterCFinalizerEx(ans, R_callback_finalizer, TRUE);
210 return ans;
211 }
212
213 void R_callback_finalizer(SEXP x)
214 {
215 DCCallback* cb = R_ExternalPtrAddr(x);
216 R_Callback* rdata = dcbGetUserData(cb);
217 R_ReleaseObject(rdata->fun);
218 R_ReleaseObject(rdata->rho);
219 Free(rdata);
220 dcbFreeCallback(cb);
221 }
222