(* input.sml
 *
 * Sample code for CMSC 32102 Project-1
 *
 * This module provides a work around for a bug in the current
 * implementation of CML.  Use the operations from this module
 * instead of the TextIO event constructors on stdIn.  Note
 * that if you use this module, you will have to call RunCML.shutdown
 * to exit the vsh.
 *)

structure Input : sig

    type instream

    val init : TextIO.instream -> instream

    val inputLine : instream -> string
    val inputLineEvt : instream -> string CML.event
    val inputEvt : instream -> string CML.event

  end = struct

    structure MB = Mailbox
    structure SIO = TextIO.StreamIO

    datatype req = Input | InputLn

    datatype instream = C of (req * string CML.chan * unit CML.event) MB.mbox

    fun init inStrm = let
	  val reqCh = Mailbox.mailbox()
	  fun lp inS = let
		val (req, replCh, nackEvt) = MB.recv reqCh
		val (s, inS') = (case req
		       of Input => SIO.input inS
			| InputLn => SIO.inputLine inS
		      (* end case *))
		in
		  CML.select [
		     CML.wrap (CML.sendEvt(replCh, s),
		       fn () => if (s = "")
			    then ()
			    else lp inS'),
		     CML.wrap (nackEvt, fn () => lp inS)
		   ]
		end
	  in
	    CML.spawnc lp (TextIO.getInstream inStrm);
	    C reqCh
	  end

    fun inputEvt (C reqCh) = CML.withNack (fn nack => let
	  val replCh = CML.channel()
	  in
	    MB.send (reqCh, (Input, replCh, nack));
	    CML.recvEvt replCh
	  end)

    fun inputLineEvt (C reqCh) = CML.withNack (fn nack => let
	  val replCh = CML.channel()
	  in
	    MB.send (reqCh, (InputLn, replCh, nack));
	    CML.recvEvt replCh
	  end)

    val inputLine = CML.sync o inputLineEvt

  end
