Mercurial > pub > dyncall > bindings
comparison R/rdyncall/src/rdyncall.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/rdyncall.c | |
| 4 ** Description: R bindings to dyncall | |
| 5 **/ | |
| 6 | |
| 7 #include <Rinternals.h> | |
| 8 #include "dyncall.h" | |
| 9 #include "rdyncall_signature.h" | |
| 10 #include <string.h> | |
| 11 #include <ctype.h> | |
| 12 | |
| 13 /** --------------------------------------------------------------------------- | |
| 14 ** C-Function: new_callvm | |
| 15 ** R-Interface: .Call | |
| 16 **/ | |
| 17 | |
| 18 SEXP r_new_callvm(SEXP mode_x, SEXP size_x) | |
| 19 { | |
| 20 /* default call mode is "cdecl" */ | |
| 21 int size_i = INTEGER(size_x)[0]; | |
| 22 | |
| 23 const char* mode_S = CHAR( STRING_ELT( mode_x, 0 ) ); | |
| 24 | |
| 25 int mode_i = DC_CALL_C_DEFAULT; | |
| 26 if (strcmp(mode_S,"default") == 0 || strcmp(mode_S,"cdecl") == 0) mode_i = DC_CALL_C_DEFAULT; | |
| 27 #if WIN32 | |
| 28 else if (strcmp(mode_S,"stdcall") == 0) mode_i = DC_CALL_C_X86_WIN32_STD; | |
| 29 else if (strcmp(mode_S,"thiscall") == 0) mode_i = DC_CALL_C_X86_WIN32_THIS_GNU; | |
| 30 else if (strcmp(mode_S,"thiscall.gcc") == 0) mode_i = DC_CALL_C_X86_WIN32_THIS_GNU; | |
| 31 else if (strcmp(mode_S,"thiscall.msvc") == 0) mode_i = DC_CALL_C_X86_WIN32_THIS_MS; | |
| 32 else if (strcmp(mode_S,"fastcall") == 0) mode_i = DC_CALL_C_X86_WIN32_FAST_GNU; | |
| 33 else if (strcmp(mode_S,"fastcall.msvc") == 0) mode_i = DC_CALL_C_X86_WIN32_FAST_MS; | |
| 34 else if (strcmp(mode_S,"fastcall.gcc") == 0) mode_i = DC_CALL_C_X86_WIN32_FAST_GNU; | |
| 35 #endif | |
| 36 /* | |
| 37 else { error("invalid 'callmode'"); return R_NilValue; } | |
| 38 */ | |
| 39 | |
| 40 DCCallVM* pvm = dcNewCallVM(size_i); | |
| 41 dcMode( pvm, mode_i ); | |
| 42 return R_MakeExternalPtr( pvm, R_NilValue, R_NilValue ); | |
| 43 } | |
| 44 | |
| 45 /** --------------------------------------------------------------------------- | |
| 46 ** C-Function: free_callvm | |
| 47 ** R-Interface: .Call | |
| 48 **/ | |
| 49 | |
| 50 SEXP r_free_callvm(SEXP callvm_x) | |
| 51 { | |
| 52 DCCallVM* callvm_p = (DCCallVM*) R_ExternalPtrAddr( callvm_x ); | |
| 53 dcFree( callvm_p ); | |
| 54 return R_NilValue; | |
| 55 } | |
| 56 | |
| 57 /** --------------------------------------------------------------------------- | |
| 58 ** C-Function: r_dyncall | |
| 59 ** R-Interface: .External | |
| 60 **/ | |
| 61 | |
| 62 SEXP r_dyncall(SEXP args) /* callvm, address, signature, args ... */ | |
| 63 { | |
| 64 DCCallVM* pvm; | |
| 65 void* addr; | |
| 66 const char* signature; | |
| 67 const char* sig; | |
| 68 SEXP arg; | |
| 69 int ptrcnt; | |
| 70 int argpos; | |
| 71 | |
| 72 args = CDR(args); | |
| 73 | |
| 74 /* extract CallVM reference, address and signature */ | |
| 75 | |
| 76 pvm = (DCCallVM*) R_ExternalPtrAddr( CAR(args) ); args = CDR(args); | |
| 77 | |
| 78 switch(TYPEOF(CAR(args))) { | |
| 79 case EXTPTRSXP: | |
| 80 addr = R_ExternalPtrAddr( CAR(args) ); args = CDR(args); | |
| 81 if (!addr) { | |
| 82 error("Target address is null-pointer."); | |
| 83 return R_NilValue; /* dummy */ | |
| 84 } | |
| 85 break; | |
| 86 default: | |
| 87 error("Target address must be external pointer."); | |
| 88 return R_NilValue; /* dummy */ | |
| 89 } | |
| 90 signature = CHAR( STRING_ELT( CAR(args), 0 ) ); args = CDR(args); | |
| 91 sig = signature; | |
| 92 | |
| 93 if (!pvm) { | |
| 94 error("Argument 'callvm' is null"); | |
| 95 /* dummy */ return R_NilValue; | |
| 96 } | |
| 97 if (!addr) { | |
| 98 error("Argument 'addr' is null"); | |
| 99 /* dummy */ return R_NilValue; | |
| 100 } | |
| 101 /* reset CallVM to initial state */ | |
| 102 | |
| 103 dcReset(pvm); | |
| 104 ptrcnt = 0; | |
| 105 argpos = 0; | |
| 106 | |
| 107 /* function calling convention prefix '_' */ | |
| 108 if (*sig == DC_SIGCHAR_CC_PREFIX) { | |
| 109 /* specify calling convention by signature prefix hint */ | |
| 110 ++sig; | |
| 111 char ch = *sig++; | |
| 112 int mode = DC_CALL_C_DEFAULT; | |
| 113 switch(ch) | |
| 114 { | |
| 115 case DC_SIGCHAR_CC_STDCALL: | |
| 116 mode = DC_CALL_C_X86_WIN32_STD; break; | |
| 117 case DC_SIGCHAR_CC_FASTCALL_GNU: | |
| 118 mode = DC_CALL_C_X86_WIN32_FAST_GNU; break; | |
| 119 case DC_SIGCHAR_CC_FASTCALL_MS: | |
| 120 mode = DC_CALL_C_X86_WIN32_FAST_MS; break; | |
| 121 default: | |
| 122 error("Unknown calling convention prefix hint signature character '%c'", ch ); | |
| 123 /* dummy */ return R_NilValue; | |
| 124 } | |
| 125 dcMode(pvm, mode); | |
| 126 } | |
| 127 | |
| 128 /* load arguments */ | |
| 129 for(;;) { | |
| 130 | |
| 131 char ch = *sig++; | |
| 132 | |
| 133 if (ch == '\0') { | |
| 134 error("Function-call signature '%s' is invalid - missing argument terminator character ')' and return type signature.", signature); | |
| 135 /* dummy */ return R_NilValue; | |
| 136 } | |
| 137 /* argument terminator */ | |
| 138 if (ch == ')') break; | |
| 139 | |
| 140 /* end of arguments? */ | |
| 141 if (args == R_NilValue) { | |
| 142 error("Not enough arguments for function-call signature '%s'.", signature); | |
| 143 /* dummy */ return R_NilValue; | |
| 144 } | |
| 145 /* pointer counter */ | |
| 146 else if (ch == '*') { ptrcnt++; continue; } | |
| 147 | |
| 148 /* unpack next argument */ | |
| 149 arg = CAR(args); args = CDR(args); | |
| 150 argpos++; | |
| 151 | |
| 152 int type_id = TYPEOF(arg); | |
| 153 | |
| 154 if (ptrcnt == 0) { /* base types */ | |
| 155 | |
| 156 /* 'x' signature for passing language objects 'as-is' */ | |
| 157 if (ch == DC_SIGCHAR_SEXP) { | |
| 158 dcArgPointer(pvm, (void*)arg); | |
| 159 continue; | |
| 160 } | |
| 161 | |
| 162 if ( type_id != NILSXP && type_id != EXTPTRSXP && LENGTH(arg) == 0 ) { | |
| 163 error("Argument type mismatch at position %d: expected length greater zero.", argpos); | |
| 164 /* dummy */ return R_NilValue; | |
| 165 } | |
| 166 switch(ch) { | |
| 167 case DC_SIGCHAR_BOOL: | |
| 168 { | |
| 169 DCbool boolValue; | |
| 170 switch(type_id) | |
| 171 { | |
| 172 case LGLSXP: boolValue = ( LOGICAL(arg)[0] == 0 ) ? DC_FALSE : DC_TRUE; break; | |
| 173 case INTSXP: boolValue = ( INTEGER(arg)[0] == 0 ) ? DC_FALSE : DC_TRUE; break; | |
| 174 case REALSXP: boolValue = ( REAL(arg)[0] == 0.0 ) ? DC_FALSE : DC_TRUE; break; | |
| 175 case RAWSXP: boolValue = ( RAW(arg)[0] == 0 ) ? DC_FALSE : DC_TRUE; break; | |
| 176 default: error("Argument type mismatch at position %d: expected C bool convertable value", argpos); /* dummy */ return R_NilValue; | |
| 177 } | |
| 178 dcArgBool(pvm, boolValue ); | |
| 179 } | |
| 180 break; | |
| 181 case DC_SIGCHAR_CHAR: | |
| 182 { | |
| 183 char charValue; | |
| 184 switch(type_id) | |
| 185 { | |
| 186 case LGLSXP: charValue = (char) LOGICAL(arg)[0]; break; | |
| 187 case INTSXP: charValue = (char) INTEGER(arg)[0]; break; | |
| 188 case REALSXP: charValue = (char) REAL(arg)[0]; break; | |
| 189 case RAWSXP: charValue = (char) RAW(arg)[0]; break; | |
| 190 default: error("Argument type mismatch at position %d: expected C char convertable value", argpos); /* dummy */ return R_NilValue; | |
| 191 } | |
| 192 dcArgChar(pvm, charValue); | |
| 193 } | |
| 194 break; | |
| 195 case DC_SIGCHAR_UCHAR: | |
| 196 { | |
| 197 unsigned char charValue; | |
| 198 switch(type_id) | |
| 199 { | |
| 200 case LGLSXP: charValue = (unsigned char) LOGICAL(arg)[0]; break; | |
| 201 case INTSXP: charValue = (unsigned char) INTEGER(arg)[0]; break; | |
| 202 case REALSXP: charValue = (unsigned char) REAL(arg)[0]; break; | |
| 203 case RAWSXP: charValue = (unsigned char) RAW(arg)[0]; break; | |
| 204 default: error("Argument type mismatch at position %d: expected C unsigned char convertable value", argpos); /* dummy */ return R_NilValue; | |
| 205 } | |
| 206 dcArgChar(pvm, *( (char*) &charValue )); | |
| 207 } | |
| 208 break; | |
| 209 case DC_SIGCHAR_SHORT: | |
| 210 { | |
| 211 short shortValue; | |
| 212 switch(type_id) | |
| 213 { | |
| 214 case LGLSXP: shortValue = (short) LOGICAL(arg)[0]; break; | |
| 215 case INTSXP: shortValue = (short) INTEGER(arg)[0]; break; | |
| 216 case REALSXP: shortValue = (short) REAL(arg)[0]; break; | |
| 217 case RAWSXP: shortValue = (short) RAW(arg)[0]; break; | |
| 218 default: error("Argument type mismatch at position %d: expected C short convertable value", argpos); /* dummy */ return R_NilValue; | |
| 219 } | |
| 220 dcArgShort(pvm, shortValue); | |
| 221 } | |
| 222 break; | |
| 223 case DC_SIGCHAR_USHORT: | |
| 224 { | |
| 225 unsigned short shortValue; | |
| 226 switch(type_id) | |
| 227 { | |
| 228 case LGLSXP: shortValue = (unsigned short) LOGICAL(arg)[0]; break; | |
| 229 case INTSXP: shortValue = (unsigned short) INTEGER(arg)[0]; break; | |
| 230 case REALSXP: shortValue = (unsigned short) REAL(arg)[0]; break; | |
| 231 case RAWSXP: shortValue = (unsigned short) RAW(arg)[0]; break; | |
| 232 default: error("Argument type mismatch at position %d: expected C unsigned short convertable value", argpos); /* dummy */ return R_NilValue; | |
| 233 } | |
| 234 dcArgShort(pvm, *( (short*) &shortValue ) ); | |
| 235 } | |
| 236 break; | |
| 237 case DC_SIGCHAR_LONG: | |
| 238 { | |
| 239 long longValue; | |
| 240 switch(type_id) | |
| 241 { | |
| 242 case LGLSXP: longValue = (long) LOGICAL(arg)[0]; break; | |
| 243 case INTSXP: longValue = (long) INTEGER(arg)[0]; break; | |
| 244 case REALSXP: longValue = (long) REAL(arg)[0]; break; | |
| 245 case RAWSXP: longValue = (long) RAW(arg)[0]; break; | |
| 246 default: error("Argument type mismatch at position %d: expected C long convertable value", argpos); /* dummy */ return R_NilValue; | |
| 247 } | |
| 248 dcArgLong(pvm, longValue); | |
| 249 } | |
| 250 break; | |
| 251 case DC_SIGCHAR_ULONG: | |
| 252 { | |
| 253 unsigned long ulongValue; | |
| 254 switch(type_id) | |
| 255 { | |
| 256 case LGLSXP: ulongValue = (unsigned long) LOGICAL(arg)[0]; break; | |
| 257 case INTSXP: ulongValue = (unsigned long) INTEGER(arg)[0]; break; | |
| 258 case REALSXP: ulongValue = (unsigned long) REAL(arg)[0]; break; | |
| 259 case RAWSXP: ulongValue = (unsigned long) RAW(arg)[0]; break; | |
| 260 default: error("Argument type mismatch at position %d: expected C unsigned long convertable value", argpos); /* dummy */ return R_NilValue; | |
| 261 } | |
| 262 dcArgLong(pvm, (unsigned long) ulongValue); | |
| 263 } | |
| 264 break; | |
| 265 case DC_SIGCHAR_INT: | |
| 266 { | |
| 267 int intValue; | |
| 268 switch(type_id) | |
| 269 { | |
| 270 case LGLSXP: intValue = (int) LOGICAL(arg)[0]; break; | |
| 271 case INTSXP: intValue = INTEGER(arg)[0]; break; | |
| 272 case REALSXP: intValue = (int) REAL(arg)[0]; break; | |
| 273 case RAWSXP: intValue = (int) RAW(arg)[0]; break; | |
| 274 default: error("Argument type mismatch at position %d: expected C int convertable value", argpos); /*dummy*/ return R_NilValue; | |
| 275 } | |
| 276 dcArgInt(pvm, intValue); | |
| 277 } | |
| 278 break; | |
| 279 case DC_SIGCHAR_UINT: | |
| 280 { | |
| 281 unsigned int intValue; | |
| 282 switch(type_id) | |
| 283 { | |
| 284 case LGLSXP: intValue = (unsigned int) LOGICAL(arg)[0]; break; | |
| 285 case INTSXP: intValue = (unsigned int) INTEGER(arg)[0]; break; | |
| 286 case REALSXP: intValue = (unsigned int) REAL(arg)[0]; break; | |
| 287 case RAWSXP: intValue = (unsigned int) RAW(arg)[0]; break; | |
| 288 default: error("Argument type mismatch at position %d: expected C unsigned int convertable value", argpos); /* dummy */ return R_NilValue; | |
| 289 } | |
| 290 dcArgInt(pvm, * (int*) &intValue); | |
| 291 } | |
| 292 break; | |
| 293 case DC_SIGCHAR_FLOAT: | |
| 294 { | |
| 295 float floatValue; | |
| 296 switch(type_id) | |
| 297 { | |
| 298 case LGLSXP: floatValue = (float) LOGICAL(arg)[0]; break; | |
| 299 case INTSXP: floatValue = (float) INTEGER(arg)[0]; break; | |
| 300 case REALSXP: floatValue = (float) REAL(arg)[0]; break; | |
| 301 case RAWSXP: floatValue = (float) RAW(arg)[0]; break; | |
| 302 default: error("Argument type mismatch at position %d: expected C float convertable value", argpos); /* dummy */ return R_NilValue; | |
| 303 } | |
| 304 dcArgFloat( pvm, floatValue ); | |
| 305 } | |
| 306 break; | |
| 307 case DC_SIGCHAR_DOUBLE: | |
| 308 { | |
| 309 DCdouble doubleValue; | |
| 310 switch(type_id) | |
| 311 { | |
| 312 case LGLSXP: doubleValue = (double) LOGICAL(arg)[0]; break; | |
| 313 case INTSXP: doubleValue = (double) INTEGER(arg)[0]; break; | |
| 314 case REALSXP: doubleValue = REAL(arg)[0]; break; | |
| 315 case RAWSXP: doubleValue = (double) RAW(arg)[0]; break; | |
| 316 default: error("Argument type mismatch at position %d: expected C double convertable value", argpos); /* dummy */ return R_NilValue; | |
| 317 } | |
| 318 dcArgDouble( pvm, doubleValue ); | |
| 319 } | |
| 320 break; | |
| 321 case DC_SIGCHAR_LONGLONG: | |
| 322 { | |
| 323 DClonglong longlongValue; | |
| 324 switch(type_id) | |
| 325 { | |
| 326 case LGLSXP: longlongValue = (DClonglong) LOGICAL(arg)[0]; break; | |
| 327 case INTSXP: longlongValue = (DClonglong) INTEGER(arg)[0]; break; | |
| 328 case REALSXP: longlongValue = (DClonglong) REAL(arg)[0]; break; | |
| 329 case RAWSXP: longlongValue = (DClonglong) RAW(arg)[0]; break; | |
| 330 default: error("Argument type mismatch at position %d: expected C long long (int64_t) convertable value", argpos); /* dummy */ return R_NilValue; | |
| 331 } | |
| 332 dcArgLongLong( pvm, longlongValue ); | |
| 333 } | |
| 334 break; | |
| 335 case DC_SIGCHAR_ULONGLONG: | |
| 336 { | |
| 337 DCulonglong ulonglongValue; | |
| 338 switch(type_id) | |
| 339 { | |
| 340 case LGLSXP: ulonglongValue = (DCulonglong) LOGICAL(arg)[0]; break; | |
| 341 case INTSXP: ulonglongValue = (DCulonglong) INTEGER(arg)[0]; break; | |
| 342 case REALSXP: ulonglongValue = (DCulonglong) REAL(arg)[0]; break; | |
| 343 case RAWSXP: ulonglongValue = (DCulonglong) RAW(arg)[0]; break; | |
| 344 default: error("Argument type mismatch at position %d: expected C unsigned long long (uint64_t) convertable value", argpos); /* dummy */ return R_NilValue; | |
| 345 } | |
| 346 dcArgLongLong( pvm, *( (DClonglong*)&ulonglongValue ) ); | |
| 347 } | |
| 348 break; | |
| 349 case DC_SIGCHAR_POINTER: | |
| 350 { | |
| 351 DCpointer ptrValue; | |
| 352 switch(type_id) | |
| 353 { | |
| 354 case NILSXP: ptrValue = (DCpointer) 0; break; | |
| 355 case CHARSXP: ptrValue = (DCpointer) CHAR(arg); break; | |
| 356 case SYMSXP: ptrValue = (DCpointer) PRINTNAME(arg); break; | |
| 357 case STRSXP: ptrValue = (DCpointer) CHAR(STRING_ELT(arg,0)); break; | |
| 358 case LGLSXP: ptrValue = (DCpointer) LOGICAL(arg); break; | |
| 359 case INTSXP: ptrValue = (DCpointer) INTEGER(arg); break; | |
| 360 case REALSXP: ptrValue = (DCpointer) REAL(arg); break; | |
| 361 case CPLXSXP: ptrValue = (DCpointer) COMPLEX(arg); break; | |
| 362 case RAWSXP: ptrValue = (DCpointer) RAW(arg); break; | |
| 363 case EXTPTRSXP: ptrValue = R_ExternalPtrAddr(arg); break; | |
| 364 // case ENVSXP: ptrValue = (DCpointer) arg; break; | |
| 365 default: error("Argument type mismatch at position %d: expected C pointer convertable value", argpos); /* dummy */ return R_NilValue; | |
| 366 } | |
| 367 dcArgPointer(pvm, ptrValue); | |
| 368 } | |
| 369 break; | |
| 370 case DC_SIGCHAR_STRING: | |
| 371 { | |
| 372 DCpointer cstringValue; | |
| 373 switch(type_id) | |
| 374 { | |
| 375 case NILSXP: cstringValue = (DCpointer) 0; break; | |
| 376 case CHARSXP: cstringValue = (DCpointer) CHAR(arg); break; | |
| 377 case SYMSXP: cstringValue = (DCpointer) PRINTNAME(arg); break; | |
| 378 case STRSXP: cstringValue = (DCpointer) CHAR( STRING_ELT(arg,0) ); break; | |
| 379 case EXTPTRSXP: cstringValue = R_ExternalPtrAddr(arg); break; | |
| 380 default: error("Argument type mismatch at position %d: expected C string pointer convertable value", argpos); /* dummy */ return R_NilValue; | |
| 381 } | |
| 382 dcArgPointer(pvm, cstringValue); | |
| 383 } | |
| 384 break; | |
| 385 default: error("Signature type mismatch at position %d: Unknown token '%c' at argument %d.", ch, argpos); /* dummy */ return R_NilValue; | |
| 386 } | |
| 387 } else { /* ptrcnt > 0 */ | |
| 388 DCpointer ptrValue; | |
| 389 if (ch == '<') { /* typed high-level struct/union pointer */ | |
| 390 char const * e; | |
| 391 char const * b; | |
| 392 char const * n; | |
| 393 int l; | |
| 394 b = sig; | |
| 395 while( isalnum(*sig) || *sig == '_' ) sig++; | |
| 396 if (*sig != '>') { | |
| 397 error("Invalid signature '%s' - missing '>' marker for structure at argument %d.", signature, argpos); | |
| 398 return R_NilValue; /* Dummy */ | |
| 399 } | |
| 400 sig++; | |
| 401 /* check pointer type */ | |
| 402 if (type_id != NILSXP) { | |
| 403 SEXP structName = getAttrib(arg, install("struct")); | |
| 404 if (structName == R_NilValue) { | |
| 405 error("typed pointer needed here"); | |
| 406 return R_NilValue; /* Dummy */ | |
| 407 } | |
| 408 e = sig-1; | |
| 409 l = e - b; | |
| 410 n = CHAR(STRING_ELT(structName,0)); | |
| 411 if ( (strlen(n) != l) || (strncmp(b,n,l) != 0) ) { | |
| 412 error("incompatible pointer types"); | |
| 413 return R_NilValue; /* Dummy */ | |
| 414 } | |
| 415 } | |
| 416 switch(type_id) { | |
| 417 case NILSXP: ptrValue = (DCpointer) 0; break; | |
| 418 case EXTPTRSXP: ptrValue = R_ExternalPtrAddr(arg); break; | |
| 419 case RAWSXP: ptrValue = (DCpointer) RAW(arg); break; | |
| 420 default: error("internal error: typed-pointer can be external pointers or raw only."); | |
| 421 return R_NilValue; /* Dummy */ | |
| 422 } | |
| 423 dcArgPointer(pvm, ptrValue); | |
| 424 ptrcnt = 0; | |
| 425 } else { /* typed low-level pointers */ | |
| 426 switch(ch) { | |
| 427 case DC_SIGCHAR_VOID: | |
| 428 switch(type_id) | |
| 429 { | |
| 430 case NILSXP: ptrValue = (DCpointer) 0; break; | |
| 431 case STRSXP: ptrValue = (DCpointer) CHAR(STRING_ELT(arg,0)); break; | |
| 432 case LGLSXP: ptrValue = (DCpointer) LOGICAL(arg); break; | |
| 433 case INTSXP: ptrValue = (DCpointer) INTEGER(arg); break; | |
| 434 case REALSXP: ptrValue = (DCpointer) REAL(arg); break; | |
| 435 case CPLXSXP: ptrValue = (DCpointer) COMPLEX(arg); break; | |
| 436 case RAWSXP: ptrValue = (DCpointer) RAW(arg); break; | |
| 437 case EXTPTRSXP: ptrValue = R_ExternalPtrAddr(arg); break; | |
| 438 default: error("Argument type mismatch at position %d: expected pointer convertable value", argpos); | |
| 439 return R_NilValue; /* dummy */ | |
| 440 } | |
| 441 break; | |
| 442 case DC_SIGCHAR_CHAR: | |
| 443 case DC_SIGCHAR_UCHAR: | |
| 444 switch(type_id) | |
| 445 { | |
| 446 case NILSXP: ptrValue = (DCpointer) 0; break; | |
| 447 case STRSXP: | |
| 448 if (ptrcnt == 1) { | |
| 449 ptrValue = (DCpointer) CHAR( STRING_ELT(arg,0) ); | |
| 450 } else { | |
| 451 error("Argument type mismatch at position %d: expected 'C string' convertable value", argpos); | |
| 452 return R_NilValue; /* dummy */ | |
| 453 } | |
| 454 break; | |
| 455 case RAWSXP: | |
| 456 if (ptrcnt == 1) { | |
| 457 ptrValue = RAW(arg); | |
| 458 } else { | |
| 459 error("Argument type mismatch at position %d: expected 'C string' convertable value", argpos); | |
| 460 return R_NilValue; /* dummy */ | |
| 461 } | |
| 462 break; | |
| 463 case EXTPTRSXP: ptrValue = R_ExternalPtrAddr(arg); break; | |
| 464 default: | |
| 465 error("Argument type mismatch at position %d: expected 'C string' convertable value", argpos); | |
| 466 return R_NilValue; /* dummy */ | |
| 467 } | |
| 468 break; | |
| 469 case DC_SIGCHAR_USHORT: | |
| 470 case DC_SIGCHAR_SHORT: | |
| 471 error("Signature '*[sS]' not implemented"); | |
| 472 return R_NilValue; /* dummy */ | |
| 473 case DC_SIGCHAR_UINT: | |
| 474 case DC_SIGCHAR_INT: | |
| 475 switch(type_id) | |
| 476 { | |
| 477 case NILSXP: ptrValue = (DCpointer) 0; break; | |
| 478 case INTSXP: ptrValue = (DCpointer) INTEGER(arg); break; | |
| 479 default: error("Argument type mismatch at position %d: expected 'pointer to C integer' convertable value", argpos); | |
| 480 return R_NilValue; /* dummy */ | |
| 481 } | |
| 482 break; | |
| 483 case DC_SIGCHAR_ULONG: | |
| 484 case DC_SIGCHAR_LONG: | |
| 485 error("Signature '*[jJ]' not implemented"); | |
| 486 return R_NilValue; /* dummy */ | |
| 487 case DC_SIGCHAR_ULONGLONG: | |
| 488 case DC_SIGCHAR_LONGLONG: | |
| 489 error("Signature '*[lJ]' not implemented"); | |
| 490 return R_NilValue; /* dummy */ | |
| 491 case DC_SIGCHAR_FLOAT: | |
| 492 switch(type_id) | |
| 493 { | |
| 494 case NILSXP: ptrValue = (DCpointer) 0; break; | |
| 495 case RAWSXP: | |
| 496 if ( strcmp( CHAR(STRING_ELT(getAttrib(arg, install("class")),0)),"floatraw") == 0 ) { | |
| 497 ptrValue = (DCpointer) RAW(arg); | |
| 498 } else { | |
| 499 error("Argument type mismatch at position %d: expected 'pointer to C double' convertable value", argpos); | |
| 500 return R_NilValue; /* dummy */ | |
| 501 } | |
| 502 break; | |
| 503 default: error("Argument type mismatch at position %d: expected 'pointer to C double' convertable value", argpos); | |
| 504 return R_NilValue; /* dummy */ | |
| 505 } | |
| 506 break; | |
| 507 case DC_SIGCHAR_DOUBLE: | |
| 508 switch(type_id) | |
| 509 { | |
| 510 case NILSXP: ptrValue = (DCpointer) 0; break; | |
| 511 case REALSXP: ptrValue = (DCpointer) REAL(arg); break; | |
| 512 default: error("Argument type mismatch at position %d: expected 'pointer to C double' convertable value", argpos); | |
| 513 return R_NilValue; /* dummy */ | |
| 514 } | |
| 515 break; | |
| 516 case DC_SIGCHAR_POINTER: | |
| 517 case DC_SIGCHAR_STRING: | |
| 518 switch(type_id) | |
| 519 { | |
| 520 case EXTPTRSXP: | |
| 521 ptrValue = R_ExternalPtrAddr( arg ); break; | |
| 522 default: error("low-level typed pointer on pointer not implemented"); | |
| 523 return R_NilValue; /* dummy */ | |
| 524 } | |
| 525 break; | |
| 526 default: | |
| 527 error("low-level typed pointer on C char pointer not implemented"); | |
| 528 return R_NilValue; /* dummy */ | |
| 529 } | |
| 530 dcArgPointer(pvm, ptrValue); | |
| 531 ptrcnt = 0; | |
| 532 } | |
| 533 } | |
| 534 } | |
| 535 | |
| 536 | |
| 537 if (args != R_NilValue) { | |
| 538 error ("Too many arguments for signature '%s'.", signature); | |
| 539 return R_NilValue; /* dummy */ | |
| 540 } | |
| 541 /* process return type, invoke call and return R value */ | |
| 542 | |
| 543 switch(*sig++) { | |
| 544 case DC_SIGCHAR_BOOL: return ScalarLogical( ( dcCallBool(pvm, addr) == DC_FALSE ) ? FALSE : TRUE ); | |
| 545 | |
| 546 case DC_SIGCHAR_CHAR: return ScalarInteger( (int) dcCallChar(pvm, addr) ); | |
| 547 case DC_SIGCHAR_UCHAR: return ScalarInteger( (int) ( (unsigned char) dcCallChar(pvm, addr ) ) ); | |
| 548 | |
| 549 case DC_SIGCHAR_SHORT: return ScalarInteger( (int) dcCallShort(pvm,addr) ); | |
| 550 case DC_SIGCHAR_USHORT: return ScalarInteger( (int) ( (unsigned short) dcCallShort(pvm,addr) ) ); | |
| 551 | |
| 552 case DC_SIGCHAR_INT: return ScalarInteger( dcCallInt(pvm,addr) ); | |
| 553 case DC_SIGCHAR_UINT: return ScalarReal( (double) (unsigned int) dcCallInt(pvm, addr) ); | |
| 554 | |
| 555 case DC_SIGCHAR_LONG: return ScalarReal( (double) dcCallLong(pvm, addr) ); | |
| 556 case DC_SIGCHAR_ULONG: return ScalarReal( (double) ( (unsigned long) dcCallLong(pvm, addr) ) ); | |
| 557 | |
| 558 case DC_SIGCHAR_LONGLONG: return ScalarReal( (double) dcCallLongLong(pvm, addr) ); | |
| 559 case DC_SIGCHAR_ULONGLONG: return ScalarReal( (double) dcCallLongLong(pvm, addr) ); | |
| 560 | |
| 561 case DC_SIGCHAR_FLOAT: return ScalarReal( (double) dcCallFloat(pvm,addr) ); | |
| 562 case DC_SIGCHAR_DOUBLE: return ScalarReal( dcCallDouble(pvm,addr) ); | |
| 563 case DC_SIGCHAR_POINTER: return R_MakeExternalPtr( dcCallPointer(pvm,addr), R_NilValue, R_NilValue ); | |
| 564 case DC_SIGCHAR_STRING: return mkString( dcCallPointer(pvm, addr) ); | |
| 565 case DC_SIGCHAR_VOID: dcCallVoid(pvm,addr); /* TODO: return invisible */ return R_NilValue; | |
| 566 case '*': | |
| 567 { | |
| 568 SEXP ans; | |
| 569 ptrcnt = 1; | |
| 570 while (*sig == '*') { ptrcnt++; sig++; } | |
| 571 switch(*sig) { | |
| 572 case '<': { | |
| 573 /* struct/union pointers */ | |
| 574 PROTECT(ans = R_MakeExternalPtr( dcCallPointer(pvm, addr), R_NilValue, R_NilValue ) ); | |
| 575 char buf[128]; | |
| 576 const char* begin = ++sig; | |
| 577 const char* end = strchr(sig, '>'); | |
| 578 size_t n = end - begin; | |
| 579 strncpy(buf, begin, n); | |
| 580 buf[n] = '\0'; | |
| 581 setAttrib(ans, install("struct"), mkString(buf) ); | |
| 582 setAttrib(ans, install("class"), mkString("struct") ); | |
| 583 } break; | |
| 584 case 'C': | |
| 585 case 'c': { | |
| 586 PROTECT(ans = mkString( dcCallPointer(pvm, addr) ) ); | |
| 587 } break; | |
| 588 case 'v': { | |
| 589 PROTECT(ans = R_MakeExternalPtr( dcCallPointer(pvm, addr), R_NilValue, R_NilValue ) ); | |
| 590 } break; | |
| 591 default: error("Unsupported return type signature"); return R_NilValue; | |
| 592 } | |
| 593 UNPROTECT(1); | |
| 594 return(ans); | |
| 595 } | |
| 596 default: error("Unknown return type specification for signature '%s'.", signature); | |
| 597 return R_NilValue; /* dummy */ | |
| 598 } | |
| 599 | |
| 600 } | |
| 601 |
