Subject: [clisp-list] task proposal: UFFI support for CLISP

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Tue Dec 10 06:30:03 2002

Hi,

Andrei Formiga asked about CLISP support on the UFFI user list.

I came to realize that there's nothing but time that prevents one from starting to port UFFI to CLISP right now.
I myself don't have time. But I can give advice.
Kevin Rosenberg, author of UFFI, promised to integrate patches.

1. no shared libraries. what the heck, CLISP didn't have them for 7 years and that prevented nobody from doing FFI stuff. UFFI:def-function can nevertheless expand to ffi:def-call-out.
One can use the regexp or linux modules and see if that works, or create own modules and link them, as usual.

2. the newest CLISP (2.30) has with-foreign-object, with-c-var for stack allocation and unsigned-foreign-address and foreign-address-unsigned for low-level stuff.

3. What's truly missing is malloc and free, where the nice design is not there. IMHO, that doesn't prevent many UFFI examples from working. WITH-* constructs are recommended, like in CL in general.

4. convert-from-string et al could be more efficient in the future, but here's a quick shot:
(defun uffi:convert-from-foreign-string (address)
  (ffi:with-c-var (ptr c-pointer (foreign-address address))
    (cast ptr 'c-string)))

; probably fastest and with least GC:
(defun uffi::convert-from-foreign-string (address)
  (funcall
   (load-time-value
    (foreign-address-function "ffi_identity" #'c-self
     (ffi::parse-c-type '((:arguments (in c-pointer))(:return-type c-string)))))
   (foreign-address address)))

; alternatively
(def-c-call-out uffi:convert-from-foreign-string
  (:name "ffi_identity")
  (:arguments (in c-pointer)) ; expects FOREIGN-ADDRESS object, not FOREIGN-VARIABLE
  (:return-type c-string))

; however UFFI supports some keywords:
(defun uffi:convert-from-foreign-string (address &key length (null-terminated-p T))
 (ffi:with-foreign-object (ptr c-pointer (foreign-address address))
  (let ((type (if null-terminated-p
		  (if length
		      `(c-ptr-null (c-array-max character ,length))
		      'c-string) ; eventually return-from shortcut
		  (if length
		      `(c-ptr-null (c-array character ,length))
		      (error "bad combination")))))
    ;; only length=NIL case can be optimized as above (constant)
    (ffi::foreign-value (ffi::%cast ptr (ffi::parse-c-type type))))))
or simply (cast ptr type) when using with-c-var

(defun uffi::char-array-to-pointer (array)
  (ffi:foreign-address array)) ; or possibly identity if c-pointer accepts foreign-variable argument

5. There need to be some early design decision that can affect some aspects.

CLISP has FOREIGN-ADDRESS and FOREIGN-VARIABLE objects.

The latter includes the former and additionaly provides a C type declaration (in CLISP syntax). I.e. FOREIGN-ADDRESS is like a void*.

FOREIGN-ADDRESS is what CLISP yields when the C-POINTER interface specification is used in a function definition. FOREIGN-VARIABLE objects are not accepted by the call-out code (but I could change that).

Only FOREIGN-VARIABLE objects permit access to foreign memory, e.g. DEREF, CAST, OFFSET, ELEMENT etc. only work on these objects (since they need the foreign type declaration and check it).

WITH-FOREIGN-OBJECT yields a FORIGN-VARIABLE. When passed to a function, one can use (FOREIGN-ADDRESS f-v), resp. (C-VAR-ADDRESS x) for WITH-C-VAR.

WITH-FOREIGN-STRING (not finished yet) will yield a FOREIGN-ADDRESS only, because I found that I cannot return an adequate FOREIGN-VARIABLE lacking knowledge upon properties of the string and use (e.g. 16bit string, 32bit unicode etc.)

So far, it's unclear to me what the UFFI should use internally.

Comments?

Regards,
	Jorg Hohle.