<> <> <> DIRECTORY Atom, Convert, IO, IOUtils, RefText, Rope, TapeStreams, Translate; TapeFmtConversion: CEDAR PROGRAM IMPORTS Atom, Convert, IO, IOUtils, RefText, Translate SHARES TapeStreams = BEGIN FromANSIVariable: TapeStreams.Conversion = BEGIN <<[ base: IO.STREAM , clientData: REF ANY _ NIL] RETURNS [ s: IO.STREAM ];>> s _ IO.CreateStream[ streamProcs: IO.CreateStreamProcs[ variety: input, class: $FromANSIVariable, getChar: ANSIGetChar], streamData: NEW[ANSIInRec _ []], backingStream: base]; END; ANSIInRec: TYPE = RECORD [ charsToCR: INT _ -1 ]; ANSIIn: TYPE = REF ANSIInRec _ NIL; ANSIGetChar: PROC [ self: IO.STREAM ] RETURNS [ CHAR ] = BEGIN a: ANSIIn = NARROW[self.streamData]; DO SELECT (a.charsToCR _ a.charsToCR-1) FROM > -1 => RETURN[IO.GetChar[self.backingStream]]; = -1 => RETURN['\n]; ENDCASE => BEGIN t: REF TEXT = NEW[TEXT[4]]; c: CHAR; FOR c _ IO.GetChar[self.backingStream], IO.GetChar[self.backingStream] WHILE NOT c IN ['0..'9] DO -- skip over interblock padding IF c # '^ THEN ERROR; -- is padding always '^ ? ENDLOOP; t.length _ 4; t[0] _ c; FOR i: INT IN [1..3] DO t[i] _ IO.GetChar[self.backingStream] ENDLOOP; a.charsToCR _ Convert.IntFromRope[RefText.TrustTextAsRope[t]]-4; END; ENDLOOP; END; ToANSIVariable: TapeStreams.Conversion = BEGIN <<[ base: IO.STREAM , clientData: REF ANY _ NIL] RETURNS [ s: IO.STREAM ];>> blockSize: INT _ 80; streamData: ANSIOut _ NEW[ANSIOutRec _ [ flushBlockBacking: NARROW[IOUtils.LookupProc[base, $FlushBlock], REF TapeStreams.FlushBlockProc]^]]; FOR prev: IO.STREAM _ base, prev.backingStream WHILE prev # NIL DO WITH prev.streamData SELECT FROM t: TapeStreams.TapeStreamState => {blockSize _ t.blockSize; EXIT}; ENDCASE => NULL; ENDLOOP; streamData.buf _ NEW[TEXT[blockSize-4]]; streamData.buf.length _ 0; s _ IO.CreateStream[ streamProcs: IO.CreateStreamProcs[ variety: output, class: $ToANSIVariable, putChar: ANSIPutChar, flush: ANSIFlush], streamData: streamData, backingStream: base]; END; ANSIOutRec: TYPE = RECORD [ flushBlockBacking: TapeStreams.FlushBlockProc _ NIL, buf: REF TEXT _ NIL ]; ANSIOut: TYPE = REF ANSIOutRec _ NIL; ANSIPutChar: PROC [ self: IO.STREAM, char: CHAR ] = BEGIN a: ANSIOut = NARROW[self.streamData]; SELECT char FROM '\n => BEGIN a.flushBlockBacking[self: self.backingStream, padChar: '^, bytesRequired: 4+a.buf.length]; self.backingStream.PutF["%04d%g", IO.int[4+a.buf.length], IO.text[a.buf]]; a.buf.length _ 0; END; ENDCASE => {a.buf[a.buf.length] _ char; a.buf.length _ a.buf.length+1}; END; ANSIFlush: PROC [ self: IO.STREAM ] = BEGIN a: ANSIOut = NARROW[self.streamData]; ANSIPutChar[self, ' ]; a.flushBlockBacking[self: self.backingStream, padChar: '^]; END; ANSIFlushBlock: PROC [ self: IO.STREAM, padChar: CHAR _ '\000, bytesRequired: INT _ LAST[INT], truncate: BOOL _ FALSE ] -- TapeStreams.FlushBlockProc -- = BEGIN a: ANSIOut = NARROW[self.streamData]; ERROR; -- I'm not quite sure what this operation means... END; ToPGT: TapeStreams.Conversion = BEGIN <<[ base: IO.STREAM , clientData: REF ANY _ NIL] RETURNS [ s: IO.STREAM ];>> convert: TapeStreams.Conversion = Translate.AsciiToEbcdic[lrecl: 0].first^.proc; ebcdicBase: IO.STREAM = convert[base]; s _ IO.CreateStream[ streamProcs: IO.CreateStreamProcs[ variety: output, class: $ToPGT, putChar: PGTPutChar], streamData: NIL, backingStream: ebcdicBase]; END; PGTPutChar: PROC [ self: IO.STREAM, char: CHAR ] = BEGIN SELECT char FROM ' , '\n => NULL; ENDCASE => self.backingStream.PutChar[char]; END; pl: Atom.PropList _ NARROW[Atom.GetProp[$TapeTool, $Conversions]]; pl _ Atom.PutPropOnList[pl, $FromEbcdic, Translate.EbcdicToAscii[].first]; pl _ Atom.PutPropOnList[pl, $ToEbcdic, Translate.AsciiToEbcdic[].first]; pl _ Atom.PutPropOnList[pl, $ToPGT, NEW[TapeStreams.ConversionRecord _ [$ToPGT, ToPGT, NIL]]]; pl _ Atom.PutPropOnList[pl, $FromANSIVariable, NEW[TapeStreams.ConversionRecord _ [$FromANSIVariable, FromANSIVariable, NIL]]]; pl _ Atom.PutPropOnList[pl, $ToANSIVariable, NEW[TapeStreams.ConversionRecord _ [$ToANSIVariable, ToANSIVariable, NIL]]]; Atom.PutProp[$TapeTool, $Conversions, pl]; END.