Returning a string from C library to OCaml using CTypes and Foreign

I am having trouble displaying native OSX calls from OCaml, where the c-call is expecting the buffer and size to be transferred. I worked with examples in Real World OCaml using CTypes and Foreign, but they don’t cover this case or at least I don’t understand how I feel about it.

Here is my fragment 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 to allocate a buffer to pass to proc_pidpath()and is there a better way to wrap this call so that it returns an Option type (String or Nil) or just a string?

+4
source share
1 answer

. .

( Core, , , - , 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 
     /questions/1519549/passing-a-string-to-a-c-library-from-ocaml-using-ctypes-and-foreign *)

  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 *))
+4

Source: https://habr.com/ru/post/1533463/


All Articles