[rdnzl-cvs] CVS RDNZL

eweitz eweitz at common-lisp.net
Mon Jun 12 08:47:10 UTC 2006


Update of /project/rdnzl/cvsroot/RDNZL
In directory clnet:/tmp/cvs-serv27065

Modified Files:
	CHANGELOG.txt arrays.lisp load.lisp port-ccl.lisp 
	port-sbcl.lisp rdnzl.asd 
Added Files:
	port-ecl.lisp 
Log Message:
release 0.10.0 (ECL support)


--- /project/rdnzl/cvsroot/RDNZL/CHANGELOG.txt	2006/05/24 21:49:09	1.8
+++ /project/rdnzl/cvsroot/RDNZL/CHANGELOG.txt	2006/06/12 08:47:10	1.9
@@ -1,3 +1,7 @@
+Version 0.10.0
+2006-06-12
+ECL port (provided by Michael Goffioul)
+
 Version 0.9.5
 2006-05-24
 Fixed delivery scripts and IMPORT statement for LW
--- /project/rdnzl/cvsroot/RDNZL/arrays.lisp	2006/02/18 22:26:12	1.5
+++ /project/rdnzl/cvsroot/RDNZL/arrays.lisp	2006/06/12 08:47:10	1.6
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: RDNZL; Base: 10 -*-
-;;; $Header: /project/rdnzl/cvsroot/RDNZL/arrays.lisp,v 1.5 2006/02/18 22:26:12 eweitz Exp $
+;;; $Header: /project/rdnzl/cvsroot/RDNZL/arrays.lisp,v 1.6 2006/06/12 08:47:10 eweitz Exp $
 
 ;;; Copyright (c) 2004-2006, Dr. Edmund Weitz.  All rights reserved.
 
