1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
(*
Title: Standard Basis Library: Binary IO
Copyright David C.J. Matthews 2000, 2005
This library 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 2.1 of the License, or (at your option) any later version.
This library 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 library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*)
(* G&R 2004 status: in progress. *)
signature BIN_IO =
sig
include IMPERATIVE_IO
where type StreamIO.vector = Word8Vector.vector
where type StreamIO.elem = Word8.word
where type StreamIO.reader = BinPrimIO.reader
where type StreamIO.writer = BinPrimIO.writer
where type StreamIO.pos = BinPrimIO.pos
val openIn : string -> instream
val openOut : string -> outstream
val openAppend : string -> outstream
end;
structure BinIO: BIN_IO =
struct
open IO
structure StreamIO =
struct
structure SIO = BasicStreamIO(
structure PrimIO = BinPrimIO
structure Vector = Word8Vector
structure Array = Word8Array
structure VectorSlice = Word8VectorSlice
structure ArraySlice = Word8ArraySlice
val someElem : PrimIO.elem = 0wx20
);
open SIO
(* StreamIO treats line buffering on output as block buffering
since it has no concept of a line separator. It's not clear whether
line buffering makes sense for binary IO either but at least there
is a value (0w12) which we can use. *)
fun output(f, v) =
case getBufferMode f of
LINE_BUF =>
let
val vecLen = Word8Vector.length v
(* Find the last newline character in the string. *)
fun lastNewline 0 = 0
| lastNewline i =
if Word8Vector.sub(v, i-1) = 0w12 then i
else lastNewline(i-1)
val newLinePos = lastNewline vecLen
in
if newLinePos = 0
then (* No newlines in it. *)
SIO.output(f, v)
else (* There's at least one newline. *)
(
SIO.outputVec(f, Word8VectorSlice.slice(v, 0, SOME(newLinePos-1)));
flushOut f;
SIO.outputVec(f, Word8VectorSlice.slice(v, newLinePos, NONE))
)
end
| _ => SIO.output(f, v) (* Not line buffering. *)
(* This could be defined in terms of output but the underlying
output1 function is likely to be more efficient. *)
fun output1(f, c) =
(
SIO.output1(f, c);
if c = 0w12 andalso getBufferMode f = LINE_BUF
then flushOut f else ()
)
end;
structure ImpIO = ImperativeIO(
structure StreamIO = StreamIO
structure Vector = Word8Vector
structure Array = Word8Array)
open ImpIO
open RuntimeCalls;
local
structure Interrupt = RunCall.Run_exception0( val ex_iden = EXC_interrupt )
in
exception Interrupt = Interrupt.ex
end
(* Called after any exception in the lower level reader or
writer to map any exception other than Io into Io. *)
fun mapToIo (io as Io _, _, _) = io
| mapToIo (Interrupt, _, _) = Interrupt
| mapToIo (nonIo, name, caller) =
Io { name = name, function = caller, cause = nonIo }
type fileDescr = OS.IO.iodesc (* Actually abstract. This isn't
the file descriptor itself, rather
a pointer into the io table. *)
local
local
val doIo: int*int*string -> fileDescr
= RunCall.run_call3 POLY_SYS_io_dispatch
in
fun sys_open_in_bin name = doIo(4, 0, name)
and sys_open_out_bin name = doIo(6, 0, name)
and sys_open_append_bin name = doIo(14, 0, name)
end
local
val doIo = RunCall.run_call3 POLY_SYS_io_dispatch
in
fun sys_get_buffsize (strm: fileDescr): int = doIo(15, strm, 0)
end
fun wrapInFileDescr(n, name) =
let
val binPrimRd =
LibraryIOSupport.wrapBinInFileDescr {fd=n, name=name, initBlkMode=true}
val streamIo =
StreamIO.mkInstream(binPrimRd, Word8Vector.fromList [])
in
mkInstream streamIo
end
fun wrapOutFileDescr(n, name, buffering, isAppend) =
let
val buffSize = sys_get_buffsize n
val binPrimWr =
LibraryIOSupport.wrapBinOutFileDescr{fd=n,
name=name, appendMode=isAppend, chunkSize=buffSize, initBlkMode=true}
(* Construct a stream. *)
val streamIo = StreamIO.mkOutstream(binPrimWr, buffering)
in
mkOutstream streamIo
end
in
(* Open a file for input. *)
fun openIn s =
wrapInFileDescr(
sys_open_in_bin s
handle exn => raise mapToIo(exn, s, "BinIO.openIn"),
s)
(* Open a file for output. *)
fun openOut s =
let
val f =
sys_open_out_bin s
handle exn => raise mapToIo(exn, s, "BinIO.openOut")
(* Look at the stream to see what kind of buffering to use. *)
val k = OS.IO.kind f
in
wrapOutFileDescr (f, s,
if k = OS.IO.Kind.tty orelse k = OS.IO.Kind.pipe orelse k = OS.IO.Kind.device
then IO.LINE_BUF else IO.BLOCK_BUF,
false (* Not append *))
end
fun openAppend s =
let
val f =
sys_open_append_bin s
handle exn => raise mapToIo(exn, s, "BinIO.openAppend")
val k = OS.IO.kind f
in
wrapOutFileDescr (f, s,
if k = OS.IO.Kind.tty orelse k = OS.IO.Kind.pipe orelse k = OS.IO.Kind.device
then IO.LINE_BUF else IO.BLOCK_BUF,
true (* setPos will not work. *))
end
end
end;
|