27.11.2014 Views

CFFI User Manual - Common Lisp.net

CFFI User Manual - Common Lisp.net

CFFI User Manual - Common Lisp.net

SHOW MORE
SHOW LESS

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.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!