Lisp HUG Maillist Archive

FLI question

Before I go through the effort of going down a particular path with a C library, I was wondering if the following was possible. I'd basically like a FLI function to return multiple values based on an error return values from C (an integer), where 0 = no error and anything else is an error. If I can't then I'll just end up working the C library so that there's a get_last_error() function to return the error code and grab it as needed. I'm just at the design phase and if someone know the answer to this off the top of their head, then it'd just save me time trying it out. ;-)

;;;; -*- code -*-

(defun error-values (err) 
  "Returns 2 values: T/NIL for err==0 and the error code if NIL"
  (if (zerop err) t (values nil err)))

(fli:define-c-typedef error-result (:wrapper :int :foreign-to-lisp error-values))

(fli:define-foreign-function (…)
    ()
  :result-type error-result)


Thanks!
Jeff M.

Re: FLI question

Jeffrey Massung <massung@gmail.com> writes:

> Before I go through the effort of going down a particular path with a
> C library, I was wondering if the following was possible. I'd
> basically like a FLI function to return multiple values based on an
> error return values from C (an integer), where 0 = no error and
> anything else is an error.

I've done something slightly similar, only I wanted to raise lisp
errors on error returns, and I in some cases needed more than one
success-return.  And this was for interfacing with a C library I had no
control over.

I solved it on a layer above the FLI.  I treat the FLI bindings as
strictly private and unexported from my lisp library, and have my lisp
library present the interface I want to the rest of my lisp world.

To fit your purposes, you probably only have to change the (error ...)
call to (values (eq status :success) status) in the code below.

;;; -*- code -*-

;; Helpers

(defun call-foreign-api (normal-returns function &rest args)
  "Calls a function in the foreign API and decodes the return value.
Primary return value is a keyword, :SUCCESS or one of NORMAL-RETURNS.
If the API call returns another status, an error is raised.  Using a
symbol instead of a function object as FUNCTION makes the error message
nicer."
  (multiple-value-call #'(lambda (status &rest values)
			   (setq status (car (rassoc status *foreign-api-return-values*)))
			   (if (or (eq status :succ)
				   (member status normal-returns :test #'eq))
			       (apply #'values status values)
			       (error "~s: ~a" function status)))
    (apply #'funcall function args)))

(defun call-foreign-api-with-error (function &rest args)
  "Calls a function in the foreign API and decodes the return values.
Primary return value: :SUCCESS or an error."
  (apply #'call-foreign-api nil function args))

(defparameter *foreign-api-return-values*
  '((:success . 0)
    (:information-code-1 . 1)
    (:information-code-2 . 2)
    (:error-code-1 . -1)
    (:error-code-2 . -2)))

;; Exported interface

(defun simple-api-call (in)
  (call-foreign-api-with-error '%simple-api-call in)) ;; %simple-api-call is the FFI binding

(defun complex-api-call (in)
  (call-foreign-api '(:information-code-1 :information-code-2)
		    '%complex-api-call in)) ;; %complex-api-call is likewise an FFI binding

-- 
Mvh/Regards
Peder O. Klingenberg
Netfonds Bank AS


Re: FLI question

>>>>> On Tue, 11 Oct 2011 11:32:40 -0600, Jeffrey Massung said:
> 
> Before I go through the effort of going down a particular path with a C
> library, I was wondering if the following was possible. I'd basically like a
> FLI function to return multiple values based on an error return values from
> C (an integer), where 0 = no error and anything else is an error. If I can't
> then I'll just end up working the C library so that there's a
> get_last_error() function to return the error code and grab it as
> needed. I'm just at the design phase and if someone know the answer to this
> off the top of their head, then it'd just save me time trying it out. ;-)
> 
> ;;;; -*- code -*-
> 
> (defun error-values (err) 
>   "Returns 2 values: T/NIL for err==0 and the error code if NIL"
>   (if (zerop err) t (values nil err)))
> 
> (fli:define-c-typedef error-result (:wrapper :int :foreign-to-lisp error-values))
> 
> (fli:define-foreign-function (…)
>     ()
>   :result-type error-result)

This appears to work for fli:define-foreign-function, but we don't support it.
Please do it with a wrapper like Peder suggested.

-- 
Martin Simmons
LispWorks Ltd
http://www.lispworks.com/


Updated at: 2020-12-10 08:37 UTC