1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
3 ;;; funcall.lisp --- Tests function calling.
5 ;;; Copyright (C) 2005-2006, James Bielman <jamesjb@jamesjb.com>
6 ;;; Copyright (C) 2005-2007, Luis Oliveira <loliveira@common-lisp.net>
8 ;;; Permission is hereby granted, free of charge, to any person
9 ;;; obtaining a copy of this software and associated documentation
10 ;;; files (the "Software"), to deal in the Software without
11 ;;; restriction, including without limitation the rights to use, copy,
12 ;;; modify, merge, publish, distribute, sublicense, and/or sell copies
13 ;;; of the Software, and to permit persons to whom the Software is
14 ;;; furnished to do so, subject to the following conditions:
16 ;;; The above copyright notice and this permission notice shall be
17 ;;; included in all copies or substantial portions of the Software.
19 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 ;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 ;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 ;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 ;;; DEALINGS IN THE SOFTWARE.
29 (in-package #:cffi-tests
)
31 ;;;# Calling with Built-In C Types
33 ;;; Tests calling standard C library functions both passing and
34 ;;; returning each built-in type.
36 ;;; Don't run these tests if the implementation does not support
38 #-cffi-sys
::no-foreign-funcall
42 (foreign-funcall "toupper" :char
(char-code #\a) :char
)
45 (deftest funcall.int
.1
46 (foreign-funcall "abs" :int -
100 :int
)
49 (defun funcall-abs (n)
50 (foreign-funcall "abs" :int n
:int
))
52 ;;; regression test: lispworks's %foreign-funcall based on creating
53 ;;; and caching foreign-funcallables at macro-expansion time.
54 (deftest funcall.int
.2
59 (foreign-funcall "labs" :long -
131072 :long
)
62 #-cffi-sys
::no-long-long
63 (deftest funcall.long-long
64 (foreign-funcall "my_llabs" :long-long -
9223372036854775807 :long-long
)
67 #-cffi-sys
::no-long-long
68 (deftest funcall.unsigned-long-long
69 (let ((ullong-max (1- (expt 2 (* 8 (foreign-type-size :unsigned-long-long
))))))
71 (foreign-funcall "ullong" :unsigned-long-long ullong-max
72 :unsigned-long-long
)))
75 (deftest funcall.float
76 (foreign-funcall "my_sqrtf" :float
16.0 :float
)
79 (deftest funcall.double
80 (foreign-funcall "sqrt" :double
36.0d0
:double
)
83 #+(and scl long-float
)
84 (deftest funcall.long-double
85 (foreign-funcall "sqrtl" :long-double
36.0l0 :long-double
)
88 (deftest funcall.string
.1
89 (foreign-funcall "strlen" :string
"Hello" :int
)
92 (deftest funcall.string
.2
93 (with-foreign-pointer-as-string (s 100)
94 (setf (mem-ref s
:char
) 0)
95 (foreign-funcall "strcpy" :pointer s
:string
"Hello" :pointer
)
96 (foreign-funcall "strcat" :pointer s
:string
", world!" :pointer
))
99 (deftest funcall.string
.3
100 (with-foreign-pointer (ptr 100)
101 (lisp-string-to-foreign "Hello, " ptr
8)
102 (foreign-funcall "strcat" :pointer ptr
:string
"world!" :string
))
105 ;;;# Calling Varargs Functions
107 ;; The CHAR argument must be passed as :INT because chars are promoted
108 ;; to ints when passed as variable arguments.
109 (deftest funcall.varargs.char
110 (with-foreign-pointer-as-string (s 100)
111 (setf (mem-ref s
:char
) 0)
112 (foreign-funcall "sprintf" :pointer s
:string
"%c" :int
65 :int
))
115 (deftest funcall.varargs.int
116 (with-foreign-pointer-as-string (s 100)
117 (setf (mem-ref s
:char
) 0)
118 (foreign-funcall "sprintf" :pointer s
:string
"%d" :int
1000 :int
))
121 (deftest funcall.varargs.long
122 (with-foreign-pointer-as-string (s 100)
123 (setf (mem-ref s
:char
) 0)
124 (foreign-funcall "sprintf" :pointer s
:string
"%ld" :long
131072 :int
))
127 ;;; There is no FUNCALL.VARARGS.FLOAT as floats are promoted to double
128 ;;; when passed as variable arguments. Currently this fails in SBCL
129 ;;; and CMU CL on Darwin/ppc.
130 (deftest funcall.varargs.double
131 (with-foreign-pointer-as-string (s 100)
132 (setf (mem-ref s
:char
) 0)
133 (foreign-funcall "sprintf" :pointer s
:string
"%.2f"
134 :double
(coerce pi
'double-float
) :int
))
137 #+(and scl long-float
)
138 (deftest funcall.varargs.long-double
139 (with-foreign-pointer-as-string (s 100)
140 (setf (mem-ref s
:char
) 0)
141 (foreign-funcall "sprintf" :pointer s
:string
"%.2Lf"
142 :long-double pi
:int
))
145 (deftest funcall.varargs.string
146 (with-foreign-pointer-as-string (s 100)
147 (setf (mem-ref s
:char
) 0)
148 (foreign-funcall "sprintf" :pointer s
:string
"%s, %s!"
149 :string
"Hello" :string
"world" :int
))
152 ;;; See DEFCFUN.DOUBLE26.
153 (deftest funcall.double26
154 (foreign-funcall "sum_double26"
155 :double
3.14d0
:double
3.14d0
:double
3.14d0
156 :double
3.14d0
:double
3.14d0
:double
3.14d0
157 :double
3.14d0
:double
3.14d0
:double
3.14d0
158 :double
3.14d0
:double
3.14d0
:double
3.14d0
159 :double
3.14d0
:double
3.14d0
:double
3.14d0
160 :double
3.14d0
:double
3.14d0
:double
3.14d0
161 :double
3.14d0
:double
3.14d0
:double
3.14d0
162 :double
3.14d0
:double
3.14d0
:double
3.14d0
163 :double
3.14d0
:double
3.14d0
:double
)
166 ;;; See DEFCFUN.FLOAT26.
167 (deftest funcall.float26
168 (foreign-funcall "sum_float26"
169 :float
5.0 :float
5.0 :float
5.0 :float
5.0 :float
5.0
170 :float
5.0 :float
5.0 :float
5.0 :float
5.0 :float
5.0
171 :float
5.0 :float
5.0 :float
5.0 :float
5.0 :float
5.0
172 :float
5.0 :float
5.0 :float
5.0 :float
5.0 :float
5.0
173 :float
5.0 :float
5.0 :float
5.0 :float
5.0 :float
5.0
177 ;;; Funcalling a pointer.
178 (deftest funcall.f-s-p
.1
179 (foreign-funcall-pointer (foreign-symbol-pointer "abs") nil
:int -
42 :int
)
184 #-cffi-sys
::flat-namespace
185 (deftest funcall.namespace
.1
186 (values (foreign-funcall ("ns_function" :library libtest
) :boolean
)
187 (foreign-funcall ("ns_function" :library libtest2
) :boolean
))
192 #+(and x86 windows
(not cffi-sys
::no-stdcall
))
193 (deftest funcall.stdcall
.1
195 (foreign-funcall ("stdcall_fun@12" :convention
:stdcall
)
196 :int
1 :int
2 :int
3 :int
)))
197 (loop repeat
100 do
(fun)
198 finally
(return (fun))))
201 ;;; RT: NIL arguments are skipped
203 (defvar *nil-skipped
*)
205 (define-foreign-type check-nil-skip-type
()
207 (:actual-type
:pointer
)
208 (:simple-parser check-nil-skip-type
))
210 (defmethod expand-to-foreign (val (type check-nil-skip-type
))
211 (declare (ignore val
))
212 (setf *nil-skipped
* nil
)
215 (deftest funcall.nil-skip
216 (let ((*nil-skipped
* t
))
217 (compile nil
'(lambda ()
218 (foreign-funcall "abs" check-nil-skip-type nil
)))
222 ;;; RT: CLISP returns NIL instead of a null-pointer
224 (deftest funcall.pointer-not-nil
225 (not (null (foreign-funcall "strchr" :string
"" :int
1 :pointer
)))
228 ) ;; #-cffi-sys::no-foreign-funcall