change from unlimited to big stack, to allow for interrupts to be handled
(async under unix)
"
COPYRIGHT (c) 2004 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
"{ Package: 'stx:libbasic' }"
ExternalFunction subclass:#ExternalLibraryFunction
instanceVariableNames:'flags moduleName callType returnType argumentTypes'
classVariableNames:''
poolDictionaries:''
category:'System-Support'
!
!ExternalLibraryFunction primitiveDefinitions!
%{
/*
* does this architecture support FFI ?
* NOTICE: this is now defined in the architecture-specific configuration file.
*/
#if defined(WIN32) || defined(LINUX)
# ifndef HAVE_FFI
# define HAVE_FFI
# endif
#endif
#ifdef HAVE_FFI
# include <ffi.h>
# define MAX_ARGS 128
extern ffi_type *__get_ffi_type_sint();
extern ffi_type *__get_ffi_type_sint8();
extern ffi_type *__get_ffi_type_sint16();
extern ffi_type *__get_ffi_type_sint32();
extern ffi_type *__get_ffi_type_sint64();
extern ffi_type *__get_ffi_type_uint();
extern ffi_type *__get_ffi_type_uint8();
extern ffi_type *__get_ffi_type_uint16();
extern ffi_type *__get_ffi_type_uint32();
extern ffi_type *__get_ffi_type_uint64();
extern ffi_type *__get_ffi_type_float();
extern ffi_type *__get_ffi_type_double();
extern ffi_type *__get_ffi_type_void();
extern ffi_type *__get_ffi_type_pointer();
#endif
%}
! !
!ExternalLibraryFunction class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 2004 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
instances of me are used to interface to external library functions (as found in a dll/shared object).
When a special external-call pragma such as:
<api: bool MessageBeep(uint)>
is encountered by the parser in a method, the compiler generates a call via
<correspondingExternalLibraryFunctionObject> invokeWithArguments: argumentArray.
In the invoke method, the library is checked to be loaded (and loaded if not already),
the arguments are converted to C and pushed onto the C-stack, the function is called,
and finally, the return value is converted back from C to a smalltalk object.
"
!
example
"
[exBegin]
|f|
f := ExternalLibraryFunction new.
f name:'MessageBeep'
module:'user32.dll'
callType:#WINAPI
returnType:#boolean
argumentTypes:#(uint).
f invokeWith:1.
[exEnd]
"
! !
!ExternalLibraryFunction class methodsFor:'instance creation'!
name:functionName module:moduleName callType:callType returnType:returnType argumentTypes:argTypes
^ self new
name:functionName module:moduleName callType:callType
returnType:returnType argumentTypes:argTypes
! !
!ExternalLibraryFunction class methodsFor:'constants'!
callTypeAPI
^ #callTypeAPI
!
callTypeAPIAsync
^ #callTypeAPIAsync
!
callTypeC
^ #callTypeC
!
callTypeCAsync
^ #callTypeCAsync
!
callTypeCDecl
^ #callTypeCDecl
!
callTypeCDeclAsync
^ #callTypeCDeclAsync
!
callTypeOLE
^ #callTypeOLE
!
callTypeOLEAsync
^ #callTypeOLEAsync
! !
!ExternalLibraryFunction methodsFor:'accessing'!
argumentTypes
^ argumentTypes
! !
!ExternalLibraryFunction methodsFor:'invoking'!
invoke
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeFFIWithArguments:#()
!
invokeCPPVirtualOn:anInstance
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeCPPVirtualFFIOn:anInstance withArguments:#()
!
invokeCPPVirtualOn:instance with:arg
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeCPPVirtualFFIOn:instance withArguments:(Array with:arg)
!
invokeCPPVirtualOn:instance with:arg1 with:arg2
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeCPPVirtualFFIOn:instance withArguments:(Array with:arg1 with:arg2)
!
invokeCPPVirtualOn:instance with:arg1 with:arg2 with:arg3
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeCPPVirtualFFIOn:instance withArguments:(Array with:arg1 with:arg2 with:arg3)
!
invokeCPPVirtualOn:instance with:arg1 with:arg2 with:arg3 with:arg4
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeCPPVirtualFFIOn:instance withArguments:(Array with:arg1 with:arg2 with:arg3 with:arg4)
!
invokeWith:arg
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeFFIWithArguments:(Array with:arg)
!
invokeWith:arg1 with:arg2
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeFFIWithArguments:(Array with:arg1 with:arg2)
!
invokeWith:arg1 with:arg2 with:arg3
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3)
!
invokeWith:arg1 with:arg2 with:arg3 with:arg4
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeFFIWithArguments:(Array with:arg1 with:arg2 with:arg3 with:arg4)
!
invokeWithArguments:argArray
self hasCode ifFalse:[
self prepareInvoke.
].
^ self invokeFFIWithArguments:argArray
! !
!ExternalLibraryFunction methodsFor:'printing'!
printOn:aStream
aStream nextPutAll:'<'.
callType printOn:aStream.
aStream nextPutAll:' '.
name printOn:aStream.
aStream nextPutAll:' module:'.
moduleName printOn:aStream.
aStream nextPutAll:'>'.
! !
!ExternalLibraryFunction methodsFor:'private'!
linkToModule
"link this function to the external module.
I.e. retrieve the module handle and the code pointer."
|handle functionName|
moduleName isNil ifTrue:[
self error:'Missing moduleName'.
].
moduleHandle isNil ifTrue:[
handle := ObjectFileLoader loadDynamicObject:(moduleName asString).
handle isNil ifTrue:[
handle := ObjectFileLoader
loadDynamicObject:(Filename currentDirectory construct:moduleName) pathName.
handle isNil ifTrue:[
self error:'Cannot load module: ', moduleName.
].
].
moduleHandle := handle.
].
name isNumber ifFalse:[
functionName := name.
(moduleHandle getFunctionAddress:functionName into:self) isNil ifTrue:[
functionName := ('_', functionName) asSymbol.
(moduleHandle getFunctionAddress:functionName into:self) isNil ifTrue:[
moduleHandle := nil.
self error:'Missing function: ', name, ' in module: ', moduleName.
].
].
].
"Modified: / 22-06-2006 / 16:48:57 / cg"
!
prepareInvoke
self hasCode ifFalse:[
moduleHandle isNil ifTrue:[
self linkToModule.
].
].
! !
!ExternalLibraryFunction methodsFor:'private-accessing'!
ffiTypeSymbolForType:aType
|t|
"/ kludge for those who do not have the CType package...
t := aType.
t isSymbol ifFalse:[
aType isString ifFalse:[
CType isNil ifTrue:[
self error:'unknown type'.
].
t := aType typeSymbol.
].
aType isString ifTrue:[
self halt
].
t isSymbol ifFalse:[
self error:'unknown type'.
].
].
^ t
!
name:functionName module:aModuleName callType:aCallType returnType:aReturnType argumentTypes:argTypes
name := functionName.
moduleName := aModuleName.
callType := aCallType.
returnType := aReturnType.
argumentTypes := argTypes.
! !
!ExternalLibraryFunction methodsFor:'private-invoking'!
invokeCPPVirtualFFIOn:instance withArguments:arguments
^ self invokeFFIwithArguments:arguments forCPPInstance:instance virtual:true
!
invokeFFIWithArguments:arguments
^ self invokeFFIwithArguments:arguments forCPPInstance:nil virtual:false
!
invokeFFIwithArguments:arguments forCPPInstance:aCPlusPlusObjectOrNil virtual:virtual
|argTypeSymbols returnTypeSymbol failureCode returnValue stClass vtOffset|
argumentTypes notNil ifTrue:[
argTypeSymbols := argumentTypes collect:[:argType | self ffiTypeSymbolForType:argType].
].
returnTypeSymbol := self ffiTypeSymbolForType:returnType.
aCPlusPlusObjectOrNil notNil ifTrue:[
"/ it must be a kind of ExternalStructure !!
(aCPlusPlusObjectOrNil isKindOf:ExternalStructure) ifFalse:[
self primitiveFailed.
].
virtual ifTrue:[
vtOffset := name.
(vtOffset between:0 and:10000) ifFalse:[
self primitiveFailed.
]
].
].
%{ /* STACK: 100000 */
#ifdef HAVE_FFI
ffi_cif __cif;
ffi_type *__argTypesIncludingThis[MAX_ARGS+1];
ffi_type **__argTypes = __argTypesIncludingThis;
ffi_type *__returnType = NULL;
union u {
int iVal;
float fVal;
double dVal;
void *pointerVal;
};
union u __argValuesIncludingThis[MAX_ARGS+1];
union u *__argValues = __argValuesIncludingThis;
union u __returnValue;
void *__argValuePointersIncludingThis[MAX_ARGS+1];
void **__argValuePointers = __argValuePointersIncludingThis;
void *__returnValuePointer;
int __numArgs, __numArgsIncludingThis;
static int null = 0;
int i;
ffi_abi __callType = FFI_DEFAULT_ABI;
int __asyncCall = 0;
VOIDFUNC codeAddress = (VOIDFUNC)__INST(code_);
if (arguments == nil) {
__numArgs = 0;
if (argTypeSymbols != nil) {
if (! __isArray(argTypeSymbols)
|| (__arraySize(argTypeSymbols) != __numArgs)) {
failureCode = @symbol(ArgumentCountMismatch);
goto getOutOfHere;
}
}
} else {
if (! __isArray(arguments)
|| ! __isArray(argTypeSymbols)
|| (__arraySize(argTypeSymbols) != (__numArgs = __arraySize(arguments)))) {
failureCode = @symbol(ArgumentCountMismatch);
goto getOutOfHere;
}
}
if (__numArgs > MAX_ARGS) {
failureCode = @symbol(TooManyArguments);
goto getOutOfHere;
}
if ((__INST(callType) == @symbol(callTypeCAsync))
|| (__INST(callType) == @symbol(callTypeAPIAsync))
|| (__INST(callType) == @symbol(callTypeCDeclAsync))
|| (__INST(callType) == @symbol(callTypeOLEAsync))) {
__asyncCall = 1;
}
/*
* validate the return type
*/
__returnValuePointer = &__returnValue;
if (returnTypeSymbol == @symbol(int)) {
__returnType = __get_ffi_type_sint();
} else if (returnTypeSymbol == @symbol(uint)) {
__returnType = __get_ffi_type_uint();
} else if (returnTypeSymbol == @symbol(long)) {
if (sizeof(long) == 4) {
__returnType = __get_ffi_type_sint32();
} else if (sizeof(long) == 8) {
__returnType = __get_ffi_type_sint64();
} else {
failureCode = @symbol(UnknownReturnType);
goto getOutOfHere;
}
} else if (returnTypeSymbol == @symbol(ulong)) {
if (sizeof(long) == 4) {
__returnType = __get_ffi_type_uint32();
}else if (sizeof(long) == 8) {
__returnType = __get_ffi_type_uint64();
} else {
failureCode = @symbol(UnknownReturnType);
goto getOutOfHere;
}
} else if (returnTypeSymbol == @symbol(boolean)) {
__returnType = __get_ffi_type_uint();
} else if (returnTypeSymbol == @symbol(uint8)) {
__returnType = __get_ffi_type_uint8();
} else if (returnTypeSymbol == @symbol(sint8)) {
__returnType = __get_ffi_type_sint8();
} else if (returnTypeSymbol == @symbol(uint16)) {
__returnType = __get_ffi_type_uint16();
} else if (returnTypeSymbol == @symbol(sint16)) {
__returnType = __get_ffi_type_sint16();
} else if (returnTypeSymbol == @symbol(float)) {
__returnType = __get_ffi_type_float();
} else if (returnTypeSymbol == @symbol(double)) {
__returnType = __get_ffi_type_double();
} else if (returnTypeSymbol == @symbol(void)) {
__returnType = __get_ffi_type_void();
__returnValuePointer = NULL;
} else if (returnTypeSymbol == @symbol(pointer)) {
__returnType = __get_ffi_type_pointer();
} else if (returnTypeSymbol == @symbol(handle)) {
__returnType = __get_ffi_type_pointer();
} else {
failureCode = @symbol(UnknownReturnType);
goto getOutOfHere;
}
/*
* validate the c++ object
*/
if (aCPlusPlusObjectOrNil != nil) {
struct cPlusPlusInstance {
void **vTable;
};
struct cPlusPlusInstance *inst;
if (__isExternalAddressLike(aCPlusPlusObjectOrNil)) {
inst = (void *)(__externalAddressVal(aCPlusPlusObjectOrNil));
} else if (__isExternalBytesLike(aCPlusPlusObjectOrNil)) {
inst = (void *)(__externalBytesVal(aCPlusPlusObjectOrNil));
} else {
failureCode = @symbol(InvalidInstance);
goto getOutOfHere;
}
__argValues[0].pointerVal = inst;
__argValuePointersIncludingThis[0] = &(__argValues[0]);
__argTypes[0] = __get_ffi_type_pointer();
__argValuePointers = &__argValuePointersIncludingThis[1];
__argTypes = &__argTypesIncludingThis[1];
__argValues = &__argValuesIncludingThis[1];
__numArgsIncludingThis = __numArgs + 1;
if (virtual == true) {
if (! __isSmallInteger(vtOffset)) {
failureCode = @symbol(InvalidVTableIndex);
goto getOutOfHere;
}
codeAddress = inst->vTable[__intVal(vtOffset)];
printf("codeAddress: %x\n", codeAddress);
}
} else {
__numArgsIncludingThis = __numArgs;
}
/*
* validate all arg types and setup arg-buffers
*/
for (i=0; i<__numArgs; i++) {
ffi_type *thisType;
void *argValuePtr;
OBJ typeSymbol;
OBJ arg;
typeSymbol = __ArrayInstPtr(argTypeSymbols)->a_element[i];
arg = __ArrayInstPtr(arguments)->a_element[i];
if (typeSymbol == @symbol(long)) {
if (sizeof(long) == sizeof(int)) {
typeSymbol = @symbol(sint);
} else {
if (sizeof(long) == 4) {
typeSymbol = @symbol(sint32);
} else if (sizeof(long) == 8) {
typeSymbol = @symbol(sint64);
}
}
}
if (typeSymbol == @symbol(ulong)) {
if (sizeof(unsigned long) == sizeof(unsigned int)) {
typeSymbol = @symbol(uint);
} else {
if (sizeof(long) == 4) {
typeSymbol = @symbol(uint32);
} else if (sizeof(long) == 8) {
typeSymbol = @symbol(uint64);
}
}
}
if (typeSymbol == @symbol(int)) {
thisType = __get_ffi_type_sint();
if (__isSmallInteger(arg)) {
__argValues[i].iVal = __intVal(arg);
} else {
__argValues[i].iVal = __signedLongIntVal(arg);
if (__argValues[i].iVal == 0) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
}
argValuePtr = &(__argValues[i].iVal);
} else if (typeSymbol == @symbol(uint)) {
thisType = __get_ffi_type_uint();
if (__isSmallInteger(arg)) {
__argValues[i].iVal = __intVal(arg);
} else {
__argValues[i].iVal = __unsignedLongIntVal(arg);
if (__argValues[i].iVal == 0) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
}
argValuePtr = &(__argValues[i].iVal);
} else if (typeSymbol == @symbol(uint8)) {
thisType = __get_ffi_type_uint8();
if (! __isSmallInteger(arg)) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
__argValues[i].iVal = __intVal(arg);
if (((unsigned)(__argValues[i].iVal)) > 0xFF) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
argValuePtr = &(__argValues[i].iVal);
} else if (typeSymbol == @symbol(sint8)) {
thisType = __get_ffi_type_sint8();
if (! __isSmallInteger(arg)) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
__argValues[i].iVal = __intVal(arg);
if (((__argValues[i].iVal) < -0x80) || ((__argValues[i].iVal) > 0x7F)) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
argValuePtr = &(__argValues[i].iVal);
} else if (typeSymbol == @symbol(uint16)) {
thisType = __get_ffi_type_uint16();
if (! __isSmallInteger(arg)) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
__argValues[i].iVal = __intVal(arg);
if (((unsigned)(__argValues[i].iVal)) > 0xFFFF) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
argValuePtr = &(__argValues[i].iVal);
} else if (typeSymbol == @symbol(sint16)) {
thisType = __get_ffi_type_sint16();
if (! __isSmallInteger(arg)) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
__argValues[i].iVal = __intVal(arg);
if (((__argValues[i].iVal) < -0x8000) || ((__argValues[i].iVal) > 0x7FFF)) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
argValuePtr = &(__argValues[i].iVal);
} else if (typeSymbol == @symbol(float)) {
thisType = __get_ffi_type_float();
if (__isSmallInteger(arg)) {
__argValues[i].fVal = (float)(__intVal(arg));
} else if (__isFloat(arg)) {
__argValues[i].fVal = (float)(__floatVal(arg));
} else if (__isShortFloat(arg)) {
__argValues[i].fVal = (float)(__shortFloatVal(arg));
} else {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
argValuePtr = &(__argValues[i].fVal);
} else if (typeSymbol == @symbol(double)) {
thisType = __get_ffi_type_double();
if (__isSmallInteger(arg)) {
__argValues[i].dVal = (double)(__intVal(arg));
} else if (__isFloat(arg)) {
__argValues[i].dVal = (double)(__floatVal(arg));
} else if (__isShortFloat(arg)) {
__argValues[i].dVal = (double)(__shortFloatVal(arg));
} else {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
argValuePtr = &(__argValues[i].dVal);
} else if (typeSymbol == @symbol(void)) {
thisType = __get_ffi_type_void();
argValuePtr = &null;
} else if (typeSymbol == @symbol(pointer)) {
thisType = __get_ffi_type_pointer();
if (__isExternalAddressLike(arg)) {
__argValues[i].pointerVal = (void *)(__externalAddressVal(arg));
} else if (__isExternalBytesLike(arg)) {
__argValues[i].pointerVal = (void *)(__externalBytesVal(arg));
} else if (__isByteArray(arg)) {
if (__asyncCall) goto badArgForAsyncCall;
__argValues[i].pointerVal = (void *)(__byteArrayVal(arg));
} else if (__isFloatArray(arg)) {
if (__asyncCall) goto badArgForAsyncCall;
__argValues[i].pointerVal = (void *)(__FloatArrayInstPtr(arg)->f_element);
} else if (__isDoubleArray(arg)) {
if (__asyncCall) goto badArgForAsyncCall;
__argValues[i].pointerVal = (void *)(__DoubleArrayInstPtr(arg)->d_element);
} else if (__isString(arg) || __isSymbol(arg)) {
if (__asyncCall) {
badArgForAsyncCall: ;
failureCode = @symbol(BadArgForAsyncCall);
goto getOutOfHere;
}
__argValues[i].pointerVal = (void *)(__stringVal(arg));
} else {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
argValuePtr = &(__argValues[i].pointerVal);;
} else if (typeSymbol == @symbol(boolean)) {
thisType = __get_ffi_type_uint();
if (arg == true) {
__argValues[i].iVal = 1;
} else if (arg == false) {
__argValues[i].iVal = 0;
} else if (__isSmallInteger(arg)) {
__argValues[i].iVal = __intVal(arg);
} else {
__argValues[i].iVal = __unsignedLongIntVal(arg);
if (__argValues[i].iVal == 0) {
failureCode = @symbol(InvalidArgument);
goto getOutOfHere;
}
}
argValuePtr = &(__argValues[i].iVal);
} else {
failureCode = @symbol(UnknownArgumentType);
goto getOutOfHere;
}
__argTypes[i] = thisType;
__argValuePointers[i] = argValuePtr;
}
__callType = FFI_DEFAULT_ABI;
#ifdef CALLTYPE_FFI_STDCALL
if ((__INST(callType) == @symbol(callTypeAPI))
|| (__INST(callType) == @symbol(WINAPI))
|| (__INST(callType) == @symbol(STDCALL))
|| (__INST(callType) == @symbol(callTypeAPIAsync))) {
__callType = CALLTYPE_FFI_STDCALL;
}
#endif
#ifdef CALLTYPE_FFI_V8
if ((__INST(callType) == @symbol(callTypeV8))
|| (__INST(callType) == @symbol(V8))) {
__callType = CALLTYPE_FFI_V8;
}
#endif
#ifdef CALLTYPE_FFI_V9
if ((__INST(callType) == @symbol(callTypeV9))
|| (__INST(callType) == @symbol(V9))) {
__callType = CALLTYPE_FFI_V9;
}
#endif
#ifdef CALLTYPE_FFI_UNIX64
if ((__INST(callType) == @symbol(callTypeUnix64))
|| (__INST(callType) == @symbol(UNIX64))) {
__callType = CALLTYPE_FFI_UNIX64;
}
#endif
if (ffi_prep_cif(&__cif, __callType, __numArgsIncludingThis, __returnType, __argTypesIncludingThis) != FFI_OK) {
failureCode = @symbol(FFIPrepareFailed);
goto getOutOfHere;
}
if (__asyncCall) {
#ifdef WIN32
__STX_C_CALL4( "ffi_call", ffi_call, &__cif, codeAddress, __returnValuePointer, __argValuePointersIncludingThis);
#else
fprintf(stderr, 'async\n');
__BEGIN_INTERRUPTABLE__
ffi_call(&__cif, codeAddress, __returnValuePointer, __argValuePointersIncludingThis);
__END_INTERRUPTABLE__
#endif
} else {
fprintf(stderr, 'sync\n');
ffi_call(&__cif, codeAddress, __returnValuePointer, __argValuePointersIncludingThis);
}
if ((returnTypeSymbol == @symbol(int))
|| (returnTypeSymbol == @symbol(int8))
|| (returnTypeSymbol == @symbol(int16))
|| (returnTypeSymbol == @symbol(int32))) {
RETURN ( __MKINT(__returnValue.iVal) );
}
if ((returnTypeSymbol == @symbol(uint))
|| (returnTypeSymbol == @symbol(uint8))
|| (returnTypeSymbol == @symbol(uint16))
|| (returnTypeSymbol == @symbol(uint32))) {
RETURN ( __MKUINT(__returnValue.iVal) );
}
if (returnTypeSymbol == @symbol(boolean)) {
RETURN ( __returnValue.iVal ? true : false );
}
if (returnTypeSymbol == @symbol(float)) {
RETURN ( __MKFLOAT(__returnValue.fVal ));
}
if (returnTypeSymbol == @symbol(double)) {
RETURN ( __MKFLOAT(__returnValue.dVal ));
}
if (returnTypeSymbol == @symbol(void)) {
RETURN ( nil );
}
if (returnTypeSymbol == @symbol(handle)) {
returnValue = __MKEXTERNALADDRESS(__returnValue.pointerVal);
} else if (returnTypeSymbol == @symbol(pointer)) {
returnValue = __MKEXTERNALBYTES(__returnValue.pointerVal);
} else {
failureCode = @symbol(UnknownReturnType2);
}
getOutOfHere: ;
#else /* no FFI support */
failureCode = @symbol(FFINotSupported);
#endif /* HAVE_FFI */
%}.
failureCode notNil ifTrue:[
self primitiveFailed.
^ nil
].
returnType isCPointer ifTrue:[
returnType baseType isCStruct ifTrue:[
stClass := Smalltalk classNamed:returnType baseType name.
stClass notNil ifTrue:[
^ stClass fromExternalAddress:returnValue.
].
].
returnType baseType isCChar ifTrue:[
^ returnValue stringAt:1
].
].
^ returnValue
! !
!ExternalLibraryFunction class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libbasic/ExternalLibraryFunction.st,v 1.32 2006-07-26 13:37:09 ca Exp $'
! !