[cffi-devel] Help needed: Tcl/Tk via CFFI (OSX 10.4.6 Intel, AllegroCL)

James Bielman jamesjb at jamesjb.com
Wed Apr 26 07:35:23 UTC 2006


Frank Goenninger <fgoenninger at prion.de> writes:

> Thanks for looking into this ...
> I want to call the functions Tcl_CreateInterp and Tcl_Eval from Lisp.
> So I defined the libs and the functions :

[ snippage ]

>      ;; Tcl_EvalFile
>
>      (defcfun ("Tcl_EvalFile" %Tcl_EvalFile) :int
>        (interp        :pointer)
>        (filename-cstr :pointer))
>
>      (defun Tcl_EvalFile (interp filename)
>        (with-foreign-pointer (filename-cstr (length filename) strlen)
> 	(setf (mem-ref filename-cstr :char (1- strlen)) 0)
> 	(lisp-string-to-foreign filename filename-cstr strlen)
>          %Tcl_EvalFile interp filename-cstr))
>
>      ;; Tcl_Eval
>
>      (defcfun ("Tcl_Eval" %Tcl_Eval) :int
>        (interp      :pointer)
>        (script-cstr :pointer))
>
>      (defun Tcl_Eval (interp script)
>        (with-foreign-pointer (script-cstr (length script) strlen)
> 	(setf (mem-ref script-cstr :char (1- strlen)) 0)
> 	(lisp-string-to-foreign script script-cstr strlen)
> 	%Tcl_Eval interp script-cstr))

You seem to be going to a fair bit of trouble here to reproduce what
the CFFI :STRING type does automatically... why not something like:

(defcfun ("Tcl_EvalFile" tcl-eval-file) :int
  (interp :pointer)
  (filename :string))

(defcfun ("Tcl_Eval" tcl-eval) :int
  (interp :pointer)
  (script :string))

instead of mucking about with low-level stuff like null terminators.
There is also WITH-FOREIGN-STRING that encapsulates this pattern in a
macro when you don't want to use the :STRING type.

Also, one technique I've found very handy when writing bindings for
APIs that are consistent about returning error codes is to define a
special result type and hang a translator on it, to get automatic
error checking (untested, caveat executor):

;; Now TCL-EVAL-FILE and TCL-EVAL can return a TCL-ERROR instead of
;; :INT and the translator will get called on the return value.
(defctype tcl-error :int)

(defmethod translate-from-foreign (value (type (eql 'tcl-error)))
  (unless (zerop value) ;; or whatever
    (error "got some tcl error ~D..." value))
  value)

Apart from any other TCL-specific issues like Yaroslav mentioned,
perhaps the TCL output stream is buffered and needs to be flushed
somehow?

James



More information about the cffi-devel mailing list