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