(* Copyright 2005-2007 Berke DURAK, INRIA Rocquencourt.

This file is part of Dose2.

Dose2 is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Dose2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. *)

(*** IN *)
module type IN =
  sig
    type i
    val input_byte : i -> int
    val input_char : i -> char
    val input : i -> string -> int -> int -> unit
  end
;;
(* ***)
(*** OUT *)
module type OUT =
  sig
    type o
    val output_byte : o -> int -> unit
    val output_char : o -> char -> unit
    val output_string : o -> string -> unit
    val output : o -> string -> int -> int -> unit
    val flush : o -> unit
  end
;;
(* ***)
(*** CHANNEL_IN *)
module CHANNEL_IN =
  struct
    type i = in_channel
    let input_byte = input_byte
    let input_char = input_char
    let input = really_input
  end
;;
(* ***)
(*** CHANNEL_OUT *)
module CHANNEL_OUT =
  struct
    type o = out_channel
    let output_char = output_char
    let output_byte = output_byte
    let output_string = output_string
    let output = output
    let flush = Pervasives.flush
  end
;;
(* ***)
(*** STRING_OUT *)
module STRING_OUT =
  struct
    type o = Buffer.t
    let create = Buffer.create
    let contents = Buffer.contents
    let output_byte b x = Buffer.add_char b (Char.unsafe_chr x)
    let output_char b x = Buffer.add_char b x
    let output_string = Buffer.add_string
    let output = Buffer.add_substring
    let flush _ = ()
  end
;;
(* ***)
(*** STRING_IN *)
module STRING_IN =
  struct
    type i = {
      i_string : string;
      i_length : int;
      mutable i_pos : int
    }
    (*** of_string *)
    let of_string ?(offset=0) ?length u =
      let length =
        match length with
        | None -> String.length u - offset
        | Some l -> l
      in
      if 0 <= offset &&
         offset < String.length u &&
         0 <= length &&
         offset + length <= String.length u
      then
        { i_string = u;
          i_length = length;
          i_pos = offset }
      else
        invalid_arg "STRING_IN.of_string"
    ;;
    (* ***)
    (*** input_char *)
    let input_char i =
      if i.i_pos >= i.i_length then
        raise End_of_file
      else
        begin
          let c = i.i_string.[i.i_pos] in
          i.i_pos <- i.i_pos + 1;
          c
        end
    ;;
    (* ***)
    let input_byte i = Char.code (input_char i);;
    let input i u o n =
      String.blit i.i_string i.i_pos u o n;
      i.i_pos <- i.i_pos + n
    ;;
  end
;;
(* ***)
