chicken-users
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]