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)))