r2997: *** empty log message ***
[uffi.git] / src / strings.lisp
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: UFFI -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          strings.cl
6 ;;;; Purpose:       UFFI source to handle strings, cstring and foreigns
7 ;;;; Programmer:    Kevin M. Rosenberg
8 ;;;; Date Started:  Feb 2002
9 ;;;;
10 ;;;; $Id: strings.lisp,v 1.2 2002/10/14 01:51:15 kevin Exp $
11 ;;;;
12 ;;;; This file, part of UFFI, is Copyright (c) 2002 by Kevin M. Rosenberg
13 ;;;;
14 ;;;; UFFI users are granted the rights to distribute and use this software
15 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
16 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
17 ;;;; *************************************************************************
18
19 (declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
20 (in-package :uffi)
21
22
23 (defvar +null-cstring-pointer+
24     #+cmu nil
25     #+sbcl nil
26     #+allegro 0
27     #+lispworks (fli:make-pointer :address 0 :type '(:unsigned :char))
28     #+mcl (ccl:%null-ptr)
29     #-(or cmu allegro lispworks mcl) nil
30 )
31
32 (defmacro convert-from-cstring (obj)
33   "Converts a string from a c-call. Same as convert-from-foreign-string, except
34 that LW/CMU automatically converts strings from c-calls."
35   #+cmu obj
36   #+sbcl obj
37   #+lispworks obj
38   #+allegro 
39   (let ((stored (gensym)))
40     `(let ((,stored ,obj))
41        (if (zerop ,stored)
42            nil
43          (values (excl:native-to-string ,stored)))))
44   #+mcl 
45   (let ((stored (gensym)))
46     `(let ((,stored ,obj))
47        (if (ccl:%null-ptr-p ,stored)
48            nil
49          (values (ccl:%get-cstring ,stored)))))
50   )
51
52 (defmacro convert-to-cstring (obj)
53   #+cmu obj
54   #+sbcl obj
55   #+lispworks obj
56   #+allegro
57   `(if (null ,obj)
58     0
59     (values (excl:string-to-native ,obj)))
60   #+mcl
61   `(if (null ,obj)
62     +null-cstring-pointer+
63     (let ((ptr (new-ptr (1+ (length ,obj)))))
64       (ccl:%put-cstring ptr ,obj)
65       ptr))
66   )
67
68 (defmacro free-cstring (obj)
69   #+(or cmu sbcl lispworks) (declare (ignore obj))
70   #+allegro
71   `(unless (zerop obj)
72      (ff:free-fobject ,obj))
73   #+mcl
74   `(unless (ccl:%null-ptr-p ,obj)
75      (dispose-ptr ,obj))
76   )
77
78 (defmacro with-cstring ((cstring lisp-string) &body body)
79   #+(or cmu sbcl lispworks)
80   `(let ((,cstring ,lisp-string)) ,@body) 
81   #+allegro
82   (let ((acl-native (gensym)))
83     `(excl:with-native-string (,acl-native ,lisp-string)
84        (let ((,cstring (if ,lisp-string ,acl-native 0)))
85          ,@body)))
86   #+mcl
87   `(if (stringp ,lisp-string)
88      (ccl:with-cstrs ((,cstring ,lisp-string))
89        ,@body)
90      (let ((,cstring +null-cstring-pointer+))
91        ,@body))
92   )
93
94 (defmacro with-cstrings (bindings &rest body)
95   (if bindings
96       `(with-cstring ,(car bindings)
97         (with-cstrings ,(cdr bindings)
98           ,@body))
99       `(progn ,@body)))
100
101 ;;; Foreign string functions
102
103 (defmacro convert-to-foreign-string (obj)
104   #+lispworks
105   `(if (null ,obj)
106        +null-cstring-pointer+
107     (fli:convert-to-foreign-string ,obj))
108   #+allegro
109   `(if (null ,obj)
110        0
111      (values (excl:string-to-native ,obj)))
112   #+cmu
113   (let ((size (gensym))
114         (storage (gensym))
115         (i (gensym)))
116     `(etypecase ,obj
117       (null 
118        (alien:sap-alien (system:int-sap 0) (* (alien:unsigned 8))))
119       (string
120        (let* ((,size (length ,obj))
121               (,storage (alien:make-alien (alien:unsigned 8) (1+ ,size))))
122          (setq ,storage (alien:cast ,storage (* (alien:unsigned 8))))
123          (locally
124              (declare (optimize (speed 3) (safety 0)))
125            (dotimes (,i ,size)
126              (declare (fixnum ,i))
127              (setf (alien:deref ,storage ,i) (char-code (char ,obj ,i))))
128            (setf (alien:deref ,storage ,size) 0))
129          ,storage))))
130   #+sbcl
131   (let ((size (gensym))
132         (storage (gensym))
133         (i (gensym)))
134     `(etypecase ,obj
135       (null 
136        (sb-alien:sap-alien (sb-sys:int-sap 0) (* (sb-alien:unsigned 8))))
137       (string
138        (let* ((,size (length ,obj))
139               (,storage (sb-alien:make-alien (sb-alien:unsigned 8) (1+ ,size))))
140          (setq ,storage (sb-alien:cast ,storage (* (sb-alien:unsigned 8))))
141          (locally
142              (declare (optimize (speed 3) (safety 0)))
143            (dotimes (,i ,size)
144              (declare (fixnum ,i))
145              (setf (sb-alien:deref ,storage ,i) (char-code (char ,obj ,i))))
146            (setf (sb-alien:deref ,storage ,size) 0))
147          ,storage))))
148   #+mcl
149   `(if (null ,obj)
150        +null-cstring-pointer+
151      (let ((ptr (new-ptr (1+ (length ,obj)))))
152        (ccl:%put-cstring ptr ,obj)
153        ptr))
154   )
155
156
157 ;; Either length or null-terminated-p must be non-nil
158 (defmacro convert-from-foreign-string (obj &key
159                                            length
160                                            (null-terminated-p t))
161   #+allegro
162   `(if (zerop ,obj)
163        nil
164      (values (excl:native-to-string
165               ,obj 
166               ,@(if length (list :length length) (values))
167               :truncate (not ,null-terminated-p))))
168   #+lispworks
169   `(if (fli:null-pointer-p ,obj)
170        nil
171      (fli:convert-from-foreign-string 
172       ,obj
173       ,@(if length (list :length length) (values))
174       :null-terminated-p ,null-terminated-p
175       :external-format '(:latin-1 :eol-style :lf)))      
176   #+cmu
177   `(if (null-pointer-p ,obj)
178     nil
179     (cmucl-naturalize-cstring (alien:alien-sap ,obj)
180      :length ,length
181      :null-terminated-p ,null-terminated-p))
182   #+sbcl
183   `(if (null-pointer-p ,obj)
184     nil
185     (sbcl-naturalize-cstring (sb-alien:alien-sap ,obj)
186      :length ,length
187      :null-terminated-p ,null-terminated-p))
188   #+mcl
189   (declare (ignore null-terminated-p))
190   #+mcl
191   `(if (ccl:%null-ptr-p ,obj)
192      nil
193      (ccl:%get-cstring ,obj 0 ,@(if length (list length) nil)))
194   )
195
196
197
198 (defmacro allocate-foreign-string (size &key (unsigned t))
199   #+cmu
200   (let ((array-def (gensym)))
201     `(let ((,array-def (list 'alien:array 'c-call:char ,size)))
202        (eval `(alien:cast (alien:make-alien ,,array-def) 
203                           ,(if ,unsigned 
204                                '(* (alien:unsigned 8))
205                              '(* (alien:signed 8)))))))
206   #+sbcl
207   (let ((array-def (gensym)))
208     `(let ((,array-def (list 'sb-alien:array 'char ,size)))
209        (eval `(alien:cast (sb-alien:make-alien ,,array-def) 
210                           ,(if ,unsigned 
211                                '(* (sb-alien:unsigned 8))
212                              '(* (sb-alien:signed 8)))))))
213   #+lispworks
214   `(fli:allocate-foreign-object :type 
215                                 ,(if unsigned 
216                                      ''(:unsigned :char) 
217                                    :char)
218                                 :nelems ,size)
219   #+allegro
220   (declare (ignore unsigned))
221   #+allegro
222   `(ff:allocate-fobject :char :c ,size)
223   #+mcl
224   (declare (ignore unsigned))
225   #+mcl
226   `(new-ptr ,size)
227   )
228
229 (defmacro with-foreign-string ((foreign-string lisp-string) &body body)
230   (let ((result (gensym)))
231     `(let* ((,foreign-string (convert-to-foreign-string ,lisp-string))
232             (,result (progn ,@body)))
233       (declare (dynamic-extent ,foreign-string))
234       (free-foreign-object ,foreign-string)
235       ,result)))
236
237
238 ;; Modified from CMUCL's source to handle non-null terminated strings
239 #+cmu
240 (defun cmucl-naturalize-cstring (sap &key 
241                                            length
242                                            (null-terminated-p t))
243   (declare (type system:system-area-pointer sap))
244   (locally
245       (declare (optimize (speed 3) (safety 0)))
246     (let ((null-terminated-length
247            (when null-terminated-p
248              (loop
249                  for offset of-type fixnum upfrom 0
250                  until (zerop (system:sap-ref-8 sap offset))
251                  finally (return offset)))))
252       (if length
253           (if (and null-terminated-length
254                    (> (the fixnum length) (the fixnum null-terminated-length)))
255               (setq length null-terminated-length))
256         (setq length null-terminated-length)))
257     (let ((result (make-string length)))
258       (kernel:copy-from-system-area sap 0
259                                     result (* vm:vector-data-offset
260                                               vm:word-bits)
261                                     (* length vm:byte-bits))
262       result)))
263
264 #+sbcl
265 (defun sbcl-naturalize-cstring (sap &key 
266                                            length
267                                            (null-terminated-p t))
268   (declare (type sb-sys:system-area-pointer sap))
269   (locally
270       (declare (optimize (speed 3) (safety 0)))
271     (let ((null-terminated-length
272            (when null-terminated-p
273              (loop
274                  for offset of-type fixnum upfrom 0
275                  until (zerop (system:sap-ref-8 sap offset))
276                  finally (return offset)))))
277       (if length
278           (if (and null-terminated-length
279                    (> (the fixnum length) (the fixnum null-terminated-length)))
280               (setq length null-terminated-length))
281         (setq length null-terminated-length)))
282     (let ((result (make-string length)))
283       (sb-kernel:copy-from-system-area sap 0
284                                     result (* sb-vm:vector-data-offset
285                                               sb-vm:word-bits)
286                                     (* length sb-vm:byte-bits))
287       result)))