From: John S. <jwe...@co...> - 2005-02-12 00:20:52
|
That was a long 2-3 hours - sorry I was tied up at work. Basically I don't understand why I can't take a returned c-pointer and use it with the following. "s" is a returned ffi:c-pointer (ffi:foreign-value (ffi:foreign-variable s (ffi:parse-c-type 'ffi:c-string))) The above expression will produce the following error: *** - Incomplete FFI type C-STRING is not allowed here. Below is the complete example with foo.c and foo.lisp demonstrating what I'm trying to do with the returned array of strings which is not nulled terminated but may have null pointers embedded to represent SQL null values. (Thanks for all your help.) ------------------------------------------------------------ // foo.c #include <stdio.h> // define for M$ Visual C #define DLLEXPORT _declspec(dllexport) // #define DLLEXPORT char * cols[] = { "one", "two", "three", "four" }; DLLEXPORT void display_c_addresses() { printf("\nC address of string array: %x",cols); printf("\nC address of 1st string: %x %s",cols[0],cols[0]); printf("\nC address of 2nd string: %x %s",cols[1],cols[1]); printf("\nC address of 3st string: %x %s",cols[2],cols[2]); printf("\nC address of 4nd string: %x %s",cols[3],cols[3]); } DLLEXPORT char * foo() { return cols[0]; } DLLEXPORT char ** bar() { return cols; } ------------------------------------------------------------------- ;; Example of accessing arrays not null terminated ;; foo.lisp ;; see foo.c ;; Display C addresses of array and strings (FFI:DEF-CALL-OUT display-c-addresses (:library "foo.dll") (:language :stdc) (:name "display_c_addresses") (:arguments) (:return-type ffi:nil)) (display-c-addresses) ;; Demonstrate foreign-variable on a single c-pointer ;; First use automatic allocation and copy of string. (FFI:DEF-CALL-OUT foo1 (:library "foo.dll") (:language :stdc) (:name "foo") (:arguments) (:return-type ffi:c-string)) (setf s (foo1)) (format t "~%1. one: ~A" s) ;; Now manually allocate and copy string. (FFI:DEF-CALL-OUT foo2 (:library "foo.dll") (:language :stdc) (:name "foo") (:arguments) (:return-type ffi:c-pointer)) (setf s (foo2)) (format t "~%2. Address of one: ~A" s) ; Follow generates error: ; *** - Incomplete FFI type C-STRING is not allowed here. '(if (not (ffi:foreign-address-null s)) (format t "~%3. one: ~A" (ffi:foreign-value (ffi:foreign-variable s (ffi::parse-c-type 'c-string))))) ;; Now experiment with array of string pointers. (FFI:DEF-CALL-OUT bar1 (:library "foo.dll") (:language :stdc) (:name "bar") (:arguments) (:return-type ffi:c-pointer)) (setf s (bar1)) (format t "~%4. Foreign address s: ~A" s) (setf s (ffi:foreign-value (ffi:foreign-variable s (ffi:parse-c-type `(ffi:c-array ffi:c-string ,4))))) (format t "~%5. Vector of strings: ~A" s) ;; c-string worked above and in conjunction ;; with foreign-value automatically allocated ;; and copied the strings! ;; Now we get fancy and first allocate ;; the array of foreign addresses. (setf s (bar1)) (setf s (ffi:foreign-value (ffi:foreign-variable s (ffi:parse-c-type `(ffi:c-array ffi:c-pointer ,4))))) ;; c-pointer "conversion" above is used so that ;; a test using foreign-address-null can be made ;; on each char * foreign address. That's because ;; SQL null values are indicated by null ptrs ;; and thus the array may have embedded NULL's! (format t "~%6. Vector of foreign addresses: ~A" s) ;; But now if we want to pull back a specific ;; string we can't for the same reason #3 above ;; failed. (setf s2 (svref s 1)) (format t "~%7. Foreign address of 2nd string: ~A" s2) ; Follow generates error again: ; *** - Incomplete FFI type C-STRING is not allowed here. '(if (not (ffi:foreign-address-null s2)) (format t "~%8. two: ~A" (ffi:foreign-value (ffi:foreign-variable s2 (ffi::parse-c-type 'c-string))))) |