123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- #
- (*
- (c) copyright 1988 by the Vrije Universiteit, Amsterdam, The Netherlands.
- See the copyright notice in the ACK home directory, in the file "Copyright".
- *)
- (*$R-*)
- IMPLEMENTATION MODULE Streams;
- (*
- Module: Stream Input/Output
- Author: Ceriel J.H. Jacobs
- Version: $Id$
- Implementation for Unix
- *)
- FROM SYSTEM IMPORT BYTE, ADR;
- FROM Epilogue IMPORT CallAtEnd;
- FROM Storage IMPORT Allocate, Available;
- IMPORT StripUnix;
- CONST BUFSIZ = 1024; (* tunable *)
- TYPE IOB = RECORD
- kind: StreamKind;
- mode: StreamMode;
- eof: BOOLEAN;
- buffering: StreamBuffering;
- next : Stream;
- fildes: INTEGER;
- cnt, maxcnt: INTEGER;
- bufferedcnt: INTEGER;
- buf: ARRAY[1..BUFSIZ] OF BYTE;
- END;
- Stream = POINTER TO IOB;
- VAR
- ibuf, obuf, ebuf: IOB;
- head: Stream;
- PROCEDURE getstruct(VAR stream: Stream);
- BEGIN
- stream := head;
- WHILE (stream # NIL) AND (stream^.kind # none) DO
- stream := stream^.next;
- END;
- IF stream = NIL THEN
- IF NOT Available(SIZE(IOB)) THEN
- RETURN;
- END;
- Allocate(stream,SIZE(IOB));
- stream^.next := head;
- head := stream;
- END;
- END getstruct;
-
- PROCEDURE freestruct(stream: Stream);
- BEGIN
- stream^.kind := none;
- END freestruct;
- PROCEDURE OpenStream(VAR stream: Stream;
- filename: ARRAY OF CHAR;
- kind: StreamKind;
- mode: StreamMode;
- VAR result: StreamResult);
- VAR fd: INTEGER;
- i: CARDINAL;
- BEGIN
- IF kind = none THEN
- result := illegaloperation;
- RETURN;
- END;
- getstruct(stream);
- IF stream = NIL THEN
- result := nomemory;
- RETURN;
- END;
- WITH stream^ DO
- FOR i := 0 TO HIGH(filename) DO
- buf[i+1] := BYTE(filename[i]);
- END;
- buf[HIGH(filename)+2] := BYTE(0C);
- END;
- IF (mode = reading) THEN
- fd := StripUnix.open(ADR(stream^.buf), 0);
- ELSE
- fd := -1;
- IF (mode = appending) THEN
- fd := StripUnix.open(ADR(stream^.buf), 1);
- IF fd >= 0 THEN
- IF (StripUnix.lseek(fd, 0D , 2) < 0D) THEN ; END;
- END;
- END;
- IF fd < 0 THEN
- fd := StripUnix.creat(ADR(stream^.buf), 666B);
- END;
- END;
- IF fd < 0 THEN
- result := openfailed;
- freestruct(stream);
- stream := NIL;
- RETURN;
- END;
- result := succeeded;
- stream^.fildes := fd;
- stream^.kind := kind;
- stream^.mode := mode;
- stream^.buffering := blockbuffered;
- stream^.bufferedcnt := BUFSIZ;
- stream^.maxcnt := 0;
- stream^.eof := FALSE;
- IF mode = reading THEN
- stream^.cnt := 1;
- ELSE
- stream^.cnt := 0;
- END;
- END OpenStream;
- PROCEDURE SetStreamBuffering( stream: Stream;
- b: StreamBuffering;
- VAR result: StreamResult);
- BEGIN
- result := succeeded;
- IF (stream = NIL) OR (stream^.kind = none) THEN
- result := nostream;
- RETURN;
- END;
- IF (stream^.mode = reading) OR
- ((b = linebuffered) AND (stream^.kind = binary)) THEN
- result := illegaloperation;
- RETURN;
- END;
- FlushStream(stream, result);
- IF b = unbuffered THEN
- stream^.bufferedcnt := 1;
- END;
- stream^.buffering := b;
- END SetStreamBuffering;
- PROCEDURE FlushStream(stream: Stream; VAR result: StreamResult);
- VAR cnt1: INTEGER;
- BEGIN
- result := succeeded;
- IF (stream = NIL) OR (stream^.kind = none) THEN
- result := nostream;
- RETURN;
- END;
- WITH stream^ DO
- IF mode = reading THEN
- result := illegaloperation;
- RETURN;
- END;
- IF (cnt > 0) THEN
- cnt1 := cnt;
- cnt := 0;
- IF StripUnix.write(fildes, ADR(buf), cnt1) < 0 THEN END;
- END;
- END;
- END FlushStream;
- PROCEDURE CloseStream(VAR stream: Stream; VAR result: StreamResult);
- BEGIN
- IF (stream # NIL) AND (stream^.kind # none) THEN
- result := succeeded;
- IF stream^.mode # reading THEN
- FlushStream(stream, result);
- END;
- IF StripUnix.close(stream^.fildes) < 0 THEN ; END;
- freestruct(stream);
- ELSE
- result := nostream;
- END;
- stream := NIL;
- END CloseStream;
-
- PROCEDURE EndOfStream(stream: Stream; VAR result: StreamResult): BOOLEAN;
- BEGIN
- result := succeeded;
- IF (stream = NIL) OR (stream^.kind = none) THEN
- result := nostream;
- RETURN FALSE;
- END;
- IF stream^.mode # reading THEN
- result := illegaloperation;
- RETURN FALSE;
- END;
- IF stream^.eof THEN RETURN TRUE; END;
- RETURN (CHAR(NextByte(stream)) = 0C) AND stream^.eof;
- END EndOfStream;
- PROCEDURE FlushLineBuffers();
- VAR s: Stream;
- result: StreamResult;
- BEGIN
- s := head;
- WHILE s # NIL DO
- IF (s^.kind # none) AND (s^.buffering = linebuffered) THEN
- FlushStream(s, result);
- END;
- s := s^.next;
- END;
- END FlushLineBuffers;
- PROCEDURE NextByte(stream: Stream): BYTE;
- VAR c: BYTE;
- BEGIN
- WITH stream^ DO
- IF cnt <= maxcnt THEN
- c := buf[cnt];
- ELSE
- IF eof THEN RETURN BYTE(0C); END;
- IF stream = InputStream THEN
- FlushLineBuffers();
- END;
- maxcnt := StripUnix.read(fildes, ADR(buf), bufferedcnt);
- cnt := 1;
- IF maxcnt <= 0 THEN
- eof := TRUE;
- c := BYTE(0C);
- ELSE
- c := buf[1];
- END;
- END;
- END;
- RETURN c;
- END NextByte;
- PROCEDURE Read(stream: Stream; VAR ch: CHAR; VAR result: StreamResult);
- VAR EoF: BOOLEAN;
- BEGIN
- ch := 0C;
- EoF := EndOfStream(stream, result);
- IF result # succeeded THEN RETURN; END;
- IF EoF THEN
- result := endoffile;
- RETURN;
- END;
- WITH stream^ DO
- ch := CHAR(buf[cnt]);
- INC(cnt);
- END;
- END Read;
- PROCEDURE ReadByte(stream: Stream; VAR byte: BYTE; VAR result: StreamResult);
- VAR EoF: BOOLEAN;
- BEGIN
- byte := BYTE(0C);
- EoF := EndOfStream(stream, result);
- IF result # succeeded THEN RETURN; END;
- IF EoF THEN
- result := endoffile;
- RETURN;
- END;
- WITH stream^ DO
- byte := buf[cnt];
- INC(cnt);
- END;
- END ReadByte;
- PROCEDURE ReadBytes(stream: Stream;
- VAR bytes: ARRAY OF BYTE;
- VAR result: StreamResult);
- VAR i: CARDINAL;
- BEGIN
- FOR i := 0 TO HIGH(bytes) DO
- ReadByte(stream, bytes[i], result);
- END;
- END ReadBytes;
- PROCEDURE Write(stream: Stream; ch: CHAR; VAR result: StreamResult);
- BEGIN
- IF (stream = NIL) OR (stream^.kind = none) THEN
- result := nostream;
- RETURN;
- END;
- IF (stream^.kind # text) OR (stream^.mode = reading) THEN
- result := illegaloperation;
- RETURN;
- END;
- WITH stream^ DO
- INC(cnt);
- buf[cnt] := BYTE(ch);
- IF (cnt >= bufferedcnt) OR
- ((ch = 12C) AND (buffering = linebuffered))
- THEN
- FlushStream(stream, result);
- END;
- END;
- END Write;
- PROCEDURE WriteByte(stream: Stream; byte: BYTE; VAR result: StreamResult);
- BEGIN
- IF (stream = NIL) OR (stream^.kind = none) THEN
- result := nostream;
- RETURN;
- END;
- IF (stream^.kind # binary) OR (stream^.mode = reading) THEN
- result := illegaloperation;
- RETURN;
- END;
- WITH stream^ DO
- INC(cnt);
- buf[cnt] := byte;
- IF cnt >= bufferedcnt THEN
- FlushStream(stream, result);
- END;
- END;
- END WriteByte;
- PROCEDURE WriteBytes(stream: Stream; bytes: ARRAY OF BYTE; VAR result: StreamResult);
- VAR i: CARDINAL;
- BEGIN
- FOR i := 0 TO HIGH(bytes) DO
- WriteByte(stream, bytes[i], result);
- END;
- END WriteBytes;
- PROCEDURE EndIt;
- VAR h, h1 : Stream;
- result: StreamResult;
- BEGIN
- h := head;
- WHILE h # NIL DO
- h1 := h;
- CloseStream(h1, result);
- h := h^.next;
- END;
- END EndIt;
- PROCEDURE GetPosition(s: Stream; VAR position: LONGINT;
- VAR result: StreamResult);
- BEGIN
- IF (s = NIL) OR (s^.kind = none) THEN
- result := illegaloperation;
- RETURN;
- END;
- IF (s^.mode # reading) THEN FlushStream(s, result); END;
- position := StripUnix.lseek(s^.fildes, 0D, 1);
- IF position < 0D THEN
- result := illegaloperation;
- RETURN;
- END;
- IF s^.mode = reading THEN
- position := position - LONG(s^.maxcnt - s^.cnt + 1);
- END;
- END GetPosition;
- PROCEDURE SetPosition(s: Stream; position: LONGINT; VAR result: StreamResult);
- VAR currpos: LONGINT;
- BEGIN
- currpos := 0D;
- IF (s = NIL) OR (s^.kind = none) THEN
- result := nostream;
- RETURN;
- END;
- IF (s^.mode # reading) THEN
- FlushStream(s, result);
- ELSE
- s^.maxcnt := 0;
- s^.eof := FALSE;
- END;
- IF s^.mode = appending THEN
- currpos := StripUnix.lseek(s^.fildes, 0D, 1);
- IF currpos < 0D THEN
- result := illegaloperation;
- RETURN;
- END;
- END;
- IF position < currpos THEN
- result := illegaloperation;
- RETURN;
- END;
- currpos := StripUnix.lseek(s^.fildes, position, 0);
- IF currpos < 0D THEN
- result := illegaloperation;
- RETURN;
- END;
- result := succeeded;
- END SetPosition;
- PROCEDURE isatty(stream: Stream; VAR result: StreamResult): BOOLEAN;
- BEGIN
- IF (stream = NIL) OR (stream^.kind = none) THEN
- result := nostream;
- RETURN FALSE;
- END;
- IF (StripUnix.isatty(stream^.fildes) = 0) THEN
- RETURN FALSE;
- END;
- RETURN TRUE;
- END isatty;
- PROCEDURE InitStreams;
- VAR result: StreamResult;
- BEGIN
- InputStream := ADR(ibuf);
- OutputStream := ADR(obuf);
- ErrorStream := ADR(ebuf);
- WITH ibuf DO
- kind := text;
- mode := reading;
- eof := FALSE;
- next := ADR(obuf);
- fildes := 0;
- maxcnt := 0;
- cnt := 1;
- bufferedcnt := BUFSIZ;
- END;
- WITH obuf DO
- kind := text;
- mode := writing;
- eof := TRUE;
- next := ADR(ebuf);
- fildes := 1;
- maxcnt := 0;
- cnt := 0;
- bufferedcnt := BUFSIZ;
- IF isatty(OutputStream, result) THEN
- buffering := linebuffered;
- ELSE
- buffering := blockbuffered;
- END;
- END;
- WITH ebuf DO
- kind := text;
- mode := writing;
- eof := TRUE;
- next := NIL;
- fildes := 2;
- maxcnt := 0;
- cnt := 0;
- bufferedcnt := BUFSIZ;
- IF isatty(ErrorStream, result) THEN
- buffering := linebuffered;
- ELSE
- buffering := blockbuffered;
- END;
- END;
- head := InputStream;
- IF CallAtEnd(EndIt) THEN ; END;
- END InitStreams;
- BEGIN
- InitStreams
- END Streams.
|