From: David Richards
Subject: Allegro CL's Foreign Function Interface
Date: 
Message-ID: <3A994F18.3080303@earthlink.net>
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

From: Vebjorn Ljosa
Subject: Re: Allegro CL's Foreign Function Interface
Date: 
Message-ID: <cy3hf1ilbl7.fsf@proto.pvv.ntnu.no>
* 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.
From: David Richards
Subject: Re: Allegro CL's Foreign Function Interface
Date: 
Message-ID: <3A9AF89C.6070903@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(*) )))

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)))
> 
From: Vebjorn Ljosa
Subject: Re: Allegro CL's Foreign Function Interface
Date: 
Message-ID: <cy3vgpwputn.fsf@proto.pvv.ntnu.no>
* 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
From: David Richards
Subject: Re: Allegro CL's Foreign Function Interface
Date: 
Message-ID: <3A9F020F.8030306@earthlink.net>
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.
>