Returning a string from a C library to OCaml using CTypes and Foreign
ffi, macos, ocaml
Solution
This question share a lot of the issue with this one. I encourage you to have a look at it.
For your particular problem the following should work (it doesn't use `Core` so you may have to adjust some things, did they make the result of `Unix.getpid` abstract ?).
open Ctypes;;
open Foreign;;
module Proc : sig
val pidpath : int -> string
(** @raise [Unix.Unix_error] in case of error *)
end = struct
let pidpathinfo_maxsize = 1024 * 4
(* value of PROC_PIDPATHINFO_MAXSIZE.
N.B. this should not be hardcoded, see 1) in this answer
https://stackoverflow.com/questions/20851390 *)
let char_array_as_string a len =
(* This function should soon no longer be required see:
https://github.com/ocamllabs/ocaml-ctypes/pull/139 *)
let b = Buffer.create len in
for i = 0 to len -1 do Buffer.add_char b (Array.get a i) done;
Buffer.contents b
let pidpath =
foreign ~check_errno:true "proc_pidpath"
(int @-> ptr char @-> int @-> returning int)
let pidpath pid =
let path = Array.make char ~initial:'\x00' pidpathinfo_maxsize in
let len = pidpath pid (Array.start path) pidpathinfo_maxsize in
char_array_as_string path len
end
let () =
let print_pidpath pid =
try
let path = Proc.pidpath pid in
Format.printf "Pid %d: %s@." pid path;
with Unix.Unix_error (e, _, _) ->
Format.eprintf "Pid %d: %s@." pid (Unix.error_message e)
in
print_pidpath (Unix.getpid ());
print_pidpath (-10000 (* bogus *))
Problem
I'm having some trouble mapping native OSX calls from OCaml where the c call expects a buffer and size to be passed in. I've worked through the examples in Real World OCaml on using CTypes and Foreign but they don't cover this case or at least it's not clear to me how I'd to it. Here's my snippet of OCaml: ``` open Core.Std open Unix open Ctypes open Foreign (* from /usr/include/libproc.h int proc_pidpath(int pid, void * buffer, uint32_t buffersize); *) let proc_pidpath = foreign "proc_pidpath" (int @-> ptr void @-> int @-> returning int) let () = let pid = Pid.to_int (Unix.getpid ()) in let buf = allocate string 255 in let path = proc_pidpath(pid, buf, 255) in printf "Pid: %i Path: %s\n" pid buf ``` How do I allocate a buffer to pass into `proc_pidpath()` and is there a nicer way of wrapping this call so it returns an Option type (String or Nil) or just a String?