I'm trying to call a library which returns all of its data through
char **'s. I'm pretty sure I could write a plugin to do this, but I
would prefer to use FFI. Here's an example of two basic functions
with signatures similar to this library:
-----------------------------------------------------------------------
--- int s_dup(char * in, char ** out);
int s_free(char * in);
-----------------------------------------------------------------------
---
These particular ones are just test functions I wrote in a test
library:
-----------------------------------------------------------------------
--- int s_dup(char * in, char ** out)
{
printf("s_dup(%08x, %08x)", in, out);
if (out) printf(" ((%08x))", * out);
printf("\n");
* out = strdup(in);
return 0;
}
int s_free(char * in)
{
printf("s_free(%08x)", in);
if (in)
free(in);
return 0;
}
-----------------------------------------------------------------------
---
In English, the returned string is passed as an out parameter, which
must be freed by the client using a supplied function. Well, that was
almost English. So, to call these functions I made a FFIStringTest
class:
-----------------------------------------------------------------------
--- 'From Squeak3.5 of ''11 April 2003'' [latest update: #5180] on 27
September 2003 at 11:00:13 am'!
ExternalLibrary subclass: #FFIStringTest
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'FFI-StringTest'!
!FFIStringTest methodsFor: 'as yet unclassified' stamp: 'acb 9/27/2003
10:47'!
dup: str to: aStrPtr
"Copy the string passed in to us."
<cdecl: long 's_dup' (char * FFIStringPtr *) module: 'strt'>
^ self externalCallFailed! !
!FFIStringTest methodsFor: 'as yet unclassified' stamp: 'acb 9/26/2003
21:40'!
free: aStrPtr
"Free the string passed in to us."
<cdecl: long 's_free' (FFIStringPtr) module: 'strt'>
^ self externalCallFailed! !
-----------------------------------------------------------------------
---
And, a FFIStringPtr class, since 'char **' is not a happy parameter
type:
-----------------------------------------------------------------------
--- 'From Squeak3.5 of ''11 April 2003'' [latest update: #5180] on 27
September 2003 at 11:03:53 am'!
ExternalStructure subclass: #FFIStringPtr
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'FFI-StringTest'!
!FFIStringPtr methodsFor: 'as yet unclassified' stamp: 'acb 9/27/2003
08:01'!
str
"Dereference the pointer and return the string."
"^ (self handle pointerAt: 1) "
^ ( ExternalData fromHandle: self handle type: ExternalType char )
fromCString! !
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
FFIStringPtr class
instanceVariableNames: ''!
!FFIStringPtr class methodsFor: 'as yet unclassified' stamp: 'acb
9/27/2003 08:00'!
fields
"FFIStringPtr defineFields"
"Define a structure which is just a string pointer."
^#(
(ptr 'char *')
)! !
FFIStringPtr compileFields!
-----------------------------------------------------------------------
---
So, it seems to me that I'm pretty close, yet not so close at all.
When I run this:
-----------------------------------------------------------------------
--- | f p |
f _ FFIStringTest new.
p _ FFIStringPtr new.
f dup: 'hi there' to: p.
f free: p.
-----------------------------------------------------------------------
---
I get some of my printf output to the console, followed by an enormous
stack dump:
-----------------------------------------------------------------------
--- s_dup(08155e58, 40cdc904) ((40b283d1))
Segmentation fault
1087228576 ProtoObject>become:
1087228392 MethodContext>doesNotUnderstand:
1087228300 MethodContext>doesNotUnderstand:
1087228208 Behavior>removeSelectorSimply:
1087197804 Compiler>evaluate:in:to:notifying:ifFail:
1087198172 [] in ParagraphEditor>evaluateSelection
..
.. (and a _bunch_ of lines of stuff that looks like Morphic handling
of an alt-d)
..
-----------------------------------------------------------------------
---
About as much as I can really say is that it is not getting to the
s_free call. Can anyone tell me what I'm doing wrong, or perhaps
suggest another place to look for documentation/comments?
Thanks,
-andrew
--
andrew_c_berg_at_yahoo.com
>From the "FFI questions" thread of Sept. 4, Andreas helped me
out with:
> > <cdecl: ulong 'cgCreateProgram' (ulong ulong byte*
> > ulong byte* byte** ) module: 'Cg'>
> ^^
> And this is the problem. The FFI can't coerce arrays of pointers
> automatically, so using "foo **" in any way is simply invalid.
See the thread for more details.
I've attached the NullTerminatedStringArray class that I wrote
as a result of that discussion. I hope that you find it useful.
Joshua