Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Chapter 4: An Introduction to Foreign Interfaces and <strong>CFFI</strong> 8<br />
TYPE-OFFSETS is a plist of TYPEs to their integer offsets, as<br />
defined by the CURLOPTTYPE_LONG et al constants in curl.h."<br />
(flet ((enumerated-value (type offset)<br />
(+ (getf type-offsets type) offset)))<br />
‘(progn<br />
(defcenum ,name<br />
,@(loop for (name type number) in enum-args<br />
collect (list name (enumerated-value type number))))<br />
’,name)))<br />
;for REPL users’ sanity<br />
(define-curl-options curl-option<br />
(long 0 objectpoint 10000 functionpoint 20000 off-t 30000)<br />
(:noprogress long 43)<br />
(:nosignal long 99)<br />
(:errorbuffer objectpoint 10)<br />
(:url objectpoint 2))<br />
With some well-placed Emacs query-replace-regexps, you could probably similarly<br />
define the entire CURLoption enumeration. I have selected to transcribe a few that we will<br />
use in this tutorial.<br />
If you’re having trouble following the macrology, just macroexpand the curl-option<br />
definition, or see the following macroexpansion, conveniently downcased and reformatted:<br />
(progn<br />
(defcenum curl-option<br />
(:noprogress 43)<br />
(:nosignal 99)<br />
(:errorbuffer 10010)<br />
(:url 10002))<br />
’curl-option)<br />
That seems more than reasonable. You may notice that we only use the type to compute<br />
the real enumeration offset; we will also need the type information later.<br />
First, however, let’s make sure a simple call to the foreign function works:<br />
cffi-user> (foreign-funcall "curl_easy_setopt"<br />
:pointer *easy-handle*<br />
curl-option :nosignal :long 1 curl-code)<br />
⇒ 0<br />
foreign-funcall, despite its surface simplicity, can be used to call any C function. Its<br />
first argument is a string, naming the function to be called. Next, for each argument, we<br />
pass the name of the C type, which is the same as in defcfun, followed by a <strong>Lisp</strong> object<br />
representing the data to be passed as the argument. The final argument is the return type,<br />
for which we use the curl-code type defined earlier.<br />
defcfun just puts a convenient façade on foreign-funcall. 4 Our earlier call to curlglobal-init<br />
could have been written as follows:<br />
4 This isn’t entirely true; some <strong>Lisp</strong>s don’t support foreign-funcall, so defcfun is implemented without<br />
it. defcfun may also perform optimizations that foreign-funcall cannot.