source: trunk/minix/lib/ack/libm2/Streams.mod@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 9.3 KB
Line 
1#
2(*
3 (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
4 See the copyright notice in the ACK home directory, in the file "Copyright".
5*)
6
7(*$R-*)
8IMPLEMENTATION MODULE Streams;
9(*
10 Module: Stream Input/Output
11 Author: Ceriel J.H. Jacobs
12 Version: $Header: /cvsup/minix/src/lib/ack/libm2/Streams.mod,v 1.1 2005/10/10 15:27:46 beng Exp $
13
14 Implementation for Unix
15*)
16
17 FROM SYSTEM IMPORT BYTE, ADR;
18 FROM Epilogue IMPORT CallAtEnd;
19 FROM Storage IMPORT Allocate, Available;
20 FROM StripUnix IMPORT
21 open, close, lseek, read, write, creat;
22 IMPORT StripUnix;
23
24 CONST BUFSIZ = 1024; (* tunable *)
25 TYPE IOB = RECORD
26 kind: StreamKind;
27 mode: StreamMode;
28 eof: BOOLEAN;
29 buffering: StreamBuffering;
30 next : Stream;
31 fildes: INTEGER;
32 cnt, maxcnt: INTEGER;
33 bufferedcnt: INTEGER;
34 buf: ARRAY[1..BUFSIZ] OF BYTE;
35 END;
36 Stream = POINTER TO IOB;
37 VAR
38 ibuf, obuf, ebuf: IOB;
39 head: Stream;
40
41 PROCEDURE getstruct(VAR stream: Stream);
42 BEGIN
43 stream := head;
44 WHILE (stream # NIL) AND (stream^.kind # none) DO
45 stream := stream^.next;
46 END;
47 IF stream = NIL THEN
48 IF NOT Available(SIZE(IOB)) THEN
49 RETURN;
50 END;
51 Allocate(stream,SIZE(IOB));
52 stream^.next := head;
53 head := stream;
54 END;
55 END getstruct;
56
57 PROCEDURE freestruct(stream: Stream);
58 BEGIN
59 stream^.kind := none;
60 END freestruct;
61
62 PROCEDURE OpenStream(VAR stream: Stream;
63 filename: ARRAY OF CHAR;
64 kind: StreamKind;
65 mode: StreamMode;
66 VAR result: StreamResult);
67 VAR fd: INTEGER;
68 i: CARDINAL;
69 BEGIN
70 IF kind = none THEN
71 result := illegaloperation;
72 RETURN;
73 END;
74 getstruct(stream);
75 IF stream = NIL THEN
76 result := nomemory;
77 RETURN;
78 END;
79 WITH stream^ DO
80 FOR i := 0 TO HIGH(filename) DO
81 buf[i+1] := BYTE(filename[i]);
82 END;
83 buf[HIGH(filename)+2] := BYTE(0C);
84 END;
85 IF (mode = reading) THEN
86 fd := open(ADR(stream^.buf), 0);
87 ELSE
88 fd := -1;
89 IF (mode = appending) THEN
90 fd := open(ADR(stream^.buf), 1);
91 IF fd >= 0 THEN
92 IF (lseek(fd, 0D , 2) < 0D) THEN ; END;
93 END;
94 END;
95 IF fd < 0 THEN
96 fd := creat(ADR(stream^.buf), 666B);
97 END;
98 END;
99 IF fd < 0 THEN
100 result := openfailed;
101 freestruct(stream);
102 stream := NIL;
103 RETURN;
104 END;
105 result := succeeded;
106 stream^.fildes := fd;
107 stream^.kind := kind;
108 stream^.mode := mode;
109 stream^.buffering := blockbuffered;
110 stream^.bufferedcnt := BUFSIZ;
111 stream^.maxcnt := 0;
112 stream^.eof := FALSE;
113 IF mode = reading THEN
114 stream^.cnt := 1;
115 ELSE
116 stream^.cnt := 0;
117 END;
118 END OpenStream;
119
120 PROCEDURE SetStreamBuffering( stream: Stream;
121 b: StreamBuffering;
122 VAR result: StreamResult);
123 BEGIN
124 result := succeeded;
125 IF (stream = NIL) OR (stream^.kind = none) THEN
126 result := nostream;
127 RETURN;
128 END;
129 IF (stream^.mode = reading) OR
130 ((b = linebuffered) AND (stream^.kind = binary)) THEN
131 result := illegaloperation;
132 RETURN;
133 END;
134 FlushStream(stream, result);
135 IF b = unbuffered THEN
136 stream^.bufferedcnt := 1;
137 END;
138 stream^.buffering := b;
139 END SetStreamBuffering;
140
141 PROCEDURE FlushStream(stream: Stream; VAR result: StreamResult);
142 VAR cnt1: INTEGER;
143 BEGIN
144 result := succeeded;
145 IF (stream = NIL) OR (stream^.kind = none) THEN
146 result := nostream;
147 RETURN;
148 END;
149 WITH stream^ DO
150 IF mode = reading THEN
151 result := illegaloperation;
152 RETURN;
153 END;
154 IF (cnt > 0) THEN
155 cnt1 := cnt;
156 cnt := 0;
157 IF write(fildes, ADR(buf), cnt1) < 0 THEN END;
158 END;
159 END;
160 END FlushStream;
161
162 PROCEDURE CloseStream(VAR stream: Stream; VAR result: StreamResult);
163 BEGIN
164 IF (stream # NIL) AND (stream^.kind # none) THEN
165 result := succeeded;
166 IF stream^.mode # reading THEN
167 FlushStream(stream, result);
168 END;
169 IF close(stream^.fildes) < 0 THEN ; END;
170 freestruct(stream);
171 ELSE
172 result := nostream;
173 END;
174 stream := NIL;
175 END CloseStream;
176
177 PROCEDURE EndOfStream(stream: Stream; VAR result: StreamResult): BOOLEAN;
178 BEGIN
179 result := succeeded;
180 IF (stream = NIL) OR (stream^.kind = none) THEN
181 result := nostream;
182 RETURN FALSE;
183 END;
184 IF stream^.mode # reading THEN
185 result := illegaloperation;
186 RETURN FALSE;
187 END;
188 IF stream^.eof THEN RETURN TRUE; END;
189 RETURN (CHAR(NextByte(stream)) = 0C) AND stream^.eof;
190 END EndOfStream;
191
192 PROCEDURE FlushLineBuffers();
193 VAR s: Stream;
194 result: StreamResult;
195 BEGIN
196 s := head;
197 WHILE s # NIL DO
198 IF (s^.kind # none) AND (s^.buffering = linebuffered) THEN
199 FlushStream(s, result);
200 END;
201 s := s^.next;
202 END;
203 END FlushLineBuffers;
204
205 PROCEDURE NextByte(stream: Stream): BYTE;
206 VAR c: BYTE;
207 BEGIN
208 WITH stream^ DO
209 IF cnt <= maxcnt THEN
210 c := buf[cnt];
211 ELSE
212 IF eof THEN RETURN BYTE(0C); END;
213 IF stream = InputStream THEN
214 FlushLineBuffers();
215 END;
216 maxcnt := read(fildes, ADR(buf), bufferedcnt);
217 cnt := 1;
218 IF maxcnt <= 0 THEN
219 eof := TRUE;
220 c := BYTE(0C);
221 ELSE
222 c := buf[1];
223 END;
224 END;
225 END;
226 RETURN c;
227 END NextByte;
228
229 PROCEDURE Read(stream: Stream; VAR ch: CHAR; VAR result: StreamResult);
230 VAR EoF: BOOLEAN;
231 BEGIN
232 ch := 0C;
233 EoF := EndOfStream(stream, result);
234 IF result # succeeded THEN RETURN; END;
235 IF EoF THEN
236 result := endoffile;
237 RETURN;
238 END;
239 WITH stream^ DO
240 ch := CHAR(buf[cnt]);
241 INC(cnt);
242 END;
243 END Read;
244
245 PROCEDURE ReadByte(stream: Stream; VAR byte: BYTE; VAR result: StreamResult);
246 VAR EoF: BOOLEAN;
247 BEGIN
248 byte := BYTE(0C);
249 EoF := EndOfStream(stream, result);
250 IF result # succeeded THEN RETURN; END;
251 IF EoF THEN
252 result := endoffile;
253 RETURN;
254 END;
255 WITH stream^ DO
256 byte := buf[cnt];
257 INC(cnt);
258 END;
259 END ReadByte;
260
261 PROCEDURE ReadBytes(stream: Stream;
262 VAR bytes: ARRAY OF BYTE;
263 VAR result: StreamResult);
264 VAR i: CARDINAL;
265 BEGIN
266 FOR i := 0 TO HIGH(bytes) DO
267 ReadByte(stream, bytes[i], result);
268 END;
269 END ReadBytes;
270
271 PROCEDURE Write(stream: Stream; ch: CHAR; VAR result: StreamResult);
272 BEGIN
273 IF (stream = NIL) OR (stream^.kind = none) THEN
274 result := nostream;
275 RETURN;
276 END;
277 IF (stream^.kind # text) OR (stream^.mode = reading) THEN
278 result := illegaloperation;
279 RETURN;
280 END;
281 WITH stream^ DO
282 INC(cnt);
283 buf[cnt] := BYTE(ch);
284 IF (cnt >= bufferedcnt) OR
285 ((ch = 12C) AND (buffering = linebuffered))
286 THEN
287 FlushStream(stream, result);
288 END;
289 END;
290 END Write;
291
292 PROCEDURE WriteByte(stream: Stream; byte: BYTE; VAR result: StreamResult);
293 BEGIN
294 IF (stream = NIL) OR (stream^.kind = none) THEN
295 result := nostream;
296 RETURN;
297 END;
298 IF (stream^.kind # binary) OR (stream^.mode = reading) THEN
299 result := illegaloperation;
300 RETURN;
301 END;
302 WITH stream^ DO
303 INC(cnt);
304 buf[cnt] := byte;
305 IF cnt >= bufferedcnt THEN
306 FlushStream(stream, result);
307 END;
308 END;
309 END WriteByte;
310
311 PROCEDURE WriteBytes(stream: Stream; bytes: ARRAY OF BYTE; VAR result: StreamResult);
312 VAR i: CARDINAL;
313 BEGIN
314 FOR i := 0 TO HIGH(bytes) DO
315 WriteByte(stream, bytes[i], result);
316 END;
317 END WriteBytes;
318
319 PROCEDURE EndIt;
320 VAR h, h1 : Stream;
321 result: StreamResult;
322 BEGIN
323 h := head;
324 WHILE h # NIL DO
325 h1 := h;
326 CloseStream(h1, result);
327 h := h^.next;
328 END;
329 END EndIt;
330
331 PROCEDURE GetPosition(s: Stream; VAR position: LONGINT;
332 VAR result: StreamResult);
333 BEGIN
334 IF (s = NIL) OR (s^.kind = none) THEN
335 result := illegaloperation;
336 RETURN;
337 END;
338 IF (s^.mode # reading) THEN FlushStream(s, result); END;
339 position := lseek(s^.fildes, 0D, 1);
340 IF position < 0D THEN
341 result := illegaloperation;
342 RETURN;
343 END;
344 IF s^.mode = reading THEN
345 position := position + LONG(s^.maxcnt - s^.cnt + 1);
346 END;
347 END GetPosition;
348
349 PROCEDURE SetPosition(s: Stream; position: LONGINT; VAR result: StreamResult);
350 VAR currpos: LONGINT;
351 BEGIN
352 currpos := 0D;
353 IF (s = NIL) OR (s^.kind = none) THEN
354 result := nostream;
355 RETURN;
356 END;
357 IF (s^.mode # reading) THEN
358 FlushStream(s, result);
359 ELSE
360 s^.maxcnt := 0;
361 s^.eof := FALSE;
362 END;
363 IF s^.mode = appending THEN
364 currpos := lseek(s^.fildes, 0D, 1);
365 IF currpos < 0D THEN
366 result := illegaloperation;
367 RETURN;
368 END;
369 END;
370 IF position < currpos THEN
371 result := illegaloperation;
372 RETURN;
373 END;
374 currpos := lseek(s^.fildes, position, 0);
375 IF currpos < 0D THEN
376 result := illegaloperation;
377 RETURN;
378 END;
379 result := succeeded;
380 END SetPosition;
381
382 PROCEDURE isatty(stream: Stream; VAR result: StreamResult): BOOLEAN;
383 BEGIN
384 IF (stream = NIL) OR (stream^.kind = none) THEN
385 result := nostream;
386 RETURN FALSE;
387 END;
388 RETURN StripUnix.isatty(stream^.fildes);
389 END isatty;
390
391 PROCEDURE InitStreams;
392 VAR result: StreamResult;
393 BEGIN
394 InputStream := ADR(ibuf);
395 OutputStream := ADR(obuf);
396 ErrorStream := ADR(ebuf);
397 WITH ibuf DO
398 kind := text;
399 mode := reading;
400 eof := FALSE;
401 next := ADR(obuf);
402 fildes := 0;
403 maxcnt := 0;
404 cnt := 1;
405 bufferedcnt := BUFSIZ;
406 END;
407 WITH obuf DO
408 kind := text;
409 mode := writing;
410 eof := TRUE;
411 next := ADR(ebuf);
412 fildes := 1;
413 maxcnt := 0;
414 cnt := 0;
415 bufferedcnt := BUFSIZ;
416 IF isatty(OutputStream, result) THEN
417 buffering := linebuffered;
418 ELSE
419 buffering := blockbuffered;
420 END;
421 END;
422 WITH ebuf DO
423 kind := text;
424 mode := writing;
425 eof := TRUE;
426 next := NIL;
427 fildes := 2;
428 maxcnt := 0;
429 cnt := 0;
430 bufferedcnt := BUFSIZ;
431 IF isatty(ErrorStream, result) THEN
432 buffering := linebuffered;
433 ELSE
434 buffering := blockbuffered;
435 END;
436 END;
437 head := InputStream;
438 IF CallAtEnd(EndIt) THEN ; END;
439 END InitStreams;
440
441BEGIN
442 InitStreams
443END Streams.
Note: See TracBrowser for help on using the repository browser.