IOClassesImpl:
CEDAR
PROGRAM
IMPORTS IO, IOUtils
EXPORTS IOClasses
SHARES IO --for representation of StreamProcs
= BEGIN
STREAM: TYPE = IO.STREAM;
StreamProcs: TYPE = IO.StreamProcs;
UnsafeBlock: TYPE = IO.UnsafeBlock;
Comment-filtered Input Stream
FilterCommentsStreamData: TYPE = REF FilterCommentsStreamRecord;
FilterCommentsStreamRecord:
TYPE =
RECORD [
inStringLiteral: BOOL ← FALSE,
inCharLiteral: BOOL ← FALSE,
inExtendedChar: BOOL ← FALSE
];
FilterCommentsStreamProcs:
REF
IO.StreamProcs = IO.CreateStreamProcs[
variety: $input, class: $CommentFilter,
getChar: FilterCommentsStreamGetChar
];
CreateCommentFilterStream:
PUBLIC
PROC [input:
STREAM]
RETURNS [IO.STREAM] = {
RETURN[
IO.CreateStream[
streamProcs: FilterCommentsStreamProcs, backingStream: input,
streamData: NEW[FilterCommentsStreamRecord ← []]]];
};
FilterCommentsStreamGetChar:
PROC[self:
IO.
STREAM]
RETURNS [char:
CHAR] = {
data: FilterCommentsStreamData = NARROW[self.streamData];
char ← self.backingStream.GetChar[];
May raise IO.EndOfStream.
SELECT
TRUE
FROM
data.inExtendedChar => {
data.inExtendedChar ← FALSE; -- not really, but rest of extended char can't contain '"
RETURN
};
data.inCharLiteral => {
data.inCharLiteral ← FALSE;
IF char = '\\ THEN data.inExtendedChar ← TRUE;
RETURN
};
data.inStringLiteral => {
SELECT char
FROM
'\\ => data.inExtendedChar ← TRUE;
'\" => data.inStringLiteral ← FALSE; -- not really, but if following char is '" it will look like a new string literal, which is ok
ENDCASE;
RETURN };
ENDCASE =>
SELECT char
FROM
'\" => data.inStringLiteral ← TRUE;
'\' => data.inCharLiteral ← TRUE;
'- =>
IF
NOT self.backingStream.EndOf[]
AND self.backingStream.PeekChar[] = '-
THEN {
Skip over the comment. Return ending CR, or SP if ends without CR, or raise IO.EndOfStream if comment ends with end of input.
[] ← self.backingStream.GetChar[];
DO
SELECT (char ← self.backingStream.GetChar[])
FROM
'\n => EXIT;
'- =>
IF self.backingStream.GetChar[] = '-
THEN {
char ← IO.SP; EXIT };
ENDCASE;
ENDLOOP;
}
ENDCASE;
};
Concatenated Input Stream
CatInputStreamData: TYPE = REF CatInputStreamRecord;
CatInputStreamRecord:
TYPE =
RECORD [
input1, input2: STREAM,
state: CatInputStreamState];
CatInputStreamState: TYPE = { initial, swapped, closed };
CatInputStreamProcs:
REF
IO.StreamProcs = IO.CreateStreamProcs[
variety: $input, class: $Concatenated,
getChar: CatInputStreamGetChar,
getBlock: CatInputStreamGetBlock,
unsafeGetBlock: CatInputStreamUnsafeGetBlock,
charsAvail: CatInputStreamCharsAvail,
backup: CatInputStreamBackup,
endOf: CatInputStreamEndOf,
reset: CatInputStreamReset,
close: CatInputStreamClose
];
CreateCatInputStream:
PUBLIC
PROC [input1, input2:
STREAM]
RETURNS [
STREAM] = {
RETURN[
IO.CreateStream[
streamProcs: CatInputStreamProcs, streamData:
NEW[CatInputStreamRecord ← [
input1: input1, input2: input2, state: $initial]]]];
};
CatInputStreamGetChar:
PROC [self:
STREAM]
RETURNS [
CHAR] = {
data: CatInputStreamData = NARROW[self.streamData];
{
RETURN[data.input1.GetChar[ !
IO.EndOfStream =>
IF data.state = $initial THEN GOTO nextStream]];
EXITS nextStream => {
SwapStreams[data];
RETURN[data.input1.GetChar[]];
}
}
};
SwapStreams:
PROC [data: CatInputStreamData] = {
we preserve the information for debugging purposes
temp: STREAM ← data.input1;
data.input1 ← data.input2;
data.input2 ← temp;
};
CatInputStreamGetBlock:
PROC [self:
STREAM, block:
REF
TEXT, startIndex:
NAT, count:
NAT]
RETURNS [nBytesRead: NAT] = {
data: CatInputStreamData = NARROW[self.streamData];
nBytesRead ← data.input1.GetBlock[block, startIndex, count];
IF nBytesRead > 0 OR data.state = $swapped THEN RETURN [nBytesRead];
SwapStreams[data];
RETURN[data.input1.GetBlock[block, startIndex, count]];
};
CatInputStreamUnsafeGetBlock:
PROC [self:
STREAM, block: UnsafeBlock]
RETURNS [nBytesRead: INT] = TRUSTED {
data: CatInputStreamData = NARROW[self.streamData];
nBytesRead ← data.input1.UnsafeGetBlock[block];
IF nBytesRead > 0 OR data.state = $swapped THEN RETURN [nBytesRead];
SwapStreams[data];
RETURN[data.input1.UnsafeGetBlock[block]];
};
CatInputStreamEndOf:
PROC [self:
STREAM]
RETURNS [
BOOL] = {
data: CatInputStreamData = NARROW[self.streamData];
IF data.input1.EndOf[] AND data.state = $swapped THEN RETURN [TRUE];
SwapStreams[data];
RETURN [data.input1.EndOf[]];
};
CatInputStreamCharsAvail:
PROC [self:
STREAM, wait:
BOOL]
RETURNS [
INT] = {
data: CatInputStreamData = NARROW[self.streamData];
RETURN[data.input1.CharsAvail[wait]];
};
CatInputStreamBackup:
PROC [self:
STREAM, char:
CHAR] = {
data: CatInputStreamData = NARROW[self.streamData];
data.input1.Backup[char];
};
CatInputStreamReset:
PROC [self:
STREAM] = {
data: CatInputStreamData = NARROW[self.streamData];
data.input1.Reset[];
data.input2.Reset[];
};
CatInputStreamClose:
PROC [self:
STREAM, abort:
BOOL] = {
data: CatInputStreamData = NARROW[self.streamData];
data.input1.Close[];
data.input2.Close[];
data.state ← $closed;
self.streamProcs ← IOUtils.closedStreamProcs;
};
Dribble Output Stream
DribbleStreamData: TYPE = REF DribbleStreamRecord;
DribbleStreamRecord: TYPE = RECORD[output1, output2: STREAM];
DribbleStreamProcs:
REF StreamProcs ←
IO.CreateStreamProcs[
variety: $output, class: $Dribble,
putChar: DribbleStreamPutChar,
putBlock: DribbleStreamPutBlock,
unsafePutBlock: DribbleStreamUnsafePutBlock,
flush: DribbleStreamFlush,
eraseChar: DribbleStreamEraseChar,
reset: DribbleStreamReset,
close: DribbleStreamClose
];
CreateDribbleOutputStream:
PUBLIC
PROC [output1, output2:
STREAM]
RETURNS [
STREAM] = {
RETURN[
IO.CreateStream[
streamProcs: DribbleStreamProcs,
streamData: NEW[DribbleStreamRecord ← [output1: output1, output2: output2]]]];
};
DribbleStreamPutChar:
PROC [self:
STREAM, char:
CHAR] = {
data: DribbleStreamData = NARROW[self.streamData];
data.output1.PutChar[char];
data.output2.PutChar[char];
};
DribbleStreamPutBlock:
PROC [
self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = {
data: DribbleStreamData = NARROW[self.streamData];
data.output1.PutBlock[block, startIndex, count];
data.output2.PutBlock[block, startIndex, count];
};
DribbleStreamUnsafePutBlock:
PROC [self:
STREAM, block: IO.UnsafeBlock] = {
data: DribbleStreamData = NARROW[self.streamData];
data.output1.UnsafePutBlock[block];
data.output2.UnsafePutBlock[block];
};
DribbleStreamFlush:
PROC[self:
STREAM] = {
data: DribbleStreamData = NARROW[self.streamData];
data.output1.Flush[];
data.output2.Flush[];
};
DribbleStreamEraseChar:
PROC [self:
STREAM, char:
CHAR] = {
data: DribbleStreamData = NARROW[self.streamData];
data.output1.EraseChar[char];
data.output2.EraseChar[char];
};
DribbleStreamReset:
PROC[self:
STREAM] = {
data: DribbleStreamData = NARROW[self.streamData];
data.output1.Reset[];
data.output2.Reset[];
};
DribbleStreamClose:
PROC[self:
STREAM, abort:
BOOL] = {
data: DribbleStreamData = NARROW[self.streamData];
data.output1.Close[abort];
data.output2.Close[abort];
};
END.