[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [spr1064] adjustable array from Lisp to C??



   Date: Tue, 13 Feb 90 09:41:15 PST
   From: klin@argon.berkeley.edu (Kuang-Kuo Lin)

   I am trying to pass a string with variable size from Lisp to C,
   and expect that C would change the value of the string.

In C, an array is simply treated as a pointer to the first element of
the array.  In Lisp an array is an object with header information
which may include the size, adjustable flag, fill-pointer information,
etc.

When an array is passed to C through the foreign function interface,
only the pointer to the data block is passed.  The other header
information is not readily available to the C program.  Therefore, if
you want to change the fill-pointer or adjust the array, you can't do
that in C without going back into Lisp.

If you really do want to pass a string buffer from Lisp to C and have
C fill it, then you should create a simple-string (using MAKE-STRING)
with a size no smaller than the maximum amount that your C function
will want to write and pass that to C.

If, on the other hand, you are less concerned about having C overwrite
a lisp array, and just have your C function return its own array, you
can use the Allegro function FF:CHAR*-TO-STRING (I believe this
function started being available with Allegro 3.1).  With this
function, you can just have your C function return a C string as an
integer (ie, pointer to the character array).  Then FF:CHAR*-TO-STRING
will create a lisp string from that pointer.  There is an inverse
function FF:STRING-TO-CHAR* that returns the integer to the beginning
of the data block in the Lisp string.

Finally, if you don't have FF:CHAR*-TO-STRING already in your Allegro,
you can use the following definition. It first determines the length
of the string, then allocates a Lisp string, and finally copies the
characters one-by-one.  It is quite efficient in execution.

   (defcstruct (c-string :malloc) (char 1 :char))

   (defun char*-to-string (address)
     "Create a Lisp string copy of a C string"
     (declare (optimize (speed 3))
	      (integer address))
     (if (eq 0 address)
	 (error "0 is not a valid character pointer"))
     (let* ((length
	     (do* ((i 0 (1+ i))
		   (intchar (c-string-char address i)
		    	    (c-string-char address i)))
		  ((eq 0 intchar) i)))
	    (string (make-string length)))
       (declare (simple-string string)
		(fixnum length i))
       (do* ((i 0 (1+ i))
	     char)
	    ((= i length))
	    (declare (optimize (safety 0))
		     (fixnum i)
		     (string-char char)
		     (simple-string str))
	    (setq char (code-char (c-string-char address i)))
	    (setf (schar string i) char))
       string))

If you don't need to create a real Lisp array object and only need to
access the individual characters of the C string in place (the way C
itself does) the C-STRING-CHAR function defined by the DEFCSTRUCT is
all you need.  It is setfable and very fast, since the compiler
opencodes it.


	Charley
---
Charles A. Cox, Franz Inc.        1995 University Avenue, Suite 275
Internet: cox@franz.com           Berkeley, CA  94704
uucp:     uunet!franz!cox         Phone: (415) 548-3600    FAX: (415) 548-8253