File: BinIO.sml

package info (click to toggle)
polyml 5.2.1-1.1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 19,692 kB
  • ctags: 17,567
  • sloc: cpp: 37,221; sh: 9,591; asm: 4,120; ansic: 428; makefile: 203; ml: 191; awk: 91; sed: 10
file content (192 lines) | stat: -rw-r--r-- 5,568 bytes parent folder | download | duplicates (2)
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;