-- StreamIO.Mesa Edited by Sandman on August 1, 1980 10:20 AM -- Updated for Pilot Martin Newell 23-Jul-81 14:02:05 DIRECTORY DCSFileTypes USING [tLeaderPage], Directory USING [CreateFile, Lookup, UpdateDates, Error], File USING [Permissions, Capability, read, write, grow, shrink, delete], FileStream USING [Create, EndOf], IODefs USING [SP, CR, NumberFormat], TTY USING[Handle, SetEcho, GetChar, PutChar, GetEditedString, NewLine, Create, PutBackChar], Storage USING [Node, Free], Stream USING [Handle, GetChar, PutChar, GetWord, PutWord, Delete], StreamDefs USING [AccessOptions, StreamHandle, StreamObject, Read, Write, Append], String USING [SubString, StringToNumber, AppendChar, AppendNumber]; StreamIO: PROGRAM IMPORTS Directory, FileStream, TTY, Storage, Stream, String EXPORTS IODefs, StreamDefs = BEGIN OPEN Directory, File, FileStream, IODefs, Storage, StreamDefs, String; in, out: StreamHandle; inStreamRecord,outStreamRecord: StreamObject; NILTTY: TTY.Handle ← LOOPHOLE[NIL]; --EXPORTS to IODefs GetInputStream: PUBLIC PROCEDURE RETURNS [StreamHandle] = BEGIN RETURN[in] END; GetOutputStream: PUBLIC PROCEDURE RETURNS [StreamHandle] = BEGIN RETURN[out] END; SetInputStream: PUBLIC PROCEDURE [s: StreamHandle] = BEGIN in ← s; END; SetOutputStream: PUBLIC PROCEDURE [s: StreamHandle] = BEGIN out ← s; END; SetEcho: PUBLIC PROCEDURE [new: BOOLEAN] RETURNS [old: BOOLEAN] = BEGIN IF in.tty#NILTTY THEN RETURN[TTY.SetEcho[in.tty, new]] ELSE RETURN[FALSE]; END; -- Character operations ReadChar: PUBLIC PROCEDURE RETURNS [CHARACTER] = BEGIN RETURN[in.get[in]]; END; WriteChar: PUBLIC PROCEDURE [c: CHARACTER] = BEGIN out.put[out,c]; END; -- Reading Strings GetString: PROCEDURE [s: STRING, t: PROCEDURE [CHARACTER] RETURNS [BOOLEAN]] RETURNS[CHARACTER] = BEGIN IF in.tty#NILTTY THEN RETURN[TTY.GetEditedString[in.tty,s,t,TRUE]] ELSE { s.length ← 0; DO c: CHARACTER ← ReadChar[]; IF t[c] THEN RETURN[c]; AppendChar[s,c]; ENDLOOP; }; END; ReadString: PUBLIC PROCEDURE [s: STRING, t: PROCEDURE [CHARACTER] RETURNS [BOOLEAN]] = BEGIN [] ← GetString[s,t]; END; ReadID: PUBLIC PROCEDURE [s: STRING] = BEGIN ReadString[s, IsAtom]; END; ReadLine: PUBLIC PROCEDURE [s: STRING] = BEGIN ReadString[s, IsCR]; END; IsCR: PRIVATE PROCEDURE [c: CHARACTER] RETURNS [BOOLEAN] = BEGIN RETURN[c = CR] END; IsAtom: PRIVATE PROCEDURE [c: CHARACTER] RETURNS [BOOLEAN] = BEGIN RETURN[c=SP OR c=CR] END; Rubout: PUBLIC SIGNAL = CODE; LineOverflow: PUBLIC SIGNAL [s: STRING] RETURNS [ns: STRING] = CODE; ReadEditedString: PUBLIC PROCEDURE [ s: STRING, t: PROCEDURE [CHARACTER] RETURNS [BOOLEAN], newstring: BOOLEAN] RETURNS [CHARACTER] = BEGIN IF in.tty#NILTTY THEN RETURN[TTY.GetEditedString[in.tty,s,t,newstring]] ELSE RETURN[GetString[s,t]]; END; -- Writing Strings WriteString: PUBLIC PROCEDURE [s: STRING] = BEGIN i: CARDINAL; FOR i IN [0..s.length) DO out.put[out, s[i]]; ENDLOOP; END; WriteSubString: PUBLIC PROCEDURE [s: String.SubString] = BEGIN i: CARDINAL; FOR i IN [s.offset..s.offset + s.length) DO out.put[out, s.base[i]]; ENDLOOP; END; WriteLine: PUBLIC PROCEDURE [s: STRING] = BEGIN WriteString[s]; WriteChar[CR]; END; NewLine: PUBLIC PROCEDURE RETURNS [BOOLEAN] = BEGIN IF out.tty#NILTTY THEN RETURN[TTY.NewLine[out.tty]] ELSE RETURN[FALSE]; END; -- Numerical i/o ReadNumber: PUBLIC PROCEDURE [default: UNSPECIFIED, radix: CARDINAL] RETURNS [UNSPECIFIED] = BEGIN s: STRING ← [10]; IF radix = 10 AND LOOPHOLE[default, INTEGER] < 0 THEN BEGIN default ← -default; s[0] ← '-; s.length ← 1 END; AppendNumber[s, default, radix]; IF radix = 8 THEN AppendChar[s, 'B]; [] ← ReadEditedString[s, IsAtom, TRUE]; RETURN[StringToNumber[s, radix]]; END; ReadDecimal: PUBLIC PROCEDURE RETURNS [INTEGER] = BEGIN s: STRING ← [10]; [] ← ReadEditedString[s, IsAtom, TRUE]; RETURN[StringToNumber[s, 10]] END; ReadOctal: PUBLIC PROCEDURE RETURNS [UNSPECIFIED] = BEGIN s: STRING ← [10]; [] ← ReadEditedString[s, IsAtom, TRUE]; RETURN[StringToNumber[s, 8]] END; OutNumber: PUBLIC PROCEDURE [ stream: StreamHandle, val: INTEGER, format: NumberFormat] = BEGIN i: CARDINAL; neg: BOOLEAN ← FALSE; fill: CHARACTER ← (IF format.zerofill THEN '0 ELSE ' ); s: STRING ← [17]; IF val < 0 AND ~format.unsigned THEN BEGIN val ← -val; neg ← TRUE END; AppendNumber[s, val, format.base]; i ← s.length; IF neg THEN BEGIN i ← i + 1; IF format.zerofill THEN BEGIN stream.put[stream, '-]; neg ← FALSE END; END; THROUGH (i..format.columns] DO stream.put[stream, fill] ENDLOOP; IF neg THEN stream.put[stream, '-]; FOR i IN [0..s.length) DO stream.put[stream, s[i]] ENDLOOP; RETURN END; WriteNumber: PUBLIC PROCEDURE [v: UNSPECIFIED, f: NumberFormat] = BEGIN OutNumber[out, v, f]; RETURN END; WriteDecimal: PUBLIC PROCEDURE [n: INTEGER] = BEGIN WriteNumber[n, NumberFormat[10, FALSE, FALSE, 0]]; RETURN END; WriteOctal: PUBLIC PROCEDURE [n: UNSPECIFIED] = BEGIN WriteNumber[n, NumberFormat[8, FALSE, TRUE, 0]]; IF n ~IN [0..7] THEN WriteChar['B]; RETURN END; --TTY Stream Procedures TTYReset: PROCEDURE [s: StreamHandle] = BEGIN END; TTYGet: PROCEDURE [s: StreamHandle] RETURNS [CHARACTER] = BEGIN RETURN[TTY.GetChar[s.tty]]; END; TTYPutback: PROCEDURE [s: StreamHandle, c: CHARACTER] = BEGIN TTY.PutBackChar[s.tty, c]; END; TTYPut: PROCEDURE [s: StreamHandle, c: CHARACTER] = BEGIN TTY.PutChar[s.tty, c]; END; TTYEndof: PROCEDURE [s: StreamHandle] RETURNS [BOOLEAN] = BEGIN RETURN[FALSE]; END; TTYDestroy: PROCEDURE [s: StreamHandle] = BEGIN END; --EXPORTS to StreamDefs NewByteStream: PUBLIC PROCEDURE [name: STRING, access: AccessOptions] RETURNS [StreamHandle] = BEGIN s: StreamHandle ← Node[SIZE[StreamObject]]; permissions: File.Permissions ← SELECT access FROM Read => read, Write => write+grow+shrink+delete, Append => grow+shrink+delete, Read+Write => read+write+grow+shrink+delete, Write+Append => write+grow+shrink+delete, Read+Append => read+grow+shrink+delete, Read+Write+Append => read+write+grow+shrink+delete, ENDCASE => 0; s↑ ← [ reset: FileReset, get: FileGetChar, putback: FilePutback, put: FilePutChar, endof: FileEndof, destroy: FileDestroy, link: NIL, file: NewStream[name, permissions], tty: NILTTY ]; RETURN[s]; END; NewWordStream: PUBLIC PROCEDURE [name: STRING, access: AccessOptions] RETURNS [StreamHandle] = BEGIN s: StreamHandle ← NewByteStream[name,access]; s.get ← FileGetWord; s.put ← FilePutWord; RETURN[s]; END; NewStream: PROC [name: LONG STRING, access: File.Permissions] RETURNS [Stream.Handle] = { cap: File.Capability; old: BOOLEAN ← FALSE; IF access ~= File.read THEN cap ← Directory.CreateFile[name, DCSFileTypes.tLeaderPage, 0 ! Directory.Error => { IF type = fileAlreadyExists THEN old ← TRUE ELSE ERROR; CONTINUE }] ELSE old ← TRUE; IF old THEN cap ← Directory.Lookup[fileName: name, permissions: access ! Directory.Error => ERROR]; cap ← Directory.UpdateDates[cap, access]; RETURN[FileStream.Create[cap]]; }; --File Stream Procedures FileReset: PROCEDURE [s: StreamHandle] = BEGIN END; FileGetChar: PROCEDURE [s: StreamHandle] RETURNS [CHARACTER] = BEGIN RETURN[Stream.GetChar[s.file]]; END; FileGetWord: PROCEDURE [s: StreamHandle] RETURNS [WORD] = BEGIN RETURN[Stream.GetWord[s.file]]; END; FilePutback: PROCEDURE [s: StreamHandle, c: CHARACTER] = BEGIN END; FilePutChar: PROCEDURE [s: StreamHandle, c: CHARACTER] = BEGIN Stream.PutChar[s.file, c]; END; FilePutWord: PROCEDURE [s: StreamHandle, w: WORD] = BEGIN Stream.PutWord[s.file, w]; END; FileEndof: PROCEDURE [s: StreamHandle] RETURNS [BOOLEAN] = BEGIN RETURN[FileStream.EndOf[s.file]]; END; FileDestroy: PROCEDURE [s: StreamHandle] = BEGIN Stream.Delete[s.file]; Free[s]; END; --START code-- inStreamRecord ← [ reset: TTYReset, get: TTYGet, putback: TTYPutback, put: TTYPut, endof: TTYEndof, destroy: TTYDestroy, link: NIL, file: NIL, tty: TTY.Create[""] ]; in ← @inStreamRecord; outStreamRecord ← [ reset: TTYReset, get: TTYGet, putback: TTYPutback, put: TTYPut, endof: TTYEndof, destroy: TTYDestroy, link: NIL, file: NIL, tty: in.tty ]; out ← @outStreamRecord; END.