manual: add Clasp to "Implementation Support"
[cffi.git] / tests / funcall.lisp
blobbdb15d36d8110be70647c14efed84ba66076e07b
1 ;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
2 ;;;
3 ;;; funcall.lisp --- Tests function calling.
4 ;;;
5 ;;; Copyright (C) 2005-2006, James Bielman <jamesjb@jamesjb.com>
6 ;;; Copyright (C) 2005-2007, Luis Oliveira <loliveira@common-lisp.net>
7 ;;;
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:
15 ;;;
16 ;;; The above copyright notice and this permission notice shall be
17 ;;; included in all copies or substantial portions of the Software.
18 ;;;
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.
27 ;;;
29 (in-package #:cffi-tests)
31 ;;;# Calling with Built-In C Types
32 ;;;
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
37 ;;; foreign-funcall.
38 #-cffi-sys::no-foreign-funcall
39 (progn
41 (deftest funcall.char
42 (foreign-funcall "toupper" :char (char-code #\a) :char)
43 #.(char-code #\A))
45 (deftest funcall.int.1
46 (foreign-funcall "abs" :int -100 :int)
47 100)
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
55 (funcall-abs -42)
56 42)
58 (deftest funcall.long
59 (foreign-funcall "labs" :long -131072 :long)
60 131072)
62 #-cffi-sys::no-long-long
63 (deftest funcall.long-long
64 (foreign-funcall "my_llabs" :long-long -9223372036854775807 :long-long)
65 9223372036854775807)
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))))))
70 (eql ullong-max
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)
77 4.0)
79 (deftest funcall.double
80 (foreign-funcall "sqrt" :double 36.0d0 :double)
81 6.0d0)
83 #+(and scl long-float)
84 (deftest funcall.long-double
85 (foreign-funcall "sqrtl" :long-double 36.0l0 :long-double)
86 6.0l0)
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))
97 "Hello, world!")
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))
103 "Hello, world!")
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))
113 "A")
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))
119 "1000")
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))
125 "131072")
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))
135 "3.14")
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))
143 "3.14")
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))
150 "Hello, world!")
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)
164 81.64d0)
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
174 :float 5.0 :float)
175 130.0)
177 ;;; Funcalling a pointer.
178 (deftest funcall.f-s-p.1
179 (foreign-funcall-pointer (foreign-symbol-pointer "abs") nil :int -42 :int)
182 ;;;# Namespaces
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))
188 t nil)
190 ;;;# stdcall
192 #+(and x86 windows (not cffi-sys::no-stdcall))
193 (deftest funcall.stdcall.1
194 (flet ((fun ()
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)
213 (null-pointer))
215 (deftest funcall.nil-skip
216 (let ((*nil-skipped* t))
217 (compile nil '(lambda ()
218 (foreign-funcall "abs" check-nil-skip-type nil)))
219 *nil-skipped*)
220 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