@@ -43,7 +43,7 @@
     ;; FFI array so we don't have the expensive call to INVOKE on each
     ;; iteration - but we don't do that now
     `(let* ((,array ,array-form)
-            (,length [%Length ,array]))
+            (,length (property ,array "Length")))
        (dotimes (,i ,length)
          (let ((,var (get-array-element ,array ,i)))
            , at body))
--- /project/rdnzl/cvsroot/RDNZL/load.lisp	2006/02/18 22:26:12	1.5
+++ /project/rdnzl/cvsroot/RDNZL/load.lisp	2006/06/12 08:47:10	1.6
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
-;;; $Header: /project/rdnzl/cvsroot/RDNZL/load.lisp,v 1.5 2006/02/18 22:26:12 eweitz Exp $
+;;; $Header: /project/rdnzl/cvsroot/RDNZL/load.lisp,v 1.6 2006/06/12 08:47:10 eweitz Exp $
 
 ;;; Copyright (c) 2004-2006, Dr. Edmund Weitz.  All rights reserved.
 
@@ -43,6 +43,7 @@
                     #+:allegro "port-acl"
                     #+:cormanlisp "port-ccl"
                     #+:clisp "port-clisp"
+                    #+:ecl "port-ecl"
                     #+:lispworks "port-lw"
                     #+:sbcl "port-sbcl"
                     "ffi"
--- /project/rdnzl/cvsroot/RDNZL/port-ccl.lisp	2006/05/24 21:49:09	1.6
+++ /project/rdnzl/cvsroot/RDNZL/port-ccl.lisp	2006/06/12 08:47:10	1.7
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: RDNZL; Base: 10 -*-
-;;; $Header: /project/rdnzl/cvsroot/RDNZL/port-ccl.lisp,v 1.6 2006/05/24 21:49:09 eweitz Exp $
+;;; $Header: /project/rdnzl/cvsroot/RDNZL/port-ccl.lisp,v 1.7 2006/06/12 08:47:10 eweitz Exp $
 
 ;;; Copyright (c) 2004-2006, Dr. Edmund Weitz.  All rights reserved.
 
--- /project/rdnzl/cvsroot/RDNZL/port-sbcl.lisp	2006/05/24 21:49:09	1.4
+++ /project/rdnzl/cvsroot/RDNZL/port-sbcl.lisp	2006/06/12 08:47:10	1.5
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: RDNZL; Base: 10 -*-
-;;; $Header: /project/rdnzl/cvsroot/RDNZL/port-sbcl.lisp,v 1.4 2006/05/24 21:49:09 eweitz Exp $
+;;; $Header: /project/rdnzl/cvsroot/RDNZL/port-sbcl.lisp,v 1.5 2006/06/12 08:47:10 eweitz Exp $
 
 ;;; Copyright (c) 2004-2006, Dr. Edmund Weitz.  All rights reserved.
 
--- /project/rdnzl/cvsroot/RDNZL/rdnzl.asd	2006/05/24 21:49:09	1.7
+++ /project/rdnzl/cvsroot/RDNZL/rdnzl.asd	2006/06/12 08:47:10	1.8
@@ -1,5 +1,5 @@
 ;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*-
-;;; $Header: /project/rdnzl/cvsroot/RDNZL/rdnzl.asd,v 1.7 2006/05/24 21:49:09 eweitz Exp $
+;;; $Header: /project/rdnzl/cvsroot/RDNZL/rdnzl.asd,v 1.8 2006/06/12 08:47:10 eweitz Exp $
 
 ;;; Copyright (c) 2004, Dr. Edmund Weitz.  All rights reserved.
 
@@ -46,6 +46,7 @@
                #+:allegro (:file "port-acl")    ; AllegroCL-specific stuff here
                #+:cormanlisp (:file "port-ccl") ; Corman-specific stuff here
                #+:clisp (:file "port-clisp")    ; CLISP-specific stuff here
+               #+:ecl (:file "port-ecl")        ; ECL-specific stuff here
                #+:lispworks (:file "port-lw")   ; LispWorks-specific stuff here
                #+:sbcl (:file "port-sbcl")      ; SBCL-specific stuff here
                (:file "ffi")

--- /project/rdnzl/cvsroot/RDNZL/port-ecl.lisp	2006/06/12 08:47:10	NONE
+++ /project/rdnzl/cvsroot/RDNZL/port-ecl.lisp	2006/06/12 08:47:10	1.1
;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: RDNZL; Base: 10 -*-
;;; $Header: /project/rdnzl/cvsroot/RDNZL/port-ecl.lisp,v 1.1 2006/06/12 08:47:10 eweitz Exp $

;;; Copyright (c) 2004-2006, Vasilis Margioulas, Michael Goffioul, Dr. Edmund Weitz.  All rights reserved.

;;; Redistribution and use in source and binary forms, with or without
;;; modification, are permitted provided that the following conditions
;;; are met:

;;;   * Redistributions of source code must retain the above copyright
;;;     notice, this list of conditions and the following disclaimer.

;;;   * Redistributions in binary form must reproduce the above
;;;     copyright notice, this list of conditions and the following
;;;     disclaimer in the documentation and/or other materials
;;;     provided with the distribution.

;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
;;; ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

;;; ECL-specific definitions

(in-package :rdnzl)

(defvar *dll-path* nil
  "The name of RDNZL.dll.")

(defmacro ffi-register-module (dll-path &optional module-name)
  "Store the DLL name provided by the argument DLL-PATH."
  (declare (ignore module-name))
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (setq *dll-path* ,dll-path)))

(defun ffi-pointer-p (object)
  "Tests whether OBJECT is an FFI pointer."
  (eql (type-of object) 'si::foreign-data))

(defun ffi-null-pointer-p (pointer)
  "Returns whether the FFI pointer POINTER is a null pointer."
  (ffi:null-pointer-p pointer))

(defun ffi-pointer-address (pointer)
  "Returns the address of the FFI pointer POINTER."
  (ffi:pointer-address pointer))

(defun ffi-make-pointer (name)
  "Returns an FFI pointer to the address specified by the name NAME."
  (ffi:callback name))

(defun ffi-map-type (type-name)
  "Maps type names like FFI-INTEGER to their corresponding names in
the ECL FFI."
  (ecase type-name
    (ffi-void :void)
    (ffi-void-pointer :pointer-void)
    (ffi-const-string '(* :unsigned-short))
    (ffi-integer :int)
    (ffi-boolean :byte)
    (ffi-wide-char :unsigned-short)
    (ffi-float :float)
    (ffi-double :double)))
      
(defmacro ffi-define-function* ((lisp-name c-name)
                                arg-list
                                result-type)
  "Defines a Lisp function LISP-NAME which acts as an interface
to the C function C-NAME.  ARG-LIST is a list of \(NAME TYPE)
pairs.  All types are supposed to be symbols mappable by
FFI-MAP-TYPE above."
  (cond ((or (member result-type '(ffi-wide-char ffi-boolean))
             (find 'ffi-wide-char arg-list :key #'second :test #'eq)
             (find 'ffi-boolean arg-list :key #'second :test #'eq))
         ;; define a wrapper if one of the args and/or the return type
         ;; is a __wchar_t because ECL doesn't handle this
         ;; type automatically
         (with-unique-names (internal-name result)
           `(progn
              (ffi:def-function (,c-name ,internal-name)
		,(mapcar (lambda (name-and-type)
			   (destructuring-bind (name type) name-and-type
			     (list name (ffi-map-type type))))
			 arg-list)
		,@(when (ffi-map-type result-type)
		    `(:returning ,(ffi-map-type result-type)))
		:module ,*dll-path*)
              (defun ,lisp-name ,(mapcar #'first arg-list)
                (let ((,result (,internal-name ,@(loop for (name type) in arg-list
                                                       if (eq type 'ffi-wide-char)
                                                         collect `(char-code ,name)
						       else if (eq type 'ffi-boolean)
						         collect `(if ,name 1 0)
                                                       else
                                                         collect name))))
                  ,(cond ((eq result-type 'ffi-wide-char)
			  `(code-char ,result))
			 ((eq result-type 'ffi-boolean)
			  `(if (= ,result 0) nil t))
			 (t result)))))))
        (t
         `(ffi:def-function (,c-name ,lisp-name)
	    ,(mapcar (lambda (name-and-type)
		       (destructuring-bind (name type) name-and-type
			 (list name (ffi-map-type type))))
		     arg-list)
	    ,@(when (ffi-map-type result-type)
		    `(:returning ,(ffi-map-type result-type)))
	    :module ,*dll-path*))))

(defmacro ffi-define-callable ((c-name result-type)
                               arg-list
                               &body body)
  "Defines a Lisp function which can be called from C.
ARG-LIST is a list of \(NAME TYPE) pairs. All types are supposed
to be symbols mappable by FFI-MAP-TYPE above."
  `(ffi:defcallback ,c-name ,(ffi-map-type result-type)
		    ,(mapcar (lambda (name-and-type)
			       (destructuring-bind (name type) name-and-type
				 (list name (ffi-map-type type))))
			     arg-list)
		    , at body))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defmacro with-unicode-string ((var lisp-string) &body body)
    (with-unique-names (str-len k)
      `(let* ((,str-len (length ,lisp-string)))
	 (ffi:with-foreign-object (,var `(:array :unsigned-short ,(1+ ,str-len)))
	   (loop for ,k below ,str-len
		 do (si::foreign-data-set-elt ,var (* 2 ,k) :unsigned-short (char-code (char ,lisp-string ,k))))
	   (si::foreign-data-set-elt ,var (* 2 ,str-len) :unsigned-short 0)
	   , at body)))))

(defun unicode-string-to-lisp (ubyte16-array)
  (let ((char-list (loop for k from 0
			 for uc = (si::foreign-data-ref-elt ubyte16-array (* 2 k) :unsigned-short)
			 while (/= uc 0) collect (code-char uc))))
    (coerce char-list 'string)))

(defmacro ffi-get-call-by-ref-string (function object length-function)
  "Calls the foreign function FUNCTION.  FUNCTION is supposed to call
a C function f with the signature void f\(..., __wchar_t *s) where s
is a result string which is returned by this macro.  OBJECT is the
first argument given to f.  Prior to calling f the length of the
result string s is obtained by evaluating \(LENGTH-FUNCTION OBJECT)."
  (with-rebinding (object)
    (with-unique-names (length temp)
      `(let* ((,length (,length-function ,object)))
	 (ffi:with-foreign-object (,temp `(:array :unsigned-short ,(1+ ,length)))
	   (,function ,object ,temp)
	   (unicode-string-to-lisp ,temp))))))

(defmacro ffi-call-with-foreign-string* (function string &optional other-args)
  "Applies the foreign function FUNCTION to the string STRING and
OTHER-ARGS.  OTHER-ARGS \(a list of CONTAINER structures or `native'
Lisp objects) is converted to a foreign array prior to calling
FUNCTION.  STRING may be NIL which means that this argument is skipped
\(i.e. the macro actually needs a better name)."
  (with-rebinding (other-args)
    (with-unique-names (length arg-pointers ffi-arg-pointers arg i
                        arg-pointer foreign-string)
      (declare (ignorable foreign-string))
      `(let* ((,length (length ,other-args))
              (,arg-pointers (make-array ,length :initial-element nil)))
         (unwind-protect
             (let ((,ffi-arg-pointers
                     (loop for ,arg in ,other-args
                           for ,i from 0
                           for ,arg-pointer = (cond
                                                ((container-p ,arg) (pointer ,arg))
                                                (t (setf (aref ,arg-pointers ,i)
                                                           (box* ,arg))))
                           collect ,arg-pointer)))
               ,(cond (string
                       `(with-unicode-string (,foreign-string ,string)
                          (apply #',function ,foreign-string ,ffi-arg-pointers)))
                      (t
                       `(apply #',function ,ffi-arg-pointers))))
           ;; all .NET elements that were solely created (by BOX*)
           ;; for this FFI call are immediately freed
           (dotimes (,i ,length)
             (named-when (,arg-pointer (aref ,arg-pointers ,i))
               (%free-dot-net-container ,arg-pointer))))))))

(defmacro ffi-call-with-args* (function object name args)
  "Applies the foreign function FUNCTION to OBJECT and ARGS.  ARGS \(a
list of CONTAINER structures or `native' Lisp objects) is converted to
a foreign array prior to calling FUNCTION.  If NAME is not NIL, then
it should be a string and the first argument to FUNCTION will be the
corresponding foreign string."
  (with-rebinding (args)
    (with-unique-names (length arg-pointers ffi-arg-pointers arg i
                        arg-pointer foreign-name)
      `(let* ((,length (length ,args))
              (,arg-pointers (make-array ,length :initial-element nil)))
         (unwind-protect
             (progn
	       (ffi:with-foreign-object (,ffi-arg-pointers `(:array :pointer-void ,,length))
		 (loop for ,arg in ,args
		       for ,i from 0
		       for ,arg-pointer = (cond
					    ((container-p ,arg) (pointer ,arg))
					    (t (setf (aref ,arg-pointers ,i)
						     (box* ,arg))))
		       do (si::foreign-data-set-elt ,ffi-arg-pointers (* 4 ,i) :pointer-void ,arg-pointer))
                 ,(cond (name
                         `(with-unicode-string (,foreign-name ,name)
                            (,function ,foreign-name
                                       ,object
                                       ,length
                                       ,ffi-arg-pointers)))
                        (t `(,function ,object
                                       ,length
                                       ,ffi-arg-pointers)))))
           ;; all .NET elements that were solely created (by BOX*)
           ;; for this FFI call are immediately freed
           (dotimes (,i ,length)
             (named-when (,arg-pointer (aref ,arg-pointers ,i))
               (%free-dot-net-container ,arg-pointer))))))))

(defun flag-for-finalization (object &optional function)
  "Mark OBJECT such that FUNCTION is applied to OBJECT before OBJECT
is removed by GC."  
  ;; don't know how to do that in ECL
  (declare (ignore object function)))

(defun register-exit-function (function &optional name)
  "Makes sure the function FUNCTION \(with no arguments) is called
before the Lisp images exits."
  ;; don't know how to do that in ECL
  (declare (ignore function name)))

(defun full-gc ()
  "Invokes a full garbage collection."
  (si::gc t))

(export 'lf-to-crlf :rdnzl)
(defun lf-to-crlf (string)
  "Add #\Return before each #\Newline in STRING."
  (loop with new-string = (make-array (+ (length string) (count #\Newline string))
                                      :element-type 'character
                                      :fill-pointer 0)
        for c across string
        when (char= c #\Newline)
          do (vector-push-extend #\Return new-string)
        do (vector-push-extend c new-string)
        finally (return new-string)))



More information about the Rdnzl-cvs mailing list