DIRECTORY Basics USING [RawChars, UnsafeBlock], IO, IOUtils, RefText, Rope USING [AppendChars, Concat, Fetch, FromRefText, InlineFetch, InlineLength, Length, ROPE], RuntimeError USING [BoundsFault]; IOSimpleStreamsImpl: CEDAR PROGRAM IMPORTS IO, IOUtils, RefText, Rope, RuntimeError EXPORTS IO = BEGIN STREAM: TYPE = IO.STREAM; ROPE: TYPE = Rope.ROPE; StreamProcs: TYPE = IO.StreamProcs; noWhereStream: PUBLIC STREAM _ IO.CreateStream[IO.CreateStreamProcs[ variety: $output, class: $Null, putChar: NoWherePutChar, close: NoWhereClose], NIL]; NoWherePutChar: PROC [self: STREAM, char: CHAR] = {}; NoWhereClose: PROC [self: STREAM, abort: BOOL] = {}; noInputStream: PUBLIC STREAM _ IO.CreateStream[ streamProcs: IO.CreateStreamProcs[ variety: $input, class: $Null, getChar: NoInputGetChar, endOf: NoInputEndOf, backup: NoInputBackup, close: NoInputClose], streamData: NIL]; NoInputGetChar: PROC [self: STREAM] RETURNS [CHAR] = { ERROR IO.EndOfStream[self] }; NoInputBackup: PROC [self: STREAM, char: CHAR] = { ERROR IO.Error[$IllegalBackup, self] }; NoInputEndOf: PROC [self: STREAM] RETURNS [BOOL] = { RETURN[TRUE] }; NoInputClose: PROC [self: STREAM, abort: BOOL] = { }; InputRopeStreamData: TYPE = REF InputRopeStreamRecord; InputRopeStreamRecord: TYPE = RECORD [ rope: ROPE, length: INT, index: INT ]; InputRopeStreamProcs: REF StreamProcs = IO.CreateStreamProcs[ variety: $input, class: $ROPE, getBlock: InputRopeStreamGetBlock, unsafeGetBlock: InputRopeStreamUnsafeGetBlock, getChar: InputRopeStreamGetChar, endOf: InputRopeStreamEndOf, reset: InputRopeStreamReset, getIndex: InputRopeStreamGetIndex, setIndex: InputRopeStreamSetIndex, getLength: InputRopeStreamGetLength, backup: InputRopeStreamBackup ]; RIS: PUBLIC PROC [rope: ROPE, oldStream: STREAM] RETURNS [stream: STREAM] = { IF oldStream = NIL THEN GOTO newStream; WITH oldStream.streamData SELECT FROM data: InputRopeStreamData => { data^ _ [rope: rope, length: rope.InlineLength[], index: 0]; oldStream.streamProcs _ InputRopeStreamProcs; RETURN[oldStream] }; ENDCASE => GOTO newStream; EXITS newStream => RETURN[IO.CreateStream[ InputRopeStreamProcs, NEW[InputRopeStreamRecord _ [ rope: rope, length: rope.Length[], index: 0]]]]; }; InputRopeStreamGetBlock: PROC [self: STREAM, block: REF TEXT, startIndex: NAT, count: NAT] RETURNS [nBytesRead: NAT] = { data: InputRopeStreamData = NARROW[self.streamData]; stop: NAT _ MIN[CARDINAL[startIndex]+CARDINAL[count], NAT.LAST]; nBytes: NAT = MIN [block.maxLength, stop] - startIndex; block.length _ startIndex; nBytesRead _ Rope.AppendChars[block, data.rope, data.index, nBytes]; data.index _ data.index + nBytesRead; block.length _ startIndex + nBytesRead; RETURN[nBytesRead]; }; InputRopeStreamUnsafeGetBlock: UNSAFE PROC [self: STREAM, block: Basics.UnsafeBlock] RETURNS [nBytesRead: INT _ 0] = UNCHECKED { data: InputRopeStreamData = NARROW[self.streamData]; start: INT _ data.index; IF block.startIndex < 0 OR block.count < 0 THEN ERROR RuntimeError.BoundsFault; FOR i: INT IN [0 .. block.count) WHILE data.index < data.length DO LOOPHOLE[block.base, LONG POINTER TO Basics.RawChars][block.startIndex+i] _ data.rope.InlineFetch[data.index]; data.index _ data.index + 1; ENDLOOP; RETURN [data.index - start]; }; InputRopeStreamGetChar: PROC [self: STREAM] RETURNS [char: CHAR] = { data: InputRopeStreamData = NARROW[self.streamData]; IF data.index >= data.length THEN ERROR IO.EndOfStream[self]; char _ data.rope.InlineFetch[data.index]; data.index _ data.index + 1; }; InputRopeStreamEndOf: PROC [self: STREAM] RETURNS [BOOL] = { data: InputRopeStreamData = NARROW[self.streamData]; RETURN[data.index >= data.length]; }; InputRopeStreamBackup: PROC [self: STREAM, char: CHAR] = { data: InputRopeStreamData = NARROW[self.streamData]; IF data.index = 0 OR data.rope.Fetch[data.index-1] # char THEN ERROR IO.Error[$IllegalBackup, self]; data.index _ data.index - 1; }; InputRopeStreamReset: PROC [self: STREAM] = { data: InputRopeStreamData = NARROW[self.streamData]; data.index _ data.length; }; InputRopeStreamGetIndex: PROC [self: STREAM] RETURNS [INT] = { data: InputRopeStreamData = NARROW[self.streamData]; RETURN[data.index]; }; InputRopeStreamSetIndex: PROC [self: STREAM, index: INT] = { data: InputRopeStreamData = NARROW[self.streamData]; IF index NOT IN [0 .. data.length] THEN ERROR IO.Error[$BadIndex, self]; data.index _ index; }; InputRopeStreamGetLength: PROC [self: STREAM] RETURNS [length: INT] = { data: InputRopeStreamData = NARROW[self.streamData]; RETURN[data.length]; }; OutputRopeStreamData: TYPE = REF OutputRopeStreamRecord; OutputRopeStreamRecord: TYPE = RECORD [ rope: ROPE, text: REF TEXT ]; OutputRopeStreamProcs: REF StreamProcs = IO.CreateStreamProcs[ variety: $output, class: $ROPE, putChar: OutputRopeStreamPutChar, eraseChar: OutputRopeStreamEraseChar, reset: OutputRopeStreamReset, getLength: OutputRopeStreamGetLength, getIndex: OutputRopeStreamGetIndex, close: OutputRopeStreamClose ]; ROS: PUBLIC PROC [oldStream: STREAM] RETURNS [stream: STREAM] = { IF oldStream = NIL THEN GOTO newStream; WITH oldStream.streamData SELECT FROM data: OutputRopeStreamData => { data.rope _ NIL; IF data.text = NIL THEN data.text _ RefText.ObtainScratch[100] ELSE data.text.length _ 0; oldStream.streamProcs _ OutputRopeStreamProcs; RETURN[oldStream] }; ENDCASE => GOTO newStream; EXITS newStream => RETURN[IO.CreateStream[ OutputRopeStreamProcs, NEW[OutputRopeStreamRecord _ [ rope: NIL, text: RefText.ObtainScratch[100]]]]]; }; OutputRopeStreamPutChar: PROC [self: STREAM, char: CHAR] = { data: OutputRopeStreamData = NARROW[self.streamData]; text: REF TEXT = data.text; IF text.length = text.maxLength THEN { data.rope _ data.rope.Concat[Rope.FromRefText[text]]; text.length _ 0 }; text[text.length] _ char; text.length _ text.length + 1; }; OutputRopeStreamEraseChar: PROC [self: STREAM, char: CHAR] = { data: OutputRopeStreamData = NARROW[self.streamData]; IF data.text.length # 0 THEN data.text.length _ data.text.length-1; }; OutputRopeStreamReset: PROC [self: STREAM] = { data: OutputRopeStreamData = NARROW[self.streamData]; data.rope _ NIL; data.text.length _ 0; }; OutputRopeStreamGetLength: PROC [self: STREAM] RETURNS [length: INT] = { data: OutputRopeStreamData = NARROW[self.streamData]; RETURN[data.text.length + data.rope.Length[]]; }; OutputRopeStreamGetIndex: PROC [self: STREAM] RETURNS [index: INT] = { RETURN[self.GetLength[]]; }; debugRopeFromROS: BOOL _ TRUE; -- crock until important clients get fixed RopeFromROS: PUBLIC PROC [self: STREAM, close: BOOL] RETURNS [ROPE] = { data: OutputRopeStreamData = NARROW[self.streamData]; result: ROPE _ IF data.text.length = 0 AND debugRopeFromROS THEN NIL ELSE Rope.FromRefText[data.text]; IF close THEN { RefText.ReleaseScratch[data.text]; data.text _ NIL; self.streamProcs _ IOUtils.closedStreamProcs; IF data.rope # NIL THEN { result _ data.rope.Concat[result]; data.rope _ NIL } } ELSE { data.text.length _ 0; result _ data.rope _ data.rope.Concat[result]; }; RETURN[result]; }; OutputRopeStreamClose: PROC [self: STREAM, abort: BOOL] = { data: OutputRopeStreamData = NARROW[self.streamData]; data.rope _ NIL; RefText.ReleaseScratch[data.text]; data.text _ NIL; self.streamProcs _ IOUtils.closedStreamProcs; }; InputTextStreamData: TYPE = REF InputTextStreamRecord; InputTextStreamRecord: TYPE = RECORD [ text: REF READONLY TEXT, index: NAT ]; InputTextStreamProcs: REF StreamProcs = IO.CreateStreamProcs[ variety: $input, class: $TEXT, getChar: InputTextStreamGetChar, endOf: InputTextStreamEndOf, reset: InputTextStreamReset, getIndex: InputTextStreamGetIndex, setIndex: InputTextStreamSetIndex, getLength: InputTextStreamGetLength, backup: InputTextStreamBackup ]; TextFromTOS: PUBLIC PROC [self: STREAM] RETURNS [REF TEXT] = { RETURN[NARROW[self.streamData]]; }; TIS: PUBLIC PROC [text: REF READONLY TEXT, oldStream: STREAM] RETURNS [STREAM] = { IF oldStream = NIL THEN GOTO newStream; WITH oldStream.streamData SELECT FROM data: InputTextStreamData => { data^ _ [text: text, index: 0]; oldStream.streamProcs _ InputTextStreamProcs; RETURN[oldStream] }; ENDCASE => GOTO newStream; EXITS newStream => RETURN[IO.CreateStream[ InputTextStreamProcs, NEW[InputTextStreamRecord _ [ text: text, index: 0]]]]; }; InputTextStreamGetChar: PROC [self: STREAM] RETURNS [char: CHAR] = { data: InputTextStreamData = NARROW[self.streamData]; IF data.index >= data.text.length THEN ERROR IO.EndOfStream[self]; char _ data.text[data.index]; data.index _ data.index + 1; }; InputTextStreamEndOf: PROC [self: STREAM] RETURNS [BOOL] = { data: InputTextStreamData = NARROW[self.streamData]; RETURN[data.index >= data.text.length]; }; InputTextStreamBackup: PROC [self: STREAM, char: CHAR] = { data: InputTextStreamData = NARROW[self.streamData]; IF data.index = 0 OR data.text[data.index-1] # char THEN ERROR IO.Error[$IllegalBackup, self]; data.index _ data.index - 1; }; InputTextStreamReset: PROC [self: STREAM] = { data: InputTextStreamData = NARROW[self.streamData]; data.index _ data.text.length; }; InputTextStreamGetIndex: PROC [self: STREAM] RETURNS [INT] = { data: InputTextStreamData = NARROW[self.streamData]; RETURN[data.index]; }; InputTextStreamSetIndex: PROC [self: STREAM, index: INT] = { data: InputTextStreamData = NARROW[self.streamData]; IF index NOT IN [0 .. data.text.length] THEN ERROR IO.Error[$BadIndex, self]; data.index _ index; }; InputTextStreamGetLength: PROC [self: STREAM] RETURNS [length: INT] = { data: InputTextStreamData = NARROW[self.streamData]; RETURN[data.text.length]; }; OutputTextStreamProcs: REF StreamProcs = IO.CreateStreamProcs[ variety: $output, class: $TEXT, putChar: OutputTextStreamPutChar, eraseChar: OutputTextStreamEraseChar, reset: OutputTextStreamReset, getLength: OutputTextStreamGetLength, getIndex: OutputTextStreamGetIndex, close: NIL ]; TOS: PUBLIC PROC [text: REF TEXT, oldStream: STREAM] RETURNS [stream: STREAM] = { IF oldStream = NIL THEN oldStream _ IO.CreateStream[OutputTextStreamProcs, NIL] ELSE { oldStream.streamProcs _ OutputTextStreamProcs; WITH oldStream.streamData SELECT FROM oldText: REF TEXT => IF text = NIL THEN text _ oldText; ENDCASE; }; IF text = NIL THEN text _ NEW[TEXT[100]]; text.length _ 0; oldStream.streamData _ text; RETURN[oldStream]; }; OutputTextStreamPutChar: PROC [self: STREAM, char: CHAR] = { self.streamData _ RefText.InlineAppendChar[to: NARROW[self.streamData], from: char]; }; OutputTextStreamEraseChar: PROC [self: STREAM, char: CHAR] = { text: REF TEXT = NARROW[self.streamData]; IF text.length > 0 THEN text.length _ text.length - 1; }; OutputTextStreamReset: PROC [self: STREAM] = { NARROW[self.streamData, REF TEXT].length _ 0; }; OutputTextStreamGetLength: PROC [self: STREAM] RETURNS [length: INT] = { RETURN[NARROW[self.streamData, REF TEXT].length]; }; OutputTextStreamGetIndex: PROC [self: STREAM] RETURNS [index: INT] = { RETURN[NARROW[self.streamData, REF TEXT].length]; }; END. :IOSimpleStreamsImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. MBrown on October 25, 1983 1:24 pm Russ Atkinson (RRA) July 25, 1985 0:07:13 am PDT TO DO remove "debugRopeFromROS" flag when no longer needed Nowhere Stream NoInput Stream Input Stream from ROPE (RIS) Output Stream to ROPE (ROS) Input Stream from REF TEXT (TIS) Applies only to the result of a TOS call. Returns the entire output sequence as a ref text. Does not close the stream, so may be called repeatedly, but same ref text may be returned several times (and is mutable). Output Stream to REF TEXT (TOS) Change Log Changed by MBrown on October 25, 1983 1:24 pm Fixed output rope stream and output text stream to implement EraseChar. Streams are prepared for Close to replace the stream procs with IOUtils.closedStreamProcs. RopeFromROS is somewhat more efficient in the normal case. RopeFromROS returns NIL when possible (work around bug in interpreter). Russ Atkinson (RRA) July 22, 1985 8:51:08 pm PDT Fixed RIS to use Rope.AppendChars for input, sped up UnsafeGetBlock too Κ=– "Cedar" style˜codešΟc™Kšœ Οmœ1™KšŸœŸœ˜%—K˜Kšœ˜—š‘œŸœŸœ˜-KšœŸœ˜4Kšœ˜Kšœ˜—š ‘œŸœŸœŸœŸœ˜>KšœŸœ˜4KšŸœ ˜Kšœ˜—š‘œŸœŸœ Ÿœ˜Kšœ˜K˜!K˜%K˜K˜%K˜#Kšœ˜K˜—šŸœŸœŸœ Ÿœ˜$KšŸœ Ÿœ˜KšŸœ ŸœŸœŸœ ˜'šŸœŸœŸ˜%šœ˜Kšœ Ÿœ˜KšŸœ ŸœŸœ'˜>KšŸœ˜Kšœ.˜.KšŸœ˜—KšŸœŸœ ˜—šŸœŸœŸœ˜*šœŸœ˜5KšœŸœ'˜0——Kšœ˜—š‘œŸœŸœŸœ˜KšœŸœ˜5KšŸœŸœ'˜CKšœ˜—š‘œŸœŸœ˜.KšœŸœ˜5Kšœ Ÿœ˜K˜Kšœ˜—š ‘œŸœŸœŸœ Ÿœ˜HKšœŸœ˜5KšŸœ(˜.Kšœ˜—š ‘œŸœŸœŸœ Ÿœ˜FKšŸœ˜Kšœ˜—KšœŸœŸœ*˜Iš‘ œŸœŸœŸœ ŸœŸœŸœ˜GKšœŸœ˜5š œŸœŸœŸœŸœŸ˜DKšŸœ˜!—šŸœ˜šŸœ˜Kšœ"˜"Kšœ Ÿœ˜Kšœ-˜-KšŸœ ŸœŸœ3Ÿœ˜OK˜—šŸœ˜Kšœ˜Kšœ.˜.K˜——KšŸœ ˜Kšœ˜—š‘œŸœŸœ Ÿœ˜;KšœŸœ˜5Kšœ Ÿœ˜Kšœ"˜"Kšœ Ÿœ˜Kšœ-˜-Kšœ˜K˜——šœŸœ™ KšœŸœŸœ˜7šœŸœŸœ˜&KšœŸœŸœŸœ˜KšœŸ˜ Kšœ˜—K˜šœŸœŸœ˜=Kšœ˜K˜ K˜K˜K˜"K˜"K˜$Kšœ˜Kšœ˜—K˜š‘ œŸœŸœŸœŸœŸœŸœ˜>KšœΧ™ΧKšŸœŸœ˜ Kšœ˜K˜—šŸœŸœŸœŸœŸœŸœ Ÿœ˜=KšŸœŸœ˜KšŸœ ŸœŸœŸœ ˜'šŸœŸœŸ˜%šœ˜Kšœ˜Kšœ-˜-KšŸœ˜—KšŸœŸœ ˜—šŸœŸœŸœ˜*šœŸœ˜3Kšœ˜——Kšœ˜—š ‘œŸœŸœŸœŸœ˜DKšœŸœ˜4KšŸœ ŸœŸœŸœ˜BK˜K˜Kšœ˜—š ‘œŸœŸœŸœŸœ˜KšœŸœ˜4KšŸœ ˜Kšœ˜—š‘œŸœŸœ Ÿœ˜Kšœ˜K˜!K˜%K˜K˜%K˜#KšœŸ˜ Kšœ˜—K˜š ŸœŸœŸœŸœŸœ Ÿœ˜4KšŸœ Ÿœ˜šŸœ Ÿ˜KšŸœ Ÿœ%Ÿœ˜<šŸœ˜Kšœ.˜.šŸœŸœŸ˜%Kš œ ŸœŸœŸœŸœŸœ˜7KšŸœ˜—K˜——Kš ŸœŸœŸœŸœŸœ˜)Kšœ˜Kšœ˜KšŸœ ˜Kšœ˜—š‘œŸœŸœŸœ˜KšœŸœŸœŸœ˜)KšŸœŸœ˜6Kšœ˜—š‘œŸœŸœ˜.KšŸœŸœŸœ ˜-Kšœ˜—š ‘œŸœŸœŸœ Ÿœ˜HKšŸœŸœŸœŸœ ˜1Kšœ˜—š ‘œŸœŸœŸœ Ÿœ˜FKšŸœŸœŸœŸœ ˜1Kšœ˜——K˜KšŸœ˜š ™ ™-Kš¨™¨——™0K™G—K™—…—*˜>