X-Git-Url: http://git.kpe.io/?a=blobdiff_plain;f=src%2Fstrings.lisp;h=f5b5634e411447429dc1ce37a187324fd03da778;hb=1a33d3d010d00a5864402dfe5acde16cdddce02f;hp=3905004cf02909af262f754d5fda90fc0575481f;hpb=52cbd471d05ae817c0f19aa01e0880233a06f630;p=uffi.git diff --git a/src/strings.lisp b/src/strings.lisp index 3905004..f5b5634 100644 --- a/src/strings.lisp +++ b/src/strings.lisp @@ -1,9 +1,9 @@ -;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: UFFI -*- +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*- ;;;; ************************************************************************* ;;;; FILE IDENTIFICATION ;;;; ;;;; Name: strings.lisp -;;;; Purpose: UFFI source to handle strings, cstring and foreigns +;;;; Purpose: UFFI source to handle strings, cstrings, and foreigns ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Feb 2002 ;;;; @@ -57,7 +57,7 @@ that LW/CMU automatically converts strings from c-calls." ) (defmacro free-cstring (obj) - #+(or cmu sbcl scl lispworks) (declare (ignore obj)) + (declare (ignorable obj)) #+allegro (let ((stored (gensym))) `(let ((,stored ,obj)) @@ -99,102 +99,211 @@ that LW/CMU automatically converts strings from c-calls." ;;; Foreign string functions -(defmacro convert-to-foreign-string (obj) - #+lispworks - (let ((stored (gensym))) - `(let ((,stored ,obj)) - (if (null ,stored) - +null-cstring-pointer+ - (fli:convert-to-foreign-string - ,stored - :external-format '(:latin-1 :eol-style :lf))))) - #+allegro - (let ((stored (gensym))) - `(let ((,stored ,obj)) - (if (null ,stored) - 0 - (values (excl:string-to-native ,stored))))) +(defun %convert-to-foreign-string (str encoding) + (declare (ignorable str encoding)) #+(or cmu scl) - (let ((size (gensym)) - (storage (gensym)) - (stored-obj (gensym)) - (i (gensym))) - `(let ((,stored-obj ,obj)) - (etypecase ,stored-obj - (null - (alien:sap-alien (system:int-sap 0) (* (alien:unsigned 8)))) - (string - (let* ((,size (length ,stored-obj)) - (,storage (alien:make-alien (alien:unsigned 8) (1+ ,size)))) - (setq ,storage (alien:cast ,storage (* (alien:unsigned 8)))) - (locally - (declare (optimize (speed 3) (safety 0))) - (dotimes (,i ,size) - (declare (fixnum ,i)) - (setf (alien:deref ,storage ,i) - (char-code (char ,stored-obj ,i)))) - (setf (alien:deref ,storage ,size) 0)) - ,storage))))) - #+sbcl - (let ((size (gensym)) - (storage (gensym)) - (stored-obj (gensym)) - (i (gensym))) - `(let ((,stored-obj ,obj)) - (etypecase ,stored-obj - (null - (sb-alien:sap-alien (sb-sys:int-sap 0) (* (sb-alien:unsigned 8)))) - (string - (let* ((,size (length ,stored-obj)) - (,storage (sb-alien:make-alien (sb-alien:unsigned 8) (1+ ,size)))) - (setq ,storage (sb-alien:cast ,storage (* (sb-alien:unsigned 8)))) - (locally - (declare (optimize (speed 3) (safety 0))) - (dotimes (,i ,size) - (declare (fixnum ,i)) - (setf (sb-alien:deref ,storage ,i) - (char-code (char ,stored-obj ,i)))) - (setf (sb-alien:deref ,storage ,size) 0)) - ,storage))))) - #+(or openmcl digitool) - (let ((stored-obj (gensym))) - `(let ((,stored-obj ,obj)) - (if (null ,stored-obj) - +null-cstring-pointer+ - (let ((ptr (new-ptr (1+ (length ,stored-obj))))) - (ccl::%put-cstring ptr ,stored-obj) - ptr)))) + (etypecase str + (null + (alien:sap-alien (system:int-sap 0) (* (alien:unsigned 8)))) + (string + (locally + (declare (optimize (speed 3) (safety 0))) + (let* ((size (length str)) + (storage (alien:make-alien (alien:unsigned 8) (1+ size)))) + (declare (fixnum size)) + (setq storage (alien:cast storage (* (alien:unsigned 8)))) + (dotimes (i size) + (declare (fixnum i)) + (setf (alien:deref storage i) + (char-code (char str i)))) + (setf (alien:deref storage size) 0) + storage)))) + + #+(and sbcl (not sb-unicode)) + (etypecase str + (null + (sb-alien:sap-alien (sb-sys:int-sap 0) (* (sb-alien:unsigned 8)))) + (string + (locally + (declare (optimize (speed 3) (safety 0))) + (let* ((size (length str)) + (storage (sb-alien:make-alien (sb-alien:unsigned 8) (1+ size)))) + (declare (fixnum i)) + (setq storage (sb-alien:cast storage (* (sb-alien:unsigned 8)))) + (dotimes (i size) + (declare (fixnum i)) + (setf (sb-alien:deref storage i) + (char-code (char str i)))) + (setf (sb-alien:deref storage size) 0)) + storage))) + + #+(and sbcl sb-unicode) + (etypecase str + (null + (sb-alien:sap-alien (sb-sys:int-sap 0) (* (sb-alien:unsigned 8)))) + (string + (locally + (declare (optimize (speed 3) (safety 0))) + (let* ((fe (or encoding *default-foreign-encoding*)) + (ife (when fe (lookup-foreign-encoding fe)))) + (if ife + (let* ((octets (sb-ext:string-to-octets str :external-format ife)) + (size (length octets)) + (storage (sb-alien:make-alien (sb-alien:unsigned 8) (+ size 2)))) + (declare (fixnum size)) + (setq storage (sb-alien:cast storage (* (sb-alien:unsigned 8)))) + (dotimes (i size) + (declare (fixnum i)) + (setf (sb-alien:deref storage i) (svref octets i))) + ;; terminate with 2 nulls, maybe needed for some encodings + (setf (sb-alien:deref storage size) 0) + (setf (sb-alien:deref storage (1+ size)) 0) + storage) + + (let* ((size (length str)) + (storage (sb-alien:make-alien (sb-alien:unsigned 8) (1+ size)))) + (declare (fixnum size)) + (setq storage (sb-alien:cast storage (* (sb-alien:unsigned 8)))) + (dotimes (i size) + (declare (fixnum i)) + (setf (sb-alien:deref storage i) + (char-code (char str i)))) + (setf (sb-alien:deref storage size) 0) + storage)))))) + + #+(and openmcl openmcl-unicode-strings) + (if (null str) + +null-cstring-pointer+ + (locally + (declare (optimize (speed 3) (safety 0))) + (let* ((fe (or encoding *default-foreign-encoding*)) + (ife (when fe (lookup-foreign-encoding fe)))) + (if ife + (let* ((octets (ccl:encode-string-to-octets str :external-format ife)) + (size (length octets)) + (ptr (new-ptr (+ size 2)))) + (declare (fixnum size)) + (dotimes (i size) + (declare (fixnum i)) + (setf (ccl:%get-unsigned-byte ptr i) (svref octets i))) + (setf (ccl:%get-unsigned-byte ptr size) 0) + (setf (ccl:%get-unsigned-byte ptr (1+ size)) 0) + ptr) + + (let ((ptr (new-ptr (1+ (length str))))) + (ccl::%put-cstring ptr str) + ptr))))) + + #+(or digitool (and openmcl (not openmcl-unicode-strings))) + (if (null str) + +null-cstring-pointer+ + (let ((ptr (new-ptr (1+ (length str))))) + (ccl::%put-cstring ptr str) + ptr)) + + #+(or allegro lispworks) + nil ) +(defmacro convert-to-foreign-string (obj &optional encoding) + (declare (ignorable encoding)) + #+allegro + (let ((stored (gensym "STR-")) + (fe (gensym "FE-")) + (ife (gensym "IFE-"))) + `(let* ((,stored ,obj) + (,fe (or encoding *default-foreign-encoding*)) + (,ife (when ,fe + (lookup-foreign-encoding ,fe)))) + (cond + ((null ,stored) + 0) + ((null ,ife) + (values (excl:string-to-native ,stored))) + (t + (values (excl:string-to-native ,stored :external-format ,ife)))))) + + #+lispworks + (let ((stored (gensym "STR-")) + (fe (gensym "EF-")) + (ife (gensym "NEF-"))) + `(let* ((,stored ,obj) + (,fe (or ,encoding *default-foreign-encoding*)) + (,ife (when ,fe + (lookup-foreign-encoding ,fe)))) + (cond + ((null ,stored) + +null-cstring-pointer+) + ((null ,ife) + (fli:convert-to-foreign-string ,stored)) + (t + (fli:convert-to-foreign-string ,stored :external-format ,ife))))) + + #+(or cmu scl sbcl digitool openmcl) + `(%convert-to-foreign-string ,obj (lookup-foreign-encoding + (or ,encoding *default-foreign-encoding*))) +) + + ;; Either length or null-terminated-p must be non-nil (defmacro convert-from-foreign-string (obj &key - length - (locale :default) - (null-terminated-p t)) + length + encoding + (null-terminated-p t)) + (declare (ignorable length encoding null-terminated-p)) #+allegro - (let ((stored-obj (gensym))) + (let ((stored-obj (gensym "STR-")) + (fe (gensym "FE-")) + (ife (gensym "IFE-"))) `(let ((,stored-obj ,obj)) (if (zerop ,stored-obj) nil - (if (eq ,locale :none) - (fast-native-to-string ,stored-obj ,length) - (values - (excl:native-to-string - ,stored-obj - ,@(when length (list :length length)) - :truncate (not ,null-terminated-p))))))) + (let* ((,fe (or ,encoding *default-foreign-encoding*)) + (,ife (when ,fe (lookup-foreign-encoding ,fe)))) + (if ,ife + (values + (excl:native-to-string + ,stored-obj + ,@(when length (list :length length)) + :truncate (not ,null-terminated-p) + :external-format ,ife)) + (fast-native-to-string ,stored-obj ,length)))))) + #+lispworks - (let ((stored-obj (gensym))) + #| + ;; FAST-NATIVE-TO-STRING (suprisingly) works just fine to make strings + ;; for formatted printing with Lispworks and UTF-8 multibyte character strings. + ;; However, without knowledge of specific-encoding, the LENGTH call in FAST-NATIVE-TO-STRING + ;; will be be incorrect for some encodings/strings and strings consist of octets rather + ;; than wide characters + ;; This is a stop-gap until get tech support on why the below fails. + (let ((stored-obj (gensym "STR-"))) `(let ((,stored-obj ,obj)) (if (fli:null-pointer-p ,stored-obj) nil - (if (eq ,locale :none) - (fast-native-to-string ,stored-obj ,length) - (fli:convert-from-foreign-string - ,stored-obj - ,@(when length (list :length length)) - :null-terminated-p ,null-terminated-p - :external-format '(:latin-1 :eol-style :lf)))))) + (fast-native-to-string ,stored-obj ,length)))) + |# + #| + ;; Below code doesn't work on tesing with LW 6.0 testing with a UTF-8 string. + ;; fli:convert-from-foreign-string with :external-format of :UTF-8 doesn't + ;; properly code multibyte characters. + |# + (let ((stored-obj (gensym "STR-")) + (fe (gensym "FE-")) + (ife (gensym "IFE-"))) + `(let ((,stored-obj ,obj)) + (if (fli:null-pointer-p ,stored-obj) + nil + (let* ((,fe (or ,encoding *default-foreign-encoding*)) + (,ife (when ,fe (lookup-foreign-encoding ,fe)))) + (if ,ife + (fli:convert-from-foreign-string + ,stored-obj + ,@(when length (list :length length)) + :null-terminated-p ,null-terminated-p + :external-format (list ,ife :eol-style :lf)) + (fast-native-to-string ,stored-obj ,length)))))) + #+(or cmu scl) (let ((stored-obj (gensym))) `(let ((,stored-obj ,obj)) @@ -203,32 +312,54 @@ that LW/CMU automatically converts strings from c-calls." (cmucl-naturalize-cstring (alien:alien-sap ,stored-obj) :length ,length :null-terminated-p ,null-terminated-p)))) - - #+sbcl + #+(and sbcl (not sb-unicode)) (let ((stored-obj (gensym))) `(let ((,stored-obj ,obj)) (if (null-pointer-p ,stored-obj) - nil - (sbcl-naturalize-cstring (sb-alien:alien-sap ,stored-obj) - :length ,length - :null-terminated-p ,null-terminated-p)))) - #+(or openmcl digitool) - (declare (ignore null-terminated-p)) + nil + (sbcl-naturalize-cstring (sb-alien:alien-sap ,stored-obj) + :length ,length + :null-terminated-p ,null-terminated-p)))) + + #+(and sbcl sb-unicode) + (let ((stored-obj (gensym "STR-")) + (fe (gensym "FE-")) + (ife (gensym "IFE-"))) + `(let ((,stored-obj ,obj)) + (if (null-pointer-p ,stored-obj) + nil + (let* ((,fe (or ,encoding *default-foreign-encoding*)) + (,ife (when ,fe (lookup-foreign-encoding ,fe)))) + (sb-alien::c-string-to-string (sb-alien:alien-sap ,stored-obj) + (or ,ife sb-impl::*default-external-format* :latin-1) + 'character))))) + #+(or openmcl digitool) - (let ((stored-obj (gensym))) + (let ((stored-obj (gensym "STR-")) + (fe (gensym "FE-"))) `(let ((,stored-obj ,obj)) (if (ccl:%null-ptr-p ,stored-obj) nil - #+digitool (ccl:%get-cstring - ,stored-obj 0 - ,@(if length (list length) nil)) - #+openmcl ,@(if length - `((ccl:%str-from-ptr ,stored-obj ,length)) - `((ccl:%get-cstring ,stored-obj)))))) + #+digitool + (ccl:%get-cstring + ,stored-obj 0 + ,@(if length (list length) nil)) + #+openmcl + (let ((,fe (or ,encoding *default-foreign-encoding*))) + (case ,fe + (:utf-8 + (ccl::%get-utf-8-cstring ,stored-obj)) + (:ucs-2 + (ccl::%get-native-utf-16-cstring ,stored-obj)) + (t + ,@(if length + `((ccl:%str-from-ptr ,stored-obj ,length)) + `((ccl:%get-cstring ,stored-obj))))))))) ) (defmacro allocate-foreign-string (size &key (unsigned t)) + (declare (ignorable unsigned)) #+ignore (let ((array-def (gensym))) `(let ((,array-def (list 'alien:array 'c-call:char ,size))) @@ -256,12 +387,8 @@ that LW/CMU automatically converts strings from c-calls." :char) :nelems ,size) #+allegro - (declare (ignore unsigned)) - #+allegro `(ff:allocate-fobject :char :c ,size) #+(or openmcl digitool) - (declare (ignore unsigned)) - #+(or openmcl digitool) `(new-ptr ,size) ) @@ -274,9 +401,12 @@ that LW/CMU automatically converts strings from c-calls." finally return size)) -(defmacro with-foreign-string ((foreign-string lisp-string) &body body) - (let ((result (gensym))) - `(let* ((,foreign-string (convert-to-foreign-string ,lisp-string)) +(defmacro with-foreign-string ((foreign-string lisp-string &optional encoding) + &body body) + (let ((result (gensym)) + (fe (gensym))) + `(let* ((,fe ,encoding) + (,foreign-string (convert-to-foreign-string ,lisp-string ,fe)) (,result (progn ,@body))) (declare (dynamic-extent ,foreign-string)) (free-foreign-object ,foreign-string) @@ -358,27 +488,6 @@ that LW/CMU automatically converts strings from c-calls." (* length +system-copy-multiplier+)) result))) -#+(and sbcl sb-unicode) -(defun sbcl-naturalize-cstring (sap &key length (null-terminated-p t)) - (declare (type sb-sys:system-area-pointer sap) - (type (or null fixnum) length)) - (locally - (declare (optimize (speed 3) (safety 0))) - (cond - (null-terminated-p - (let ((casted (sb-alien:cast (sb-alien:sap-alien sap (* char)) - #+sb-unicode sb-alien:utf8-string - #-sb-unicode sb-alien:c-string))) - (if length - (copy-seq (subseq casted 0 length)) - (copy-seq casted)))) - (t - (let ((result (make-string length))) - ;; this will not work in sb-unicode - (funcall *system-copy-fn* sap 0 result +system-copy-offset+ - (* length +system-copy-multiplier+)) - result))))) - (eval-when (:compile-toplevel :load-toplevel :execute) (def-function "strlen" @@ -406,5 +515,5 @@ that LW/CMU automatically converts strings from c-calls." (type char-ptr-def s)) (let* ((len (or len (strlen s))) (str (make-string len))) - (dotimes (i len str) - (setf (schar str i) (code-char (uffi:deref-array s '(:array :unsigned-byte) i)))))) + (dotimes (i len str) + (setf (schar str i) (code-char (uffi:deref-array s '(:array :unsigned-byte) i))))))