4.1.1 Defining and calling foreign functions
;;; This example shows how the Foreign Function Interface works in ;;; C. It copies the Lisp data into foreign space, which is ;;; guaranteed to be stationary. After the call is finished, the ;;; foreign space is reclaimed. ;;; The Lisp interface to GETENV(3) provided by LIBC-GETENV uses ;;; foreign storage for both its argument and value. The LIBC ;;; declaration of GETENV(3) is given in the following code: ;;; char *getenv(name) ;;; char *name; ;;; The (3) in the name of this function is a reference to the ;;; section of the OS manual pages in which the function is ;;; described. The descriptions are generally available on line.;;; NOTE: GETENV is similar to the extension ENVIRONMENT- ;;; VARIABLE, which is described in ;;; Chapter 2, "Customizing the Lisp Environment". > (def-foreign-function (libc-getenv (:return-type (:pointer :character)) (:name "getenv") (:language :c)) (name (:pointer :character))) LIBC-GETENV
;; Using LIBC-GETENV, GETENV returns a Lisp string containing the ;; value of the environment variable name; if the name is not in ;; the environment, NIL is returned. Since LIBC-GETENV's ;; argument and value are both (:pointer :character), GETENV ;; calls LIBC-GETENV with a foreign storage copy of name, a Lisp ;; string, and uses FOREIGN-STRING-VALUE to convert LIBC-GETENV's ;; value back into a Lisp string (or NIL). Since foreign storage ;; is not reclaimed, GETENV must reclaim the foreign storage. > (defun getenv (name) (check-type name string) (let ((f-name (malloc-foreign-string name))) (prog1 (foreign-string-value (libc-getenv f-name)) (free-foreign-pointer f-name)))) GETENV
;; The value of MALLOC-FOREIGN-STRING is a (:pointer :character) ;; to a newly created foreign array of characters. This array's ;; contents is a null-terminated copy of MALLOC-FOREIGN-STRING's ;; argument, a Lisp string. The form ;; foreign-string-value (malloc-foreign-string <string>)) ;; returns a copy of <string>, if <string> does not contain a null ;; byte.
> (defun malloc-foreign-string (str) (check-type str string) ;; Allocate foreign storage for str and a null byte. (let ((f-str (malloc-foreign-pointer :type '(:pointer (:array :character (,(1+ (length str)))))))) ;; Copy str and the null byte into foreign storage. (setf (foreign-string-value f-str) str) ;; Update the foreign type. (setf (foreign-pointer-type f-str) '(:pointer :character)) f-str)) MALLOC-FOREIGN-STRING
> (getenv "SHELL") "/bin/csh"
> (getenv "no variable") NIL
;; The difference between returning (:pointer :character) and ;; returning :simple-string is not in the foreign function, but in ;; the way that the Foreign Function Interface handles the value ;; returned. When the value of :return-type is (:pointer ;; :character), the Foreign Function Interface creates a foreign ;; pointer. When value of :return-type is :simple-string, the ;; Foreign Function Interface copies the foreign string into a ;; Lisp string.
;; LIBC-GETENV-STRING returns a :simple-string so that GETENV- ;; STRING does not have to convert its value into a Lisp string. > (def-foreign-function (libc-getenv-string (:return-type :simple-string) (:name "getenv") (:language :c)) (name (:pointer :character))) LIBC-GETENV-STRING
> (defun getenv-string (name) (check-type name string) (let ((f-name (malloc-foreign-string name))) (prog1 (libc-getenv-string f-name) (free-foreign-pointer f-name)))) GETENV-STRING
;; The output from this invocation depends on the value of the ;; SHELL environment variable.
> (getenv-string "SHELL") "/bin/csh"
> (getenv-string "no variable") NIL
Generated with Harlequin WebMaker