You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Chapter 4: An Introduction to Foreign Interfaces and <strong>CFFI</strong> 12<br />
(define-curl-option-setter set-curl-option-errorbuffer<br />
curl-option :errorbuffer :pointer)<br />
(define-curl-option-setter set-curl-option-url<br />
curl-option :url :pointer)<br />
’curl-option)<br />
Macroexpanding one of the new define-curl-option-setter forms yields the following:<br />
(progn<br />
(defcfun ("curl_easy_setopt" set-curl-option-nosignal) curl-code<br />
(easy-handle easy-handle)<br />
(option curl-option)<br />
(new-value :long))<br />
(curry-curl-option-setter ’set-curl-option-nosignal ’:nosignal))<br />
Finally, let’s try this out:<br />
cffi-user> (set-curl-option-nosignal *easy-handle* 1)<br />
⇒ 0<br />
Looks like it works just as well. This interface is now reasonably high-level to wash out<br />
some of the ugliness of the thinnest possible curl_easy_setopt FFI, without obscuring the<br />
remaining C bookkeeping details we will explore.<br />
4.8 Memory management<br />
According to the documentation for curl_easy_setopt, the type of the third argument<br />
when option is CURLOPT_ERRORBUFFER is char*. Above, we’ve defined set-curl-optionerrorbuffer<br />
to accept a :pointer as the new option value. However, there is a <strong>CFFI</strong> type<br />
:string, which translates <strong>Lisp</strong> strings to C strings when passed as arguments to foreign<br />
function calls. Why not, then, use :string as the <strong>CFFI</strong> type of the third argument? There<br />
are two reasons, both related to the necessity of breaking abstraction described in Section 4.6<br />
[Breaking the abstraction], page 9.<br />
The first reason also applies to CURLOPT_URL, which we will use to illustrate the point.<br />
Assuming we have changed the type of the third argument underlying set-curl-optionurl<br />
to :string, look at these two equivalent forms.<br />
(set-curl-option-url *easy-handle* "http://www.cliki.<strong>net</strong>/<strong>CFFI</strong>")<br />
≡ (with-foreign-string (url "http://www.cliki.<strong>net</strong>/<strong>CFFI</strong>")<br />
(foreign-funcall "curl_easy_setopt" easy-handle *easy-handle*<br />
curl-option :url :pointer url curl-code))<br />
The latter, in fact, is mostly equivalent to what a foreign function call’s macroexpansion<br />
actually does. As you can see, the <strong>Lisp</strong> string "http://www.cliki.<strong>net</strong>/<strong>CFFI</strong>" is copied<br />
into a char array and null-terminated; the pointer to beginning of this array, now a C<br />
string, is passed as a <strong>CFFI</strong> :pointer to the foreign function.<br />
Unfortunately, the C abstraction has failed us, and we must break it. While :string<br />
works well for many char* arguments, it does not for cases like this. As the curl_easy_<br />
setopt documentation explains, “The string must remain present until curl no longer needs<br />
it, as it doesn’t copy the string.” The C string created by with-foreign-string, however,<br />
only has dynamic extent: it is “deallocated” when the body (above containing the foreignfuncall<br />
form) exits.