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> 18<br />

Of course, that itself is slightly unwieldy, so you may want to define a function around it<br />

that simply retrieves a URL. I will leave synthesis of all the relevant REPL forms presented<br />

thus far into a single function as an exercise for the reader.<br />

The remaining sections of this tutorial explore some advanced features of <strong>CFFI</strong>; the<br />

definition of new types will receive special attention. Some of these features are essential<br />

for particular foreign function calls; some are very helpful when trying to develop a <strong>Lisp</strong>y<br />

interface to C.<br />

4.11 Defining new types<br />

We’ve occasionally used the defctype macro in previous sections as a kind of documentation,<br />

much what you’d use typedef for in C. We also tried one special kind of type<br />

definition, the defcenum type. See [defcstruct], page 33, for a definition macro that may<br />

come in handy if you need to use C structs as data.<br />

However, all of these are mostly sugar for the powerful underlying foreign type interface<br />

called type translators. You can easily define new translators for any simple named foreign<br />

type. Since we’ve defined the new type curl-code to use as the return type for various<br />

libcurl functions, we can use that to directly convert cURL errors to <strong>Lisp</strong> errors.<br />

defctype’s purpose is to define simple typedef-like aliases. In order to use type translators<br />

we must use the define-foreign-type macro. So let’s redefine curl-code using<br />

it.<br />

(define-foreign-type curl-code-type ()<br />

()<br />

(:actual-type :int)<br />

(:simple-parser curl-code))<br />

define-foreign-type is a thin wrapper around defclass. For now, all you need to<br />

know in the context of this example is that it does what (defctype curl-code :int) would<br />

do and, additionally, defines a new class curl-code-type which we will take advantage of<br />

shortly.<br />

The CURLcode enumeration seems to follow the typical error code convention of ‘0’<br />

meaning all is well, and each non-zero integer indicating a different kind of error. We can<br />

apply that trivially to differentiate between normal exits and error exits.<br />

(define-condition curl-code-error (error)<br />

(($code :initarg :curl-code :reader curl-error-code))<br />

(:report (lambda (c stream)<br />

(format stream "libcurl function returned error ~A"<br />

(curl-error-code c))))<br />

(:documentation "Signalled when a libcurl function answers<br />

a code other than CURLE_OK."))<br />

(defmethod translate-from-foreign (value (type curl-code-type))<br />

"Raise a CURL-CODE-ERROR if VALUE, a curl-code, is non-zero."<br />

(if (zerop value)<br />

:curle-ok<br />

(error ’curl-code-error :curl-code value)))

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

Saved successfully!

Ooh no, something went wrong!