⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 text-io-fn.sml

📁 这是我们参加06年全国开源软件的竞赛作品
💻 SML
📖 第 1 页 / 共 3 页
字号:
	      val getPos = (case (getPos, setPos)		     of (SOME f, SOME _) => (fn () => SOME(f()))		      | _ => (fn () => NONE)		    (* end case *))	      val more = SV.mVarInit NOMORE	      val closedFlg = ref false	      val tag = CleanIO.addCleaner dummyCleaner	      val info = INFO{		      reader=reader, readVec=readVec, readVecEvt=readVecEvt,		      closed = closedFlg, getPos = getPos,		      tail = SV.mVarInit more, cleanTag = tag		    }	      val buf = (case optData		     of NONE => IBUF{			    basePos = getPos(), data=empty,			    info=info, more=more			  }(** What should we do about the position in this case ?? **)(** Suggestion: When building a stream with supplied initial data, ** nothing can be said about the positions inside that initial ** data (who knows where that data even came from!). **) 		      | (SOME v) => IBUF{			    basePos = NONE, data=v,			    info=info, more=more}		    (* end case *))	      val strm =  ISTRM(buf, 0)	      in		(tag, strm)	      end        fun mkInstream arg = let	      val (tag, strm) = mkInstream' arg	      in		CleanIO.rebindCleaner (tag, fn () => closeIn strm);		strm	      end	fun getReader (ISTRM(buf, pos)) = let	      val IBUF{data, info as INFO{reader, ...}, more, ...} = buf	      fun getData more = (case SV.mGet more		     of (MORE(IBUF{data, more=more', ...})) => data :: getData more'		      | _ => []		    (* end case *))	      in		terminate info;		if (pos < V.length data)		  then (		      reader,		      V.concat(vecExtract(data, pos, NONE) :: getData more)		    )		  else (reader, V.concat(getData more))	      end      (** Position operations on instreams **)	datatype in_pos = INP of {	    base : pos,	    offset : int,	    info : info	  }	fun getPosIn (ISTRM(buf, pos)) = (case buf	       of IBUF{basePos=NONE, info, ...} =>		    inputExn (info, "getPosIn", IO.RandomAccessNotSupported)		| IBUF{basePos=SOME p, info, ...} => INP{		      base = p, offset = pos, info = info		    }	      (* end case *))	fun filePosIn (INP{base, offset, ...}) =	      Position.+(base, Position.fromInt offset)	fun setPosIn (pos as INP{info as INFO{reader, ...}, ...}) = let	      val fpos = filePosIn pos	      val (PIO.RD rd) = reader	      in		terminate info;		valOf (#setPos rd) fpos;		mkInstream (PIO.RD rd, NONE)	      end      (** Text stream specific operations **)	fun inputLine (ISTRM(buf as IBUF{data, ...}, pos)) = let	      fun join (item, (list, strm)) = (item::list, strm)	      fun nextBuf (isEmpty, buf as IBUF{more, data, ...}) = let		    fun last () =			  (if isEmpty then [] else ["\n"], ISTRM(buf, V.length data))		    fun get (MORE buf) = scanData (buf, 0)		      | get NOMORE = (case (SV.mTake more)			       of NOMORE => (				    case extendStream (readVec buf, "inputLine", buf)				     of EOF => last ()				      | (DATA rest) => scanData (rest, 0)				    (* end case *))				| next => (SV.mPut(more, next); get next)			      (* end case *))		      | get TERMINATED = last()		    in		      get (SV.mGet more)		    end	      and scanData (buf as IBUF{data, ...}, i) = let		    val len = V.length data		    fun scan j = if (j = len)			    then join(vecExtract(data, i, NONE), nextBuf(false, buf))			  else if (vecSub(data, j) = #"\n")			    then ([vecExtract(data, i, SOME(j+1-i))], ISTRM(buf, j+1))			    else scan (j+1)		    in		      scan i		    end	      val (data, strm) = if (V.length data = pos)		    then nextBuf (true, buf)		    else scanData (buf, pos)	      in		(V.concat data, strm)	      end      (*** Output streams ***)      (* an output stream is implemented as a monitor using an mvar to       * hold its data.       *)	datatype ostrm_info = OSTRM of {	    buf : A.array,	    pos : int ref,	    closed : bool ref,	    bufferMode : IO.buffer_mode ref,	    writer : writer,	    writeArr : {buf : A.array, i : int, sz : int option} -> unit,	    writeVec : {buf : V.vector, i : int, sz : int option} -> unit,	    cleanTag : CleanIO.tag	  }	type outstream = ostrm_info SV.mvar	fun isNL #"\n" = true	  | isNL _ = false	fun isLineBreak (OSTRM{bufferMode, ...}) =	      if (!bufferMode = IO.LINE_BUF) then isNL else (fn _ => false)	fun outputExn (OSTRM{writer=PIO.WR{name, ...}, ...}, mlOp, exn) =	      raise IO.Io{function=mlOp, name=name, cause=exn}      (* lock access to the stream and make sure that it is not closed. *)	fun lockAndChkClosedOut (strmMV, mlOp) = (case SV.mTake strmMV	       of (strm as OSTRM({closed=ref true, ...})) => (		    SV.mPut (strmMV, strm);		    outputExn (strm, mlOp, IO.ClosedStream))		| strm => strm	      (* end case *))	fun flushBuffer (strmMV, strm as OSTRM{buf, pos, writeArr, ...}, mlOp) = (	      case !pos	       of 0 => ()		| n => ((		    writeArr {buf=buf, i=0, sz=SOME n}; pos := 0)		      handle ex => (			SV.mPut(strmMV, strm); outputExn (strm, mlOp, ex)))	      (* end case *))      (* A version of copyVec that checks for newlines, while it is copying.       * This is used for LINE_BUF output of strings and substrings.       *)	fun lineBufCopyVec (src, srcI, srcLen, dst, dstI) = let	      val stop = srcI+srcLen	      fun cpy (srcI, dstI, lb) =		    if (srcI < stop)		      then let val c = vecSub(src, srcI)			in			  arrUpdate (dst, dstI, c);			  cpy (srcI+1, dstI+1, lb orelse isNL c)			end		      else lb	      in		cpy (srcI, dstI, false)	      end      (* a version of copyVec for BLOCK_BUF output of strings and substrings. *)	fun blockBufCopyVec (src, srcI, srcLen, dst, dstI) = (	      A.copyVec {		  src = src, si = srcI, len = SOME srcLen, dst = dst, di = dstI		};	      false)	fun output (strmMV, v) = let	      val (strm as OSTRM os) = lockAndChkClosedOut (strmMV, "output")	      fun release () = SV.mPut (strmMV, strm)	      val {buf, pos, bufferMode, ...} = os	      fun flush () = flushBuffer (strmMV, strm, "output")	      fun flushAll () = (#writeArr os {buf=buf, i=0, sz=NONE}		    handle ex => (release(); outputExn (strm, "output", ex)))	      fun writeDirect () = (		    case !pos		     of 0 => ()		      | n => (#writeArr os {buf=buf, i=0, sz=SOME n}; pos := 0)		    (* end case *);		    #writeVec os {buf=v, i=0, sz=NONE})		      handle ex => (release(); outputExn (strm, "output", ex))	      fun insert copyVec = let		    val bufLen = A.length buf		    val dataLen = V.length v		    in		      if (dataLen >= bufLen)			then writeDirect()			else let			  val i = !pos			  val avail = bufLen - i			  in			    if (avail < dataLen)			      then let				val _ = A.copyVec{					src=v, si=0, len=SOME avail, dst=buf, di=i				      }				val _ = flushAll()				val needsFlush = copyVec(v, avail, dataLen-avail, buf, 0)				in			  	  pos := dataLen-avail;				  if needsFlush then flush () else ()				end			    else let			      val needsFlush = copyVec(v, 0, dataLen, buf, i)			      in			        pos := i + dataLen;			        if (needsFlush orelse (avail = dataLen))				  then flush()				  else ()			      end			  end		    end	      in		case !bufferMode		 of IO.NO_BUF => writeDirect ()		  | IO.LINE_BUF => insert lineBufCopyVec		  | IO.BLOCK_BUF => insert blockBufCopyVec		(* end case *);		release()	      end	fun output1 (strmMV, elem) = let	      val (strm as OSTRM{buf, pos, bufferMode, writeArr, ...}) =		    lockAndChkClosedOut (strmMV, "output1")	      fun release () = SV.mPut (strmMV, strm)	      in		case !bufferMode		 of IO.NO_BUF => (		      arrUpdate (buf, 0, elem);		      writeArr {buf=buf, i=0, sz=SOME 1}			handle ex => (release(); outputExn (strm, "output1", ex)))		  | IO.LINE_BUF => let val i = !pos val i' = i+1		      in			arrUpdate (buf, i, elem); pos := i';			if ((i' = A.length buf) orelse (isNL elem))			  then flushBuffer (strmMV, strm, "output1")			  else ()		      end		  | IO.BLOCK_BUF => let val i = !pos val i' = i+1		      in			arrUpdate (buf, i, elem); pos := i';			if (i' = A.length buf)			  then flushBuffer (strmMV, strm, "output1")			  else ()		      end		(* end case *);		release()	      end	fun flushOut strmMV = let	      val strm = lockAndChkClosedOut (strmMV, "flushOut")	      in		flushBuffer (strmMV, strm, "flushOut");		SV.mPut (strmMV, strm)	      end	fun closeOut strmMV = let	      val (strm as OSTRM{writer=PIO.WR{close, ...}, closed, cleanTag, ...}) =		    SV.mTake strmMV	      in		if !closed		  then ()		  else (		    flushBuffer (strmMV, strm, "closeOut");		    closed := true;		    CleanIO.removeCleaner cleanTag;		    close());		SV.mPut (strmMV, strm)	      end	fun mkOutstream' (wr as PIO.WR{chunkSize, writeArr, writeVec, ...}, mode) =	      let	      fun iterate f (buf, i, sz) = let		    fun lp (_, 0) = ()		      | lp (i, n) = let val n' = f{buf=buf, i=i, sz=SOME n}			  in lp (i+n', n-n') end		    in		      lp (i, sz)		    end	      fun writeArr' {buf, i, sz} = let		    val len = (case sz			   of NONE => A.length buf - i			    | (SOME n) => n			  (* end case *))		    in		      iterate writeArr (buf, i, len)		    end	      fun writeVec' {buf, i, sz} = let		    val len = (case sz			   of NONE => V.length buf - i			    | (SOME n) => n			  (* end case *))		    in		      iterate writeVec (buf, i, len)		    end	    (* install a dummy cleaner *)	      val tag = CleanIO.addCleaner dummyCleaner	      val strm = SV.mVarInit (OSTRM{		      buf = A.array(chunkSize, someElem),		      pos = ref 0,		      closed = ref false,		      bufferMode = ref mode,		      writer = wr,		      writeArr = writeArr',		      writeVec = writeVec',		      cleanTag = tag		    })	      in		(tag, strm)	      end	fun mkOutstream arg = let	      val (tag, strm) = mkOutstream' arg	      in		CleanIO.rebindCleaner (tag, fn () => closeOut strm);		strm	      end	fun getWriter strmMV = let	      val (strm as OSTRM{writer, bufferMode, ...}) =		    lockAndChkClosedOut (strmMV, "getWriter")	      in

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -