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

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

cluttered than the equivalent disjoint-function set would be; in addition, setting a new option<br />

in an old libcurl can generate a run-time error rather than breaking the compile. <strong>Lisp</strong> can<br />

just as concisely generate functions as compare values, and the “undefined function” error<br />

is just as useful as any explicit error we could define here might be.<br />

4.7 Option functions in <strong>Lisp</strong><br />

We could use foreign-funcall directly every time we wanted to call curl_easy_setopt.<br />

However, we can encapsulate some of the necessary information with the following.<br />

;;; We will use this type later in a more creative way. For<br />

;;; now, just consider it a marker that this isn’t just any<br />

;;; pointer.<br />

(defctype easy-handle :pointer)<br />

(defmacro curl-easy-setopt (easy-handle enumerated-name<br />

value-type new-value)<br />

"Call ‘curl_easy_setopt’ on EASY-HANDLE, using ENUMERATED-NAME<br />

as the OPTION. VALUE-TYPE is the <strong>CFFI</strong> foreign type of the third<br />

argument, and NEW-VALUE is the <strong>Lisp</strong> data to be translated to the<br />

third argument. VALUE-TYPE is not evaluated."<br />

‘(foreign-funcall "curl_easy_setopt" easy-handle ,easy-handle<br />

curl-option ,enumerated-name<br />

,value-type ,new-value curl-code))<br />

Now we define a function for each kind of argument that encodes the correct value-type<br />

in the above. This can be done reasonably in the define-curl-options macroexpansion;<br />

after all, that is where the different options are listed!<br />

We could make cl:defun forms in the expansion that simply call curl-easy-setopt;<br />

however, it is probably easier and clearer to use defcfun. define-curl-options was<br />

becoming unwieldy, so I defined some helpers in this new definition.<br />

(defun curry-curl-option-setter (function-name option-keyword)<br />

"Wrap the function named by FUNCTION-NAME with a version that<br />

curries the second argument as OPTION-KEYWORD.<br />

This function is intended for use in DEFINE-CURL-OPTION-SETTER."<br />

(setf (symbol-function function-name)<br />

(let ((c-function (symbol-function function-name)))<br />

(lambda (easy-handle new-value)<br />

(funcall c-function easy-handle option-keyword<br />

new-value)))))<br />

(defmacro define-curl-option-setter (name option-type<br />

option-value foreign-type)<br />

"Define (with DEFCFUN) a function NAME that calls<br />

curl_easy_setopt. OPTION-TYPE and OPTION-VALUE are the <strong>CFFI</strong><br />

foreign type and value to be passed as the second argument to<br />

easy_setopt, and FOREIGN-TYPE is the <strong>CFFI</strong> foreign type to be used<br />

for the resultant function’s third argument.<br />

This macro is intended for use in DEFINE-CURL-OPTIONS."<br />

‘(progn<br />

(defcfun ("curl_easy_setopt" ,name) curl-code

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

Saved successfully!

Ooh no, something went wrong!