Function pointers in Ctypes and Foreign

ctypes

#1

Hi, I’m trying to build use the Ctypes/Foreign FFI to bind GNU Readline to Ocaml in order to add vi line editing to the ocaml toplevels. To do this, I need to bind a variable which is a C function pointer and assign it at runtime to an ocaml function, which RWO doesn’t cover. I’m doing this with the functioni pointer rl_attempted_completion_function (cf. The relevant code from readline.h:

\\ ..
typedef char **rl_completion_func_t (const char *, int, int); 
\\ ...
extern rl_completion_func_t *rl_attempted_completion_function;

In my readline.ml I have:

open Ctypes
open Foreign

let rl_completion_func_t =
    funptr ( string @-> int @-> int @-> returning (ptr string))

let rl_attempted_completion_function = 
    foreign_value "rl_attempted_completion_function"
 	( rl_completion_func_t )

And to test it, I write in term.ml:

open Ctypes
open Readline

let custom_attempted_completion_function text a b  =  text

let () = 
    rl_attempted_completion_function <-@ custom_attempted_completion_function;

This does not work, because

  • rl_attempted function is a ptr to a funptr, while custom_attempted_completion_function isn’t a funptr at all
  • my function is returning a string, when it ought to return the ocaml equivalent of a char **, which I suppose is string ptr. But I don’t know how to get a pointer to the string argument?

How can I assign the bound function pointer variable to my ocaml function? Or is my approach incorrect?


#2

The code is almost correct: in particular, the assignment is fine, since the funptr view handles the conversion from the OCaml function to the function pointer.

In order to deal with the return value, you need to decide what strategy to use for allocating the return value. It looks (from the documentation) that the reason the return value is a pointer to pointer to char is to support return arrays of strings, in which case returning a single string won’t work out. One possible approach is to build an array of pointers to char

let completions = CArray.make (ptr char) n

and return its address, which can be obtained using Ctypes.CArray.start, from custom_attempted_completion_function.