-- 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.