4.1.1 Defining and calling foreign functions

4.1.1.2 Examples

The code in the following example demonstrates how a foreign function is defined and used. For more information about the function definitions, see Section 4.1.8 on page 113.

;;; 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


The Advanced User's Guide - 9 SEP 1996

Generated with Harlequin WebMaker