[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Chicken-users] define-foreign-type question
From: |
Felix Winkelmann |
Subject: |
Re: [Chicken-users] define-foreign-type question |
Date: |
Mon, 27 Oct 2003 10:47:08 +0100 |
User-agent: |
Opera7.11/Win32 M2 build 2887 |
On Fri, 24 Oct 2003 22:29:47 -0700 (PDT), Anurag Mendhekar
<address@hidden> wrote:
Hello,
I'm trying to understand how define-foreign-type works. I want to
define a foreign type that is the equivalent of stringlist:
typedef char *string;
typedef string stringlist[];
(define-foreign-type (pointer c-string) ?1 ?2)
My question is: what should ?1 and ?2 look like if I wanted string list
to be a list of strings in Scheme.
Hi!
What follows is a simple example that passes stringlists to and from C
code. I'm afraid it is a little bit verbose, but there are some subtleties
that one has to take into account, like who is responsible
for freeing used storage, etc.
I'm assuming a stringlist is a pointer to pointers to char, with the
last pointer being NULL to mark the end of the list.
---------------------8<-----------------------
;; We need this for pretty print:
(declare (uses extras))
;; Define a sample function that prints the contents of the stringlist:
(declare (foreign-declare "
typedef char *string;
typedef string *stringlist;
static stringlist foo(stringlist sl)
{
int i;
for(i = 0; sl[ i ] != NULL; ++i)
printf(\"foo: %d: %s\\n\", i, sl[ i ]);
return sl;
}
") )
;; Allocate a stringlist buffer. Note that no error checking is done, here!
(define list_to_string_list (foreign-lambda* c-pointer ([scheme-object
lst])
"stringlist sl;"
"int i, slen;"
"string p;"
"C_word str;"
"int len = C_unfix(C_i_length(lst));"
"sl = (stringlist)malloc((sizeof(string) + 1) * len);"
"for(i = 0; i < len; ++i) {"
" str = C_block_item(lst, 0);"
" slen = C_header_size(str);"
" p = (string)malloc(slen + 1);"
" memcpy(p, C_data_pointer(str), slen);"
" p[ slen ] = '\\0';"
" sl[ i ] = p;"
" lst = C_block_item(lst, 1);"
"}"
"sl[ i ] = NULL;"
"return(sl);") )
;; Convert a stringlist back to a Scheme list. We use a callback
;; (cons_string_list) to simplify storage allocation and the
;; extraction of a C-string (null-terminated):
(define string-list->list
(foreign-callback-lambda* scheme-object ([(pointer "string") sl])
"int i;"
"C_word lst = C_SCHEME_END_OF_LIST;"
"for(i = 0; sl[ i ] != NULL; ++i);"
"while(i > 0)"
" lst = cons_string_list(sl[ --i ], lst);"
"return(lst);") )
;; A function for freeing allocated storage:
(define free_stringlist
(foreign-lambda* void ([(pointer "string") sl])
"int i;"
"for(i = 0; sl[ i ] != NULL; ++i)"
" free(sl[ i ]);"
"free(sl);") )
;; This one is called by string-list->list:
(define-external (cons_string_list [c-string str] [scheme-object lst])
scheme-object
(cons str lst) )
;; A small wrapper for list_to_string_list, allows finalization, if needed:
(define (list->string-list lst)
(let ([p (list_to_string_list lst)])
(set-finalizer! p free_stringlist)
p) )
;; Our user-defined type:
(define-foreign-type string-list c-pointer list->string-list string-list-
list)
;; The sample function:
(define foo (foreign-lambda string-list "foo" string-list))
(pretty-print (foo '("one" "two" "three" "four")))
A final note about finalization: one has to be careful when to define
finalizers
for data passed directly to C, since the foreign code may use that data,
while
the Scheme data-object (the foreign-pointer object) associated with that
data
may be garbage collected. In that case the GC will trigger finalization,
even
though the C code is still using it. This is a general problem when using
garbage collected languages with non-garbage collected ones.
cheers,
felix