Mercurial > pub > dyncall > bindings
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 |