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