Hello,
I have a question having to do with the Allegro CL's (version 6.0)
Foreign Function Interface. I defined a 'C' function as follows:
char *tststring(char *s);
I compiled the code and made a shared library out of it (I'm on a Linux
system). Then in lisp I loaded it with:
(load "libtststring.so")
And then using the Foreign Function interface I created my lisp function
for calling it as follows:
(ff:def-foreign-call (tst-string "tststring") ((s (* :char) string))
:returning ((* :char) string))
Now the string that is returned to me by my function call is correct but
the string that is being passed into my 'C' function is not. When I
enter the 'C' function I am only seeing the first character of the
string I am trying to pass to it ( I have confirmed this by having
included some debugging code). I tried to redefine my lisp function as
follows but still with out success:
(ff:def-foreign-call (tst-string "tststring") ((s (* :char)
with-native-string)) ;; doesn't work either!
:returning ((* :char) string))
Can someone give me some insight as to what I am doing wrong?
Many thanks!
Dave Richards
* David Richards <·········@earthlink.net>
| (ff:def-foreign-call (tst-string "tststring") ((s (* :char) string))
| :returning ((* :char) string))
|
| Now the string that is returned to me by my function call is correct but
| the string that is being passed into my 'C' function is not. When I
| enter the 'C' function I am only seeing the first character of the
| string I am trying to pass to it ( I have confirmed this by having
| included some debugging code).
this works for me:
(ff:def-foreign-call foo ((input (* :char)))
:strings-convert t
:returning ((* :char)))
--
Vebjorn
Shameless plug: Student looking for lispy summer job anywhere in the
United States.
Thanks to Vebjorn Ljosa for the answer - I came up with something not so
dissimilar. And now, if you don't mind, how can I define a function that
expects an array of strings from a 'C' function. I tried the following
but with no success:
(ff:def-foreign-call (querry "sqlQuerry") ((s (* :char)))
:returning (( *( * :char)) (simple-array simple-string(*) )))
I borrowed the syntax from the documentation that explains how to SEND
an array of strings to a 'C' function not how to retrieve one. Any help
would be greatly appreciated!
Dave
Vebjorn Ljosa wrote:
> * David Richards <·········@earthlink.net>
> | (ff:def-foreign-call (tst-string "tststring") ((s (* :char) string))
> | :returning ((* :char) string))
> |
> | Now the string that is returned to me by my function call is correct but
> | the string that is being passed into my 'C' function is not. When I
> | enter the 'C' function I am only seeing the first character of the
> | string I am trying to pass to it ( I have confirmed this by having
> | included some debugging code).
>
> this works for me:
>
> (ff:def-foreign-call foo ((input (* :char)))
> :strings-convert t
> :returning ((* :char)))
>
* David Richards <·········@earthlink.net>
| Thanks to Vebjorn Ljosa for the answer - I came up with something not so
| dissimilar. And now, if you don't mind, how can I define a function that
| expects an array of strings from a 'C' function. I tried the following
| but with no success:
|
| (ff:def-foreign-call (querry "sqlQuerry") ((s (* :char)))
| :returning (( *( * :char)) (simple-array simple-string(*) )))
ACL does not automatically convert arrays of C strings to a Lisp type.
(at least it didn't in version 5, when I asked Franz, and I can't find
any mention of it in the ACL6 documentation.)
you can, however, tell FF:DEF-FOREIGN-CALL that you want the raw
address, and then dig out the strings yourself:
char **bar(void)
{
char **strings;
strings = calloc(4, sizeof(char *));
if (!strings) return NULL;
strings[0] = strdup("foo");
if (!strings[0]) return NULL;
strings[1] = strdup("bar");
if (!strings[0]) return NULL;
strings[2] = strdup("baz");
if (!strings[0]) return NULL;
return strings;
}
(ff:def-foreign-call (bar-1 "bar") ()
:returning ((* (* :char))))
(defun bar ()
(let ((object (bar-1)))
(when (zerop object)
(error "C function bar() failed."))
(loop
for i from 0
for pointer = (ff:fslot-value-typed '(:array (* :char)) :c object i)
until (zerop pointer)
collect (native-to-string pointer)
do
(ff:free-fobject pointer)
finally
(ff:free-fobject object))))
I'm not sure that it's OK to use FF:FREE-FOBJECT to free the memory
allocated dynamically by the C function, because the documentation
says only that FF:FREE-FOBJECT is for freeing object allocated by
FF:ALLOCATE-FOBJECT, but it "seems to work" (famous last words). :)
alternatively, you can write a C function for freeing the memory and
pass the pointer to it when you're done with the pointer on the Lisp
side.
--
Vebjorn
Thanks so much for this info - It's helped tremendously!
Dave
Vebjorn Ljosa wrote:
> * David Richards <·········@earthlink.net>
> | Thanks to Vebjorn Ljosa for the answer - I came up with something not so
> | dissimilar. And now, if you don't mind, how can I define a function that
> | expects an array of strings from a 'C' function. I tried the following
> | but with no success:
> |
> | (ff:def-foreign-call (querry "sqlQuerry") ((s (* :char)))
> | :returning (( *( * :char)) (simple-array simple-string(*) )))
>
> ACL does not automatically convert arrays of C strings to a Lisp type.
> (at least it didn't in version 5, when I asked Franz, and I can't find
> any mention of it in the ACL6 documentation.)
>
> you can, however, tell FF:DEF-FOREIGN-CALL that you want the raw
> address, and then dig out the strings yourself:
>
> char **bar(void)
> {
> char **strings;
>
> strings = calloc(4, sizeof(char *));
> if (!strings) return NULL;
> strings[0] = strdup("foo");
> if (!strings[0]) return NULL;
> strings[1] = strdup("bar");
> if (!strings[0]) return NULL;
> strings[2] = strdup("baz");
> if (!strings[0]) return NULL;
> return strings;
> }
>
>
> (ff:def-foreign-call (bar-1 "bar") ()
> :returning ((* (* :char))))
>
>
> (defun bar ()
> (let ((object (bar-1)))
> (when (zerop object)
> (error "C function bar() failed."))
> (loop
> for i from 0
> for pointer = (ff:fslot-value-typed '(:array (* :char)) :c object i)
> until (zerop pointer)
> collect (native-to-string pointer)
> do
> (ff:free-fobject pointer)
> finally
> (ff:free-fobject object))))
>
> I'm not sure that it's OK to use FF:FREE-FOBJECT to free the memory
> allocated dynamically by the C function, because the documentation
> says only that FF:FREE-FOBJECT is for freeing object allocated by
> FF:ALLOCATE-FOBJECT, but it "seems to work" (famous last words). :)
>
> alternatively, you can write a C function for freeing the memory and
> pass the pointer to it when you're done with the pointer on the Lisp
> side.
>