IO.ml 1.94 KB
Newer Older
1 2 3
(* Input-output utilities. *)

(* ------------------------------------------------------------------------- *)
4
(* [exhaust channel] reads all of the data that's available on [channel].
POTTIER Francois's avatar
POTTIER Francois committed
5 6
   It does not assume that the length of the data is known ahead of time.
   It does not close the channel. *)
7 8

let chunk_size =
POTTIER Francois's avatar
POTTIER Francois committed
9
  16384
10 11 12

let exhaust channel =
  let buffer = Buffer.create chunk_size in
POTTIER Francois's avatar
POTTIER Francois committed
13
  let chunk = Bytes.create chunk_size in
14 15 16 17 18
  let rec loop () =
    let length = input channel chunk 0 chunk_size in
    if length = 0 then
      Buffer.contents buffer
    else begin
POTTIER Francois's avatar
POTTIER Francois committed
19
      Buffer.add_subbytes buffer chunk 0 length;
20 21 22 23 24 25 26 27 28 29 30 31
      loop()
    end
  in
  loop()

(* ------------------------------------------------------------------------- *)
(* [invoke command] invokes an external command (which expects no
   input) and returns its output, if the command succeeds. It returns
   [None] if the command fails. *)

let invoke command =
  let ic = Unix.open_process_in command in
32 33 34
  (* 20130911 Be careful to read in text mode, so as to avoid newline
     translation problems (which would manifest themselves on Windows). *)
  set_binary_mode_in ic false;
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
  let result = exhaust ic in
  match Unix.close_process_in ic with
  | Unix.WEXITED 0 ->
      Some result
  | _ ->
      None

(* ------------------------------------------------------------------------- *)
(* [winvoke writers command cleaners] invokes each of the [writer]
   functions, invokes the command [command], and runs each of the
   [cleaner] functions. Then, it either returns the command's output,
   if the command succeeded, or exits, otherwise. *)

let winvoke writers command cleaners =
  let call action =
    action ()
  in
  List.iter call writers;
  let output = invoke command in
  List.iter call cleaners;

  (* Stop if the command failed. Otherwise, return its output. *)

  match output with
  | None ->
      (* Presumably, the command printed an error message for us. *)
      exit 1
  | Some output ->
      output